From 58b04696e876955e15eadabb999f19a737db795a Mon Sep 17 00:00:00 2001 From: xichutian Date: Mon, 25 Dec 2023 17:08:09 +0800 Subject: [PATCH 1/2] sync code connector3.0.0 --- .clang-format | 346 ++ .gitattributes | 50 + .gitconfig | 10 + .gitignore | 34 + ...tion 3.0.0 Open Source Software Notice.txt | 52 + LICENST.txt | 347 ++ README | 42 + README.en.md | 36 - README.md | 37 - mysql-test/mysql-scripts-meta.patch | 716 +++ mysql-test/mysql-source-code-meta.patch | 3501 +++++++++++ mysql-test/mysql-test-meta.patch | 84 + .../suite/tianchi/t/ctc_atomic_ddl.test | 201 + .../suite/tianchi/t/ctc_auto_increment.test | 396 ++ mysql-test/suite/tianchi/t/ctc_charset.test | 321 + .../suite/tianchi/t/ctc_charset_binary.test | 201 + .../suite/tianchi/t/ctc_charset_collate.test | 429 ++ .../tianchi/t/ctc_compressed_proxy_conn.test | 16 + .../suite/tianchi/t/ctc_cond_pushdown.test | 288 + .../tianchi/t/ctc_cond_pushdown_explain.test | 140 + .../tianchi/t/ctc_crud_for_drop_column.test | 453 ++ mysql-test/suite/tianchi/t/ctc_datatype.test | 280 + .../suite/tianchi/t/ctc_datatype_adapt.test | 145 + .../suite/tianchi/t/ctc_datatype_blob.test | 153 + mysql-test/suite/tianchi/t/ctc_dc_reuse.test | 204 + mysql-test/suite/tianchi/t/ctc_dcl.test | 203 + mysql-test/suite/tianchi/t/ctc_ddl.test | 143 + .../suite/tianchi/t/ctc_ddl_alter_table.test | 909 +++ .../suite/tianchi/t/ctc_ddl_analyze.test | 52 + .../suite/tianchi/t/ctc_ddl_auto_inc.test | 587 ++ .../suite/tianchi/t/ctc_ddl_cascade.test | 786 +++ .../tianchi/t/ctc_ddl_character_set.test | 74 + .../suite/tianchi/t/ctc_ddl_create_table.test | 1081 ++++ .../tianchi/t/ctc_ddl_create_table_check.test | 9 + .../tianchi/t/ctc_ddl_default_index.test | 373 ++ .../suite/tianchi/t/ctc_ddl_engine.test | 41 + .../tianchi/t/ctc_ddl_fault_process.test | 171 + .../suite/tianchi/t/ctc_ddl_foreign_key.test | 309 + .../t/ctc_ddl_foreign_key_set_enum.test | 75 + .../suite/tianchi/t/ctc_ddl_func_index.test | 54 + .../suite/tianchi/t/ctc_ddl_func_proc.test | 55 + .../tianchi/t/ctc_ddl_generated_columns.test | 96 + mysql-test/suite/tianchi/t/ctc_ddl_index.test | 150 + mysql-test/suite/tianchi/t/ctc_ddl_limit.test | 20 + .../tianchi/t/ctc_ddl_max_reclength.test | 54 + .../suite/tianchi/t/ctc_ddl_multi_db.test | 82 + .../suite/tianchi/t/ctc_ddl_partition.test | 545 ++ .../suite/tianchi/t/ctc_ddl_tablespace.test | 123 + .../tianchi/t/ctc_ddl_temporary_table.test | 79 + .../tianchi/t/ctc_ddl_too_many_databases.test | 57 + .../suite/tianchi/t/ctc_ddl_trigger.test | 73 + .../tianchi/t/ctc_ddl_unsupport_command.test | 185 + mysql-test/suite/tianchi/t/ctc_ddl_view.test | 50 + .../suite/tianchi/t/ctc_delete_time.test | 122 + .../tianchi/t/ctc_dml_decimal_table.test | 195 + .../suite/tianchi/t/ctc_dml_ignore.test | 193 + .../suite/tianchi/t/ctc_dml_two_table.test | 52 + .../tianchi/t/ctc_handler_operation.test | 48 + .../tianchi/t/ctc_index_functions_base.test | 140 + .../suite/tianchi/t/ctc_insert_time.test | 1063 ++++ .../suite/tianchi/t/ctc_json_value.test | 233 + mysql-test/suite/tianchi/t/ctc_lcov.test | 62 + .../tianchi/t/ctc_link_and_migr_row.test | 349 ++ .../suite/tianchi/t/ctc_lock_instance.test | 23 + ...ncurrency_with_nowait_and_skip_locked.test | 62 + .../suite/tianchi/t/ctc_partition_update.test | 103 + mysql-test/suite/tianchi/t/ctc_read_only.test | 270 + .../tianchi/t/ctc_select_early_return.test | 83 + .../suite/tianchi/t/ctc_update_time.test | 198 + mysql-test/suite/tianchi/t/ctc_varchar.test | 184 + .../suite/tianchi/t/recreate_test_db.test | 4 + storage/tianchi/CMakeLists.txt | 89 + storage/tianchi/ctc_meta_data.cc | 779 +++ storage/tianchi/ctc_meta_data.h | 35 + .../tianchi/datatype_cnvrt_4_index_search.cc | 218 + .../tianchi/datatype_cnvrt_4_index_search.h | 25 + storage/tianchi/datatype_cnvrtr.cc | 1824 ++++++ storage/tianchi/datatype_cnvrtr.h | 242 + storage/tianchi/decimal_convert.cc | 756 +++ storage/tianchi/decimal_convert.h | 357 ++ storage/tianchi/ha_tse.cc | 5241 +++++++++++++++++ storage/tianchi/ha_tse.h | 980 +++ storage/tianchi/ha_tse_ddl.cc | 2706 +++++++++ storage/tianchi/ha_tse_ddl.h | 234 + storage/tianchi/ha_tsepart.cc | 1115 ++++ storage/tianchi/ha_tsepart.h | 438 ++ storage/tianchi/message_queue/dsw_list.h | 484 ++ storage/tianchi/message_queue/dsw_message.h | 131 + storage/tianchi/message_queue/dsw_shm.h | 289 + storage/tianchi/message_queue/dsw_typedef.h | 94 + storage/tianchi/mysql_daac_plugin.cc | 152 + storage/tianchi/protobuf/tc_db.pb-c.c | 3998 +++++++++++++ storage/tianchi/protobuf/tc_db.pb-c.h | 1152 ++++ storage/tianchi/protobuf/tc_db.proto | 259 + storage/tianchi/srv_mq_msg.h | 427 ++ storage/tianchi/tse_cbo.cc | 231 + storage/tianchi/tse_cbo.h | 52 + storage/tianchi/tse_ddl_rewriter_plugin.cc | 1324 +++++ storage/tianchi/tse_ddl_util.cc | 495 ++ storage/tianchi/tse_ddl_util.h | 48 + storage/tianchi/tse_error.cc | 159 + storage/tianchi/tse_error.h | 218 + storage/tianchi/tse_log.h | 152 + storage/tianchi/tse_mysql_proxy.cc | 690 +++ storage/tianchi/tse_proxy_util.cc | 224 + storage/tianchi/tse_proxy_util.h | 72 + storage/tianchi/tse_srv.h | 604 ++ storage/tianchi/tse_srv_mq_module.cc | 548 ++ storage/tianchi/tse_srv_mq_module.h | 41 + storage/tianchi/tse_srv_mq_stub.cc | 1458 +++++ storage/tianchi/tse_stats.cc | 146 + storage/tianchi/tse_stats.h | 50 + storage/tianchi/tse_util.cc | 710 +++ storage/tianchi/tse_util.h | 79 + 114 files changed, 47555 insertions(+), 73 deletions(-) create mode 100644 .clang-format create mode 100644 .gitattributes create mode 100644 .gitconfig create mode 100644 .gitignore create mode 100644 Distributed DB Storage Solution 3.0.0 Open Source Software Notice.txt create mode 100644 LICENST.txt create mode 100644 README delete mode 100644 README.en.md delete mode 100644 README.md create mode 100644 mysql-test/mysql-scripts-meta.patch create mode 100644 mysql-test/mysql-source-code-meta.patch create mode 100644 mysql-test/mysql-test-meta.patch create mode 100644 mysql-test/suite/tianchi/t/ctc_atomic_ddl.test create mode 100644 mysql-test/suite/tianchi/t/ctc_auto_increment.test create mode 100644 mysql-test/suite/tianchi/t/ctc_charset.test create mode 100644 mysql-test/suite/tianchi/t/ctc_charset_binary.test create mode 100644 mysql-test/suite/tianchi/t/ctc_charset_collate.test create mode 100644 mysql-test/suite/tianchi/t/ctc_compressed_proxy_conn.test create mode 100644 mysql-test/suite/tianchi/t/ctc_cond_pushdown.test create mode 100644 mysql-test/suite/tianchi/t/ctc_cond_pushdown_explain.test create mode 100644 mysql-test/suite/tianchi/t/ctc_crud_for_drop_column.test create mode 100644 mysql-test/suite/tianchi/t/ctc_datatype.test create mode 100644 mysql-test/suite/tianchi/t/ctc_datatype_adapt.test create mode 100644 mysql-test/suite/tianchi/t/ctc_datatype_blob.test create mode 100644 mysql-test/suite/tianchi/t/ctc_dc_reuse.test create mode 100644 mysql-test/suite/tianchi/t/ctc_dcl.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_alter_table.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_analyze.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_auto_inc.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_cascade.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_character_set.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_create_table.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_create_table_check.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_default_index.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_engine.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_fault_process.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_foreign_key.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_foreign_key_set_enum.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_func_index.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_func_proc.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_generated_columns.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_index.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_limit.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_max_reclength.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_multi_db.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_partition.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_tablespace.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_temporary_table.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_too_many_databases.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_trigger.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_unsupport_command.test create mode 100644 mysql-test/suite/tianchi/t/ctc_ddl_view.test create mode 100644 mysql-test/suite/tianchi/t/ctc_delete_time.test create mode 100644 mysql-test/suite/tianchi/t/ctc_dml_decimal_table.test create mode 100644 mysql-test/suite/tianchi/t/ctc_dml_ignore.test create mode 100644 mysql-test/suite/tianchi/t/ctc_dml_two_table.test create mode 100644 mysql-test/suite/tianchi/t/ctc_handler_operation.test create mode 100644 mysql-test/suite/tianchi/t/ctc_index_functions_base.test create mode 100644 mysql-test/suite/tianchi/t/ctc_insert_time.test create mode 100644 mysql-test/suite/tianchi/t/ctc_json_value.test create mode 100644 mysql-test/suite/tianchi/t/ctc_lcov.test create mode 100644 mysql-test/suite/tianchi/t/ctc_link_and_migr_row.test create mode 100644 mysql-test/suite/tianchi/t/ctc_lock_instance.test create mode 100644 mysql-test/suite/tianchi/t/ctc_locking_read_concurrency_with_nowait_and_skip_locked.test create mode 100644 mysql-test/suite/tianchi/t/ctc_partition_update.test create mode 100644 mysql-test/suite/tianchi/t/ctc_read_only.test create mode 100644 mysql-test/suite/tianchi/t/ctc_select_early_return.test create mode 100644 mysql-test/suite/tianchi/t/ctc_update_time.test create mode 100644 mysql-test/suite/tianchi/t/ctc_varchar.test create mode 100644 mysql-test/suite/tianchi/t/recreate_test_db.test create mode 100644 storage/tianchi/CMakeLists.txt create mode 100644 storage/tianchi/ctc_meta_data.cc create mode 100644 storage/tianchi/ctc_meta_data.h create mode 100644 storage/tianchi/datatype_cnvrt_4_index_search.cc create mode 100644 storage/tianchi/datatype_cnvrt_4_index_search.h create mode 100644 storage/tianchi/datatype_cnvrtr.cc create mode 100644 storage/tianchi/datatype_cnvrtr.h create mode 100644 storage/tianchi/decimal_convert.cc create mode 100644 storage/tianchi/decimal_convert.h create mode 100644 storage/tianchi/ha_tse.cc create mode 100644 storage/tianchi/ha_tse.h create mode 100644 storage/tianchi/ha_tse_ddl.cc create mode 100644 storage/tianchi/ha_tse_ddl.h create mode 100644 storage/tianchi/ha_tsepart.cc create mode 100644 storage/tianchi/ha_tsepart.h create mode 100644 storage/tianchi/message_queue/dsw_list.h create mode 100644 storage/tianchi/message_queue/dsw_message.h create mode 100644 storage/tianchi/message_queue/dsw_shm.h create mode 100644 storage/tianchi/message_queue/dsw_typedef.h create mode 100644 storage/tianchi/mysql_daac_plugin.cc create mode 100644 storage/tianchi/protobuf/tc_db.pb-c.c create mode 100644 storage/tianchi/protobuf/tc_db.pb-c.h create mode 100644 storage/tianchi/protobuf/tc_db.proto create mode 100644 storage/tianchi/srv_mq_msg.h create mode 100644 storage/tianchi/tse_cbo.cc create mode 100644 storage/tianchi/tse_cbo.h create mode 100644 storage/tianchi/tse_ddl_rewriter_plugin.cc create mode 100644 storage/tianchi/tse_ddl_util.cc create mode 100644 storage/tianchi/tse_ddl_util.h create mode 100644 storage/tianchi/tse_error.cc create mode 100644 storage/tianchi/tse_error.h create mode 100644 storage/tianchi/tse_log.h create mode 100644 storage/tianchi/tse_mysql_proxy.cc create mode 100644 storage/tianchi/tse_proxy_util.cc create mode 100644 storage/tianchi/tse_proxy_util.h create mode 100644 storage/tianchi/tse_srv.h create mode 100644 storage/tianchi/tse_srv_mq_module.cc create mode 100644 storage/tianchi/tse_srv_mq_module.h create mode 100644 storage/tianchi/tse_srv_mq_stub.cc create mode 100644 storage/tianchi/tse_stats.cc create mode 100644 storage/tianchi/tse_stats.h create mode 100644 storage/tianchi/tse_util.cc create mode 100644 storage/tianchi/tse_util.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..55ed2b2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,346 @@ +# Run manually to reformat a file: +# clang-format -i --style=file +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + - Regex: '.*' + Priority: 3 + SortPriority: 0 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never + +# We declare one specific pointer style since right alignment is dominant in +# the MySQL code base (default --style=google has DerivePointerAlignment true). +DerivePointerAlignment: false +PointerAlignment: Right + +# MySQL source code is allowed to use C++11 (and C++14) features. +Standard: Cpp11 + +# MySQL includes frequently are not order-independent (e.g. my_config.h needs +# to go on top). This is unfortunate, but not something we can change easily, +# so we keep the clang-format 8 behavior of preserving blocks. +IncludeBlocks: Preserve +--- +Language: JavaScript +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: AlwaysBreak +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: false +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '(taze:|^/[ ]*<|@see)' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + - Regex: '.*' + Priority: 3 + SortPriority: 0 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 3 +NamespaceIndentation: All +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3018dd4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,50 @@ +.gitattributes export-ignore +.gitignore export-ignore + +# All MySQL code is auto-formatted using clang-format. +*.c filter=codeformat +*.cc filter=codeformat +*.cpp filter=codeformat +*.h filter=codeformat +*.hpp filter=codeformat +*.i filter=codeformat +*.ic filter=codeformat +*.js filter=codeformat + +# Third-party code. +/extra/** !filter +/internal/extra/** !filter +/include/boost_*/** !filter +/plugin/innodb_memcached/daemon_memcached/** !filter +/plugin/innodb_memcached/innodb_memcache/cache-src/** !filter +/internal/plugin/keyring_okv/okv_client_sdk/** !filter +/plugin/group_replication/libmysqlgcs/src/bindings/xcom/xcom/windeps/** !filter + +# RQG combination files have the .cc extension, but they are not C++ files. +/internal/rqg_grammars/**/*.cc !filter + +# Generated from lex/yacc. +/storage/innobase/fts/fts0blex.cc !filter +/storage/innobase/fts/fts0pars.cc !filter +/storage/innobase/fts/fts0tlex.cc !filter +/storage/innobase/include/fts0blex.h !filter +/storage/innobase/include/fts0pars.h !filter +/storage/innobase/include/fts0tlex.h !filter +/storage/innobase/pars/lexyy.cc !filter +/storage/innobase/pars/pars0grm.cc !filter + +# Other autogenerated files. The generators should eventually be updated. +/strings/uca900_data.h !filter +/strings/uca900_ja_data.h !filter +/strings/uca_data.h !filter +/internal/meb/meb/mysqloption_list.cpp !filter + +# Some NDB source is currently exempt +/storage/ndb/clusterj/** !filter +/storage/ndb/include/** !filter +/storage/ndb/memcache/** !filter +/storage/ndb/ndbapi-examples/** !filter +/storage/ndb/nodejs/** !filter +/storage/ndb/src/** !filter +/storage/ndb/test/** !filter +/storage/ndb/tools/** !filter diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..72c38ce --- /dev/null +++ b/.gitconfig @@ -0,0 +1,10 @@ +# To automatically add this to your git config so that “git add” and +# “git merge” automatically run clang-format, use +# +# git config --local include.path ../.gitconfig +# +[filter "codeformat"] + clean = clang-format --assume-filename=%f --style=file +[merge] + renormalize = true + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7ad2cbd --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# emacs backup files +*~ + +# Misc tags/ctags files +tags +TAGS +TAGS_sorted_by_file +cscope*.out + +# googletest files +source_downloads + +# Vim swap files +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Configuration files for Visual Studio Code +.vscode/ + +# Bld +/bld +/bld_debug +/bld_release +/mysql-source +# daac +/daac_lib +/mysql_bin + +# test +/bin +mysql-test/stdin.log diff --git a/Distributed DB Storage Solution 3.0.0 Open Source Software Notice.txt b/Distributed DB Storage Solution 3.0.0 Open Source Software Notice.txt new file mode 100644 index 0000000..145d9ba --- /dev/null +++ b/Distributed DB Storage Solution 3.0.0 Open Source Software Notice.txt @@ -0,0 +1,52 @@ +OPEN SOURCE SOFTWARE NOTICE + +Please note we provide an open source software notice along with this product and/or this product firmware (in the following just this product). The open source software licenses are granted by the respective right holders. And the open source licenses prevail all other license information with regard to the respective open source software contained in the product, including but not limited to End User Software Licensing Agreement. This notice is provided on behalf of Huawei Technologies Co. Ltd. and any of its local subsidiaries which may have provided this product to you in your local country. + +Warranty Disclaimer +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +Copyright Notice and License Texts +Software: protobuf-c v1.4.1 +Copyright notice: +Copyright (c) 2012 Zack Weinberg +Copyright (c) 2011 Maarten Bosmans +Copyright (c) 2015 Moritz Klammler +Copyright (c) 2008 Benjamin Kosnik +Copyright (c) 2012 Christian Persch +Copyright (c) 2014, The protobuf-c authors +Copyright (c) 2014, 2015 Google Inc. +Copyright (c) 2012, 2014 Philip Withnall +Copyright (c) 2021, the protobuf-c authors +Copyright (c) 2013 Roy Stogner +Copyright (c) 2012 Paolo Borelli +Copyright (c) 2015 Paul Norman +Copyright (c) 2016, 2018 Krzesimir Nowak +Copyright (c) 2004 Scott James Remnant +Copyright (c) 2008 Guido U. Draheim +Copyright 2008 Google Inc. +Copyright (c) 2008-2014 Free Software Foundation, Inc. +Copyright (c) 2008-2022, Dave Benson and the protobuf-c authors +Copyright (c) 2008-2014, Dave Benson and the protobuf-c authors +Copyright (c) 2012 Dan Winship +Copyright (c) 2012 Xan Lopez +Copyright (c) 2008-2011 Free Software Foundation, Inc. +Copyright (c) 2008-2013, Dave Benson + +License: BSD 2-Clause License +BSD Two Clause License +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +Written Offer +This product contains software whose rights holders license it on the terms of the GNU General Public License, version 2 (GPLv2) and/or other open source software licenses. We will provide you and any third party with the source code of the software licensed under an open source software license if you send us a written request by mail or email to the following addresses: +foss@huawei.com +detailing the name of the product and the firmware version for which you need the source code and indicating how we can contact you. + +Please note you need to make a payment before you obtain the complete Corresponding Source Code from us. For how much you will pay and how we will deliver the complete Corresponding Source Code to you, we will further discuss it by mail or email. +This offer is valid to anyone in receipt of this information. + +THIS OFFER IS VALID FOR THREE YEARS FROM THE MOMENT WE DISTRIBUTED THE PRODUCT OR FIRMWARE. + diff --git a/LICENST.txt b/LICENST.txt new file mode 100644 index 0000000..1f841fa --- /dev/null +++ b/LICENST.txt @@ -0,0 +1,347 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Everyone is permitted to copy and distribute verbatim +copies of this license document, but changing it is not +allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, +and (2) offer you this license which gives you legal permission to +copy, distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, +so that any problems introduced by others will not reflect on the +original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software + interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as +a special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new +versions of the General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a +version number of this License, you may choose any version ever +published by the Free Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the +author to ask for permission. For software which is copyrighted by the +Free Software Foundation, write to the Free Software Foundation; we +sometimes make exceptions for this. Our decision will be guided by the +two goals of preserving the free status of all derivatives of our free +software and of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS +WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details + type 'show w'. This is free software, and you are welcome + to redistribute it under certain conditions; type 'show c' + for details. + +The hypothetical commands 'show w' and 'show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than 'show w' and +'show c'; they could even be mouse-clicks or menu items--whatever +suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program 'Gnomovision' (which makes passes at compilers) written + by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, +you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use +the GNU Lesser General Public License instead of this License. \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..6dc3a89 --- /dev/null +++ b/README @@ -0,0 +1,42 @@ +Cantian connector (MySQL版)是由华为研发的一款MySQL存储引擎插件。它能够在无侵入的情况下将16个(或更多)MySQL实例组成一个多读多写的应用透明集群,并借助Cantian数据存储引擎提供更高的OLTP性能以及更强的高可用能力。这将使MySQL单机的应用无需进行(分库分表等)改造就可以获得集群架构的灵活并发、高性能处理与故障快速恢复能力。 +Cantian connector通过插件加载方式集成到MySQL中运行,替代InnoDB作为默认的数据存储引擎执行表的数据存储、查询与索引等功能。此外,MySQL仍然以原有方式访问元数据缓存(Dictionary cache)且使用InnoDB存储元数据(data dictionary)。Cantian connector能够将这些元数据访问进行追踪与同步,达到元数据的集群一致化。 + +Cantian connector for MySQL is a storage engine software developed by Huawei, which enables an application transparent cluster on top of 16 or more MySQL instances. Together with the Cantian software, it can improve performance and high availability of the original MySQL server. As a result, traditional OLTP SQL applications would run faster and be resilient to disaster incidents without modifications. +The Cantian connector runs as one of the MySQL installable plugins and handles table data operations such as selection, insertion, deletion, in replace of the InnoDB. Other than that, Cantian connector keeps cluster-wise consistency of the data dictionary of all MySQL instances by tracking and synchronizing standalone DD operations that still take place at InnoDB. + +平台支持 +当前支持CentOS8/AArch64、CentOS8/x86_64 平台 + +License + +使用 GPLv2协议,请见 License + +安装指导 +1、下载cantian代码,链接见https://gitee.com/openeuler/cantian +2、完成cantian编译 +3、下载MySQL代码,将mysql代码放置到mysql-source文件夹下 +4、完成connector编译 +4.1、Debug 版 +cd /home/regress/CantianKernel/build;sh Makefile.sh mysql +4.2、Release 版 +cd /home/regress/CantianKernel/build;sh Makefile.sh mysql_release +5、拷贝mysql相关so(元数据归一版本无需执行) +# 单节点 +cd /home/regress/CantianKernel/build;sh Makefile.sh mysql_package_node0 +# 双节点节点0执行 +cd /home/regress/CantianKernel/build;sh Makefile.sh mysql_package_node0 +# 双节点节点1执行 +cd /home/regress/CantianKernel/build;sh Makefile.sh mysql_package_node1 +6、部署MySQL +# 创建文件:所有节点 +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/regress/mysql-server/bld_debug//library_output_directory/ +mkdir -p /home/regress/mydata/ +rm -rf /home/regress/mydata/* +mkdir /data +mkdir /data/data + +# 初始化(任一/所有节点):仅1个节点能执行成功 +/usr/local/mysql/bin/mysqld --defaults-file=/home/regress/mysql-server/scripts/my.cnf --initialize-insecure --datadir=/home/regress/mydata --early-plugin-load="ha_ctc.so" --core-file >> /data/data/mysql.log 2>&1 & + +# 启动:所有节点 +/usr/local/mysql/bin/mysqld --defaults-file=/home/regress/mysql-server/scripts/my.cnf --datadir=/home/regress/mydata --user=root --core-file --early-plugin-load="ha_ctc.so" --skip-innodb --core-file >> /data/data/mysql.log 2>&1 & \ No newline at end of file diff --git a/README.en.md b/README.en.md deleted file mode 100644 index c242f3a..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# cantian-connector-mysql - -#### Description -Cantian connector for MySQL is a MySQL storage engine plugin. It is capable of forming MySQL instances into a multi-read, multi-write transparent cluster with the help of the cantian storage engine. - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md deleted file mode 100644 index 96c303c..0000000 --- a/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# cantian-connector-mysql - -#### 介绍 -Cantian connector for MySQL is a MySQL storage engine plugin. It is capable of forming MySQL instances into a multi-read, multi-write transparent cluster with the help of the cantian storage engine. - -#### 软件架构 -软件架构说明 - - -#### 安装教程 - -1. xxxx -2. xxxx -3. xxxx - -#### 使用说明 - -1. xxxx -2. xxxx -3. xxxx - -#### 参与贡献 - -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request - - -#### 特技 - -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/mysql-test/mysql-scripts-meta.patch b/mysql-test/mysql-scripts-meta.patch new file mode 100644 index 0000000..0bbc50a --- /dev/null +++ b/mysql-test/mysql-scripts-meta.patch @@ -0,0 +1,716 @@ +diff --git a/scripts/mysql_system_tables.sql b/scripts/mysql_system_tables.sql +index bc23872..bc85611 100644 +--- a/scripts/mysql_system_tables.sql ++++ b/scripts/mysql_system_tables.sql +@@ -1,39 +1,10 @@ +--- Copyright (c) 2007, 2021, Oracle and/or its affiliates. +--- +--- This program is free software; you can redistribute it and/or modify +--- it under the terms of the GNU General Public License, version 2.0, +--- as published by the Free Software Foundation. +--- +--- This program is also distributed with certain software (including +--- but not limited to OpenSSL) that is licensed under separate terms, +--- as designated in a particular file or component or in included license +--- documentation. The authors of MySQL hereby grant you an additional +--- permission to link the program and your derivative works with the +--- separately licensed software that they have included with MySQL. +--- +--- This program is distributed in the hope that it will be useful, +--- but WITHOUT ANY WARRANTY; without even the implied warranty of +--- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +--- GNU General Public License, version 2.0, for more details. +--- +--- You should have received a copy of the GNU General Public License +--- along with this program; if not, write to the Free Software +--- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +- +--- +--- The system tables of MySQL Server +--- +- +-set @have_innodb= (select count(engine) from information_schema.engines where engine='INNODB' and support != 'NO'); +-set @is_mysql_encrypted = (select ENCRYPTION from information_schema.INNODB_TABLESPACES where NAME='mysql'); +- +--- Tables below are NOT treated as DD tables by MySQL server yet. ++set @have_innodb=0; ++-- set @is_mysql_encrypted = (select ENCRYPTION from information_schema.CTC_TABLESPACES where NAME='mysql'); ++set @is_mysql_encrypted = 0; + + SET FOREIGN_KEY_CHECKS= 1; + +-# Added sql_mode elements and making it as SET, instead of ENUM +- +-set default_storage_engine=InnoDB; ++set default_storage_engine=CTC; + + SET @cmd = "CREATE TABLE IF NOT EXISTS db + ( +@@ -61,14 +32,14 @@ Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + Trigger_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + PRIMARY KEY Host (Host,Db,User), KEY User (User) + ) +-engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + +--- Remember for later if db table already existed + set @had_db_table= @@warning_count != 0; + + SET @cmd = "CREATE TABLE IF NOT EXISTS user +@@ -125,8 +96,9 @@ Password_reuse_time smallint unsigned NULL DEFAULT NULL, + Password_require_current enum('N', 'Y') COLLATE utf8_general_ci DEFAULT NULL, + User_attributes JSON DEFAULT NULL, + PRIMARY KEY Host (Host,User) +-) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Users and global privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -139,8 +111,9 @@ USER CHAR(32) BINARY DEFAULT '' NOT NULL, + DEFAULT_ROLE_HOST CHAR(255) CHARACTER SET ASCII DEFAULT '%' NOT NULL, + DEFAULT_ROLE_USER CHAR(32) BINARY DEFAULT '' NOT NULL, + PRIMARY KEY (HOST, USER, DEFAULT_ROLE_HOST, DEFAULT_ROLE_USER) +-) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Default roles' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Default roles' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -154,8 +127,9 @@ TO_HOST CHAR(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, + TO_USER CHAR(32) BINARY DEFAULT '' NOT NULL, + WITH_ADMIN_OPTION ENUM('N', 'Y') COLLATE UTF8_GENERAL_CI DEFAULT 'N' NOT NULL, + PRIMARY KEY (FROM_HOST,FROM_USER,TO_HOST,TO_USER) +-) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Role hierarchy and role grants' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Role hierarchy and role grants' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -168,14 +142,14 @@ HOST CHAR(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, + PRIV CHAR(32) COLLATE UTF8_GENERAL_CI DEFAULT '' NOT NULL, + WITH_GRANT_OPTION ENUM('N','Y') COLLATE UTF8_GENERAL_CI DEFAULT 'N' NOT NULL, + PRIMARY KEY (USER,HOST,PRIV) +-) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Extended global grants' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Extended global grants' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + +--- Remember for later if user table already existed + set @had_user_table= @@warning_count != 0; + + SET @cmd = "CREATE TABLE IF NOT EXISTS password_history +@@ -185,149 +159,162 @@ SET @cmd = "CREATE TABLE IF NOT EXISTS password_history + Password_timestamp TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), + Password TEXT, + PRIMARY KEY(Host, User, Password_timestamp DESC) +- ) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin ++ ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin + comment='Password history for user accounts' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS func ( name char(64) binary DEFAULT '' NOT NULL, ret tinyint DEFAULT '0' NOT NULL, dl char(128) DEFAULT '' NOT NULL, type enum ('function','aggregate') COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (name) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='User defined functions' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS func ( name char(64) binary DEFAULT '' NOT NULL, ret tinyint DEFAULT '0' NOT NULL, dl char(128) DEFAULT '' NOT NULL, type enum ('function','aggregate') COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='User defined functions' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS plugin ( name varchar(64) DEFAULT '' NOT NULL, dl varchar(128) DEFAULT '' NOT NULL, PRIMARY KEY (name) ) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_general_ci comment='MySQL plugins' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS plugin ( name varchar(64) DEFAULT '' NOT NULL, dl varchar(128) DEFAULT '' NOT NULL, PRIMARY KEY (name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_general_ci comment='MySQL plugins' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS help_topic ( help_topic_id int unsigned not null, name char(64) not null, help_category_id smallint unsigned not null, description text not null, example text not null, url text not null, primary key (help_topic_id), unique index (name) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help topics' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS help_topic ( help_topic_id int unsigned not null, name char(64) not null, help_category_id smallint unsigned not null, description text not null, example text not null, url text not null, primary key (help_topic_id), unique index (name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help topics' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS help_category ( help_category_id smallint unsigned not null, name char(64) not null, parent_category_id smallint unsigned null, url text not null, primary key (help_category_id), unique index (name) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help categories' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS help_category ( help_category_id smallint unsigned not null, name char(64) not null, parent_category_id smallint unsigned null, url text not null, primary key (help_category_id), unique index (name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help categories' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS help_relation ( help_topic_id int unsigned not null, help_keyword_id int unsigned not null, primary key (help_keyword_id, help_topic_id) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='keyword-topic relation' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS help_relation ( help_topic_id int unsigned not null, help_keyword_id int unsigned not null, primary key (help_keyword_id, help_topic_id) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='keyword-topic relation' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS servers ( Server_name char(64) NOT NULL DEFAULT '', Host char(255) CHARACTER SET ASCII NOT NULL DEFAULT '', Db char(64) NOT NULL DEFAULT '', Username char(64) NOT NULL DEFAULT '', Password char(64) NOT NULL DEFAULT '', Port INT NOT NULL DEFAULT '0', Socket char(64) NOT NULL DEFAULT '', Wrapper char(64) NOT NULL DEFAULT '', Owner char(64) NOT NULL DEFAULT '', PRIMARY KEY (Server_name)) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='MySQL Foreign Servers table' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS servers ( Server_name char(64) NOT NULL DEFAULT '', Host char(255) CHARACTER SET ASCII NOT NULL DEFAULT '', Db char(64) NOT NULL DEFAULT '', Username char(64) NOT NULL DEFAULT '', Password char(64) NOT NULL DEFAULT '', Port INT NOT NULL DEFAULT '0', Socket char(64) NOT NULL DEFAULT '', Wrapper char(64) NOT NULL DEFAULT '', Owner char(64) NOT NULL DEFAULT '', PRIMARY KEY (Server_name)) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='MySQL Foreign Servers table' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS tables_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name), KEY Grantor (Grantor) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Table privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS tables_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Table_priv set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name), KEY Grantor (Grantor) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Table privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS columns_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Column_name char(64) binary DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name,Column_name) ) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Column privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS columns_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Table_name char(64) binary DEFAULT '' NOT NULL, Column_name char(64) binary DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name,Column_name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Column privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS help_keyword ( help_keyword_id int unsigned not null, name char(64) not null, primary key (help_keyword_id), unique index (name) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help keywords' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS help_keyword ( help_keyword_id int unsigned not null, name char(64) not null, primary key (help_keyword_id), unique index (name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='help keywords' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_name ( Name char(64) NOT NULL, Time_zone_id int unsigned NOT NULL, PRIMARY KEY Name (Name) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone names' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_name ( Name char(64) NOT NULL, Time_zone_id int unsigned NOT NULL, PRIMARY KEY Name (Name) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone names' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone ( Time_zone_id int unsigned NOT NULL auto_increment, Use_leap_seconds enum('Y','N') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY TzId (Time_zone_id) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zones' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone ( Time_zone_id int unsigned NOT NULL auto_increment, Use_leap_seconds enum('Y','N') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY TzId (Time_zone_id) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zones' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_transition ( Time_zone_id int unsigned NOT NULL, Transition_time bigint signed NOT NULL, Transition_type_id int unsigned NOT NULL, PRIMARY KEY TzIdTranTime (Time_zone_id, Transition_time) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone transitions' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_transition ( Time_zone_id int unsigned NOT NULL, Transition_time bigint signed NOT NULL, Transition_type_id int unsigned NOT NULL, PRIMARY KEY TzIdTranTime (Time_zone_id, Transition_time) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone transitions' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_transition_type ( Time_zone_id int unsigned NOT NULL, Transition_type_id int unsigned NOT NULL, Offset int signed DEFAULT 0 NOT NULL, Is_DST tinyint unsigned DEFAULT 0 NOT NULL, Abbreviation char(8) DEFAULT '' NOT NULL, PRIMARY KEY TzIdTrTId (Time_zone_id, Transition_type_id) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone transition types' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_transition_type ( Time_zone_id int unsigned NOT NULL, Transition_type_id int unsigned NOT NULL, Offset int signed DEFAULT 0 NOT NULL, Is_DST tinyint unsigned DEFAULT 0 NOT NULL, Abbreviation char(8) DEFAULT '' NOT NULL, PRIMARY KEY TzIdTrTId (Time_zone_id, Transition_type_id) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Time zone transition types' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime (Transition_time) ) engine=INNODB STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Leap seconds information for time zones' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS time_zone_leap_second ( Transition_time bigint signed NOT NULL, Correction int signed NOT NULL, PRIMARY KEY TranTime (Transition_time) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 comment='Leap seconds information for time zones' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS procs_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS procs_priv ( Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Routine_name char(64) COLLATE utf8_general_ci DEFAULT '' NOT NULL, Routine_type enum('FUNCTION','PROCEDURE') NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (Host,Db,User,Routine_name,Routine_type), KEY Grantor (Grantor) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + +--- bug#92988: Temporarily turn off sql_require_primary_key for the +--- next 2 tables as this is not necessary as they do not replicate. + SET @old_sql_require_primary_key = @@session.sql_require_primary_key; + SET @@session.sql_require_primary_key = 0; + +--- Create general_log +-CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host MEDIUMTEXT NOT NULL, thread_id BIGINT UNSIGNED NOT NULL, server_id INTEGER UNSIGNED NOT NULL, command_type VARCHAR(64) NOT NULL, argument MEDIUMBLOB NOT NULL) engine=CSV CHARACTER SET utf8 comment="General log"; ++CREATE TABLE IF NOT EXISTS general_log (event_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host MEDIUMTEXT NOT NULL, thread_id BIGINT UNSIGNED NOT NULL, server_id INTEGER UNSIGNED NOT NULL, command_type VARCHAR(64) NOT NULL, argument MEDIUMBLOB NOT NULL) engine=CTC CHARACTER SET utf8 comment="General log"; + +--- Create slow_log +-CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host MEDIUMTEXT NOT NULL, query_time TIME(6) NOT NULL, lock_time TIME(6) NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512) NOT NULL, last_insert_id INTEGER NOT NULL, insert_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, sql_text MEDIUMBLOB NOT NULL, thread_id BIGINT UNSIGNED NOT NULL) engine=CSV CHARACTER SET utf8 comment="Slow log"; ++CREATE TABLE IF NOT EXISTS slow_log (start_time TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), user_host MEDIUMTEXT NOT NULL, query_time TIME(6) NOT NULL, lock_time TIME(6) NOT NULL, rows_sent INTEGER NOT NULL, rows_examined INTEGER NOT NULL, db VARCHAR(512) NOT NULL, last_insert_id INTEGER NOT NULL, insert_id INTEGER NOT NULL, server_id INTEGER UNSIGNED NOT NULL, sql_text MEDIUMBLOB NOT NULL, thread_id BIGINT UNSIGNED NOT NULL) engine=CTC CHARACTER SET utf8 comment="Slow log"; + + SET @@session.sql_require_primary_key = @old_sql_require_primary_key; + +-SET @cmd = "CREATE TABLE IF NOT EXISTS component ( component_id int unsigned NOT NULL AUTO_INCREMENT, component_group_id int unsigned NOT NULL, component_urn text NOT NULL, PRIMARY KEY (component_id)) engine=INNODB DEFAULT CHARSET=utf8 COMMENT 'Components' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS component ( component_id int unsigned NOT NULL AUTO_INCREMENT, component_group_id int unsigned NOT NULL, component_urn text NOT NULL, PRIMARY KEY (component_id)) engine=CTC DEFAULT CHARSET=utf8 COMMENT 'Components' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -351,7 +338,7 @@ SET @cmd="CREATE TABLE IF NOT EXISTS slave_relay_log_info ( + Assign_gtids_to_anonymous_transactions_value TEXT CHARACTER SET utf8 COLLATE utf8_bin COMMENT 'Indicates the UUID used while generating GTIDs for anonymous transactions', + PRIMARY KEY(Channel_name)) DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT 'Relay Log Information'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -391,7 +378,7 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS slave_master_info ( + Source_connection_auto_failover BOOLEAN NOT NULL DEFAULT FALSE COMMENT 'Indicates whether the channel connection failover is enabled.', + PRIMARY KEY(Channel_name)) DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT 'Master Information'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -412,7 +399,7 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS slave_worker_info ( + Channel_name CHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'The channel on which the slave is connected to a source. Used in Multisource Replication', + PRIMARY KEY(Channel_name, Id)) DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT 'Worker Information'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -423,12 +410,11 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS gtid_executed ( + interval_end BIGINT NOT NULL COMMENT 'Last number of interval.', + PRIMARY KEY(source_uuid, interval_start)) STATS_PERSISTENT=0"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + +--- replication_asynchronous_connection_failover table + SET @cmd= "CREATE TABLE IF NOT EXISTS replication_asynchronous_connection_failover ( + Channel_name CHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'The replication channel name that connects source and replica.', + Host CHAR(255) CHARACTER SET ASCII NOT NULL COMMENT 'The source hostname that the replica will attempt to switch over the replication connection to in case of a failure.', +@@ -438,12 +424,11 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS replication_asynchronous_connection_failov + Managed_name CHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The name of the group which this server belongs to.', + PRIMARY KEY(Channel_name, Host, Port, Network_namespace, Managed_name), KEY(Channel_name, Managed_name)) DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT 'The source configuration details'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + +--- replication_asynchronous_connection_failover_managed table + SET @cmd= "CREATE TABLE IF NOT EXISTS replication_asynchronous_connection_failover_managed ( + Channel_name CHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'The replication channel name that connects source and replica.', + Managed_name CHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'The name of the source which needs to be managed.', +@@ -451,12 +436,11 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS replication_asynchronous_connection_failov + Configuration JSON DEFAULT NULL COMMENT 'The data to help manage group. For Managed_type = GroupReplication, Configuration value should contain {\"Primary_weight\": 80, \"Secondary_weight\": 60}, so that it assigns weight=80 to PRIMARY of the group, and weight=60 for rest of the members in mysql.replication_asynchronous_connection_failover table.', + PRIMARY KEY(Channel_name, Managed_name)) DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 COMMENT 'The managed source configuration details'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + +--- replication_group_member_actions + SET @cmd= "CREATE TABLE IF NOT EXISTS replication_group_member_actions ( + name CHAR(255) CHARACTER SET ASCII NOT NULL COMMENT 'The action name.', + event CHAR(64) CHARACTER SET ASCII NOT NULL COMMENT 'The event that will trigger the action.', +@@ -466,30 +450,21 @@ SET @cmd= "CREATE TABLE IF NOT EXISTS replication_group_member_actions ( + error_handling CHAR(64) CHARACTER SET ASCII NOT NULL COMMENT 'On errors during the action will be handled: IGNORE, CRITICAL.', + PRIMARY KEY(name, event), KEY(event)) DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0 COMMENT 'The member actions configuration.'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + +--- replication_group_configuration_version + SET @cmd= "CREATE TABLE IF NOT EXISTS replication_group_configuration_version ( + name CHAR(255) CHARACTER SET ASCII NOT NULL COMMENT 'The configuration name.', + version BIGINT UNSIGNED NOT NULL COMMENT 'The version of the configuration name.', + PRIMARY KEY(name)) DEFAULT CHARSET=utf8mb4 STATS_PERSISTENT=0 COMMENT 'The group configuration version.'"; + +-SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= INNODB ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= MYISAM')); ++SET @str=IF(@have_innodb <> 0, CONCAT(@cmd, ' ENGINE= CTC ROW_FORMAT=DYNAMIC TABLESPACE=mysql ENCRYPTION=\'', @is_mysql_encrypted,'\''), CONCAT(@cmd, ' ENGINE= CTC')); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + +--- +--- Optimizer Cost Model configuration +--- (Note: Column definition for default_value needs to be updated when a +--- default value is changed). +--- +- +--- Server cost constants +- + SET @cmd = "CREATE TABLE IF NOT EXISTS server_cost ( + cost_name VARCHAR(64) NOT NULL, + cost_value FLOAT DEFAULT NULL, +@@ -506,8 +481,9 @@ SET @cmd = "CREATE TABLE IF NOT EXISTS server_cost ( + ELSE NULL + END) VIRTUAL, + PRIMARY KEY (cost_name) +-) ENGINE=InnoDB CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) ENGINE=CTC CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -518,7 +494,6 @@ INSERT IGNORE INTO server_cost(cost_name) VALUES + ("memory_temptable_create_cost"), ("memory_temptable_row_cost"), + ("disk_temptable_create_cost"), ("disk_temptable_row_cost"); + +--- Engine cost constants + + SET @cmd = "CREATE TABLE IF NOT EXISTS engine_cost ( + engine_name VARCHAR(64) NOT NULL, +@@ -534,8 +509,9 @@ SET @cmd = "CREATE TABLE IF NOT EXISTS engine_cost ( + ELSE NULL + END) VIRTUAL, + PRIMARY KEY (cost_name, engine_name, device_type) +-) ENGINE=InnoDB CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++) ENGINE=CTC CHARACTER SET=utf8 COLLATE=utf8_general_ci STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +@@ -546,23 +522,19 @@ INSERT IGNORE INTO engine_cost(engine_name, device_type, cost_name) VALUES + ("default", 0, "io_block_read_cost"); + + +-SET @cmd = "CREATE TABLE IF NOT EXISTS proxies_priv (Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Proxied_host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Proxied_user char(32) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY Host (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=InnoDB STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='User proxy privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @cmd = "CREATE TABLE IF NOT EXISTS proxies_priv (Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, User char(32) binary DEFAULT '' NOT NULL, Proxied_host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, Proxied_user char(32) binary DEFAULT '' NOT NULL, With_grant BOOL DEFAULT 0 NOT NULL, Grantor varchar(288) DEFAULT '' NOT NULL, Timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY Host (Host,User,Proxied_host,Proxied_user), KEY Grantor (Grantor) ) engine=CTC STATS_PERSISTENT=0 CHARACTER SET utf8 COLLATE utf8_bin comment='User proxy privileges' ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; + + +--- Remember for later if proxies_priv table already existed + set @had_proxies_priv_table= @@warning_count != 0; + + +--- +--- Only create the ndb_binlog_index table if the server is built with ndb. +--- Create this table last among the tables in the mysql schema to make it +--- easier to keep tests agnostic wrt. the existence of this table. +--- +-SET @have_ndb= (select count(engine) from information_schema.engines where engine='ndbcluster'); ++-- SET @have_ndb= (select count(engine) from information_schema.engines where engine='ndbcluster'); ++SET @have_ndb= 0; + SET @cmd="CREATE TABLE IF NOT EXISTS ndb_binlog_index ( + Position BIGINT UNSIGNED NOT NULL, + File VARCHAR(255) NOT NULL, +@@ -577,9 +549,10 @@ SET @cmd="CREATE TABLE IF NOT EXISTS ndb_binlog_index ( + next_position BIGINT UNSIGNED NOT NULL, + next_file VARCHAR(255) NOT NULL, + PRIMARY KEY(epoch, orig_server_id, orig_epoch) +- ) ENGINE=INNODB CHARACTER SET latin1 STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; ++ ) ENGINE=CTC CHARACTER SET latin1 STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC TABLESPACE=mysql"; + +-SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++-- SET @str = CONCAT(@cmd, " ENCRYPTION='", @is_mysql_encrypted, "'"); ++SET @str = @cmd; + SET @str = IF(@have_ndb = 1, @str, 'SET @dummy = 0'); + PREPARE stmt FROM @str; + EXECUTE stmt; +diff --git a/scripts/mysql_system_tables_fix.sql b/scripts/mysql_system_tables_fix.sql +index 79cf2fc..39b7137 100644 +--- a/scripts/mysql_system_tables_fix.sql ++++ b/scripts/mysql_system_tables_fix.sql +@@ -30,7 +30,7 @@ + # Warning message(s) produced for a statement can be printed by explicitly + # adding a 'SHOW WARNINGS' after the statement. + +-set default_storage_engine=InnoDB; ++set default_storage_engine=CTC; + + # We meed to turn off the default strict mode in case legacy data contains e.g. + # zero dates ('0000-00-00-00:00:00'), otherwise, we risk to end up with +@@ -157,7 +157,7 @@ ADD max_connections int unsigned NOT NULL DEFAULT 0 AFTER max_updates; + # + ALTER TABLE proxies_priv MODIFY User char(32) binary DEFAULT '' NOT NULL; + ALTER TABLE proxies_priv MODIFY Proxied_user char(32) binary DEFAULT '' NOT NULL; +-ALTER TABLE proxies_priv MODIFY Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, ENGINE=InnoDB; ++ALTER TABLE proxies_priv MODIFY Host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL, ENGINE=CTC; + ALTER TABLE proxies_priv MODIFY Proxied_host char(255) CHARACTER SET ASCII DEFAULT '' NOT NULL; + ALTER TABLE proxies_priv MODIFY Grantor varchar(288) DEFAULT '' NOT NULL; + +@@ -946,7 +946,7 @@ EXECUTE stmt; + DROP PREPARE stmt; + + SET @cmd="ALTER TABLE ndb_binlog_index +- ENGINE=InnoDB STATS_PERSISTENT=0"; ++ ENGINE=CTC STATS_PERSISTENT=0"; + + SET @str = IF(@have_ndb_binlog_index = 1, @cmd, 'SET @dummy = 0'); + PREPARE stmt FROM @str; +@@ -999,29 +999,29 @@ ALTER TABLE help_relation CONVERT TO CHARACTER SET utf8; + ALTER TABLE help_keyword CONVERT TO CHARACTER SET utf8; + + -- +--- Upgrade a table engine from MyISAM to InnoDB for the system tables ++-- Upgrade a table engine from MyISAM to CTC for the system tables + -- help_topic, help_category, help_relation, help_keyword, plugin, servers, + -- time_zone, time_zone_leap_second, time_zone_name, time_zone_transition, + -- time_zone_transition_type, columns_priv, db, procs_priv, proxies_priv, + -- tables_priv, user. +-ALTER TABLE func ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE help_topic ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE help_category ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE help_relation ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE help_keyword ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE plugin ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE servers ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE time_zone ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE time_zone_leap_second ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE time_zone_name ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE time_zone_transition ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE time_zone_transition_type ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE db ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE user ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE tables_priv ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE columns_priv ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE procs_priv ENGINE=InnoDB STATS_PERSISTENT=0; +-ALTER TABLE proxies_priv ENGINE=InnoDB STATS_PERSISTENT=0; ++ALTER TABLE func ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE help_topic ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE help_category ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE help_relation ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE help_keyword ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE plugin ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE servers ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE time_zone ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE time_zone_leap_second ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE time_zone_name ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE time_zone_transition ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE time_zone_transition_type ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE db ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE user ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE tables_priv ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE columns_priv ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE procs_priv ENGINE=CTC STATS_PERSISTENT=0; ++ALTER TABLE proxies_priv ENGINE=CTC STATS_PERSISTENT=0; + + -- + -- CREATE_ROLE_ACL and DROP_ROLE_ACL +@@ -1042,13 +1042,13 @@ ALTER TABLE user MODIFY Password_require_current enum('N','Y') COLLATE utf8_gene + ALTER TABLE user ADD User_attributes JSON DEFAULT NULL AFTER Password_require_current; + + -- +--- Change engine of the firewall tables to InnoDB ++-- Change engine of the firewall tables to CTC + -- + SET @had_firewall_whitelist = + (SELECT COUNT(table_name) FROM information_schema.tables + WHERE table_schema = 'mysql' AND table_name = 'firewall_whitelist' AND + table_type = 'BASE TABLE'); +-SET @cmd="ALTER TABLE mysql.firewall_whitelist ENGINE=InnoDB"; ++SET @cmd="ALTER TABLE mysql.firewall_whitelist ENGINE=CTC"; + SET @str = IF(@had_firewall_whitelist > 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; +@@ -1064,7 +1064,7 @@ SET @had_firewall_users = + (SELECT COUNT(table_name) FROM information_schema.tables + WHERE table_schema = 'mysql' AND table_name = 'firewall_users' AND + table_type = 'BASE TABLE'); +-SET @cmd="ALTER TABLE mysql.firewall_users ENGINE=InnoDB"; ++SET @cmd="ALTER TABLE mysql.firewall_users ENGINE=CTC"; + SET @str = IF(@had_firewall_users > 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; +@@ -1100,17 +1100,17 @@ SET @had_group_allowlist = + (SELECT COUNT(table_name) FROM information_schema.tables + WHERE table_schema = 'mysql' AND table_name = 'firewall_group_allowlist' AND + table_type = 'BASE TABLE'); +-SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_group_allowlist(NAME VARCHAR(288) NOT NULL, RULE text NOT NULL, ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) engine= InnoDB"; ++SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_group_allowlist(NAME VARCHAR(288) NOT NULL, RULE text NOT NULL, ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY) engine= CTC"; + SET @str = IF(@had_user_allowlist > 0 AND @had_group_allowlist = 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +-SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_groups(NAME VARCHAR(288) PRIMARY KEY, MODE ENUM ('OFF', 'RECORDING', 'PROTECTING', 'DETECTING') DEFAULT 'OFF', USERHOST VARCHAR(288)) engine= InnoDB"; ++SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_groups(NAME VARCHAR(288) PRIMARY KEY, MODE ENUM ('OFF', 'RECORDING', 'PROTECTING', 'DETECTING') DEFAULT 'OFF', USERHOST VARCHAR(288)) engine= CTC"; + SET @str = IF(@had_user_allowlist > 0 AND @had_group_allowlist = 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; + DROP PREPARE stmt; +-SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_membership(GROUP_ID VARCHAR(288), MEMBER_ID VARCHAR(288)) engine= InnoDB"; ++SET @cmd="CREATE TABLE IF NOT EXISTS mysql.firewall_membership(GROUP_ID VARCHAR(288), MEMBER_ID VARCHAR(288)) engine= CTC"; + SET @str = IF(@had_user_allowlist > 0 AND @had_group_allowlist = 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; +@@ -1144,7 +1144,7 @@ SET @had_audit_log_filter = + (SELECT COUNT(table_name) FROM information_schema.tables + WHERE table_schema = 'mysql' AND table_name = 'audit_log_filter' AND + table_type = 'BASE TABLE'); +-SET @cmd="ALTER TABLE mysql.audit_log_filter ENGINE=InnoDB"; ++SET @cmd="ALTER TABLE mysql.audit_log_filter ENGINE=CTC"; + SET @str = IF(@had_audit_log_filter > 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; +@@ -1160,7 +1160,7 @@ SET @had_audit_log_user = + (SELECT COUNT(table_name) FROM information_schema.tables + WHERE table_schema = 'mysql' AND table_name = 'audit_log_user' AND + table_type = 'BASE TABLE'); +-SET @cmd="ALTER TABLE mysql.audit_log_user ENGINE=InnoDB"; ++SET @cmd="ALTER TABLE mysql.audit_log_user ENGINE=CTC"; + SET @str = IF(@had_audit_log_user > 0, @cmd, "SET @dummy = 0"); + PREPARE stmt FROM @str; + EXECUTE stmt; +@@ -1266,7 +1266,7 @@ INSERT IGNORE INTO mysql.global_grants VALUES ('mysql.session', 'localhost', 'CO + # upgrade. + INSERT IGNORE INTO mysql.global_grants VALUES ('mysql.session', 'localhost', 'SYSTEM_USER', 'N'); + +-# Move all system tables with InnoDB storage engine to mysql tablespace. ++# Move all system tables with CTC storage engine to mysql tablespace. + SET @cmd="ALTER TABLE mysql.db TABLESPACE = mysql"; + PREPARE stmt FROM @cmd; + EXECUTE stmt; +diff --git a/scripts/sys_schema/functions/format_path.sql b/scripts/sys_schema/functions/format_path.sql +index 100fd59..41c8bf3 100644 +--- a/scripts/sys_schema/functions/format_path.sql ++++ b/scripts/sys_schema/functions/format_path.sql +@@ -92,10 +92,10 @@ BEGIN + SET v_path = REPLACE(v_path, @@global.tmpdir, CONCAT('@@tmpdir', IF(SUBSTRING(@@global.tmpdir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(@@global.replica_load_tmpdir, IF(SUBSTRING(@@global.replica_load_tmpdir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, @@global.replica_load_tmpdir, CONCAT('@@replica_load_tmpdir', IF(SUBSTRING(@@global.replica_load_tmpdir, -1) = path_separator, path_separator, ''))); +- ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN +- SET v_path = REPLACE(v_path, @@global.innodb_data_home_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, path_separator, ''))); +- ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN +- SET v_path = REPLACE(v_path, @@global.innodb_log_group_home_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, path_separator, ''))); ++-- ELSEIF v_path LIKE CONCAT(@@global.innodb_data_home_dir, IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN ++-- SET v_path = REPLACE(v_path, @@global.innodb_data_home_dir, CONCAT('@@innodb_data_home_dir', IF(SUBSTRING(@@global.innodb_data_home_dir, -1) = path_separator, path_separator, ''))); ++-- ELSEIF v_path LIKE CONCAT(@@global.innodb_log_group_home_dir, IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN ++-- SET v_path = REPLACE(v_path, @@global.innodb_log_group_home_dir, CONCAT('@@innodb_log_group_home_dir', IF(SUBSTRING(@@global.innodb_log_group_home_dir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(v_undo_dir, IF(SUBSTRING(v_undo_dir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN + SET v_path = REPLACE(v_path, v_undo_dir, CONCAT('@@innodb_undo_directory', IF(SUBSTRING(v_undo_dir, -1) = path_separator, path_separator, ''))); + ELSEIF v_path LIKE CONCAT(@@global.basedir, IF(SUBSTRING(@@global.basedir, -1) = path_separator, '%', CONCAT(path_separator, '%'))) ESCAPE '|' THEN +diff --git a/scripts/sys_schema/procedures/diagnostics.sql b/scripts/sys_schema/procedures/diagnostics.sql +index 2f81086..75e61ef 100644 +--- a/scripts/sys_schema/procedures/diagnostics.sql ++++ b/scripts/sys_schema/procedures/diagnostics.sql +@@ -719,7 +719,7 @@ BEGIN + Type VARCHAR(225) NOT NULL, + Enabled ENUM(''YES'', ''NO'', ''PARTIAL'') NOT NULL, + PRIMARY KEY (Type, Variable_name) +-) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4')); ++) ENGINE = MyISAM DEFAULT CHARSET=utf8mb4')); + + SET @sys.diagnostics.sql = CONCAT( + 'INSERT INTO ', v_table_name, +diff --git a/scripts/sys_schema/procedures/statement_performance_analyzer.sql b/scripts/sys_schema/procedures/statement_performance_analyzer.sql +index d1726d5..0e2650a 100644 +--- a/scripts/sys_schema/procedures/statement_performance_analyzer.sql ++++ b/scripts/sys_schema/procedures/statement_performance_analyzer.sql +@@ -541,7 +541,7 @@ SELECT `d_end`.`SCHEMA_NAME`, + cnt bigint unsigned NOT NULL, + avg_us decimal(21,0) NOT NULL, + PRIMARY KEY (avg_us) +- ) ENGINE=InnoDB; ++ ) ENGINE=MyISAM; + + SET v_sql = CONCAT('INSERT INTO tmp_digest_avg_latency_distribution1 + SELECT COUNT(*) cnt, +@@ -557,7 +557,7 @@ SELECT COUNT(*) cnt, + avg_us decimal(21,0) NOT NULL, + percentile decimal(46,4) NOT NULL, + PRIMARY KEY (avg_us) +- ) ENGINE=InnoDB; ++ ) ENGINE=MyISAM; + + SET v_sql = CONCAT('INSERT INTO tmp_digest_95th_percentile_by_avg_us + SELECT s2.avg_us avg_us, +diff --git a/scripts/sys_schema/tables/sys_config.sql b/scripts/sys_schema/tables/sys_config.sql +index a4e48c5..459dc61 100644 +--- a/scripts/sys_schema/tables/sys_config.sql ++++ b/scripts/sys_schema/tables/sys_config.sql +@@ -24,4 +24,4 @@ CREATE TABLE IF NOT EXISTS sys_config ( + value VARCHAR(128), + set_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + set_by VARCHAR(128) +-) ENGINE = InnoDB; ++) ENGINE = CTC; diff --git a/mysql-test/mysql-source-code-meta.patch b/mysql-test/mysql-source-code-meta.patch new file mode 100644 index 0000000..bca8773 --- /dev/null +++ b/mysql-test/mysql-source-code-meta.patch @@ -0,0 +1,3501 @@ +diff --git a/sql/auth/acl_table_user.cc b/sql/auth/acl_table_user.cc +index f9846bd..fda3f0e 100644 +--- a/sql/auth/acl_table_user.cc ++++ b/sql/auth/acl_table_user.cc +@@ -1393,9 +1393,14 @@ void Acl_table_user_reader::read_account_name(ACL_USER &user) { + bool Acl_table_user_reader::read_authentication_string(ACL_USER &user) { + /* Read password from authentication_string field */ + if (m_table->s->fields > m_table_schema->authentication_string_idx()) { +- user.credentials[PRIMARY_CRED].m_auth_string.str = +- get_field(&m_mem_root, +- m_table->field[m_table_schema->authentication_string_idx()]); ++ if (m_table->field[m_table_schema->authentication_string_idx()]->is_null()) { ++ user.credentials[PRIMARY_CRED].m_auth_string.str = nullptr; ++ } ++ else { ++ user.credentials[PRIMARY_CRED].m_auth_string.str = ++ get_field(&m_mem_root, ++ m_table->field[m_table_schema->authentication_string_idx()]); ++ } + } else { + LogErr(ERROR_LEVEL, ER_AUTHCACHE_USER_TABLE_DODGY); + return true; +diff --git a/sql/auth/dynamic_privilege_table.cc b/sql/auth/dynamic_privilege_table.cc +index a4216d0..f8c4c1e 100644 +--- a/sql/auth/dynamic_privilege_table.cc ++++ b/sql/auth/dynamic_privilege_table.cc +@@ -228,7 +228,7 @@ bool modify_dynamic_privileges_in_table(THD *thd, TABLE *table, + /* If the key didn't exist the record is already gone and all is well. */ + return false; + } +- } else if (ret == HA_ERR_KEY_NOT_FOUND && !delete_option) { ++ } else if ((ret == HA_ERR_KEY_NOT_FOUND || ret == HA_ERR_END_OF_FILE) && !delete_option) { + /* Insert new edge into table */ + DBUG_PRINT("note", + ("Insert dynamic privilege %s for `%s`@`%s` %s", privilege.str, +diff --git a/sql/auth/sql_user_table.cc b/sql/auth/sql_user_table.cc +index 112d255..9c166bd 100644 +--- a/sql/auth/sql_user_table.cc ++++ b/sql/auth/sql_user_table.cc +@@ -1060,7 +1060,7 @@ int replace_proxies_priv_table(THD *thd, TABLE *table, const LEX_USER *user, + } + } else { + error = table->file->ha_write_row(table->record[0]); +- assert(error != HA_ERR_FOUND_DUPP_KEY); ++ //assert(error != HA_ERR_FOUND_DUPP_KEY); + assert(table->file->ht->db_type == DB_TYPE_NDBCLUSTER || + error != HA_ERR_LOCK_DEADLOCK); + assert(table->file->ht->db_type == DB_TYPE_NDBCLUSTER || +diff --git a/sql/bootstrap.cc b/sql/bootstrap.cc +index 785fa78..fb5be6f 100644 +--- a/sql/bootstrap.cc ++++ b/sql/bootstrap.cc +@@ -198,6 +198,7 @@ static int process_iterator(THD *thd, Command_iterator *it, + int rc; + + rc = it->next(query); ++ printf("query: %s\n", query.c_str()); + + if (rc == READ_BOOTSTRAP_EOF) { + break; +diff --git a/sql/composite_iterators.cc b/sql/composite_iterators.cc +index 43c59a1..4f6b8d4 100644 +--- a/sql/composite_iterators.cc ++++ b/sql/composite_iterators.cc +@@ -859,7 +859,9 @@ bool MaterializeIterator::MaterializeQueryBlock(const QueryBlock &query_block, + // so they'll need to reposition themselves. + for (const QueryBlock &query_b : m_query_blocks_to_materialize) { + if (query_b.is_recursive_reference) { +- query_b.recursive_reader->RepositionCursorAfterSpillToDisk(); ++ if (query_b.recursive_reader->RepositionCursorAfterSpillToDisk()) { ++ return true; ++ } + } + } + } else { +diff --git a/sql/dd/cache/dictionary_client.h b/sql/dd/cache/dictionary_client.h +index dbd6c18..4666753 100644 +--- a/sql/dd/cache/dictionary_client.h ++++ b/sql/dd/cache/dictionary_client.h +@@ -472,6 +472,9 @@ class Dictionary_client { + void remove_uncommitted_objects(bool commit_to_shared_cache); + + template ++ void add_modified_objects(); ++ ++ template + using Const_ptr_vec = std::vector; + + /** +@@ -1180,6 +1183,13 @@ class Dictionary_client { + @retval true There was an error. + */ + ++ /** ++ Refer to remove_uncommitted_objects(). Uncommitted objects has been added to invalidate list ++ before commit. Only drop cache and remove element from committed registry included. ++ */ ++ template ++ void invalidate_after_commit(const T *object); ++ + template + bool drop(const T *object) MY_ATTRIBUTE((warn_unused_result)); + +@@ -1261,6 +1271,7 @@ class Dictionary_client { + */ + + void commit_modified_objects(); ++ void add_modified_objects_before_commit(); + + /** + Remove table statistics entries from mysql.table_stats and +diff --git a/sql/dd/dd_table.cc b/sql/dd/dd_table.cc +index 7bf60f4..7be1743 100644 +--- a/sql/dd/dd_table.cc ++++ b/sql/dd/dd_table.cc +@@ -2322,7 +2322,7 @@ static std::unique_ptr create_dd_system_table( + } + + // Register the se private id with the DDSE. +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->dict_register_dd_table_id == nullptr) return nullptr; + ddse->dict_register_dd_table_id(tab_obj->se_private_id()); + +diff --git a/sql/dd/dd_tablespace.cc b/sql/dd/dd_tablespace.cc +index 2c97cb3..0d5b05b 100644 +--- a/sql/dd/dd_tablespace.cc ++++ b/sql/dd/dd_tablespace.cc +@@ -53,6 +53,7 @@ + #include "sql/sql_servers.h" + #include "sql/sql_table.h" // validate_comment_length + #include "sql/table.h" ++#include + + namespace { + template +@@ -154,7 +155,6 @@ bool get_tablespace_name(THD *thd, const T *obj, String_type *name) { + // Read Tablespace + // + assert(name->empty()); +- + if (obj->tablespace_id() == Dictionary_impl::dd_tablespace_id()) { + // If this is the DD tablespace id, then we use its name. + *name = MYSQL_TABLESPACE_NAME.str; +diff --git a/sql/dd/dd_utility.cc b/sql/dd/dd_utility.cc +index 7f9b9df..1d5575d 100644 +--- a/sql/dd/dd_utility.cc ++++ b/sql/dd/dd_utility.cc +@@ -62,7 +62,7 @@ bool check_if_server_ddse_readonly(THD *thd, const char *schema_name_abbrev) { + to retrieve the handlerton for the DDSE should be replaced by a more + generic mechanism. + */ +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->is_dict_readonly && ddse->is_dict_readonly()) { + LogErr(WARNING_LEVEL, ER_SKIP_UPDATING_METADATA_IN_SE_RO_MODE, + schema_name_abbrev); +diff --git a/sql/dd/impl/bootstrap/bootstrapper.cc b/sql/dd/impl/bootstrap/bootstrapper.cc +index d08718a..6440b0b 100644 +--- a/sql/dd/impl/bootstrap/bootstrapper.cc ++++ b/sql/dd/impl/bootstrap/bootstrapper.cc +@@ -81,7 +81,7 @@ namespace { + // Initialize recovery in the DDSE. + bool DDSE_dict_recover(THD *thd, dict_recovery_mode_t dict_recovery_mode, + uint version) { +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->dict_recover == nullptr) return true; + + bool error = ddse->dict_recover(dict_recovery_mode, version); +@@ -266,6 +266,9 @@ bool acquire_exclusive_mdl(THD *thd) { + reset ID, store persistently, and update the storage adapter. + */ + bool flush_meta_data(THD *thd) { ++ // Turn off FK checks, this is needed since we have cyclic FKs. ++ if (dd::execute_query(thd, "SET FOREIGN_KEY_CHECKS= 0")) return true; ++ + // Acquire exclusive meta data locks for the relevant DD objects. + if (acquire_exclusive_mdl(thd)) return true; + +@@ -573,6 +576,9 @@ bool flush_meta_data(THD *thd) { + if (persisted_dd_table != nullptr) delete persisted_dd_table; + } + ++ // Turn FK checks back on. ++ if (dd::execute_query(thd, "SET FOREIGN_KEY_CHECKS= 1")) return true; ++ + bootstrap::DD_bootstrap_ctx::instance().set_stage(bootstrap::Stage::SYNCED); + + return dd::end_transaction(thd, false); +@@ -580,6 +586,8 @@ bool flush_meta_data(THD *thd) { + + // Insert additional data into the DD tables. + bool populate_tables(THD *thd) { ++ // Turn off FK checks, this is needed since we have cyclic FKs. ++ if (dd::execute_query(thd, "SET FOREIGN_KEY_CHECKS= 0")) return true; + // Iterate over DD tables, populate tables. + for (System_tables::Const_iterator it = System_tables::instance()->begin(); + it != System_tables::instance()->end(); ++it) { +@@ -610,6 +618,9 @@ bool populate_tables(THD *thd) { + bootstrap::DD_bootstrap_ctx::instance().set_stage( + bootstrap::Stage::POPULATED); + ++ // Turn FK checks back on. ++ if (dd::execute_query(thd, "SET FOREIGN_KEY_CHECKS= 1")) return true; ++ + return false; + } + +@@ -621,7 +632,7 @@ bool repopulate_charsets_and_collations(THD *thd) { + to retrieve the handlerton for the DDSE should be replaced by a more + generic mechanism. + */ +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->is_dict_readonly && ddse->is_dict_readonly()) { + LogErr(WARNING_LEVEL, ER_DD_NO_WRITES_NO_REPOPULATION, "InnoDB", " "); + return false; +@@ -724,7 +735,7 @@ namespace bootstrap { + predefined tables and tablespaces. + */ + bool DDSE_dict_init(THD *thd, dict_init_mode_t dict_init_mode, uint version) { +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + + /* + The lists with element wrappers are mem root allocated. The wrapped +@@ -908,6 +919,10 @@ bool initialize(THD *thd) { + + // Normal server restart. + bool restart(THD *thd) { ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); ++ if (ddse->op_before_load_meta(thd) != 0) { ++ return true; ++ } + bootstrap::DD_bootstrap_ctx::instance().set_stage(bootstrap::Stage::STARTED); + + /* +@@ -946,7 +961,9 @@ bool restart(THD *thd) { + dd::execute_query(thd, "DROP SCHEMA schema_read_only") || + dd::execute_query(thd, "CREATE TABLE IF NOT EXISTS S.restart(i INT)")) + assert(false);); +- ++ if (ddse->op_after_load_meta(thd) != 0) { ++ return true; ++ } + bootstrap::DD_bootstrap_ctx::instance().set_stage(bootstrap::Stage::FINISHED); + LogErr(INFORMATION_LEVEL, ER_DD_VERSION_FOUND, d->get_actual_dd_version(thd)); + +@@ -1502,7 +1519,7 @@ bool sync_meta_data(THD *thd) { + return true; + + // Reset the DDSE local dictionary cache. +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->dict_cache_reset == nullptr) return true; + + for (System_tables::Const_iterator it = System_tables::instance()->begin(); +@@ -1797,7 +1814,7 @@ bool update_versions(THD *thd, bool is_dd_upgrade_57) { + back in case of an abort, so this better be the last step we + do before committing. + */ +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (bootstrap::DD_bootstrap_ctx::instance().is_server_upgrade()) { + if (ddse->dict_set_server_version == nullptr || + ddse->dict_set_server_version()) { +diff --git a/sql/dd/impl/cache/dictionary_client.cc b/sql/dd/impl/cache/dictionary_client.cc +index 8063806..c649fa5 100644 +--- a/sql/dd/impl/cache/dictionary_client.cc ++++ b/sql/dd/impl/cache/dictionary_client.cc +@@ -93,6 +93,7 @@ + #include "sql/mdl.h" + #include "sql/mysqld.h" + #include "sql/sql_class.h" // THD ++#include "sql/sql_lex.h" // LEX + #include "sql/sql_plugin_ref.h" + #include "sql/table.h" + #include "sql/tztime.h" // Time_zone, my_tz_OFFSET0 +@@ -359,6 +360,130 @@ class MDL_checker { + } + + public: ++ static void add_to_invalidate(THD *thd, const dd::Abstract_table *table) ++ { ++ dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); ++ const dd::Schema *schema = nullptr; ++ ++ // If the schema acquisition fails, we cannot assure that we have a lock, ++ // and therefore return false. ++ if (thd->dd_client()->acquire(table->schema_id(), &schema)) return; ++ ++ // Skip check for temporary tables. ++ if (!table || is_prefix(table->name().c_str(), tmp_file_prefix)) ++ return; ++ ++ // Likewise, if there is no schema, we cannot have a proper lock. ++ // This may in theory happen during bootstrapping since the meta data for ++ // the system schema is not stored yet; however, this is prevented by ++ // surrounding code calling this function only if ++ // '!thd->is_dd_system_thread' i.e., this is not a bootstrapping thread. ++ if (thd->is_dd_system_thread() || !schema) { ++ return; ++ } ++ ++ // We must take l_c_t_n into account when reconstructing the MDL key ++ // from the schema and table name, and we need buffers for this purpose. ++ //char table_name_buf[NAME_LEN + 1]; ++ char schema_name_buf[NAME_LEN + 1]; ++ ++ const char *table_name = table->name().c_str(); ++ const char *schema_name = dd::Object_table_definition_impl::fs_name_case( ++ schema->name(), schema_name_buf); ++ ++ thd->add(schema_name, table_name, THD::OBJ_ABSTRACT_TABLE); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Schema *schema) ++ { ++ if (thd->is_dd_system_thread() || !schema) { ++ return; ++ } ++ ++ char name_buf[NAME_LEN + 1]; ++ ++ const char *schema_name = dd::Object_table_definition_impl::fs_name_case(schema->name(), ++ name_buf); ++ thd->add(schema_name, "", THD::OBJ_SCHEMA); ++ ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Charset *charset) ++ { ++ (void(thd)); ++ (void(charset)); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Collation *collation) ++ { ++ (void(thd)); ++ (void(collation)); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Event *event) ++ { ++ (void(thd)); ++ (void(event)); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Routine *routine) ++ { ++ dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); ++ const dd::Schema *schema = nullptr; ++ ++ // If the schema acquisition fails, we cannot assure that we have a lock, ++ // and therefore return false. ++ if (thd->dd_client()->acquire(routine->schema_id(), &schema)) return; ++ ++ assert(schema); ++ ++ MDL_key mdl_key; ++ char schema_name_buf[NAME_LEN + 1]; ++ const char *schema_name = dd::Object_table_definition_impl::fs_name_case( ++ schema->name(), schema_name_buf); ++ const char *routine_name = routine->name().c_str(); ++ if (routine->type() == dd::Routine::RT_PROCEDURE) { ++ thd->add(schema_name, routine_name, THD::OBJ_RT_PROCEDURE); ++ } else { ++ thd->add(schema_name, routine_name, THD::OBJ_RT_FUNCTION); ++ } ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Resource_group *resource_group) ++ { ++ (void(thd)); ++ (void(resource_group)); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Spatial_reference_system *srs) ++ { ++ (void(thd)); ++ (void(srs)); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Tablespace *tablespace) ++ { ++ if (!tablespace) return; ++ ++ thd->add(tablespace->name().c_str(), "", THD::OBJ_TABLESPACE); ++ return; ++ } ++ ++ static void add_to_invalidate(THD *thd, const dd::Column_statistics *column_statistics) ++ { ++ (void(thd)); ++ (void(column_statistics)); ++ return; ++ } ++ + // Releasing arbitrary dictionary objects is not checked. + static bool is_release_locked(THD *, const dd::Entity_object *) { + return true; +@@ -2423,6 +2548,7 @@ bool Dictionary_client::invalidate(const String_type &schema_name, + + Auto_releaser releaser(this); + const Table *table; ++ // If target object is a View, table will be nullptr + if (acquire(schema_name, table_name, &table)) { + assert(m_thd->is_system_thread() || m_thd->killed || m_thd->is_error()); + return true; +@@ -2430,6 +2556,18 @@ bool Dictionary_client::invalidate(const String_type &schema_name, + + if (table != nullptr) { + invalidate(table); ++ return false; ++ } ++ ++ // If aquire table failed(refer to Dictionary_client::acquire()), try aquire view instead. ++ const View *view; ++ if (acquire(schema_name, table_name, &view)) { ++ assert(m_thd->is_system_thread() || m_thd->killed || m_thd->is_error()); ++ return true; ++ } ++ if (view != nullptr) { ++ invalidate(view); ++ return false; + } + + // Invalidation of a non-existing object is not treated as an error. +@@ -2458,16 +2596,44 @@ void Dictionary_client::invalidate(const T *object) { + m_registry_committed.get(id_key, &element); + + if (element) { ++ if (m_thd->query().str && std::string(m_thd->query().str) == "tse_mdl_thd_notify") { ++ } else { ++ MDL_checker::add_to_invalidate(m_thd, element->object()); ++ } ++ + // Remove the element from the chain of auto releasers. + (void)m_current_releaser->remove(element); + // Remove the element from the local registry. + m_registry_committed.remove(element); + // Remove the element from the cache, delete the wrapper and the object. + Shared_dictionary_cache::instance()->drop(element); +- } else ++ } else { + Shared_dictionary_cache::instance() + ->drop_if_present( + id_key); ++ } ++} ++ ++// Refer to remove_uncommitted_objects(). Uncommitted objects has been added to invalidate list before commit. ++template ++void Dictionary_client::invalidate_after_commit(const T *object) { ++ assert(MDL_checker::is_write_locked(m_thd, object)); ++ Cache_element *element = nullptr; ++ const typename T::Id_key id_key(object->id()); ++ m_registry_committed.get(id_key, &element); ++ ++ if (element) { ++ // Remove the element from the chain of auto releasers. ++ (void)m_current_releaser->remove(element); ++ // Remove the element from the local registry. ++ m_registry_committed.remove(element); ++ // Remove the element from the cache, delete the wrapper and the object. ++ Shared_dictionary_cache::instance()->drop(element); ++ } else { ++ Shared_dictionary_cache::instance() ++ ->drop_if_present( ++ id_key); ++ } + } + + #ifndef NDEBUG +@@ -2845,7 +3011,7 @@ void Dictionary_client::remove_uncommitted_objects( + dd::cache::Storage_adapter::instance()->core_update(it->second->object()); + + // Invalidate the entry in the shared cache (if present). +- invalidate(uncommitted_object); ++ invalidate_after_commit(uncommitted_object); + + #ifndef NDEBUG + // Make sure the uncommitted id is not present in the dropped registry. +@@ -2919,6 +3085,45 @@ void Dictionary_client::commit_modified_objects() { + remove_uncommitted_objects(true); + } + ++template ++void Dictionary_client::add_modified_objects() { ++#ifndef NDEBUG ++#endif ++ typename Multi_map_base::Const_iterator it; ++ for (it = m_registry_uncommitted.begin(); ++ it != m_registry_uncommitted.end(); ++ it++) { ++ typename T::Cache_partition *uncommitted_object = ++ const_cast(it->second->object()); ++ ++ // Invalidate the entry in the shared cache (if present). ++ Cache_element *element = nullptr; ++ const typename T::Id_key id_key(uncommitted_object->id()); ++ m_registry_committed.get(id_key, &element); ++ if (element) { ++ MDL_checker::add_to_invalidate(m_thd, element->object()); ++ } else if (m_thd->lex->sql_command == SQLCOM_CREATE_TRIGGER) { ++ MDL_checker::add_to_invalidate(m_thd, uncommitted_object); ++ } ++ } ++} ++ ++void Dictionary_client::add_modified_objects_before_commit() { ++ if (m_thd->query().str && std::string(m_thd->query().str) == "tse_mdl_thd_notify") { ++ return; ++ } ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++ add_modified_objects(); ++} ++ + // Debug dump of the client and its registry to stderr. + /* purecov: begin inspected */ + template +@@ -3028,6 +3233,7 @@ template bool Dictionary_client::acquire_for_modification(const String_type &, + Abstract_table **); + template void Dictionary_client::remove_uncommitted_objects( + bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::drop(const Abstract_table *); + template bool Dictionary_client::store(Abstract_table *); + template bool Dictionary_client::update(Abstract_table *); +@@ -3037,6 +3243,7 @@ template bool Dictionary_client::acquire(Object_id, dd::Charset const **); + template bool Dictionary_client::acquire_for_modification(Object_id, + dd::Charset **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::acquire(String_type const &, Charset const **); + template bool Dictionary_client::acquire(String_type const &, Schema const **); + template bool Dictionary_client::acquire_for_modification(String_type const &, +@@ -3052,6 +3259,7 @@ template bool Dictionary_client::acquire(Object_id, dd::Collation const **); + template bool Dictionary_client::acquire_for_modification(Object_id, + dd::Collation **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::acquire_uncached(Object_id, Collation **); + template bool Dictionary_client::acquire(const String_type &, + const Collation **); +@@ -3072,6 +3280,7 @@ template bool Dictionary_client::acquire_uncached_uncommitted( + template bool Dictionary_client::acquire_for_modification(const String_type &, + Schema **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + + template bool Dictionary_client::drop(const Schema *); + template bool Dictionary_client::store(Schema *); +@@ -3112,6 +3321,7 @@ template bool Dictionary_client::acquire_for_modification(const String_type &, + const String_type &, + Table **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects
(); + template bool Dictionary_client::drop(const Table *); + template bool Dictionary_client::store(Table *); + template bool Dictionary_client::update(Table *); +@@ -3131,6 +3341,7 @@ template bool Dictionary_client::acquire_uncached_uncommitted( + template bool Dictionary_client::acquire_for_modification(Object_id, + Tablespace **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::drop(const Tablespace *); + template bool Dictionary_client::store(Tablespace *); + template bool Dictionary_client::update(Tablespace *); +@@ -3149,6 +3360,7 @@ template bool Dictionary_client::acquire_for_modification(const String_type &, + const String_type &, + View **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::drop(const View *); + template bool Dictionary_client::store(View *); + template bool Dictionary_client::update(View *); +@@ -3159,6 +3371,7 @@ template bool Dictionary_client::acquire_uncached(Object_id, Event **); + template bool Dictionary_client::acquire(Object_id, const Event **); + template bool Dictionary_client::acquire_for_modification(Object_id, Event **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::acquire(const String_type &, + const String_type &, const Event **); + template bool Dictionary_client::acquire_for_modification(const String_type &, +@@ -3184,6 +3397,7 @@ template bool Dictionary_client::acquire(Object_id, const Procedure **); + template bool Dictionary_client::acquire_for_modification(Object_id, + Procedure **); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::acquire(const String_type &, + const String_type &, + const Procedure **); +@@ -3196,6 +3410,7 @@ template bool Dictionary_client::update(Procedure *); + + template bool Dictionary_client::drop(const Routine *); + template void Dictionary_client::remove_uncommitted_objects(bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::update(Routine *); + template bool Dictionary_client::is_user_definer(const LEX_USER &, + bool *) const; +@@ -3222,6 +3437,7 @@ template bool Dictionary_client::drop(const Resource_group *); + template bool Dictionary_client::store(Resource_group *); + template void Dictionary_client::remove_uncommitted_objects( + bool); ++template void Dictionary_client::add_modified_objects(); + template bool Dictionary_client::update(Resource_group *); + /** + @endcond +diff --git a/sql/dd/impl/dictionary_impl.cc b/sql/dd/impl/dictionary_impl.cc +index 7115491..790403f 100644 +--- a/sql/dd/impl/dictionary_impl.cc ++++ b/sql/dd/impl/dictionary_impl.cc +@@ -693,7 +693,7 @@ bool drop_native_table(THD *thd, const char *schema_name, + + bool reset_tables_and_tablespaces() { + Auto_THD thd; +- handlerton *ddse = ha_resolve_by_legacy_type(thd.thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd.thd, DB_TYPE_CTC); + + // Acquire transactional metadata locks and evict all cached objects. + if (dd::cache::Shared_dictionary_cache::reset_tables_and_tablespaces(thd.thd)) +diff --git a/sql/dd/impl/sdi.cc b/sql/dd/impl/sdi.cc +index ef5b920..276a34f 100644 +--- a/sql/dd/impl/sdi.cc ++++ b/sql/dd/impl/sdi.cc +@@ -608,6 +608,7 @@ bool store(THD *thd, const Table *tp) { + const Table &t = ptr_as_cref(tp); + handlerton *hton = resolve_hton(thd, t); + ++ return false; + return with_schema(thd, t.schema_id(), [&](const Schema &s) { + dd::Sdi_type sdi = serialize(thd, t, s.name()); + if (sdi.empty()) { +@@ -626,6 +627,8 @@ bool store(THD *thd, const Table *tp) { + + bool store(THD *thd, const Tablespace *ts) { + handlerton *hton = resolve_hton(thd, *ts); ++ ++ return false; + if (hton->sdi_set == nullptr) { + return false; // SDI api not supported + } +diff --git a/sql/dd/impl/tables/table_partitions.cc b/sql/dd/impl/tables/table_partitions.cc +index da7a46e..1555449 100644 +--- a/sql/dd/impl/tables/table_partitions.cc ++++ b/sql/dd/impl/tables/table_partitions.cc +@@ -88,7 +88,7 @@ Table_partitions::Table_partitions() { + "UNIQUE KEY(table_id, parent_partition_id, number)"); + m_target_def.add_index(INDEX_UK_ENGINE_SE_PRIVATE_ID, + "INDEX_UK_ENGINE_SE_PRIVATE_ID", +- "UNIQUE KEY(engine, se_private_id)"); ++ "KEY(engine, se_private_id)"); + m_target_def.add_index(INDEX_K_ENGINE, "INDEX_K_ENGINE", "KEY(engine)"); + m_target_def.add_index(INDEX_K_TABLESPACE_ID, "INDEX_K_TABLESPACE_ID", + "KEY(tablespace_id)"); +diff --git a/sql/dd/impl/tables/tables.cc b/sql/dd/impl/tables/tables.cc +index 77372a2..4ea7850 100644 +--- a/sql/dd/impl/tables/tables.cc ++++ b/sql/dd/impl/tables/tables.cc +@@ -168,7 +168,8 @@ Tables::Tables() { + "UNIQUE KEY (schema_id, name)"); + m_target_def.add_index(INDEX_UK_ENGINE_SE_PRIVATE_ID, + "INDEX_UK_ENGINE_SE_PRIVATE_ID", +- "UNIQUE KEY (engine, se_private_id)"); ++ // "UNIQUE KEY (engine, se_private_id)"); ++ "KEY (engine, se_private_id)"); + m_target_def.add_index(INDEX_K_ENGINE, "INDEX_K_ENGINE", "KEY(engine)"); + m_target_def.add_index(INDEX_K_COLLATION_ID, "INDEX_K_COLLATION_ID", + "KEY(collation_id)"); +diff --git a/sql/dd/impl/transaction_impl.h b/sql/dd/impl/transaction_impl.h +index f21b82a..86f9e59 100644 +--- a/sql/dd/impl/transaction_impl.h ++++ b/sql/dd/impl/transaction_impl.h +@@ -133,9 +133,13 @@ class Transaction_ro { + : otx(thd, TL_READ), m_thd(thd), m_kill_immunizer(thd) { + thd->begin_attachable_ro_transaction(); + thd->tx_isolation = isolation; ++ thd->is_reading_dd = true; + } + +- ~Transaction_ro() { m_thd->end_attachable_transaction(); } ++ ~Transaction_ro() { ++ m_thd->is_reading_dd = false; ++ m_thd->end_attachable_transaction(); ++ } + + Open_dictionary_tables_ctx otx; + +diff --git a/sql/dd/impl/types/object_table_impl.cc b/sql/dd/impl/types/object_table_impl.cc +index 4b2b7ba..fde262d 100644 +--- a/sql/dd/impl/types/object_table_impl.cc ++++ b/sql/dd/impl/types/object_table_impl.cc +@@ -37,7 +37,7 @@ Object_table_impl::Object_table_impl() + m_actual_def(), + m_hidden(true) { + m_target_def.add_option(static_cast(Common_option::ENGINE), "ENGINE", +- "ENGINE=INNODB"); ++ "ENGINE=CTC"); + m_target_def.add_option(static_cast(Common_option::CHARSET), "CHARSET", + "DEFAULT CHARSET=utf8"); + m_target_def.add_option(static_cast(Common_option::COLLATION), +diff --git a/sql/dd/impl/types/tablespace_impl.cc b/sql/dd/impl/types/tablespace_impl.cc +index 8880468..9cd1727 100644 +--- a/sql/dd/impl/types/tablespace_impl.cc ++++ b/sql/dd/impl/types/tablespace_impl.cc +@@ -179,14 +179,14 @@ bool Tablespace_impl::restore_attributes(const Raw_record &r) { + + bool Tablespace_impl::store_attributes(Raw_record *r) { + #ifndef NDEBUG +- if (my_strcasecmp(system_charset_info, "InnoDB", m_engine.c_str()) == 0) { +- /* Innodb can request for space rename during upgrade when options are not +- upgraded yet. */ +- assert(m_options.exists("encryption") || +- bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade()); +- } else { +- assert(!m_options.exists("encryption")); +- } ++ //if (my_strcasecmp(system_charset_info, "CTC", m_engine.c_str()) == 0) { ++ // /* Innodb can request for space rename during upgrade when options are not ++ // upgraded yet. */ ++ // assert(m_options.exists("encryption") || ++ // bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade()); ++ //} else { ++ // assert(!m_options.exists("encryption")); ++ //} + #endif + + // Store engine_attributes and secondary_engine_attributes only if +diff --git a/sql/dd/impl/upgrade/dd.cc b/sql/dd/impl/upgrade/dd.cc +index 065400f..da58b04 100644 +--- a/sql/dd/impl/upgrade/dd.cc ++++ b/sql/dd/impl/upgrade/dd.cc +@@ -1155,7 +1155,7 @@ bool upgrade_tables(THD *thd) { + Object_table_definition_impl::set_dd_tablespace_encrypted(false); + + // Reset the DDSE local dictionary cache. +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->dict_cache_reset == nullptr) return true; + + for (System_tables::Const_iterator it = +diff --git a/sql/dd/impl/upgrade/server.cc b/sql/dd/impl/upgrade/server.cc +index 1e3ce91..4812569 100644 +--- a/sql/dd/impl/upgrade/server.cc ++++ b/sql/dd/impl/upgrade/server.cc +@@ -518,12 +518,12 @@ static void create_upgrade_file() { + + static bool get_shared_tablespace_names( + THD *thd, std::set *shared_spaces) { +- assert(innodb_hton != nullptr && innodb_hton->get_tablespace_type); ++ assert(tse_hton != nullptr && tse_hton->get_tablespace_type); + auto process_spaces = [&](std::unique_ptr &space) { +- if (my_strcasecmp(system_charset_info, space->engine().c_str(), "InnoDB")) ++ if (my_strcasecmp(system_charset_info, space->engine().c_str(), "CTC")) + return false; + Tablespace_type space_type; +- if (innodb_hton->get_tablespace_type(*space, &space_type)) { ++ if (tse_hton->get_tablespace_type(*space, &space_type)) { + LogErr(ERROR_LEVEL, ER_UNKNOWN_TABLESPACE_TYPE, space->name().c_str()); + return true; + } +diff --git a/sql/dd/info_schema/metadata.cc b/sql/dd/info_schema/metadata.cc +index 4c9a38f..3f1488b 100644 +--- a/sql/dd/info_schema/metadata.cc ++++ b/sql/dd/info_schema/metadata.cc +@@ -629,7 +629,19 @@ bool store_server_I_S_metadata(THD *thd) { + + // Update server and plugin I_S table metadata on server restart. + bool update_I_S_metadata(THD *thd) { +- return update_server_I_S_metadata(thd) || update_plugins_I_S_metadata(thd); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); ++ if (!opt_initialize && !mysqld_server_started) { ++ if (ddse->op_before_load_meta(thd) != 0) { ++ return true; ++ } ++ } ++ bool error = update_server_I_S_metadata(thd) || update_plugins_I_S_metadata(thd); ++ if (!opt_initialize && !mysqld_server_started) { ++ if (ddse->op_after_load_meta(thd) != 0) { ++ return true; ++ } ++ } ++ return error; + } + + /* +diff --git a/sql/dd/info_schema/table_stats.cc b/sql/dd/info_schema/table_stats.cc +index cc1041d..b69b7b7 100644 +--- a/sql/dd/info_schema/table_stats.cc ++++ b/sql/dd/info_schema/table_stats.cc +@@ -69,7 +69,7 @@ namespace { + inline bool can_persist_I_S_dynamic_statistics(THD *thd, + const char *schema_name, + const char *partition_name) { +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse == nullptr || ddse->is_dict_readonly()) return false; + + return (thd->variables.information_schema_stats_expiry && +diff --git a/sql/dd/upgrade_57/upgrade.cc b/sql/dd/upgrade_57/upgrade.cc +index ebda371..6310acc 100644 +--- a/sql/dd/upgrade_57/upgrade.cc ++++ b/sql/dd/upgrade_57/upgrade.cc +@@ -845,12 +845,13 @@ bool do_pre_checks_and_initialize_dd(THD *thd) { + bool not_used; + build_table_filename(path, sizeof(path) - 1, "", "mysql", ".ibd", 0, + ¬_used); +- bool exists_mysql_tablespace = (!my_access(path, F_OK)); ++ // bool exists_mysql_tablespace = (!my_access(path, F_OK)); ++ bool exists_mysql_tablespace = true; + + // Check existence of mysql/plugin.frm +- build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", ".frm", 0, +- ¬_used); +- bool exists_plugin_frm = (!my_access(path, F_OK)); ++ //build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", ".frm", 0, ++ // ¬_used); ++ //bool exists_plugin_frm = (!my_access(path, F_OK)); + + /* + If mysql.ibd and mysql/plugin.frm do not exist, +@@ -859,10 +860,10 @@ bool do_pre_checks_and_initialize_dd(THD *thd) { + Server restart is not possible without mysql.ibd. + Exit with an error. + */ +- if (!exists_mysql_tablespace && !exists_plugin_frm) { +- LogErr(ERROR_LEVEL, ER_DD_UPGRADE_FAILED_FIND_VALID_DATA_DIR); +- return true; +- } ++ // if (!exists_mysql_tablespace && !exists_plugin_frm) { ++ // LogErr(ERROR_LEVEL, ER_DD_UPGRADE_FAILED_FIND_VALID_DATA_DIR); ++ // return true; ++ // } + + // Read stage of upgrade from the file. + Upgrade_status upgrade_status; +diff --git a/sql/handler.cc b/sql/handler.cc +index 217a0c1..fe900eb 100644 +--- a/sql/handler.cc ++++ b/sql/handler.cc +@@ -769,11 +769,13 @@ int ha_initialize_handlerton(st_plugin_int *plugin) { + hton->slot = HA_SLOT_UNDEF; + /* Historical Requirement */ + plugin->data = hton; // shortcut for the future +- if (plugin->plugin->init && plugin->plugin->init(hton)) { +- LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); +- goto err; ++ { ++ if (plugin->plugin->init && plugin->plugin->init(hton)) { ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ } + } +- ++ + /* + the switch below and hton->state should be removed when + command-line options for plugins will be implemented +@@ -852,6 +854,9 @@ int ha_initialize_handlerton(st_plugin_int *plugin) { + case DB_TYPE_INNODB: + innodb_hton = hton; + break; ++ case DB_TYPE_CTC: ++ tse_hton = hton; ++ break; + default: + break; + }; +@@ -901,13 +906,15 @@ void ha_end() { + + static bool dropdb_handlerton(THD *, plugin_ref plugin, void *path) { + handlerton *hton = plugin_data(plugin); +- if (hton->state == SHOW_OPTION_YES && hton->drop_database) +- hton->drop_database(hton, (char *)path); +- return false; ++ bool error = false; ++ if (hton->state == SHOW_OPTION_YES && hton->drop_database) { ++ error |= hton->drop_database(hton, (char *)path); ++ } ++ return error; + } + +-void ha_drop_database(char *path) { +- plugin_foreach(nullptr, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path); ++bool ha_drop_database(char *path) { ++ return plugin_foreach(nullptr, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path); + } + + static bool closecon_handlerton(THD *thd, plugin_ref plugin, void *) { +@@ -3875,9 +3882,7 @@ int handler::update_auto_increment() { + which will set first_successful_insert_id_in_cur_stmt if it's not + already set. + */ +- insert_id_for_cur_row = nr; +- /* +- Set next insert id to point to next auto-increment value to be able to ++ insert_id_for_cur_row = nr; /* Set next insert id to point to next auto-increment value to be able to + handle multi-row statements. + */ + set_next_insert_id(compute_next_insert_id(nr, variables)); +@@ -5798,10 +5803,12 @@ struct binlog_log_query_st { + static bool binlog_log_query_handlerton2(THD *thd, handlerton *hton, + void *args) { + struct binlog_log_query_st *b = (struct binlog_log_query_st *)args; +- if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) +- hton->binlog_log_query(hton, thd, b->binlog_command, b->query, ++ bool error = false; ++ if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query) { ++ error |= hton->binlog_log_query(hton, thd, b->binlog_command, b->query, + b->query_length, b->db, b->table_name); +- return false; ++ } ++ return error; + } + + static bool binlog_log_query_handlerton(THD *thd, plugin_ref plugin, +@@ -5810,7 +5817,7 @@ static bool binlog_log_query_handlerton(THD *thd, plugin_ref plugin, + args); + } + +-void ha_binlog_log_query(THD *thd, handlerton *hton, ++bool ha_binlog_log_query(THD *thd, handlerton *hton, + enum_binlog_command binlog_command, const char *query, + size_t query_length, const char *db, + const char *table_name) { +@@ -5821,10 +5828,10 @@ void ha_binlog_log_query(THD *thd, handlerton *hton, + b.db = db; + b.table_name = table_name; + if (hton == nullptr) +- plugin_foreach(thd, binlog_log_query_handlerton, ++ return plugin_foreach(thd, binlog_log_query_handlerton, + MYSQL_STORAGE_ENGINE_PLUGIN, &b); + else +- binlog_log_query_handlerton2(thd, hton, &b); ++ return binlog_log_query_handlerton2(thd, hton, &b); + } + + int ha_binlog_end(THD *thd) { +@@ -7875,7 +7882,7 @@ int handler::ha_reset() { + return retval; + } + +-int handler::ha_write_row(uchar *buf) { ++int handler::ha_write_row(uchar *buf, bool write_through) { + int error; + Log_func *log_func = Write_rows_log_event::binlog_row_logging_function; + assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK); +@@ -7892,7 +7899,7 @@ int handler::ha_write_row(uchar *buf) { + set_my_errno(HA_ERR_CRASHED); return HA_ERR_CRASHED;); + + MYSQL_TABLE_IO_WAIT(PSI_TABLE_WRITE_ROW, MAX_KEY, error, +- { error = write_row(buf); }) ++ { error = write_row(buf, write_through); }) + + if (unlikely(error)) return error; + +diff --git a/sql/handler.h b/sql/handler.h +index 0530ca1..214027d 100644 +--- a/sql/handler.h ++++ b/sql/handler.h +@@ -662,7 +662,8 @@ enum legacy_db_type { + /** Performance schema engine. */ + DB_TYPE_PERFORMANCE_SCHEMA, + DB_TYPE_TEMPTABLE, +- DB_TYPE_FIRST_DYNAMIC = 42, ++ DB_TYPE_CTC = 30, ++ DB_TYPE_FIRST_DYNAMIC = 42, + DB_TYPE_DEFAULT = 127 // Must be last + }; + +@@ -1334,7 +1335,7 @@ typedef xa_status_code (*rollback_by_xid_t)(handlerton *hton, XID *xid); + typedef handler *(*create_t)(handlerton *hton, TABLE_SHARE *table, + bool partitioned, MEM_ROOT *mem_root); + +-typedef void (*drop_database_t)(handlerton *hton, char *path); ++typedef bool (*drop_database_t)(handlerton *hton, char *path); + + typedef int (*panic_t)(handlerton *hton, enum ha_panic_function flag); + +@@ -1510,7 +1511,7 @@ typedef int (*fill_is_table_t)(handlerton *hton, THD *thd, TABLE_LIST *tables, + typedef int (*binlog_func_t)(handlerton *hton, THD *thd, enum_binlog_func fn, + void *arg); + +-typedef void (*binlog_log_query_t)(handlerton *hton, THD *thd, ++typedef bool (*binlog_log_query_t)(handlerton *hton, THD *thd, + enum_binlog_command binlog_command, + const char *query, uint query_length, + const char *db, const char *table_name); +@@ -2133,6 +2134,13 @@ typedef bool (*check_fk_column_compat_t)( + + typedef bool (*is_reserved_db_name_t)(handlerton *hton, const char *name); + ++typedef int (*get_inst_id_t)(); ++typedef void (*set_metadata_switch_t)(); ++typedef int (*get_metadata_switch_t)(); ++typedef int (*get_metadata_status_t)(); ++typedef int (*op_before_load_meta_t)(THD *thd); ++typedef int (*op_after_load_meta_t)(THD *thd); ++ + /** + Prepare the secondary engine for executing a statement. This function is + called right after the secondary engine TABLE objects have been opened by +@@ -2420,6 +2428,8 @@ struct handlerton { + */ + uint savepoint_offset; + ++ uint64_t pre_sess_addr; ++ + /* handlerton methods */ + + close_connection_t close_connection; +@@ -2464,6 +2474,14 @@ struct handlerton { + dict_set_server_version_t dict_set_server_version; + is_reserved_db_name_t is_reserved_db_name; + ++ /** CTC metadata methods. */ ++ get_inst_id_t get_inst_id; ++ set_metadata_switch_t set_metadata_switch; ++ get_metadata_switch_t get_metadata_switch; ++ get_metadata_status_t get_metadata_status; ++ op_before_load_meta_t op_before_load_meta; ++ op_after_load_meta_t op_after_load_meta; ++ + /** Global handler flags. */ + uint32 flags{0}; + +@@ -4482,7 +4500,7 @@ class handler { + and delete_row() below. + */ + int ha_external_lock(THD *thd, int lock_type); +- int ha_write_row(uchar *buf); ++ int ha_write_row(uchar *buf, bool write_through = false); + /** + Update the current row. + +@@ -6161,12 +6179,13 @@ class handler { + } + + @param buf Buffer to write from. ++ @param write_through flag to force write without begining a tx. + + @return Operation status. + @retval 0 Success. + @retval != 0 Error code. + */ +- virtual int write_row(uchar *buf MY_ATTRIBUTE((unused))) { ++ virtual int write_row(uchar *buf MY_ATTRIBUTE((unused)), bool write_through MY_ATTRIBUTE((unused)) = false) { + return HA_ERR_WRONG_COMMAND; + } + +@@ -6178,6 +6197,7 @@ class handler { + the columns required for the error message are not read, the error + message will contain garbage. + */ ++#define METADATA_NORMALIZED + virtual int update_row(const uchar *old_data MY_ATTRIBUTE((unused)), + uchar *new_data MY_ATTRIBUTE((unused))) { + return HA_ERR_WRONG_COMMAND; +@@ -6874,7 +6894,7 @@ void ha_pre_dd_shutdown(void); + @retval true Error + */ + bool ha_flush_logs(bool binlog_group_flush = false); +-void ha_drop_database(char *path); ++bool ha_drop_database(char *path); + int ha_create_table(THD *thd, const char *path, const char *db, + const char *table_name, HA_CREATE_INFO *create_info, + bool update_create_info, bool is_temp_table, +@@ -6973,7 +6993,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht, + int ha_reset_logs(THD *thd); + int ha_binlog_index_purge_file(THD *thd, const char *file); + void ha_reset_slave(THD *thd); +-void ha_binlog_log_query(THD *thd, handlerton *db_type, ++bool ha_binlog_log_query(THD *thd, handlerton *db_type, + enum_binlog_command binlog_command, const char *query, + size_t query_length, const char *db, + const char *table_name); +diff --git a/sql/log.cc b/sql/log.cc +index 4da945a..fc6f9c5 100644 +--- a/sql/log.cc ++++ b/sql/log.cc +@@ -906,11 +906,7 @@ bool Log_to_csv_event_handler::log_general( + if (log_table_intact.check(thd, table_list.table, &general_log_table_def)) + goto err; + +- if (table->file->ha_extra(HA_EXTRA_MARK_AS_LOG_TABLE) || +- table->file->ha_rnd_init(false)) +- goto err; +- +- need_rnd_end = true; ++ need_rnd_end = false; + + /* Honor next number columns if present */ + table->next_number_field = table->found_next_number_field; +@@ -960,7 +956,7 @@ bool Log_to_csv_event_handler::log_general( + } + + /* log table entries are not replicated */ +- if (table->file->ha_write_row(table->record[0])) goto err; ++ if (table->file->ha_write_row(table->record[0], true)) goto err; + + result = false; + +@@ -1026,13 +1022,7 @@ bool Log_to_csv_event_handler::log_slow( + goto err; + } + +- if (table->file->ha_extra(HA_EXTRA_MARK_AS_LOG_TABLE) || +- table->file->ha_rnd_init(false)) { +- reason = "mark log or init failed"; +- goto err; +- } +- +- need_rnd_end = true; ++ need_rnd_end = false; + + /* Honor next number columns if present */ + table->next_number_field = table->found_next_number_field; +@@ -1131,7 +1121,7 @@ bool Log_to_csv_event_handler::log_slow( + table->field[SQLT_FIELD_THREAD_ID]->store((longlong)thd->thread_id(), true); + + /* log table entries are not replicated */ +- if (table->file->ha_write_row(table->record[0])) { ++ if (table->file->ha_write_row(table->record[0], true)) { + reason = "write slow table failed"; + goto err; + } +diff --git a/sql/mdl.cc b/sql/mdl.cc +index da9ff9e..410b686 100644 +--- a/sql/mdl.cc ++++ b/sql/mdl.cc +@@ -1654,6 +1654,25 @@ bool MDL_lock::needs_hton_notification( + } + } + ++static bool is_notify_ctc_se(enum_mdl_type mdl_type, MDL_key::enum_mdl_namespace mdl_namespace) { ++ switch (mdl_namespace) { ++ case MDL_key::GLOBAL: ++ case MDL_key::BACKUP_LOCK: ++ if (mdl_type == MDL_SHARED) { ++ return true; ++ } ++ break; ++ ++ default: ++ if (mdl_type == MDL_EXCLUSIVE) { ++ return true; ++ } ++ return false; ++ } ++ ++ return false; ++} ++ + /** + Auxiliary functions needed for creation/destruction of MDL_ticket + objects. +@@ -2901,8 +2920,11 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, + We need to notify/get permission from storage engines before acquiring + X lock if it is requested in one of namespaces interesting for SEs. + */ +- if (mdl_request->type == MDL_EXCLUSIVE && +- MDL_lock::needs_hton_notification(key->mdl_namespace())) { ++ ++ /* ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(key->mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, key->mdl_namespace())) { + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); + + bool victimized; +@@ -2916,6 +2938,7 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, + + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); + } ++ */ + + retry: + /* +@@ -3034,6 +3057,26 @@ retry: + m_ticket_store.push_front(mdl_request->duration, ticket); + mdl_request->ticket = ticket; + ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(key->mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, key->mdl_namespace())) { ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ ++ bool victimized; ++ if (m_owner->notify_hton_pre_acquire_exclusive(key, &victimized)) { ++ ++ ticket->m_hton_notified = false; ++ release_lock(mdl_request->duration, ticket); ++ mdl_request->ticket = nullptr; ++ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, ++ MYF(0)); ++ return true; ++ } ++ ++ ticket->m_hton_notified = true; ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ } + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + return false; + } +@@ -3147,6 +3190,26 @@ slow_path: + m_ticket_store.push_front(mdl_request->duration, ticket); + mdl_request->ticket = ticket; + ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(key->mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, key->mdl_namespace())) { ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ ++ bool victimized; ++ if (m_owner->notify_hton_pre_acquire_exclusive(key, &victimized)) { ++ ++ ticket->m_hton_notified = false; ++ release_lock(mdl_request->duration, ticket); ++ mdl_request->ticket = nullptr; ++ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, ++ MYF(0)); ++ return true; ++ } ++ ticket->m_hton_notified = true; ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ } ++ + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + } else + *out_ticket = ticket; +@@ -3207,10 +3270,11 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { + of storage engines we need to notify/get permission from SEs similarly + to situation when lock acquired. + */ +- if (mdl_request->type == MDL_EXCLUSIVE && +- MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) { ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { + assert(mdl_request->ticket->m_hton_notified); +- ++ /* + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); + + bool victimized; +@@ -3224,6 +3288,7 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { + ticket->m_hton_notified = true; + + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ */ + } + + ticket->m_lock = mdl_request->ticket->m_lock; +@@ -3275,6 +3340,28 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { + + mdl_request->ticket = ticket; + m_ticket_store.push_front(mdl_request->duration, ticket); ++ ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ ++ bool victimized; ++ if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, ++ &victimized)) { ++ ticket->m_hton_notified = false; ++ release_lock(mdl_request->duration, ticket); ++ mdl_request->ticket = nullptr; ++ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, ++ MYF(0)); ++ return true; ++ } ++ ticket->m_hton_notified = true; ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ } ++ + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + + return false; +@@ -3576,6 +3663,27 @@ bool MDL_context::acquire_lock(MDL_request *mdl_request, + m_ticket_store.push_front(mdl_request->duration, ticket); + mdl_request->ticket = ticket; + ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ ++ bool victimized; ++ if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, ++ &victimized)) { ++ ticket->m_hton_notified = false; ++ release_lock(mdl_request->duration, ticket); ++ mdl_request->ticket = nullptr; ++ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, ++ MYF(0)); ++ return true; ++ } ++ ticket->m_hton_notified = true; ++ ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ } ++ + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + + return false; +@@ -4234,6 +4342,29 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration, + } + } + ++void MDL_context::dump_lock(enum_mdl_duration duration, MDL_ticket *ticket) { ++ MDL_lock *lock = ticket->m_lock; ++ DBUG_TRACE; ++ fprintf(stderr, "\ndb=%s name=%s type=%d, duration=%d\n", lock->key.db_name(), lock->key.name(), ++ ticket->get_type(), duration); ++} ++ ++void MDL_context::dump_locks_stored_before(enum_mdl_duration duration, ++ MDL_ticket *sentinel) { ++ DBUG_TRACE; ++ ++ MDL_ticket *ticket; ++ MDL_ticket_store::List_iterator it = m_ticket_store.list_iterator(duration); ++ if (m_ticket_store.is_empty(duration)) { ++ return; ++ } ++ ++ while ((ticket = it++) && ticket != sentinel) { ++ fprintf(stderr, "\nfound lock to release ticket=%p\n", ticket); ++ dump_lock(duration, ticket); ++ } ++} ++ + /** + Release all explicit locks in the context which correspond to the + same name/object as this lock request. +diff --git a/sql/mdl.h b/sql/mdl.h +index f1f49f0..0127906 100644 +--- a/sql/mdl.h ++++ b/sql/mdl.h +@@ -1444,6 +1444,14 @@ class MDL_context { + void release_all_locks_for_name(MDL_ticket *ticket); + void release_locks(MDL_release_locks_visitor *visitor); + void release_lock(MDL_ticket *ticket); ++ void dump_lock(enum_mdl_duration duration, MDL_ticket *ticket); ++ void dump_locks_stored_before(enum_mdl_duration duration, ++ MDL_ticket *sentinel); ++ void inline dump_locks() { ++ dump_locks_stored_before(MDL_EXPLICIT, nullptr); ++ dump_locks_stored_before(MDL_STATEMENT, nullptr); ++ dump_locks_stored_before(MDL_TRANSACTION, nullptr); ++ } + + bool owns_equal_or_stronger_lock(const MDL_key *mdl_key, + enum_mdl_type mdl_type); +diff --git a/sql/mysqld.cc b/sql/mysqld.cc +index 50b76e2..080fdf9 100644 +--- a/sql/mysqld.cc ++++ b/sql/mysqld.cc +@@ -1216,6 +1216,7 @@ handlerton *heap_hton; + handlerton *temptable_hton; + handlerton *myisam_hton; + handlerton *innodb_hton; ++handlerton *tse_hton; + + char *opt_disabled_storage_engines; + uint opt_server_id_bits = 0; +@@ -4623,7 +4624,8 @@ int init_common_variables() { + + From MySQL 5.5 onwards, the default storage engine is InnoDB. + */ +- default_storage_engine = "InnoDB"; ++ //default_storage_engine = "InnoDB"; ++ default_storage_engine = "CTC"; + default_tmp_storage_engine = default_storage_engine; + + /* +@@ -5673,6 +5675,7 @@ static int setup_error_log_components() { + + static int init_server_components() { + DBUG_TRACE; ++ + /* + We need to call each of these following functions to ensure that + all things are initialized so that unireg_abort() doesn't fail +@@ -7574,6 +7577,7 @@ int mysqld_main(int argc, char **argv) + #endif + + server_components_initialized(); ++ printf("[SYSTEM] mysqld server start success! (mysqld_server_started = true)\n"); + + /* + Set opt_super_readonly here because if opt_super_readonly is set +diff --git a/sql/mysqld.h b/sql/mysqld.h +index 0d7d41c..b3f86eb 100644 +--- a/sql/mysqld.h ++++ b/sql/mysqld.h +@@ -358,6 +358,7 @@ extern handlerton *myisam_hton; + extern handlerton *heap_hton; + extern handlerton *temptable_hton; + extern handlerton *innodb_hton; ++extern handlerton *tse_hton; + extern uint opt_server_id_bits; + extern ulong opt_server_id_mask; + extern const char *load_default_groups[]; +diff --git a/sql/mysqld_thd_manager.cc b/sql/mysqld_thd_manager.cc +index 902fe2b..2fad578 100644 +--- a/sql/mysqld_thd_manager.cc ++++ b/sql/mysqld_thd_manager.cc +@@ -48,6 +48,7 @@ + #include "mysql/thread_pool_priv.h" // inc_thread_created + #include "sql/sql_class.h" // THD + #include "thr_mutex.h" ++#include "sql/handler.h" + + std::atomic Global_THD_manager::atomic_global_thd_count{0U}; + Global_THD_manager *Global_THD_manager::thd_manager = nullptr; +@@ -228,6 +229,11 @@ my_thread_id Global_THD_manager::get_new_thread_id() { + my_thread_id new_id; + MUTEX_LOCK(lock, &LOCK_thread_ids); + do { ++ if (thread_id_counter == 0) { ++ handlerton *hton = ha_resolve_by_legacy_type(current_thd, DB_TYPE_CTC); ++ my_thread_id tse_inst_id = hton->get_inst_id ? (my_thread_id)hton->get_inst_id() : 0; ++ thread_id_counter = tse_inst_id << 16; ++ } + new_id = thread_id_counter++; + } while (!thread_ids.insert_unique(new_id).second); + return new_id; +diff --git a/sql/resourcegroups/resource_group_mgr.cc b/sql/resourcegroups/resource_group_mgr.cc +index a90b15d..309763d 100644 +--- a/sql/resourcegroups/resource_group_mgr.cc ++++ b/sql/resourcegroups/resource_group_mgr.cc +@@ -119,7 +119,7 @@ Resource_group_mgr *Resource_group_mgr::instance() { + static inline bool persist_resource_group( + THD *thd, const resourcegroups::Resource_group &resource_group, + bool update) { +- handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_INNODB); ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); + if (ddse->is_dict_readonly && ddse->is_dict_readonly()) { + LogErr(WARNING_LEVEL, ER_RESOURCE_GROUP_METADATA_UPDATE_SKIPPED); + return false; +@@ -141,7 +141,12 @@ static inline bool persist_resource_group( + + static bool deserialize_resource_groups(THD *thd) { + DBUG_TRACE; +- ++ handlerton *ddse = ha_resolve_by_legacy_type(thd, DB_TYPE_CTC); ++ if (!opt_initialize && !mysqld_server_started) { ++ if (ddse->op_before_load_meta(thd) != 0) { ++ return true; ++ } ++ } + /* + Associate flag SYSTEM_THREAD_DD_INITIALIZE with THD context. + This ensures we need not acquire MDL locks during initialization phase. +@@ -207,7 +212,11 @@ static bool deserialize_resource_groups(THD *thd) { + if (persist_resource_group(thd, *res_grp_mgr->sys_default_resource_group(), + sys_default_in_dd)) + return true; +- ++ if (!opt_initialize && !mysqld_server_started) { ++ if (ddse->op_after_load_meta(thd) != 0) { ++ return true; ++ } ++ } + return false; + } + +diff --git a/sql/rpl_gtid_persist.cc b/sql/rpl_gtid_persist.cc +index e16b39c..efdfba2 100644 +--- a/sql/rpl_gtid_persist.cc ++++ b/sql/rpl_gtid_persist.cc +@@ -771,6 +771,8 @@ static void *compress_gtid_table(void *p_thd) { + mysql_mutex_unlock(&LOCK_compress_gtid_table); + THD_EXIT_COND(thd, nullptr); + ++ continue; // skip compress gtid table ++ + THD_STAGE_INFO(thd, stage_compressing_gtid_table); + /* Compressing the gtid_executed table. */ + if (gtid_state->compress(thd)) { +diff --git a/sql/sql_class.cc b/sql/sql_class.cc +index c171f0b..a34904d 100644 +--- a/sql/sql_class.cc ++++ b/sql/sql_class.cc +@@ -2890,6 +2890,17 @@ void THD::update_slow_query_status() { + server_status |= SERVER_QUERY_WAS_SLOW; + } + ++void THD::add(const char *schema_name, const char *table_name, const invalidate_object_type obj_type) ++{ ++ std::map, invalidate_object_type>::iterator ++ it = m_invalidate_map.find(typename Invalidate_map::key_type(schema_name, table_name)); ++ if (it == m_invalidate_map.end()) { ++ m_invalidate_map.insert(typename Invalidate_map::value_type( ++ typename Invalidate_map::key_type(schema_name, table_name), ++ typename Invalidate_map::mapped_type(obj_type))); ++ } ++} ++ + /** + Initialize the transactional ddl context when executing CREATE TABLE ... + SELECT command with engine which supports atomic DDL. +diff --git a/sql/sql_class.h b/sql/sql_class.h +index 9f68530..c7004b4 100644 +--- a/sql/sql_class.h ++++ b/sql/sql_class.h +@@ -841,6 +841,7 @@ class THD : public MDL_context_owner, + } + + public: ++ bool is_reading_dd = false; + MDL_context mdl_context; + + /** +@@ -4417,6 +4418,29 @@ class THD : public MDL_context_owner, + @param thd parent session + */ + void copy_table_access_properties(THD *thd); ++ ++ enum invalidate_object_type { ++ OBJ_ABSTRACT_TABLE, ++ OBJ_SCHEMA, ++ OBJ_EVENT, ++ OBJ_COLUMN_STATISTICS, ++ OBJ_CHARSET, ++ OBJ_COLLATION, ++ OBJ_RT_PROCEDURE, ++ OBJ_RT_FUNCTION, ++ OBJ_TABLESPACE, ++ OBJ_RESOURCE_GROUP, ++ OBJ_SPATIAL_REFERENCE_SYSTEM ++ }; ++ private: ++ typedef std::map, invalidate_object_type> Invalidate_map; ++ Invalidate_map m_invalidate_map; ++ public: ++ void add(const char *schema_name, const char *table_name, const invalidate_object_type obj_type); ++ const Invalidate_map &invalidates() const { return m_invalidate_map; } ++ //void invalidate(); ++ bool is_empty() const { return m_invalidate_map.empty(); } ++ void clear() { m_invalidate_map.clear(); } + }; + + /** +diff --git a/sql/sql_db.cc b/sql/sql_db.cc +index 662f522..975e017 100644 +--- a/sql/sql_db.cc ++++ b/sql/sql_db.cc +@@ -120,6 +120,7 @@ static bool rm_dir_w_symlink(const char *org_path, bool send_error); + static void mysql_change_db_impl(THD *thd, const LEX_CSTRING &new_db_name, + ulong new_db_access, + const CHARSET_INFO *new_db_charset); ++static bool no_need_schema_dir = true; + + bool get_default_db_collation(const dd::Schema &schema, + const CHARSET_INFO **collation) { +@@ -422,13 +423,13 @@ bool mysql_create_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + Server should either be in restart mode or upgrade mode to create only + dd::Schema object for the dictionary cache. + */ +- if (!schema_dir_exists) { ++ if (!no_need_schema_dir && !schema_dir_exists) { + my_printf_error(ER_BAD_DB_ERROR, + "System schema directory does not exist.", MYF(0)); + return true; + } + } else if (store_in_dd) { +- if (schema_dir_exists) { ++ if (!no_need_schema_dir && !schema_dir_exists) { + my_error(ER_SCHEMA_DIR_EXISTS, MYF(0), path); + return true; + } +@@ -440,7 +441,7 @@ bool mysql_create_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + my_strerror(errbuf, sizeof(errbuf), my_errno())); + return true; + } +- if (my_mkdir(path, 0777, MYF(0)) < 0) { ++ if (!no_need_schema_dir && my_mkdir(path, 0777, MYF(0)) < 0) { + char errbuf[MYSQL_ERRMSG_SIZE]; + my_error(ER_SCHEMA_DIR_CREATE_FAILED, MYF(0), db, my_errno(), + my_strerror(errbuf, MYSQL_ERRMSG_SIZE, my_errno())); +@@ -472,14 +473,18 @@ bool mysql_create_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + other error we ignore the error as we anyway return + failure (true) here. + */ +- if (!schema_dir_exists) rm_dir_w_symlink(path, true); ++ if (!no_need_schema_dir && !schema_dir_exists) rm_dir_w_symlink(path, true); + return true; + } + } + + // Log the query in the handler's binlog +- ha_binlog_log_query(thd, nullptr, LOGCOM_CREATE_DB, thd->query().str, +- thd->query().length, db, ""); ++ if (ha_binlog_log_query(thd, nullptr, LOGCOM_CREATE_DB, thd->query().str, ++ thd->query().length, db, "")) { ++ my_printf_error(ER_BAD_DB_ERROR, ++ "Binlog create database query failed.", MYF(0)); ++ return true; ++ } + + /* + If we have not added database to the data-dictionary we don't have +@@ -487,7 +492,7 @@ bool mysql_create_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + binlog's trx cache, which requires transaction with valid XID. + */ + if (write_db_cmd_to_binlog(thd, db, store_in_dd)) { +- if (!schema_dir_exists) rm_dir_w_symlink(path, true); ++ if (!no_need_schema_dir && !schema_dir_exists) rm_dir_w_symlink(path, true); + return true; + } + +@@ -496,7 +501,7 @@ bool mysql_create_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + able to remove directory in case of failure. + */ + if (trans_commit_stmt(thd) || trans_commit(thd)) { +- if (!schema_dir_exists) rm_dir_w_symlink(path, true); ++ if (!no_need_schema_dir && !schema_dir_exists) rm_dir_w_symlink(path, true); + return true; + } + +@@ -602,8 +607,12 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { + because e.g. NDB needs to propagate the read only option to + other mysqld servers in the cluster. + */ +- ha_binlog_log_query(thd, nullptr, LOGCOM_ALTER_DB, thd->query().str, +- thd->query().length, db, ""); ++ if (ha_binlog_log_query(thd, nullptr, LOGCOM_ALTER_DB, thd->query().str, ++ thd->query().length, db, "")) { ++ my_printf_error(ER_BAD_DB_ERROR, ++ "Binlog alter database query failed.", MYF(0)); ++ return true; ++ } + + /* + The original query is written to the binlog and hence replicated. +@@ -768,16 +777,18 @@ bool mysql_rm_db(THD *thd, const LEX_CSTRING &db, bool if_exists) { + } else // Schema found in DD + { + /* Database directory does not exist. */ +- if (schema_dirp == nullptr) { +- if (!if_exists) { +- my_error(ER_SCHEMA_DIR_MISSING, MYF(0), path); +- return true; +- } +- push_warning_printf(thd, Sql_condition::SL_NOTE, ER_SCHEMA_DIR_MISSING, +- ER_THD(thd, ER_SCHEMA_DIR_MISSING), path); +- } else { +- if (find_unknown_and_remove_deletable_files(thd, schema_dirp, path)) { +- return true; ++ if (!no_need_schema_dir) { ++ if (schema_dirp == nullptr) { ++ if (!if_exists) { ++ my_error(ER_SCHEMA_DIR_MISSING, MYF(0), path); ++ return true; ++ } ++ push_warning_printf(thd, Sql_condition::SL_NOTE, ER_SCHEMA_DIR_MISSING, ++ ER_THD(thd, ER_SCHEMA_DIR_MISSING), path); ++ } else { ++ if (find_unknown_and_remove_deletable_files(thd, schema_dirp, path)) { ++ return true; ++ } + } + } + +@@ -834,10 +845,13 @@ bool mysql_rm_db(THD *thd, const LEX_CSTRING &db, bool if_exists) { + other connected server. + */ + +- ha_drop_database(path); +- thd->clear_error(); /* @todo Do not ignore errors */ ++ if (ha_drop_database(path)) { ++ my_printf_error(ER_BAD_DB_ERROR, ++ "Drop database failed.", MYF(0)); ++ error = true; ++ } + Disable_binlog_guard binlog_guard(thd); +- error = Events::drop_schema_events(thd, *schema); ++ error = (error || Events::drop_schema_events(thd, *schema)); + error = (error || sp_drop_db_routines(thd, *schema)); + } + thd->pop_internal_handler(); +diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc +index 70d9c1f..02e6bc6 100644 +--- a/sql/sql_insert.cc ++++ b/sql/sql_insert.cc +@@ -2681,8 +2681,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, + init_tmp_table_share(thd, &share, "", 0, "", "", nullptr); + + tmp_table.s->db_create_options = 0; +- tmp_table.s->db_low_byte_first = (create_info->db_type == myisam_hton || +- create_info->db_type == heap_hton); ++ tmp_table.s->db_low_byte_first = ++ (create_info->db_type == myisam_hton || create_info->db_type == heap_hton || create_info->db_type == tse_hton); + tmp_table.set_not_started(); + + if (!thd->variables.explicit_defaults_for_timestamp) +diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc +index 3860d34..e89ca4c 100644 +--- a/sql/sql_plugin.cc ++++ b/sql/sql_plugin.cc +@@ -358,6 +358,7 @@ const LEX_CSTRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM] = { + + extern int initialize_schema_table(st_plugin_int *plugin); + extern int finalize_schema_table(st_plugin_int *plugin); ++extern bool opt_initialize_insecure; + + /* + The number of elements in both plugin_type_initialize and +@@ -1272,6 +1273,7 @@ void plugin_unlock_list(THD *thd, plugin_ref *list, size_t count) { + mysql_mutex_unlock(&LOCK_plugin); + } + ++ + static int plugin_initialize(st_plugin_int *plugin) { + int ret = 1; + DBUG_TRACE; +@@ -1296,6 +1298,69 @@ static int plugin_initialize(st_plugin_int *plugin) { + if (strcmp(plugin->name.str, "InnoDB") == 0) { + innodb_callback_data = ((handlerton *)plugin->data)->data; + } ++ if (strcmp(plugin->name.str, "CTC") == 0) { ++ plugin->load_option = PLUGIN_FORCE; ++ ++ handlerton *hton = (handlerton *)plugin->data; ++ hton->set_metadata_switch(); ++ int meta_version_match = hton->get_metadata_switch(); ++ switch (meta_version_match) { ++ case 0: ++ printf("[ERROR] INIT CTC PLUGIN FAILED! Metadata version not match.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ case 1: // success ++ break; ++ case 2: ++ printf("[ERROR] INIT CTC PLUGIN FAILED! Neither metadata switch is turned on.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ case 3: ++ printf("[ERROR] INIT CTC PLUGIN FAILED! At least one cantian node is not ready.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ default: ++ printf("[ERROR] INIT CTC PLUGIN FAILED! get_metadata_status FAILED, meta_version_match = %d.\n", meta_version_match); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ } ++ ++ int ctc_init_status = hton->get_metadata_status(); ++ if (opt_initialize || opt_initialize_insecure) { // init stage ++ switch (ctc_init_status) { ++ case 0: // success ++ break; ++ case 1: ++ printf("[ERROR] INIT FAILED! No need to repeat initialization. One node has started initialization, but has not completed.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ case 2: ++ printf("[ERROR] INIT FAILED! No need to repeat initialization. A node has completed initialization.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ default: ++ printf("[ERROR] INIT FAILED! get_metadata_status failed in initialization, ctc_init_status = %d.\n", ctc_init_status); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ } ++ } else { // start stage ++ switch (ctc_init_status) { ++ case 0: ++ printf("[ERROR] START FAILED! Please wait for the initialization to complete. None of the nodes have started initialization yet.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ case 1: ++ printf("[ERROR] START FAILED! Please wait for the initialization to complete. One node has started initialization, but has not completed.\n"); ++ LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str); ++ goto err; ++ case 2: // success ++ break; ++ default: ++ printf("[ERROR] START FAILED! get_metadata_status failed in starting, ctc_init_status = %d.\n", ctc_init_status); ++ goto err; ++ } ++ } ++ } + } else if (plugin->plugin->init) { + if (strcmp(plugin->name.str, "daemon_memcached") == 0) { + plugin->data = innodb_callback_data; +@@ -1566,6 +1631,11 @@ bool plugin_register_builtin_and_init_core_se(int *argc, char **argv) { + tmp.load_option = PLUGIN_FORCE; + } + ++ if (!my_strcasecmp(&my_charset_latin1, plugin->name, "InnoDB")) { ++ tmp.load_option = PLUGIN_OFF; ++ continue; ++ } ++ + free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE)); + if (test_plugin_options(&tmp_root, &tmp, argc, argv)) + tmp.state = PLUGIN_IS_DISABLED; +diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc +index 7bd705b..ace7923 100644 +--- a/sql/sql_rename.cc ++++ b/sql/sql_rename.cc +@@ -35,6 +35,7 @@ + #include "my_murmur3.h" + #include "my_sys.h" + #include "mysql/components/services/log_shared.h" ++#include "mysql/plugin.h" + #include "mysqld_error.h" + #include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client + #include "sql/dd/dd_table.h" // dd::table_storage_engine +@@ -718,6 +719,7 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, + } + } + ++ hton->pre_sess_addr = *(uint64_t *)thd_get_ha_data(thd, hton); + if (collect_and_lock_fk_tables_for_rename_table( + thd, ren_table->db, old_alias, from_table, new_db, new_alias, + hton, fk_invalidator)) { +@@ -732,13 +734,17 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, + happen. So it is safe to clear invalidator. + */ + fk_invalidator->clear(); ++ hton->pre_sess_addr = 0; + return true; + } + } + + if (lock_check_constraint_names_for_rename(thd, ren_table->db, old_alias, +- from_table, new_db, new_alias)) ++ from_table, new_db, new_alias)) { ++ ++ hton->pre_sess_addr = 0; + return true; ++ } + + /* + We commit changes to data-dictionary immediately after renaming +@@ -777,8 +783,10 @@ static bool do_rename(THD *thd, TABLE_LIST *ren_table, const char *new_db, + */ + fk_invalidator->clear(); + } ++ hton->pre_sess_addr = 0; + return true; + } ++ hton->pre_sess_addr = 0; + + /* + If RENAME TABLE is non-atomic but we have not committed the above +diff --git a/sql/sql_select.cc b/sql/sql_select.cc +index 5963cf6..3218795 100644 +--- a/sql/sql_select.cc ++++ b/sql/sql_select.cc +@@ -2755,7 +2755,7 @@ void QEP_TAB::push_index_cond(const JOIN_TAB *join_tab, uint keyno, + TABLE *const tbl = table(); + + // Disable ICP for Innodb intrinsic temp table because of performance +- if (tbl->s->db_type() == innodb_hton && tbl->s->tmp_table != NO_TMP_TABLE && ++ if ((tbl->s->db_type() == innodb_hton || tbl->s->db_type() == tse_hton) && tbl->s->tmp_table != NO_TMP_TABLE && + tbl->s->tmp_table != TRANSACTIONAL_TMP_TABLE) + return; + +diff --git a/sql/sql_table.cc b/sql/sql_table.cc +index 04bc666..7230fda 100644 +--- a/sql/sql_table.cc ++++ b/sql/sql_table.cc +@@ -8670,7 +8670,7 @@ static bool create_table_impl( + (create_info->options & HA_LEX_CREATE_TMP_TABLE) != + HA_LEX_CREATE_TMP_TABLE && + (thd->is_server_upgrade_thread() || +- create_info->db_type->db_type == DB_TYPE_INNODB) && ++ create_info->db_type->db_type == DB_TYPE_CTC) && + (dd::get_dictionary()->is_dd_table_name(db, error_table_name) || + dd::get_dictionary()->is_system_table_name(db, error_table_name)); + if (is_whitelisted_table) thd->push_internal_handler(&error_handler); +@@ -9398,6 +9398,10 @@ static bool adjust_fk_child_after_parent_def_change( + + if (!check_only && thd->dd_client()->update(child_table_def)) return true; + ++ if (!thd->is_attachable_rw_transaction_active()) { ++ thd->dd_client()->add_modified_objects_before_commit(); ++ } ++ + return false; + } + +@@ -11624,7 +11628,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, + Note: strcmp branch is to be removed in future when we fix it + in InnoDB. + */ +- if (ha_alter_info->create_info->db_type->db_type == DB_TYPE_INNODB || ++ if (ha_alter_info->create_info->db_type->db_type == DB_TYPE_CTC || + ha_alter_info->create_info->db_type->db_type == DB_TYPE_NDBCLUSTER) + field_renamed = strcmp(field->field_name, new_field->field_name); + else +diff --git a/sql/sql_tmp_table.cc b/sql/sql_tmp_table.cc +index 2063261..1c71f77 100644 +--- a/sql/sql_tmp_table.cc ++++ b/sql/sql_tmp_table.cc +@@ -558,12 +558,15 @@ class Cache_temp_engine_properties { + static uint HEAP_MAX_KEY_LENGTH; + static uint TEMPTABLE_MAX_KEY_LENGTH; + static uint INNODB_MAX_KEY_LENGTH; ++ static uint CTC_MAX_KEY_LENGTH; + static uint HEAP_MAX_KEY_PART_LENGTH; + static uint TEMPTABLE_MAX_KEY_PART_LENGTH; + static uint INNODB_MAX_KEY_PART_LENGTH; ++ static uint CTC_MAX_KEY_PART_LENGTH; + static uint HEAP_MAX_KEY_PARTS; + static uint TEMPTABLE_MAX_KEY_PARTS; + static uint INNODB_MAX_KEY_PARTS; ++ static uint CTC_MAX_KEY_PARTS; + + static void init(THD *thd); + }; +@@ -609,17 +612,30 @@ void Cache_temp_engine_properties::init(THD *thd) { + INNODB_MAX_KEY_PARTS = handler->max_key_parts(); + destroy(handler); + plugin_unlock(nullptr, db_plugin); ++ ++ // Cache CTC engine's ++ db_plugin = ha_lock_engine(nullptr, tse_hton); ++ handler = get_new_handler((TABLE_SHARE *)nullptr, false, thd->mem_root, ++ tse_hton); ++ CTC_MAX_KEY_LENGTH = handler->max_key_length(); ++ CTC_MAX_KEY_PART_LENGTH = handler->max_key_parts(); ++ CTC_MAX_KEY_PARTS = handler->max_key_parts(); ++ destroy(handler); ++ plugin_unlock(nullptr, db_plugin); + } + + uint Cache_temp_engine_properties::HEAP_MAX_KEY_LENGTH = 0; + uint Cache_temp_engine_properties::TEMPTABLE_MAX_KEY_LENGTH = 0; + uint Cache_temp_engine_properties::INNODB_MAX_KEY_LENGTH = 0; ++uint Cache_temp_engine_properties::CTC_MAX_KEY_LENGTH = 0; + uint Cache_temp_engine_properties::HEAP_MAX_KEY_PART_LENGTH = 0; + uint Cache_temp_engine_properties::TEMPTABLE_MAX_KEY_PART_LENGTH = 0; + uint Cache_temp_engine_properties::INNODB_MAX_KEY_PART_LENGTH = 0; ++uint Cache_temp_engine_properties::CTC_MAX_KEY_PART_LENGTH = 0; + uint Cache_temp_engine_properties::HEAP_MAX_KEY_PARTS = 0; + uint Cache_temp_engine_properties::TEMPTABLE_MAX_KEY_PARTS = 0; + uint Cache_temp_engine_properties::INNODB_MAX_KEY_PARTS = 0; ++uint Cache_temp_engine_properties::CTC_MAX_KEY_PARTS = 0; + + /** + Initialize the storage engine properties for the alternative temporary table +@@ -651,12 +667,12 @@ void get_max_key_and_part_length(uint *max_key_length, + + *max_key_length = + std::min(Cache_temp_engine_properties::HEAP_MAX_KEY_LENGTH, +- Cache_temp_engine_properties::INNODB_MAX_KEY_LENGTH); ++ Cache_temp_engine_properties::CTC_MAX_KEY_LENGTH); + *max_key_part_length = + std::min(Cache_temp_engine_properties::HEAP_MAX_KEY_PART_LENGTH, +- Cache_temp_engine_properties::INNODB_MAX_KEY_PART_LENGTH); ++ Cache_temp_engine_properties::CTC_MAX_KEY_PART_LENGTH); + *max_key_parts = std::min(Cache_temp_engine_properties::HEAP_MAX_KEY_PARTS, +- Cache_temp_engine_properties::INNODB_MAX_KEY_PARTS); ++ Cache_temp_engine_properties::CTC_MAX_KEY_PARTS); + } + + /** +@@ -2085,7 +2101,8 @@ bool setup_tmp_table_handler(THD *thd, TABLE *table, ulonglong select_options, + + if (use_tmp_disk_storage_engine(thd, table, select_options, + force_disk_table, mem_engine)) { +- hton = innodb_hton; ++ //hton = innodb_hton; ++ hton = tse_hton; + } else { + switch (mem_engine) { + case TMP_TABLE_TEMPTABLE: +@@ -2186,7 +2203,9 @@ bool open_tmp_table(TABLE *table) { + assert(table->s->ref_count() == 1 || // not shared, or: + table->s->db_type() == heap_hton || // using right engines + table->s->db_type() == temptable_hton || +- table->s->db_type() == innodb_hton); ++ table->s->db_type() == innodb_hton || ++ table->s->db_type() == myisam_hton || ++ table->s->db_type() == tse_hton); + + int error; + if ((error = table->file->ha_open(table, table->s->table_name.str, O_RDWR, +@@ -2257,7 +2276,7 @@ static bool create_tmp_table_with_fallback(THD *thd, TABLE *table) { + if (error == HA_ERR_RECORD_FILE_FULL && + table->s->db_type() == temptable_hton) { + table->file = get_new_handler( +- table->s, false, share->alloc_for_tmp_file_handler, innodb_hton); ++ table->s, false, share->alloc_for_tmp_file_handler, tse_hton); + error = table->file->create(share->table_name.str, table, &create_info, + nullptr); + } +@@ -2299,6 +2318,8 @@ static void trace_tmp_table(Opt_trace_context *trace, const TABLE *table) { + trace_tmp.add_alnum("record_format", "fixed"); + } else if (table->s->db_type() == temptable_hton) { + trace_tmp.add_alnum("location", "TempTable"); ++ } else if (table->s->db_type() == tse_hton) { ++ trace_tmp.add_alnum("location", "CTC"); + } else { + assert(s->db_type() == heap_hton); + trace_tmp.add_alnum("location", "memory (heap)") +@@ -2344,7 +2365,12 @@ bool instantiate_tmp_table(THD *thd, TABLE *table) { + if (create_tmp_table_with_fallback(thd, table)) return true; + // Make empty record so random data is not written to disk + empty_record(table); ++ } else if (share->db_type() == tse_hton) { ++ if (create_tmp_table_with_fallback(thd, table)) return true; ++ // Make empty record so random data is not written to disk ++ empty_record(table); + } ++ + + // If a heap table, it's created by open_tmp_table(). + if (open_tmp_table(table)) { +@@ -2561,7 +2587,8 @@ bool create_ondisk_from_heap(THD *thd, TABLE *wtable, int error, + TABLE_SHARE share = std::move(*old_share); + assert(share.ha_share == nullptr); + +- share.db_plugin = ha_lock_engine(thd, innodb_hton); ++ //share.db_plugin = ha_lock_engine(thd, innodb_hton); ++ share.db_plugin = ha_lock_engine(thd, tse_hton); + + TABLE_LIST *const wtable_list = wtable->pos_in_table_list; + Derived_refs_iterator ref_it(wtable_list); +@@ -2869,7 +2896,9 @@ void encode_innodb_position(uchar *rowid_bytes, + order. + */ + bool reposition_innodb_cursor(TABLE *table, ha_rows row_num) { +- assert(table->s->db_type() == innodb_hton); ++ assert(table->s->db_type() == tse_hton); ++ my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "reposition_innodb_cursor", "by CTC"); ++ return true; + if (table->file->ha_rnd_init(false)) return true; /* purecov: inspected */ + // Per the explanation above, the wanted InnoDB row has PK=row_num. + uchar rowid_bytes[6]; +diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc +index 1012337..62d2c4b 100644 +--- a/sql/sys_vars.cc ++++ b/sql/sys_vars.cc +@@ -7256,3 +7256,11 @@ static Sys_var_enum Sys_terminology_use_previous( + terminology_use_previous_names, DEFAULT(terminology_use_previous::NONE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(nullptr), ON_UPDATE(nullptr), + DEPRECATED_VAR("")); ++ ++bool srv_stats_auto_recalc_substitite; ++static Sys_var_bool Sys_substitute_innodb_stats_auto_recalc( ++ "innodb_stats_auto_recalc", ++ "Replacement of the innodb_stats_auto_recalc variable." ++ "the purpose is to prevent errors when setting the innodb_stats_auto_recalc variable" ++ "using meta data in CANTIAN.", ++ GLOBAL_VAR(srv_stats_auto_recalc_substitite), CMD_LINE(OPT_ARG), DEFAULT(false)); +diff --git a/sql/transaction.cc b/sql/transaction.cc +index 9f955ad..178d46e 100644 +--- a/sql/transaction.cc ++++ b/sql/transaction.cc +@@ -240,6 +240,14 @@ bool trans_commit(THD *thd, bool ignore_global_read_lock) { + + if (trans_check_state(thd)) return true; + ++ /* ++ Add modified uncommitted objects before committing attachable ++ read-write transaction. ++ */ ++ if (!thd->is_attachable_rw_transaction_active()) { ++ thd->dd_client()->add_modified_objects_before_commit(); ++ } ++ + thd->server_status &= + ~(SERVER_STATUS_IN_TRANS | SERVER_STATUS_IN_TRANS_READONLY); + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); +@@ -328,6 +336,14 @@ bool trans_commit_implicit(THD *thd, bool ignore_global_read_lock) { + !thd->in_sub_stmt && + !thd->get_transaction()->xid_state()->check_in_xa(false)); + ++ /* ++ Add modified uncommitted objects before committing attachable ++ read-write transaction. ++ */ ++ if (!thd->is_attachable_rw_transaction_active()) { ++ thd->dd_client()->add_modified_objects_before_commit(); ++ } ++ + if (thd->in_multi_stmt_transaction_mode() || + (thd->variables.option_bits & OPTION_TABLE_LOCK)) { + /* Safety if one did "drop table" on locked tables */ +diff --git a/sql/window_iterators.cc b/sql/window_iterators.cc +index cb0f140..a6da724 100644 +--- a/sql/window_iterators.cc ++++ b/sql/window_iterators.cc +@@ -159,7 +159,7 @@ bool buffer_record_somewhere(THD *thd, Window *w, int64 rowno) { + if (create_ondisk_from_heap(thd, t, error, true, &is_duplicate)) + return true; + +- assert(t->s->db_type() == innodb_hton); ++ assert(t->s->db_type() == tse_hton); + if (t->file->ha_rnd_init(true)) return true; /* purecov: inspected */ + + if (!w->m_frame_buffer_positions.empty()) { +@@ -191,6 +191,8 @@ bool buffer_record_somewhere(THD *thd, Window *w, int64 rowno) { + also one-based, so we can use w->frame_buffer_partition_offset() "as is" + to construct the position. + */ ++ my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "encode_innodb_position", "by CTC"); ++ return true; + encode_innodb_position( + w->m_frame_buffer_positions[first_in_partition].m_position, + t->file->ref_length, w->frame_buffer_partition_offset()); +diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc +index ac21c57..345fae9 100644 +--- a/storage/archive/ha_archive.cc ++++ b/storage/archive/ha_archive.cc +@@ -780,7 +780,7 @@ unsigned int ha_archive::pack_row(uchar *record, azio_stream *writer) { + for implementing start_bulk_insert() is that we could skip + setting dirty to true each time. + */ +-int ha_archive::write_row(uchar *buf) { ++int ha_archive::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) { + int rc; + uchar *read_buf = nullptr; + ulonglong temp_auto; +diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h +index 4f6bc3a..a777454 100644 +--- a/storage/archive/ha_archive.h ++++ b/storage/archive/ha_archive.h +@@ -139,7 +139,7 @@ class ha_archive : public handler { + int open(const char *name, int mode, uint test_if_locked, + const dd::Table *table_def) override; + int close(void) override; +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) override; + int real_write_row(uchar *buf, azio_stream *writer); + int truncate(dd::Table *table_def) override; + int rnd_init(bool scan = true) override; +diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc +index ff5ac51..60633eb 100644 +--- a/storage/blackhole/ha_blackhole.cc ++++ b/storage/blackhole/ha_blackhole.cc +@@ -94,7 +94,7 @@ int ha_blackhole::create(const char *, TABLE *, HA_CREATE_INFO *, dd::Table *) { + return 0; + } + +-int ha_blackhole::write_row(uchar *) { ++int ha_blackhole::write_row(uchar *, bool write_through MY_ATTRIBUTE((unused)) = false) { + DBUG_TRACE; + return table->next_number_field ? update_auto_increment() : 0; + } +diff --git a/storage/blackhole/ha_blackhole.h b/storage/blackhole/ha_blackhole.h +index 951ed39..c236a20 100644 +--- a/storage/blackhole/ha_blackhole.h ++++ b/storage/blackhole/ha_blackhole.h +@@ -106,7 +106,7 @@ class ha_blackhole : public handler { + enum thr_lock_type lock_type) override; + + private: +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + }; +diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc +index e3998ce..3e74761 100644 +--- a/storage/csv/ha_tina.cc ++++ b/storage/csv/ha_tina.cc +@@ -931,7 +931,7 @@ int ha_tina::close(void) { + of the file and appends the data. In an error case it really should + just truncate to the original position (this is not done yet). + */ +-int ha_tina::write_row(uchar *buf) { ++int ha_tina::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) { + int size; + DBUG_TRACE; + +diff --git a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h +index df63b48..8bcef46 100644 +--- a/storage/csv/ha_tina.h ++++ b/storage/csv/ha_tina.h +@@ -143,7 +143,7 @@ class ha_tina : public handler { + int open(const char *name, int mode, uint open_options, + const dd::Table *table_def) override; + int close(void) override; +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + int rnd_init(bool scan = true) override; +diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc +index e773501..9ef9c99 100644 +--- a/storage/example/ha_example.cc ++++ b/storage/example/ha_example.cc +@@ -274,7 +274,7 @@ int ha_example::close(void) { + sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc + */ + +-int ha_example::write_row(uchar *) { ++int ha_example::write_row(uchar *, bool write_through MY_ATTRIBUTE((unused)) = false) { + DBUG_TRACE; + /* + Example of a successful write_row. We don't store the data +diff --git a/storage/example/ha_example.h b/storage/example/ha_example.h +index c0515b2..a52c408 100644 +--- a/storage/example/ha_example.h ++++ b/storage/example/ha_example.h +@@ -195,7 +195,7 @@ class ha_example : public handler { + We implement this in ha_example.cc. It's not an obligatory method; + skip it and and MySQL will treat it as not implemented. + */ +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + + /** @brief + We implement this in ha_example.cc. It's not an obligatory method; +diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc +index 05f151e..023b64c 100644 +--- a/storage/federated/ha_federated.cc ++++ b/storage/federated/ha_federated.cc +@@ -1706,7 +1706,7 @@ bool ha_federated::append_stmt_insert(String *query) { + sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc. + */ + +-int ha_federated::write_row(uchar *) { ++int ha_federated::write_row(uchar *, bool write_through MY_ATTRIBUTE((unused)) = false) { + char values_buffer[FEDERATED_QUERY_BUFFER_SIZE]; + char insert_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; + Field **field; +diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h +index 75b29e4..99df51b 100644 +--- a/storage/federated/ha_federated.h ++++ b/storage/federated/ha_federated.h +@@ -218,7 +218,7 @@ class ha_federated : public handler { + + void start_bulk_insert(ha_rows rows) override; + int end_bulk_insert() override; +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + int index_init(uint keynr, bool sorted) override; +diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc +index 0d71f25..4178081 100644 +--- a/storage/heap/ha_heap.cc ++++ b/storage/heap/ha_heap.cc +@@ -204,7 +204,7 @@ void ha_heap::update_key_stats() { + key_stat_version = file->s->key_stat_version; + } + +-int ha_heap::write_row(uchar *buf) { ++int ha_heap::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) { + int res; + ha_statistic_increment(&System_status_var::ha_write_count); + if (table->next_number_field && buf == table->record[0]) { +diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h +index e1fb36c..85f3ec2 100644 +--- a/storage/heap/ha_heap.h ++++ b/storage/heap/ha_heap.h +@@ -81,7 +81,7 @@ class ha_heap : public handler { + const dd::Table *table_def) override; + int close(void) override; + void set_keys_for_scanning(void); +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + void get_auto_increment(ulonglong offset, ulonglong increment, +diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc +index e041606..a7fcecb 100644 +--- a/storage/innobase/handler/ha_innodb.cc ++++ b/storage/innobase/handler/ha_innodb.cc +@@ -8707,7 +8707,7 @@ void innobase_get_multi_value(const TABLE *mysql_table, ulint f_idx, + handle. + @return error code */ + +-int ha_innobase::write_row(uchar *record) /*!< in: a row in MySQL format */ ++int ha_innobase::write_row(uchar *record, bool write_through MY_ATTRIBUTE((unused))) /*!< in: a row in MySQL format */ + { + dberr_t error; + int error_result = 0; +diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h +index 6844bbf..d7b74c6 100644 +--- a/storage/innobase/handler/ha_innodb.h ++++ b/storage/innobase/handler/ha_innodb.h +@@ -127,10 +127,11 @@ class ha_innobase : public handler { + + longlong get_memory_buffer_size() const override; + +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) override; + + int update_row(const uchar *old_data, uchar *new_data) override; + ++ + int delete_row(const uchar *buf) override; + + /** Delete all rows from the table. +diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h +index 5163227..9dacf52 100644 +--- a/storage/innobase/handler/ha_innopart.h ++++ b/storage/innobase/handler/ha_innopart.h +@@ -996,7 +996,7 @@ class ha_innopart : public ha_innobase, + THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, + thr_lock_type lock_type) override; + +- int write_row(uchar *record) override { ++ int write_row(uchar *record, bool write_through MY_ATTRIBUTE((unused)) = false) override { + bool entered = false; + auto trx = m_prebuilt->trx; + +diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc +index 9b56731..9218f11 100644 +--- a/storage/innobase/handler/i_s.cc ++++ b/storage/innobase/handler/i_s.cc +@@ -72,6 +72,7 @@ this program; if not, write to the Free Software Foundation, Inc., + + #include "my_dbug.h" + ++ + extern mysql_mutex_t LOCK_global_system_variables; + + constexpr char plugin_author[] = PLUGIN_AUTHOR_ORACLE; +@@ -118,6 +119,7 @@ static_assert(I_S_PAGE_TYPE_LAST < (1 << I_S_PAGE_TYPE_BITS), + "i_s_page_type[] is too large"); + + /** Name string for File Page Types */ ++#ifdef DEFAULT_INNODB + static buf_page_desc_t i_s_page_type[] = { + {"ALLOCATED", FIL_PAGE_TYPE_ALLOCATED}, + {"INDEX", FIL_PAGE_INDEX}, +@@ -152,6 +154,7 @@ static buf_page_desc_t i_s_page_type[] = { + {"RTREE_INDEX", I_S_PAGE_TYPE_RTREE}, + {"IBUF_INDEX", I_S_PAGE_TYPE_IBUF}, + {"SDI_INDEX", I_S_PAGE_TYPE_SDI}}; ++#endif + + /** This structure defines information we will fetch from pages + currently cached in the buffer pool. It will be used to populate +@@ -275,6 +278,7 @@ static int i_s_common_deinit(void *p); /*!< in/out: table schema object */ + /** Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME + field. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int field_store_time_t( + Field *field, /*!< in/out: target field for storage */ + time_t time) /*!< in: value to store */ +@@ -299,9 +303,11 @@ static int field_store_time_t( + + return (field->store_time(&my_time, MYSQL_TIMESTAMP_DATETIME)); + } ++#endif + + /** Auxiliary function to store char* value in MYSQL_TYPE_STRING field. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int field_store_string( + Field *field, /*!< in/out: target field for storage */ + const char *str) /*!< in: NUL-terminated utf-8 string, +@@ -320,10 +326,12 @@ static int field_store_string( + + return (ret); + } ++#endif + + /** Store the name of an index in a MYSQL_TYPE_VARCHAR field. + Handles the names of incomplete secondary indexes. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int field_store_index_name( + Field *field, /*!< in/out: target field for + storage */ +@@ -353,6 +361,7 @@ static int field_store_index_name( + + return (ret); + } ++#endif + + /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx + Every time any column gets changed, added or removed, please remember +@@ -532,6 +541,7 @@ static ST_FIELD_INFO innodb_trx_fields_info[] = { + /** Read data from cache buffer and fill the INFORMATION_SCHEMA.innodb_trx + table with it. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int fill_innodb_trx_from_cache( + trx_i_s_cache_t *cache, /*!< in: cache to read from */ + THD *thd, /*!< in: used to call +@@ -664,6 +674,7 @@ static int fill_innodb_trx_from_cache( + + return 0; + } ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_trx + @return 0 on success */ +@@ -743,6 +754,7 @@ struct st_mysql_plugin i_s_innodb_trx = { + /** Common function to fill any of the dynamic tables: + INFORMATION_SCHEMA.innodb_trx + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int trx_i_s_common_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -813,6 +825,15 @@ static int trx_i_s_common_fill_table( + return 0; + #endif + } ++#else ++static int trx_i_s_common_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (not used) */ ++{ ++ return 0; ++} ++#endif + + /* Fields of the dynamic table information_schema.innodb_cmp. + Every time any column gets changed, added or removed, please remember +@@ -870,6 +891,7 @@ static ST_FIELD_INFO i_s_cmp_fields_info[] = { + /** Fill the dynamic table information_schema.innodb_cmp or + innodb_cmp_reset. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_cmp_fill_low(THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ + Item *, /*!< in: condition (ignored) */ +@@ -914,6 +936,15 @@ static int i_s_cmp_fill_low(THD *thd, /*!< in: thread */ + + return status; + } ++#else ++static int i_s_cmp_fill_low(THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *, /*!< in: condition (ignored) */ ++ ibool reset) /*!< in: TRUE=reset cumulated counts */ ++{ ++ return 0; ++} ++#endif + + /** Fill the dynamic table information_schema.innodb_cmp. + @return 0 on success, 1 on failure */ +@@ -1139,6 +1170,7 @@ static ST_FIELD_INFO i_s_cmp_per_index_fields_info[] = { + information_schema.innodb_cmp_per_index or + information_schema.innodb_cmp_per_index_reset. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_cmp_per_index_fill_low( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -1234,7 +1266,16 @@ err: + + return status; + } +- ++#else ++static int i_s_cmp_per_index_fill_low( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *, /*!< in: condition (ignored) */ ++ ibool reset) /*!< in: TRUE=reset cumulated counts */ ++{ ++ return 0; ++} ++#endif + /** Fill the dynamic table information_schema.innodb_cmp_per_index. + @return 0 on success, 1 on failure */ + static int i_s_cmp_per_index_fill( +@@ -1449,6 +1490,7 @@ innodb_cmpmem_reset. + @param[in] item condition (ignored) + @param[in] reset TRUE=reset cumulated counts + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_cmpmem_fill_low(THD *thd, TABLE_LIST *tables, Item *item, + ibool reset) { + int status = 0; +@@ -1512,6 +1554,12 @@ static int i_s_cmpmem_fill_low(THD *thd, TABLE_LIST *tables, Item *item, + + return status; + } ++#else ++static int i_s_cmpmem_fill_low(THD *thd, TABLE_LIST *tables, Item *item, ibool reset) ++{ ++ return 0; ++} ++#endif + + /** Fill the dynamic table information_schema.innodb_cmpmem. + @return 0 on success, 1 on failure */ +@@ -1793,6 +1841,7 @@ static ST_FIELD_INFO innodb_metrics_fields_info[] = { + + /** Fill the information schema metrics table. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_metrics_fill( + THD *thd, /*!< in: thread */ + TABLE *table_to_fill) /*!< in/out: fill this table */ +@@ -2036,9 +2085,11 @@ static int i_s_metrics_fill( + + return 0; + } ++#endif + + /** Function to fill information schema metrics tables. + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_metrics_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -2055,6 +2106,15 @@ static int i_s_metrics_fill_table( + + return 0; + } ++#else ++static int i_s_metrics_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (not used) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_metrics + @return 0 on success */ + static int innodb_metrics_init(void *p) /*!< in/out: table schema object */ +@@ -2141,6 +2201,7 @@ static ST_FIELD_INFO i_s_stopword_fields_info[] = { + + /** Fill the dynamic table information_schema.innodb_ft_default_stopword. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_stopword_fill(THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ + Item *) /*!< in: condition (not used) */ +@@ -2164,7 +2225,14 @@ static int i_s_stopword_fill(THD *thd, /*!< in: thread */ + + return 0; + } +- ++#else ++static int i_s_stopword_fill(THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (not used) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table information_schema.innodb_ft_default_stopword. + @return 0 on success */ + static int i_s_stopword_init(void *p) /*!< in/out: table schema object */ +@@ -2252,6 +2320,7 @@ static ST_FIELD_INFO i_s_fts_doc_fields_info[] = { + /** Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED or + INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_deleted_generic_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -2336,7 +2405,15 @@ static int i_s_fts_deleted_generic_fill( + + return 0; + } +- ++#else ++static int i_s_fts_deleted_generic_fill( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ ibool being_deleted) /*!< in: BEING_DELTED table */ ++{ ++ return 0; ++} ++#endif + /** Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED + @return 0 on success, 1 on failure */ + static int i_s_fts_deleted_fill( +@@ -2553,6 +2630,7 @@ static ST_FIELD_INFO i_s_fts_index_fields_info[] = { + /** Go through the Doc Node and its ilist, fill the dynamic table + INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED for one FTS index on the table. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_index_cache_fill_one_index( + fts_index_cache_t *index_cache, /*!< in: FTS index cache */ + THD *thd, /*!< in: thread */ +@@ -2642,8 +2720,11 @@ static int i_s_fts_index_cache_fill_one_index( + + return 0; + } ++#endif ++ + /** Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_index_cache_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -2707,7 +2788,15 @@ static int i_s_fts_index_cache_fill( + + return 0; + } +- ++#else ++static int i_s_fts_index_cache_fill( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE + @return 0 on success */ + static int i_s_fts_index_cache_init(void *p) /*!< in/out: table schema object */ +@@ -2780,6 +2869,7 @@ struct st_mysql_plugin i_s_innodb_ft_index_cache = { + /** Go through a FTS index auxiliary table, fetch its rows and fill + FTS word cache structure. + @return DB_SUCCESS on success, otherwise error code */ ++#ifdef DEFAULT_INNODB + static dberr_t i_s_fts_index_table_fill_selected( + dict_index_t *index, /*!< in: FTS index */ + ib_vector_t *words, /*!< in/out: vector to hold +@@ -2867,8 +2957,10 @@ static dberr_t i_s_fts_index_table_fill_selected( + + return (error); + } ++#endif + + /** Free words. */ ++#ifdef DEFAULT_INNODB + static void i_s_fts_index_table_free_one_fetch( + ib_vector_t *words) /*!< in: words fetched */ + { +@@ -2889,9 +2981,11 @@ static void i_s_fts_index_table_free_one_fetch( + + ib_vector_reset(words); + } ++#endif + + /** Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_index_table_fill_one_fetch( + CHARSET_INFO *index_charset, /*!< in: FTS index charset */ + THD *thd, /*!< in: thread */ +@@ -2986,10 +3080,12 @@ static int i_s_fts_index_table_fill_one_fetch( + + return ret; + } ++#endif + + /** Go through a FTS index and its auxiliary tables, fetch rows in each table + and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_index_table_fill_one_index( + dict_index_t *index, /*!< in: FTS index */ + THD *thd, /*!< in: thread */ +@@ -3065,8 +3161,11 @@ func_exit: + + return ret; + } ++#endif ++ + /** Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_index_table_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -3117,7 +3216,15 @@ static int i_s_fts_index_table_fill( + + return 0; + } +- ++#else ++static int i_s_fts_index_table_fill( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE + @return 0 on success */ + static int i_s_fts_index_table_init(void *p) /*!< in/out: table schema object */ +@@ -3206,12 +3313,15 @@ static ST_FIELD_INFO i_s_fts_config_fields_info[] = { + + END_OF_ST_FIELD_INFO}; + ++#ifdef DEFAULT_INNODB + static const char *fts_config_key[] = { + FTS_OPTIMIZE_LIMIT_IN_SECS, FTS_SYNCED_DOC_ID, FTS_STOPWORD_TABLE_NAME, + FTS_USE_STOPWORD, nullptr}; ++#endif + + /** Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_fts_config_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -3322,7 +3432,15 @@ static int i_s_fts_config_fill( + + return 0; + } +- ++#else ++static int i_s_fts_config_fill( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_CONFIG + @return 0 on success */ + static int i_s_fts_config_init(void *p) /*!< in/out: table schema object */ +@@ -3438,6 +3556,7 @@ typedef std::vector> + /** Fill Information Schema table INNODB_TEMP_TABLE_INFO for a particular + temp-table + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_temp_table_info_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables +@@ -3464,10 +3583,12 @@ static int i_s_innodb_temp_table_info_fill( + + return schema_table_store_record(thd, table); + } ++#endif + + /** Populate current table information to cache + @param[in] table table + @param[in,out] cache populate data in this cache */ ++#ifdef DEFAULT_INNODB + static void innodb_temp_table_populate_cache(const dict_table_t *table, + temp_table_info_t *cache) { + cache->m_table_id = table->id; +@@ -3483,10 +3604,12 @@ static void innodb_temp_table_populate_cache(const dict_table_t *table, + + cache->m_space_id = table->space; + } ++#endif + + /** This function will iterate over all available table and will fill + stats for temp-tables to INNODB_TEMP_TABLE_INFO. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_temp_table_info_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -3533,6 +3656,15 @@ static int i_s_innodb_temp_table_info_fill_table( + + return status; + } ++#else ++static int i_s_innodb_temp_table_info_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_TEMP_TABLE_INFO. + @return 0 on success, 1 on failure */ +@@ -3841,6 +3973,7 @@ static ST_FIELD_INFO i_s_innodb_buffer_stats_fields_info[] = { + /** Fill Information Schema table INNODB_BUFFER_POOL_STATS for a particular + buffer pool + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_stats_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -3935,10 +4068,12 @@ static int i_s_innodb_stats_fill( + + return schema_table_store_record(thd, table); + } ++#endif + + /** This is the function that loops through each buffer pool and fetch buffer + pool stats to information schema table: I_S_INNODB_BUFFER_POOL_STATS + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_buffer_stats_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -3978,7 +4113,15 @@ static int i_s_innodb_buffer_stats_fill_table( + + return status; + } +- ++#else ++static int i_s_innodb_buffer_stats_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_POOL_STATS. + @return 0 on success, 1 on failure */ + static int i_s_innodb_buffer_pool_stats_init( +@@ -4201,6 +4344,7 @@ static ST_FIELD_INFO i_s_innodb_buffer_page_fields_info[] = { + /** Fill Information Schema table INNODB_BUFFER_PAGE with information + cached in the buf_page_info_t array + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_buffer_page_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -4366,8 +4510,10 @@ static int i_s_innodb_buffer_page_fill( + + return 0; + } ++#endif + + /** Set appropriate page type to a buf_page_info_t structure */ ++#ifdef DEFAULT_INNODB + static void i_s_innodb_set_page_type( + buf_page_info_t *page_info, /*!< in/out: structure to fill with + scanned info */ +@@ -4430,9 +4576,12 @@ static void i_s_innodb_set_page_type( + mach_read_from_4(frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + } + } ++#endif ++ + /** Scans pages in the buffer cache, and collect their general information + into the buf_page_info_t array which is zero-filled. So any fields + that are not initialized in the function will default to 0 */ ++#ifdef DEFAULT_INNODB + static void i_s_innodb_buffer_page_get_info( + const buf_page_t *bpage, /*!< in: buffer pool page to scan */ + ulint pool_id, /*!< in: buffer pool id */ +@@ -4519,10 +4668,12 @@ static void i_s_innodb_buffer_page_get_info( + + mutex_exit(mutex); + } ++#endif + + /** This is the function that goes through each block of the buffer pool + and fetch information to information schema tables: INNODB_BUFFER_PAGE. + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_fill_buffer_pool( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -4592,10 +4743,12 @@ static int i_s_innodb_fill_buffer_pool( + + return status; + } ++#endif + + /** Fill page information for pages in InnoDB buffer pool to the + dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_buffer_page_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -4628,6 +4781,15 @@ static int i_s_innodb_buffer_page_fill_table( + + return status; + } ++#else ++static int i_s_innodb_buffer_page_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE. + @return 0 on success, 1 on failure */ +@@ -4844,6 +5006,7 @@ static ST_FIELD_INFO i_s_innodb_buf_page_lru_fields_info[] = { + /** Fill Information Schema table INNODB_BUFFER_PAGE_LRU with information + cached in the buf_page_info_t array + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_buf_page_lru_fill( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -4998,6 +5161,7 @@ static int i_s_innodb_buf_page_lru_fill( + + return 0; + } ++#endif + + /** This is the function that goes through buffer pool's LRU list + and fetch information to INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU. +@@ -5006,6 +5170,7 @@ and fetch information to INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU. + @param[in] buf_pool buffer pool to scan + @param[in] pool_id buffer pool id + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_fill_buffer_lru(THD *thd, TABLE_LIST *tables, + buf_pool_t *buf_pool, + const ulint pool_id) { +@@ -5063,10 +5228,12 @@ exit: + + return status; + } ++#endif + + /** Fill page information for pages in InnoDB buffer pool to the + dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU + @return 0 on success, 1 on failure */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_buf_page_lru_fill_table( + THD *thd, /*!< in: thread */ + TABLE_LIST *tables, /*!< in/out: tables to fill */ +@@ -5099,6 +5266,15 @@ static int i_s_innodb_buf_page_lru_fill_table( + + return status; + } ++#else ++static int i_s_innodb_buf_page_lru_fill_table( ++ THD *thd, /*!< in: thread */ ++ TABLE_LIST *tables, /*!< in/out: tables to fill */ ++ Item *) /*!< in: condition (ignored) */ ++{ ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU. + @return 0 on success, 1 on failure */ +@@ -5259,6 +5435,7 @@ from INNODB_TABLES. + @param[in] table table obj + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_tables(THD *thd, dict_table_t *table, + TABLE *table_to_fill) { + Field **fields; +@@ -5314,12 +5491,14 @@ static int i_s_dict_fill_innodb_tables(THD *thd, dict_table_t *table, + + return 0; + } ++#endif + + /** Function to go through each record in INNODB_TABLES table, and fill the + information_schema.innodb_tables table with related table information + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_tables_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + btr_pcur_t pcur; + const rec_t *rec; +@@ -5414,6 +5593,11 @@ static int i_s_innodb_tables_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + + return 0; + } ++#else ++static int i_s_innodb_tables_fill_table(THD *thd, TABLE_LIST *tables, Item *) { ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_tables + @param[in,out] p table schema object +@@ -5564,6 +5748,7 @@ from INNODB_TABLES. + @param[in] ref_count table reference count + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_tablestats(THD *thd, dict_table_t *table, + ulint ref_count, + TABLE *table_to_fill) { +@@ -5614,6 +5799,7 @@ static int i_s_dict_fill_innodb_tablestats(THD *thd, dict_table_t *table, + + return 0; + } ++#endif + + /** Function to go through each record in INNODB_TABLES table, and fill the + information_schema.innodb_tablestats table with table statistics +@@ -5621,6 +5807,7 @@ related information + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_tables_fill_table_stats(THD *thd, TABLE_LIST *tables, + Item *) { + btr_pcur_t pcur; +@@ -5693,6 +5880,12 @@ static int i_s_innodb_tables_fill_table_stats(THD *thd, TABLE_LIST *tables, + + return 0; + } ++#else ++static int i_s_innodb_tables_fill_table_stats(THD *thd, TABLE_LIST *tables, Item *) ++{ ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_tablestats + @param[in,out] p table schema object +@@ -5835,6 +6028,7 @@ collected index information + @param[in] index dict_index_t obj + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_indexes(THD *thd, const dict_index_t *index, + TABLE *table_to_fill) { + Field **fields; +@@ -5868,12 +6062,14 @@ static int i_s_dict_fill_innodb_indexes(THD *thd, const dict_index_t *index, + + return 0; + } ++#endif + + /** Function to go through each record in INNODB_INDEXES table, and fill the + information_schema.innodb_indexes table with related index information + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_indexes_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + btr_pcur_t pcur; + const rec_t *rec; +@@ -5941,7 +6137,11 @@ static int i_s_innodb_indexes_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + + return 0; + } +- ++#else ++static int i_s_innodb_indexes_fill_table(THD *thd, TABLE_LIST *tables, Item *) { ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_indexes + @param[in,out] p table schema object + @return 0 on success */ +@@ -6081,6 +6281,7 @@ static ST_FIELD_INFO innodb_columns_fields_info[] = { + @param[in,out] field field to store default value + @param[in] default_val default value to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int field_blob_store(Field *field, dict_col_default_t *default_val) { + int ret = 0; + +@@ -6098,6 +6299,7 @@ static int field_blob_store(Field *field, dict_col_default_t *default_val) { + + return (ret); + } ++#endif + + /** Function to populate the information_schema.innodb_columns with + related column information +@@ -6108,6 +6310,7 @@ related column information + @param[in] nth_v_col virtual column, its sequence number + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_columns(THD *thd, table_id_t table_id, + const char *col_name, + dict_col_t *column, ulint nth_v_col, +@@ -6148,7 +6351,9 @@ static int i_s_dict_fill_innodb_columns(THD *thd, table_id_t table_id, + + return 0; + } ++#endif + ++#ifdef DEFAULT_INNODB + static void process_rows(THD *thd, TABLE_LIST *tables, const rec_t *rec, + dict_table_t *dd_table, btr_pcur_t &pcur, mtr_t &mtr, + mem_heap_t *heap, bool is_partition) { +@@ -6236,12 +6441,14 @@ static void process_rows(THD *thd, TABLE_LIST *tables, const rec_t *rec, + rec = dd_getnext_system_rec(&pcur, &mtr); + } + } ++#endif + + /** Function to fill information_schema.innodb_columns with information + collected by scanning INNODB_COLUMNS table. + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_columns_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + btr_pcur_t pcur; + const rec_t *rec; +@@ -6286,7 +6493,11 @@ static int i_s_innodb_columns_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + + return 0; + } +- ++#else ++static int i_s_innodb_columns_fill_table(THD *thd, TABLE_LIST *tables, Item *) { ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_columns + @param[in,out] p table schema object + @return 0 on success */ +@@ -6396,6 +6607,7 @@ param[in] pos virtual column position + param[in] base_pos base column position + param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_virtual(THD *thd, table_id_t table_id, + ulint pos, ulint base_pos, + TABLE *table_to_fill) { +@@ -6415,6 +6627,7 @@ static int i_s_dict_fill_innodb_virtual(THD *thd, table_id_t table_id, + + return 0; + } ++#endif + + /** Function to fill information_schema.innodb_virtual with information + collected by scanning INNODB_VIRTUAL table. +@@ -6422,6 +6635,7 @@ param[in] thd thread + param[in,out] tables tables to fill + param[in] item condition (not used) + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_virtual_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + btr_pcur_t pcur; + const rec_t *rec; +@@ -6481,6 +6695,11 @@ static int i_s_innodb_virtual_fill_table(THD *thd, TABLE_LIST *tables, Item *) { + + return 0; + } ++#else ++static int i_s_innodb_virtual_fill_table(THD *thd, TABLE_LIST *tables, Item *) { ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.innodb_virtual + param[in,out] p table schema object +@@ -6677,6 +6896,7 @@ collected by scanning INNODB_TABLESPACESS table. + @param[in] state tablespace state + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_dict_fill_innodb_tablespaces( + THD *thd, space_id_t space_id, const char *name, uint32_t flags, + uint32 server_version, uint32 space_version, bool is_encrypted, +@@ -6808,6 +7028,7 @@ static int i_s_dict_fill_innodb_tablespaces( + + return 0; + } ++#endif + + /** Function to populate INFORMATION_SCHEMA.INNODB_TABLESPACES table. + Loop through each record in INNODB_TABLESPACES, and extract the column +@@ -6815,6 +7036,7 @@ information and fill the INFORMATION_SCHEMA.INNODB_TABLESPACES table. + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, + Item *) { + btr_pcur_t pcur; +@@ -6877,6 +7099,12 @@ static int i_s_innodb_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, + + return 0; + } ++#else ++static int i_s_innodb_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, Item *) ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_TABLESPACES + @param[in,out] p table schema object + @return 0 on success */ +@@ -6985,6 +7213,7 @@ static ST_FIELD_INFO innodb_cached_indexes_fields_info[] = { + @param[in] index_id index id + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_fill_innodb_cached_indexes_row(THD *thd, space_id_t space_id, + ulint index_id, + TABLE *table_to_fill) { +@@ -7009,12 +7238,14 @@ static int i_s_fill_innodb_cached_indexes_row(THD *thd, space_id_t space_id, + + return 0; + } ++#endif + + /** Go through each record in INNODB_INDEXES, and fill + INFORMATION_SCHEMA.INNODB_CACHED_INDEXES. + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_cached_indexes_fill_table(THD *thd, TABLE_LIST *tables, + Item * /* not used */) { + MDL_ticket *mdl = nullptr; +@@ -7078,6 +7309,12 @@ static int i_s_innodb_cached_indexes_fill_table(THD *thd, TABLE_LIST *tables, + + return 0; + } ++#else ++static int i_s_innodb_cached_indexes_fill_table(THD *thd, TABLE_LIST *tables, Item * /* not used */) ++{ ++ return 0; ++} ++#endif + + /** Bind the dynamic table INFORMATION_SCHEMA.INNODB_CACHED_INDEXES. + @param[in,out] p table schema object +@@ -7204,6 +7441,7 @@ static ST_FIELD_INFO innodb_session_temp_tablespaces_fields_info[] = { + @param[in] ts temp tablespace object + @param[in,out] table_to_fill fill this table + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_session_temp_tablespaces_fill_one( + THD *thd, const ibt::Tablespace *ts, TABLE *table_to_fill) { + Field **fields; +@@ -7251,12 +7489,14 @@ static int i_s_innodb_session_temp_tablespaces_fill_one( + + return 0; + } ++#endif + + /** Function to populate INFORMATION_SCHEMA.INNODB_SESSION_TEMPORARY_TABLESPACES + table. Iterate over the in-memory structure and fill the table + @param[in] thd thread + @param[in,out] tables tables to fill + @return 0 on success */ ++#ifdef DEFAULT_INNODB + static int i_s_innodb_session_temp_tablespaces_fill(THD *thd, + TABLE_LIST *tables, + Item *) { +@@ -7283,7 +7523,12 @@ static int i_s_innodb_session_temp_tablespaces_fill(THD *thd, + + return 0; + } +- ++#else ++static int i_s_innodb_session_temp_tablespaces_fill(THD *thd, TABLE_LIST *tables, Item *) ++{ ++ return 0; ++} ++#endif + /** Bind the dynamic table + INFORMATION_SCHEMA.INNODB_SESSION_TEMPORARY_TABLESPACES + @param[in,out] p table schema object +diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc +index d05f758..cc4ebfc 100644 +--- a/storage/myisam/ha_myisam.cc ++++ b/storage/myisam/ha_myisam.cc +@@ -825,7 +825,7 @@ int ha_myisam::close(void) { + return err; + } + +-int ha_myisam::write_row(uchar *buf) { ++int ha_myisam::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) { + ha_statistic_increment(&System_status_var::ha_write_count); + + /* +@@ -1786,7 +1786,7 @@ int ha_myisam::create(const char *name, TABLE *table_arg, + : (ulonglong)0); + create_info.data_file_length = + ((ulonglong)share->max_rows * share->avg_row_length); +- create_info.language = share->table_charset->number; ++ //create_info.language = share->table_charset->number; + + #ifndef _WIN32 + if (my_enable_symlinks) { +diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h +index 98ca35d..c00f71d 100644 +--- a/storage/myisam/ha_myisam.h ++++ b/storage/myisam/ha_myisam.h +@@ -114,7 +114,7 @@ class ha_myisam : public handler { + int open(const char *name, int mode, uint test_if_locked, + const dd::Table *table_def) override; + int close(void) override; +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + int index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map, +diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc +index 2107967..cc4f0a7 100644 +--- a/storage/myisammrg/ha_myisammrg.cc ++++ b/storage/myisammrg/ha_myisammrg.cc +@@ -982,7 +982,7 @@ int ha_myisammrg::close(void) { + return rc; + } + +-int ha_myisammrg::write_row(uchar *buf) { ++int ha_myisammrg::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) { + DBUG_TRACE; + assert(this->file->children_attached); + ha_statistic_increment(&System_status_var::ha_write_count); +diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h +index 11c0fc0..42050e1 100644 +--- a/storage/myisammrg/ha_myisammrg.h ++++ b/storage/myisammrg/ha_myisammrg.h +@@ -123,7 +123,7 @@ class ha_myisammrg : public handler { + int detach_children(void); + handler *clone(const char *name, MEM_ROOT *mem_root) override; + int close(void) override; +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + int update_row(const uchar *old_data, uchar *new_data) override; + int delete_row(const uchar *buf) override; + int index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map, +diff --git a/storage/ndb/plugin/ha_ndbcluster.cc b/storage/ndb/plugin/ha_ndbcluster.cc +index c29d260..9d13607 100644 +--- a/storage/ndb/plugin/ha_ndbcluster.cc ++++ b/storage/ndb/plugin/ha_ndbcluster.cc +@@ -12045,7 +12045,7 @@ static int drop_database_impl(THD *thd, + return 0; + } + +-static void ndbcluster_drop_database(handlerton *, char *path) { ++static bool ndbcluster_drop_database(handlerton *, char *path) { + THD *thd = current_thd; + DBUG_TRACE; + DBUG_PRINT("enter", ("path: '%s'", path)); +@@ -12056,18 +12056,20 @@ static void ndbcluster_drop_database(handlerton *, char *path) { + + if (!schema_dist_client.prepare(db, "")) { + /* Don't allow drop database unless schema distribution is ready */ +- return; ++ return true; + } + + if (drop_database_impl(thd, schema_dist_client, db) != 0) { +- return; ++ return true; + } + + if (!schema_dist_client.drop_db(db)) { + // NOTE! There is currently no way to report an error from this + // function, just log an error and proceed + ndb_log_error("Failed to distribute 'DROP DATABASE %s'", db); ++ return true; + } ++ return false; + } + + /** +diff --git a/storage/ndb/plugin/ha_ndbcluster_binlog.cc b/storage/ndb/plugin/ha_ndbcluster_binlog.cc +index c310cf6..9dec5d4 100644 +--- a/storage/ndb/plugin/ha_ndbcluster_binlog.cc ++++ b/storage/ndb/plugin/ha_ndbcluster_binlog.cc +@@ -496,7 +496,7 @@ static int ndbcluster_binlog_index_purge_file(THD *thd, const char *filename) { + -- privilege tables have been modified + */ + +-static void ndbcluster_binlog_log_query(handlerton *, THD *thd, ++static bool ndbcluster_binlog_log_query(handlerton *, THD *thd, + enum_binlog_command binlog_command, + const char *query, uint query_length, + const char *db, const char *) { +@@ -515,7 +515,7 @@ static void ndbcluster_binlog_log_query(handlerton *, THD *thd, + // NOTE! As there is no way return error, this may have to be + // revisited, the prepare should be done + // much earlier where it can return an error for the query +- return; ++ return true; + } + + // Generate the id, version +@@ -527,12 +527,18 @@ static void ndbcluster_binlog_log_query(handlerton *, THD *thd, + if (result) { + // Update the schema with the generated id and version but skip + // committing the change in DD. Commit will be done by the caller. +- ndb_dd_update_schema_version(thd, db, id, version, +- true /*skip_commit*/); ++ if (!ndb_dd_update_schema_version(thd, db, id, version, ++ true /*skip_commit*/)) { ++ log_and_clear_thd_conditions(m_thd, condition_logging_level::ERROR); ++ ndb_log_error("Failed to update schema version for database '%s'", ++ db); ++ return true; ++ } + } else { + // NOTE! There is currently no way to report an error from this + // function, just log an error and proceed + ndb_log_error("Failed to distribute 'CREATE DATABASE %s'", db); ++ return true; + } + } break; + +@@ -546,7 +552,7 @@ static void ndbcluster_binlog_log_query(handlerton *, THD *thd, + // NOTE! As there is no way return error, this may have to be + // revisited, the prepare should be done + // much earlier where it can return an error for the query +- return; ++ return true; + } + + // Generate the id, version +@@ -558,12 +564,18 @@ static void ndbcluster_binlog_log_query(handlerton *, THD *thd, + if (result) { + // Update the schema with the generated id and version but skip + // committing the change in DD. Commit will be done by the caller. +- ndb_dd_update_schema_version(thd, db, id, version, +- true /*skip_commit*/); ++ if (!ndb_dd_update_schema_version(thd, db, id, version, ++ true /*skip_commit*/)) { ++ log_and_clear_thd_conditions(m_thd, condition_logging_level::ERROR); ++ ndb_log_error("Failed to update schema version for database '%s'", ++ db); ++ return true; ++ } + } else { + // NOTE! There is currently no way to report an error from this + // function, just log an error and proceed + ndb_log_error("Failed to distribute 'ALTER DATABASE %s'", db); ++ return true; + } + } break; + +@@ -577,6 +589,7 @@ static void ndbcluster_binlog_log_query(handlerton *, THD *thd, + binlog_command)); + break; + } ++ return false; + } + + static void ndbcluster_acl_notify(THD *thd, +diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc +index a27da72..75f7e14 100644 +--- a/storage/perfschema/ha_perfschema.cc ++++ b/storage/perfschema/ha_perfschema.cc +@@ -1581,7 +1581,7 @@ int ha_perfschema::close(void) { + return 0; + } + +-int ha_perfschema::write_row(uchar *buf) { ++int ha_perfschema::write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused)) = false) { + int result; + + DBUG_TRACE; +diff --git a/storage/perfschema/ha_perfschema.h b/storage/perfschema/ha_perfschema.h +index 6efd57e..f8d03e3 100644 +--- a/storage/perfschema/ha_perfschema.h ++++ b/storage/perfschema/ha_perfschema.h +@@ -153,7 +153,7 @@ class ha_perfschema : public handler { + @param buf the row to write + @return 0 on success + */ +- int write_row(uchar *buf) override; ++ int write_row(uchar *buf, bool write_through MY_ATTRIBUTE((unused))) override; + + void use_hidden_primary_key() override; + +diff --git a/storage/temptable/include/temptable/handler.h b/storage/temptable/include/temptable/handler.h +index b9213f8..97bab4b 100644 +--- a/storage/temptable/include/temptable/handler.h ++++ b/storage/temptable/include/temptable/handler.h +@@ -317,7 +317,7 @@ class Handler : public ::handler { + * @return 0 on success or HA_ERR_* error code */ + int write_row( + /** [in] Row to insert. */ +- uchar *mysql_row) override; ++ uchar *mysql_row, bool write_through MY_ATTRIBUTE((unused)) = false) override; + + /** Update a row. + * @return 0 on success or HA_ERR_* error code */ +diff --git a/storage/temptable/src/handler.cc b/storage/temptable/src/handler.cc +index e949235..d46fca8 100644 +--- a/storage/temptable/src/handler.cc ++++ b/storage/temptable/src/handler.cc +@@ -639,7 +639,7 @@ void Handler::position(const uchar *) { + DBUG_PRINT("temptable_api", ("this=%p; saved position=%p", this, row)); + } + +-int Handler::write_row(uchar *mysql_row) { ++int Handler::write_row(uchar *mysql_row, bool write_through MY_ATTRIBUTE((unused))) { + DBUG_TRACE; + + opened_table_validate(); diff --git a/mysql-test/mysql-test-meta.patch b/mysql-test/mysql-test-meta.patch new file mode 100644 index 0000000..700c9cc --- /dev/null +++ b/mysql-test/mysql-test-meta.patch @@ -0,0 +1,84 @@ +diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test +index 03dedb25272..a6303991b6a 100644 +--- a/mysql-test/include/check-testcase.test ++++ b/mysql-test/include/check-testcase.test +@@ -142,7 +142,8 @@ if ($NDB_BACKUP_DIR) + # Hence, check-testcase will not work in these cases. + + --let $secure_file_priv = `SELECT @@global.secure_file_priv` +---let $proceed_with_check_of_files = `SELECT @@global.innodb_force_recovery = 0 AND '$secure_file_priv' = '$MYSQLTEST_VARDIR_ABS/'` ++# --let $proceed_with_check_of_files = `SELECT @@global.innodb_force_recovery = 0 AND '$secure_file_priv' = '$MYSQLTEST_VARDIR_ABS/'` ++--let $proceed_with_check_of_files = 0; + if ($proceed_with_check_of_files) { + # Ensure that we have no impact on the content of the binary log. + # +diff --git a/mysql-test/include/default_mysqld.cnf b/mysql-test/include/default_mysqld.cnf +index 0dd92e19ad5..be84ee0c6de 100644 +--- a/mysql-test/include/default_mysqld.cnf ++++ b/mysql-test/include/default_mysqld.cnf +@@ -16,8 +16,8 @@ log-bin-trust-function-creators=1 + # Set innodb-buffer-pool-size and innodb-log-file-size to a lower + # value because running tests in parallel, on the ramdisk may consume + # excessive memory. +-innodb-buffer-pool-size=24M +-innodb-log-file-size=5M ++# innodb-buffer-pool-size=24M ++# innodb-log-file-size=5M + # MAINTAINER: + # the loose- syntax is to make sure the cnf file is also + # valid when building without the performance schema. +diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl +index 10668310763..79f17a2203d 100755 +--- a/mysql-test/mysql-test-run.pl ++++ b/mysql-test/mysql-test-run.pl +@@ -4032,10 +4032,11 @@ sub mysql_install_db { + mtr_add_arg($args, "--core-file"); + mtr_add_arg($args, "--datadir=%s", "$install_datadir"); + mtr_add_arg($args, "--secure-file-priv=%s", "$opt_vardir"); ++ mtr_add_arg($args, "--early-plugin-load=%s", "ha_ctc.so"); + + # Overwrite the buffer size to 24M for certain tests to pass +- mtr_add_arg($args, "--innodb_buffer_pool_size=24M"); +- mtr_add_arg($args, "--innodb-log-file-size=5M"); ++ # mtr_add_arg($args, "--innodb_buffer_pool_size=24M"); ++ # mtr_add_arg($args, "--innodb-log-file-size=5M"); + + # Overwrite innodb_autoextend_increment to 8 for reducing the + # ibdata1 file size. +@@ -6067,6 +6068,8 @@ sub mysqld_arguments ($$$) { + mtr_add_arg($args, "--user=root"); + } + ++ mtr_add_arg($args, "--early-plugin-load=%s", "ha_ctc.so"); ++ + if ($opt_valgrind_mysqld) { + if ($mysql_version_id < 50100) { + mtr_add_arg($args, "--skip-bdb"); +diff --git a/unittest/gunit/dd.h b/unittest/gunit/dd.h +index 31b97e634ac..dc8cc561000 100644 +--- a/unittest/gunit/dd.h ++++ b/unittest/gunit/dd.h +@@ -74,7 +74,7 @@ class Mock_dd_HANDLER : public Base_mock_HANDLER { + key_part_map, enum ha_rkey_function)); + + // Handler method used for inserts +- MOCK_METHOD1(write_row, int(::uchar *)); ++ MOCK_METHOD2(write_row, int(::uchar *, bool)); + + // Handler method used for updates + MOCK_METHOD2(update_row, int(const ::uchar *, ::uchar *)); +diff --git a/unittest/gunit/dd_schema-t.cc b/unittest/gunit/dd_schema-t.cc +index 51da5ca391c..f92f8a17780 100644 +--- a/unittest/gunit/dd_schema-t.cc ++++ b/unittest/gunit/dd_schema-t.cc +@@ -240,8 +240,8 @@ TEST_F(SchemaTest, CreateSchema) { + EXPECT_CALL(*last_altered, store(real_last_altered, true)).Times(1); + + // ha->write_row: Called once, return 0 +- ON_CALL(*ha, write_row(_)).WillByDefault(Return(0)); +- EXPECT_CALL(*ha, write_row(_)).Times(1); ++ ON_CALL(*ha, write_row(_, false)).WillByDefault(Return(0)); ++ EXPECT_CALL(*ha, write_row(_, false)).Times(1); + + // Store the schema. + schema->store(&ctx->otx); diff --git a/mysql-test/suite/tianchi/t/ctc_atomic_ddl.test b/mysql-test/suite/tianchi/t/ctc_atomic_ddl.test new file mode 100644 index 0000000..4eed823 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_atomic_ddl.test @@ -0,0 +1,201 @@ +--disable_warnings +drop table if exists t,t1,t2,t3,t4; +--enable_warnings + + +create table t(id int primary key); +create table t1( +a int DEFAULT NULL, +b blob, +c float, +`col2` int, `col3` int, gcol1 INTEGER GENERATED ALWAYS AS (col2 + col3) VIRTUAL, +c1 TEXT character set armscii8 collate armscii8_general_ci, +id int primary key auto_increment,name varchar(8) not null,id_crd bigint zerofill, +foreign key(id) references t(id)); +CREATE TABLE t2(a int primary key,c1 float AUTO_INCREMENT,index(c1)) +PARTITION BY RANGE(a) subpartition by hash(a) +subpartitions 4( +partition p0 values less than(10), +partition p1 values less than(99), +partition p2 values less than(999), +partition p3 values less than(1000), +partition p4 values less than(2001), +partition p5 values less than(3000)); +create table t3(a varchar(100), b int, c int, index(b)) +partition by list columns(a) ( +partition p1 values in ('p1'), +partition p2 values in ('p2'), +partition p3 values in ('p3'), +partition p4 values in ('p4')); +create table t4( +a int DEFAULT NULL, +b blob, +c float, +`col2` int, `col3` int, gcol1 INTEGER GENERATED ALWAYS AS (col2 + col3) VIRTUAL, +c1 TEXT character set armscii8 collate armscii8_general_ci, +id int primary key auto_increment,name varchar(8) not null,id_crd bigint zerofill); +show create table t; +show create table t1; +show create table t2; +show create table t3; +show create table t4; +INSERT INTO t (id) VALUES (1); +INSERT INTO t (id) VALUES (2); +INSERT INTO t1 (a, b, c, `col2`, `col3`, c1, id, name, id_crd) VALUES (1, repeat('g', 16), 3.1415, 1, 2, 'abc', 1, concat('name',1), 10000000000+1); +INSERT INTO t2 VALUES(5, null); +INSERT INTO t2 VALUES(99, null); +INSERT INTO t2 VALUES(2100, null); +INSERT INTO t3 VALUES('p1',10,20); +INSERT INTO t3 VALUES('p2',100,200); +INSERT INTO t4 (a, b, c, `col2`, `col3`, c1, id, name, id_crd) VALUES (1, repeat('g', 16), 3.1415, 1, 2, 'abc', 1, concat('name',1), 10000000000+1); +SELECT * FROM t; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +SELECT * FROM t4; +--error 1050 +rename table t to t00,t1 to t2; +--error 1050 +rename table t1 to t11,t2 to t3; +--error 1050 +rename table t2 to t22,t3 to t4; +--error 1050 +rename table t3 to t33,t4 to t; +--error 1050 +rename table t4 to t44,t to t1; + +--error 1146 +rename table t to t00,t to t55; +--error 1146 +rename table t1 to t11,t1 to t55; +--error 1146 +rename table t2 to t22,t2 to t55; +--error 1146 +rename table t3 to t33,t3 to t55; +--error 1146 +rename table t4 to t44,t4 to t55; + +--error 1050 +rename table t to t00,t to t00; +--error 1050 +rename table t1 to t11,t1 to t11; +--error 1050 +rename table t2 to t22,t2 to t22; +--error 1050 +rename table t3 to t33,t3 to t33; +--error 1050 +rename table t4 to t44,t4 to t44; +show tables; +show create table t; +show create table t1; +show create table t2; +show create table t3; +show create table t4; + +--error 1146 +show create table t00; +--error 1146 +show create table t11; +--error 1146 +show create table t22; +--error 1146 +show create table t33; +--error 1146 +show create table t44; +--error 1146 +show create table t55; + +rename table t1 to t11, t to t1; +rename table t2 to t22, t11 to t2; +rename table t3 to t33, t22 to t3; +rename table t4 to t44, t33 to t4; +show tables; +--error 1146 +show create table t; +show create table t1; +show create table t2; +show create table t3; +show create table t4; +show create table t44; + +rename table t1 to t, t2 to t1, t3 to t2, t4 to t3, t44 to t4; +rename table t to t00, t00 to t; +rename table t1 to t11, t11 to t1; +rename table t2 to t22, t22 to t2; +rename table t3 to t33, t33 to t3; +rename table t4 to t44, t44 to t4; + +rename table t1 to t11, t11 to t111, t111 to t1111; +rename table t to t00, t00 to t000, t000 to t0000; +rename table t2 to t22, t22 to t222, t222 to t2222; +rename table t3 to t33, t33 to t333, t333 to t3333; +rename table t4 to t44, t44 to t444, t444 to t4444; + +show tables; +drop table t0000,t1111,t2222,t3333,t4444; + +create table t0 SELECT 1,"table 1"; +create table t2 SELECT 2,"table 2"; +create table t3 SELECT 3,"table 3"; +rename table t0 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t1; +select * from t1; +--error 1050 +rename table t1 to t2; +--error 1050 +rename table t1 to t1; +--error 1050 +rename table t3 to t4, t2 to t3, t1 to t2, t4 to t2; +show tables like "t_"; +--error 1050 +rename table t3 to t1, t2 to t3, t1 to t2, t4 to t1; +--error 1146 +rename table t3 to t4, t5 to t3, t1 to t2, t4 to t1; +drop table t1; +drop table t2,t3; + + +CREATE TABLE t(c1 INT CONSTRAINT t2_chk_1 CHECK (c1 > 10)); +CREATE TABLE t1(c1 INT CHECK (c1 > 10), CONSTRAINT ck CHECK(c1 > 10)); +--error 3822 +CREATE TABLE t2(c1 INT, CONSTRAINT ck CHECK(c1 > 10)); +--error 3822 +ALTER TABLE t1 ADD CONSTRAINT ck CHECK(c1 > 10); +--error 3822 +ALTER TABLE t1 RENAME TO t2; +--error 3822 +ALTER TABLE t1 ADD c2 INT, RENAME TO t2; +DROP TABLE t; +DROP TABLE t1; +CREATE TABLE t0(a INT, b INT); +INSERT INTO t0 VALUES (1,1), (1,2), (2,2); +--error 1062 +CREATE TABLE t1(a INT PRIMARY KEY,b INT) SELECT a,b FROM t0 ORDER BY a,b; +drop table t0; + + +CREATE TABLE parent(pk INTEGER PRIMARY KEY, j INTEGER, + UNIQUE KEY parent_key(j)); +CREATE TABLE child(pk INTEGER PRIMARY KEY, k INTEGER, fk INTEGER, + FOREIGN KEY (fk) REFERENCES parent(j), UNIQUE KEY child_key(k)); +CREATE TABLE grandchild(pk INTEGER PRIMARY KEY, fk INTEGER, + FOREIGN KEY (fk) REFERENCES child(k)); +SET @@foreign_key_checks= 0; +CREATE TABLE orphan_grandchild(pk INTEGER PRIMARY KEY, fk INTEGER, + FOREIGN KEY (fk) REFERENCES siebling(k)); +SET @@foreign_key_checks= 1; +CREATE TABLE non_atomic_t1(pk INTEGER) ENGINE= CTC; +CREATE TABLE non_atomic_t2(pk INTEGER) ENGINE= CTC; +--error 1050 +RENAME TABLE child TO siebling, + non_atomic_t1 TO non_atomic_t3, + non_atomic_t3 TO non_atomic_t2; +DROP TABLE grandchild; +DROP TABLE orphan_grandchild; +DROP TABLE child; +DROP TABLE parent; +DROP TABLE non_atomic_t1; +DROP TABLE non_atomic_t2; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_auto_increment.test b/mysql-test/suite/tianchi/t/ctc_auto_increment.test new file mode 100644 index 0000000..2605465 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_auto_increment.test @@ -0,0 +1,396 @@ +# This test runs for auto increment feature +# test set auto_increment_increment +# test set auto_increment_offset +# test use alter to reset the starting value of auto increment column +# test set auto increment column with a default value +# test set foreign key +--disable_warnings +drop table if exists t1; +--enable_warnings + +# Change the variable auto_increment_offset, from 1 to 5 +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=10; +SHOW VARIABLES LIKE 'auto_inc%'; +CREATE TABLE t1 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL), (NULL), (NULL), (NULL); +SELECT col FROM t1; +set @@session.auto_increment_offset=5; +INSERT INTO t1 VALUES (NULL), (NULL), (NULL), (NULL); +select col from t1; +drop table t1; + +# Change the variable auto_increment_increment, from 1 to 10 +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +SHOW VARIABLES LIKE 'auto_inc%'; +CREATE TABLE t1 (col INT NOT NULL AUTO_INCREMENT PRIMARY KEY); +INSERT INTO t1 VALUES (NULL), (NULL); +SELECT col FROM t1; +set @@session.auto_increment_increment=10; +INSERT INTO t1 VALUES (NULL), (NULL); +select col from t1; +drop table t1; + +# Set auto_increment_offset, meanwhile, table created with auto_increment larger than offset +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=2; +SHOW VARIABLES LIKE 'auto_inc%'; +CREATE TABLE t1 ( + id int NOT NULL AUTO_INCREMENT, + name varchar(30), + PRIMARY KEY (id) +) AUTO_INCREMENT=2; +INSERT into t1(name) values('3'); +INSERT into t1(name) values('5'); +INSERT into t1(name) values('7'); +select * from t1; +drop table t1; + +# alter the auto_increment when table is empty +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +CREATE TABLE t1(c1 TINYINT AUTO_INCREMENT NOT NULL KEY); +ALTER TABLE t1 AUTO_INCREMENT=10; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES (NULL), (NULL); +select * from t1; +drop table t1; + +# alter the auto_increment after insert some values to table +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +CREATE TABLE t1(c1 TINYINT AUTO_INCREMENT NOT NULL KEY); +INSERT INTO t1 VALUES (NULL), (NULL); +SHOW CREATE TABLE t1; +ALTER TABLE t1 AUTO_INCREMENT=10; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES (NULL), (NULL); +select * from t1; +drop table t1; + +# truncate table and alter auto increment value +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +CREATE TABLE t3(a SMALLINT AUTO_INCREMENT KEY); +ALTER TABLE t3 AUTO_INCREMENT = 100; +INSERT INTO t3 VALUES(0), (0); +select * from t3; +truncate table t3; +ALTER TABLE t3 AUTO_INCREMENT = 100; +INSERT INTO t3 VALUES(0), (0); +select * from t3; +drop table t3; + +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +# truncate non-empty table and alter auto_inc +create table t3(id int,c1 int,index(id)); +alter table t3 MODIFY COLUMN id int auto_increment,auto_increment=100; +insert into t3 values(null,1); +truncate table t3; +alter table t3 MODIFY COLUMN id int auto_increment,auto_increment=100; +show create table t3; +drop table t3; +# truncate empty table and alter auto_inc +create table t3(id int,c1 int,index(id)); +alter table t3 MODIFY COLUMN id int auto_increment,auto_increment=100; +truncate table t3; +alter table t3 MODIFY COLUMN id int auto_increment,auto_increment=100; +show create table t3; +drop table t3; + +# End test, reset auto increment variables to default value 1 +set @@session.auto_increment_offset=1; +set @@session.auto_increment_increment=1; +SHOW VARIABLES LIKE 'auto_inc%'; + +# auto increment boundary +CREATE TABLE DEMO (a DOUBLE AUTO_INCREMENT KEY); +--error 1292 +insert into DEMO values (-1.7976931348623157E+308); +show create table DEMO; +--error 1292 +insert into DEMO values (1.7976931348623157E+308); +insert into DEMO values (null); +select * from DEMO; +show create table DEMO; +drop table DEMO; + +CREATE TABLE DEMO (a FLOAT AUTO_INCREMENT KEY); +insert into DEMO values(-3.402823466E+38); +select * from DEMO; +show create table DEMO; +insert into DEMO values(-1.175494351E-38); +select * from DEMO; +show create table DEMO; +insert into DEMO values(3.402823466E+38); +select * from DEMO; +show create table DEMO; +insert into DEMO values(16777215); +select * from DEMO; +show create table DEMO; +insert into DEMO values(16777216); +select * from DEMO; +show create table DEMO; +--error 1062 +insert into DEMO values(16777217); +insert into DEMO values (9223372036854775807); +drop table DEMO; + +# LAST_INSERT_ID() and IS NULL +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); +SET insert_id = 2; +INSERT INTO t1 VALUES (NULL); +SELECT LAST_INSERT_ID(); +SELECT a FROM t1 WHERE a IS NULL; +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +INSERT INTO t1 VALUES (1); +SELECT LAST_INSERT_ID(); +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +INSERT INTO t1 VALUES (); +SELECT LAST_INSERT_ID(); +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +INSERT INTO t1 VALUES (0); +SELECT LAST_INSERT_ID(); +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +INSERT INTO t1 VALUES (NULL); +SELECT LAST_INSERT_ID(); +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +SET insert_id = 0; +INSERT INTO t1 VALUES (NULL); +SELECT LAST_INSERT_ID(); +SELECT /*+ SET_VAR(sql_auto_is_null=1) */ a FROM t1 WHERE a IS NULL; + +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +create table t1 (a INT AUTO_INCREMENT KEY, b varchar(30)); +insert into t1 values(1000, '1'); +insert into t1(b) values('1001'); +select * from t1; +replace into t1 values(0, '1002'),(1000, '2'); +select * from t1; +DROP TABLE t1; + +# alter table ALTER COLUMN set default ; +# If the auto-inc column is not primary key, `insert ()` will insert default value. +create table t1 (a INT AUTO_INCREMENT, index(a)); +insert into t1 values(null),(null); +select * from t1; +alter table t1 ALTER COLUMN a set default 10; +insert into t1 values(); +insert into t1 values(); +select * from t1; +insert into t1 values(null); +select * from t1; +drop table t1; + +# If the auto-inc column is primary key, the second and later `insert ()` command will get duplicate key err. +create table t1 (a INT AUTO_INCREMENT KEY); +insert into t1 values(null),(null); +select * from t1; +alter table t1 ALTER COLUMN a set default 10; +insert into t1 values(); +select * from t1; +--error 1062 +insert into t1 values(); +insert into t1 values(null); +select * from t1; +drop table t1; + +# After alter set default value, `insert (null)` will insert auto-generate value based on existing value. +# `insert ()` will insert default value. +create table t1 (a INT AUTO_INCREMENT KEY); +insert into t1 values(null); +select * from t1; +alter table t1 ALTER COLUMN a set default 10; +insert into t1 values(null); +select * from t1; +insert into t1 values(); +select * from t1; +insert into t1 values(null); +select * from t1; +drop table t1; + +# After alter set default value, `insert (0)` will auto generate value based on existing value. +# `insert ()` will insert default value. +create table t1 (a INT AUTO_INCREMENT KEY); +insert into t1 values(0); +select * from t1; +alter table t1 ALTER COLUMN a set default 10; +insert into t1 values(0); +select * from t1; +insert into t1 values(); +select * from t1; +insert into t1 values(0); +select * from t1; +drop table t1; + +# After set default and then drop the default, `insert ()` on auto increment column is disabled. +# insert (0) and insert (null) still work. +create table t1(a int AUTO_INCREMENT PRIMARY KEY); +insert into t1 values (); +select * from t1; +alter table t1 ALTER COLUMN a set default 10; +insert into t1 values (); +select * from t1; +alter table t1 ALTER COLUMN a drop default; +--error 1364 +insert into t1 values (); +insert into t1 values (0); +insert into t1 values (null); +select * from t1; +drop table t1; + +# auto increment and foreign key constraint +SET FOREIGN_KEY_CHECKS= 0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t11 VALUES (); +select * from t11; +update IGNORE t11 SET id = 20 where id=1; +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS= 1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT INTO t11 VALUES (); +select * from t11; +update IGNORE t11 SET id = 20 where id=1; +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS= 1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT INTO t11 VALUES (); +select * from t11; +--error 1452 +update t11 SET id = 20 where id=1; +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS= 0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t11 VALUES (); +update t11 SET id = 20 where id=1; +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS=0; +set global ctc_autoinc_lock_mode=0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS=default; + +SET FOREIGN_KEY_CHECKS= 1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS=0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t11 VALUES (); +INSERT INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS=1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT INTO t11 VALUES (); +--error 1452 +INSERT INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; +set global ctc_autoinc_lock_mode=default; + +SET FOREIGN_KEY_CHECKS= 0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS=default; + +SET FOREIGN_KEY_CHECKS= 1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +INSERT IGNORE INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS= 0; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t11 VALUES (); +INSERT INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; + +SET FOREIGN_KEY_CHECKS= 1; +create table t(id int primary key); +create table t11(id int primary key auto_increment, foreign key(id) references t(id)); +INSERT INTO t VALUES (1); +INSERT INTO t11 VALUES (); +select * from t11; +show create table t11; +--error 1452 +INSERT INTO t11 VALUES (); +select * from t11; +show create table t11; +drop table t,t11; +SET FOREIGN_KEY_CHECKS= default; +--echo End of tests diff --git a/mysql-test/suite/tianchi/t/ctc_charset.test b/mysql-test/suite/tianchi/t/ctc_charset.test new file mode 100644 index 0000000..e6a2a94 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_charset.test @@ -0,0 +1,321 @@ +# a test for charset when field type is char && index query +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255), +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset latin1; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset koi8r; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset hebrew; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset cp1257; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset armscii8; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset macce; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset big5; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0 charset eucjpms; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + + +CREATE TABLE worklog5743 (col_1_CHAR CHAR(255) , col_2_CHAR CHAR(255) , +PRIMARY KEY (col_1_CHAR)) engine = CTC STATS_PERSISTENT=0; +INSERT INTO worklog5743 VALUES(repeat("a", 200) , repeat("o", 200)); +INSERT INTO worklog5743 VALUES(repeat("b", 200) , repeat("o", 200)); +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +UPDATE worklog5743 SET col_1_CHAR = repeat("d", 200) WHERE col_1_CHAR = +repeat("a", 200) AND col_2_CHAR = repeat("o", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("a", 200); +SELECT * FROM worklog5743 where col_1_CHAR = repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +UPDATE worklog5743 SET col_1_CHAR = repeat("c", 200) WHERE col_1_CHAR = +repeat("d", 200); +SELECT col_1_CHAR = repeat("b", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("a", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("c", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT col_1_CHAR = repeat("d", 200) , col_2_CHAR = repeat("o", 200) FROM +worklog5743; +SELECT * FROM worklog5743 where col_1_CHAR = repeat("c", 200); +SELECT * FROM worklog5743 where col_2_CHAR = repeat("o", 200); +DROP TABLE worklog5743; + +create table t1(a bigint , b char(255), c date) partition by list columns(a,b,c) +(partition p0 values in((4,'aaa', '1948-10-10'),(5,'abb', '1949-10-10'), +(6,'abc', '1950-10-10'),(7,'abd', '1951-10-10')), +partition p1 values in((10, 'baa', '1990-10-10'),(11, 'bab', '1991-10-10'), +(11, 'bac', '1992-10-10'),(12, 'bad', '1993-10-10')), +partition p2 values in((20, 'caa', '2010-10-10'),(21, 'cab', '2011-10-10'), +(22, 'cac', '2012-10-10'),(23, 'cad', '2013-10-10')), +partition p3 values in ((30, 'daa', '2020-10-10'),(31, 'dab', '2021-10-10'), +(32, 'dac', '2022-10-10'),(33, 'dae', '2023-10-10'))); +insert into t1 values(4,'aaa', '1948-10-10'),(10, 'baa', '1990-10-10'), +(32, 'dac', '2022-10-10'),(22, 'cac', '2012-10-10'); +update t1 set a=6,b='abc',c='1950-10-10' where a=4; +update t1 set a=32,b='dac',c='2022-10-10' where a=6; +update t1 set a=11,b='bac',c='1992-10-10' where a=10; +update t1 set a=4,b='aaa',c='1948-10-10' where a=22; +drop table t1; diff --git a/mysql-test/suite/tianchi/t/ctc_charset_binary.test b/mysql-test/suite/tianchi/t/ctc_charset_binary.test new file mode 100644 index 0000000..911b961 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_charset_binary.test @@ -0,0 +1,201 @@ + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default '' not null key) charset binary; +insert into t1 values(0, default, default); +insert into t1 values(1, 1, 'abc'); +select c1, c2, hex(c3) from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default '' not null, key(c1, c3)) charset binary; +insert into t1 values(0, default, default); +insert into t1 values(1, 1, 'abc'); +select c1, c2, hex(c3) from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 varbinary(10) default '' not null key) charset binary; +insert into t1 values(0, default, default); +insert into t1 values(1, 1, 'abc'); +select c1, c2, c3 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 varbinary(10) default '' not null, key(c1, c3)) charset binary; +insert into t1 values(0, default, default); +insert into t1 values(1, 1, 'abc'); +select c1, c2, c3 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 char(10) default '' not null, c4 varchar(120) default '' not null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 char(10) default '' not null, c4 varchar(120) default '' not null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer, c3 char(10), c4 varchar(120)) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default '' not null, c4 varbinary(120) default '' not null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default '' not null, c4 varbinary(120) default '' not null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer, c3 binary(10), c4 varbinary(120)) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 char(10) default null, c4 varchar(120) default null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 char(10) default null, c4 varchar(120) default null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer, c3 char(10), c4 varchar(120)) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default null, c4 varbinary(120) default null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default null, c4 varbinary(120) default null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default b'101' not null, c4 varbinary(120) default b'101' not null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), hex(c4) from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default b'101' not null, c4 varbinary(120) default b'101' not null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), hex(c4) from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default 'aaaaa' not null, c4 varbinary(120) default 'aaaaa' not null) charset binary; +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; + +create table t1(c1 int, c2 integer default '0' not null, c3 binary(10) default 'aaaaa' not null, c4 varbinary(120) default 'aaaaa' not null) charset binary; +create index idx1 on t1(c1); +create index idx2 on t1(c2); +create index idx3 on t1(c3); +create index idx4 on t1(c4); +create index idx5 on t1(c1, c2); +create index idx6 on t1(c2, c3); +create index idx7 on t1(c3, c4); +create index idx8 on t1(c2, c3, c4); +create index idx9 on t1(c1, c2, c3); +create index idx10 on t1(c1, c2, c3, c4); +insert into t1 values(0, default, default, default); +insert into t1 values(1, 1, 'abc', 'def'); +select c1, c2, hex(c3), c4 from t1; +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_charset_collate.test b/mysql-test/suite/tianchi/t/ctc_charset_collate.test new file mode 100644 index 0000000..61033d2 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_charset_collate.test @@ -0,0 +1,429 @@ +--disable_warnings +drop table if exists t1, t2, t3, t4; +--enable_warnings + +# utf8mb4_bin: pad_space时 'a ' = 'a' +create table t1 (c1 varchar(5) collate utf8mb4_bin, key(c1)); +insert into t1 values('ae'); +insert into t1 values('äa'); +select length(c1), c1 from t1 where c1 < 'ae'; +delete from t1; +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 = _utf8mb4 'ab' collate utf8mb4_general_ci; +drop table t1; + +# utf8mb4_0900_bin: no_pad时 'a ' != 'a' +create table t2 (c1 varchar(5) collate utf8mb4_0900_bin, key(c1)); +insert into t2 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t2 where c1 = 'a' or c1 = 'b'; # a +select length(c1), c1 from t2 where c1 = 'ab'; +alter table t2 add primary key (c1); +drop table t2; + +# utf8mb4_general_ci: pad_space时 'a ' = 'a' = 'A ' = 'A' +create table t3 (c1 varchar(5) collate utf8mb4_general_ci, key(c1)); +insert into t3 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t3 where c1 = 'a' or c1 = 'b'; # a A b B +select length(c1), c1 from t3 where c1 = 'ab'; +select length(c1), c1 from t3 where c1 > 'a'; +select length(c1), c1 from t3 where c1 > 'A'; +select length(c1), c1 from t3 order by c1; +drop table t3; + +# utf8mb4_0900_ai_ci: no_pad时 'a ' = 'A ' != 'a' = 'A' +create table t4 (c1 varchar(5) collate utf8mb4_0900_ai_ci, key(c1)); +insert into t4 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t4 where c1 = 'a' or c1 = 'b'; +select length(c1), c1 from t4 where c1 = 'ab'; +select length(c1), c1 from t4 where c1 > 'a'; +select length(c1), c1 from t4 where c1 > 'A'; +drop table t4; + +create table t1 (c1 varchar(5) collate latin1_general_ci, key(c1)); +insert into t1 values('ae'); +insert into t1 values('äa'); +select length(c1), c1 from t1 where c1 < 'ae'; +delete from t1; +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_ci; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_cs; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate latin1_general_cs, key(c1)); +insert into t1 values('ae'); +insert into t1 values('äa'); +select length(c1), c1 from t1 where c1 < 'ae'; +delete from t1; +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_ci; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_cs; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate latin1_bin, key(c1)); +insert into t1 values('ae'); +insert into t1 values('äa'); +select length(c1), c1 from t1 where c1 < 'ae'; +delete from t1; +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_ci; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_general_cs; +select length(c1), c1 from t1 where c1 = _latin1 'ab' collate latin1_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate ascii_general_ci, key(c1)); +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _ascii 'ab' collate ascii_general_ci; +select length(c1), c1 from t1 where c1 = _ascii 'ab' collate ascii_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate ascii_bin, key(c1)); +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _ascii 'ab' collate ascii_general_ci; +select length(c1), c1 from t1 where c1 = _ascii 'ab' collate ascii_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate gbk_chinese_ci, key(c1)); +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _gbk 'ab' collate gbk_chinese_ci; +select length(c1), c1 from t1 where c1 = _gbk 'ab' collate gbk_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate gbk_bin, key(c1)); +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _gbk 'ab' collate gbk_chinese_ci; +select length(c1), c1 from t1 where c1 = _gbk 'ab' collate gbk_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate utf8_general_ci, key(c1)); +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _utf8 'ab' collate utf8_general_ci; +select length(c1), c1 from t1 where c1 = _utf8 'ab' collate utf8_bin; +drop table t1; + +create table t1 (c1 varchar(5) collate utf8_bin, key(c1)); +insert into t1 values('ae'); +insert into t1 values('äa'); +select length(c1), c1 from t1 where c1 < 'ae'; +delete from t1; +insert into t1 values ('a'), ('b '), ('A '), ('B'), ('ab'), ('Ab'); +select length(c1), c1 from t1 where c1 = 'a' or c1 = 'b'; # a, b +select length(c1), c1 from t1 where c1 = 'ab'; +select length(c1), c1 from t1 where c1 > 'a'; +select length(c1), c1 from t1 where c1 > 'A'; +select length(c1), c1 from t1 where c1 > 'a '; +select length(c1), c1 from t1 where c1 > 'A '; +select length(c1), c1 from t1 where c1 = _utf8 'ab' collate utf8_general_ci; +select length(c1), c1 from t1 where c1 = _utf8 'ab' collate utf8_bin; +drop table t1; + +# unsupport sql +create table t1(c1 varchar(5) charset gbk); +alter table t1 add index idx(c1); +drop table t1; + +create table t1(c1 varchar(5) charset gbk collate gbk_chinese_ci); +drop table t1; + +create table t1(c1 varchar(5) charset gbk, key(c1)); +drop table t1; + +create table t1(c1 varchar(5) charset gbk collate gbk_chinese_ci, key(c1)); +drop table t1; + +CREATE TABLE t1(C VARCHAR(100) CHARACTER SET gb18030, KEY(c(20))); +drop table t1; + +create table t1(a int, b char(10), c char(10), filler char(10), primary key(a, b(2)), unique key (a, c(2))) character set ucs2; +drop table t1; + +create table t1 (a varchar(2) character set cp1250) partition by list columns (a) (partition p0 values in (0x81)); +show create table t1; +drop table t1; + +create table t1 (c1 varchar(8)) default character set 'ujis'; +insert into t1 values (0xA4A2),(0xA2A2),(0xA4A2); +select c1 as 'no index' from t1 where c1 like cast(concat(0xA4A2, '%') as char character set ujis); +create index idx_c1 on t1(c1); +drop table t1; + +# pad +create table t1(c1 char(10) collate utf8mb4_bin, key(c1)); +create table t2(c1 char(10) collate utf8mb4_0900_bin, key(c1)); +insert into t1 values('a'); +insert into t2 values('a'); +select length(c1), c1 from t1 where c1 = 'a '; +select length(c1), c1 from t1 where c1 = 'a'; +select length(c1), c1 from t2 where c1 = 'a '; +select length(c1), c1 from t2 where c1 = 'a'; +drop table t1, t2; + +# 联合索引 +create table t1 (c1 int, c2 varchar(10), c3 varchar(10)) charset utf8mb4; +create index idx1 on t1(c1, c2, c3); +insert into t1 values (1, 'aaa', 'bbb'); +insert into t1 values (2, '张三', '李四'); +select * from t1; +drop table t1; + +create table t1 (c1 int, c2 varchar(10), c3 varchar(10)) charset binary; +create index idx1 on t1(c1, c2, c3); +insert into t1 values (1, 'aaa', 'bbb'); +insert into t1 values (2, '张三', '李四'); +select * from t1; +drop table t1; + +create table t1 (c1 int, c2 varchar(10), c3 varchar(10)) charset gbk; +create index idx1 on t1(c1, c2, c3); +insert into t1 values (1, 'aaa', 'bbb'); +insert into t1 values (2, '张三', '李四'); +select * from t1; +drop table t1; + +create table t1 (c1 int, c2 varchar(10), c3 varchar(10)) charset latin1; +create index idx1 on t1(c1, c2, c3); +insert into t1 values (1, 'aaa', 'bbb'); +--error 1366 +insert into t1 values (2, '张三', '李四'); +select * from t1; +drop table t1; + +CREATE USER mohit@localhost IDENTIFIED WITH sha256_password BY 'mohit' PASSWORD HISTORY 1; +SELECT COUNT(*) FROM mysql.password_history WHERE User='mohit' AND Host='localhost'; +CREATE TABLE pwd_history_backup AS SELECT * FROM mysql.password_history WHERE User='mohit' AND Host='localhost'; +ALTER USER mohit@localhost IDENTIFIED WITH mysql_native_password BY 'mohit'; +SELECT COUNT(*) FROM mysql.password_history WHERE User='mohit' AND Host='localhost'; +UPDATE mysql.password_history SET Password = ( SELECT Password FROM pwd_history_backup WHERE User='mohit' AND Host='localhost') WHERE User='mohit' AND Host='localhost'; +drop table pwd_history_backup; +drop user mohit@localhost; + +# set names, insert, hex, weight_string +SET NAMES 'utf8mb4' COLLATE 'utf8mb4_bin'; +create table t1(c1 varchar(5), key(c1)); +INSERT INTO t1 VALUES ('a'),('A'),('À'),('á'); +SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1; +delete from t1; +insert into t1 values('a'),('A'),('AA'),('aa'),('aA'),('Aa'),('ab'),('aB'),('AB'),('Ab'),('b'),('B'); +select c1, hex(c1), hex(weight_string(c1)) from t1; +drop table t1; + +# insert +CREATE TABLE t1 (c1 CHAR(10) CHARACTER SET UTF8MB4 COLLATE utf8mb4_general_ci); +INSERT INTO t1 VALUES ('a'),('A'),('À'),('á'); +SELECT c1, HEX(c1), HEX(WEIGHT_STRING(c1)) FROM t1; +drop table t1; + +# select - collate: weight_string +create table t1 (c1 varchar(5) collate utf8mb4_0900_ai_ci, key(c1)); +create table t2 (c1 varchar(5) collate utf8mb4_bin, key(c1)); +insert into t1 values('a'),('A'),('AA'),('aa'),('aA'),('Aa'),('ab'),('aB'),('AB'),('Ab'),('b'),('B'); +insert into t2 values('a'),('A'),('AA'),('aa'),('aA'),('Aa'),('ab'),('aB'),('AB'),('Ab'),('b'),('B'); +select c1, hex(c1), hex(weight_string(c1)) from t1; # WEIGHT_STRING结果和列collate相关 +select c1, hex(c1), hex(weight_string(c1)) from t2; +drop table t1, t2; + +# select - collate +# order by primary key +create table t1(id int auto_increment primary key, c1 varchar(5), key(c1)); +insert into t1 values(null,'aa'),(null,'aA'),(null,'Aa'),(null,'ab'),(null,'aB'),(null,'AB'),(null,'Ab'),(null,'b'),(null,'B'),(null, 'a'),(null,'A'),(null,'AA'); +select c1 from t1; +drop table t1; +# order by collated key c1 > primary key when collate is specified +create table t1(id int auto_increment primary key, c1 varchar(5) collate utf8mb4_bin, key(c1)); +insert into t1 values(null,'aa'),(null,'aA'),(null,'Aa'),(null,'ab'),(null,'aB'),(null,'AB'),(null,'Ab'),(null,'b'),(null,'B'),(null, 'a'),(null,'A'),(null,'AA'); +# select length(c1), c1 from t1; +drop table t1; +# order by collated key c2 > primary key +create table t1(id int auto_increment primary key, c1 varchar(5) collate utf8mb4_0900_ai_ci, key(c1)); +insert into t1 values(null,'aa'),(null,'aA'),(null,'Aa'),(null,'ab'),(null,'aB'),(null,'AB'),(null,'Ab'),(null,'b'),(null,'B'),(null, 'a'),(null,'A'),(null,'AA'); +select c1 from t1; +drop table t1; +# order by primary key when fields > 2 +create table t1(id int auto_increment primary key, c1 varchar(5) collate utf8mb4_bin, c2 varchar(5) collate utf8mb4_0900_ai_ci, key(c1), key(c2)); +insert into t1 values(null, 'a', 'b'),(null,'b', 'a'),(null, 'AA', 'c'),(null, 'B', 'd'); +select c1 from t1; +drop table t1; +create table t1(id int auto_increment primary key, c1 varchar(5) collate utf8mb4_bin, c2 varchar(5) collate utf8mb4_0900_ai_ci, key(c1)); +insert into t1 values(null, 'a', 'b'),(null,'b', 'a'),(null, 'AA', 'c'),(null, 'B', 'd'); +select c1 from t1; +drop table t1; +create table t1(id int auto_increment primary key, c1 varchar(5) collate utf8mb4_bin, c2 varchar(5), key(c1)); +insert into t1 values(null, 'a', 'b'),(null,'b', 'a'),(null, 'AA', 'c'),(null, 'B', 'd'); +select c1 from t1; +drop table t1; + +set sql_mode = ''; + +# length: order by, group by表现不同 +create table t1(id int auto_increment primary key, c1 varchar(5), c2 varchar(5), key(c1)); +insert into t1 values(null,'a ','a '),(null,'a','a'),(null,'a ','a '),(null,'A ','A '),(null,'A','A'),(null,'A ','A '); +select length(c1), c1, hex(weight_string(c1)) from t1; # innodb: 先length后id, cantian: id +select length(c1), c1, hex(weight_string(c1)) from t1 order by c1 collate utf8mb4_general_ci; +select length(c1), c1, hex(weight_string(c1)) from t1 order by c1 collate utf8mb4_bin; +select length(c1), c1, hex(weight_string(c1)) from t1 order by c1 collate utf8mb4_0900_ai_ci; +select length(c1), c1, hex(weight_string(c1)) from t1 order by c1 collate utf8mb4_0900_bin; +select length(c1), c1, hex(weight_string(c1)) from t1 group by c1 collate utf8mb4_general_ci; +select length(c1), c1, hex(weight_string(c1)) from t1 group by c1 collate utf8mb4_bin; +select length(c1), c1, hex(weight_string(c1)) from t1 group by c1 collate utf8mb4_0900_ai_ci; +select length(c1), c1, hex(weight_string(c1)) from t1 group by c1 collate utf8mb4_0900_bin; +drop table t1; + +# 使用 collate 的不同场景 +create table t1(id int auto_increment primary key, c1 varchar(5), key(c1)); +# 插入数据 +insert into t1 values(null,'a '), (null,'b '), (null,'a'), (null,'A'), (null,'b'), (null, 'B'), (null,'a '), (null,'b '), (null,'AA'), (null,'aA'), (null, 'Aa'), (null, 'aa'), (null, 'D'), (null, 'd'), (null,'C'), (null,'c'); +select c1 from t1; + +# order by +select length(c1), c1 from t1 order by c1; +select length(c1), c1 from t1 order by c1 collate utf8mb4_general_ci; +select length(c1), c1 from t1 order by c1 collate utf8mb4_bin; +select length(c1), c1 from t1 order by c1 collate utf8mb4_0900_ai_ci; +select length(c1), c1 from t1 order by c1 collate utf8mb4_0900_bin; + +# as +select length(c1), c1 as c from t1 order by c1; +select length(c1), c1 collate utf8mb4_general_ci as c from t1 order by c1; +select length(c1), c1 collate utf8mb4_bin as c from t1 order by c1; +select length(c1), c1 collate utf8mb4_0900_ai_ci as c from t1 order by c1; +select length(c1), c1 collate utf8mb4_0900_bin as c from t1 order by c1; + +# group by +select length(c1), c1 from t1 group by c1; +select length(c1), c1 from t1 group by c1 collate utf8mb4_general_ci; +select length(c1), c1 from t1 group by c1 collate utf8mb4_bin; +select length(c1), c1 from t1 group by c1 collate utf8mb4_0900_ai_ci; +select length(c1), c1 from t1 group by c1 collate utf8mb4_0900_bin; + +# aggregate functions +select length(c1), max(c1 collate utf8mb4_general_ci) from t1; +select length(c1), max(c1 collate utf8mb4_bin) from t1; +select length(c1), max(c1 collate utf8mb4_0900_ai_ci) from t1; +select length(c1), max(c1 collate utf8mb4_0900_bin) from t1; + +# distinct +select distinct c1 collate utf8mb4_general_ci from t1; +select distinct c1 collate utf8mb4_bin from t1; +select distinct c1 collate utf8mb4_0900_ai_ci from t1; +select distinct c1 collate utf8mb4_0900_bin from t1; + +# where +select length(c1), c1 from t1 where c1 = _utf8mb4 'a' collate utf8mb4_general_ci; +select length(c1), c1 from t1 where c1 = _utf8mb4 'a' collate utf8mb4_bin; +select length(c1), c1 from t1 where c1 = _utf8mb4 'a' collate utf8mb4_0900_ai_ci; +select length(c1), c1 from t1 where c1 = _utf8mb4 'a' collate utf8mb4_0900_bin; +select length(c1), c1 from t1 where _utf8mb4 'a' collate utf8mb4_general_ci = c1; +select length(c1), c1 from t1 where _utf8mb4 'a' collate utf8mb4_bin = c1; +select length(c1), c1 from t1 where _utf8mb4 'a' collate utf8mb4_0900_ai_ci = c1; +select length(c1), c1 from t1 where _utf8mb4 'a' collate utf8mb4_0900_bin = c1; +select length(c1), c1 from t1 where c1 like _utf8mb4 'a' collate utf8mb4_general_ci; +select length(c1), c1 from t1 where c1 like _utf8mb4 'a' collate utf8mb4_bin; +select length(c1), c1 from t1 where c1 like _utf8mb4 'a' collate utf8mb4_0900_ai_ci; +select length(c1), c1 from t1 where c1 like _utf8mb4 'a' collate utf8mb4_0900_bin; + +# having +select length(c1), c1 from t1 group by c1 having c1 = _utf8mb4 'a' collate utf8mb4_general_ci; +select length(c1), c1 from t1 group by c1 having c1 = _utf8mb4 'a' collate utf8mb4_bin; +select length(c1), c1 from t1 group by c1 having c1 = _utf8mb4 'a' collate utf8mb4_0900_ai_ci; +select length(c1), c1 from t1 group by c1 having c1 = _utf8mb4 'a' collate utf8mb4_0900_bin; +drop table t1; + +CREATE TABLE t1 (c1 INT, c2 BINARY(100), c3 VARBINARY(100), key(c1), key(c2), key(c3)); +INSERT INTO t1 VALUES (null,null,null); +INSERT INTO t1 VALUES (1,'',''); +INSERT INTO t1 VALUES (2,'abcde','abcde'); +INSERT INTO t1 VALUES (100,'abcdefghij','abcdefghij'); +select c1, hex(c2), hex(c3) from t1; +select hex(c2) from t1 where c2 = 'abcde'; +select hex(c2) from t1 where c2 = 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; +select hex(c3) from t1 where c3 = 'abcde'; +select hex(c3) from t1 where c3 = 'ABCDE'; +drop table t1; + +CREATE TABLE t1 (code varchar(10)) charset utf8mb4; +INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13'); +INSERT INTO t1 VALUES (_utf16 0x0061003100320007), (_utf16 0x00410031003200070007); +SELECT LENGTH(code), HEX(code) FROM t1 WHERE code='A12'; +ALTER TABLE t1 ADD INDEX (code); +CREATE TABLE t2 (id varchar(10) PRIMARY KEY) charset utf8mb4; +INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14'); +SELECT LENGTH(code), HEX(code), LENGTH(id), HEX(id) FROM t1 INNER JOIN t2 ON t1.code=t2.id WHERE t2.id='a12' AND (LENGTH(code)=5 OR code < 'a00'); +SELECT LENGTH(code), HEX(code), LENGTH(id), HEX(id) FROM t1 INNER JOIN t2 ON t1.code=t2.id WHERE t2.id='a12' AND (LENGTH(code)=3); +drop table t1, t2; + +set names koi8r; +create table t1(a char character set cp1251 default _koi8r 0xFF); +show create table t1; +drop table t1; + +create table t1(c1 char character set cp1251); +insert into t1 values('a'), ('b'); +alter table t1 add column c2 char character set cp1251 default _koi8r 0xFF; +insert into t1 values('c', default), ('d', default); +select c1, hex(c2), c2, length(c2) from t1; +show create table t1; +drop table t1; + +set names cp1250; +CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY, str VARCHAR(32) CHARACTER SET cp1250 COLLATE cp1250_czech_cs NOT NULL default '', UNIQUE KEY (str)); +drop table t1; + +SET collation_connection='eucjpms_japanese_ci'; +CREATE TABLE t1 AS SELECT 10 AS a, REPEAT('a',20) AS b, REPEAT('a',8) AS c, REPEAT('a',8) AS d; +ALTER TABLE t1 ADD PRIMARY KEY(a), ADD KEY(b); +drop table t1; + +set names utf8mb4; + +SET sql_mode = default; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_compressed_proxy_conn.test b/mysql-test/suite/tianchi/t/ctc_compressed_proxy_conn.test new file mode 100644 index 0000000..d052026 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_compressed_proxy_conn.test @@ -0,0 +1,16 @@ +# server set to allow new connection must use zstd compressed header to handshake +SET GLOBAL protocol_compression_algorithms= "zstd"; +# next SET SQL will new a internal proxy conn. only proxy conn support compressed can it succeed. +SET GLOBAL protocol_compression_algorithms= "zstd"; +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +insert into t1 values (1, 'LIOR', 35, 6.9); +insert into t1 values (4, 'MIKE', 55, 99.92); +SELECT * FROM t1; +drop table t1; +SET GLOBAL protocol_compression_algorithms= "zlib"; +SET GLOBAL protocol_compression_algorithms= "zlib"; +# set back to original options +SET GLOBAL protocol_compression_algorithms= "zlib,zstd,uncompressed"; diff --git a/mysql-test/suite/tianchi/t/ctc_cond_pushdown.test b/mysql-test/suite/tianchi/t/ctc_cond_pushdown.test new file mode 100644 index 0000000..d882afe --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_cond_pushdown.test @@ -0,0 +1,288 @@ +--disable_warnings +drop table if exists t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15; +--enable_warnings + +CREATE TABLE t1(c1 tinyint, c2 tinyint not null, c3 tinyint signed, c4 tinyint unsigned, c5 int, c6 long); +INSERT INTO t1 VALUES (1,1,1,1,1,1), (2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null); +INSERT INTO t1 VALUES (3,3,3,3,3,3), (4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null); +INSERT INTO t1 VALUES (8,8,127,255,8,8); +select * from t1; + +CREATE TABLE t2(c1 float , c2 float(6, 3), c3 float(6,3), c4 double, c5 double(6, 3), c6 double(6, 3)); +INSERT INTO t2 VALUES (1.1,11.11, 11.11111,1.1,11.11,11.11111), (2.2,22.22,22.22222, 2.2,22.22, 22.22222), (3.3,33.33, 33.33333, 3.3,33.33, 33.33333); +select * from t2; + +CREATE TABLE t3(c1 DECIMAL(10,5) UNSIGNED NOT NULL, c2 DECIMAL(10,5) SIGNED NULL, c3 DECIMAL); +INSERT INTO t3 VALUES ('11111.11111','11111.11111','1111111111'),('22222.22222','22222.22222','2222222222'),('33333.33333','33333.33333','3333333333'),('44444.44444','44444.44444','4444444444'),('55555.55555','55555.55555','5555555555'); +select * from t3; + +CREATE TABLE t4(c1 char(10), c2 varchar(20), c3 varchar(20) binary); +INSERT INTO t4 VALUES ('1234','abcd','abcd'), ('123','ABCD','ABCD'),('123456','aBcD','aBcD'),('23456','abCD','abCD'),('','',''),(null, null, null); +select * from t4; + +CREATE TABLE t5(c1 TIME, c2 TIME NOT NULL); +INSERT INTO t5 VALUES ('01:01:01.01', '1000-01-01 00:00:00'); +INSERT INTO t5 VALUES ('01:01:01.00', '1999-12-31 23:59:59'); +INSERT INTO t5 VALUES ('02:02:02', '2000-01-01 00:00:00'); +INSERT INTO t5 VALUES ('02:02:02', '2008-02-29 13:13:13'); +select * from t5; + +CREATE TABLE t6(c1 DATE, c2 DATE NOT NULL); +INSERT INTO t6 VALUES('1000-01-01', '1000-01-01 00:00:00'); +INSERT INTO t6 VALUES('1999-12-31', '1999-12-31 23:59:59'); +INSERT INTO t6 VALUES('2000-01-01', '2000-01-01 00:00:00'); +INSERT INTO t6 VALUES('2008-02-29', '2008-02-29 13:13:13'); +select * from t6; + +CREATE TABLE t7(c1 DATETIME, c2 DATETIME NOT NULL); +INSERT INTO t7 VALUES('1000-01-01', '1000-01-01 00:00:00'); +INSERT INTO t7 VALUES('1999-12-31', '1999-12-31 23:59:59'); +INSERT INTO t7 VALUES('2000-01-01', '2000-01-01 00:00:00'); +INSERT INTO t7 VALUES('2008-02-29', '2008-02-29 13:13:13'); +select * from t7; + +CREATE TABLE t8(c1 TIMESTAMP, c2 TIMESTAMP NOT NULL); +INSERT INTO t8 VALUES('1999-12-31', '1999-12-31 23:59:59'); +INSERT INTO t8 VALUES('2000-01-01', '2000-01-01 00:00:00'); +INSERT INTO t8 VALUES('2008-02-29', '2008-02-29 13:13:13'); +select * from t8; + +CREATE TABLE t9(c1 bool, c2 bool NOT NULL); +INSERT INTO t9 VALUES(true, true); +INSERT INTO t9 VALUES(false, false); +INSERT INTO t9 VALUES(null, false); +select * from t9; + +CREATE TABLE t10(c1 int, c2 int, key(c1,c2)); +INSERT INTO t10 VALUES (94,94),(64,64),(69,69),(97,97); +select * from t10; + +CREATE TABLE t11(c1 YEAR, c2 YEAR, UNIQUE INDEX idx(c1,c2)); +INSERT INTO t11 VALUES (94, 94),(64, 64),(69, 69),(97, null); +INSERT INTO t11 VALUES (4, null),(8, 8),(null, 35),(75, 75); +select * from t11; + +create table t12 (IDA blob); +insert into t12 (IDA) values ('aaa'); +select * from t12; + +create table t13(id int, a_integer integer, b_char char, c_varchar varchar(10), d_deciaml decimal, e_tinyint tinyint, f_bigint bigint, g_float float, h_date date); +insert into t13 values(1, 11, "b", "varchar", 111, 10, 100, 10.01, 20220923); +insert into t13 values(2, 22, "b", "varchar", 222, 20, 200, 20.01, 20220923); +insert into t13 values(3, 33, "b", "varchar", 333, 30, 300, 30.01, 20220923); +insert into t13 values(4, 44, "b", "varchar", 444, 40, 400, 40.01, 20220923); +insert into t13 values(5, 55, "b", "varchar", 555, 50, 500, 50.01, 20220923); +select * from t13; + +CREATE TABLE t14(c1 char(5), c2 varchar(2000)); +INSERT INTO t14 VALUES ('1111','1111111111111111111111111111111111122222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555555555555555555555555'); +select * from t14; + +CREATE TABLE t15 (c1 INT, c2 BINARY(100), c3 VARBINARY(100)); +INSERT INTO t15 VALUES (null,null,null); +INSERT INTO t15 VALUES (1,'',''); +INSERT INTO t15 VALUES (2,'abcde','abcde'); +INSERT INTO t15 VALUES (100,'abcdefghij','abcdefghij'); +select c1, hex(c2), hex(c3) from t15; + +# tinyint +select * from t1 where c3 = 255; +select * from t1 where c1 = 3; +select * from t1 where c1 > 3; +select * from t1 where c1 != 3; +select * from t1 where c2 = 3; + +# unsigned +select * from t1 where c4 = 255; + +# float double +select * from t2 where c3 = 11.111; +select * from t2 where c4 = 1.1; +select * from t2 where c6 = 11.111; + +# null +select * from t1 where null <=> null; +select * from t1 where c1 = null; +select * from t1 where c1 != null; +select * from t1 where c1 > null; +select * from t1 where c1 < null; +select * from t1 where c1 <=> null; +select * from t1 where c1 is null; +select * from t1 where c1 is not null; +select * from t1 where not c1 <=> null; +select * from t1 where c1 > 3 or c2 = 4 or c3 >=3 or c4 = 5 or (c1 > 1 and c2 < 5 and c3 > 2); + +# decimal +select * from t3 where c1 = '22222.22222'; +select * from t3 where c1 > '22222.22222'; +select * from t3 where c1 < '22222.33333'; +select * from t3 where c1 > '222'; +select * from t3 where c1 > '0.1'; +select * from t3 where c1 > '0.0'; +select * from t3 where c1 > '0'; +select * from t3 where c2 = '22222.22222'; +select * from t3 where c2 > '22222.22222'; +select * from t3 where c2 < '22222.33333'; +select * from t3 where c2 > '222'; +select * from t3 where c2 > '0.1'; +select * from t3 where c2 > '0.0'; +select * from t3 where c2 > '0'; +select * from t3 where c1 like '%3'; +select * from t3 where c1 like '3%'; +select * from t3 where c1 not like '1'; +select * from t3 where not c1 like '1'; +select * from t3 where c3 = 1111111111; +select * from t3 where c3 > 1111111111.0; +select * from t3 where c3 > 1111111111.; +select * from t3 where c3 = 1.0; +select * from t3 where c3 > 1; +select * from t3 where c1 > '11111.11111' and c1 < '55555.55555'; +select * from t3 where c1 > '11111.11111' and c1 < '55555.55555'; + + +# bool +select * from t9 where c1 is null; +select * from t9 where c1 is not null; +select * from t9 where c1 is true; +select * from t9 where c1 is not true; +select * from t9 where c1 is false; +select * from t9 where c1 = 1; + +# char +select * from t4 where c1 = '1234'; +select * from t4 where c1 > '123'; +select * from t14 where c2 = '1111111111111111111111111111111111122222222222222222222222222222222222222223333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333344444444444444444444444444444444444444444444444444444444444444444444455555555555555555555555555555555555555555555555555555555555555555555555555555555555555'; +select * from t4 where c1 = ''; +select * from t4 where c1 = '' and c2 = ''; +select * from t4 where c1 = '' and c2 = ''; +select * from t4 where c1 = null; +select * from t4 where c1 <=> null; + +# sensitive +select * from t4 where c2 = 'abcd'; +select * from t4 where c3 = 'abcd'; +select * from t4 where c2 = 'ABCD'; +select * from t4 where c3 = 'ABCD'; +select * from t4 where c2 like 'ab%'; +select * from t4 where c3 like 'ab%'; + +# like +select * from t14 where c1 = '1111'; +select * from t14 where c1 like '%111'; +select * from t14 where c1 not like '%111'; +select * from t14 where not c1 like '%111'; +select * from t14 where not c1 like '1111'; +select * from t14 where c1 not like '1_11'; +select * from t14 where not c1 like '1_11'; +select * from t14 where c1 like concat('%','1','%'); + +# and or xor not +select * from t1 where c1 > 3 and c2 = 4 and c3 >=1; +select * from t1 where c1 > 3 and c2 = 8; +select * from t1 where not c1 > 3; +select * from t1 where not (c1 > 3 and c2 = 4 and c3 >=1); +select * from t1 where c1 = 1 xor c2 = 5; +select * from t1 where c1 = 1 xor c2 = 1; +select * from t1 where c1 > 3 or c2 = 4 or c3 >=3 or c4 = 5 or (c1 > 1 and c2 < 5 and c3 > 2); + + +# index +select c1 from t10 where c2=69; +select c1 from t10 where c1=69; +select c1 from t11 where c2=69; +select c1 from t11 where c2=69; +select c1,c2 from t11 where c2=4; + +# drop column +select * from t13 where e_tinyint = 30; +alter table t13 drop column d_deciaml; +select * from t13 where e_tinyint = 30; + +# binary +select hex(c2) from t15 where c2 = 'abcde'; +select hex(c2) from t15 where c2 = 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; +select hex(c3) from t15 where c3 = 'abcde'; + +# time +select * from t5 where c1 = '01:01:01.01'; +select * from t5 where c1 > '01:01:01.01'; +select * from t5 where c1 = '02:02:02'; +select * from t5 where c2 = '00:00:00'; +select * from t5 where c2 = '1000-01-01 00:00:00'; +select * from t5 where c2 = '1999-12-31 23:59:59'; + +select * from t6 where c1 = '1000-01-01'; +select * from t6 where c1 = '1000-01-01 00:00:00'; +select * from t6 where c1 > '1000-01-01 00:00:00'; +select * from t6 where c2 = '1000-01-01'; +select * from t6 where c2 = '1000-01-01 00:00:00'; + +select * from t7 where c1 = '1000-01-01'; +select * from t7 where c1 = '1000-01-01 00:00:00'; +select * from t7 where c1 > '1000-01-01 00:00:00'; +select * from t7 where c2 = '1000-01-01'; +select * from t7 where c2 = '1000-01-01 00:00:00'; + +select * from t8 where c1 = '2000-01-01'; +select * from t8 where c1 = '2000-01-01 00:00:00'; +select * from t8 where c1 > '2000-01-01 00:00:00'; +select * from t8 where c2 = '2000-01-01'; +select * from t8 where c2 = '2000-01-01 00:00:00'; + +select * from t11 where c1 = 4; +select * from t11 where c1 = 2004; +select * from t11 where c1 = '2004'; +#select * from t11 where c1 = 'abc'; +select * from t11 where c1 = 2004.0; +#select * from t11 where 'abc' = c1; +select * from t11 where '2004' = c1; + + +# blob: not supported +select * from t12 where IDA = 'aaa'; + +# enum: not supported +drop table if exists tickets; +CREATE TABLE tickets ( + id INT PRIMARY KEY AUTO_INCREMENT, + title VARCHAR(255) NOT NULL, + priority ENUM('Low', 'Medium', 'High') NOT NULL +); +INSERT INTO tickets(title, priority) VALUES('Scan virus for computer A', 'High'); +INSERT INTO tickets(title, priority) VALUES('Upgrade Windows OS for all computers', 1); +INSERT INTO tickets(title) VALUES('Refresh the computer of Ms. Lily'); +SELECT * FROM tickets WHERE priority = 3; +drop table if exists tickets; + +# set: not supported +drop table if exists myset; +CREATE TABLE myset (col SET('a', 'b', 'c', 'd')); +INSERT INTO myset (col) VALUES('a,d'); +INSERT INTO myset (col) VALUES('d,a'); +INSERT INTO myset (col) VALUES('a,d,a'); +INSERT INTO myset (col) VALUES('a,d,d'); +INSERT INTO myset (col) VALUES('d,a,d'); +INSERT INTO myset (col) VALUES('A'); +INSERT INTO myset (col) VALUES('a,C,b,d'); +select * from myset where col = 'a'; +select * from myset where col = 'a,d'; +select * from myset where col like 'a,d'; +drop table if exists myset; + +drop table t1; +drop table t2; +drop table t3; +drop table t4; +drop table t5; +drop table t6; +drop table t7; +drop table t8; +drop table t9; +drop table t10; +drop table t11; +drop table t12; +drop table t13; +drop table t14; +drop table t15; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_cond_pushdown_explain.test b/mysql-test/suite/tianchi/t/ctc_cond_pushdown_explain.test new file mode 100644 index 0000000..e283388 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_cond_pushdown_explain.test @@ -0,0 +1,140 @@ +--disable_warnings +drop table if exists t1, t2, t3, t4, t5, t6, t7; + +CREATE TABLE t1(c1 TINYINT, c2 SMALLINT not null, c3 MEDIUMINT, c4 INT unsigned, c5 INT, c6 BIGINT, c7 BIGINT unsigned); +INSERT INTO t1 VALUES (1,1,1,1,1,1,1), (2,2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null,null); +INSERT INTO t1 VALUES (3,3,3,3,3,3,3), (4,4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null,null); +INSERT INTO t1 VALUES (8,8,127,255,8,8,8); +select * from t1; + +# > < = >= <= != <=> and integer type supported to push down +select * from t1 where c1 > 1; +explain select * from t1 where c1 > 1; +select * from t1 where c2 < 7; +explain select * from t1 where c2 < 7; +select * from t1 where c3 = 3; +explain select * from t1 where c3 = 3; +select * from t1 where c4 >= 4; +explain select * from t1 where c4 >= 4; +select * from t1 where c5 <= 8; +explain select * from t1 where c5 <= 8; +select * from t1 where c6 != 2; +explain select * from t1 where c6 != 2; +select * from t1 where c5 <=> null; +explain select * from t1 where c5 <=> null; +select * from t1 where c1 = null; +explain select * from t1 where c1 = null; + +# bigint unsigned not supported to push down +select * from t1 where c7 = 8; +explain select * from t1 where c7 = 8; + +# like is null is not null supported to push down +CREATE TABLE t2(c1 char(10), c2 varchar(20), c3 varchar(20) binary); +INSERT INTO t2 VALUES ('1234','abcd','abcd'), ('123','ABCD','ABCD'),('123456','aBcD','aBcD'),('23456','abCD','abCD'),('','',''),(null, null, null); +select * from t2; +select * from t2 where c1 like '%123%'; +explain select * from t2 where c1 like '%123%'; +select * from t2 where c2 like '%abc%'; +explain select * from t2 where c2 like '%abc%'; +select * from t2 where c1 is null; +explain select * from t2 where c1 is null; +select * from t2 where c2 is null; +explain select * from t2 where c2 is null; +select * from t2 where c1 is not null; +explain select * from t2 where c1 is not null; +select * from t2 where c2 is not null; +explain select * from t2 where c2 is not null; + +# varchar binary is case sensitive +select * from t2 where c3 like '%abc%'; +explain select * from t2 where c3 like '%abc%'; + +# float double supported to push down +CREATE TABLE t3(c1 float , c2 float(6,3), c3 double, c4 double(6,3)); +INSERT INTO t3 VALUES (1.1,11.11,1.1,11.11), (2.2,22.22,2.2,22.22), (3.3,33.33,3.3,33.33); +select * from t3; +select * from t3 where c1 = 1.1; +explain select * from t3 where c1 = 1.1; +select * from t3 where c2 > 1.1; +explain select * from t3 where c2 > 1.1; +select * from t3 where c3 < 3.3; +explain select * from t3 where c3 < 3.3; +select * from t3 where c4 >= 11.11; +explain select * from t3 where c4 >= 11.11; +select * from t3 where c1 <= 3.3; +explain select * from t3 where c1 <= 3.3; +select * from t3 where c2 != 22.22; +explain select * from t3 where c2 != 22.22; +select * from t3 where c3 <=> 2.2; +explain select * from t3 where c3 <=> 2.2; + +# decimal supported to push down +CREATE TABLE t4(c1 DECIMAL(10,5) UNSIGNED NOT NULL, c2 DECIMAL(10,5) SIGNED NULL, c3 DECIMAL); +INSERT INTO t4 VALUES ('11111.11111','11111.11111','1111111111'),('22222.22222','22222.22222','2222222222'),('33333.33333','33333.33333','3333333333'); +select * from t4; +select * from t4 where c1 = '11111.11111'; +explain select * from t4 where c1 = '11111.11111'; +select * from t4 where c1 > '22222.22222'; +explain select * from t4 where c1 > '22222.22222'; +select * from t4 where c1 < '33333.33333'; +explain select * from t4 where c1 < '33333.33333'; +select * from t4 where c2 >= '11111.11111'; +explain select * from t4 where c2 >= '11111.11111'; +select * from t4 where c2 <= '22222.22222'; +explain select * from t4 where c2 <= '22222.22222'; +select * from t4 where c2 != '33333.33333'; +explain select * from t4 where c2 != '33333.33333'; +select * from t4 where c3 <=> '1111111111'; +explain select * from t4 where c3 <=> '1111111111'; + +# year time date datetime timestamp supported to push down +CREATE TABLE t5(c1 year, c2 TIME, c3 DATE, c4 DATETIME, c5 TIMESTAMP); +INSERT INTO t5 VALUES (94, '1999-12-31 23:59:59', '2000-01-01', '2008-02-29 13:13:13', '2012-03-04 11:21:14'); +INSERT INTO t5 VALUES (2014, '2001-12-31 23:59:59', '2004-01-01', '2007-01-29 13:13:13', '2014-03-04 11:21:14'); +INSERT INTO t5 VALUES (2023, '2009-12-31 23:59:59', '2012-01-01', '2015-05-29 13:13:13', '2020-03-04 11:21:14'); +select * from t5; +select * from t5 where c1 = 1994; +explain select * from t5 where c1 = 1994; +select * from t5 where c2 > '23:59:50'; +explain select * from t5 where c2 > '23:59:50'; +select * from t5 where c3 < '2012-01-01'; +explain select * from t5 where c3 < '2012-01-01'; +select * from t5 where c4 >= '2008-02-29 13:13:13'; +explain select * from t5 where c4 >= '2008-02-29 13:13:13'; +select * from t5 where c5 <=> '2020-03-04 11:21:14'; +explain select * from t5 where c5 <=> '2020-03-04 11:21:14'; + +CREATE TABLE t6(x VARCHAR(10), gc INTEGER GENERATED ALWAYS AS (x LIKE 'abba' ESCAPE 'b'), y INTEGER, gc_1 INTEGER GENERATED ALWAYS AS (y + 1), z varchar(20)); +insert into t6 values('abba', default, 1, default, 'aasf'); +insert into t6 values('aba', default, 2, default, 'afgc'); +insert into t6 values('bbba', default, 4, default, 'test'); +select * from t6; +# gcol not supported to push down +explain select * from t6 where gc <> 0; +select * from t6 where x = 'abba'; +explain select * from t6 where x = 'abba'; +select * from t6 where y = 2; +explain select * from t6 where y = 2; +select * from t6 where z = 'test'; +explain select * from t6 where z = 'test'; + +# push cache item for integer type +CREATE TABLE t7(c1 TINYINT, c2 SMALLINT not null, c3 MEDIUMINT, c4 INT); +insert into t7 values(-1, -5, -7, -9); +insert into t7 values(-11, -15, -17, -19); +insert into t7 values(-21, -25, -27, -29); +insert into t7 values(-31, -35, -37, -39); +select * from t7 where c1 < -10; +explain select * from t7 where c1 < -10; +select * from t7 where c2 >= -15; +explain select * from t7 where c2 >= -15; +select * from t7 where c3 = -27; +explain select * from t7 where c3 = -27; +select * from t7 where c4 != -39; +explain select * from t7 where c4 != -39; + +--enable_warnings +drop table t1, t2, t3, t4, t5, t6, t7; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_crud_for_drop_column.test b/mysql-test/suite/tianchi/t/ctc_crud_for_drop_column.test new file mode 100644 index 0000000..04ea241 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_crud_for_drop_column.test @@ -0,0 +1,453 @@ +drop database if exists test_DB; +create database test_DB; +use test_DB; + +#定长int类型,无索引,删去一列,插入数据,更新数据,删去一列,插入数据,更新数据(列前,列后,列前后),删除数据,删除表 +create table t1 (a int, b int, c int, d int, e int); +insert into t1 values(1, 2, 3, 4, 5); +insert into t1 values(2, 2, 3, 4, 5); +insert into t1 values(3, 2, 3, 4, 5); +insert into t1 values(4, 2, 3, 4, 5); +insert into t1 values(5, 2, 3, 4, 5); +select * from t1; +#删去c列 +alter table t1 drop column c; +select * from t1; +#插入数据 +insert into t1 values(6, 2, 4, 5); +select * from t1; +#更新数据 +update t1 set e = 55 where a = 5; +select * from t1; +#删去d列 +alter table t1 drop column d; +select * from t1; +#插入数据 +insert into t1 values(7, 2, 5); +select * from t1; +#更新被删列前的列 +update t1 set b = 22 where a = 7; +select * from t1; +#更新被删列后的列 +update t1 set e = 55 where a = 7; +select * from t1; +#同时更新被删列前后的列 +update t1 set b = 8, e = 8 where a = 7; +select * from t1; +#删除数据 +delete from t1 where a = 7; +select * from t1; +#删除表 +drop table t1; + + +#定长int类型,普通索引,删去一列,插入数据,更新数据,普通查询,index_only查询,删去一列,插入数据,更新数据(列前,列后,列前后),普通查询,index_only查询,删除数据,删除表 +create table t2 (a int, b int, c int, d int, e int); +insert into t2 values(1, 2, 3, 4, 5); +insert into t2 values(2, 2, 3, 4, 5); +insert into t2 values(3, 2, 3, 4, 5); +insert into t2 values(4, 2, 3, 4, 5); +insert into t2 values(5, 2, 3, 4, 5); +select * from t2; +#建立索引 +create index t2_i on t2(a); +select* from t2; +#删去c列 +alter table t2 drop column c; +select * from t2; +#插入数据 +insert into t2 values(6, 2, 4, 5); +select * from t2; +#更新数据 +update t2 set e = 55 where a = 5; +select * from t2; +#index_only查询 +select a from t2; +#删去d列 +alter table t2 drop column d; +select * from t2; +#插入数据 +insert into t2 values(7, 2, 5); +select * from t2; +#更新被删列前的列 +update t2 set b = 22 where a = 7; +select * from t2; +#更新被删列后的列 +update t2 set e = 55 where a = 7; +select * from t2; +#同时更新被删列前后的列 +update t2 set b = 8, e = 8 where a = 7; +select * from t2; +#index_only查询 +select a from t2; +#删除数据 +delete from t2 where a = 7; +select * from t2; +#删除表 +drop table t2; + + +#定长int类型,联合索引,删去一列,插入数据,更新数据,普通查询,index_only查询,删去一列,插入数据,更新数据(列前,列后,列前后),普通查询,index_only查询,删除数据,删除表 +create table t3 (a int, b int, c int, d int, e int); +insert into t3 values(1, 2, 3, 4, 5); +insert into t3 values(2, 2, 3, 4, 5); +insert into t3 values(3, 2, 3, 4, 5); +insert into t3 values(4, 2, 3, 4, 5); +insert into t3 values(5, 2, 3, 4, 5); +select * from t3; +#建立索引 +create index t3_i on t3(a, b); +select* from t3; +#删去c列 +alter table t3 drop column c; +select * from t3; +#插入数据 +insert into t3 values(6, 2, 4, 5); +select * from t3; +#更新数据 +update t3 set e = 55 where a = 5; +select * from t3; +#index_only查询 +select a from t3; +select a, b from t3; +#删去d列 +alter table t3 drop column d; +select * from t3; +#插入数据 +insert into t3 values(7, 2, 5); +select * from t3; +#更新被删列前的列 +update t3 set b = 22 where a = 7; +select * from t3; +#更新被删列后的列 +update t3 set e = 55 where a = 7; +select * from t3; +#同时更新被删列前后的列 +update t3 set b = 8, e = 8 where a = 7; +select * from t3; +#index_only查询 +select a from t3; +select a, b from t3; +#删除数据 +delete from t3 where a = 7; +select * from t3; +#删除表 +drop table t3; + + +#变长varchar类型,无索引,删去一列,插入数据,更新数据,删去一列,插入数据,更新数据(列前,列后,列前后),删除数据,条件查询,删表 +create table t4(a int, b varchar(10), c varchar(10), d varchar(20), e varchar(10)); +insert into t4 values(1, "bb", "ccc", "dddd", "eeeee"); +insert into t4 values(2, "bb", "ccc", "dddd", "eeeee"); +insert into t4 values(3, "bb", "ccc", "dddd", "eeeee"); +insert into t4 values(4, "bb", "ccc", "dddd", "eeeee"); +insert into t4 values(5, "bb", "ccc", "dddd", "eeeee"); +select * from t4; +#删去c列 +alter table t4 drop column c; +select * from t4; +#插入数据 +insert into t4 values(6, "bb", "dddd", "eeeee"); +select * from t4; +#更新数据 +update t4 set e = "ee" where a = 6; +select * from t4; +#删去d列 +alter table t4 drop column d; +select * from t4; +#插入数据 +insert into t4 values(7, "bb", "eeeee"); +select * from t4; +#更新被删列前的列 +update t4 set b = "bbbbbbb" where a = 7; +select * from t4; +#更新被删列后的列 +update t4 set e = "eeeeeee" where a = 7; +select * from t4; +#同时更新被删列前后的列 +update t4 set b = "b", e = "e" where a = 7; +select * from t4; +#删除数据 +delete from t4 where a = 7; +select * from t4; +#条件查询 +select * from t4 where a = 6; +#删表 +drop table t4; + + + +#变长varchar类型,普通索引,删去一列,插入数据,更新数据,普通查询,index_only查询,删去一列,插入数据,更新数据(列前,列后,列前后),普通查询,条件查询,index_only查询,删除数据,删表 +create table t5(a int, b varchar(10), c varchar(10), d varchar(20), e varchar(10)); +insert into t5 values(1, "bb", "ccc", "dddd", "eeeee"); +insert into t5 values(2, "bb", "ccc", "dddd", "eeeee"); +insert into t5 values(3, "bb", "ccc", "dddd", "eeeee"); +insert into t5 values(4, "bb", "ccc", "dddd", "eeeee"); +insert into t5 values(5, "bb", "ccc", "dddd", "eeeee"); +select * from t5; +#创建索引 +create index t5_i on t5(a); +select * from t5; +#删去c列 +alter table t5 drop column c; +select * from t5; +#插入数据 +insert into t5 values(6, "bb", "dddd", "eeeee"); +select * from t5; +#更新数据 +update t5 set e = "ee" where a = 6; +select * from t5; +#删去d列 +alter table t5 drop column d; +select * from t5; +#插入数据 +insert into t5 values(7, "bb", "eeeee"); +select * from t5; +#更新被删列前的列 +update t5 set b = "bbbbbbb" where a = 7; +select * from t5; +#更新被删列后的列 +update t5 set e = "eeeeeee" where a = 7; +select * from t5; +#同时更新被删列前后的列 +update t5 set b = "b", e = "e" where a = 7; +select * from t5; +#条件查询 +select * from t5 where a = 6; +#index_only查询 +select a from t5; +#删除数据 +delete from t5 where a = 7; +select * from t5; +#删表 +drop table t5; + + + +#变长varchar类型,联合索引,删去一列,插入数据,更新数据,普通查询,index_only查询,删去一列,插入数据,更新数据(列前,列后,列前后),普通查询,条件查询,index_only查询,删除数据, 删表 +create table t6(a int, b varchar(10), c varchar(10), d varchar(20), e varchar(10)); +insert into t6 values(1, "bb", "ccc", "dddd", "eeeee"); +insert into t6 values(2, "bb", "ccc", "dddd", "eeeee"); +insert into t6 values(3, "bb", "ccc", "dddd", "eeeee"); +insert into t6 values(4, "bb", "ccc", "dddd", "eeeee"); +insert into t6 values(5, "bb", "ccc", "dddd", "eeeee"); +select * from t6; +#创建联合索引 +create index t6_i on t6(a, b); +select * from t6; +#删去c列 +alter table t6 drop column c; +select * from t6; +#插入数据 +insert into t6 values(6, "bb", "dddd", "eeeee"); +select * from t6; +#更新数据 +update t6 set e = "ee" where a = 6; +select * from t6; +#删去d列 +alter table t6 drop column d; +select * from t6; +#插入数据 +insert into t6 values(7, "bb", "eeeee"); +select * from t6; +#更新被删列前的列 +update t6 set b = "bbbbbbb" where a = 7; +select * from t6; +#更新被删列后的列 +update t6 set e = "eeeeeee" where a = 7; +select * from t6; +#同时更新被删列前后的列 +update t6 set b = "b", e = "e" where a = 7; +select * from t6; +#条件查询 +select * from t6 where a = 6; +#index_only查询 +select a from t6; +select a, b from t6; +#删除数据 +delete from t6 where a = 7; +select * from t6; +#删表 +drop table t6; + + +#包含多种数据类型的表,删去一列,插入数据,更新数据,删去一列,插入数据,更新数据,条件查询,index_only查询,删除数据,删表 +create table t7(id int, a_integer integer, b_char char, c_varchar varchar(10), d_deciaml decimal, e_tinyint tinyint, f_bigint bigint, g_float float, h_date date); +insert into t7 values(1, 1, "b", "varchar", 1, 1, 100, 10.01, 20220923); +insert into t7 values(2, 1, "b", "varchar", 2, 2, 200, 20.01, 20220923); +insert into t7 values(3, 1, "b", "varchar", 3, 3, 300, 30.01, 20220923); +insert into t7 values(4, 1, "b", "varchar", 4, 4, 400, 40.01, 20220923); +insert into t7 values(5, 1, "b", "varchar", 5, 5, 500, 50.01, 20220923); +select * from t7; +#删去b列 +alter table t7 drop column b_char; +select * from t7; +#插入数据 +insert into t7 values(6, 1, "varchar", 6, 6, 600, 60.01, 20220923); +select * from t7; +#更新数据 +update t7 set h_date = 20220924 where id = 6; +select * from t7; +#创建联合索引 +create index t7_i on t7(id, a_integer); +select * from t7; +#删去d列 +alter table t7 drop column d_deciaml; +select * from t7; +#插入数据 +insert into t7 values(7, 1, "varchar", 7, 700, 70.01, 20220923); +select * from t7; +#更新数据 +update t7 set g_float = 70.77 where id = 7; +select * from t7; +#条件查询 +select * from t7 where e_tinyint = 7; +#index_only查询 +select id, a_integer from t7; +#删除数据 +delete from t7 where id = 7; +select * from t7; +#删表 +drop table t7; + +#建立联合索引,删除联合索引中的一列,并进行index_only查询 +create table t8(a int, b varchar(10), c varchar(10)); +insert into t8 values(1, "bb", "ccc"); +insert into t8 values(2, "bb", "ccc"); +select * from t8; +#创建联合索引 +create index t8_i on t8(a, b, c); +select * from t8; +#删去b列 +alter table t8 drop column b; +select * from t8; +#index_only查询 +select * from t8; +#插入数据 +insert into t8 values(3, "ccc"); +select * from t8; +#index_only查询 +select a, c from t8; +#删表 +drop table t8; + +#表中有null的情况 +create table t9 (a int, b int, c int, d int, e int); +insert into t9 values(1, 2, 3, 4, 5); +insert into t9 values(2, 2, null, 4, 5); +insert into t9 values(3, 2, 3, null, 5); +select * from t9; +#删去c列 +alter table t9 drop column c; +select * from t9; +#插入含有null的数据 +insert into t9 values(4, 2, null, 5); +select * from t9; +#删表 +drop table t9; + + +#数据类型涉及decimal,非index_only查询 +CREATE TABLE t10 (a int, b int, c NUMERIC, d int, e int, f DECIMAL, g int) ; +insert into t10 values(1,2,3,4,5,6,7); +insert into t10 values(2,2,3,4,5,6,7); +insert into t10 values(3,2,3,4,5,6,7); +select * from t10; +#创建索引 +create index idx10 on t10 (a,b,c); +#删去b列 +alter table t10 drop column b; +select * from t10; +#插入数据 +insert into t10 values(4,3,4,5,6,7); +select * from t10; +#index_only查询 +select a,c from t10; +update t10 set d = 44 where a = 3; +select * from t10; +update t10 set f = 66 where a = 4; +select * from t10; +#删去NUMERIC列 +alter table t10 drop column c; +select * from t10; +#插入数据 +insert into t10 values(5,4,5,6,7); +#普通查询 +select * from t10; +select * from t10 where a = 4; +#删表 +drop table t10; + + +#数据类型涉及decimal,index_only查询 +CREATE TABLE t11 (a int, b int, c NUMERIC, d int, e int, f DECIMAL, g int) ; +insert into t11 values(1,2,3,4,5,6,7); +insert into t11 values(2,2,3,4,5,6,7); +insert into t11 values(3,2,3,4,5,6,7); +select * from t11; +#创建全表索引 +create index idx11 on t11 (a,b,c,d,e,f,g); +#删去b列 +alter table t11 drop column b; +select * from t11; +#插入数据 +insert into t11 values(4,3,4,5,6,7); +select * from t11; +#更新数据 +update t11 set a = 44, d = 44 where a = 4; +select * from t11; +#删去NUMERIC列 +alter table t11 drop column c; +select * from t11; +#插入数据 +insert into t11 values(5,4,5,6,7); +select * from t11; +#删去d列 +alter table t11 drop column d; +select * from t11; +#插入数据 +insert into t11 values(6,5,6,7); +select * from t11; +#删去DECIMAL列 +alter table t11 drop column f; +select * from t11; +#插入数据 +insert into t11 values(7,5,7); +select * from t11; +#删表 +drop table t11; + +create table t12 (a int, b int, c int, d int, e int); +insert into t12 values(1, 2, 3, 4, 5); +insert into t12 values(2, 2, 3, 4, 5); +insert into t12 values(3, 2, 3, 4, 5); +insert into t12 values(4, 2, 3, 4, 5); +insert into t12 values(5, 2, 3, 4, 5); +create index t12_i on t12(a, b, c); +select * from t12; +#删去c列 +alter table t12 drop column b; +select * from t12; +#插入数据 +insert into t12 values(6, 3, 4, 5); +select * from t12; +#更新数据 +update t12 set c = 33 where a = 3; +select * from t12; +drop table t12; + +create table t13 (a int, b int, c int, d int, e int); +insert into t13 values(1, 2, 3, 4, 5); +insert into t13 values(2, 2, 3, 4, 5); +insert into t13 values(3, 2, 3, 4, 5); +create index t13_i on t13(a, b, c, d, e); +select * from t13; +#删去c列 +alter table t13 drop column c; +select * from t13; +#更新数据 +update t13 set b = 22, d = 44 where a = 3; +select * from t13; +drop table t13; + +drop database test_DB; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_datatype.test b/mysql-test/suite/tianchi/t/ctc_datatype.test new file mode 100644 index 0000000..6898200 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_datatype.test @@ -0,0 +1,280 @@ +# +# Simple test for the TSE storage engine +# with most datatypes and null / not null +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +-- echo # test with NUMERIC data type +create table t1 (IDA tinyint, IDB smallint, IDC int, IDD bigint, IDE float, IDF double, IDG real, IDH integer) ENGINE=CTC; +insert into t1 values (1,2,3,4,4.143,4.146,4.365,6); +insert into t1 values (11,22,33,44,4.55,4.66,4.77,66); +insert into t1 values (null,null,null,null,null,null,null,null); +select * from t1; +drop table t1; + +-- echo # test the boundary value of the numeric type +create table t1 (IDA tinyint DEFAULT NULL, IDB tinyint unsigned DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-128,0); +insert into t1 values (127,255); +--error 1264 +insert into t1 values (-129,0); +--error 1264 +insert into t1 values (128,0); +--error 1264 +insert into t1 values (127,-1); +--error 1264 +insert into t1 values (127,256); +select * from t1; +drop table t1; + +create table t1 (IDA SMALLINT DEFAULT NULL, IDB SMALLINT unsigned DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-32768,0); +insert into t1 values (32767,65535); +--error 1264 +insert into t1 values (-32769,0); +--error 1264 +insert into t1 values (32768,0); +--error 1264 +insert into t1 values (32767,-1); +--error 1264 +insert into t1 values (32767,65536); +select * from t1; +drop table t1; + +create table t1 (IDA MEDIUMINT DEFAULT NULL, IDB MEDIUMINT unsigned DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-8388608,0); +insert into t1 values (8388607,16777215); +--error 1264 +insert into t1 values (-8388609,0); +--error 1264 +insert into t1 values (8388608,0); +--error 1264 +insert into t1 values (8388607,-1); +--error 1264 +insert into t1 values (8388607,16777216); +select * from t1; +drop table t1; + +create table t1 (IDA INT DEFAULT NULL, IDB INT unsigned DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-2147483648,0); +insert into t1 values (2147483647,4294967295); +--error 1264 +insert into t1 values (-2147483649,0); +--error 1264 +insert into t1 values (2147483648,0); +--error 1264 +insert into t1 values (2147483647,-1); +--error 1264 +insert into t1 values (2147483647,4294967296); +select * from t1; +drop table t1; + +create table t1 (IDA BIGINT DEFAULT NULL, IDB BIGINT unsigned DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-9223372036854775808,0); +insert into t1 values (9223372036854775807,18446744073709551615); +--error 1264 +insert into t1 values (-9223372036854775809,0); +--error 1264 +insert into t1 values (9223372036854775808,0); +--error 1264 +insert into t1 values (9223372036854775807,-1); +--error 1264 +insert into t1 values (9223372036854775807,18446744073709551616); +select * from t1; +drop table t1; + +create table t1 (IDA FLOAT DEFAULT NULL, IDB DOUBLE DEFAULT NULL) ENGINE=CTC; +insert into t1 values (-3.402823466E+38,-1.7976931348623157E+308); +insert into t1 values (-1.175494351E-38,-2.2250738585072014E-308); +insert into t1 values (1.175494351E-38,2.2250738585072014E-308); +insert into t1 values (3.402823466351E+38,1.7976931348623157E+308); +insert into t1 values (0,0); +select * from t1; +drop table t1; + + +-- echo # test with DATETIME data type +create table t1 (IDA date, IDB datetime, IDC timestamp(2), IDD timestamp(4), IDE timestamp(6)) ENGINE=CTC; +insert into t1 values ('2017-03-04','2008-06-05 11:22:33','2020-5-12 12:24:56.2','2020-5-12 12:24:56.444','2020-5-12 12:24:56.66666'); +insert into t1 values ('2018-11-11','2020-10-10 22:33:44','2009-6-28 10:20:30.22','2009-6-28 10:20:30.4444','2009-6-28 10:20:30.666666'); +insert into t1 values (null,null,null,null,null); +select * from t1; +drop table t1; + +-- echo # test the boundary value of the datetime type +create table t1 (IDA date, IDB datetime) ENGINE=CTC; +#insert into t1 values ('1000-01-01','1000-01-01 00:00:00'); +insert into t1 values ('9999-12-31','9999-12-31 23:59:59'); +--error 1292 +insert into t1 values ('10000-12-31','9999-12-31 23:59:59'); +--error 1292 +insert into t1 values ('9999-12-31','10000-12-31 23:59:59'); +select * from t1; +drop table t1; + +-- echo # test with char/varchar data type +create table t1 (IDA char(10), IDB varchar(10)) ENGINE=CTC; +insert into t1 values ('abc','abcd'); +insert into t1 values ('aaa','cccc'); +insert into t1 values (null,null); +select * from t1; +drop table t1; + +-- echo # test the boundary value of the char/varchar type +create table t1 (IDA char(255), IDB varchar(2000)) ENGINE=CTC DEFAULT CHARSET=utf8mb4; +insert into t1 values (REPEAT('a',255),REPEAT('b',2000)); +select length(IDA) from t1; +select length(IDB) from t1; +drop table t1; + +create table t1 (IDA char(255), IDB varchar(4000)) ENGINE=CTC DEFAULT CHARSET=gbk; +insert into t1 values (REPEAT('a',255),REPEAT('b',4000)); +select length(IDA) from t1; +select length(IDB) from t1; +drop table t1; + +--disable_query_log +call mtr.add_suppression("tse_ddl_fill_column_by_field"); +call mtr.add_suppression("TSE_RETURN_IF_ERROR return"); +--enable_query_log + +create table t1 (IDA varchar(2001)) ENGINE=CTC DEFAULT CHARSET=utf8mb4; +show create table t1; +drop table t1; +create table t1 (IDA varchar(2667)) ENGINE=CTC DEFAULT CHARSET=utf8; +show create table t1; +drop table t1; +create table t1 (IDA varchar(4001)) ENGINE=CTC DEFAULT CHARSET=gbk; +show create table t1; +drop table t1; +create table t1 (IDA varchar(8001)) ENGINE=CTC DEFAULT CHARSET=ascii; +show create table t1; +drop table t1; +-- echo # test with FLOAT(p) data type +#the precision is limit between 1 ~ 38 +create table t1 (IDA float(24), IDB float(30)) ENGINE=CTC; +insert into t1 values (10,10),(1e+5,1e+5),(1234567890,1234567890),(1e+10,1e+10),(1e+15,1e+15),(1e+20,1e+20); +insert into t1 values (-10,-10),(1e-5,1e-5),(1e-10,1e-10),(1e-15,1e-15),(1e-20,1e-20),(null,null); +select * from t1; +drop table t1; + +-- echo # test with binary/varbinary data type +create table t1 (IDA binary(2), IDB varbinary(2)) ENGINE=CTC; +insert into t1 values (0x4100,0x4100),(0x01, 0x02),(null,null); +select hex(IDA),hex(IDB) from t1; +drop table t1; + +-- echo # test with decimal/numeric data type +create table t1 (w_id integer, w_ytd decimal(12,2), w_tax numeric(4,4), w_dec varchar(10), IDA decimal(1,1), IDB decimal(37,10)) ENGINE=CTC; +insert into t1 values (1,123.5,0.5126,'asdsfaf',0.5,111111111111111111111111111.32423421); +insert into t1 values (2,85743.34,0.3432,'bbbffsd',-0.5,-111111111111111111111111111.32423421); +insert into t1 values (3,-85743.34,-0.3432,'testgog',-0.5,-4548343534.1341252323); +insert into t1 values (null,null,null,null,null,null); +select * from t1; +drop table t1; + +-- echo # add test cases of decimal/numeric data type +create table t1 (IDA decimal(1,0), IDB decimal(1,1), IDC numeric(2,0), IDD decimal(2,1), IDE decimal(2,2), IDF decimal(3,0)) ENGINE=CTC; +insert into t1 values (1,0.3,12,5.6,0.45,999); +insert into t1 values (2,0.8,99,9.9,0.89,108); +insert into t1 values (null,0.7,null,8.3,null,456); +insert into t1 values (null,null,null,null,null,null); +select * from t1; +drop table t1; + +-- echo # add test cases of decimal/numeric data type +create table t1 (IDA decimal(3,1), IDB decimal(3,2), IDC numeric(3,3), IDD decimal(4,1), IDE decimal(4,2), IDF decimal(12,5),IDG decimal(38,20)) ENGINE=CTC; +insert into t1 values (1.3,2.54,0.999,534.6,86.54,1234567.98765,123456789123456789.12345678900123456789); +insert into t1 values (-1.3,-2.54,-0.999,-534.6,-86.54,-1234567.98765,-123456789123456789.12345678900123456789); +insert into t1 values (1.3,null,0.999,null,86.54,null,123456789123456789.12345678900123456789); +insert into t1 values (null,null,null,null,null,null,null); +select * from t1; +drop table t1; + +-- echo # add test cases of decimal/numeric data type +create table t1 (id int, val decimal(38, 30)) ENGINE=CTC; +insert into t1 values (1, 12345678.123456789); +insert into t1 values (2, 12345678.123456789123456789123456789123); +insert into t1 values (3, -12345678.123456789123456789123456789123); +insert into t1 values (4, 12345678.123456789123456789123456789123456789); +--error 1264 +insert into t1 values (5, 12345678912.123456789); +--error 1264 +insert into t1 values (6, 12345678912.123456789123456789123456789123456789); +select * from t1; +drop table t1; + +-- echo # add test cases of decimal/numeric data type +create table t1 (id int, val decimal(38, 30) unsigned) ENGINE=CTC; +insert into t1 values (1, 12345678.123456789); +insert into t1 values (2, 12345678.123456789123456789123456789123); +--error 1264 +insert into t1 values (3, -12345678.123456789123456789123456789123); +--error 1264 +insert into t1 values (4, -12345678.123456789123456789123456789123456789); +select * from t1; +drop table t1; + +-- echo # add error test cases of decimal/numeric data type +create table t1 (IDA decimal(39,20)) ENGINE=CTC; +drop table t1; +create table t1 (IDA decimal(40,20)) ENGINE=CTC; +drop table t1; +create table t1 (IDA decimal(41,20)) ENGINE=CTC; +drop table t1; +--error 1426 +create table t1 (IDA decimal(66,20)) ENGINE=CTC; +--error 1426 +create table t1 (IDA decimal(80,20)) ENGINE=CTC; +--error 1426 +create table t1 (IDA decimal(100,20)) ENGINE=CTC; +--error 1425 +create table t1 (IDA decimal(100,40)) ENGINE=CTC; +--error 1425 +create table t1 (IDA decimal(30,40)) ENGINE=CTC; +--error 1427 +create table t1 (IDA decimal(20,30)) ENGINE=CTC; +--error 1427 +create table t1 (IDA decimal(10,20)) ENGINE=CTC; + +-- echo # add test cases of text/blob data type +create table t1 (IDA TINYTEXT, IDB TINYTEXT) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +create table t1 (IDA MEDIUMTEXT, IDB MEDIUMTEXT) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +create table t1 (IDA TINYBLOB, IDB TINYBLOB) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +create table t1 (IDA FLOAT) ENGINE=CTC; +insert into t1 values (10.5); +insert into t1 values (20.5); +CREATE INDEX floatIndexTest ON t1 (IDA); +select * from t1 where IDA < 20.0; +select * from t1 where IDA > 10.0; +drop table t1; diff --git a/mysql-test/suite/tianchi/t/ctc_datatype_adapt.test b/mysql-test/suite/tianchi/t/ctc_datatype_adapt.test new file mode 100644 index 0000000..c7da00e --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_datatype_adapt.test @@ -0,0 +1,145 @@ +# +# Simple test for the TSE storage engine +# with the data type which not supported by CantianDB +# such as YEAR, TIME ,etc. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +-- echo # test with YEAR data type +create table t1 (y year,y4 year(4)); +insert into t1 values (1999,1999),(2000,2000),(2001,2001),(70,70),(69,69),(null,null); +select * from t1; +drop table t1; + +create table t1(c1 YEAR); +insert into t1 values (1901),(2155); +select * from t1; +drop table t1; + +-- echo # test with TIME data type +# +# Note:for TIME data type, TSE just support data +# range 00:00:00.000000 to 23:59:59.000000, +# not -838:59:59.000000~838:59:59.000000 +# +SET sql_mode = 'NO_ENGINE_SUBSTITUTION'; +create table t1 (t time); +insert into t1 values("10:22:33"),("12:34:56.78"),(10),(1234),(123456.78),("1"),("1:23"),("1:23:45"), ("10.22"),("1999-02-03 20:33:34"); +insert t1 values (30),(1230),("1230"),("12:30"),("12:30:35"); +insert t1 values (NULL); +select * from t1; +drop table t1; + +create table t1(c1 time, c2 time(2), c3 time(4), c4 time(6)); +insert into t1 values ("10:22:33.567865","10:22:33.567865","10:22:33.567865","10:22:33.567865"); +select * from t1; +drop table t1; +SET sql_mode = default; + +-- echo # test with MEDIUMINT data type +create table t1 (c1 MEDIUMINT); +insert into t1 values (-8388608),(0),(100),(8388607),(null); +select * from t1; +drop table t1; + +create table t1 (c1 MEDIUMINT UNSIGNED); +insert into t1 values (0),(100),(65535),(16777215),(null); +select * from t1; +drop table t1; + +-- echo # test with Json data type +# check json_set +create table t1 (c1 json); +insert into t1 values ('{ "a": 1, "b": [2, 3]}'); +select * from t1; +update t1 set c1 = json_set(c1, '$.a', 10, '$.c', '[true, false]'); +select * from t1; +drop table t1; + +#check json_insert +create table t1 (c1 json); +insert into t1 values ('{ "a": 1, "b": [2, 3]}'); +update t1 set c1 = json_insert(c1, '$.a', 10, '$.c', '[true, false]'); +select * from t1; +drop table t1; + +#check json_insert +create table t1 (c1 json); +insert into t1 values ('{ "a": 1, "b": [2, 3]}'); +update t1 set c1 = json_replace(c1, '$.a', 10, '$.c', '[true, false]'); +select * from t1; +drop table t1; + +#check JSON_ARRAY_APPEND +SET @j = '["a", ["b", "c"], "d"]'; +create table t1 (c1 json); +insert into t1 values (@j); +update t1 set c1 = JSON_ARRAY_APPEND(c1, '$[1]', 1); +select * from t1; +drop table t1; + +#check JSON_ARRAY_INSERT +SET @j = '["a", {"b": [1, 2]}, [3, 4]]'; +create table t1 (c1 json); +insert into t1 values (@j); +update t1 set c1 = JSON_ARRAY_INSERT(c1, '$[1]', 'x'); +select * from t1; +drop table t1; + +#check JSON_MERGE_PATCH +create table t1 (c1 json); +insert into t1 values (JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}', '{"id": 87}')); +select * from t1; +drop table t1; + +#check JSON_MERGE_PRESERVE +create table t1 (c1 json); +insert into t1 values (JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}', '{"id": 87}')); +select * from t1; +drop table t1; + +#check JSON_REMOVE +SET @j = '["a", ["b", "c"], "d"]'; +create table t1 (c1 json); +insert into t1 values (JSON_REMOVE(@j, '$[1]')); +select * from t1; +drop table t1; + +#check JSON_REMOVE +SET @j = '["a", ["b", "c"], "d"]'; +create table t1 (c1 json); +insert into t1 values (JSON_REMOVE(@j, '$[1]')); +select * from t1; +drop table t1; + +#check JSON_UNQUOTE +create table t1 (c1 json); +insert into t1 values (JSON_UNQUOTE('"\\t\\u0032"')); +select * from t1; +drop table t1; + +# json duplicate key update +CREATE TABLE t1(id INT PRIMARY KEY, j JSON); +INSERT INTO t1 VALUES (1, '[1]') AS n ON DUPLICATE KEY UPDATE j = JSON_OBJECT("a", n.j); +SELECT * FROM t1; +INSERT INTO t1 VALUES (1, '[1,2]') AS n ON DUPLICATE KEY UPDATE j = JSON_OBJECT("ab", n.j); +SELECT * FROM t1; +INSERT INTO t1 VALUES (1, '[1,2,3]') AS n ON DUPLICATE KEY UPDATE j = JSON_OBJECT("abc", n.j); +SELECT * FROM t1; +drop table t1; + +# json cast +CREATE TABLE t1 (i INT, j JSON) CHARSET utf8mb4; +INSERT INTO t1 VALUES (16, CAST(CAST('2015-01-15 23:24:25' AS DATETIME) AS JSON)); +INSERT INTO t1 VALUES (17, CAST(CAST('23:24:25' AS TIME) AS JSON)); +INSERT INTO t1 VALUES (18, CAST(CAST('2015-01-15' AS DATE) AS JSON)); +INSERT INTO t1 VALUES (19, CAST(TIMESTAMP'2015-01-15 23:24:25' AS JSON)); +INSERT INTO t1 VALUES (20, CAST(ST_GeomFromText('POINT(1 1)') AS JSON)); +INSERT INTO t1 VALUES (21, CAST('1988' AS CHAR CHARACTER SET 'ascii')); +INSERT INTO t1 VALUES (22, CAST(x'07C4' AS JSON)); +INSERT INTO t1 VALUES (23, CAST(x'07C407C4' AS JSON)); +SELECT i, CAST(j AS YEAR), CAST(j AS SIGNED) FROM t1 ORDER BY i; +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_datatype_blob.test b/mysql-test/suite/tianchi/t/ctc_datatype_blob.test new file mode 100644 index 0000000..c1301f1 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_datatype_blob.test @@ -0,0 +1,153 @@ +# +# Simple test for the TSE storage engine +# with blob data and null / not null +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +-- echo # test with text data +create table t1 (IDA text, IDB text) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +-- echo # test with text data length +create table t1 (IDA text) ENGINE=CTC; +insert into t1 (IDA) values (REPEAT('a',1024)); +insert into t1 (IDA) values (REPEAT('a',10000)); +insert into t1 (IDA) values (REPEAT('a',32768)); +select length(IDA) from t1; +drop table t1; + +-- echo # test with longtext data +create table t1 (IDA LONGTEXT, IDB LONGTEXT) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +-- echo # test with longtext data length +create table t1 (IDA LONGTEXT) ENGINE=CTC; +insert into t1 (IDA) values (REPEAT('a',1024)); +insert into t1 (IDA) values (REPEAT('a',10000)); +insert into t1 (IDA) values (REPEAT('a',65536)); +insert into t1 (IDA) values (REPEAT('a',1024*1024)); +insert into t1 values (null); +select length(IDA) from t1; +drop table t1; + +-- echo # test with blob data +create table t1 (IDA blob, IDB blob) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +-- echo # test with blob data length +create table t1 (IDA blob) ENGINE=CTC; +insert into t1 (IDA) values (REPEAT('a',1024)); +insert into t1 (IDA) values (REPEAT('a',10000)); +insert into t1 (IDA) values (REPEAT('a',32768)); +insert into t1 values (null); +select length(IDA) from t1; +drop table t1; + +-- echo # test with MediumBlob data +create table t1 (IDA MediumBlob, IDB MediumBlob) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +-- echo # test with MediumBlob data length +create table t1 (IDA MediumBlob) ENGINE=CTC; +insert into t1 (IDA) values (REPEAT('a',1024)); +insert into t1 (IDA) values (REPEAT('a',10000)); +insert into t1 (IDA) values (REPEAT('a',1024*1024)); +insert into t1 values (null); +select length(IDA) from t1; +drop table t1; + +-- echo # test with LongBlob data +create table t1 (IDA LongBlob, IDB LongBlob) ENGINE=CTC; +insert into t1 values (43, 7889); +insert into t1 values ('',555); +insert into t1 values (444,''); +insert into t1 values (4343, 'here'); +insert into t1 values ('where',777); +insert into t1 values (null, null); +select * from t1; +drop table t1; + +-- echo # test with LongBlob data length +create table t1 (IDA LongBlob) ENGINE=CTC; +insert into t1 (IDA) values (REPEAT('a',1024)); +insert into t1 (IDA) values (REPEAT('a',10000)); +insert into t1 (IDA) values (REPEAT('a',1024 * 1000)); +insert into t1 (IDA) values (REPEAT('a',1024 * 1024)); +insert into t1 (IDA) values (REPEAT('a',1024 * 1024 * 4)); +insert into t1 (IDA) values (REPEAT('a',1024 * 1024 * 8)); +insert into t1 values (null); +select length(IDA) from t1; +drop table t1; + +-- echo # test blob with replace / on duplicate key update +create table t1 (IDA int primary key, IDB LongBlob, IDC LongText) ENGINE=CTC; +insert into t1 values (1, 'idb', 'idc'); +--disable_warnings +insert into t1 values (1, REPEAT('a',5000), REPEAT('b',5000)) on duplicate key update IDB=VALUES(IDB), IDC=VALUES(IDC); +insert into t1 values (1, REPEAT('c',5000), REPEAT('d',5000)) on duplicate key update IDB=VALUES(IDB), IDC=VALUES(IDC); +insert into t1 values (1, REPEAT('e',4000), REPEAT('f',4000)) on duplicate key update IDB=VALUES(IDB), IDC=VALUES(IDC); +insert into t1 values (1, 'idb1', 'idc1') on duplicate key update IDB=VALUES(IDB), IDC=VALUES(IDC); +--enable_warnings +replace into t1 values (1, REPEAT('g',5000), REPEAT('h',5000)); +replace into t1 values (1, REPEAT('i',4000), REPEAT('j',4000)); +replace into t1 values (1, 'idb2', 'idc2'); +select IDA, length(IDB), IDC from t1; +drop table t1; + +CREATE TABLE t1(col1 INT PRIMARY KEY, col2 int, col3 varchar(64), col4 BLOB) PARTITION BY KEY(col1) PARTITIONS 5; +INSERT INTO t1 VALUES(1,1,'Clone Test Row - ',REPEAT('Large Column Data ', 2048)); +INSERT INTO t1 VALUES(2,2,'Clone Test Row2 - ',REPEAT('Large Column Data2 ', 2048)); +DELETE FROM t1 WHERE col1 = 1; +UPDATE t1 set col4 = REPEAT('Large Column Data2 ', 1024) where col1 = 2; +select length(col4) from t1; +drop table t1; + +CREATE TABLE t1( +`a` BLOB, +`b` BLOB, +`c` BLOB GENERATED ALWAYS AS (CONCAT(a,b)) VIRTUAL, +`h` VARCHAR(10) DEFAULT NULL, +`col2` int primary key, +`col3` int, +gcol1 INTEGER GENERATED ALWAYS AS (col3 + col3) VIRTUAL, +gcol2 INTEGER GENERATED ALWAYS AS (col2 + col2) VIRTUAL, +gcol3 INTEGER GENERATED ALWAYS AS (gcol2 / gcol2) VIRTUAL +); + +INSERT INTO t1 VALUES (REPEAT('g', 16000), REPEAT('x', 16000), DEFAULT, "kk", 1, 1, DEFAULT, DEFAULT, DEFAULT); +INSERT INTO t1 VALUES (REPEAT('m', 16000), REPEAT('n', 16000), DEFAULT, "aa", 2, 2, DEFAULT, DEFAULT, DEFAULT); +INSERT INTO t1 VALUES (REPEAT('p', 16000), REPEAT('q', 16000), DEFAULT, "bb", 3, 3, DEFAULT, DEFAULT, DEFAULT); +INSERT INTO t1 VALUES (REPEAT('x', 16000), REPEAT('y', 16000), DEFAULT, "cc", 4, 4, DEFAULT, DEFAULT, DEFAULT); +select length(a), length(b), length(c) from t1; +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_dc_reuse.test b/mysql-test/suite/tianchi/t/ctc_dc_reuse.test new file mode 100644 index 0000000..b43d0ef --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_dc_reuse.test @@ -0,0 +1,204 @@ +let $engine_type= CTC; + +--disable_warnings +drop table if exists t1; + + +--echo ######## test case 1, test create index will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +insert into t1 values(1,1,1),(2,2,2),(3,3,3); +commit; +begin; +explain select * from t1 where b > 2; + +connection b; +--send +create index b_index ON t1 (b); + +connection a; +explain select * from t1 where b > 2; +commit; + +connection b; +reap; + +connection a; +explain select * from t1 where b > 2; +DROP INDEX b_index ON t1; +drop table t1; +disconnect a; +disconnect b; + + +--echo ######## test case 2, test add index will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +insert into t1 values(1,1,1),(2,2,2),(3,3,3); +commit; +begin; +explain select * from t1 where b > 2; + +connection b; +--send +ALTER TABLE t1 ADD INDEX b_index (b); + +connection a; +explain select * from t1 where b > 2; +commit; + +connection b; +reap; + +connection a; +explain select * from t1 where b > 2; +DROP INDEX b_index ON t1; +drop table t1; +disconnect a; +disconnect b; + + +--echo ######## test case 3, test drop index will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +ALTER TABLE t1 ADD INDEX b_index (b); +insert into t1 values(1,1,1),(2,2,2),(3,3,3); +commit; +begin; +explain select * from t1 where b > 2; + +connection b; +--send +DROP INDEX b_index ON t1; + +connection a; +explain select * from t1 where b > 2; +commit; + +connection b; +reap; + +connection a; +explain select * from t1 where b > 2; +drop table t1; +disconnect a; +disconnect b; +--enable_warnings + + +--echo ######## test case 4, test add column will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +insert into t1 values(1,1,1),(2,2,2),(3,3,3); +commit; +begin; +select * from t1; + +connection b; +--send +ALTER TABLE t1 ADD COLUMN test INT default 0; + +connection a; +select * from t1; +commit; + +connection b; +reap; + +connection a; +select * from t1; +drop table t1; +disconnect a; +disconnect b; + + +--echo ######## test case 5, test renaming column will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +insert into t1 values(1,1,1),(2,2,2),(3,3,3); +commit; +begin; +select * from t1; + +connection b; +--send +ALTER TABLE t1 RENAME COLUMN c TO c_new; + +connection a; +select * from t1; +commit; + +connection b; +reap; + +connection a; +select * from t1; +drop table t1; +disconnect a; +disconnect b; + + +--echo ######## test case 6, test changing the column data type will open new dc +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +insert into t1(a, b) values(1,1),(2,2),(3,3); +commit; +begin; +select * from t1; + +connection b; +--send +ALTER TABLE t1 MODIFY c FLOAT; + +connection a; +select * from t1; +commit; + +connection b; +reap; + +connection a; +select * from t1; +desc t1; +drop table t1; +disconnect a; +disconnect b; + +# --echo ######## test case 7, test dropping a column will open new dc +# connect (a,localhost,root,,); +# connect (b,localhost,root,,); +# connection a; +# create table t1(a int not null, b int, c int, primary key(a)) ENGINE=CTC; +# insert into t1 values(1,1,1),(2,2,2),(3,3,3); +# commit; +# begin; +# select * from t1; +# +# connection b; +# --send +# ALTER TABLE t1 DROP COLUMN c; +# +# connection a; +# select * from t1; +# commit; +# +# connection b; +# reap; +# +# connection a; +# select * from t1; +# drop table t1; can not drop table here will core +# disconnect a; +# disconnect b; diff --git a/mysql-test/suite/tianchi/t/ctc_dcl.test b/mysql-test/suite/tianchi/t/ctc_dcl.test new file mode 100644 index 0000000..4a6487e --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_dcl.test @@ -0,0 +1,203 @@ +# ctc_dcl_disabled +drop user if exists yyz; + +# different values +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; + +set @ctc_dcl_disabled = true; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = TRUE; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = 1; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = 'true'; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = 'True'; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = '1'; +select @ctc_dcl_disabled; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +drop user if exists yyz; + +set @ctc_dcl_disabled = false; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + +set @ctc_dcl_disabled = 0; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + +set @ctc_dcl_disabled = 123; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + +set @ctc_dcl_disabled = 'false'; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + +set @ctc_dcl_disabled = 'abc'; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + +set @ctc_dcl_disabled = NULL; +select @ctc_dcl_disabled; +create user yyz; +select user from mysql.user; +drop user if exists yyz; +select user from mysql.user; + + +set @ctc_dcl_disabled = true; +select @ctc_dcl_disabled; +--error 3655 +drop user if exists yyz; +--error 3655 +create user yyz; +select user from mysql.user; +--error 3655 +rename user yyz to mysqltest_1; +--error 3655 +alter user mysqltest_1 identified by 'systpass'; +--error 1141 +show grants for mysqltest_1; +--error 3655 +drop user if exists mysqltest_1; +--error 3655 +create user mysqltest_1; +--error 3655 +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1; +--error 1141 +show grants for mysqltest_1; +flush privileges; +--error 1141 +show grants for mysqltest_1; +--error 3655 +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1; +--error 1141 +show grants for mysqltest_1; +--error 3655 +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1 with grant option; +flush privileges; +--error 1141 +show grants for mysqltest_1; +--error 3655 +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1; +--error 1141 +show grants for mysqltest_1; +--error 3655 +revoke all privileges on mysqltest.* from mysqltest_1; +--error 3655 +drop user if exists mysqltest_1; +flush privileges; +--error 3655 +create role role1; +--error 3655 +create user mysqltest_1; +--error 3655 +grant role1 to mysqltest_1; +--error 3655 +drop role if exists role1; +--error 3655 +drop user if exists mysqltest_1; +--error 3655 +create role role1; +--error 3655 +create user mysqltest_1; +--error 3655 +set default role all to role1; +--error 3655 +alter user current_user() default role none; +--error 3655 +revoke role1 from mysqltest_1; +--error 3655 +drop role if exists role1; +--error 3655 +drop user if exists mysqltest_1; + +set @ctc_dcl_disabled = false; +select @ctc_dcl_disabled; +drop user if exists yyz; +create user yyz; +select user from mysql.user; +rename user yyz to mysqltest_1; +alter user mysqltest_1 identified by 'systpass'; +show grants for mysqltest_1; +drop user if exists mysqltest_1; +create user mysqltest_1; +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1; +show grants for mysqltest_1; +flush privileges; +show grants for mysqltest_1; +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1; +show grants for mysqltest_1; +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1 with grant option; +flush privileges; +show grants for mysqltest_1; +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1; +show grants for mysqltest_1; +revoke all privileges on mysqltest.* from mysqltest_1; +drop user if exists mysqltest_1; +flush privileges; +create role role1; +create user mysqltest_1; +grant role1 to mysqltest_1; +drop role if exists role1; +drop user if exists mysqltest_1; +create role role1; +create user mysqltest_1; +set default role all to role1; +alter user current_user() default role none; +revoke role1 from mysqltest_1; +drop role if exists role1; +drop user if exists mysqltest_1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl.test b/mysql-test/suite/tianchi/t/ctc_ddl.test new file mode 100644 index 0000000..e944c8a --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl.test @@ -0,0 +1,143 @@ +--disable_warnings +drop table if exists DEMO; +--enable_warnings + +# create a table. +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); + +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); + +#select update insert delete. +SELECT * FROM DEMO; + +#此处会失败,不支持在含有重复值的列上设置主键 +--error ER_DUP_ENTRY +ALTER TABLE DEMO ADD PRIMARY KEY (ID); + +#把重复的记录删了能够成功 +DELETE FROM DEMO WHERE GRADE = 4.9; +ALTER TABLE DEMO ADD PRIMARY KEY (ID); + +#创建用户 +#CREATE USER zd1 IDENTIFIED BY "Zd1-123456"; +#GRANT ALL PRIVILEGES ON *.* TO zd1; #daac里面需要把 ON *.*删除掉,DAAC不支持此语法 +#CREATE USER zd2 IDENTIFIED BY "Zd1-123456"; +#GRANT SELECT,INSERT,UPDATE, DELETE ON demo_db.DEMO TO zd2; #这里只支持db.table语法,daac不支持db,发到daac侧需要把db删掉 + +#Adding a foreign key constraint +create table DEMO_A (ID integer not null, NAME varchar(19) not null, SCORE float, CONSTRAINT id_fk FOREIGN KEY (ID) REFERENCES DEMO(ID)); +desc DEMO_A; +show create table DEMO_A; +#Dropping a foreign key constraint +alter table DEMO_A drop CONSTRAINT id_fk; +show create table DEMO_A; +alter table DEMO_A drop index id_fk; +show create table DEMO_A; + +#Dropping a primary key +ALTER TABLE DEMO DROP PRIMARY KEY; +show create table DEMO; + +#Adding a column +ALTER TABLE DEMO ADD COLUMN CLASS INT; +SELECT * FROM DEMO; + +#Renaming a column +ALTER TABLE DEMO RENAME COLUMN CLASS TO NEW_CLASS; +SELECT * FROM DEMO; + +#Setting a column default value +ALTER TABLE DEMO MODIFY NEW_CLASS INT DEFAULT 1; +desc DEMO; + +#Changing the column data type +ALTER TABLE DEMO MODIFY NEW_CLASS FLOAT; +desc DEMO; + +#Dropping a column +ALTER TABLE DEMO DROP COLUMN NEW_CLASS; +SELECT * FROM DEMO; + +#Extending VARCHAR column size +ALTER TABLE DEMO MODIFY COLUMN NAME varchar(32); +desc DEMO; + +#Making a column NULL +ALTER TABLE DEMO MODIFY ID int NULL; +desc DEMO; + +#Making a column NOT NULL +ALTER TABLE DEMO MODIFY ID int NOT NULL; +desc DEMO; + +#Renaming a table +ALTER TABLE DEMO RENAME TO DEMO1; +SELECT * FROM DEMO1; + +#Renaming a general tablespace +#TSE不支持CREATE TABLESPACE,也就无法rename TABLESPACE,也就无法rename tablespace +#CREATE TABLESPACE TEST_SPACE; +#ERROR 1478 (HY000): Table storage engine 'CTC' does not support the create option 'CREATE TABLESPACE' + +drop table DEMO1; +drop table DEMO_A; + +# 表名为特殊符号 +CREATE TABLE `@#$%`(i int); +SHOW TABLES; +INSERT INTO `@#$%` VALUES(123123); +SELECT * from `@#$%`; +ALTER TABLE `@#$%` ADD test int; +RENAME TABLE `@#$%` to `$$$$`; +INSERT INTO `$$$$` VALUES(233233, 11111); +SELECT * from `$$$$`; +TRUNCATE TABLE `$$$$`; +SELECT * from `$$$$`; +DROP TABLE `$$$$`; +create table ` #`(i int); +insert into ` #` values (1); +select * from ` #`; +drop table ` #`; +CREATE TABLE `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#`(i int); +DROP TABLE `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#`; +CREATE TABLE `#test`(i int); +INSERT INTO `#test` VALUES (1123); +SELECT * FROM `#test`; +ALTER TABLE `#test` add col2 int; +DROP TABLE `#test`; +--error ER_TOO_LONG_IDENT +create table `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#$`(i int); +--error ER_WRONG_TABLE_NAME +create table ``(i int); +--error ER_WRONG_TABLE_NAME +create table ` `(i int); +set debug = '+d, tse_lock_table_fail'; +set debug = '+d, tse_lock_table_fail_DDL_LOCKED'; +--error ER_DISALLOWED_OPERATION +create table test1(i int); +set debug = '-d, tse_lock_table_fail_DDL_LOCKED'; +set debug = '+d, tse_lock_table_fail_VERSION_NOT_MATCH'; +--error ER_DISALLOWED_OPERATION +create table test1(i int); +set debug = '-d, tse_lock_table_fail_VERSION_NOT_MATCH'; +set debug = '+d, tse_lock_table_fail_DISALLOW_OPERATION'; +--error ER_DISALLOWED_OPERATION +create table test1(i int); +set debug = '-d, tse_lock_table_fail_DISALLOW_OPERATION'; +set debug = '-d, tse_lock_table_fail'; +create table test1(i int); +set debug = '+d, non_metadata_normalization'; +set debug = '+d, tse_ddl_rewrite_broadcast_fail'; +--error ER_DISALLOWED_OPERATION +lock table test1 write; +set debug = '-d, tse_ddl_rewrite_broadcast_fail'; +set debug = '-d, non_metadata_normalization'; +drop table test1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_alter_table.test b/mysql-test/suite/tianchi/t/ctc_ddl_alter_table.test new file mode 100644 index 0000000..b5433bd --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_alter_table.test @@ -0,0 +1,909 @@ +--disable_warnings +drop table if exists DEMO; +drop table if exists t1; +--enable_warnings +#特别注意,每个测试用例直接用2行空行隔开,中间不要有任何空行 + + +#以下为修改表的相关测试 +#create table for rename table test (修改表名) +create table DEMO (ID integer primary key, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(1,'demo',1,1.1); +SELECT * FROM DEMO; +alter table DEMO rename to DEMO1; +SELECT * FROM DEMO1; +alter table DEMO1 rename to DEMO2; +SELECT * FROM DEMO2; +--error 1146 +#ERROR 1146 (42S02): Table 'demo_db.DEMO1' doesn't exist +SELECT * FROM DEMO1; +desc DEMO2; +insert into DEMO2 values (2, 'LIOR', 35, 6.9); +#执行 select +SELECT * FROM DEMO2; +# 表名修改后仍可以找到对应的索引和约束 +alter table DEMO2 drop primary key; +#drop Table +drop table DEMO2; + + +#TODODDL这个测试用例还需要重点审视 +#create table for alter add column (添加列,支持primary key) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(30,'insert',21,23); +ALTER TABLE DEMO ADD COLUMN col1 integer; +insert into DEMO values (1, 'LIOR', 35, 6.9,1987); +# 执行 select 语句 +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#带auto_increment 可以成功赋值 +ALTER TABLE DEMO ADD COLUMN col2 integer PRIMARY KEY auto_increment; +insert into DEMO values (1, 'LIOR', 35, 6.9,1987,3); +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9,1987,3); +insert into DEMO (ID,NAME, AGE,GRADE,col1) values (1, 'LIOR', 35, 6.9,1987); +#再次插入可以成功 +insert into DEMO (ID,NAME, AGE,GRADE,col1) values (1, 'LIOR', 35, 6.9,1987); +--error 1075 +#ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key +#这个表现是跟innodb是一样的表现 +alter table DEMO drop primary key; +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9,1987,3); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for add column (unique key) (添加列,支持唯一索引 unique key) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(30,'insert',21,23); +ALTER TABLE DEMO ADD COLUMN col1 integer; +insert into DEMO values (1, 'LIOR', 35, 6.9, 1987); +ALTER TABLE DEMO ADD COLUMN col2 integer UNIQUE KEY; +insert into DEMO values (2, 'LIOR', 35, 6.9, 1987, 1); +--error 1062 +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, 1); +insert into DEMO values (4, 'BOB', 44, 8.1, 1962, 2); +--error 1062 +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, 2); +#null不认为违反unqiue约束 +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, null); +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, null); +ALTER TABLE DEMO DROP INDEX col2; +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, 2); +insert into DEMO values (3, 'AMY', 37, 7.9, 1982, null); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for add column (auto increment & unique key) (添加列,支持自增) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(30,'insert',21,23); +ALTER TABLE DEMO ADD COLUMN col1 integer; +insert into DEMO values (1, 'LIOR', 35, 6.9, 1987); +# 执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#ALTER TABLE DEMO ADD COLUMN col2 integer UNIQUE KEY auto_increment; +#desc DEMO; +#show create table DEMO; +#show index from DEMO; +#insert into DEMO (ID, NAME, AGE, GRADE, col1) values (2, 'BOB', 36, 6.9, 1987); +#insert into DEMO (ID, NAME, AGE, GRADE, col1) values (4, 'TONY', 40, 7.2, 2002); +#insert into DEMO values (1, 'LIOR', 35, 6.9, 1987,7); +#--error 1062 +##ERROR 1062 (23000): Duplicate entry '7' for key 'DEMO.col2' +#insert into DEMO values (1, 'LIOR', 35, 6.9, 1987,7); +#insert into DEMO (ID, NAME, AGE, GRADE, col1) values (4, 'TONY', 40, 7.2, 2002); +#insert into DEMO (ID, NAME, AGE, GRADE, col1) values (4, 'TONY', 40, 7.2, 2002); +#--error 1075 +##ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key +#ALTER TABLE DEMO DROP INDEX col2; +#--error 1062 +#insert into DEMO values (1, 'LIOR', 35, 6.9, 1987,7); +#SELECT * FROM DEMO; +#desc DEMO; +#show create table DEMO; +#show index from DEMO; +drop table DEMO; + + +#create table for rename column (rename列) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +show create table DEMO; +INSERT INTO DEMO values(30,'insert',21,23); +INSERT INTO DEMO(NAME,ID,AGE,GRADE) values('insert1',31,21,28); +alter table DEMO rename column ID to NEW_ID; +show create table DEMO; +--error 1054 +#ERROR 1054 (42S22): Unknown column 'ID' in 'field list' +INSERT INTO DEMO(NAME,ID,AGE,GRADE) values('insert1',31,21,28); +INSERT INTO DEMO values(30,'insert3',21,23); +INSERT INTO DEMO(NAME,NEW_ID,AGE,GRADE) values('insert4',31,21,28); +alter table DEMO rename column NEW_ID to ID; +show create table DEMO; +INSERT INTO DEMO values(30,'insert5',21,23); +--error 1054 +#ERROR 1054 (42S22): Unknown column 'NEW_ID' in 'field list' +INSERT INTO DEMO(NAME,NEW_ID,AGE,GRADE) values('insert6',31,21,28); +INSERT INTO DEMO(NAME,ID,AGE,GRADE) values('insert7',31,21,28); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for drop column (删除列,删除列后再添加同名的列) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(30,'insert1',21,23); +alter table DEMO drop column NAME; +--error 1136 +#ERROR 1136 (21S01): Column count doesn't match value count at row 1 +INSERT INTO DEMO values(30,'insert2',21,23); +--error 1054 +#ERROR 1054 (42S22): Unknown column 'NAME' in 'field list' +INSERT INTO DEMO (ID,NAME,AGE,GRADE) values(30,'insert3',21,23); +INSERT INTO DEMO (ID,AGE,GRADE) values(312,21,23); +INSERT INTO DEMO values(313,21,23); +#SELECT * FROM DEMO; +alter table DEMO drop column AGE; +--error 1136 +INSERT INTO DEMO values(1, 'TEST', 2, 23.33); +INSERT INTO DEMO values(2, 23.33); +INSERT INTO DEMO values(5, 66.33); +#SELECT * FROM DEMO; +ALTER TABLE DEMO ADD COLUMN NAME varchar(19); +INSERT INTO DEMO (ID,NAME,GRADE) values(30,'insert20', 23.38); +#SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for modify column attr (修改列属性) +create table DEMO (ID integer not null, NAME varchar(10)); +INSERT INTO DEMO values(1, '1234567890'); +--error 1406 +#ERROR 1406 (22001): Data too long for column 'NAME' at row 1 +INSERT INTO DEMO values(2, '12345678901'); +alter table DEMO modify NAME VARCHAR(11); +INSERT INTO DEMO values(3, '12345678901'); +--error 1406 +#ERROR 1406 (22001): Data too long for column 'NAME' at row 1 +INSERT INTO DEMO values(4, '123456789012'); +SELECT * FROM DEMO; +--error 1265 +alter table DEMO modify NAME VARCHAR(10); +delete from DEMO where ID = 3; +SELECT * FROM DEMO; +alter table DEMO modify NAME VARCHAR(10); +delete from DEMO; +alter table DEMO modify NAME VARCHAR(10); +INSERT INTO DEMO values(5, '1234567890'); +--error 1406 +#ERROR 1406 (22001): Data too long for column 'NAME' at row 1 +INSERT INTO DEMO values(6, '12345678901'); +alter table DEMO modify NAME VARCHAR(11) UNIQUE KEY DEFAULT NULL; +INSERT INTO DEMO values(6, '12345678901'); +--error 1062 +#ERROR 1062 (23000): Duplicate entry '12345678901' for key 'DEMO.NAME' +INSERT INTO DEMO values(6, '12345678901'); +desc DEMO; +show create table DEMO; +show index from DEMO; +INSERT INTO DEMO values(28, 'BOB'); +insert into DEMO (ID) values (4); +insert into DEMO values (4,null); +insert into DEMO values (4,null); +--error 1062 +INSERT INTO DEMO values(3, 'BOB'); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +##create table for modify column attr (修改列属性,修改自增列) +create table DEMO (ID integer not null, col integer); +INSERT INTO DEMO values(1, 1); +INSERT INTO DEMO values(2, 1); +SELECT * FROM DEMO; +--error 1062 +alter table DEMO modify col integer UNIQUE KEY auto_increment; +delete from DEMO where ID = 2; +SELECT * FROM DEMO; +alter table DEMO modify col integer UNIQUE KEY auto_increment; +insert into DEMO (ID) values(3); +insert into DEMO (ID) values(4); +insert into DEMO (ID) values(5); +insert into DEMO (ID) values(6); +--error 1075 +#ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key +ALTER TABLE DEMO DROP INDEX col; +--error 1062 +#ERROR 1062 (23000): Duplicate entry '1' for key 'DEMO.col' +INSERT INTO DEMO values(2, 1); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +##create table for modify column attr (change列为主键) +create table DEMO (ID integer, col integer); +insert into DEMO values(1,1); +insert into DEMO values(2,1); +insert into DEMO (col) values(3); +insert into DEMO (col) values(4); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +alter table DEMO change ID ID integer PRIMARY KEY auto_increment; +DELETE FROM DEMO; +insert into DEMO values(1,1); +insert into DEMO values(2,1); +--error 1062 +insert into DEMO values(2,3); +SELECT * FROM DEMO; +--error 1068 +alter table DEMO change ID ID integer PRIMARY KEY auto_increment; +DELETE FROM DEMO where col = 3; +SELECT * FROM DEMO; +--error 1068 +alter table DEMO change ID ID integer PRIMARY KEY auto_increment; +--error 1062 +insert into DEMO (ID) values(1); +--error 1062 +insert into DEMO (ID) values(2); +insert into DEMO (ID) values(3); +SELECT * FROM DEMO; +#测试自增 +insert into DEMO (col) values(4); +insert into DEMO (col) values(5); +insert into DEMO (col) values(6); +SELECT * FROM DEMO; +#注意上方两次失败的语句的id会空余出来 +insert into DEMO (col) values(33); +insert into DEMO (col) values(44); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for set and delete column default (列增加删除默认值) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +insert into DEMO values(1,'insert1',1,1.1); +SELECT * FROM DEMO; +alter table DEMO alter column ID set default 1; +insert into DEMO (NAME, AGE, GRADE) values ('BOB', 36, 6.9); +alter table DEMO alter column ID set default 112; +insert into DEMO (NAME, AGE, GRADE) values ('BOB2', 36, 6.9); +alter table DEMO alter column ID drop default; +--error 1364 +#ERROR 1364 (HY000): Field 'ID' doesn't have a default value +insert into DEMO (NAME, AGE, GRADE) values ('AMY', 32, 8.1); +insert into DEMO (ID, NAME, AGE, GRADE) values (3,'ALEX', 45, 9.2); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for add unqiue index when alter column and drop a unique index (添加、删除、rename唯一索引) +#测试给一列添加唯一索引和删除唯一索引 +create table DEMO (ID integer PRIMARY KEY auto_increment NOT NULL); +insert into DEMO values (null); +insert into DEMO values (null); +ALTER TABLE DEMO ADD COLUMN col1 integer; +ALTER TABLE DEMO ADD COLUMN col2 integer; +ALTER TABLE DEMO ADD UNIQUE (col1); +insert into DEMO values (null,null,null); +insert into DEMO values (null,null,null); +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1); +INSERT INTO DEMO (col1,col2) values(2,1); +--error 1062 +INSERT INTO DEMO (col1,col2) values(1,1);#失败,unique重复 +INSERT INTO DEMO (col1,col2) values(3,1); #成功 +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +ALTER TABLE DEMO DROP INDEX col1; +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1);#成功,已经删除unique索引 +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#测试给两列添加唯一索引和删除唯一索引 +create table DEMO (ID integer PRIMARY KEY auto_increment NOT NULL); +ALTER TABLE DEMO ADD COLUMN col1 integer; +ALTER TABLE DEMO ADD COLUMN col2 integer; +ALTER TABLE DEMO ADD UNIQUE (col1,col2); +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1); +INSERT INTO DEMO (col1,col2) values(2,1); +INSERT INTO DEMO (col1,col2) values(1,2); +INSERT INTO DEMO (col1,col2) values(2,2); +--error 1062 +#ERROR 1062 (23000): Duplicate entry '1-1' for key 'DEMO.col1' +INSERT INTO DEMO (col1,col2) values(1,1); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +ALTER TABLE DEMO DROP INDEX col1; +INSERT INTO DEMO (col1,col2) values(1,1); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#create table for add unqiue index when alter column and drop a primary index (添加、删除、rename主键) +#测试给一列添加主键和删除主键 +create table DEMO (ID integer UNIQUE KEY auto_increment NOT NULL); +insert into DEMO values (null); +insert into DEMO values (null); +--error 1062 +#ERROR 1062 (23000): Duplicate entry '1' for key 'DEMO.ID' +insert into DEMO values (1); +insert into DEMO values (null); +SELECT * FROM DEMO; +ALTER TABLE DEMO ADD COLUMN col1 integer; +ALTER TABLE DEMO ADD COLUMN col2 integer; +--error 3655 +#Can't set NULL value for column 'col1' , 有NULL的时候不能设置主键 +ALTER TABLE DEMO ADD PRIMARY KEY (col1); +UPDATE DEMO set col1 = 1 where ID = 1; +UPDATE DEMO set col1 = 2 where ID = 2; +UPDATE DEMO set col1 = 3 where ID = 3; +ALTER TABLE DEMO ADD PRIMARY KEY (col1); +SELECT * FROM DEMO; +show index from DEMO; +--error 1062 +INSERT INTO DEMO (col1,col2) values(1,1); #失败,primary key col1不能重复 +INSERT INTO DEMO (col1,col2) values(4,1); +--error 1048 +INSERT INTO DEMO (col1,col2) values(null,1);#失败primary key不能插入null +INSERT INTO DEMO (col1,col2) values(5,1); #成功 +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +ALTER TABLE DEMO DROP PRIMARY KEY;#删除主键 +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1);#成功,已经删除主键索引 +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +drop table DEMO; + + +#测试给两列添加主键和删除 添加复合主键 +#测试语句一:alter table 表名 drop primary key; +#测试语句二:alter table 表名 add constraint 主键约束的名字 primary key(列名1,列名2); +#删除语句:alter table 表名 drop primary key; +create table DEMO (ID integer UNIQUE KEY auto_increment NOT NULL); +insert into DEMO values (null); +insert into DEMO values (null); +ALTER TABLE DEMO ADD COLUMN col1 integer; +ALTER TABLE DEMO ADD COLUMN col2 integer; +SELECT * FROM DEMO; +--error 3655 +#Can't set NULL value for column 'col1' , 有NULL的时候不能设置主键 +ALTER TABLE DEMO ADD PRIMARY KEY (col1,col2); +UPDATE DEMO set col1 = 1; +--error 3655 +#Can't set NULL value for column 'col2' , 有NULL的时候不能设置主键 +ALTER TABLE DEMO ADD PRIMARY KEY (col1,col2); +UPDATE DEMO set col2 = 2; +SELECT * FROM DEMO; +--error ER_DUP_ENTRY +#Duplicate entry +ALTER TABLE DEMO ADD PRIMARY KEY (col1,col2); +UPDATE DEMO set col1 = 2 where ID = 2; +ALTER TABLE DEMO ADD PRIMARY KEY (col1,col2); +SELECT * FROM DEMO; +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1); +INSERT INTO DEMO (col1,col2) values(3,3); +INSERT INTO DEMO (col1,col2) values(3,4); +INSERT INTO DEMO (col1,col2) values(4,3); +INSERT INTO DEMO (col1,col2) values(4,4); +--error 1062 +INSERT INTO DEMO (col1,col2) values(3,3); +--error 1062 +INSERT INTO DEMO (col1,col2) values(3,4); +--error 1062 +INSERT INTO DEMO (col1,col2) values(4,3); +--error 1062 +INSERT INTO DEMO (col1,col2) values(4,4); +#这句其实并没有修改成功因为受到主键唯一的约束,但是并没有报错 TODODDL ,innodb其实会报主键重复的(Duplicate entry '2-2' for key 'DEMO.PRIMARY') +--error 1062 +UPDATE DEMO set col1 = 2 where ID = 1; +SELECT * FROM DEMO; +#没有修改成功,但是也没执行报错, TODODDL 后面需要来审视 innodb能够修改成功,daac没有修改成功 +UPDATE DEMO set col1 = 100 where ID = 1; +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +--error 1062 +INSERT INTO DEMO (col1,col2) values(3,3); +ALTER TABLE DEMO DROP PRIMARY KEY;#删除主键 +INSERT INTO DEMO (col1,col2) values(3,3); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +INSERT INTO DEMO (col1,col2) values(1,1);#成功,已经删除复合主键 +drop table DEMO; + + +#create table for add auto_increment (修改表添加和删除自增) +create table DEMO (ID integer PRIMARY KEY not null, NAME varchar(19), AGE integer, GRADE real); +INSERT INTO DEMO values(1,'insert1',1,1.1); +--error 1062 +INSERT INTO DEMO values(1,'insert2',1,1.2); +INSERT INTO DEMO values(2,'insert2',1,1.2); +SELECT * FROM DEMO; +alter table DEMO modify ID int auto_increment; +desc DEMO; +show create table DEMO; +show index from DEMO; +INSERT INTO DEMO (NAME, AGE, GRADE) values('insert3',1,1.2); +INSERT INTO DEMO (NAME, AGE, GRADE) values('insert4',1,1.2); +INSERT INTO DEMO (NAME, AGE, GRADE) values('insert5',1,1.2); +INSERT INTO DEMO (NAME, AGE, GRADE) values('insert6',1,1.2); +INSERT INTO DEMO values(null, 'insert6',1,1.2); +INSERT INTO DEMO values(null, 'insert6',1,1.2); +INSERT INTO DEMO values(null, 'insert6',1,1.2); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +alter table DEMO modify ID int; +desc DEMO; +show create table DEMO; +show index from DEMO; +--error 1048 +#这个地方modify了以后感觉丢失了自增属性,但是唯一属性daac还在 +INSERT INTO DEMO values(null, 'insert6',1,1.2); #1048 (23000): Column 'ID' cannot be null +--error 1062 +INSERT INTO DEMO values(7, 'insert6',1,1.2);#ERROR 1062 (23000): Duplicate entry '7' for key 'DEMO.PRIMARY' +--error 1062 +INSERT INTO DEMO values(8, 'insert6',1,1.2); +SELECT * FROM DEMO; +drop table DEMO; + + +#alter table 修改comment +create table DEMO (ID integer PRIMARY KEY not null, NAME varchar(19), AGE integer, GRADE real); +ALTER TABLE DEMO MODIFY ID integer COMMENT 'id of user'; +show create table DEMO; +#修改多列的comment +ALTER TABLE DEMO MODIFY NAME varchar(19) COMMENT 'name of user', MODIFY AGE integer COMMENT 'age of user'; +show create table DEMO; +drop table DEMO; + + +#create table for alter invisible column test 修改表时设置隐藏列 +create table t1 (col1 INT, col2 INT, col3 INT); +alter table t1 add column col4 int invisible; +--error 1136 +insert into t1 values(1, 2, 3, 4); +insert into t1 (col1, col2, col3, col4) values (11, 22, 33, 44), (111, 222, 333, 444); +#查询语句 *不包含隐藏字段,col4不会出现在返回结果中 +select * from t1; +#显式指定了col4字段,返回结果中包含该隐藏列 +select col1, col2, col3, col4 from t1; +alter table t1 modify column col1 INT INVISIBLE; +alter table t1 alter column col2 set INVISIBLE; +alter table t1 change column col4 col4 INT VISIBLE; +--error 1136 +insert into t1 values(1, 2, 3, 4); +insert into t1 (col3, col4) values (3333,4444); +select * from t1; +select col1, col2, col3, col4 from t1; +alter table t1 alter column col2 set VISIBLE; +select * from t1; +drop table t1; + +# 更改主键列的数据类型 +CREATE TABLE t1 (COL_1 INT COMMENT '列1', COL_2 INTEGER COMMENT '列2', COL_3 BIGINT PRIMARY KEY COMMENT '列3'); +ALTER TABLE t1 MODIFY COLUMN COL_3 TINYINT; +ALTER TABLE t1 MODIFY COLUMN COL_3 SMALLINT; +ALTER TABLE t1 MODIFY COLUMN COL_3 MEDIUMINT; +ALTER TABLE t1 MODIFY COLUMN COL_3 INT; +ALTER TABLE t1 MODIFY COLUMN COL_3 INTEGER; +ALTER TABLE t1 MODIFY COLUMN COL_3 BIGINT; +ALTER TABLE t1 MODIFY COLUMN COL_3 FLOAT; +ALTER TABLE t1 MODIFY COLUMN COL_3 DOUBLE; +ALTER TABLE t1 MODIFY COLUMN COL_3 VARCHAR(20); +DROP TABLE t1; + +# 添加CONSTRAINT +CREATE TABLE `test`.`supplier`( +group_id int(11) not null primary key, +group_name varchar(255) not null +); +CREATE TABLE `test`.`supplier11` ( +id int(11) NOT NULL, +supplier_id int(11) NOT NULL DEFAULT 1, +supplier_name varchar(255) NOT NULL, +group_id int(11) NOT NULL, +PRIMARY KEY (`id`), +UNIQUE KEY `uni_sid`(supplier_id) USING BTREE, +CONSTRAINT `fk_gid` FOREIGN KEY (`group_id`) REFERENCES `test`.`supplier`(`group_id`) ON DELETE NO ACTION ON UPDATE NO ACTION, +CONSTRAINT `chk_1` CHECK (supplier_id > 2 and supplier_id < 100) +); +ALTER TABLE `test`.`supplier11` DROP CHECK `chk_1`; +ALTER TABLE `test`.`supplier11` ADD CONSTRAINT `chk_1000` CHECK((`supplier_id` > 2) and (`supplier_id` < 1000)); +DROP TABLE `test`.`supplier11`; +DROP TABLE `test`.`supplier`; + +# 验证TSE PK在使用add column方式进行创建时,存在约束名称对接不一致问题 +create table DEMO_KEY (ID integer, AGE integer, GRADE real); +# 原先使用 被索引列的列名+tableid作为 PK约束名 现改为PRIMARY+tableid +alter table DEMO_KEY add column col1 integer primary key; +# 原方案是使用PRIMARY+tableid作为约束名进行查找并删除 +alter table DEMO_KEY drop primary key; +# 添加成功说明,mysql侧和cantian侧的元数据均成功删除了primary key,否则报Multi-key +alter table DEMO_KEY add primary key (id); +drop table DEMO_KEY; + + +## 测试新增列名|约束名|索引名大小写不敏感 +--disable_warnings +drop table if exists TEST_COL; +drop table if exists FK_TEST; +CREATE TABLE TEST_COL (id int(18)); +# 增列 +ALTER TABLE TEST_COL ADD COLUMN Col2 integer; +#insert into TEST_COL values(1, 2); +#SELECT cOL2 FROM TEST_COL; +# 删列 +ALTER TABLE TEST_COL DROP COLUMN col2; +# 旧列重命名 +ALTER TABLE TEST_COL RENAME COLUMN ID TO my_ID; +# 改旧列类型并改新列名 +ALTER TABLE TEST_COL ADD COLUMN col3 integer; +ALTER TABLE TEST_COL CHANGE COLUMN coL3 my_col3 varchar(20); +show create table TEST_COL; +# 增加外键约束 +CREATE TABLE FK_TEST (id int(18) primary key); +ALTER TABLE TEST_COL ADD CONSTRAINT my_fk_CONS FOREIGN KEY(MY_ID) REFERENCES FK_TEST(Id); +show create table TEST_COL; +# 删除外键约束 +ALTER TABLE TEST_COL DROP FOREIGN KEY my_fk_CONS; +# 增加索引 +ALTER TABLE TEST_COL ADD INDEX (My_col3); +show create table TEST_COL; +# 删除索引 +ALTER TABLE TEST_COL drop index MY_Col3; +drop table TEST_COL; +drop table FK_TEST; +--enable_warnings + + +## 测试alter_copy情况,运行多次执行失败 +--disable_warnings +drop table if exists test; +--enable_warnings +#普通表转分区表 +create table test(c1 int, c2 int, c3 double); +insert into test values (1,2,10),(2,3,4),(3,5,6),(4,12,16),(1,2,4),(10,2,17),(6,12,21); +alter table test partition by range(c1)(partition p0 values less than (4), +partition p1 values less than (7), partition p2 values less than (12)); +alter table test partition by range(c1)(partition p0 values less than (7), +partition p1 values less than (12)); +--error 1526 +alter table test partition by range(c1)(partition p0 values less than (7), +partition p1 values less than (10)); +--error 1526 +alter table test partition by range(c1)(partition p0 values less than (7), +partition p1 values less than (10)); +alter table test partition by range(c1)(partition p0 values less than (7), +partition p1 values less than (12)); +--error 1526 +alter table test partition by range(c2)(partition p0 values less than (7), +partition p1 values less than (12)); +--error 1526 +alter table test partition by range(c2)(partition p0 values less than (7), +partition p1 values less than (12)); +alter table test partition by range(c2)(partition p0 values less than (7), +partition p1 values less than (15)); +alter table test partition by range(c2)(partition p0 values less than (20)); +alter table test partition by range(c2)(partition p0 values less than (25)); +alter table test partition by range(c2)(partition p0 values less than (20)); +alter table test partition by range(c2)(partition p0 values less than (25)); +drop table test; + +#分区表转分区表 +create table test(c1 int, c2 int) partition by range(c1) (partition p0 values less than (6), +partition p1 values less than (10)); +insert into test values (1,2),(3,4),(6,6),(9,10); +--error 1526 +alter table test partition by range(c1) (partition p0 values less than (7)); +alter table test partition by range(c1) (partition p0 values less than (20)); +drop table test; + +#支持cantian重命名交换列 +create table test (a int, b int, c int, d int); +alter table test rename column a to b, rename column b to c, rename column c to a; +show create table test; +alter table test rename column a to b, rename column b to a, rename column c to newc; +show create table test; +--error 1060 +alter table test rename column a to b; +drop table test; +--error 1059 +CREATE TABLE test (C123456789C123456789C123456789C123456789C123456789C123456789C1234 INT, b int); +CREATE TABLE test (C123456789C123456789C123456789C123456789C123456789C123456789C123 INT, b int); +alter table test rename column C123456789C123456789C123456789C123456789C123456789C123456789C123 to b, + rename column b to C123456789C123456789C123456789C123456789C123456789C123456789C123; +show create table test; +drop table test; +create table test (a integer primary key, b varchar(19) not null, c integer, d real); +# insert some data to table. +insert into test values (1, 'LIOR', 35, 6.9); +insert into test values (4, 'MIKE', 55, 99.92); +insert into test values (8, 'ROMAN', 40, 94.1); +insert into test values (5, 'Eitan', NULL, 4.9); +insert into test values (7, 'zhangdi', NULL, 10000.8); +insert into test values (9, 'Hisses', 1, NULL); +alter table test rename column a to b, rename column b to c, rename column c to a; +show create table test; +drop table test; + +#空表修改列类型 varchar to int +create table test(a INT,b VARCHAR(255) NOT NULL); +alter table test change column b b INT; +insert into test values (1,2),(3,4),(6,6),(9,10); +select * from test; +drop table test; + +#空表修改列类型 int to varchar +create table test(a INT,b INT NOT NULL); +alter table test change column b b VARCHAR(255); +insert into test values (1,'aa'),(2,'bb'),(3,'cc'),(4,'dd'); +select * from test; +drop table test; + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,4),(2,2),(2,2),(4,1),(4,1),(4,1),(4,1),(2,1),(2,1); +SELECT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b) FROM t1 GROUP BY a WITH ROLLUP; +SELECT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT DISTINCT SUM(b), COUNT(DISTINCT b), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP; +SELECT a, SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT a, SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT b, a, SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP; +SELECT DISTINCT b,a, SUM(b) FROM t1 GROUP BY a,b WITH ROLLUP; +ALTER TABLE t1 ADD COLUMN c INT; +SELECT a,b,SUM(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +SELECT distinct a,b,SUM(c) FROM t1 GROUP BY a,b,c WITH ROLLUP; +drop table t1; + +CREATE TABLE t1 (a int, b int); +INSERT INTO t1 VALUES (1,4),(2,2),(2,2),(4,1),(4,1),(4,1),(4,1),(2,1),(2,1); +ALTER TABLE t1 ADD COLUMN c INT; +ALTER TABLE t1 ADD COLUMN d INT; +SELECT * FROM t1; +UPDATE t1 SET c = 3 WHERE a = 1; +SELECT * FROM t1; +ALTER TABLE t1 DROP COLUMN c; +SELECT * FROM t1; +UPDATE t1 SET d = 4 WHERE a = 1; +SELECT * FROM t1; +ALTER TABLE t1 ADD COLUMN e INT; +SELECT * FROM t1; +ALTER TABLE t1 DROP COLUMN b; +SELECT * FROM t1; +INSERT INTO t1 VALUES (8,NULL,NULL),(9,3,5),(10,5,NULL),(11,NULL,7); +SELECT * FROM t1; +drop table t1; + +create table t1(a int, b int, c int auto_increment unique key); +insert into t1 values (1,1,1); +alter table t1 drop column c; +select * from t1; +show create table t1; +drop table t1; + +create table t1(a int, b int unique key, c int auto_increment primary key); +insert into t1 values (1,1,1); +alter table t1 drop column c; +select * from t1; +show create table t1; +drop table t1; + +CREATE TABLE t1(c1 TINYINT NOT NULL, c2 TINYINT NOT NULL, c3 TINYINT NOT NULL); +INSERT INTO t1 VALUES(1,3,1),(3,1,2),(2,2,1),(8,9,2),(7,5,1); +SELECT * FROM t1; +ALTER TABLE t1 ORDER BY c1,c2,c3; +SELECT * FROM t1; +ALTER TABLE t1 ORDER BY c2 desc; +SELECT * FROM t1; +ALTER TABLE t1 ORDER BY c3; +SELECT * FROM t1; +ALTER TABLE t1 ORDER BY c1 asc; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE IF NOT EXISTS t1 ( + id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + pattern VARCHAR(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + pattern_database VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, + replacement VARCHAR(5000) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + enabled ENUM('YES', 'NO') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL + DEFAULT 'YES', + message VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, + pattern_digest VARCHAR(64), + normalized_pattern VARCHAR(5000) +) DEFAULT CHARSET = utf8mb4 ENGINE=CTC; +show tables; +ALTER TABLE t1 DROP COLUMN pattern_digest,ALGORITHM = COPY; +show create table t1; +drop table t1; +# null转not null +SET sql_mode = 'NO_ENGINE_SUBSTITUTION'; +DROP TABLE IF EXISTS t1; +SET CHARACTER SET koi8r; +CREATE TABLE t1 ( + comment CHAR(32) ASCII NOT NULL, + koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL default '' +) CHARSET=latin5; +INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A'); +ALTER TABLE t1 ADD ucs2_f CHAR(32) CHARACTER SET ucs2; +ALTER TABLE t1 CHANGE ucs2_f ucs2_f CHAR(32) UNICODE NOT NULL; +DROP TABLE t1; +SET sql_mode = DEFAULT; +# varchar(3000) -> varchar (5000) +create table t1(col int, col1 varchar(3000)); +insert into t1 values (1,'abc'); +alter table t1 modify column col1 varchar(5000); +drop table t1; + +CREATE TABLE t1(a FLOAT); +INSERT INTO t1 values(1.5); +ALTER TABLE t1 MODIFY COLUMN a FLOAT; +ALTER TABLE t1 CHANGE COLUMN a a FLOAT; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(a DOUBLE); +INSERT INTO t1 values(1.5); +ALTER TABLE t1 MODIFY COLUMN a DOUBLE; +ALTER TABLE t1 CHANGE COLUMN a a DOUBLE; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +create table t1 (f1 int unique, f2 int, f3 float DEFAULT 0.0); +INSERT INTO t1 VALUES (1, 80, 0.0); +INSERT INTO t1 VALUES (2, 81, 0.0); +create table t2 (f1 int, f2 int, f3 float DEFAULT 0.0, constraint c1 foreign key (f2) references t1(f1) on update cascade); +show create table t2; +INSERT INTO t2 VALUES (51, 1, 0.0); +INSERT INTO t2 VALUES (52, 2, 0.0); +--error ER_FK_COLUMN_CANNOT_DROP_CHILD +ALTER TABLE t1 DROP COLUMN f1; +ALTER TABLE t1 DROP COLUMN f2; +--error ER_FK_COLUMN_CANNOT_DROP +ALTER TABLE t2 DROP COLUMN f2; +ALTER TABLE t2 DROP COLUMN f1; +drop table t2; +drop table t1; + +#更改列名 +CREATE TABLE t1(fld1 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld1; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld2; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT, fld2 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld2, RENAME COLUMN fld2 TO fld1; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT, fld2 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld1, RENAME COLUMN fld2 TO fld2; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT, fld2 INT, fld3 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld1, RENAME COLUMN fld2 TO fld3, RENAME COLUMN fld3 TO fld2; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT, fld2 INT, fld3 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld1, RENAME COLUMN fld2 TO fld2, RENAME COLUMN fld3 TO fld3; +DROP TABLE t1; +CREATE TABLE t1(fld1 INT, fld2 INT, fld3 INT); +ALTER TABLE t1 RENAME COLUMN fld1 TO fld2, RENAME COLUMN fld3 TO fld4, RENAME COLUMN fld2 TO fld1; +DROP TABLE t1; + +#添加NOT NULL列 +CREATE TABLE t1(col1 int); +INSERT INTO t1 values (1234); +ALTER TABLE t1 ADD COLUMN col2 int NOT NULL; +ALTER TABLE t1 ADD COLUMN coL3 double NOT NULL; +ALTER TABLE t1 ADD COLUMN col4 float NOT NULL; +ALTER TABLE t1 ADD COLUMN col5 blob NOT NULL; +ALTER TABLE t1 ADD COLUMN col6 blob NOT NULL, ADD COLUMN col7 int NOT NULL; +ALTER TABLE t1 DROP COLUMN col2, ADD COLUMN col8 int NOT NULL, ADD COLUMN col9 int; +ALTER TABLE t1 ADD COLUMN col10 int NOT NULL, DROP COLUMN col3, DROP COLUMN col4; +SELECT * FROM t1; +ALTER TABLE t1 ADD COLUMN col15 int default 333; +ALTER TABLE t1 ADD COLUMN col16 int NOT NULL default 444; +SELECT * FROM t1; +DROP TABLE t1; + +create table t1 (i int unsigned not null auto_increment primary key); +insert into t1 values (null),(null),(null),(null); +alter table t1 drop i,add i int unsigned not null auto_increment, drop primary key, add primary key (i); +drop table t1; + +--disable_warnings +CREATE TABLE t1 (c1 FLOAT(6,2)); +INSERT INTO t1 VALUES (123); +ALTER TABLE t1 MODIFY COLUMN c1 FLOAT(7,3); +drop table t1; +CREATE TABLE t1 (c1 DOUBLE(6,2)); +INSERT INTO t1 VALUES (123); +ALTER TABLE t1 MODIFY COLUMN c1 DOUBLE(7,3); +drop table t1; +CREATE TABLE t1 (c1 REAL(6,2)); +INSERT INTO t1 VALUES (123); +ALTER TABLE t1 MODIFY COLUMN c1 REAL(7,3); +drop table t1; +CREATE TABLE t1 (c1 FLOAT(6,2), c2 DOUBLE(6,2), c3 REAL(6,2)); +INSERT INTO t1 VALUES (123, 456, 789); +ALTER TABLE t1 MODIFY COLUMN c2 DOUBLE(7,3); +drop table t1; +--enable_warnings + +create database db1; +create database db2; +use db1; +create table t(id int primary key); +create table t1( +a int DEFAULT NULL, +c float, +id int primary key auto_increment, +foreign key(id) references t(id)); +alter table t1 rename to t2, add column b int, algorithm = copy; +alter table t2 rename to t1; +rename table t1 to db2.t2; +alter table db2.t2 modify column c int; +alter table db2.t2 alter column a drop default, rename to t1; +alter table t1 rename to db2.t2; +alter table db2.t2 rename to db1.t1, modify column c char(10); +alter table t1 rename to t2; +drop database db1; +drop database db2; diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_analyze.test b/mysql-test/suite/tianchi/t/ctc_ddl_analyze.test new file mode 100644 index 0000000..b36212a --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_analyze.test @@ -0,0 +1,52 @@ +--disable_warnings +drop table if exists DEMO; +--enable_warnings + +# create a table. +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); + +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); + +# create index 创建普通 +create index idx_id ON DEMO (ID); + +analyze table DEMO; + +select * from DEMO where ID = 1; +select * from DEMO where ID >= 1; +select * from DEMO where ID <= 10; +select * from DEMO where ID >= 1 AND ID <= 10; + +create table t1(a1 int, a2 int,a3 int,a4 int,a5 int,a6 int,a7 int,a8 int, a9 int,a10 int, +a11 int,a12 int,a13 int,a14 int,a15 int,a16 int,a17 int,a18 int,a19 int,a20 int,a21 int, +a22 int,a23 int,a24 int,a25 int,a26 int,a27 int,a28 int,a29 int,a30 int,a31 int,a32 int, +a33 int,a34 int,a35 int,a36 int,a37 int,a38 int,a39 int,a40 int,a41 int,a42 int,a43 int, +a44 int,a45 int,a46 int,a47 int,a48 int,a49 int,a50 int,a51 int,a52 int,a53 int,a54 int, +a55 int,a56 int,a57 int,a58 int,a59 int,a60 int,a61 int,a62 int,a63 int,a64 int,a65 int, +a66 int,a67 int,a68 int,a69 int,a70 int,a71 int,a72 int,a73 int,a74 int,a75 int,a76 int, +a77 int,a78 int,a79 int,a80 int,a81 int,a82 int,a83 int,a84 int,a85 int,a86 int,a87 int, +a88 int,a89 int,a90 int,a91 int,a92 int,a93 int,a94 int,a95 int,a96 int,a97 int,a98 int +)PARTITION BY HASH (`a1`) PARTITIONS 1024; +insert into t1 values(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, +26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54, +55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83, +84,85,86,87,88,89,90,91,92,93,94,95,96,97,98); +insert into t1 values(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25, +26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54, +55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83, +84,85,86,87,88,89,90,91,92,93,94,95,96,97,98); +select a1 from t1 where a1 = 1; +analyze table t1; +explain select a1 from t1 where a1 = 1; +drop table t1; + +#drop table +drop table DEMO; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_auto_inc.test b/mysql-test/suite/tianchi/t/ctc_ddl_auto_inc.test new file mode 100644 index 0000000..7f7ff5c --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_auto_inc.test @@ -0,0 +1,587 @@ +--disable_warnings +drop table if exists DEMO; +--enable_warnings +#特别注意,每个测试用例直接用2行空行隔开,中间不要有任何空行 + +#有符号TINYINT主键自增测试(范围为-128-127) +create table DEMO (ID TINYINT PRIMARY KEY auto_increment ,ID1 integer); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (-100, 1);#负数不会影响自增值 +--error 1062 +insert DEMO values (-100, 1);#主键重复 +insert DEMO values (-127, 1); +insert DEMO values (-128, 1); +--error 1264 +insert DEMO values (-129, 1); +insert DEMO values (null, 3); +insert DEMO values (30, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (60, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 80 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (80, 80); +delete from DEMO where ID = 80;#删除以后,自增值依旧存在 +insert DEMO values (null, 81); +update DEMO set ID = 90 where ID1 = 80; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (126, 2147483646); +insert DEMO values (null, 2147483647); +--error 1062 +insert DEMO values (null, 2147483647);#自增超出范围了,不能在插入了,自增还是2147483647 +--error 1264 +insert DEMO values (128, 2147483647); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#无符号TINYINT主键自增测试(范围为0-255) +create table DEMO (ID TINYINT unsigned PRIMARY KEY auto_increment ,ID1 integer); +--error 1264 +insert DEMO values (-1, 3);#负数插入失败 +insert DEMO values (0, 3);#此处0和null相同 +insert DEMO values (0, 3);#此处0和null相同 +--error 1062 +insert DEMO values (1, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (20, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (50, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 110 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (110, 110); +delete from DEMO where ID = 110;#删除以后,自增值依旧存在 +insert DEMO values (null, 111); +update DEMO set ID = 120 where ID1 = 111; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (254, 254); +insert DEMO values (null, 255); +--error 1062 +insert DEMO values (null, 256);#自增超出范围了,不能在插入了,自增还是255 +--error 1264 +insert DEMO values (256, 256); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#有符号SMALLINT主键自增测试(范围为-32768-32767) +create table DEMO (ID SMALLINT PRIMARY KEY auto_increment ,ID1 integer); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (-100, 1);#负数不会影响自增值 +--error 1062 +insert DEMO values (-100, 1);#主键重复 +insert DEMO values (-32768, 1); +insert DEMO values (-128, 1); +--error 1264 +insert DEMO values (-32769, 1); +insert DEMO values (null, 3); +insert DEMO values (30, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (60, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 80 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (80, 80); +delete from DEMO where ID = 80;#删除以后,自增值依旧存在 +insert DEMO values (null, 81); +update DEMO set ID = 90 where ID1 = 80; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (32766, 2147483646); +insert DEMO values (null, 2147483647); +--error 1062 +insert DEMO values (null, 2147483647);#自增超出范围了,不能在插入了,自增还是32767 +--error 1264 +insert DEMO values (32768, 2147483647); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#无符号SMALLINT主键自增测试(范围为0-65535) +create table DEMO (ID SMALLINT unsigned PRIMARY KEY auto_increment ,ID1 integer); +--error 1264 +insert DEMO values (-1, 3);#负数插入失败 +insert DEMO values (0, 3);#此处0和null相同 +insert DEMO values (0, 3);#此处0和null相同 +--error 1062 +insert DEMO values (1, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (20, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (200, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 210 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (210, 210); +delete from DEMO where ID = 210;#删除以后,自增值依旧存在 +insert DEMO values (null, 211); +update DEMO set ID = 230 where ID1 = 210; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (65534, 65535); +insert DEMO values (null, 65535); +--error 1062 +insert DEMO values (null, 65535);#自增超出范围了,不能在插入了,自增还是65535 +--error 1264 +insert DEMO values (65536, 65536); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#有符号MEDIUMINT主键自增测试(范围为-8388608-8388607) +create table DEMO (ID MEDIUMINT PRIMARY KEY auto_increment ,ID1 integer); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (-100, 1);#负数不会影响自增值 +--error 1062 +insert DEMO values (-100, 1);#主键重复 +insert DEMO values (-8388608, 1); +insert DEMO values (-128, 1); +--error 1264 +insert DEMO values (-8388609, 1); +insert DEMO values (null, 3); +insert DEMO values (30, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (60, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 80 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (80, 80); +delete from DEMO where ID = 80;#删除以后,自增值依旧存在 +insert DEMO values (null, 81); +update DEMO set ID = 90 where ID1 = 80; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (8388606, 8388606); +insert DEMO values (null, 8388607); +--error 1062 +insert DEMO values (null, 8388607);#自增超出范围了,不能在插入了,自增还是8388607 +--error 1264 +insert DEMO values (8388608, 8388608); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#无符号MEDIUMINT主键自增测试(范围为0-16777215) +create table DEMO (ID MEDIUMINT unsigned PRIMARY KEY auto_increment ,ID1 integer); +--error 1264 +insert DEMO values (-1, 3);#负数插入失败 +insert DEMO values (0, 3);#此处0和null相同 +insert DEMO values (0, 3);#此处0和null相同 +--error 1062 +insert DEMO values (1, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (20, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (200, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 210 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (210, 210); +delete from DEMO where ID = 210;#删除以后,自增值依旧存在 +insert DEMO values (null, 211); +update DEMO set ID = 230 where ID1 = 210; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (16777214, 16777214); +insert DEMO values (null, 16777215); +--error 1062 +insert DEMO values (null, 16777215);#自增超出范围了,不能在插入了,自增还是16777215 +--error 1264 +insert DEMO values (16777216, 16777216); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#有符号整形主键自增测试(范围为-2147483648-2147483647) +create table DEMO (ID integer PRIMARY KEY auto_increment ,ID1 integer); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (-100, 1);#负数不会影响自增值 +--error 1062 +insert DEMO values (-100, 1);#主键重复 +insert DEMO values (-101, 1); +insert DEMO values (null, 3); +insert DEMO values (100, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (200, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 2000 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (2000, 2000); +delete from DEMO where ID = 2000;#删除以后,自增值依旧存在 +insert DEMO values (null, 20001); +update DEMO set ID = 20001 where ID1 = 20001; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (2147483646, 2147483646); +insert DEMO values (null, 2147483647); +--error 1062 +insert DEMO values (null, 2147483647);#自增超出范围了,不能在插入了,自增还是2147483647 +--error 1264 +insert DEMO values (2147483648, 2147483647);#自增超出范围了,不能在插入了,自增还是2147483647 +insert DEMO values (2147483644, 2147483644); +insert DEMO values (-2147483646, -2147483646); +insert DEMO values (-2147483647, -2147483646); +insert DEMO values (-2147483648, -2147483646); +--error 1264 +insert DEMO values (-2147483649, -2147483646);#ERROR 1264 (22003): Out of range value for column 'ID' at row 1 +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#无符号整形主键自增测试(范围为0-4294967295) +create table DEMO (ID integer unsigned PRIMARY KEY auto_increment ,ID1 integer); +--error 1264 +insert DEMO values (-1, 3);#负数插入失败 +insert DEMO values (0, 3);#此处0和null相同 +insert DEMO values (0, 3);#此处0和null相同 +--error 1062 +insert DEMO values (1, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (100, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (200, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 2000 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (2000, 2000); +delete from DEMO where ID = 2000;#删除以后,自增值依旧存在 +insert DEMO values (null, 20001); +update DEMO set ID = 20001 where ID1 = 20001; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (2147483646, 2147483646); +insert DEMO values (null, 2147483647); +insert DEMO values (4294967294, 2147483646); +insert DEMO values (null, 2147483646); +--error 1062 +insert DEMO values (null, 2147483646);#自增超出范围了,不能在插入了,自增还是4294967295 +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#有符号BIGINT主键自增测试(范围为-9223372036854775808-9223372036854775807) +create table DEMO (ID BIGINT PRIMARY KEY auto_increment ,ID1 BIGINT); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (-100, 1);#负数不会影响自增值 +--error 1062 +insert DEMO values (-100, 1);#主键重复 +insert DEMO values (-9223372036854775808, 1); +insert DEMO values (-128, 1); +--error 1264 +insert DEMO values (-9223372036854775809, 1); +insert DEMO values (null, 3); +insert DEMO values (30, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (60, 3);#正数会影响自增值 下一次应该从后面开始自增 +insert DEMO values (null, 3); +insert DEMO values (null, 3); +select * from DEMO; +--error 1062 +update DEMO set ID = 80 where ID1 = 3;#主键重复,因为ID1=3的列有很多列 +select * from DEMO; +insert DEMO values (80, 80); +delete from DEMO where ID = 80;#删除以后,自增值依旧存在 +insert DEMO values (null, 81); +update DEMO set ID = 90 where ID1 = 80; +insert DEMO values (null, 3); +insert DEMO values (null, 3); +insert DEMO values (9223372036854775806, 9223372036854775806); +insert DEMO values (null, 9223372036854775807); +--error 1062 +insert DEMO values (null, 9223372036854775807);#自增超出范围了,不能在插入了,自增还是9223372036854775807 +--error 1264 +insert DEMO values (9223372036854775808, 9223372036854775808); +select *from DEMO; +show create table DEMO; +drop table DEMO; + + +#无符号BIGINT主键自增测试(范围为0-18446744073709551615) +##tse的uint64_t对接参天的int64_t(范围为-9223372036854775808-9223372036854775807) +create table DEMO (ID BIGINT unsigned PRIMARY KEY auto_increment ,ID1 BIGINT); +insert DEMO values (9223372036854775806, 100); +insert DEMO values (null, 100); +insert DEMO values (18446744073709551200, 200); +insert DEMO values (null, 330); +insert DEMO values (18446744073709551608, 330); +insert DEMO values (null, 330); +insert DEMO values (null, 330); +insert DEMO values (18446744073709551614, 100); +--error 1467 +insert DEMO values (null, 320); +--error 1467 +insert DEMO values (null, 320); +select * from DEMO; +show create table DEMO; +drop table DEMO; +create table DEMO (ID1 BIGINT); +alter table DEMO add column ID BIGINT unsigned PRIMARY KEY auto_increment; +drop table DEMO; +create table DEMO (ID BIGINT, ID1 BIGINT); +alter table DEMO modify ID BIGINT unsigned PRIMARY KEY auto_increment; +drop table DEMO; + +#last_insert_id应返回一条语句里第一个成功插入的自增值 +create table DEMO (ID int PRIMARY KEY auto_increment); +insert into DEMO values (null),(null),(null),(null); +select @@last_insert_id; +insert into DEMO values (null),(null),(null),(null); +select @@last_insert_id; +drop table DEMO; + +#测试唯一索引和主键索引重复插入 +create table t1(col int); +alter table t1 add column col1 int auto_increment unique key; +alter table t1 add primary key(col); +insert into t1 values (0,1); +--error 1062 +insert into t1 values (1,1); +insert into t1 values (2,2); +--error 1062 +insert into t1 values (2,3); +insert into t1 (col) values (3); +select * from t1; +drop table t1; + +create table t1(col int); +alter table t1 add column col1 int auto_increment primary key; +alter table t1 add unique key(col); +insert into t1 values (0,1); +--error 1062 +insert into t1 values (1,1); +insert into t1 values (2,2); +--error 1062 +insert into t1 values (2,3); +insert into t1 (col) values (3); +select * from t1; +drop table t1; +create table t1(c1 int primary key auto_increment); +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(4); +insert into t1 values(-1); +insert into t1 values(-3); +insert into t1 values(-2147483648); +insert into t1 values(); +insert into t1 values(); +insert into t1 values(2147483646); +insert into t1 values(); +--error 1062 +insert into t1 values(); +select * from t1; +select * from t1 where c1 = 2147483646; +select * from t1 where c1 = -2147483648; +select * from t1 where c1 > 0; +drop table t1; +create table t1(c1 tinyint AUTO_INCREMENT,c2 int, primary key(c1,c2) ); +insert into t1 values(127 ,1); +INSERT INTO t1(c2) VALUES(33); +INSERT INTO t1(c2) VALUES(34); +INSERT INTO t1(c2) VALUES(35); +INSERT INTO t1 VALUES(-1, -1); +INSERT INTO t1(c2) VALUES(36); +select * from t1; +drop table t1; +create table DEMO (ID BIGINT unsigned PRIMARY KEY auto_increment); +--error 1264 +insert DEMO values (-1); +--error 1264 +insert DEMO values (-2); +insert DEMO values (0); +insert DEMO values (); +insert DEMO values (); +--error 1062 +insert DEMO values (2); +select * from DEMO; +insert DEMO values (9223372036854775806); +insert DEMO values (null); +insert DEMO values (18446744073709551200); +insert DEMO values (null); +insert DEMO values (null); +insert DEMO values (null); +insert DEMO values (18446744073709551614); +--error 1467 +insert DEMO values (null); +drop table DEMO; + +#测试自增列上加普通索引 +create table DEMO (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), purchased DATE, KEY(id)); +insert into DEMO (name, purchased) values ("Jack","2022-01-01"); +insert into DEMO (name, purchased) values ("Amy","2022-01-01"); +insert into DEMO (name, purchased) values ("Echo","2022-01-10"); +insert into DEMO (name, purchased) values ("Jack","2022-01-11"); +insert into DEMO (name, purchased) values ("Jack","2022-01-13"); +insert into DEMO (name, purchased) values ("Amy","2022-01-13"); +insert into DEMO (name, purchased) values ("Amy","2022-01-13"); +select * from DEMO; +select * from DEMO where id = 1; +select * from DEMO where name = "Amy" and purchased = "2022-01-01"; +insert into DEMO values(10,"Candy","2023-05-01"); +insert into DEMO (name, purchased) values ("Jack","2022-01-13"); +update DEMO SET id = 11 where name = "Candy"; +select * from DEMO; +drop table DEMO; + +create table DEMO (id INT NOT NULL AUTO_INCREMENT UNIQUE, name VARCHAR(50), KEY(id)); +insert into DEMO (name) values ("Jack"); +insert into DEMO (name) values ("Zoey"); +update DEMO SET id = 5 where name = "Zoey"; +insert into DEMO (name) values ("Maya"); +select * from DEMO; +select * from DEMO where name = "Maya"; +drop table DEMO; + +create table DEMO(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(50), purchased DATE, key(id, name)); +insert into DEMO (name, purchased) values ("Jack","2022-01-01"); +insert into DEMO (name, purchased) values ("Bob","2022-01-01"); +insert into DEMO (name, purchased) values ("Amy","2022-01-01"); +insert into DEMO (name, purchased) values ("Jack","2022-01-05"); +insert into DEMO (name, purchased) values ("Amy","2022-01-05"); +insert into DEMO (name, purchased) values (null,null); +select * from DEMO; +select * from DEMO where name = "Jack"; +select * from DEMO where id > 0; +select * from DEMO where name = "Amy" and id = 5; +select * from DEMO where purchased between "2022-01-03" and "2022-01-06"; +update DEMO SET name = "Eric" where name = "Jack"; +select * from DEMO; +drop table DEMO; + +#测试float/double创建自增 +CREATE TABLE DEMO(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10))ROW_FORMAT=REDUNDANT,ENGINE=CTC; +insert into DEMO values (0.1, "aaa"); +insert into DEMO values (0.5, "bbb"); +insert into DEMO values (0.6, "bbb"); +insert into DEMO values (10.5, "sdss"); +insert into DEMO values (null, "dssd"); +select * from DEMO; +insert into DEMO values (13.5, "sdss"); +insert into DEMO values (null, "dssd"); +select * from DEMO; +insert into DEMO values (15.9, "sdss"); +insert into DEMO values (null, "dssd"); +select * from DEMO; +select * from DEMO where c1 = 1; +update DEMO set c1 =10 where c1=15; +delete from DEMO where c1 = 1; +insert into DEMO values (null, "sdss"); +select * from DEMO; +drop table DEMO; + +CREATE TABLE DEMO(a FLOAT AUTO_INCREMENT KEY) ENGINE = CTC; +insert into DEMO values (null); +insert into DEMO values (null); +insert into DEMO values (3.1); +insert into DEMO values (null); +insert into DEMO values (3.9); +select * from DEMO; +insert into DEMO values (10.5); +insert into DEMO values (null); +select * from DEMO; +insert into DEMO values (11.5); +insert into DEMO values (null); +select * from DEMO; +select * from DEMO where a = 1; +update DEMO set a =10 where a =3.1; +delete from DEMO where a = 1; +insert into DEMO values (null); +select * from DEMO; +drop table DEMO; + +CREATE TABLE DEMO(ID int); +alter table DEMO add column ID1 double PRIMARY KEY auto_increment; +drop table DEMO; + +CREATE TABLE DEMO(ID int); +alter table DEMO add column ID1 float PRIMARY KEY auto_increment; +drop table DEMO; + +#测试自增列上删除索引 +create table DEMO (ID int unsigned PRIMARY KEY auto_increment); +alter table DEMO drop primary key, add unique(ID); +alter table DEMO drop key ID, add key(ID); +drop table DEMO; + +CREATE TABLE DEMO (ID int(5) unsigned NOT NULL auto_increment, PRIMARY KEY (ID)); +CREATE UNIQUE INDEX test on DEMO (ID); +show create table DEMO; +DROP INDEX test ON DEMO; +show create table DEMO; +drop table DEMO; + +create table DEMO (ID int unsigned PRIMARY KEY auto_increment); +alter table DEMO drop primary key, add key(ID); +drop table DEMO; + +create table DEMO (ID int unsigned PRIMARY KEY auto_increment); +--error 1075 +alter table DEMO drop primary key; +drop table DEMO; + +CREATE TABLE DEMO (f1 INT, f2 INT, f3 INT); +ALTER TABLE DEMO ADD CONSTRAINT PRIMARY KEY (f1); +ALTER TABLE DEMO DROP CONSTRAINT `primary`, DROP COLUMN f3; +ALTER TABLE DEMO ADD CONSTRAINT PRIMARY KEY (f1); +drop table DEMO; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_cascade.test b/mysql-test/suite/tianchi/t/ctc_ddl_cascade.test new file mode 100644 index 0000000..3e04a77 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_cascade.test @@ -0,0 +1,786 @@ +CREATE DATABASE IF NOT EXISTS CASCADE_TEST; +USE CASCADE_TEST; + +CREATE TABLE t1 (a INT NOT NULL UNIQUE, b INT NOT NULL); +CREATE TABLE t2 (a INT KEY, b INT, FOREIGN KEY (b) REFERENCES t1(a) ON DELETE CASCADE ON UPDATE CASCADE); + +insert into t1 values(1,1); +insert into t2 values(1,1); + +insert into t1 values(2,2); +insert into t2 values(2,2); + +update t1 set a = 5 where a = 1; + +select * from t1; +select * from t2; + +delete from t1 where b = 2; + +select * from t1; +select * from t2; + +CREATE TABLE t3 (a INT NOT NULL UNIQUE, b INT NOT NULL); +CREATE TABLE t4 (a INT KEY, b INT, FOREIGN KEY (b) REFERENCES t3(a) ON DELETE SET NULL ON UPDATE SET NULL); + +insert into t3 values(1,1); +insert into t4 values(1,1); + +insert into t3 values(2,2); +insert into t4 values(2,2); + +update t3 set a = 5 where a = 1; + +select * from t3; +select * from t4; + +delete from t3 where b = 2; + +select * from t3; +select * from t4; + +CREATE TABLE TT1(A INT PRIMARY KEY); +CREATE TABLE TT2(A INT UNIQUE, B INT); +ALTER TABLE TT2 ADD CONSTRAINT FK_CASCADE FOREIGN KEY(B) REFERENCES TT1 (A) ON DELETE CASCADE ON UPDATE CASCADE; +insert into TT1 values(1),(2),(3),(4),(5); +insert into TT2 values(1,1),(2,2),(3,3),(4,4),(5,5); + +select * from TT1; +select * from TT2; + +delete from TT1 where A = 1; + +select * from TT1; +select * from TT2; + +update TT1 set A = 12 where A = 2; + +select * from TT1; +select * from TT2; + +set foreign_key_checks = 1; +drop table if exists t1,t2; +create table t1 (f1 int unique, f2 int, f3 float DEFAULT 0.0); +INSERT INTO t1 VALUES (1, 80, 0.0); +INSERT INTO t1 VALUES (2, 81, 0.0); +create table t2 (f1 int, f2 int, f3 float DEFAULT 0.0, constraint c1 foreign key (f2) references t1(f1) on update cascade); +INSERT INTO t2 VALUES (51, 1, 0.0); +INSERT INTO t2 VALUES (52, 2, 0.0); +UPDATE t1 SET f1 = null WHERE f1 = 1; +SELECT * FROM t1; +SELECT * FROM t2; + +set foreign_key_checks = 1; +drop table if exists t1,t2; +create table t1 (f1 float, f2 int, f3 float DEFAULT 0.0, unique key(f1, f2)); +INSERT INTO t1 VALUES (1, 80, 0.0); +INSERT INTO t1 VALUES (2, 81, 0.0); +create table t2 (f1 int, f2 float, f3 int, constraint foreign key (f2, f3) references t1(f1, f2) on update cascade); +INSERT INTO t2 VALUES (12, 1, 80); +INSERT INTO t2 VALUES (22, 2, 81); +UPDATE t1 SET f1 = 100, f2 = null WHERE f1 = 1; +SELECT * FROM t1; +SELECT * FROM t2; + +set foreign_key_checks = 1; +drop table if exists t1,t2; +create table t1 (f1 float, f2 int, f3 varchar(20), f4 varchar(100), unique key(f1, f2, f3)); +INSERT INTO t1 VALUES (1, 80, 'ak47', 'mp7'); +INSERT INTO t1 VALUES (2, 81, 'xm8', 'an94'); +create table t2 (f1 int, f2 float, f3 int, f4 varchar(20), constraint foreign key (f2, f3, f4) references t1(f1, f2, f3) on update cascade); +INSERT INTO t2 VALUES (12, 1, 80, 'ak47'); +INSERT INTO t2 VALUES (22, 2, 81, 'xm8'); +UPDATE t1 SET f1 = 100, f2 = null, f3 = null WHERE f1 = 1; +SELECT * FROM t1; +SELECT * FROM t2; + +# test for delete all rows +drop table if exists t1,t2; +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1)); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 1; +delete ignore from t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1)); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 1; +--error 1451 +delete from t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1) on delete cascade); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 0; +DELETE FROM t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1) on delete cascade); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 0; +delete ignore from t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1) on delete cascade); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 1; +DELETE FROM t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + +create table t1 (f1 int primary key, f2 int); +create table t2 (f1 int, f2 int, constraint c1 foreign key (f2) references t1(f1) on delete cascade); +INSERT INTO t1 VALUES (1, 80); +INSERT INTO t1 VALUES (2, 81); +INSERT INTO t2 VALUES (51, 1); +INSERT INTO t2 VALUES (52, 2); +set foreign_key_checks = 1; +DELETE IGNORE FROM t1; +select * from t1; +select * from t2; +drop table t2; +drop table t1; + + +SET SESSION foreign_key_checks=0; +SET NAMES utf8; +CREATE TABLE `t1` ( +a INT, +b VARCHAR(512), +UNIQUE KEY (a, b) +) charset latin1; + +CREATE TABLE `t2` ( +id INT, +a INT, +b VARCHAR(512), +PRIMARY KEY (id), +UNIQUE KEY `unqq` (a, b), +FOREIGN KEY (a, b) REFERENCES `t1` (a, b) +ON DELETE CASCADE ON UPDATE CASCADE +) charset latin1; + +INSERT INTO `t1` VALUES (1, 'bbb'); +INSERT INTO `t2` VALUES (100, 1, 'bbb'), (101, 3, 'bbb'); +SET SESSION foreign_key_checks=1; +--error 1761 +UPDATE IGNORE `t1` SET a = 3; +drop table t1,t2; + +SET SESSION foreign_key_checks=0; +SET NAMES utf8; +CREATE TABLE `t1` ( +a INT, +b VARCHAR(512), +UNIQUE KEY (a, b) +) charset latin1; + +CREATE TABLE `t2` ( +id INT, +a INT, +b VARCHAR(512), +PRIMARY KEY (id), +UNIQUE KEY `unqq` (a, b), +FOREIGN KEY (a, b) REFERENCES `t1` (a, b) +ON DELETE CASCADE ON UPDATE CASCADE +) charset latin1; + +INSERT INTO `t1` VALUES (1, 'bbb'); +INSERT INTO `t2` VALUES (100, 1, 'bbb'), (101, 3, 'bbb'); +SET SESSION foreign_key_checks=1; +--error 1761 +UPDATE IGNORE `t1` SET a = 3; +drop table t1,t2; + + +SET SESSION foreign_key_checks=0; +SET NAMES utf8; +CREATE TABLE `t1` ( +a INT, +b VARCHAR(512), +UNIQUE KEY (a, b) +) charset latin1; + +CREATE TABLE `t2` ( +id INT, +a INT, +b VARCHAR(512), +PRIMARY KEY (id), +UNIQUE KEY `unqq` (a, b), +FOREIGN KEY (a, b) REFERENCES `t1` (a, b) +ON DELETE CASCADE ON UPDATE CASCADE +) charset latin1; + +INSERT INTO `t1` VALUES (1, 'bbb'), (3, 'bbb'); +INSERT INTO `t2` VALUES (100, 1, 'bbb'); +SET SESSION foreign_key_checks=1; +UPDATE IGNORE `t1` SET a = 3; +drop table t1,t2; + +drop table if exists t4; +drop table if exists t3; +create table t1(a int primary key); +create table t2(a int primary key); +create table t3(a int, constraint fk_1 foreign key(a) references t1(a) on update cascade, constraint fk_2 foreign key(a) references t2(a) on update cascade); +insert into t1 values(1); +insert into t2 values(1); +insert into t3 values(1); +--error 1452 +update t1 set a = 2; +--error 1452 +update t2 set a = 2; +drop table t1,t2,t3; + +DROP TABLE IF EXISTS T1; +DROP TABLE IF EXISTS T2; +CREATE TABLE T1(A INT UNIQUE); +CREATE TABLE T2(A INT UNIQUE NOT NULL); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE CASCADE; +INSERT INTO T1 VALUES(1); +INSERT INTO T2 VALUES(1); +--error 1451 +UPDATE T1 SET A = NULL WHERE A = 1; +DROP TABLE T1,T2; + +drop table if exists t1; +create table t1( +id int primary key, +pid int, +index(pid), +foreign key(pid) references t1(id) on delete cascade) engine=CTC; +insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), +(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); +--error 3008 +delete from t1 where id = 0; +drop table t1; + +DROP TABLE IF EXISTS T1; +DROP TABLE IF EXISTS T2; +DROP TABLE IF EXISTS T3; +DROP TABLE IF EXISTS T4; +DROP TABLE IF EXISTS T5; +DROP TABLE IF EXISTS T6; +DROP TABLE IF EXISTS T7; +DROP TABLE IF EXISTS T8; +DROP TABLE IF EXISTS T9; +DROP TABLE IF EXISTS T10; +DROP TABLE IF EXISTS T11; +DROP TABLE IF EXISTS T12; +DROP TABLE IF EXISTS T13; +DROP TABLE IF EXISTS T14; +DROP TABLE IF EXISTS T15; +DROP TABLE IF EXISTS T16; +CREATE TABLE T1(A INT UNIQUE); +CREATE TABLE T2(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T1(A) ON UPDATE CASCADE); +CREATE TABLE T3(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T2(A) ON UPDATE CASCADE); +CREATE TABLE T4(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T3(A) ON UPDATE CASCADE); +CREATE TABLE T5(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T4(A) ON UPDATE CASCADE); +CREATE TABLE T6(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T5(A) ON UPDATE CASCADE); +CREATE TABLE T7(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T6(A) ON UPDATE CASCADE); +CREATE TABLE T8(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T7(A) ON UPDATE CASCADE); +CREATE TABLE T9(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T8(A) ON UPDATE CASCADE); +CREATE TABLE T10(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T9(A) ON UPDATE CASCADE); +CREATE TABLE T11(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T10(A) ON UPDATE CASCADE); +CREATE TABLE T12(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T11(A) ON UPDATE CASCADE); +CREATE TABLE T13(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T12(A) ON UPDATE CASCADE); +CREATE TABLE T14(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T13(A) ON UPDATE CASCADE); +CREATE TABLE T15(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T14(A) ON UPDATE CASCADE); +CREATE TABLE T16(A INT UNIQUE, FOREIGN KEY(A) REFERENCES T15(A) ON UPDATE CASCADE); +INSERT INTO T1 VALUES(1); +INSERT INTO T2 VALUES(1); +INSERT INTO T3 VALUES(1); +INSERT INTO T4 VALUES(1); +INSERT INTO T5 VALUES(1); +INSERT INTO T6 VALUES(1); +INSERT INTO T7 VALUES(1); +INSERT INTO T8 VALUES(1); +INSERT INTO T9 VALUES(1); +INSERT INTO T10 VALUES(1); +INSERT INTO T11 VALUES(1); +INSERT INTO T12 VALUES(1); +INSERT INTO T13 VALUES(1); +INSERT INTO T14 VALUES(1); +INSERT INTO T15 VALUES(1); +INSERT INTO T16 VALUES(1); +--error 3008 +UPDATE T1 SET A = 2 WHERE A = 1; +drop table T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16; + +DROP TABLE IF EXISTS T1; +DROP TABLE IF EXISTS T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(19,2) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE CASCADE; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +update T1 set a = 1.2345678; +select * from T1; +select * from T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(20,3) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON DELETE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(18,5) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON DELETE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(20,3) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON DELETE CASCADE; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(18,5) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON DELETE CASCADE; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(20,3) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE CASCADE; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +UPDATE T1 set A = 1.2345678; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(18,5) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE CASCADE; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +UPDATE T1 set A = 1.2345678; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(20,3) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +UPDATE T1 set A = 1.2345678; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5) UNIQUE); +CREATE TABLE T2(A DECIMAL(18,5) UNIQUE); +ALTER TABLE T2 ADD FOREIGN KEY FF(A) REFERENCES T1(A) ON UPDATE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1); +insert into T2 values(1); +SET foreign_key_checks = 1; +UPDATE T1 set A = 1.2345678; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5), B DECIMAL(20,5), UNIQUE KEY(A, B)); +CREATE TABLE T2(A DECIMAL(18,5), B DECIMAL(20,5)); +ALTER TABLE T2 ADD FOREIGN KEY FF(A, B) REFERENCES T1(A, B) ON DELETE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1, 1); +insert into T2 values(1, 1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5), B DECIMAL(20,5), UNIQUE KEY(A, B)); +CREATE TABLE T2(A DECIMAL(20,5), B DECIMAL(20,5)); +ALTER TABLE T2 ADD FOREIGN KEY FF(A, B) REFERENCES T1(A, B) ON DELETE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1, 1); +insert into T2 values(1, 1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +DROP TABLE IF EXISTS T1,T2; +CREATE TABLE T1(A DECIMAL(20,5), B DECIMAL(20,5), UNIQUE KEY(A, B)); +CREATE TABLE T2(A DECIMAL(20,3), B DECIMAL(20,5)); +ALTER TABLE T2 ADD FOREIGN KEY FF(A, B) REFERENCES T1(A, B) ON DELETE SET NULL; +SET foreign_key_checks = 0; +insert into T1 values(1, 1); +insert into T2 values(1, 1); +SET foreign_key_checks = 1; +DELETE FROM T1 WHERE A = 1; +SELECT * FROM T1; +SELECT * FROM T2; +DROP TABLE T1,T2; + +drop table if exists t1, t2; +create table t1(id FLOAT(11,5) primary key); +create table t2(id FLOAT(11,2) primary key, CONSTRAINT fk_1 FOREIGN KEY (id) REFERENCES t1 (id) on delete set default on update cascade); +insert into t1 values(1); +insert into t2 values(1); +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists f1,c1; +create table f1(a1 char(1) primary key DEFAULT ''); +create table c1(a1 char(1) DEFAULT '', CONSTRAINT fk_1 FOREIGN KEY (a1) REFERENCES f1 (a1) on update cascade); +insert into f1(a1) values(1); +insert into c1(a1) values(1); +update f1 set a1 = '' where a1 = 1; +select * from f1; +select * from c1; +drop table f1,c1; + +drop table if exists f1,c1; +create table f1(a1 varchar(20) primary key); +create table c1(a1 varchar(20), CONSTRAINT fk_1 FOREIGN KEY (a1) REFERENCES f1 (a1) on update cascade); +insert into f1(a1) values('sssa'); +insert into c1(a1) values('sssa'); +update f1 set a1 = 'cddddsd'; +select * from f1; +select * from c1; +update f1 set a1 = 'daaass'; +select * from f1; +select * from c1; +drop table f1,c1; + +drop table if exists t1,t2; +create table t1(a int NOT NULL AUTO_INCREMENT primary key, b bit(7) ,unique(b)); +create table t2(c varchar(20), d bit(5) not null, foreign key(d) references t1(b) on update cascade); +insert into t1(b) values(b'1'); +insert into t2 values('jack', b'1'); +update t1 set b = b'1111111'; +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists t1,t2; +create table t1(a int NOT NULL AUTO_INCREMENT primary key, b bit(9) ,unique(b)); +create table t2(c varchar(20), d bit(8) not null, foreign key(d) references t1(b) on update cascade); +insert into t1(b) values(b'1'); +--error 1452 +insert into t2 values('jack', b'1'); +drop table t1,t2; + +drop table if exists t1,t2; +create table t1(a int,b enum('1',''),unique(b)); +create table t2(c varchar(20), d enum('1','a','*') not null default ('*'), foreign key(d) references t1(b) on update cascade); +insert into t1 values(1,'1'); +insert into t2 values('bob','1'); +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists T1,T2; +create table T1(id decimal(20, 5) primary key); +create table T2(id decimal(20, 3), constraint FK_ID foreign key (id) references T1(id)); +insert into T1 values(7); +--error 1452 +insert into T2 values(7); +drop table T1,T2; + +drop table if exists T1,T2; +create table T1(id decimal(20, 5) unique key); +create table T2(id decimal(20, 3), constraint FK_ID foreign key (id) references T1(id)); +insert into T2 values(NULL); +select * from T2; +drop table T1,T2; + +drop table if exists T1,T2; +set foreign_key_checks = 0; +create table T1(id decimal(20, 5) primary key); +create table T2(id decimal(20, 3), constraint FK_ID foreign key (id) references T1(id)); +insert into T1 values(7); +insert into T2 values(7); +select * from T1; +select * from T2; +set foreign_key_checks = 1; +drop table T1,T2; + +drop table if exists t1,t2; +CREATE TABLE t1 ( +datetime DATETIME(6), +UNIQUE KEY datetime (datetime) +); +CREATE TABLE t2 ( +datetime DATETIME(5), +CONSTRAINT fk_datetime FOREIGN KEY (datetime) REFERENCES t1(datetime) +); +insert into t1 values('2018-01-18 00:00:00'); +insert into t2 values('2018-01-18 00:00:00'); +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists t1,t2; +CREATE TABLE t1 ( +datetime DATETIME(5), +UNIQUE KEY datetime (datetime) +); +CREATE TABLE t2 ( +datetime DATETIME(4), +CONSTRAINT fk_datetime FOREIGN KEY (datetime) REFERENCES t1(datetime) +); +insert into t1 values('2018-01-18 00:00:00'); +--error 1452 +insert into t2 values('2018-01-18 00:00:00'); +drop table t1,t2; + +drop table if exists t1,t2; +CREATE TABLE t1 ( +timestamp TIMESTAMP(6), +UNIQUE KEY timestamp (timestamp) +); +CREATE TABLE t2 ( +timestamp TIMESTAMP(5), +CONSTRAINT fk_timestamp FOREIGN KEY (timestamp) REFERENCES t1(timestamp) +); +insert into t1 values('2018-01-18 00:00:00'); +insert into t2 values('2018-01-18 00:00:00'); +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists t1,t2; +CREATE TABLE t1 ( +timestamp TIMESTAMP(5), +UNIQUE KEY timestamp (timestamp) +); +CREATE TABLE t2 ( +timestamp TIMESTAMP(4), +CONSTRAINT fk_timestamp FOREIGN KEY (timestamp) REFERENCES t1(timestamp) +); +insert into t1 values('2018-01-18 00:00:00'); +--error 1452 +insert into t2 values('2018-01-18 00:00:00'); +drop table t1,t2; + +drop table if exists t1,t2; +create table t1(a int NOT NULL AUTO_INCREMENT primary key, b decimal(65,30),unique(b)); +create table t2(c varchar(20), d decimal(65,30) not null default 1, foreign key(d) references t1(b) on update cascade); +insert into t1 values(3,2.2250738585072014E-308); +insert into t2 values('bob',2.2250738585072014E-308); +insert into t2 values('grace',-2.2250738585072014E-308); +update t1 set a = 33, b = 999.901 where b<=0; +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists char4, char5; +create table char4(c2 char(255) unique key); +create table char5(c2 char(254) unique key, CONSTRAINT fk_char5 FOREIGN KEY (c2) REFERENCES char4 (c2) on update cascade); +insert into char4 values('a'); +insert into char5 values('a'); +--error 1451 +update char4 set c2='bbbb'; +drop table char4, char5; + +drop table if exists char4, char5; +create table char4(c2 varchar(255) unique key); +create table char5(c2 varchar(5) unique key, CONSTRAINT fk_char5 FOREIGN KEY (c2) REFERENCES char4 (c2) on update cascade); +insert into char4 values('a'); +insert into char5 values('a'); +update char4 set c2='bbbbb'; +select * from char4; +select * from char5; +--error 1451 +update char4 set c2='bbbbbb'; +select * from char4; +select * from char5; +update char4 set c2='我的啊你不'; +select * from char4; +select * from char5; +--error 1451 +update char4 set c2='我的啊你不要'; +select * from char4; +select * from char5; +update char4 set c2='我的a你b'; +select * from char4; +select * from char5; +drop table char4, char5; + +drop table if exists t1,t2; +create table t1(a varchar(20) unique key); +create table t2(a varchar(20), CONSTRAINT fk_1 FOREIGN KEY (a) REFERENCES t1 (a) on update cascade); +insert into t1 values('a'); +insert into t2 values('a'); +update t1 set a = null; +select * from t1; +select * from t2; +drop table t1,t2; + +drop table if exists t1,t2,c_t1; +create table t1(id varchar(255) primary key, i int AUTO_INCREMENT,unique key(i)); +create table t2(c1 varchar(255) unique key, i int AUTO_INCREMENT,unique key(i)); +create table c_t1(c1 varchar(255) unique key +,CONSTRAINT fk_t1 FOREIGN KEY (c1) REFERENCES t1 (id) on delete set default on update cascade +,CONSTRAINT fk_t2 FOREIGN KEY (c1) REFERENCES t2 (c1) on delete set default on update cascade); +insert into t1(id) values(''); +insert into t2(c1) values(''); +insert into c_t1(c1) values(''); +select * from t1; +select * from t2; +select * from c_t1; +select t1.i,t1.id,t2.c1 from t1,t2 where t1.i=t2.i and t1.i=1; +--error 1452 +update t1,t2 set t1.id='a',t2.c1='b' where t1.i=t2.i and t1.i=1; +select * from t1; +select * from t2; +select * from c_t1; +drop table t1,t2,c_t1; + +drop table if exists t1,t2,t3; +create table t1(a1 int, a2 int, a3 int, a4 int, a5 int, primary key(a3, a5)); +create table t2(b1 int, b2 int, b3 int, b4 int, b5 int, primary key(b2, b4)); +create table t3(c1 int, c2 int, c3 int, constraint fk_1 foreign key(c1, c2) references t1(a3, a5) on update cascade, constraint fk_2 foreign key(c2, c3) references t2(b2, b4) on update set null); +insert into t1 values(1,1,1,1,1); +insert into t2 values(1,1,1,1,1); +insert into t3 values(1,1,1); +--error 1452 +update t1 set a5 = 2, a1 = 4; +--error 1452 +update t1 set a3 = 2, a1 = 4; +select * from t1; +select * from t2; +select * from t3; +drop table t1,t2,t3; + +drop table if exists t1,t2,t3; +create table t1(a int primary key); +create table t2(a int primary key); +create table t3(a int, constraint fk_1 foreign key(a) references t1(a) on update cascade, constraint fk_2 foreign key(a) references t2(a) on update cascade); +insert into t1 values(1); +insert into t2 values(1); +insert into t3 values(1); +--error 1452 +update t1 set a = 2; +--error 1452 +update t2 set a = 2; +drop table t1,t2,t3; + +drop table if exists t1,t2,t3; +create table t1(a int primary key); +create table t2(a int primary key); +create table t3(a int, constraint fk_1 foreign key(a) references t1(a) on update cascade, constraint fk_2 foreign key(a) references t2(a) on delete cascade); +insert into t1 values(1); +insert into t2 values(1); +insert into t3 values(1); +--error 1452 +update t1 set a = 2; +delete from t2; +drop table t1,t2,t3; + +drop table if exists t1,t2,t3; +create table t1(a int primary key); +create table t2(a int primary key); +create table t3(a int, constraint fk_1 foreign key(a) references t1(a) on update cascade, constraint fk_2 foreign key(a) references t2(a) on delete set null); +insert into t1 values(1); +insert into t2 values(1); +insert into t3 values(1); +--error 1452 +update t1 set a = 2; +delete from t2; +drop table t1,t2,t3; + +drop table if exists t1,t2; +create table t1(a int, b int, primary key(a, b)); +create table t2(a int, b int, constraint fk_1 foreign key(a, b) references t1(a, b) on update cascade); +insert into t1 values(1, 1); +insert into t2 values(1, 1); +alter table t2 add constraint fk_2 foreign key(a, b) references t1(a, b) on delete set null; +--error 1451 +delete from t1; +--error 1452 +update t1 set a = 2, b = 2; +alter table t2 drop foreign key fk_1; +--error 1451 +update t1 set a = 3, b = 3; +delete from t1; +drop table t1,t2; + +DROP DATABASE CASCADE_TEST; diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_character_set.test b/mysql-test/suite/tianchi/t/ctc_ddl_character_set.test new file mode 100644 index 0000000..a53e274 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_character_set.test @@ -0,0 +1,74 @@ +#database的字符集、字符序,创建修改字符集 +CREATE DATABASE `CHAR_DB` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +use CHAR_DB; +SELECT @@character_set_database, @@collation_database; +create table DEMO (ID integer not null, NAME varchar(20)); +INSERT INTO DEMO values(1,'abc'); +INSERT INTO DEMO values(3,'Abc'); +#数据库字符集字符序为表的字符集字符序,此处utf8_general_ci会忽略大小写比较,所以下面查询将会查到两条记录 +select * from DEMO where NAME = 'aBc'; +#可以插入20个汉字 +INSERT INTO DEMO values(4,'数据库字符集字符序为表的字符集字符序汉字'); +#超过20个汉字超长 ERROR 1406 (22001): Data too long for column 'NAME' at row 1 +--error 1406 +INSERT INTO DEMO values(5,'数据库字符集字符序为表的字符集字符序汉字1'); +#修改数据库的字符集,不影响原有表的字符集 +ALTER DATABASE CHAR_DB DEFAULT CHARACTER SET ascii DEFAULT COLLATE ascii_bin; +INSERT INTO DEMO values(5,'张据库字符集字符序为表的字符集字符序汉字'); +#超过20个汉字超长 ERROR 1406 (22001): Data too long for column 'NAME' at row 1 +--error 1406 +INSERT INTO DEMO values(5,'张据库字符集字符序为表的字符集字符序汉字1'); +select * from DEMO; +#创建表的时候字符集已经制定为数据库的字符集,后续数据库的字符集修改,不会再影响表的新字段添加,除非表指定字符集 +ALTER TABLE DEMO ADD COLUMN NAME1 varchar(20); +INSERT INTO DEMO values(6,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字'); +--error 1406 +INSERT INTO DEMO values(7,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字1'); +ALTER TABLE DEMO ADD COLUMN NAME2 varchar(20) CHARACTER SET ascii COLLATE ascii_bin; +show create table DEMO; +--error 1406 +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','abcdeabcdeabcdeabcdef'); +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','abcdeabcdeabcdeabcde'); +--error 1366 +#ERROR 1366 (HY000): Incorrect string value: '\xE6\xB1\x89\xE5\xAD\x97' for column 'NAME2' at row 1 不支持插入中文 +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','汉字'); +ALTER TABLE DEMO DEFAULT CHARACTER SET ascii COLLATE ascii_bin; +show create table DEMO; +ALTER TABLE DEMO ADD COLUMN NAME3 varchar(20); +show create table DEMO; +--error 1366 +#ERROR 1366 (HY000): Incorrect string value: '\xE6\xB1\x89\xE5\xAD\x97' for column 'NAME3' at row 1 不支持插入中文 +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','abc', '汉字'); +--error 1406 +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','abc', 'abcdeabcdeabcdeabcdef'); +INSERT INTO DEMO values(8,'张据库字符集字符序为表的字符集字符序汉字','张据库字符集字符序为表的字符集字符序汉字','abc', 'abcdeabcdeabcdeabcde'); +select * from DEMO; +show create table DEMO; +drop table DEMO; +create table t1(c1 varchar(10) collate utf8mb4_general_ci); +insert into t1 values('aaa'),('aAA '),('AAA'),('aAA'),('AAA '),('BBB'),('bBb'),('Bbb'),('AAa'),('AaA'); +select c1 from t1; +create index idx1 on t1(c1); +select c1 from t1; +alter table t1 modify c1 varchar(10) collate utf8mb3_bin; +select c1 from t1; +alter table t1 modify c1 varchar(10) collate utf8mb4_general_ci; +select c1 from t1; +drop table t1; + +#测试COLLATE排序规则 +create table DEMO (ID integer not null, NAME varchar(20) character set utf8 collate utf8_bin); +INSERT INTO DEMO values(1,'abc'); +INSERT INTO DEMO values(3,'Abc'); +#此处字符集不忽略大小写,只能查出一条记录 +select * from DEMO where NAME = 'abc'; +#修改表的COLLATE,不会影响老列的排序规则 +ALTER TABLE DEMO DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +INSERT INTO DEMO values(4,'Abc'); +select * from DEMO where NAME = 'abc'; +ALTER TABLE DEMO ADD COLUMN NAME1 varchar(20); +INSERT INTO DEMO values(5,'1','abc'); +INSERT INTO DEMO values(6,'1','Abc'); +#新列会用表的新的COLLATE排序规则,此处会查出2条记录 +select * from DEMO where NAME1 = 'aBc'; +drop database CHAR_DB; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_create_table.test b/mysql-test/suite/tianchi/t/ctc_ddl_create_table.test new file mode 100644 index 0000000..7f52ded --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_create_table.test @@ -0,0 +1,1081 @@ +--disable_warnings +drop table if exists DEMO; +drop table if exists t1; +--enable_warnings +#特别注意,每个测试用例直接用2行空行隔开,中间不要有任何空行 + + +#创建表的相关测试 +#create a table. +create table DEMO (ID integer not null, NAME varchar(10), AGE integer, GRADE real) DEFAULT CHARSET=utf8; +desc DEMO; +show create table DEMO; +show index from DEMO; +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); +--error 1048 +#第一列不允许为空 +insert into DEMO values (null, 'ff', 36, 8.9); +--error 1406 +insert into DEMO values (12, 'abcdefghija', 36, 8.9); +insert into DEMO values (12, 'abcdefghij', 36, 8.9); +insert into DEMO values (12, 'abcdefghi中', 36, 8.9); +--error 1406 +insert into DEMO values (12, 'abcdefghi中国', 36, 8.9); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for primary key test (创建table过程中直接创建主键) +create table DEMO (ID integer PRIMARY KEY, NAME varchar(19), AGE integer, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +--error 1364 +#ERROR 1364 (HY000): Field 'ID' doesn't have a default value +insert into DEMO (NAME,AGE,GRADE) values ('MIKE', 55, 99.92); +insert into DEMO values (2, 'LIOR', 35, 6.9); +alter table DEMO drop primary key; +#删除主键后,原来重复的数据可以插入 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for primary key test (复合主键测试,组合索引, 包含删除主键,primary key方式创建主键) +#复合主键有两种测试语句 +#create table 表名(列名1 数据类型, 列名2 数据类型, constraint 主键约束的名字 primary key(列名1,列名2)); +#create table 表名(列名1 数据类型, 列名2 数据类型, primary key(列名1,列名2)); +create table DEMO (ID integer, NAME varchar(19), AGE integer, GRADE real, PRIMARY KEY (ID, NAME)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +--error 1062 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); #因为ID和NAME完全相同,所以无法插入 +insert into DEMO values (888889, 'zhangdi', 11, 99.8); +insert into DEMO values (888888, 'zhangdi1', 35, 10000.8); +insert into DEMO values (122, 'LIOR', 22, 77.8); +insert into DEMO values (31434, 'ALEX', 43, 100.8); +alter table DEMO drop primary key; +#删除主键后,原来重复的数据可以插入 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for primary key test (复合主键测试,组合索引, 包含删除主键,constraint方式创建主键,通过drop primary key方式删除主键) +#复合主键有两种测试语句 +#create table 表名(列名1 数据类型, 列名2 数据类型, constraint 主键约束的名字 primary key(列名1,列名2)); +#create table 表名(列名1 数据类型, 列名2 数据类型, primary key(列名1,列名2)); +create table DEMO (ID integer, NAME varchar(19), AGE integer, GRADE real, CONSTRAINT pk_demo PRIMARY KEY (ID, NAME)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +--error 1062 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); #因为ID和NAME完全相同,所以无法插入 +insert into DEMO values (888889, 'zhangdi', 11, 99.8); +insert into DEMO values (888888, 'zhangdi1', 35, 10000.8); +insert into DEMO values (122, 'LIOR', 22, 77.8); +insert into DEMO values (31434, 'ALEX', 43, 100.8); +alter table DEMO drop primary key; +#删除主键后,原来重复的数据可以插入 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for primary key test (复合主键测试,组合索引, 包含删除主键,constraint方式创建主键,通过drop primary key方式删除主键) +#复合主键有两种测试语句 +#create table 表名(列名1 数据类型, 列名2 数据类型, constraint 主键约束的名字 primary key(列名1,列名2)); +#create table 表名(列名1 数据类型, 列名2 数据类型, primary key(列名1,列名2)); +create table DEMO (ID integer, NAME varchar(19), AGE integer, GRADE real, CONSTRAINT pk_demo PRIMARY KEY (ID, NAME)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +--error 1062 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); #因为ID和NAME完全相同,所以无法插入 +insert into DEMO values (888889, 'zhangdi', 11, 99.8); +insert into DEMO values (888888, 'zhangdi1', 35, 10000.8); +insert into DEMO values (122, 'LIOR', 22, 77.8); +insert into DEMO values (31434, 'ALEX', 43, 100.8); +--error 3940 +#ERROR 3940 (HY000): Constraint 'pk_demo' does not exist. +#无法通过constraint的方式删除主键 +alter table DEMO drop constraint pk_demo; +alter table DEMO drop primary key; +#删除主键后,原来重复的数据可以插入 +insert into DEMO values (888888, 'zhangdi', 35, 10000.8); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,单列,unique or unique key) +create table DEMO (ID integer UNIQUE KEY, NAME varchar(19), AGE integer, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +#只输入unique 不写key,可能会影响之后删除列的逻辑 +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#null不认为是违反uinque约束 +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (2, 'MIKE', 55, 99.92); +ALTER TABLE DEMO DROP INDEX ID; +--error 1091 +ALTER TABLE DEMO DROP INDEX ID; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,单列,unique or unique key) +create table DEMO (ID integer UNIQUE, NAME varchar(19), AGE integer, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +#只输入unique 不写key,不影响之后删除列的逻辑 +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#null不认为是违反uinque约束 +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (null,'DAN', 45, 33.33); +insert into DEMO values (2, 'MIKE', 55, 99.92); +ALTER TABLE DEMO DROP INDEX ID; +--error 1091 +ALTER TABLE DEMO DROP INDEX ID; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,单列,通过CONSTRAINT添加) +create table DEMO (ID integer, NAME varchar(10), AGE integer, GRADE real, CONSTRAINT uk_demo UNIQUE KEY (ID)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +insert into DEMO values (2, 'MIKE', 55, 99.92); +insert into DEMO values (3, 'LIOR', 35, 6.9); +#null不认为是违反uinque约束 +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +#通过CONSTRAINT添加的unique约束,索引名字为约束名字,不能通过列名来删除了 +--error 1091 +ALTER TABLE DEMO DROP INDEX ID; +ALTER TABLE DEMO DROP INDEX uk_demo; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,单列,通过CONSTRAINT添加) +create table DEMO (ID integer, NAME varchar(10), AGE integer, GRADE real, CONSTRAINT uk_demo UNIQUE KEY (ID)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +insert into DEMO values (2, 'MIKE', 55, 99.92); +insert into DEMO values (3, 'LIOR', 35, 6.9); +#null不认为是违反uinque约束 +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +#通过CONSTRAINT添加的unique约束,索引名字为约束名字,不能通过列名来删除了 +--error 1091 +ALTER TABLE DEMO DROP INDEX ID; +alter table DEMO drop constraint uk_demo; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,单列,通过CONSTRAINT添加,约束名字可以就是列名) +create table DEMO (ID integer, NAME varchar(10), AGE integer, GRADE real, CONSTRAINT ID UNIQUE KEY (ID)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'MIKE', 55, 99.92); +insert into DEMO values (2, 'MIKE', 55, 99.92); +insert into DEMO values (3, 'LIOR', 35, 6.9); +#null不认为是违反uinque约束 +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +#下面这两种删除约束的方式都可以 +ALTER TABLE DEMO DROP INDEX ID; +#alter table DEMO drop constraint ID; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for unique key test (创建table过程中直接创建唯一键,多列,unique or unique key) +create table DEMO (ID integer, NAME varchar(10), AGE integer, GRADE real, CONSTRAINT uk_demo UNIQUE KEY (ID, NAME)); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO values (1, 'LIOR', 35, 6.9); +--error 1062 +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (1, 'MIKE', 55, 99.92); +insert into DEMO values (null, 'LIOR', 35, 6.9); +insert into DEMO values (null, 'LIOR', 35, 6.9); +#CONSTRAINT添加的复合uinque索引,不能通过下面单一索引删除 +--error 1091 +ALTER TABLE DEMO DROP INDEX ID; +--error 1091 +ALTER TABLE DEMO DROP INDEX NAME; +alter table DEMO drop constraint uk_demo; +#删除了unique索引以后,可以插入重复数据 +insert into DEMO values (1, 'MIKE', 55, 99.92); +#执行 select +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for auto_increment test (创建table过程中直接添加自增) +#PRIMARY KEY & AUTO_INCREMENT +create table DEMO (ID integer PRIMARY KEY auto_increment ,AGE integer, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO (AGE, GRADE) values (20, 5.5); +insert into DEMO (AGE, GRADE) values (30,6.5); +insert into DEMO (AGE, GRADE) values (40,7.5); +insert into DEMO values (null,40,7.5); +insert into DEMO values (null,40,7.5); +#主键重复 +--error 1062 +insert into DEMO values (4,40,7.5); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#UNIQUE KEY & AUTO_INCREMENT +create table DEMO (ID integer UNIQUE auto_increment,AGE integer, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +insert into DEMO (AGE, GRADE) values (20, 5.5); +insert into DEMO (AGE, GRADE) values (30,6.5); +insert into DEMO (AGE, GRADE) values (40,7.5); +insert into DEMO values (null,40,7.5); +insert into DEMO values (null,40,7.5); +--error 1062 +insert into DEMO values (4,40,7.5); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for default value & default null test (创建table过程中添加默认值和添加默认为空) +create table DEMO (ID integer DEFAULT NULL, NAME varchar(19), AGE integer DEFAULT 100, GRADE real); +desc DEMO; +show create table DEMO; +show index from DEMO; +INSERT INTO DEMO(NAME,GRADE) VALUES('test1',10); +INSERT INTO DEMO(NAME,GRADE) VALUES('test2',20); +INSERT INTO DEMO(NAME,GRADE) VALUES('test3',30); +INSERT INTO DEMO(NAME,GRADE) VALUES('test4',40); +INSERT INTO DEMO VALUES(10,'test4',40,200); +INSERT INTO DEMO VALUES(101,'test4',40,201); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +DROP TABLE IF EXISTS DEMO; +--enable_warnings +CREATE TABLE DEMO(c1 CHAR(10) NULL DEFAULT 'x'); +insert into DEMO values(null); +insert into DEMO values(''); +insert into DEMO values('x'); +insert into DEMO values('acbdfd'); +--error 1406 +insert into DEMO values('abdcdedcddfdfdfdfdffddfd'); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +SHOW TABLES; +##--replace_result $ENGINE ENGINE " PAGE_CHECKSUM=0" "" +SHOW CREATE TABLE DEMO; DROP TABLE DEMO; SHOW TABLES; + +DROP TABLE IF EXISTS DEMO; +--enable_warnings +CREATE TABLE DEMO(ID integer, c1 CHAR(10) NULL DEFAULT 'x'); +insert into DEMO values(1,null); +insert into DEMO values(2,''); +insert into DEMO values(3,'x'); +insert into DEMO values(4, 'acbdfd'); +--error 1406 +insert into DEMO values(5,'abdcdedcddfdfdfdfdffddfd'); +insert into DEMO(ID) values(6); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +SHOW TABLES; +#--replace_result $ENGINE ENGINE " PAGE_CHECKSUM=0" "" +SHOW CREATE TABLE DEMO; DROP TABLE DEMO; SHOW TABLES; + + +DROP TABLE IF EXISTS DEMO; +--enable_warnings +CREATE TABLE DEMO(c1 CHAR(10) NULL DEFAULT 'x', c2 int); +insert into DEMO (c2) values(2); +insert into DEMO values('12',3); +insert into DEMO values('',4); +insert into DEMO values(null,5); +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +SHOW TABLES; +#--replace_result $ENGINE ENGINE " PAGE_CHECKSUM=0" "" +SHOW CREATE TABLE DEMO; DROP TABLE DEMO; SHOW TABLES; + + +#create table for decimal (precision, scale) test (c) (创建table过程中添加decimal的精度和范围) +create table DEMO (a decimal(3,1)); +insert into DEMO values (1.3); +#ERROR 1264 (22003): Out of range value for column 'a' at row 1 +--error 1264 +insert into DEMO values (99.99); +insert into DEMO values (99.9); +insert into DEMO values (-99.9); +--error 1264 +insert into DEMO values (-99.99); +--error 1264 +insert into DEMO values (-99.95); +insert into DEMO values (-99.949); +insert into DEMO values (-99.94); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for add comment test (创建table过程中添加备注) +create table DEMO (ID integer comment 'user_id', NAME varchar(19) comment 'name', AGE integer DEFAULT 100 comment 'student_age', GRADE real comment 'student_grade'); +#select COLUMN_NAME 字段名, column_comment 字段说明, column_type 字段类型,column_key 约束 from information_schema.columns where table_schema = 'demo_db' and table_name = 'DEMO'; +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for collate (创建table过程中字符序问题,后面还需要添加排序相关的测试) +create table DEMO (NAME varchar(5) COLLATE utf8_unicode_ci); +show full columns from DEMO; +insert into DEMO values ('LIOR'); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for current timestamp 时间戳更新test +create table DEMO (id int NOT NULL AUTO_INCREMENT, name varchar(20) DEFAULT NULL, create_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, last_modify_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id)); +insert into DEMO (name) VALUES ('aa'),('bb'),('cc'); +UPDATE DEMO SET name = 'ab' WHERE id = 1; +#执行 select,这里不进行select了,避免时间戳差异导致数据结果有差异 +#SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for truncate table test(清空表) +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); +DESC DEMO; +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); +--error 1048 +insert into DEMO values (null, 'ff', 36, 8.9); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#清空表 +truncate DEMO; +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for truncate table test(清空表,带自增的逻辑时,自增值应该被重置) +create table DEMO (ID integer PRIMARY KEY auto_increment , NAME varchar(19), AGE integer, GRADE real); +DESC DEMO; +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +--error 1062 +#ERROR 1062 (23000): Duplicate entry '1' for key 'DEMO.PRIMARY' +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); +insert into DEMO values (null, 'ff', 36, 8.9); +#执行 select +SELECT * FROM DEMO; +desc DEMO; +show create table DEMO; +show index from DEMO; +#清空表 +truncate DEMO; +#执行 select +SELECT * FROM DEMO; +#从1开始重新自增 +insert into DEMO values (null, 'ff', 36, 8.9); +insert into DEMO values (null, 'ff', 36, 8.9); +insert into DEMO values (null, 'ff', 36, 8.9); +insert into DEMO values (null, 'ff', 36, 8.9); +insert into DEMO values (null, 'ff', 36, 8.9); +desc DEMO; +show create table DEMO; +show index from DEMO; +#drop Table +drop table DEMO; + + +#create table for check constraint test 创表时添加check约束 +create table DEMO (ID integer, NAME varchar(19), AGE integer, GRADE real, SEX char(1), check (5 100; +SELECT * FROM Dept WHERE NAME is NULL; + +drop table Dept; +drop PROCEDURE insert_dept; +drop FUNCTION rand_num_age; +drop FUNCTION rand_string; + diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_generated_columns.test b/mysql-test/suite/tianchi/t/ctc_ddl_generated_columns.test new file mode 100644 index 0000000..73a10bc --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_generated_columns.test @@ -0,0 +1,96 @@ +#测试生成列和虚拟列 +--error 3655 +CREATE TABLE triangle ( + sidea DOUBLE, + sideb DOUBLE, + sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) STORED +); +CREATE TABLE triangle1 ( + sidea DOUBLE, + sideb DOUBLE, + sidec DOUBLE AS (SQRT(sidea * sidea + sideb * sideb)) +); +INSERT INTO triangle1(sidea, sideb) VALUES(2,2),(4,4),(8,8); +desc triangle1; +select * from triangle1; +show create table triangle1; +drop table triangle1; + +DROP TABLE IF EXISTS t_8114; +CREATE TABLE t_8114 (Column_0 int, Column_1 CHAR(5) GENERATED ALWAYS AS (PI()+5), Column_2 CHAR(5), Column_3 CHAR(5) GENERATED ALWAYS AS (PI()+5), Column_4 int); +insert into t_8114 values(1, default, 'aa', default, 2); +insert into t_8114 values(3, default, 'bb', default, 4); +insert into t_8114 values(5, default, 'cc', default, 6); +insert into t_8114 values(7, default, 'dd', default, 8); +insert into t_8114 values(9, default, 'dd', default, 10); +select * from t_8114; +ALTER TABLE t_8114 DROP COLUMN Column_0; +select * from t_8114; +ALTER TABLE t_8114 DROP COLUMN Column_1; +select * from t_8114; +ALTER TABLE t_8114 ADD COLUMN Column_5 INT; +ALTER TABLE t_8114 ADD COLUMN Column_6 INT; +select * from t_8114; +update t_8114 set Column_5 = 6 where Column_4 = 2; +select * from t_8114; +insert into t_8114 values('ee', default, 12, 14, 16); +insert into t_8114 values('ff', default, 18, 20, 22); +select * from t_8114; +update t_8114 set Column_5 = 8, Column_6 = 9 where Column_4 = 2; +select * from t_8114; +ALTER TABLE t_8114 DROP COLUMN Column_3; +select * from t_8114; +drop table t_8114; + +CREATE TABLE t1 (a6 VARCHAR(32)); +INSERT INTO t1 VALUES ('00:00:00.000000'); +INSERT INTO t1 VALUES ('00:00:00.000001'); +INSERT INTO t1 VALUES ('00:00:00.000002'); +INSERT INTO t1 VALUES ('00:00:00.000003'); +INSERT INTO t1 VALUES ('00:00:00.000004'); +INSERT INTO t1 VALUES ('00:00:00.000005'); +INSERT INTO t1 VALUES('00:00:00.000006'); +ALTER TABLE t1 ADD a0 VARCHAR(32), ADD a1 VARCHAR(32), ADD a2 VARCHAR(32), ADD a3 VARCHAR(32), ADD a4 VARCHAR(32), ADD a5 VARCHAR(32), ADD t0 TIME(0), ADD t1 TIME(1), ADD t2 TIME(2), ADD t3 TIME(3), ADD t4 TIME(4), ADD t5 TIME(5), ADD t6 TIME(6); +select * from t1; +UPDATE t1 SET a0=LEFT(a6, LENGTH(a6) - 6); +select * from t1; +drop table t1; + +CREATE TABLE t1 (a0 VARCHAR(32),a1 VARCHAR(32),a2 VARCHAR(32),a3 VARCHAR(32),a4 VARCHAR(32),a5 VARCHAR(32),a6 VARCHAR(32), t0 TIME(0),t1 TIME(1), t2 TIME(2)); +insert into t1 values('00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001','00:00:00.000001'); +select * from t1; +alter table t1 ADD t3 TIME(3), ADD t4 TIME(4), ADD t5 TIME(5), ADD t6 TIME(6); +select * from t1; +insert into t1 values('00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002','00:00:00.000002'); +select * from t1; +alter table t1 drop t6; +select * from t1; +alter table t1 drop a2, drop a3; +select * from t1; +insert into t1 values('00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003','00:00:00.000003'); +alter table t1 add t10 TIME(6), add t11 TIME(6), add t12 TIME(6); +select * from t1; +alter table t1 drop t0, drop t1, drop t2; +select * from t1; +drop table t1; + +create table t1( +c1 int UNSIGNED not null, +c2 int, +c3 int, +c4 int, +c5 int, +c6 int, +c7 int, +c8 int, +c9 int, +c10 varchar(20), +c11 varchar(20), +c12 varchar(20), +gcol1 INTEGER GENERATED ALWAYS AS (c4 + c5) VIRTUAL +); +insert into t1 values(1,2,3,4,5,6,7,8,9,'aaa','bbb','ccc',default); +select * from t1; +update t1 set c1 = 11, c2 = 12, c3 = 13, c4 = 14, c5 = 15, c6 = 16, c7 = 17, c8 = 18, c9 = 19, c10 = 'ddd', c11 = 'eee', c12 = 'fff', gcol1 = default where c1 = 1; +select * from t1; +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_index.test b/mysql-test/suite/tianchi/t/ctc_ddl_index.test new file mode 100644 index 0000000..d47c108 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_index.test @@ -0,0 +1,150 @@ +--disable_warnings +drop table if exists DEMO; +--enable_warnings + +# create a table. +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); + +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); + +#select data. +SELECT * FROM DEMO; + +# create index 创建普通 +create index idx_id ON DEMO (ID); +# 修改index名字 +ALTER TABLE DEMO RENAME INDEX idx_id TO idx_id1; +# 删除索引 +DROP INDEX idx_id1 ON DEMO; +# 重新创建普通索引 +create index idx_id1 ON DEMO (ID); +select * from DEMO where ID = 1; +select * from DEMO where ID <= 16; +select * from DEMO where ID < 16; +select * from DEMO where ID between 4 and 32; +select * from DEMO where ID >= 32; +select * from DEMO where ID > 32; +select * from DEMO where ID in (16,32); +select * from DEMO where ID like '1%'; +select * from DEMO where ID = 1 order by ID; +select * from DEMO where ID = 1 order by ID desc; +select * from DEMO where ID <= 16 order by ID; +select * from DEMO where ID < 16 order by ID desc; +select * from DEMO where ID between 4 and 32 order by ID; +select * from DEMO where ID between 4 and 32 order by ID desc; +select * from DEMO where ID >= 32 order by ID; +select * from DEMO where ID > 32 order by ID desc; +select * from DEMO where ID in (16,32) order by ID; +select * from DEMO where ID in (16,32) order by ID desc; +select * from DEMO where ID like '1%' order by ID; +select * from DEMO where ID like '1%' order by ID desc; + +#create secnodary index 在age上创建索引 +ALTER TABLE DEMO ADD INDEX idx_age (AGE); +select * from DEMO where AGE = 35; +select * from DEMO where ID <= 100; +select * from DEMO where ID < 100; +select * from DEMO where ID between 35 and 50; + +# drop index 删除id上创建的索引 +#drop index +DROP INDEX idx_id1 ON DEMO; +select * from DEMO where ID = 1; +select * from DEMO where ID <= 16; +select * from DEMO where ID < 16; +select * from DEMO where ID between 4 and 32; +select * from DEMO where ID >= 32; +select * from DEMO where ID > 32; +select * from DEMO where ID in (16,32); +select * from DEMO where ID like '1%'; +select * from DEMO where ID = 1 order by ID; +select * from DEMO where ID = 1 order by ID desc; +select * from DEMO where ID <= 16 order by ID; +select * from DEMO where ID < 16 order by ID desc; +select * from DEMO where ID between 4 and 32 order by ID; +select * from DEMO where ID between 4 and 32 order by ID desc; +select * from DEMO where ID >= 32 order by ID; +select * from DEMO where ID > 32 order by ID desc; +select * from DEMO where ID in (16,32) order by ID; +select * from DEMO where ID in (16,32) order by ID desc; +select * from DEMO where ID like '1%' order by ID; +select * from DEMO where ID like '1%' order by ID desc; + +#drop second index 删除age上的索引 +DROP INDEX idx_age ON DEMO; +desc DEMO; + +# select after drop index +select * from DEMO where AGE = 35; +select * from DEMO where ID <= 100; +select * from DEMO where ID < 100; +select * from DEMO where ID between 35 and 50; + +#drop table +drop table DEMO; + +CREATE TABLE t1 ( + f1 int(11) DEFAULT '0' NOT NULL, + f2 varchar(16) DEFAULT '' NOT NULL, + f5 text, + KEY index_name (f1,f2,f5(16)) +); +show create table t1; +INSERT INTO t1 VALUES (0,'traktor','1111111111111'); +INSERT INTO t1 VALUES (1,'traktor','1111111111111111111111111'); +INSERT INTO t1 VALUES (3,'traktor',repeat('a',8000)); +select count(*) from t1 where f2='traktor'; +select length(f5) from t1 where f2='traktor'; +drop table t1; + +CREATE TABLE t1 ( + f1 int(11) DEFAULT '0' NOT NULL, + f2 varchar(16) DEFAULT '' NOT NULL, + f5 blob, + KEY index_name (f1,f2,f5(16)) +); +show create table t1; +INSERT INTO t1 VALUES (0,'traktor','1111111111111'); +INSERT INTO t1 VALUES (1,'traktor','1111111111111111111111111'); +INSERT INTO t1 VALUES (3,'traktor',repeat('a',8000)); +select count(*) from t1 where f2='traktor'; +select length(f5) from t1 where f2='traktor'; +drop table t1; + +CREATE TABLE t1 ( + f1 int(11) DEFAULT '0' NOT NULL, + f2 varchar(16) DEFAULT '' NOT NULL, + f5 varchar(9000), + KEY index_name (f1,f2,f5(16)) +); +show create table t1; +INSERT INTO t1 VALUES (0,'traktor','1111111111111'); +INSERT INTO t1 VALUES (1,'traktor','1111111111111111111111111'); +INSERT INTO t1 VALUES (3,'traktor',repeat('a',8000)); +select count(*) from t1 where f2='traktor'; +select length(f5) from t1 where f2='traktor'; +drop table t1; + +create table t1 (t blob, key(t(10))); +insert into t1 values('a'); +select count(*) from t1 where t like 'a%'; +drop table t1; + +create table t1 (f1 binary(5)) engine=CTC; +insert into t1 values ('w'), ('w'); +--error ER_DUP_ENTRY +create unique index index_t1 on t1(f1(4)); +drop table t1; + +create table t1 (v varchar(10), t varchar(50), key(t(5))); +insert into t1 values('a','a'); +select count(*) from t1 where t like 'a%'; +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_limit.test b/mysql-test/suite/tianchi/t/ctc_ddl_limit.test new file mode 100644 index 0000000..bad72f1 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_limit.test @@ -0,0 +1,20 @@ +#ddl的sql语句长度不允许超过64kb +set default_storage_engine=CTC; +# 创建并切换数据库 +create database demo_db_tmp; +use demo_db_tmp; +--error ER_DISALLOWED_OPERATION +#ERROR ER_DISALLOWED_OPERATION (HY000): `create table DEMO (ID1 integer comment '1', ID2 integer comment '12323431323232222222222222222222...` Is Large Than 30720 +create table DEMO (ID1 integer comment '1', ID2 integer comment '1132343132132222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333332323333333333333333333333333333333333333333333333223322323232323232323232323232323232323232323232323232323232323232', ID3 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID4 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID5 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID6 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID7 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID8 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID9 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID10 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID11 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID12 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID13 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID14 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID15 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID16 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID17 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID18 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID19 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID20 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID21 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID22 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID23 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID24 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID25 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID26 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID27 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID28 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID29 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID30 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323',ID31 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID32 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID33 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID34 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID35 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID36 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID37 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID38 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID39 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID40 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID41 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID42 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID43 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID44 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID45 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID46 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID47 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID48 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID49 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID50 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID51 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID52 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfff111'); +create table DEMO (ID1 integer comment '1', ID2 integer comment '1132343132132222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222233333333333333333333333333333333333333333333333333333333333333333333333333333333333332323333333333333333333333333333333333333333333333223322323232323232323232323232323232323232323232323232323232323232', ID3 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID4 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID5 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID6 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID7 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID8 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID9 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID10 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID11 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID12 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID13 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID14 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID15 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID16 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID17 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID18 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID19 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID20 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID21 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID22 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID23 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID24 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID25 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID26 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID27 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID28 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID29 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323', ID30 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff232323232323232323232323',ID31 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID32 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID33 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID34 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID35 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID36 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID37 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID38 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID39 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID40 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID41 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID42 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID43 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID44 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID45 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID46 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID47 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID48 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID49 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID50 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID51 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfffffffffffffffffffffffffffffff23232323232323232323232312',ID52 integer comment '1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddffffffffffffffffffffffffffffffffffffffffffffff1sddfff11'); +--error 1136 +#ERROR 1136 (21S01): Column count doesn't match value count at row 1 +insert INTO DEMO values(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21); +insert INTO DEMO values(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); +select * from DEMO; +drop table DEMO; +show tables; +drop database demo_db_tmp; + + + diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_max_reclength.test b/mysql-test/suite/tianchi/t/ctc_ddl_max_reclength.test new file mode 100644 index 0000000..2a6107f --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_max_reclength.test @@ -0,0 +1,54 @@ +DELIMITER |; +CREATE PROCEDURE create_table_columns_char(table_name varchar(50), columns int) +BEGIN + DECLARE i INT DEFAULT 1; + SET @sql_text = CONCAT('create TABLE ', table_name, ' ('); + while (i < columns) do + SET @sql_text = CONCAT(@sql_text, CONCAT('col_', i), ' char(255),'); + set i = i + 1; + end while; + SET @sql_text = CONCAT(@sql_text, CONCAT('col_', i), ' char(255)) CHARSET=ASCII;'); + #insert into DEMO values(@sql_text); + PREPARE stmt FROM @sql_text; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; +END| +create function rand_string(n int) returns varchar(255) +begin + declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; + declare return_str varchar(255) default ''; + declare i int default 0; + while i 100 THEN + SET new.AGE = 100; + END IF; + INSERT INTO DEMO_TRIGGER_LOG VALUES('update', NEW.NAME); +END| + +create TRIGGER TRIGGER_TSE3 AFTER DELETE ON DEMO FOR EACH ROW +BEGIN + IF old.AGE > 0 THEN + INSERT INTO DEMO_TRIGGER_LOG VALUES('delete', old.NAME); + END IF; +END| +DELIMITER ;| +--replace_column 6 # +SHOW TRIGGERS; + +# insert some data to table. +insert into DEMO values (1, 'LIOR', -1, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); + +select * from DEMO; +select * from DEMO_TRIGGER_LOG; + +UPDATE DEMO SET AGE=200 where ID=4; +UPDATE DEMO SET AGE=-50 where ID=8; + +select * from DEMO; +select * from DEMO_TRIGGER_LOG; + +DELETE FROM DEMO WHERE ID=1; +DELETE FROM DEMO WHERE ID=16; + +select * from DEMO; +select * from DEMO_TRIGGER_LOG; +--replace_column 6 # +SHOW TRIGGERS; +--error 1360 +DROP TRIGGER TRIGGER_TSE; + +DROP TRIGGER IF EXISTS TRIGGER_TSE; +DROP TRIGGER IF EXISTS TRIGGER_TSE1; +DROP TRIGGER IF EXISTS TRIGGER_TSE2; +DROP TRIGGER IF EXISTS TRIGGER_TSE3; +--replace_column 6 # +SHOW TRIGGERS; + +drop table DEMO; +drop table DEMO_TRIGGER_LOG; + diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_unsupport_command.test b/mysql-test/suite/tianchi/t/ctc_ddl_unsupport_command.test new file mode 100644 index 0000000..7ffd2aa --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_unsupport_command.test @@ -0,0 +1,185 @@ +#ddl不支持的语句类型测试,需要执行返回错误 +#ddl不支持event相关操作 +--error 3655 +CREATE EVENT e_totals ON SCHEDULE AT '2006-02-10 23:59:00' DO INSERT INTO test.totals VALUES (NOW()); +--error 3655 +ALTER EVENT no_such_event ON SCHEDULE EVERY '2:3' DAY_HOUR; +--error 3655 +DROP EVENT e_totals; + + +#ddl不支持资源组相关操作 +--error 3655 +CREATE RESOURCE GROUP rg1 TYPE = USER VCPU = 0 THREAD_PRIORITY = 19; +--error 3655 +ALTER RESOURCE GROUP rg2 THREAD_PRIORITY = 5; +--error 3655 +SET RESOURCE GROUP rg1; +--error 3655 +DROP RESOURCE GROUP rg1; + + +#ddl不支持spatial reference system相关操作 +--error 3655 +CREATE SPATIAL REFERENCE SYSTEM 13001003 NAME 'TEST13001003 Radian WGS 84' DEFINITION 'GEOGCS["Radian WGS 84",DATUM["World Geodetic System 1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["radian",1.0,AUTHORITY["EPSG","9101"]],AXIS["Lat",NORTH],AXIS["Lon",EAST],AUTHORITY["EPSG","4326"]]'; +--error 3655 +DROP SPATIAL REFERENCE SYSTEM 13001000; + + +#ddl不支持server相关操作 +--error 3655 +CREATE SERVER s FOREIGN DATA WRAPPER mysql OPTIONS (USER 'Remote', HOST '198.51.100.106', DATABASE 'test'); +--error 3655 +ALTER SERVER s OPTIONS (USER 'sally'); +--error 3655 +DROP SERVER s; + + +#ddl不支持alter instance相关操作 +--error 3655 +ALTER INSTANCE RELOAD KEYRING; +--error 3655 +ALTER INSTANCE ROTATE BINLOG MASTER KEY; + + +#测试alter tablespace add drop datafile(innodb不支持这两种操作,tse对标innodb需要进行禁止) +create tablespace ts01 add datafile 'ts_01.ibd' autoextend_size=1M; +--error ER_CHECK_NOT_IMPLEMENTED +alter tablespace ts01 add datafile 'ts_02.ibd' autoextend_size=4M; +--error ER_CHECK_NOT_IMPLEMENTED +alter tablespace ts01 drop datafile 'ts_01.ibd'; +drop tablespace ts01; + +#测试create tablespace检查是否为engine=Innodb情况,若是则拦截 +--error ER_DISALLOWED_OPERATION +CREATE TABLESPACE s1 ADD DATAFILE 's1.ibd' ENGINE InnoDB; + +# 不支持绝对路径 +--error ER_WRONG_FILE_NAME +create tablespace test1 add datafile "/cytest.ibd"; +--error ER_WRONG_FILE_NAME +create tablespace test1 add datafile " cytest.ibd"; +--error ER_WRONG_FILE_NAME +create tablespace test1 add datafile "cytest.ib"; + +# 不支持重建表 +create table t1 (col1 INT, col2 INT, col3 INT); +alter table t1 force; +drop table t1; + +#参天不支持调整列顺序 +create table t1 (a int, b int); +alter table t1 add column c1 int first; +alter table t1 add column c2 int after a; +alter table t1 modify a int after b; +alter table t1 modify b int first; +alter table t1 change a a int after b; +alter table t1 change b b int first; +drop table t1; + +#不支持RR隔离级别 +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +SET transaction_isolation='repeatable-read'; + +#允许修改空表单列字符集 +create table t1 (a char(10)); +show create table t1; +alter table t1 change a a char(10) character set ascii; +alter table t1 modify a char(10) character set ascii; +show create table t1; +drop table t1; + +#设置操作引擎防呆 +SET @@global.default_storage_engine = DEFAULT; +SET @@global.default_storage_engine = CTC; +--error 3655 +SET @@global.default_storage_engine = Innodb; +--error 3655 +SET @@global.default_storage_engine = @global_engine; +SET @global_engine = 'Innodb'; +--error 3655 +SET @@global.default_storage_engine = @global_engine; +SET @global_engine = 'DEFAULT'; +SET @@global.default_storage_engine = @global_engine; +SET @global_engine = 'CTC'; +SET @@global.default_storage_engine = @global_engine; + +#临时变量修改防呆 +SET @tmpvar = "DEFAULT"; +SET GLOBAL default_storage_engine = @tmpvar; +SET @tmpvar = "CTC"; +SET GLOBAL default_storage_engine = @tmpvar; +SET @tmpvar = "Innodb"; +--error 3655 +SET GLOBAL default_storage_engine = @tmpvar; + +#隔离级别防呆操作 +--error 3655 +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = @@global.transaction_isolation; +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 'repeatable-read'; +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 1; +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 'repeatable-read'; +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 'read-uncommitted'; +--error 3655 +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 'serializable'; +--error 3655 +SET @@global.transaction_isolation = @global_start_value; +SET @global_start_value = 'read-committed'; +SET @@global.transaction_isolation = @global_start_value; +SET @@global.transaction_isolation = 'repeatable-read'; +SET @@global.transaction_isolation = DEFAULT; + +#最大连接数防呆操作 +--error 3655 +SET @@global.max_connections = 5000; +--error 3655 +SET @@global.max_connections = 0; +SET @@global.max_connections = DEFAULT; +SET @tmp_max_connections = 5000; +--error 3655 +SET @@global.max_connections = @tmp_max_connections; + +#不支持虚拟列上建索引 +--error 3106 +create table t1 (a int, b int generated always as (a+1) key); +--error 3655 +CREATE TABLE t (a INT, b INT, c INT GENERATED ALWAYS AS(a+b), d INT GENERATED ALWAYS AS(a+b+b), KEY idxa (a),KEY vidxcd (c, d)); +--error 3655 +CREATE TABLE tb(id INT PRIMARY KEY, t1 LONGBLOB, t2 LONGBLOB, v1 CHAR(2) AS (SUBSTR(t1,2,2)) VIRTUAL, INDEX(id,v1)); +CREATE TABLE t5 (a int, b int GENERATED ALWAYS AS (a) VIRTUAL NOT NULL); +--error 3655 +ALTER TABLE t5 ADD UNIQUE INDEX (b); +DROP TABLE t5; + +# 不防呆设置为当前值 +SET GLOBAL protocol_compression_algorithms = @@global.protocol_compression_algorithms; +SET GLOBAL transaction_isolation = @@global.transaction_isolation; +SET GLOBAL max_connections = @@global.max_connections; + +# 变量值报错提示 +--error 1229 +SET admin_tls_version = @@SESSION.admin_tls_version; +--error 1228 +SET @@global.sql_log_bin = 0; +--error 1228 +SET @@global.timestamp = "1000"; +--error 1229 +SET admin_ssl_crl = @@SESSION.admin_ssl_crl; +--error 1229 +SET admin_ssl_crlpath = @@SESSION.admin_ssl_crlpath; +--error 1229 +SET admin_ssl_ca = @@SESSION.admin_ssl_ca; +--error 1229 +SET admin_tls_ciphersuites = @@SESSION.admin_tls_ciphersuites; +--error 1229 +SET admin_ssl_capath = @@SESSION.admin_ssl_capath; +--error 1229 +SET admin_ssl_cert = @@SESSION.admin_ssl_cert; +--error 1229 +SET admin_ssl_key = @@SESSION.admin_ssl_key; diff --git a/mysql-test/suite/tianchi/t/ctc_ddl_view.test b/mysql-test/suite/tianchi/t/ctc_ddl_view.test new file mode 100644 index 0000000..b257d7f --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_ddl_view.test @@ -0,0 +1,50 @@ +--disable_warnings +drop table if exists DEMO; +drop table if exists DEMO2; +--enable_warnings + +# create a table. +create table DEMO (ID integer not null, NAME varchar(20), AGE integer, GRADE real); +DESC DEMO; +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'KSLDK', 90, 123.36); +insert into DEMO values (1, 'BILL', 31, 76.1); +select * from DEMO; +#create a view +create view id_name as select ID, NAME from DEMO where ID = 1; +desc id_name; +select * from id_name; +insert into DEMO values (2, 'ALEX', 54, 22.45); +insert into DEMO values (7, 'ALICE', 73, 793); +#alter view +alter view id_name as select NAME, AGE from DEMO; +desc id_name; +select * from id_name; +#drop view +drop view id_name; +# create a table. +create table DEMO2 (CLASS integer not null, COURSE varchar(20), NAME varchar(20)); +DESC DEMO2; +insert into DEMO2 values (1011, 'CHINESE','LIOR'); +insert into DEMO2 values (1016, 'BIOLOGY', 'ALEX'); +insert into DEMO2 values (2033, 'HISTORY', 'ALICE'); +insert into DEMO2 values (3210, 'PE', 'SS'); +#create a view +create view combine_view as select DEMO.ID, DEMO.NAME, DEMO2.COURSE from DEMO, DEMO2 where DEMO.NAME = DEMO2.NAME; +desc combine_view; +select * from combine_view; +#drop view +drop view combine_view; +#drop Table +drop table DEMO; +drop table DEMO2; + + + + + diff --git a/mysql-test/suite/tianchi/t/ctc_delete_time.test b/mysql-test/suite/tianchi/t/ctc_delete_time.test new file mode 100644 index 0000000..56f761b --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_delete_time.test @@ -0,0 +1,122 @@ +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3,t4; +--enable_warnings +# Create tables +CREATE TABLE t1(c1 TIME NOT NULL, c2 TIME NULL, PRIMARY KEY(c1)); +CREATE TABLE t2(c1 TIME NOT NULL, c2 TIME NOT NULL, PRIMARY KEY(c1,c2)); +CREATE TABLE t3(c1 TIME NOT NULL, c2 TIME NULL, UNIQUE INDEX idx(c1,c2)); +CREATE TABLE t4(c1 TIME NOT NULL, c2 TIME NULL); + +# As a string in 'D HH:MM:SS.fraction' format + +INSERT INTO t1 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t2 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t3 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t4 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); + +#As a string with no delimiters in 'HHMMSS' format + +INSERT INTO t1 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t2 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t3 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t4 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); + +#As a number in HHMMSS format + +INSERT INTO t1 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t2 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t3 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t4 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); + +#As the result of a function that returns a value that is acceptable in a TIME context +SET TIMESTAMP=1233216687; # 2009-01-29 13:41:27 +INSERT INTO t1 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t2 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t3 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t4 VALUES(CURRENT_TIME(),CURRENT_TIME()); +#Insert permissible NULLs +INSERT INTO t1 VALUES('123456',null); +#INSERT INTO t2 VALUES('123456',null); +INSERT INTO t3 VALUES('123456',null); +INSERT INTO t4 VALUES('123456',null); +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT * FROM t4; +#Deleting the table rows +--sorted_result +SELECT c1 FROM t1 WHERE c1='00:00:07'; +DELETE FROM t1 WHERE c1='00:00:07'; +--sorted_result +SELECT c1 FROM t1; +--sorted_result +SELECT c1 FROM t2 WHERE c1='-838:59:59' AND c2='-838:59:59'; +DELETE FROM t2 WHERE c1='-838:59:59' AND c2='-838:59:59'; +--sorted_result +SELECT c1 FROM t2; + +#Deleting rowa with NULL attributes +--sorted_result +SELECT c2 FROM t3 WHERE c2=null; +DELETE FROM t3 WHERE c2=null; +--sorted_result +SELECT c2 FROM t3; + +#Delete by order by limit +--sorted_result +SELECT c1 FROM t4 WHERE c1 < '000009'; +DELETE FROM t4 WHERE c1 < '000009' ORDER BY c1 LIMIT 3; +--sorted_result +SELECT c1 FROM t4; + +#Delete by range values +DELETE FROM t1 WHERE c1='00:00:09' AND c1='01:01:01'; +--sorted_result +SELECT c2 FROM t1; +DELETE FROM t2 WHERE c2=000400 OR c2= 000900; +--sorted_result +SELECT c1 FROM t2; +DELETE FROM t2 WHERE c1 IN ('100:04:04',005454,'2:2:2',111111) ORDER BY c1 LIMIT 2; +--sorted_result +SELECT c2 FROM t2; + +#Multi table delete +DELETE t1,t2,t3,t4 FROM t1,t2,t3,t4 WHERE t1.c1='00:13:13' AND t2.c1=080808 AND t4.c1='00:04:00' AND t3.c2=020202; + +#Delete using various access methods + +# Delete using Const +# EXPLAIN SELECT * FROM t1 WHERE c1='00:09:09' AND c2='00:09:09'; +DELETE FROM t1 WHERE c1='00:09:09' AND c2='00:09:09'; +--sorted_result +SELECT * FROM t1; + +# Delete using range +# EXPLAIN SELECT * FROM t1 WHERE c1 BETWEEN 080000 AND 100000; +DELETE FROM t1 WHERE c1 BETWEEN 080000 AND 100000; +--sorted_result +SELECT * FROM t1; +# EXPLAIN SELECT * FROM t1 WHERE c1 IN (222222,8385959,1500000); +DELETE FROM t1 WHERE c1 IN (222222,8385959,1500000); +--sorted_result +SELECT * FROM t1; + +# Delete using eq_ref +# EXPLAIN SELECT * FROM t2,t3 WHERE t2.c1=t3.c1 AND t2.c3=t3.c3; +DELETE t1,t2 FROM t1,t2 WHERE t1.c1=t2.c1 AND t1.c2=t2.c2; + +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT * FROM t4; +#Drop tables; +DROP TABLE IF EXISTS t1,t2,t3,t4; + diff --git a/mysql-test/suite/tianchi/t/ctc_dml_decimal_table.test b/mysql-test/suite/tianchi/t/ctc_dml_decimal_table.test new file mode 100644 index 0000000..67711f7 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_dml_decimal_table.test @@ -0,0 +1,195 @@ +--disable_warnings +drop database if exists test; +CREATE database test; +use test; +--enable_warnings + +--disable_warnings +drop table if exists t1,t2,t3; +--enable_warnings + + +CREATE TABLE t1(c1 NUMERIC, c2 NUMERIC, c3 NUMERIC); +alter table t1 add index idx(c1, c2, c3); +insert into t1(c1, c2, c3) values(10, 1, 10); +insert into t1(c1, c2, c3) values(10, 1, 11); +insert into t1(c1, c2, c3) values(8, 1, 11); +SELECT * FROM t1; +SELECT * FROM t1 where c1 =10; +SELECT * FROM t1 where c1 =10 and c2 =1; +SELECT * FROM t1 where c1 =10 and c2 =1 and c3 = 10; +SELECT * FROM t1 where c1 >= 10; +SELECT * FROM t1 where c1 <= 10; +SELECT * FROM t1 where c2 = 1; +DROP table t1; + + +CREATE TABLE t2(c1 DECIMAL, c2 DECIMAL, c3 DECIMAL); +alter table t2 add index idx(c1, c2, c3); +insert into t2(c1, c2, c3) values(10, 1, 10); +insert into t2(c1, c2, c3) values(10, 1, 11); +SELECT * FROM t2; +SELECT * FROM t2 where c1 = 10; +SELECT * FROM t2 where c1 = 10 and c2 = 1; +SELECT * FROM t2 where c1 = 10 and c2 = 1 and c3 = 10; +SELECT * FROM t2 where c2 = 1; +SELECT * FROM t2 where c3 = 10; +DROP table t2; + + +CREATE TABLE t2(c1 DECIMAL, c2 int, c3 NUMERIC); +alter table t2 add index idx(c1, c2, c3); +insert into t2(c1, c2, c3) values(10, 1, 10); +insert into t2(c1, c2, c3) values(10, 1, 11); +SELECT * FROM t2; +SELECT * FROM t2 where c1 = 10; +SELECT * FROM t2 where c1 = 10 and c2 = 1; +SELECT * FROM t2 where c1 = 10 and c2 = 1 and c3 = 10; +DROP table t2; + + +CREATE TABLE t1(c1 NUMERIC key); +insert into t1(c1) values(10); +insert into t1(c1) values(1); +insert into t1(c1) values(5); +SELECT * FROM t1; +SELECT * FROM t1 where c1 = 10; +DROP TABLE t1; + + +CREATE TABLE t1(c1 DECIMAL key); +insert into t1(c1) values(10); +insert into t1(c1) values(1); +insert into t1(c1) values(5); +SELECT * FROM t1; +SELECT * FROM t1 where c1 = 10; +DROP TABLE t1; + + +CREATE TABLE t1(c1 NUMERIC, c2 NUMERIC, c3 NUMERIC); +alter table t1 add index idx(c1); +insert into t1(c1, c2, c3) values(10, 1, 10); +insert into t1(c1, c2, c3) values(10, 1, 11); +insert into t1(c1, c2, c3) values(8, 1, 11); +SELECT * FROM t1; +SELECT c1 FROM t1 where c1 = 10; +SELECT c1 FROM t1 where c1 >= 10; +DROP table t1; + + +#参天填充bitmap对应的索引最大支持12列,大于12列bitmap会覆盖数据,需要后移拷贝数据,索引为14列 +CREATE TABLE t2(c1 DECIMAL, c2 int, c3 NUMERIC, c4 int, c5 int, c6 DECIMAL, c7 int, +c8 int, c9 int, c10 int, c11 int, c12 int, c13 int, c14 int, c15 int, c16 int, c17 int); +alter table t2 add index idx(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, null, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(2, null, null, 4, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); +SELECT * FROM t2; +SELECT c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14 FROM t2 where c1 = 1; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14 FROM t2 where c1 >= 1; +SELECT * FROM t2 where c1 = 1; +DROP table t2; + + +#参天填充bitmap最大支持12列,大于12列bitmap会覆盖数据,需要后移拷贝数据,索引为12列 +CREATE TABLE t2(c1 DECIMAL, c2 int, c3 NUMERIC, c4 int, c5 int, c6 DECIMAL, c7 int, +c8 int, c9 int, c10 int, c11 int, c12 int, c13 int, c14 int, c15 int, c16 int, c17 int); +alter table t2 add index idx(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, null, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(2, null, null, 4, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); +SELECT * FROM t2; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11, c12 FROM t2 where c1 = 1; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11, c12 FROM t2 where c1 >= 1; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11, c12 FROM t2 where c1 <= 2; +SELECT * FROM t2 where c1 = 1; +DROP table t2; + + +#参天填充bitmap最大支持12列,大于12列bitmap会覆盖数据,需要后移拷贝数据,索引为11列 +CREATE TABLE t2(c1 DECIMAL, c2 int, c3 NUMERIC, c4 int, c5 int, c6 DECIMAL, c7 int, +c8 int, c9 int, c10 int, c11 int, c12 int, c13 int, c14 int, c15 int, c16 int, c17 int); +alter table t2 add index idx(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, null, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(2, null, null, 4, 5, 6, 7, 8, 9, 10, 11, null, 13, 14, 15, 16, 17); +insert into t2(c1, c2, c3, c4, c5, c6, c7, c8, c9, +c10, c11, c12, c13, c14, c15, c16, c17) values(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17); +SELECT * FROM t2; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11 FROM t2 where c1 = 1; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11 FROM t2 where c1 >= 1; +SELECT c1, c2 , c3, c4, c5, c6, c7, c8, c9, c10, c11 FROM t2 where c1 <= 2; +SELECT * FROM t2 where c1 = 1; +DROP table t2; + + +#index_only条件下非decimal数据查询 +CREATE TABLE t1(c1 int key); +insert into t1(c1) values(10); +insert into t1(c1) values(1); +insert into t1(c1) values(5); +SELECT * FROM t1; +SELECT * FROM t1 where c1 = 10; +DROP TABLE t1; + + +#非index_only条件下decimal数据查询 +CREATE TABLE t3(c1 NUMERIC, c2 int, c3 NUMERIC); +alter table t3 add index idx(c1); +insert into t3(c1, c2, c3) values(10, 1, 10); +insert into t3(c1, c2, c3) values(10, 1, 11); +SELECT * FROM t3; +SELECT * FROM t3 where c1 =10; +DROP table t3; + + +#index_only条件下decimal数据查询 +CREATE TABLE t1(c1 DECIMAL(10,5) UNSIGNED NOT NULL, c2 DECIMAL(10,5) SIGNED NULL, c3 DECIMAL, c4 INT, UNIQUE INDEX idx(c1,c2)); +INSERT INTO t1 VALUES ('11111.11111','-11111.11111','1111111111',1); +INSERT INTO t1 VALUES ('22222.22222','-22222.22222','2222222222',2); +INSERT INTO t1 VALUES ('33333.33333','-33333.33333','3333333333',3); +INSERT INTO t1 VALUES ('44444.44444','-44444.44444','4444444444',4); +INSERT INTO t1 VALUES ('55555.55555','-55555.55555','5555555555',5); +INSERT INTO t1 VALUES ('66666.66666','-66666.66666','6666666666',6); +INSERT INTO t1 VALUES ('77777.77777','-77777.77777','7777777777',7); +INSERT INTO t1 VALUES ('88888.88888','-88888.88888','8888888888',8); +INSERT INTO t1 VALUES ('99999.99999','-99999.99999','9999999999',9); +SELECT c1,c2 FROM t1; +DROP table t1; + + +#index_only条件下decimal数据查询 +CREATE TABLE t1(c1 INT, c2 VARCHAR(20), c3 DECIMAL(10,5) UNSIGNED NOT NULL, c4 DECIMAL(10,5) SIGNED NULL, UNIQUE INDEX idx(c2,c3)); +INSERT INTO t1 VALUES (1,'yy','11111.11111','-11111.11111'); +INSERT INTO t1 VALUES (2,'yy','22222.22222','-22222.22222'); +INSERT INTO t1 VALUES (3,'yy','33333.33333','-33333.33333'); +INSERT INTO t1 VALUES (4,'yy','44444.44444','-44444.44444'); +INSERT INTO t1 VALUES (5,'yy','55555.55555','-55555.55555'); +INSERT INTO t1 VALUES (6,'yy','66666.66666','-66666.66666'); +INSERT INTO t1 VALUES (7,'yy','77777.77777','-77777.77777'); +INSERT INTO t1 VALUES (8,'yy','88888.88888','-88888.88888'); +INSERT INTO t1 VALUES (9,'yy','99999.99999','-99999.99999'); +SELECT c2,c3 FROM t1; +DROP table t1; + +set sql_mode = ''; +CREATE TABLE t1 SELECT 12345678901234567890123456789012345678901234567890123456789012345.1 AS c1; +select * from t1; +drop table t1; +CREATE TABLE t2 SELECT 123456789012345678901234567890123456789012345678901234567890123456.1 AS c1; +select * from t2; +drop table t2; +CREATE TABLE t3 SELECT 1234567890123456789012345678901234567890123456789012345678901234.1 AS c1; +select * from t3; +drop table t3; +set sql_mode = default; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_dml_ignore.test b/mysql-test/suite/tianchi/t/ctc_dml_ignore.test new file mode 100644 index 0000000..78ef634 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_dml_ignore.test @@ -0,0 +1,193 @@ +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +CREATE TABLE t1 ( +`colA` int(10) unsigned NOT NULL auto_increment, +`colB` int(11) NOT NULL default '0', +PRIMARY KEY (`colA`) +); +INSERT INTO t1 VALUES (4433,5424); +CREATE TABLE t2 ( +`colC` int(10) unsigned NOT NULL default '0', +`colA` int(10) unsigned NOT NULL default '0', +`colD` int(10) unsigned NOT NULL default '0', +`colE` int(10) unsigned NOT NULL default '0', +`colF` int(10) unsigned NOT NULL default '0', +PRIMARY KEY (`colC`,`colA`,`colD`,`colE`) +); +INSERT INTO t2 VALUES (3,4433,10005,495,500); +INSERT INTO t2 VALUES (3,4433,10005,496,500); +INSERT INTO t2 VALUES (3,4433,10009,494,500); +INSERT INTO t2 VALUES (3,4433,10011,494,500); +INSERT INTO t2 VALUES (3,4433,10005,497,500); +INSERT INTO t2 VALUES (3,4433,10013,489,500); +INSERT INTO t2 VALUES (3,4433,10005,494,500); +INSERT INTO t2 VALUES (3,4433,10005,493,500); +INSERT INTO t2 VALUES (3,4433,10005,492,500); +select * from t2; +UPDATE IGNORE t2 set colE = colE + 1, colF = 0 where colE = 494; +select * from t2; +UPDATE IGNORE t2 set colE = colE - 1, colF = 500 where colF = 0; +select * from t2; +UPDATE IGNORE t2,t1 set t2.colE = t2.colE + 1,colF = 0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +select * from t2; +UPDATE IGNORE t2 set colE = colE - 1, colF = 500 where colF = 0; +select * from t2; +UPDATE IGNORE t2,t1 set t2.colE = t2.colE - 1,colF = 0 WHERE t1.colA = t2.colA AND (t1.colB & 4096) > 0 AND (colE + 1) < colF; +select * from t2; +UPDATE IGNORE t2 set colE = colE + 1, colF = 500 where colF = 0; +select * from t2; +drop table t1,t2; + +create table parent (a int primary key, b int); +create table child (a int, b int, foreign key (a) references parent(a)); +insert into parent values (1,1),(2,2),(3,3),(4,4),(8,8),(9,9),(10,10); +insert IGNORE into child values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +select * from child; +delete IGNORE from parent where b < 4; +delete IGNORE from parent where b = 2; +select * from parent; +delete IGNORE from parent where b <= 10; +select * from parent; +drop table child; +drop table parent; + +create table parent (a int primary key, b int); +create table child (a int, b int, foreign key (a) references parent(a)); +insert into parent values (1,1),(2,2),(3,3),(4,4),(8,8),(9,9),(10,10); +insert IGNORE into child values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +select * from child; +update IGNORE parent set a = 11 where a = 2; +select * from parent; +update IGNORE parent set a = 12 where a = 10; +select * from parent; +update IGNORE parent set a = 13 where a = 3; +select * from parent; +update IGNORE parent set a = a + 1; +select * from parent; +update IGNORE parent set a = a + 1; +select * from parent; +drop table child; +drop table parent; + +create table parent (a int primary key, b int); +create table child (a int, b int, foreign key (a) references parent(a)); +insert into parent values (1,1),(2,2),(3,3),(4,4),(8,8),(9,9),(10,10); +insert IGNORE into child values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +select * from child; +update IGNORE child set a = 11 where a = 2; +select * from child; +update IGNORE child set a = 12 where a = 3; +select * from child; +update IGNORE child set a = 8 where a = 3; +select * from child; +update IGNORE child set a = a + 1; +select * from child; +update IGNORE child set a = a + 1; +select * from child; +drop table child; +drop table parent; + +create table class(id int primary key auto_increment,c_name varchar(20) not null,room varchar(20)); +create table my_foreign1(id int primary key auto_increment, + name varchar(20) not null comment '学生姓名', + c_id int comment '班级表ID', + CONSTRAINT fk_id foreign key(c_id) references class(id) +); +insert into class values(1,'abc','aaa'); +insert into class values(2,'abc2','bbb'); +insert into class values(3,'abc3','ccc'); +insert into class values(4,'4','4'); +select * from class; +--error 1452 +insert into my_foreign1 values(null,'Charies1','6'); #父表没有,因为有外键依赖所以插入不了 +--error 1452 +insert into my_foreign1 values(null,'Charies2','7'); +--error 1452 +insert into my_foreign1 values(null,'Charies3','8'); +SET FOREIGN_KEY_CHECKS = 0; +insert into my_foreign1 values(null,'Charies','6'); #忽略外键约束检查,预期插入成功 +insert into my_foreign1 values(null,'Charies2','7'); +insert into my_foreign1 values(null,'Charies3','8'); +select * from my_foreign1; +SET FOREIGN_KEY_CHECKS = 1; +insert into my_foreign1 values(null,'Charies','1'); +insert into my_foreign1 values(null,'Bob','2'); +insert into my_foreign1 values(null,'Bob1','3'); +select * from my_foreign1; +--error 1451 +#ERROR 1452 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`demo_db`.`my_foreign1`, CONSTRAINT `fk_id` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`)) +delete from class where id = 2; +--error 1451 +#ERROR 1452 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`demo_db`.`my_foreign1`, CONSTRAINT `fk_id` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`)) +delete from class where id = 3; +SET FOREIGN_KEY_CHECKS = 0; +delete from class where id = 2; +select * from class; +delete from class where id = 3; +select * from class; +SET FOREIGN_KEY_CHECKS = 1; +insert into class values(2,'abc2','bbb'); +insert into class values(3,'abc3','ccc'); +--error 1451 +#ERROR 1452 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`demo_db`.`my_foreign1`, CONSTRAINT `fk_id` FOREIGN KEY (`c_id`) REFERENCES `class` (`id`)) +update class set id = 100 where id = 2; +SET FOREIGN_KEY_CHECKS = 0; +update class set id = 100 where id = 2; +select * from class; +SET FOREIGN_KEY_CHECKS = 1; +update class set id = 101 where id = 4;#4没有被子表引用,可以更改 +delete from class where id = 100;#100没有被子表引用,可以更改 +drop table my_foreign1; +drop table class; + + +create table t1 (id int primary key auto_increment, operation varchar(255)); +create table t1_op_log(operation varchar(255)); +create view v1 as select * from t1; +create trigger trg_bug28502_bi before insert on t1 +for each row + insert into t1_op_log (operation) + values (concat("Before INSERT, new=", new.operation)); + +create trigger trg_bug28502_ai after insert on t1 +for each row + insert into t1_op_log (operation) + values (concat("After INSERT, new=", new.operation)); + +create trigger trg_bug28502_bu before update on t1 +for each row + insert into t1_op_log (operation) + values (concat("Before UPDATE, new=", new.operation, + ", old=", old.operation)); + +create trigger trg_bug28502_au after update on t1 +for each row + insert into t1_op_log (operation) + values (concat("After UPDATE, new=", new.operation, + ", old=", old.operation)); + +create trigger trg_bug28502_bd before delete on t1 +for each row + insert into t1_op_log (operation) + values (concat("Before DELETE, old=", old.operation)); + +create trigger trg_bug28502_ad after delete on t1 +for each row + insert into t1_op_log (operation) + values (concat("After DELETE, old=", old.operation)); + +insert into t1 (operation) values ("INSERT"); + +set @id=last_insert_id(); +replace into v1 +select @id, "CREATE TABLE ... REPLACE SELECT, deleting a duplicate key"; +drop trigger if exists trg_bug28502_bi; +drop trigger if exists trg_bug28502_ai; +drop trigger if exists trg_bug28502_bu; +drop trigger if exists trg_bug28502_au; +drop trigger if exists trg_bug28502_bd; +drop trigger if exists trg_bug28502_ad; +drop table t1, t1_op_log; +drop view v1; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_dml_two_table.test b/mysql-test/suite/tianchi/t/ctc_dml_two_table.test new file mode 100644 index 0000000..c37717b --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_dml_two_table.test @@ -0,0 +1,52 @@ +# 忽略建库建表过程中执行出错引起中断执行及相关的错误日志输出.result文件,影响结果比较,我们核心只关注DML语句 +-- disable_result_log +-- disable_abort_on_error +-- disable_query_log + +# 设置默认存储引擎 (自动生成.result的时候,需要使用InnoDB,执行DML测试的时候,要使用TSE引擎,我们的策略是比较InnoDB和TSE引擎执行结果的差异来校验TSE引擎是否存在BUG) + +#注意,测试用例要保证不破坏执行环境,所以测试用例产生的数据(包括表,数据库等等),测试用例执行完毕后,原则上是要把产生的数据删除的,避免影响别的测试用例 +drop table IF EXISTS PERSONS; +drop table IF EXISTS ORDERS; + +# create table +create table PERSONS (ID integer not null, LastName varchar(25), FirstName varchar(25), Address varchar(25), City varchar(25)); +create table ORDERS (ID integer not null, OrderNo integer, ID_P integer); + +#后面可以开启相关日志了 +-- enable_query_log +-- enable_abort_on_error +-- enable_result_log + + +INSERT INTO PERSONS VALUES (1,'Gates', 'Bill', 'Xuanwumen 10', 'Beijing'); +INSERT INTO PERSONS VALUES (2,'Adams', 'John', 'Oxford Street', 'London'); +INSERT INTO PERSONS VALUES (3,'Bush', 'George', 'Fifth Avenue', 'New York'); +INSERT INTO PERSONS VALUES (4,'Carter', 'Thomas', 'Changan Street', 'Beijing'); + +INSERT INTO ORDERS VALUES (1,77895,3); +INSERT INTO ORDERS VALUES (2,44678,3); +INSERT INTO ORDERS VALUES (3,22456,1); +INSERT INTO ORDERS VALUES (4,24562,1); +INSERT INTO ORDERS VALUES (5,34764,65); + +SELECT * FROM PERSONS; +SELECT * FROM ORDERS; +SELECT PERSONS.LastName, PERSONS.FirstName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE PERSONS.ID = ORDERS.ID_P; +SELECT * FROM PERSONS, ORDERS WHERE PERSONS.ID = ORDERS.ID_P; +SELECT PERSONS.LastName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE PERSONS.ID >= 3 AND ORDERS.ID <= 1; +SELECT PERSONS.LastName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE PERSONS.ID < 3 AND ORDERS.ID > 1; +SELECT PERSONS.LastName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE PERSONS.FirstName = 'John' OR ORDERS.OrderNo < 30000; +SELECT PERSONS.LastName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE (PERSONS.LastName Like '%s' AND ORDERS.OrderNo < 30000) OR PERSONS.FirstName IN ('Bill','Thomas'); + +UPDATE PERSONS SET LastName="OMG", FirstName="GMO" where ID=3; +UPDATE ORDERS SET OrderNo=99 where ID=3; +DELETE FROM ORDERS where ID=1; +SELECT PERSONS.LastName, PERSONS.FirstName, ORDERS.OrderNo FROM PERSONS, ORDERS WHERE PERSONS.ID = ORDERS.ID_P; + +SELECT PERSONS.LastName, PERSONS.FirstName, ORDERS.OrderNo FROM PERSONS INNER JOIN ORDERS ON PERSONS.ID=ORDERS.ID_P ORDER BY PERSONS.LastName; +SELECT PERSONS.LastName, PERSONS.FirstName, ORDERS.OrderNo FROM PERSONS LEFT JOIN ORDERS ON PERSONS.ID=ORDERS.ID_P ORDER BY PERSONS.LastName; +SELECT PERSONS.LastName, PERSONS.FirstName, ORDERS.OrderNo FROM PERSONS RIGHT JOIN ORDERS ON PERSONS.ID=ORDERS.ID_P ORDER BY PERSONS.LastName; + +DROP TABLE PERSONS; +DROP TABLE ORDERS; diff --git a/mysql-test/suite/tianchi/t/ctc_handler_operation.test b/mysql-test/suite/tianchi/t/ctc_handler_operation.test new file mode 100644 index 0000000..fe4b31b --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_handler_operation.test @@ -0,0 +1,48 @@ +--disable_warnings +drop table if exists handler_table; +--enable_warnings + +# create a table. +create table handler_table(id int, name varchar(10)); + +insert into handler_table values(3, '张三'); +insert into handler_table values(4, '李四'); +insert into handler_table values(5, '王五'); +insert into handler_table values(1, '刘一'); +insert into handler_table values(2, '陈二'); +select *from handler_table; +handler handler_table open; +handler handler_table read first; +handler handler_table read next; +handler handler_table close; + +create index handler_index on handler_table(id); + +handler handler_table open; +# 打开句柄并命名为 p +handler handler_table open as p; +# 通过索引获取第一行数据 +handler p read handler_index first; +# 获取下一行数据 +handler p read handler_index next; +# 获取上一行数据 +handler p read handler_index prev; +# 获取最后一行数据 +handler p read handler_index last; +# 关闭已打开的句柄 +handler p close; + +# 打开句柄并命名为 p +handler handler_table open as p; +# 指定索引开始查看数据 +handler p read handler_index = (2); +# 获取第一行数据 +handler p read handler_index first; +# 获取下一行数据 +handler p read handler_index next; +# 获取上一行数据 +handler p read handler_index prev; +# 获取最后一行数据 +handler p read handler_index last; +handler p close; +drop table handler_table; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_index_functions_base.test b/mysql-test/suite/tianchi/t/ctc_index_functions_base.test new file mode 100644 index 0000000..65d6378 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_index_functions_base.test @@ -0,0 +1,140 @@ +--disable_warnings +drop table if exists DEMO; +--enable_warnings + +# create a table. +create table DEMO (ID integer not null, NAME varchar(19), AGE integer, GRADE real); + +# insert some data to table. +insert into DEMO values (1, 'LIOR', 35, 6.9); +insert into DEMO values (4, 'MIKE', 55, 99.92); +insert into DEMO values (8, 'ROMAN', 40, 94.1); +insert into DEMO values (16, 'DAN', 60, 1234567890); +insert into DEMO values (32, 'ZVI', 35, 777.666); +insert into DEMO values (1, 'Eitan', NULL, 4.9); +insert into DEMO values (888888, 'zhangdi', NULL, 10000.8); +insert into DEMO values (1131, 'Hisses', 1, NULL); + +#select update insert delete. +SELECT * FROM DEMO; + +# index demo test +create index aaa ON DEMO (ID); +select * from DEMO where ID = 1; +select * from DEMO where ID <= 16; +select * from DEMO where ID < 16; +select * from DEMO where ID between 4 and 32; +select * from DEMO where ID >= 32; +select * from DEMO where ID > 32; +select * from DEMO where ID in (16,32); +select * from DEMO where ID like '1%'; +select * from DEMO where ID = 1 order by ID; +select * from DEMO where ID = 1 order by ID desc; +select * from DEMO where ID <= 16 order by ID; +select * from DEMO where ID < 16 order by ID desc; +select * from DEMO where ID between 4 and 32 order by ID; +select * from DEMO where ID between 4 and 32 order by ID desc; +select * from DEMO where ID >= 32 order by ID; +select * from DEMO where ID > 32 order by ID desc; +select * from DEMO where ID in (16,32) order by ID; +select * from DEMO where ID in (16,32) order by ID desc; +select * from DEMO where ID like '1%' order by ID; +select * from DEMO where ID like '1%' order by ID desc; + +drop table DEMO; + +# Preparing Index Test Data +--disable_warnings +drop table if exists INDEX_DEMO; +--enable_warnings + +create table INDEX_DEMO (ID integer PRIMARY KEY, CARD_NUM integer UNIQUE NOT NULL, FIRST_NAME VARCHAR(25) NOT NULL, LAST_NAME VARCHAR(25) NOT NULL, AGE integer NOT NULL, EMAIL VARCHAR(30) NOT NULL, BIRTHDAY VARCHAR(20) NOT NULL, GENDER CHAR(10)); + +CREATE INDEX IDX_AGE ON INDEX_DEMO(AGE); +CREATE INDEX IDX_NAME_BIRTHDAY ON INDEX_DEMO(FIRST_NAME, LAST_NAME, BIRTHDAY); +CREATE INDEX IDX_EMAIL ON INDEX_DEMO(EMAIL); + +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (89, 46, 'Gilligan', 'Rostern', 28, 'grostern0@buzzfeed.com', '1992-12-10', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (45, 50, 'Alistair', 'Lempenny', 64, 'alempenny1@foxnews.com', '1991-06-07', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (44, 39, 'Roda', 'Paolo', 45, 'rpaolo2@mozilla.com', '1996-05-12', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (49, 74, 'Marcos', 'Coutts', 91, 'mcoutts3@blogs.com', '1998-12-18', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (6, 81, 'Kalvin', 'Tunnicliff', 35, 'ktunnicliff4@dailymotion.com', '1991-04-03', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (80, 87, 'Morna', 'Colbert', 8, 'mcolbert5@miitbeian.gov.cn', '2001-06-25', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (12, 30, 'Leoine', 'Elms', 19, 'lelms6@ucsd.edu', '2003-11-14', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (31, 77, 'Rita', 'Scotchmore', 28, 'rscotchmore7@illinois.edu', '1991-06-23', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (7, 47, 'Jarib', 'Ausiello', 69, 'jausiello8@wsj.com', '1993-05-10', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (93, 44, 'Dianna', 'Cockle', 15, 'dcockle9@mac.com', '2003-06-10', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (64, 95, 'Tait', 'Tavinor', 63, 'ttavinora@photobucket.com', '1994-11-02', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (83, 83, 'Shannon', 'Covelle', 30, 'scovelleb@tinyurl.com', '2001-01-22', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (20, 76, 'Stevana', 'Alyoshin', 88, 'salyoshinc@wired.com', '1990-11-18', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (19, 12, 'Garrard', 'Bools', 68, 'gboolsd@bandcamp.com', '1993-12-05', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (75, 2, 'Kristi', 'Boules', 46, 'kboulese@amazon.co.uk', '1993-07-29', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (67, 36, 'Mag', 'Dalgarnocht', 74, 'mdalgarnochtf@marketwatch.com', '2000-05-03', 'Male'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (3, 94, 'Cori', 'Mee', 50, 'cmeeg@fema.gov', '1993-04-29', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (69, 33, 'Emogene', 'Pedroni', 87, 'epedronih@4shared.com', '2005-06-08', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (100, 71, 'Douglas', 'Pardie', 2, 'dpardiei@spiegel.de', '2001-11-05', 'Female'); +insert into INDEX_DEMO (ID, CARD_NUM, FIRST_NAME, LAST_NAME, AGE, EMAIL, BIRTHDAY, GENDER) values (17, 38, 'Karim', 'Mainwaring', 54, 'kmainwaringj@163.com', '2003-01-21','Male'); + +select * from INDEX_DEMO; + +# index +select * from INDEX_DEMO where AGE = 32; +select * from INDEX_DEMO where AGE <= 32; +select * from INDEX_DEMO where AGE < 30; +select * from INDEX_DEMO where AGE between 20 and 30; +select * from INDEX_DEMO where AGE >= 30; +select * from INDEX_DEMO where AGE > 30; +select * from INDEX_DEMO where AGE in (24,32); +select * from INDEX_DEMO where EMAIL like 'a%'; +select * from INDEX_DEMO where EMAIL like 'ahake0@homestead.com'; +select * from INDEX_DEMO where EMAIL like '%amazon%'; +select * from INDEX_DEMO where EMAIL like '%com'; +select * from INDEX_DEMO where EMAIL is null; + +# primary key +select * from INDEX_DEMO where ID = 10; +select * from INDEX_DEMO where ID <= 10; +select * from INDEX_DEMO where ID < 10; +select * from INDEX_DEMO where ID between 10 and 20; +select * from INDEX_DEMO where ID >= 10; +select * from INDEX_DEMO where ID > 10; +select * from INDEX_DEMO where ID in (11,12); + +# unique +select * from INDEX_DEMO where CARD_NUM = 10; +select * from INDEX_DEMO where CARD_NUM <= 12; +select * from INDEX_DEMO where CARD_NUM < 10; +select * from INDEX_DEMO where CARD_NUM between 10 and 20; +select * from INDEX_DEMO where CARD_NUM >= 10; +select * from INDEX_DEMO where CARD_NUM > 10; +select * from INDEX_DEMO where CARD_NUM in (11,12); + +# index & order by +select * from INDEX_DEMO where AGE = 32 order by AGE; +select * from INDEX_DEMO where AGE = 32 order by AGE desc; +select * from INDEX_DEMO where AGE <= 32 order by AGE; +select * from INDEX_DEMO where AGE < 30 order by AGE desc; +select * from INDEX_DEMO where AGE between 20 and 30 order by AGE; +select * from INDEX_DEMO where AGE between 20 and 30 order by AGE desc; +select * from INDEX_DEMO where AGE >= 30 order by AGE; +select * from INDEX_DEMO where AGE > 30 order by AGE desc; +select * from INDEX_DEMO where AGE in (24,32) order by AGE; +select * from INDEX_DEMO where AGE in (24,32) order by AGE desc; + +drop table if exists INDEX_DEMO; + +# index only +create table DEMO (a int, b int, c int, d int, e int, f int); +create index idx on DEMO (f,e,d); +insert into DEMO values (1,2,3,4,null,6); +insert into DEMO values (1,2,3,4,5,null); +insert into DEMO values (1,2,3,4,5,6); + +select e,f from DEMO where d = 4; +Select d from DEMO where f = 6; +Select e from DEMO where d = 4 and f = 6; + +drop table if exists DEMO; + +# show prefetch buffer size +show variables like '%ctc_prefetch_buf_size%'; diff --git a/mysql-test/suite/tianchi/t/ctc_insert_time.test b/mysql-test/suite/tianchi/t/ctc_insert_time.test new file mode 100644 index 0000000..76f1981 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_insert_time.test @@ -0,0 +1,1063 @@ +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3,t4; +--enable_warnings +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +######## Running INSERT tests for TIME ######## + +# Create tables +CREATE TABLE t1(c1 TIME NOT NULL, c2 TIME NULL, c3 DATE, PRIMARY KEY(c1), UNIQUE INDEX(c2)); +CREATE TABLE t2(c1 TIME NOT NULL, c2 TIME NOT NULL, c3 DATE, PRIMARY KEY(c1,c2)); +CREATE TABLE t3(c1 TIME NOT NULL, c2 TIME NULL, c3 DATE, UNIQUE INDEX idx(c1,c2)); +CREATE TABLE t4(c1 TIME NOT NULL, c2 TIME NULL, c3 DATE); +# Insert some rows with targeted values + +# As a string in 'D HH:MM:SS.fraction' format +INSERT INTO t1 VALUES('12:34:56.78','12:34:56.78','2009-01-01'),('10:22:33','10:22:33','2009-01-02'),('1:23','1:23','2009-01-03'),('20 11:22:33','20 11:22:33','2009-01-04'),('34 9:23','34 9:23','2009-01-05'),('0 10','0 10','2009-01-06'),('45','45','2009-01-07'),('-838:59:59','-838:59:59','2009-01-08'),('0','0','2009-01-09'),('838:59:59','838:59:59','2009-01-10'); +INSERT INTO t2 VALUES('12:34:56.78','12:34:56.78','2009-01-01'),('10:22:33','10:22:33','2009-01-02'),('1:23','1:23','2009-01-03'),('20 11:22:33','20 11:22:33','2009-01-04'),('34 9:23','34 9:23','2009-01-05'),('0 10','0 10','2009-01-06'),('45','45','2009-01-07'),('-838:59:59','-838:59:59','2009-01-08'),('0','0','2009-01-09'),('838:59:59','838:59:59','2009-01-10'); +INSERT INTO t3 VALUES('12:34:56.78','12:34:56.78','2009-01-01'),('10:22:33','10:22:33','2009-01-02'),('1:23','1:23','2009-01-03'),('20 11:22:33','20 11:22:33','2009-01-04'),('34 9:23','34 9:23','2009-01-05'),('0 10','0 10','2009-01-06'),('45','45','2009-01-07'),('-838:59:59','-838:59:59','2009-01-08'),('0','0','2009-01-09'),('838:59:59','838:59:59','2009-01-10'); +INSERT INTO t4 VALUES('12:34:56.78','12:34:56.78','2009-01-01'),('10:22:33','10:22:33','2009-01-02'),('1:23','1:23','2009-01-03'),('20 11:22:33','20 11:22:33','2009-01-04'),('34 9:23','34 9:23','2009-01-05'),('0 10','0 10','2009-01-06'),('45','45','2009-01-07'),('-838:59:59','-838:59:59','2009-01-08'),('0','0','2009-01-09'),('838:59:59','838:59:59','2009-01-10'); + +# As a string with no delimiters in 'HHMMSS' format +INSERT INTO t1 VALUES('101112','101112','2009-01-11'); +INSERT INTO t2 VALUES('101112','101112','2009-01-11'); +INSERT INTO t3 VALUES('101112','101112','2009-01-11'); +INSERT INTO t4 VALUES('101112','101112','2009-01-11'); + +# As a number in HHMMSS format +INSERT INTO t1 VALUES(111112,111112,'2009-01-12'),(12,12,'2009-01-13'),(1234,1234,'2009-01-14'),(123458,123458,'2009-01-15'),(123556.99,123556.99,'2009-01-16'); +INSERT INTO t2 VALUES(111112,111112,'2009-01-12'),(12,12,'2009-01-13'),(1234,1234,'2009-01-14'),(123458,123458,'2009-01-15'),(123556.99,123556.99,'2009-01-16'); +INSERT INTO t3 VALUES(111112,111112,'2009-01-12'),(12,12,'2009-01-13'),(1234,1234,'2009-01-14'),(123458,123458,'2009-01-15'),(123556.99,123556.99,'2009-01-16'); +INSERT INTO t4 VALUES(111112,111112,'2009-01-12'),(12,12,'2009-01-13'),(1234,1234,'2009-01-14'),(123458,123458,'2009-01-15'),(123556.99,123556.99,'2009-01-16'); + +# As the result of a function +SET TIMESTAMP=1233216687; # 2009-01-29 13:41:27 +INSERT INTO t1 VALUES(CURRENT_TIME(),CURRENT_TIME(),'2009-01-17'); +INSERT INTO t2 VALUES(CURRENT_TIME(),CURRENT_TIME(),'2009-01-17'); +INSERT INTO t3 VALUES(CURRENT_TIME(),CURRENT_TIME(),'2009-01-17'); +INSERT INTO t4 VALUES(CURRENT_TIME(),CURRENT_TIME(),'2009-01-17'); + +# Other valid formats (single digit, zero hrs,mins,secs.) +INSERT INTO t1 VALUES('8:3:2','8:3:2','2009-01-18'),('1112','1112','2009-01-19'),(11,11,'2009-01-20'),('00:12:30','00:12:30','2009-01-23'),('9:00:45','9:00:45','2009-01-24'),('9:36:00','9:36:00','2009-01-25'); +INSERT INTO t2 VALUES('8:3:2','8:3:2','2009-01-18'),('1112','1112','2009-01-19'),(11,11,'2009-01-20'),('00:12:30','00:12:30','2009-01-23'),('9:00:45','9:00:45','2009-01-24'),('9:36:00','9:36:00','2009-01-25'); +INSERT INTO t3 VALUES('8:3:2','8:3:2','2009-01-18'),('1112','1112','2009-01-19'),(11,11,'2009-01-20'),('00:12:30','00:12:30','2009-01-23'),('9:00:45','9:00:45','2009-01-24'),('9:36:00','9:36:00','2009-01-25'); +INSERT INTO t4 VALUES('8:3:2','8:3:2','2009-01-18'),('1112','1112','2009-01-19'),(11,11,'2009-01-20'),('00:12:30','00:12:30','2009-01-23'),('9:00:45','9:00:45','2009-01-24'),('9:36:00','9:36:00','2009-01-25'); +# Outside range would be clipped to closest end point +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES('-850:00:00','-850:00:00','2009-01-21'); +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES('850:00:00','850:00:00','2009-01-21'); +DELETE FROM t1 WHERE c1='-838:59:59' AND c2='-838:59:59'; +DELETE FROM t1 WHERE c1='838:59:59' AND c2='838:59:59'; +INSERT INTO t1 VALUES('-850:00:00','-850:00:00','2009-01-21'),('850:00:00','850:00:00','2009-01-21'); + +# Insert invalid values +INSERT INTO t4 VALUES('10.22.22','10.22.22','2009-01-26'),(1234567,1234567,'2009-01-27'),(123456789,123456789,'2009-01-28'),(123456789.10,123456789.10,'2009-01-29'),('10 22:22','10 22:22','2009-01-30'),('12.45a','12.45a','2009-01-31'); + +# Insert permissible NULLs +INSERT INTO t1 VALUES('8:29:45',NULL,'2009-02-01'); +INSERT INTO t3 VALUES('8:29:45',NULL,'2009-02-01'); +INSERT INTO t4 VALUES('8:29:45',NULL,'2009-02-01'); + +# Insert duplicate NULLs to unique column +INSERT INTO t1(c1,c2) VALUES('9:30',NULL); +DELETE FROM t1 WHERE c1='9:30' AND c2 IS NULL; + +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT * FROM t4; + +# Now select using various table access methods (full table scan, range scan, index scan etc.) +## Full table scan ## +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t1; +--sorted_result +SELECT * FROM t1 WHERE c3 = '2009-01-17'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1 FROM t1; + +## Backward index scan, covering ## +SELECT c1 FROM t1 ORDER BY c1 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c1 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c1 DESC LIMIT 2; + +## ref type access +SELECT * FROM t1 WHERE c1 = '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 = '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 = '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 = '838:59:59' ORDER BY c1 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t1 WHERE c1 <> '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <> '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 > '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 > '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 >= '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 < '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 < '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 <= '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <= '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 <=> '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <=> '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t1 WHERE c1 <> '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <> '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 > '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 > '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 >= '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 < '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 < '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 <= '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <= '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 <=> '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <=> '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t1; +--sorted_result +SELECT * FROM t1 WHERE c3 = '2009-01-16'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1 FROM t1; + +## Backward index scan, covering ## +SELECT c1 FROM t1 ORDER BY c1 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c1 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c1 DESC LIMIT 2; + +## ref type access +SELECT * FROM t1 WHERE c1 = '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 = '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 = '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 = '00:00:00' ORDER BY c1 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t1 WHERE c1 <> '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <> '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 > '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 > '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 >= '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 < '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 < '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 <= '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <= '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 <=> '00:00:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 <=> '00:00:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t1 WHERE c1 <> '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <> '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 > '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 > '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 >= '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 < '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 < '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 <= '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <= '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 <=> '00:00:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 <=> '00:00:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IS NULL ORDER BY c1 DESC LIMIT 2; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 DESC; +SELECT * FROM t1 WHERE c1 IS NOT NULL ORDER BY c1 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t1; +--sorted_result +SELECT * FROM t1 WHERE c3 = '2009-01-15'; + +## Forward index scan, covering ## +--sorted_result +SELECT c2 FROM t1; + +## Backward index scan, covering ## +SELECT c2 FROM t1 ORDER BY c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t1 WHERE c2 = '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 = '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 = '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 = '-838:59:59' ORDER BY c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t1 WHERE c2 <> '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 <> '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 > '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 > '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 < '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 < '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 <= '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 <= '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 <=> '-838:59:59' ORDER BY c2; +SELECT * FROM t1 WHERE c2 <=> '-838:59:59' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c2; +SELECT * FROM t1 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c2; +SELECT * FROM t1 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t1 WHERE c2 <> '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <> '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 > '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 > '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 < '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 < '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 <= '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <= '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 <=> '-838:59:59' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <=> '-838:59:59' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t1; +--sorted_result +SELECT * FROM t1 WHERE c3 = '2009-01-11'; + +## Forward index scan, covering ## +--sorted_result +SELECT c2 FROM t1; + +## Backward index scan, covering ## +SELECT c2 FROM t1 ORDER BY c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t1 ORDER BY c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t1 WHERE c2 = NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 = NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 = NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 = NULL ORDER BY c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t1 WHERE c2 <> NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 <> NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 > NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 > NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 >= NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 >= NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 < NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 < NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 <= NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 <= NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 <=> NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 <=> NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c2; +SELECT * FROM t1 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IN (NULL,'10:22:33') ORDER BY c2; +SELECT * FROM t1 WHERE c2 IN (NULL,'10:22:33') ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c2; +SELECT * FROM t1 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t1 WHERE c2 <> NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <> NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 > NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 > NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 >= NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 >= NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 < NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 < NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 <= NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <= NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 <=> NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 <=> NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IN (NULL,'10:22:33') ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IN (NULL,'10:22:33') ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IS NULL ORDER BY c2 DESC LIMIT 2; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 DESC; +SELECT * FROM t1 WHERE c2 IS NOT NULL ORDER BY c2 DESC LIMIT 2; + +# Index-merge access +--sorted_result +SELECT * FROM t1 WHERE c1='838:59:59' OR c2='-838:59:59'; + +## Full table scan ## +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t2; +--sorted_result +SELECT * FROM t2 WHERE c3 = '2009-01-17'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t2; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t2 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t2 WHERE c1 = '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 = '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 = '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 = '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t2 WHERE c1 <> '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <> '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 > '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 > '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 >= '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 < '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 < '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 <= '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <= '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 <=> '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t2 WHERE c1 <> '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <> '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 > '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 > '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 >= '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 < '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 < '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 <= '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <= '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t2; +--sorted_result +SELECT * FROM t2 WHERE c3 = '2009-01-16'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t2; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t2 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t2 WHERE c1 = '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 = '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 = '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 = '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t2 WHERE c1 <> '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <> '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 > '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 > '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 < '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 < '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 <= '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <= '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 <=> '00:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t2 WHERE c1 <> '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <> '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 > '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 > '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 >= '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 < '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 < '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 <= '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <= '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t2; +--sorted_result +SELECT * FROM t2 WHERE c3 = '2009-01-15'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t2; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t2 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t2 WHERE c2 = '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 = '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 = '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 = '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t2 WHERE c2 <> '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 > '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 > '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 < '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 < '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <= '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t2 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 > '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 > '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 < '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 < '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t2; +--sorted_result +SELECT * FROM t2 WHERE c3 = '2009-01-11'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t2; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t2 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t2 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t2 WHERE c2 = NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 = NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 = NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 = NULL ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t2 WHERE c2 <> NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <> NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 > NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 > NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 >= NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 >= NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 < NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 < NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <= NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <= NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 <=> NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 <=> NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t2 WHERE c2 <> NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <> NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 > NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 > NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 >= NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 >= NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 < NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 < NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 <= NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <= NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 <=> NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 <=> NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t2 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t3; +--sorted_result +SELECT * FROM t3 WHERE c3 = '2009-01-17'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t3; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t3 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t3 WHERE c1 = '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 = '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 = '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 = '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t3 WHERE c1 <> '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <> '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 > '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 > '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 >= '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 < '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 < '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 <= '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <= '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 <=> '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t3 WHERE c1 <> '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <> '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 > '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 > '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 >= '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 < '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 < '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 <= '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <= '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <=> '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','838:59:59') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '838:59:59' AND c2 = '11:11:12' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT count(*) as total_rows, min(c1) as min_value, max(c1) FROM t3; +--sorted_result +SELECT * FROM t3 WHERE c3 = '2009-01-16'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t3; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t3 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t3 WHERE c1 = '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 = '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 = '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 = '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t3 WHERE c1 <> '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <> '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 > '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 > '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 < '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 < '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 <= '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <= '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 <=> '00:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t3 WHERE c1 <> '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <> '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 > '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 > '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 >= '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 < '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 < '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 <= '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <= '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 <=> '00:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 BETWEEN '00:00:00' AND '09:36:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IN ('00:00:00','09:36:00') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 >= '00:00:00' AND c1 < '09:36:00' AND c2 = '01:23:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c1 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t3; +--sorted_result +SELECT * FROM t3 WHERE c3 = '2009-01-15'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t3; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t3 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t3 WHERE c2 = '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 = '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 = '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 = '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t3 WHERE c2 <> '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 > '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 > '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 < '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 < '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 <= '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t3 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <> '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 > '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 > '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 < '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 < '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <= '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <=> '-838:59:59' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 BETWEEN '-838:59:59' AND '10:00:00' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IN ('-838:59:59','10:00:00') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 >= '-838:59:59' AND c2 < '10:00:00' AND c1 = '00:11:12' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; +## Full table scan ## +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT count(*) as total_rows, min(c2) as min_value, max(c2) FROM t3; +--sorted_result +SELECT * FROM t3 WHERE c3 = '2009-01-11'; + +## Forward index scan, covering ## +--sorted_result +SELECT c1,c2 FROM t3; + +## Backward index scan, covering ## +SELECT c1,c2 FROM t3 ORDER BY c1,c2 DESC; + +## Forward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 LIMIT 2; + +## Backward index scan, non-covering ## +SELECT * FROM t3 ORDER BY c1,c2 DESC LIMIT 2; + +## ref type access +SELECT * FROM t3 WHERE c2 = NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 = NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 = NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 = NULL ORDER BY c1,c2 DESC LIMIT 2; + +## Range access, ordered ## +SELECT * FROM t3 WHERE c2 <> NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <> NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 > NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 > NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 >= NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 >= NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 < NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 < NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 <= NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <= NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 <=> NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 <=> NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 LIMIT 2; + +## Range access, backwards scan ## +SELECT * FROM t3 WHERE c2 <> NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <> NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 > NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 > NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 >= NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 >= NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 < NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 < NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 <= NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <= NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 <=> NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 <=> NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 BETWEEN NULL AND '10:22:33' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IN (NULL,'10:22:33') ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 >= NULL AND c2 < '10:22:33' AND c1 = '491:22:33' ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IS NULL ORDER BY c1,c2 DESC LIMIT 2; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC; +SELECT * FROM t3 WHERE c2 IS NOT NULL ORDER BY c1,c2 DESC LIMIT 2; + +# Using index for group-by +--sorted_result +SELECT c1 FROM t3 GROUP BY c1; +--sorted_result +SELECT DISTINCT c1 FROM t3; +--sorted_result +SELECT c1,MIN(c2) FROM t3 GROUP BY c1; + +# Some more testing......... + +# These must return normal result +SELECT CAST(235959.123456 AS TIME); +SELECT CAST(0.235959123456e+6 AS TIME); +SELECT CAST(235959123456e-6 AS TIME); +# These must cut fraction part and produce warning +SELECT CAST(235959.1234567 AS TIME); +SELECT CAST(0.2359591234567e6 AS TIME); +# This must return NULL and produce warning +--replace_result 2.359591234567e+029 2.359591234567e+29 +SELECT CAST(0.2359591234567e+30 AS TIME); + +# Compare time values as strings +select cast('100:55:50' as time) < cast('24:00:00' as time); +select cast('100:55:50' as time) < cast('024:00:00' as time); +select cast('300:55:50' as time) < cast('240:00:00' as time); +select cast('100:55:50' as time) > cast('24:00:00' as time); +select cast('100:55:50' as time) > cast('024:00:00' as time); +select cast('300:55:50' as time) > cast('240:00:00' as time); +create table t5 (f1 time); +insert into t5 values ('24:00:00'); +select cast('24:00:00' as time) = (select f1 from t5); +drop table t5; +# Test Error conditions- PK constraint violation, Unique constraint violation + +# Insert duplicate value to pk column +--error ER_DUP_ENTRY +INSERT INTO t1(c1,c2) VALUES('10:22:33','10:22:34') /* throws error as row exists with c1='10:22:33' */; + +# Insert duplicate value to clustered pk, throws error +--error ER_DUP_ENTRY +INSERT INTO t2(c1,c2) VALUES('12:34:56.78','12:34:56.78') /* throws error as row exists with c1='12:34:56.78',c2='12:34:56.78' */; + +# Insert duplicate value to unique column, throws error +--error ER_DUP_ENTRY +INSERT INTO t1(c1,c2) VALUES('10:22:34','34 9:23') /* throws error as row exists with c2='34 9:23' */; + +# Insert duplicate value to clustered unique column, throws error +--error ER_DUP_ENTRY +INSERT INTO t3(c1,c2) VALUES('34 9:23','34 9:23') /* throws error as row exists with c1='34 9:23',c2='34 9:23' */; + +# Test 'INSERT IGNORE' with the same rows that reported constraint violation above +# Ignore pk constraint +INSERT IGNORE INTO t1(c1,c2) VALUES('10:22:33','10:22:34') /* doesn't throw error */; +INSERT IGNORE INTO t2(c1,c2) VALUES('12:34:56.78','12:34:56.78') /*doesn't throw error */; +# Ignore unique constraint +INSERT IGNORE INTO t1(c1,c2) VALUES('10:22:34','34 9:23') /*doesn't throw error */; +INSERT IGNORE INTO t3(c1,c2) VALUES('34 9:23','34 9:23') /*doesn't throw error */; +# Select + +# Test 'INSERT ON DUPLICATE KEY UPDATE' with PK one column/multi-column +SELECT * FROM t1 WHERE c1='10:23:33' /* no rows */; +INSERT INTO t1(c1) VALUES('10:22:33') ON DUPLICATE KEY UPDATE c1='10:23:33'; +SELECT * FROM t1 WHERE c1='10:23:33' /* 1 row */; +SELECT * FROM t2 WHERE c1='12:34:56.79' AND c2='12:34:57.78' /* no rows */; +INSERT INTO t2(c1,c2) VALUES('12:34:56.78','12:34:56.78') ON DUPLICATE KEY UPDATE c1='12:34:56.79',c2='12:34:57.78'; +SELECT * FROM t2 WHERE c1='12:34:56.79' AND c2='12:34:57.78' /* 1 row */; +# Test 'INSERT ON DUPLICATE KEY UPDATE' with unique one column/multi-column +SELECT * FROM t1 WHERE c1='10:22:35' AND c2='33 9:23' /* no rows */; +INSERT INTO t1(c1,c2) VALUES('10:22:34','34 9:23') ON DUPLICATE KEY UPDATE c1='10:22:35',c2='33 9:23'; +SELECT * FROM t1 WHERE c1='10:22:35' AND c2='33 9:23' /* 1 row */; +SELECT * FROM t3 WHERE c1='32 9:23' AND c2='33 9:23' /* no rows */; +INSERT INTO t3(c1,c2) VALUES('34 9:23','34 9:23') ON DUPLICATE KEY UPDATE c1='32 9:23',c2='33 9:23'; +SELECT * FROM t3 WHERE c1='32 9:23' AND c2='33 9:23' /* 1 row */; + +# Test 'INSERT SET' +INSERT INTO t1 SET c1='07:23:55',c2='13 06:23:55'; +INSERT INTO t2 SET c1='07:23:55',c2='13 06:23:55'; +INSERT INTO t3 SET c1='07:23:55'; +INSERT INTO t4 SET c2='07:23:55'; +SELECT * FROM t1 WHERE c1='07:23:55' AND c2='13 06:23:55' /* Returns 1 row with values for other column as NULL */; +SELECT * FROM t2 WHERE c1='07:23:55' AND c2='13 06:23:55' /* Returns 1 row with values for other column as NULL */; +SELECT * FROM t3 WHERE c1='07:23:55' /* Returns 1 row with values for other column as NULL */; +SELECT * FROM t4 WHERE c2='07:23:55' /* Returns 1 row with values for other column as NULL */; + +# Test 'INSERT INTO SELECT FROM' +CREATE TABLE t5(c1 TIME NOT NULL, c2 TIME NULL, c3 DATE, INDEX idx(c1,c2)); +INSERT INTO t5 SELECT * FROM t4; +SELECT * FROM t5; +TRUNCATE TABLE t5; +INSERT INTO t5 SELECT * FROM t4 WHERE c1 >='12colon34colon56'; +SELECT * FROM t5; +TRUNCATE TABLE t5; +DROP TABLE t5; +DROP TABLE t1,t2,t3,t4; +SET sql_mode=default; diff --git a/mysql-test/suite/tianchi/t/ctc_json_value.test b/mysql-test/suite/tianchi/t/ctc_json_value.test new file mode 100644 index 0000000..510329c --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_json_value.test @@ -0,0 +1,233 @@ +# JSON_VALUE with an implicit RETURNING clause (which returns +# CHAR(512) with utf8mb4 encoding). + +--disable_warnings +drop table if exists t1; +--enable_warnings + + +# create a table with index json_value without returning +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$')))); +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES('"asdf"'),('"dfgh"'),('"FghJ"'),('"fghj"'),('"hjkl"'); +ANALYZE TABLE t1; +--let $query = SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(10)) = 'fghj' +--eval EXPLAIN $query +--eval $query +--echo # The index is not used if the JSON_VALUE expressions differ. +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(11)) = 'fghj'; +SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(11)) = 'fghj'; +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$') = 'fghj'; +DROP TABLE t1; + + +# create a table with index json_value with returning char +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING CHAR(10))))); +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES('"asdf"'),('"dfgh"'),('"FghJ"'),('"fghj"'),('"hjkl"'); +ANALYZE TABLE t1; +--let $query = SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(10)) = 'fghj' +--eval EXPLAIN $query +--eval $query +--echo # The index is not used if the JSON_VALUE expressions differ. +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(11)) = 'fghj'; +SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(11)) = 'fghj'; +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$') = 'fghj'; +DROP TABLE t1; + + +# create a table with index json_value with returning charset +CREATE TABLE t1(j JSON, + KEY i1((JSON_VALUE(j, '$' RETURNING CHAR(10) CHARSET utf8mb4)))); +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES('"asdf"'),('"dfgh"'),('"FghJ"'),('"fghj"'),('"hjkl"'); +ANALYZE TABLE t1; +let $query = + SELECT * FROM t1 + WHERE JSON_VALUE(j, '$' RETURNING CHAR(10) CHARSET utf8mb4) = 'fghj'; +--eval EXPLAIN $query +--eval $query +--echo # The index is not used if the JSON_VALUE expressions differ. +SELECT * FROM t1 WHERE JSON_VALUE(j, '$' RETURNING CHAR(10) CHARSET latin1) = 'fghj'; +EXPLAIN SELECT * FROM t1 + WHERE JSON_VALUE(j, '$' RETURNING CHAR(10) CHARSET latin1) = 'fghj'; +DROP TABLE t1; + + +# create a table with index json_value to clob outline +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$.name' RETURNING CHAR(100)CHARSET utf8mb4)))); +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES('{"name":"First Primary School", "create_time":"2012-05-08", "classes": [{"name":"class 1", + "size":50, "teachers":{"teacher":"Master Zhang", "age":31}}, {"name":"class 2", "size":45, + "teachers":{"teacher":"Master Liu", "age":40}}]}'); +insert into t1 values('{"name":"First Primary School","create_time":"2012-05-08","year":38, + "classes":[{"name":"class 1","size":50,"teachers":{"teacher":"Master Zhang","age":31}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 3","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 4","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 5","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 6","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 7","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 8","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 9","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 10","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 11","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 12","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 13","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 14","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 15","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 16","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}, + {"name":"class 2","size":45,"teachers":{"teacher":"Master Liu","age":40}}]}'); +ANALYZE TABLE t1; +--let $query = SELECT * FROM t1 WHERE JSON_VALUE(j, '$.name' RETURNING CHAR(100)) = 'First Primary School' +--eval EXPLAIN $query +--eval $query +--echo # The index is not used if the JSON_VALUE expressions differ. +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$.name' RETURNING CHAR(100)) = 'First Primary School'; +EXPLAIN SELECT * FROM t1 WHERE JSON_VALUE(j, '$.name') = 'First Primary School'; +DROP TABLE t1; + + +# not supported json_value index +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING SIGNED)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING UNSIGNED)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING DECIMAL(3, 2))))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING FLOAT)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING DOUBLE)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING DATETIME)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING TIME)))); +--error 3655 +CREATE TABLE t1(j JSON, KEY i1((JSON_VALUE(j, '$' RETURNING DATE)))); \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_lcov.test b/mysql-test/suite/tianchi/t/ctc_lcov.test new file mode 100644 index 0000000..3d2d1c7 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_lcov.test @@ -0,0 +1,62 @@ +#补充代码覆盖率的简单测试用例,一定要追求速度,不要涉及过度复杂的测试用例 + +#ctc_ddl_tablespace.test为big-test,门禁里面不会跑,挑选里面的一些有代表性的测试用例,增加tablespace代码覆盖率 +create tablespace ts01 add datafile 'ts_01.ibd' autoextend_size=1M; +alter tablespace ts01 rename to ts01_new; +--error 3510 +alter tablespace ts01 autoextend_size = 64K; +alter tablespace ts01_new autoextend_size = 64K; +drop tablespace ts01_new; +# 测试datafile命名限制 +--error ER_WRONG_FILE_NAME +create tablespace ts04 add datafile 'ts_04' autoextend_size=1M; +#测试alter tablespace add drop datafile(innodb不支持这两种操作,tse对标innodb需要进行禁止) +create tablespace ts01 add datafile 'ts_01.ibd' autoextend_size=1M; +--error ER_CHECK_NOT_IMPLEMENTED +alter tablespace ts01 add datafile 'ts_02.ibd' autoextend_size=4M; +--error ER_CHECK_NOT_IMPLEMENTED +alter tablespace ts01 drop datafile 'ts_01.ibd'; +drop tablespace ts01; + +select @@global.max_connections into @ctc_saved_max_connections; +--error 3655 +set global max_connections=0; +--error 3655 +set global max_connections=10000; +--error 1229 +SET session super_read_only= 1; +--error 1229 +SET session super_read_only= 0; +set @ctc_ddl_enabled=true; + + +create user test_user; +drop user test_user; +set @ctc_dcl_disabled=1; +--error 3655 +create user test_user; +set @ctc_dcl_disabled=0; + +set global ctc_stats_enabled=ON; +show engine ctc status; +create table t1(i int); +insert into t1 value(123); +set debug = '+d, non_metadata_normalization'; +lock table t1 write; +unlock tables; +set debug = '-d, non_metadata_normalization'; +set sort_buffer_size = (select i from t1); +drop table t1; +set global ctc_stats_enabled=OFF; +set global max_connections=101; +set global max_connections=default; +set global autocommit=false; +set global autocommit=true; +CREATE TEMPORARY TABLE t_processlist AS SELECT ID FROM information_schema.processlist; +DROP TABLE t_processlist; +create table t1(a blob default("test")); +alter table t1 add column b varchar(10) default ("test"); +alter table t1 add column b1 varchar(10) default "test"; +alter table t1 add column c bit default ("10"); +alter table t1 add column d bit default (10); +drop table t1; diff --git a/mysql-test/suite/tianchi/t/ctc_link_and_migr_row.test b/mysql-test/suite/tianchi/t/ctc_link_and_migr_row.test new file mode 100644 index 0000000..5d379b3 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_link_and_migr_row.test @@ -0,0 +1,349 @@ +#### test case come from daac codebase gs_row_chain.sql, only part of it pick up to here +#### remember if table column is too long or column size to big, to pick new case from gs_row_chain.sql +#### 链接行: +#### 1、当行数据大于PCRH_MAX_ROW_SIZE:8050(pcrh表)或者HEAP_MAX_ROW_SIZE:8040(堆表),插入时会产生链接行 +#### 2、更新数据时,如果行数据变大达到条件1的情况,也会产生链接行 +#### 行迁移: +#### 1、当更新行数据时,新增的行数据大小ua->inc_size > 0 && ua->inc_size > page->free_size + itl->fsc时,产生行迁移 + +--disable_warnings +DROP TABLE IF EXISTS ROW_CHAIN_TABLE; +--enable_warnings + +set autocommit = 0; +CREATE TABLE ROW_CHAIN_TABLE(ID INT,A VARCHAR(8000),B VARCHAR(8000),C VARCHAR(8000),D VARCHAR(8000)) ENGINE=CTC DEFAULT CHARSET=ascii; +COMMIT; + +--echo ######## UNDO_HEAP_UPDATE_FULL_COLUMNS WITHOUT PRIMAYR KEY INDEX +--echo ######## test case 1, UPDATE_INPLACE(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(1,LPAD('A',8000,'A'),LPAD('B',8000,'B'),LPAD('C',8000,'C'),'D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=1; +UPDATE ROW_CHAIN_TABLE SET ID=1,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D='X' WHERE ID=1; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=1; +COMMIT; + +--echo ######## test case 2, UPDATE_INPAGE(CHAIN->CHAIN) +UPDATE ROW_CHAIN_TABLE SET ID=2,A=LPAD('U',3000,'U'),B=LPAD('V',2000,'V'),C=LPAD('W',3000,'W'),D='X' WHERE ID=1; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=2; +COMMIT; + +--echo ######## test case 3, UPDATE_MIGR(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(3,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=3; +UPDATE ROW_CHAIN_TABLE SET ID=3,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D=LPAD('X',8000,'X') WHERE ID=3; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=3; +COMMIT; + +--echo ######## test case 4, UPDATE_MIGR(NORMAL->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(4,'A','B','C','D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=4; +UPDATE ROW_CHAIN_TABLE SET ID=4,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D=LPAD('X',8000,'X') WHERE ID=4; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=4; +COMMIT; + +--echo ######## test case 5, UPDATE_MIGR(CHAIN->NORMAL) +INSERT INTO ROW_CHAIN_TABLE VALUES(5,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=5; +UPDATE ROW_CHAIN_TABLE SET ID=5,A='A',B='B',C='C',D='D' WHERE ID=5; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=5; +COMMIT; + +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=1; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=2; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=3; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=4; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=5; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## UNDO_HEAP_UPDATE_PART_COLUMNS WITHOUT PRIMAYR KEY INDEX +--echo ######## test case 6, UPDATE_INPLACE(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(6,LPAD('A',8000,'A'),LPAD('B',3000,'B'),LPAD('C',8000,'C'),'D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=6; +UPDATE ROW_CHAIN_TABLE SET ID=6,A=LPAD('U',8000,'U'),C=LPAD('W',8000,'W'),D='X' WHERE ID=6; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=6; +COMMIT; + +--echo ######## test case 7, UPDATE_INPAGE(CHAIN->CHAIN) +UPDATE ROW_CHAIN_TABLE SET ID=7,A=LPAD('U',3000,'U'),B=LPAD('V',2000,'V'),D='X' WHERE ID=6; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=7; +COMMIT; + +--echo ######## test case 8, UPDATE_MIGR(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(8,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=8; +UPDATE ROW_CHAIN_TABLE SET ID=8,B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W') WHERE ID=8; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=8; +COMMIT; + +--echo ######## test case 9, UPDATE_MIGR(NORMAL->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(9,'A','B','C','D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=9; +UPDATE ROW_CHAIN_TABLE SET ID=9,B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W') WHERE ID=9; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=9; +COMMIT; + +--echo ######## test case 10, UPDATE_MIGR(CHAIN->NORMAL) +INSERT INTO ROW_CHAIN_TABLE VALUES(10,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=10; +UPDATE ROW_CHAIN_TABLE SET ID=10,A='A',B='B',C='C',D='D' WHERE ID=10; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=10; +COMMIT; + +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=6; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=7; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=8; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=9; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=10; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## test case 11, ADD COLUMN WITHOUT PRIMAYR KEY INDEX +INSERT INTO ROW_CHAIN_TABLE VALUES(11,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +ALTER TABLE ROW_CHAIN_TABLE ADD COLUMN E VARCHAR(8000); +UPDATE ROW_CHAIN_TABLE SET E=LPAD('E',8000,'E') WHERE ID=11; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID > 10; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=11; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +DROP TABLE ROW_CHAIN_TABLE; +COMMIT; + + + +CREATE TABLE ROW_CHAIN_TABLE(ID INT PRIMARY KEY,A VARCHAR(8000),B VARCHAR(8000),C VARCHAR(8000),D VARCHAR(8000)) ENGINE=CTC DEFAULT CHARSET=ascii; +COMMIT; + +--echo ######## UNDO_HEAP_UPDATE_FULL_COLUMNS WITH PRIMAYR KEY INDEX +--echo ######## test case 1, UPDATE_INPLACE(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(1,LPAD('A',8000,'A'),LPAD('B',8000,'B'),LPAD('C',8000,'C'),'D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=1; +UPDATE ROW_CHAIN_TABLE SET ID=1,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D='X' WHERE ID=1; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=1; +COMMIT; + +--echo ######## test case 2, UPDATE_INPAGE(CHAIN->CHAIN) +UPDATE ROW_CHAIN_TABLE SET ID=2,A=LPAD('U',3000,'U'),B=LPAD('V',2000,'V'),C=LPAD('W',3000,'W'),D='X' WHERE ID=1; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=2; +COMMIT; + +--echo ######## test case 3, UPDATE_MIGR(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(3,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=3; +UPDATE ROW_CHAIN_TABLE SET ID=3,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D=LPAD('X',8000,'X') WHERE ID=3; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=3; +COMMIT; + +--echo ######## test case 4, UPDATE_MIGR(NORMAL->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(4,'A','B','C','D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=4; +UPDATE ROW_CHAIN_TABLE SET ID=4,A=LPAD('U',8000,'U'),B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W'),D=LPAD('X',8000,'X') WHERE ID=4; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=4; +COMMIT; + +--echo ######## test case 5, UPDATE_MIGR(NORMAL->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(5,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=5; +UPDATE ROW_CHAIN_TABLE SET ID=5,A='A',B='B',C='C',D='D' WHERE ID=5; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=5; +COMMIT; + +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=1; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=2; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=3; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=4; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=5; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## UNDO_HEAP_UPDATE_PART_COLUMNS WITH PRIMAYR KEY INDEX +--echo ######## test case 6, UPDATE_INPLACE(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(6,LPAD('A',8000,'A'),LPAD('B',3000,'B'),LPAD('C',8000,'C'),'D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=6; +UPDATE ROW_CHAIN_TABLE SET ID=6,A=LPAD('U',8000,'U'),C=LPAD('W',8000,'W'),D='X' WHERE ID=6; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=6; +COMMIT; + +--echo ######## test case 7, UPDATE_INPAGE(CHAIN->CHAIN) +UPDATE ROW_CHAIN_TABLE SET ID=7,A=LPAD('U',3000,'U'),B=LPAD('V',2000,'V'),D='X' WHERE ID=6; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=7; +COMMIT; + +--echo ######## test case 8, UPDATE_MIGR(CHAIN->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(8,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=8; +UPDATE ROW_CHAIN_TABLE SET ID=8,B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W') WHERE ID=8; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=8; +COMMIT; + +--echo ######## test case 9, UPDATE_MIGR(NORMAL->CHAIN) +INSERT INTO ROW_CHAIN_TABLE VALUES(9,'A','B','C','D'); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=9; +UPDATE ROW_CHAIN_TABLE SET ID=9,B=LPAD('V',8000,'V'),C=LPAD('W',8000,'W') WHERE ID=9; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=9; +COMMIT; + +--echo ######## test case 10, UPDATE_MIGR(CHAIN->NORMAL) +INSERT INTO ROW_CHAIN_TABLE VALUES(10,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=10; +UPDATE ROW_CHAIN_TABLE SET ID=10,A='A',B='B',C='C',D='D' WHERE ID=10; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID=10; +COMMIT; + +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=6; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=7; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=8; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=9; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=10; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## test case 11, ADD COLUMN WITH PRIMAYR KEY INDEX +INSERT INTO ROW_CHAIN_TABLE VALUES(11,LPAD('A',8000,'A'),'B','C',LPAD('D',8000,'D')); +ALTER TABLE ROW_CHAIN_TABLE ADD COLUMN E VARCHAR(8000); +UPDATE ROW_CHAIN_TABLE SET E=LPAD('E',8000,'E') WHERE ID=11; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID > 8; +DELETE FROM ROW_CHAIN_TABLE WHERE ID=11; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT COUNT(*) FROM ROW_CHAIN_TABLE; +COMMIT; + +DROP TABLE ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## LINK AND MIGR ROW OTHER CASES +--echo ######## test case 1: COLUMN > 12 WITHOUT PRIMARY KEY +CREATE TABLE ROW_CHAIN_TABLE( +ID INT, +C_SERIAL INT, +C_DOUBLE INT, +C_FLOAT FLOAT, +C_INT INT, +C_INTEGER INTEGER, C_BIGINT INT, C_REAL REAL, C_NUMERIC INT, C_NUMERIC_PARM INT, C_NUMBER INT, C_NUMBER_PARM INT, C_DECIMAL DECIMAL, C_DECIMAL_PARM DECIMAL(5,2), C_BOOL CHAR(1), +C_CLOB VARCHAR(20), C_BLOB VARCHAR(20), +C_CHAR CHAR, C_CHAR1 CHAR(1), C_CHAR20 CHAR(20), C_CHAR4000 CHAR(255), +C_VARCHAR VARCHAR(4000), C_VARCHAR1 VARCHAR(1), C_VARCHAR20 VARCHAR(20), C_VARCHAR4000 VARCHAR(4000), +C_VARCHAR2 VARCHAR(20), C_VARCHAR21 VARCHAR(1), C_VARCHAR220 VARCHAR(20), C_VARCHAR24000 VARCHAR(4000), +C_RAW VARCHAR(20), C_RAW1 VARCHAR(1), C_RAW20 VARCHAR(20), C_RAW4000 VARCHAR(4000), +C_BINARY VARCHAR(20), C_BINARY1 VARCHAR(1), C_BINARY20 VARCHAR(20), C_BINARY4000 VARCHAR(4000), +C_VARBINARY VARCHAR(20), C_VARBINARY1 VARCHAR(1), C_VARBINARY20 VARCHAR(20), C_VARBINARY4000 VARCHAR(4000), +C_DATE DATE, C_DATETIME DATE, +C_TIMESTAMP TIMESTAMP, C_TIMESTAMP3 TIMESTAMP(3), C_TIMESTAMP6 TIMESTAMP(6), +C_TIMESTAMP_WTZ TIMESTAMP, C_TIMESTAMP_WTZ3 TIMESTAMP(3), C_TIMESTAMP_WTZ6 TIMESTAMP(6), +C_INTERVAL VARCHAR(20), +C_BYTEA VARCHAR(20) +) ENGINE=CTC DEFAULT CHARSET=ascii; +INSERT INTO ROW_CHAIN_TABLE VALUES( 12, -1727922176, 1494155264, 1.1, -1644429312, 733741056, 1650917376, -1717305344, -1141374976, 1827471360, -357040128, -1113063424, 7.7, 8.8, 'W', 'MTVYCNFQDRSKGB', 'IMTVYC', 'B', 'N', 'BIMTVYCNFQ', LPAD('EBIMTVYCNF',255,'EBIMTVYCNF'), LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'), 'P', 'LUEBIMTV', LPAD('EBIMTVYCNF',2000,'EBIMTVYCNF'), +'SDLUEBIMTVYCN', 'K', 'TSDL', LPAD('EBIMTVYCNF',3000,'EBIMTVYCNF'),'ZZTSDLUEBIMTVYCNFQD', 'K', 'BZZTS', LPAD('EBIMTVYCNF',3000,'EBIMTVYCNF'), 'Z', 'D', 'XZFBZ', LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'), 'A', 'I', 'MAJXZFBZZTSDLUEBIMTV', LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'),NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'MD', 'FMDMAJXZFB' ); +SELECT * FROM ROW_CHAIN_TABLE; +UPDATE ROW_CHAIN_TABLE SET ID=12,C_CHAR4000='A',C_BINARY4000='B' WHERE ID=12; +SELECT * FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT * FROM ROW_CHAIN_TABLE; +COMMIT; +DROP TABLE ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## test case 2: COLUMN > 12 WITH PRIMARY KEY +CREATE TABLE ROW_CHAIN_TABLE( +ID INT PRIMARY KEY, +C_SERIAL INT, +C_DOUBLE INT, +C_FLOAT FLOAT, +C_INT INT, +C_INTEGER INTEGER, C_BIGINT INT, C_REAL REAL, C_NUMERIC INT, C_NUMERIC_PARM INT, C_NUMBER INT, C_NUMBER_PARM INT, C_DECIMAL DECIMAL, C_DECIMAL_PARM DECIMAL(5,2), C_BOOL CHAR(1), +C_CLOB VARCHAR(20), C_BLOB VARCHAR(20), +C_CHAR CHAR, C_CHAR1 CHAR(1), C_CHAR20 CHAR(20), C_CHAR4000 CHAR(255), +C_VARCHAR VARCHAR(4000), C_VARCHAR1 VARCHAR(1), C_VARCHAR20 VARCHAR(20), C_VARCHAR4000 VARCHAR(4000), +C_VARCHAR2 VARCHAR(20), C_VARCHAR21 VARCHAR(1), C_VARCHAR220 VARCHAR(20), C_VARCHAR24000 VARCHAR(4000), +C_RAW VARCHAR(20), C_RAW1 VARCHAR(1), C_RAW20 VARCHAR(20), C_RAW4000 VARCHAR(4000), +C_BINARY VARCHAR(20), C_BINARY1 VARCHAR(1), C_BINARY20 VARCHAR(20), C_BINARY4000 VARCHAR(4000), +C_VARBINARY VARCHAR(20), C_VARBINARY1 VARCHAR(1), C_VARBINARY20 VARCHAR(20), C_VARBINARY4000 VARCHAR(4000), +C_DATE DATE, C_DATETIME DATE, +C_TIMESTAMP TIMESTAMP, C_TIMESTAMP3 TIMESTAMP(3), C_TIMESTAMP6 TIMESTAMP(6), +C_TIMESTAMP_WTZ TIMESTAMP, C_TIMESTAMP_WTZ3 TIMESTAMP(3), C_TIMESTAMP_WTZ6 TIMESTAMP(6), +C_INTERVAL VARCHAR(20), +C_BYTEA VARCHAR(20) +) ENGINE=CTC DEFAULT CHARSET=ascii; +INSERT INTO ROW_CHAIN_TABLE VALUES( 12, -1727922176, 1494155264, 1.1, -1644429312, 733741056, 1650917376, -1717305344, -1141374976, 1827471360, -357040128, -1113063424, 7.7, 8.8, 'W', 'MTVYCNFQDRSKGB', 'IMTVYC', 'B', 'N', 'BIMTVYCNFQ', LPAD('EBIMTVYCNF',255,'EBIMTVYCNF'), LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'), 'P', 'LUEBIMTV', LPAD('EBIMTVYCNF',2000,'EBIMTVYCNF'), +'SDLUEBIMTVYCN', 'K', 'TSDL', LPAD('EBIMTVYCNF',3000,'EBIMTVYCNF'),'ZZTSDLUEBIMTVYCNFQD', 'K', 'BZZTS', LPAD('EBIMTVYCNF',3000,'EBIMTVYCNF'), 'Z', 'D', 'XZFBZ', LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'), 'A', 'I', 'MAJXZFBZZTSDLUEBIMTV', LPAD('EBIMTVYCNF',4000,'EBIMTVYCNF'),NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'MD', 'FMDMAJXZFB' ); +SELECT * FROM ROW_CHAIN_TABLE; +UPDATE ROW_CHAIN_TABLE SET ID=12,C_CHAR4000='A',C_BINARY4000='B' WHERE ID=12; +SELECT * FROM ROW_CHAIN_TABLE; +ROLLBACK; +SELECT * FROM ROW_CHAIN_TABLE; +COMMIT; +DROP TABLE ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## test case 3: create index +CREATE TABLE ROW_CHAIN_TABLE(ID INT, C1 VARCHAR(4000), C2 VARCHAR(4000), C3 VARCHAR(4000), C4 VARCHAR(4000), C5 VARCHAR(4000), C6 VARCHAR(4000), C7 VARCHAR(4000), C8 VARCHAR(3000)) ENGINE=CTC DEFAULT CHARSET=ascii; +CREATE INDEX IX_RC ON ROW_CHAIN_TABLE(ID); +INSERT INTO ROW_CHAIN_TABLE VALUES(1, LPAD('X', 2000, 'X'), LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X'),LPAD('X', 2000, 'X')); +COMMIT; +UPDATE ROW_CHAIN_TABLE SET ID = 100, C1=LPAD('X', 2000, 'X'), C2=LPAD('Y', 3000, 'Y'), C3=LPAD('Z', 2000,'Z'); +COMMIT; +SELECT * FROM ROW_CHAIN_TABLE WHERE ID = 100; +COMMIT; +DROP TABLE ROW_CHAIN_TABLE; +COMMIT; + +--echo ######## test case 4: UPDATE ROW FOR MATCH MIGR ROW CONDITION WITHOUT INDEX +CREATE TABLE ROW_MIGR_TABLE(ID INT,A INT,B VARCHAR(8000)) ENGINE=CTC DEFAULT CHARSET=ascii; +INSERT INTO ROW_MIGR_TABLE VALUES(1, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(2, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(3, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(4, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(5, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(6, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(7, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(8, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(9, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(10, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(11, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(12, 1, NULL); +COMMIT; +UPDATE ROW_MIGR_TABLE SET B=LPAD('M',7840,'M') WHERE ID=1; # DONT CHANGE THE COLUMN SIZE +SELECT * FROM ROW_MIGR_TABLE WHERE ID=1; +COMMIT; +DROP TABLE ROW_MIGR_TABLE; +COMMIT; + +--echo ######## test case 5: UPDATE ROW FOR MATCH MIGR ROW CONDITION WITH INDEX +CREATE TABLE ROW_MIGR_TABLE(ID INT PRIMARY KEY,A INT,B VARCHAR(8000)) ENGINE=CTC DEFAULT CHARSET=ascii; +INSERT INTO ROW_MIGR_TABLE VALUES(1, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(2, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(3, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(4, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(5, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(6, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(7, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(8, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(9, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(10, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(11, 1, NULL); +INSERT INTO ROW_MIGR_TABLE VALUES(12, 1, NULL); +COMMIT; +UPDATE ROW_MIGR_TABLE SET B=LPAD('M',7840,'M') WHERE ID=1; # DONT CHANGE THE COLUMN SIZE +SELECT * FROM ROW_MIGR_TABLE WHERE ID=1; +COMMIT; +DROP TABLE ROW_MIGR_TABLE; +COMMIT; + +set autocommit = 1; diff --git a/mysql-test/suite/tianchi/t/ctc_lock_instance.test b/mysql-test/suite/tianchi/t/ctc_lock_instance.test new file mode 100644 index 0000000..e2a9e70 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_lock_instance.test @@ -0,0 +1,23 @@ +# test for lock/unlock instance +LOCK INSTANCE FOR BACKUP; +--error ER_DISALLOWED_OPERATION +set global ctc_db_datafile_size=32; +--error ER_DISALLOWED_OPERATION +create database test; +--error ER_DISALLOWED_OPERATION +create table DEMO(id int); +FLUSH NO_WRITE_TO_BINLOG BINARY LOGS; +set session ctc_sampling_ratio=90; +set session ctc_sampling_ratio=100; +UNLOCK INSTANCE; +SET SESSION wait_timeout=2147483; +SET SESSION lock_wait_timeout=31536000; +SET SESSION autocommit=1; +SET NAMES utf8; +LOCK INSTANCE FOR BACKUP; +SET SESSION wait_timeout=2147483; +SET SESSION lock_wait_timeout=31536000; +SET SESSION autocommit=1; +SET NAMES utf8; +UNLOCK INSTANCE; +set @ctc_ddl_enabled=true; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_locking_read_concurrency_with_nowait_and_skip_locked.test b/mysql-test/suite/tianchi/t/ctc_locking_read_concurrency_with_nowait_and_skip_locked.test new file mode 100644 index 0000000..6854e6d --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_locking_read_concurrency_with_nowait_and_skip_locked.test @@ -0,0 +1,62 @@ +######################################################################## +# # +# Testing of Locking Read Concurrency with NOWAIT and SKIP LOCKED # +# # +######################################################################## + +connect (con1,localhost,root,,); + +# init +--echo connection default +connection default; + +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +CREATE TABLE t1 (id INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (id INT PRIMARY KEY); +INSERT INTO t2 VALUES (1),(2); +COMMIT; + +# table t1 without index +--echo start test case1 +START TRANSACTION; +select * from t1 where id = 1 for update; + +--echo connection con1 +connection con1; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +START TRANSACTION; +--error 1205 +select * from t1 for update; +select * from t1 for update skip locked; +--error 3572 +select * from t1 for update nowait; +commit; + +--echo connection default +connection default; +commit; + +# table t2 with index +--echo start test case2 +START TRANSACTION; +select * from t2 where id = 1 for update; + +--echo connection con1 +connection con1; +START TRANSACTION; +--error 1205 +select * from t2 for update; +select * from t2 for update skip locked; +--error 3572 +select * from t2 for update nowait; +commit; + +--echo connection default +connection default; +commit; + +# Cleanup +disconnect con1; +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/suite/tianchi/t/ctc_partition_update.test b/mysql-test/suite/tianchi/t/ctc_partition_update.test new file mode 100644 index 0000000..d18bfa2 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_partition_update.test @@ -0,0 +1,103 @@ +# 普通表测试 +--disable_warnings +drop database if exists db1; +--enable_warnings +create database db1; +create table db1.t1(a int , b int); +delete from db1.t1; +insert into db1.t1 values(0,0),(1,1),(2,2),(3,3),(4,4),(5,5); +update db1.t1 set a = 11 where a = 1; +select * from db1.t1 where a = 11; +update db1.t1 set a = 22 where a = 2; +select * from db1.t1 where a = 22; +update db1.t1 set a = 33 where a = 3; +select * from db1.t1 where a = 33; +update db1.t1 set a = 44 where a = 4; +select * from db1.t1 where a = 44; +update db1.t1 set a = 55 where a = 5; +select * from db1.t1 where a = 55; +update db1.t1 set a = 123 where a = 0; +select * from db1.t1 where a = 123; +# 哈希分区测试 +create table db1.t2(a int , b int) partition by hash(a) partitions 5; +delete from db1.t2; +insert into db1.t2 values(0,0),(1,1),(2,2),(3,3),(4,4),(5,5); +update db1.t2 set a = 11 where a = 1; +select * from db1.t2 where a = 11; +update db1.t2 set a = 22 where a = 2; +select * from db1.t2 where a = 22; +update db1.t2 set a = 33 where a = 3; +select * from db1.t2 where a = 33; +update db1.t2 set a = 44 where a = 4; +select * from db1.t2 where a = 44; +update db1.t2 set a = 55 where a = 5; +select * from db1.t2 where a = 55; +update db1.t2 set a = 123 where a = 0; +select * from db1.t2 where a = 123; +# range分区测试 +create table db1.t3 (a int, b int) partition by range (a) +( + partition p0 values less than (10), + partition p1 values less than (20), + partition p2 values less than (30), + partition p3 values less than (40), + partition p4 values less than (50) +); +delete from db1.t3; +insert into db1.t3 values(0,0),(1,1),(11,11),(21,21),(31,31),(41,41); +update db1.t3 set a = 2 where a = 1; +select * from db1.t3 where a = 2; +update db1.t3 set a = 12 where a = 11; +select * from db1.t3 where a = 12; +update db1.t3 set a = 22 where a = 21; +select * from db1.t3 where a = 22; +update db1.t3 set a = 32 where a = 31; +select * from db1.t3 where a = 32; +update db1.t3 set a = 42 where a = 41; +select * from db1.t3 where a = 42; +update db1.t3 set a = 18 where a = 0; +select * from db1.t3 where a = 18; +# list分区测试 +create table db1.t4 (a int, b int) partition by list (a) +( + partition p0 values in (0, 10, 20, 30), + partition p1 values in (1, 11, 21, 31), + partition p2 values in (2, 12, 22, 32), + partition p3 values in (3, 13, 23, 33), + partition p4 values in (4, 14, 24, 34) +); +delete from db1.t4; +insert into db1.t4 values(0,0),(1,1),(2,2),(3,3),(4,4); +update db1.t4 set a = 11 where a = 1; +select * from db1.t4 where a = 11; +update db1.t4 set a = 12 where a = 2; +select * from db1.t4 where a = 12; +update db1.t4 set a = 13 where a = 3; +select * from db1.t4 where a = 13; +update db1.t4 set a = 14 where a = 4; +select * from db1.t4 where a = 14; +update db1.t4 set a = 34 where a = 0; +select * from db1.t4 where a = 34; +drop table db1.t1; +drop table db1.t2; +drop table db1.t3; +drop table db1.t4; + +create table db1.t1 +( + id int unsigned auto_increment, + time datetime not null, + first_name varchar(40), + last_name varchar(50), + primary key (id, time), + index first_index (first_name), + index last_index (last_name) +) engine=CTC partition by range (to_days(time)) ( + partition p1 values less than (to_days('2007-02-07')), + partition p2 values less than (to_days('2007-02-08')), + partition p3 values less than MAXVALUE +); +insert into db1.t1 (time, first_name, last_name) values ('2007-02-07', 'Q', 'Robert'); +SELECT * FROM db1.t1 WHERE first_name='Andy' OR last_name='Jake'; +drop table db1.t1; +drop database db1; diff --git a/mysql-test/suite/tianchi/t/ctc_read_only.test b/mysql-test/suite/tianchi/t/ctc_read_only.test new file mode 100644 index 0000000..bd4d039 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_read_only.test @@ -0,0 +1,270 @@ +--disable_warnings +DROP TABLE IF EXISTS table_11733 ; +--enable_warnings + +set @orig_sql_mode= @@sql_mode; +create user test@localhost; +grant CREATE, INSERT, SELECT, DROP on *.* to test@localhost; + +connect (con1,localhost,test,,test); + +connection default; +set global read_only=0; + +# Any transactional engine will do +create table table_11733 (a int); + +connection con1; +BEGIN; +insert into table_11733 values(11733); + +connection default; +set global read_only=1; + +connection con1; +select @@global.read_only; +select * from table_11733 ; +--error 1290 +COMMIT; + +connection default; +set global read_only=0; +connection con1; +COMMIT; +connection default; +drop table table_11733 ; +drop user test@localhost; + +disconnect con1; + +CREATE USER test@localhost; +GRANT CREATE, SELECT, DROP ON *.* TO test@localhost; +connect(con1, localhost, test, , test); + +connection default; +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (0), (1); +SET GLOBAL read_only=1; + +connection con1; +SELECT * FROM t1; +BEGIN; +SELECT * FROM t1; +COMMIT; + +connection default; +SET GLOBAL read_only=0; + +FLUSH TABLES WITH READ LOCK; +connection con1; +SELECT * FROM t1; +BEGIN; +SELECT * FROM t1; +COMMIT; + +connection default; +UNLOCK TABLES; +DROP TABLE t1; +DROP USER test@localhost; + +disconnect con1; + + +--disable_warnings +DROP DATABASE IF EXISTS db1; +--enable_warnings + +--echo # Setup user and tables +CREATE USER bug33669@localhost; +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +CREATE TABLE db1.t2 (a INT); +INSERT INTO db1.t1 VALUES (1); +INSERT INTO db1.t2 VALUES (2); +GRANT CREATE TEMPORARY TABLES, DROP, INSERT, DELETE, UPDATE, + SELECT, LOCK TABLES ON db1.* TO bug33669@localhost; +SET GLOBAL READ_ONLY = ON; +connect(con1,localhost,bug33669,,db1); + +CREATE TEMPORARY TABLE temp (a INT); +INSERT INTO temp VALUES (1); +DROP TABLE temp; + + +CREATE TEMPORARY TABLE temp (a INT); +LOCK TABLES t1 READ, t2 READ; +SELECT * FROM t1; +INSERT INTO temp values (1); +SELECT * FROM t2; +UNLOCK TABLES; +DROP TABLE temp; + +BEGIN; +SELECT * FROM t1; +CREATE TEMPORARY TABLE temp (a INT); +--error ER_OPTION_PREVENTS_STATEMENT +INSERT INTO t1 VALUES (1); +INSERT INTO temp VALUES (1); +SELECT * FROM t2; +ROLLBACK; +SELECT * FROM temp; +DROP TABLE temp; + + +CREATE TEMPORARY TABLE temp (a INT); +LOCK TABLES t1 READ, temp WRITE; +SELECT * FROM t1; +SELECT * FROM temp; +--error ER_OPTION_PREVENTS_STATEMENT +INSERT INTO t1 VALUES (1); +INSERT INTO temp VALUES (1); +DROP TABLE temp; +UNLOCK TABLES; + +CREATE TEMPORARY TABLE t1 (a INT); +LOCK TABLES t1 WRITE; +DROP TABLE t1; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t1; + +CREATE TEMPORARY TABLE temp1 (a INT); +CREATE TEMPORARY TABLE temp2 LIKE temp1; +BEGIN; +INSERT INTO temp1 VALUES (10); +INSERT INTO temp2 VALUES (10); +INSERT INTO temp1 SELECT * FROM t1; +INSERT INTO temp2 SELECT * FROM t2; +SELECT * FROM temp1 ORDER BY a; +SELECT * FROM temp2 ORDER BY a; +ROLLBACK; +SELECT * FROM temp1,temp2; +LOCK TABLES t1 READ, t2 READ; +INSERT INTO temp1 VALUES (10); +INSERT INTO temp2 VALUES (10); +INSERT INTO temp1 SELECT * FROM t1; +INSERT INTO temp2 SELECT * FROM t2; +SELECT * FROM temp1 ORDER BY a; +SELECT * FROM temp2 ORDER BY a; +UNLOCK TABLES; +DELETE temp1, temp2 FROM temp1, temp2; +INSERT INTO temp1 VALUES (10); +INSERT INTO temp2 VALUES (10); +INSERT INTO temp1 SELECT * FROM t1; +INSERT INTO temp2 SELECT * FROM t2; +SELECT * FROM temp1 ORDER BY a; +SELECT * FROM temp2 ORDER BY a; +DROP TABLE temp1, temp2; + +CREATE TEMPORARY TABLE temp1 (a INT); +CREATE TEMPORARY TABLE temp2 LIKE temp1; +INSERT INTO temp1 (a) VALUES ((SELECT MAX(a) FROM t1)); +LOCK TABLES t2 READ; +INSERT INTO temp2 (a) VALUES ((SELECT MAX(a) FROM t2)); +UNLOCK TABLES; +LOCK TABLES t1 READ, t2 READ; +INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2); +INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1); +UNLOCK TABLES; +INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2); +INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1); +SELECT * FROM temp1 ORDER BY a; +SELECT * FROM temp2 ORDER BY a; +DROP TABLE temp1, temp2; + +CREATE TEMPORARY TABLE temp1 (a INT); +CREATE TEMPORARY TABLE temp2 LIKE temp1; +INSERT INTO temp1 VALUES (1),(2); +INSERT INTO temp2 VALUES (3),(4); +UPDATE temp1,temp2 SET temp1.a = 5, temp2.a = 10; +SELECT * FROM temp1, temp2; +DROP TABLE temp1, temp2; + +disconnect con1; +connection default; +SET GLOBAL READ_ONLY = OFF; +DROP USER bug33669@localhost; +DROP DATABASE db1; + +SET @start_read_only = @@global.read_only; +SET @start_super_read_only = @@global.super_read_only; +SELECT @start_read_only, @start_super_read_only; + +SET @@global.super_read_only = 1; +SET @@global.super_read_only = DEFAULT; +SELECT @@global.super_read_only; + +SET @@global.super_read_only = @start_super_read_only; +SELECT @@global.super_read_only = 0; + +SET @@global.super_read_only = 0; +SELECT @@global.super_read_only; +SET @@global.super_read_only = 1; +SELECT @@global.super_read_only; +SET @@global.super_read_only = TRUE; +SELECT @@global.super_read_only; +SET @@global.super_read_only = FALSE; +SELECT @@global.super_read_only; +SET @@global.super_read_only = ON; +SELECT @@global.super_read_only; +SET @@global.super_read_only = OFF; +SELECT @@global.super_read_only; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = -1; +SELECT @@global.super_read_only; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = 4294967296; +SELECT @@global.super_read_only; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = 10240022115; +SELECT @@global.super_read_only; +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.super_read_only = 10000.01; +SELECT @@global.super_read_only; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = -1024; +SELECT @@global.super_read_only; +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = 42949672950; +SELECT @@global.super_read_only; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@global.super_read_only = 'test'; +SELECT @@global.super_read_only; + +--Error ER_GLOBAL_VARIABLE +SET @@session.super_read_only = 0; +SELECT @@super_read_only; + +--disable_warnings +SELECT IF(@@global.super_read_only, "ON", "OFF") = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='super_read_only'; + +SELECT IF(@@read_only, "ON", "OFF") = VARIABLE_VALUE +FROM performance_schema.session_variables +WHERE VARIABLE_NAME='super_read_only'; +--enable_warnings + +SET @@global.super_read_only = 1; +SELECT @@super_read_only = @@global.super_read_only; + +--Error ER_GLOBAL_VARIABLE +SET super_read_only = 1; +SELECT @@super_read_only; +--Error ER_PARSE_ERROR +SET local.super_read_only = 1; +--Error ER_UNKNOWN_TABLE +SELECT local.super_read_only; +--Error ER_PARSE_ERROR +SET global.super_read_only = 1; +--Error ER_UNKNOWN_TABLE +SELECT global.super_read_only; +--Error ER_BAD_FIELD_ERROR +SELECT super_read_only = @@session.super_read_only; + +SET @@global.read_only = @start_read_only; +SET @@global.super_read_only = @start_super_read_only; + +SELECT @@global.super_read_only; +SELECT @@global.read_only; diff --git a/mysql-test/suite/tianchi/t/ctc_select_early_return.test b/mysql-test/suite/tianchi/t/ctc_select_early_return.test new file mode 100644 index 0000000..3ee66bc --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_select_early_return.test @@ -0,0 +1,83 @@ +drop database if exists test_DB; +create database test_DB; +use test_DB; + +create table t1 (a int, b int, c int, d int); +create index idx1 on t1 (d, c, b); +insert into t1 values (1,2,null,4); +insert into t1 values (1,2,3,null); +insert into t1 values (1,2,3,4); +# index_only +select b from t1 where b = 2; +select b, c from t1; +select d from t1; +# 非index_only +select a, b from t1; +select * from t1; +drop table t1; + +# all column is index +create table t2 (a int, b int, c int, d int); +create index idx2 on t2 (d, a, c, b); +insert into t2 values (1,2,null,4); +insert into t2 values (1,2,3,null); +insert into t2 values (1,2,3,4); +# index_only +select a from t2 where a = 1; +select b, c from t2; +select d from t2; +# 非index_only +select * from t2; +drop table t2; + +# with no index +create table t3 (a int, b int, c int, d int); +insert into t3 values (1,2,3,4); +insert into t3 values (1,2,3,4); +insert into t3 values (1,2,3,4); +select a from t3 where a = 1; +select b, c from t3; +select d from t3; +select * from t3; +drop table t3; + +# drop column with index +create table t4 (a int, b int, c int, d int, e int, f int); +create index idx4 on t4 (f,e,d); +insert into t4 values (1,2,3,4,null,6); +insert into t4 values (1,2,3,4,5,null); +insert into t4 values (1,2,3,4,5,6); +insert into t4 values (1,2,3,4,5,6); +select * from t4; +alter table t4 drop column a; +select d from t4 where d = 4; +select * from t4 where d = 4; +alter table t4 drop column b; +select d from t4 where d = 4; +select * from t4 where f = 6; +drop table t4; + +# drop column with no index +create table t5 (a int, b int, c int, d int, e int, f int); +insert into t5 values (1,2,3,4,null,6); +insert into t5 values (1,2,3,4,5,null); +insert into t5 values (1,2,3,4,5,6); +insert into t5 values (1,2,3,4,5,6); +select * from t5; +alter table t5 drop column a; +select d from t5 where d = 4; +select * from t5 where d = 4; +alter table t5 drop column b; +select d from t5 where d = 4; +drop table t5; + +create table t6(id int, v json)default CHARACTER SET=ascii; +insert into t6 values(1,'[0,1.1, "abc", "00:00:00", "1000-01-01 00:00:00", "1000-01-01", "2155", {"k1":1}, [1,2], true, null]'); +select * from t6 where id=1; + insert into t6 values(2,'{"k1":1, "k2":1.5, "k3":"abc", "k4":"00:00:00", "k5":"1000-01-01 00:00:00","k6":"1000-01-01","k7":"2155","k8":{"k1":1},"k9":[1,2],"k10":true, "k11":null}'); +select * from t6 where id=2; +update t6 set v='[1]' where id=1; +select * from t6; +drop table t6; + +drop database test_DB; \ No newline at end of file diff --git a/mysql-test/suite/tianchi/t/ctc_update_time.test b/mysql-test/suite/tianchi/t/ctc_update_time.test new file mode 100644 index 0000000..2b75771 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_update_time.test @@ -0,0 +1,198 @@ +--disable_warnings +DROP TABLE IF EXISTS t1,t2,t3,t4; +--enable_warnings +SET sql_mode='NO_ENGINE_SUBSTITUTION'; +# Create tables +CREATE TABLE t1(c1 TIME NOT NULL, c2 TIME NULL, PRIMARY KEY(c1)); +CREATE TABLE t2(c1 TIME NOT NULL, c2 TIME NOT NULL, PRIMARY KEY(c1,c2)); +CREATE TABLE t3(c1 TIME NOT NULL, c2 TIME NULL, UNIQUE INDEX idx(c1,c2)); +CREATE TABLE t4(c1 TIME NOT NULL, c2 TIME NULL); + +# As a string in 'D HH:MM:SS.fraction' format + +INSERT INTO t1 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t2 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t3 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); +INSERT INTO t4 VALUES ('00:00:00.00','00:00:00.00'),('01:01:01.01','01:01:01.00'),('838:59:59.00','838:59:59.00'),('00:00:01','00:00:01'),('02:02:02','02:02:02'),('838:59:58','838:59:58'),('-838:59:59','-838:59:59'),('00:03','00:03'),('03:03','03:03'),('838:58','838:58'),('00 00:00:04','00 00:00:04'),('04 04:04:04','04 04:04:04'),('34 22:59:57','34 22:59:57'),('00 00:04','00 00:04'),('05 05:05','05 05:05'),('34 22:56','34 22:56'),('05 05','05 05'),('06 06','06 06'),('34 22','34 22'),('07','07'),('59','59'); + +#As a string with no delimiters in 'HHMMSS' format + +INSERT INTO t1 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t2 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t3 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); +INSERT INTO t4 VALUES('000008','000008'),('080808','080808'),('8385955','8385955'),('-8385955','-8385955'),('0009','0009'),('0909','0909'),('5454','5454'),('10','10'),('53','53'); + +#As a number in HHMMSS format + +INSERT INTO t1 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t2 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t3 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); +INSERT INTO t4 VALUES (000011.00,000011.00),(111111.11,111111.11),(8385952.00,8385952.00),(000012,000012),(121212,121212),(8385951,8385951),(1313,1313),(5151,5151),(14,14),(50,50); + +#As the result of a function that returns a value that is acceptable in a TIME context +SET TIMESTAMP=1233216687; # 2009-01-29 13:41:27 +INSERT INTO t1 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t2 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t3 VALUES(CURRENT_TIME(),CURRENT_TIME()); +INSERT INTO t4 VALUES(CURRENT_TIME(),CURRENT_TIME()); +#Insert permissible NULLs +INSERT INTO t1 VALUES('123456',null); +#INSERT INTO t2 VALUES('123456',null); +INSERT INTO t3 VALUES('123456',null); +INSERT INTO t4 VALUES('123456',null); +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT * FROM t4; +#Updating the tables +--sorted_result +SELECT c1 FROM t1 WHERE c1='00:00:07'; +UPDATE t1 SET c1='22:22:22' WHERE c1='00:00:07'; +--sorted_result +SELECT c1 FROM t1; +--sorted_result +SELECT c1 FROM t2 WHERE c1='-838:59:59' AND c2='-838:59:59'; +UPDATE t2 SET c1='22:22:22' WHERE c1='-838:59:59' AND c2='-838:59:59'; +--sorted_result +SELECT c1 FROM t2; + +# Update with NULL ( NULL to number & number to NULL) +--sorted_result +SELECT c2 FROM t3 WHERE c2=null; +UPDATE t3 SET c2='34 22:59:59' WHERE c2=null; +--sorted_result +SELECT c2 FROM t3; +--sorted_result +SELECT c2 FROM t4 WHERE c1='00:00:00'; +UPDATE t4 SET c2=null WHERE c1='00:00:00'; +--sorted_result +SELECT c2 FROM t4; + +#Update order by limit +--sorted_result +SELECT c1 FROM t4 WHERE c1 < '000009'; +UPDATE t4 SET c1='0101' WHERE c1 < '000009' ORDER BY c1 LIMIT 3; +--sorted_result +SELECT c1 FROM t4; + +#Update negative value to unsigned column +--sorted_result +SELECT c1 FROM t1 WHERE c1='12:12:12'; +UPDATE t1 SET c1='-12:12:12' WHERE c1='12:12:12'; +--sorted_result +SELECT c1 FROM t1; + +#Update with Arithmetic operations +--sorted_result +SELECT c1 FROM t1 WHERE c1=111127; +UPDATE t1 SET c1=c1+c2 WHERE c1=111127; +--sorted_result +SELECT c1 FROM t1; +--sorted_result +SELECT c1 FROM t2 WHERE c2='100:04:04'; +UPDATE t2 SET c1=c1 - '010101' WHERE c2=1000404; +--sorted_result +SELECT c1 FROM t2; +--sorted_result +SELECT c2 FROM t3 WHERE c2=020202; +UPDATE t3 SET c2=c1 * 2 WHERE c2='020202'; +--sorted_result +SELECT c1 FROM t3; +--sorted_result +SELECT c1 FROM t4 WHERE c1=121212; +UPDATE t4 SET c1=c1 / 2 WHERE c1='12:12:12'; +--sorted_result +SELECT c1 FROM t4; + +#Update range values +UPDATE t1 SET c2=1250000 WHERE c1='00:00:09' AND c1='01:01:01'; +--sorted_result +SELECT c2 FROM t1; +UPDATE t2 SET c1=125959 WHERE c2=000400 OR c2= 000900; +--sorted_result +SELECT c1 FROM t2; +UPDATE t2 SET c2='1111' WHERE c1 IN ('100:04:04',005454,'2:2:2',111111); +--sorted_result +SELECT c2 FROM t2; + +#Update outside range would be clipped to closest endpoints +UPDATE t4 SET c2='-838:59:60' WHERE c1='100:04:04'; +--sorted_result +SELECT c2 FROM t4; +UPDATE t4 SET c2='838:59:60' WHERE c1='100:04:04'; +--sorted_result +SELECT c2 FROM t4; +UPDATE t4 SET c2='00:00:00' WHERE c1='100:04:04'; +--sorted_result +SELECT c2 FROM t4; +UPDATE t4 SET c2='11:11:60' WHERE c1='100:04:04'; +--sorted_result +SELECT c2 FROM t4; +UPDATE t4 SET c2='11:60:11' WHERE c1='100:04:04'; +--sorted_result +SELECT c2 FROM t4; + +# Update ignore on bad null error +--sorted_result +SELECT c1 FROM t3 WHERE c2 < '000007'; +SET SQL_MODE=STRICT_ALL_TABLES; +--error ER_BAD_NULL_ERROR +UPDATE t3 SET c1=NULL WHERE c2 < '000007'; +UPDATE IGNORE t3 SET c1=NULL WHERE c2 < '000007'; +--sorted_result +SELECT c1 from t3 WHERE c2 < '000007'; +SET SQL_MODE='NO_ENGINE_SUBSTITUTION'; + +#Duplicate keys +--error ER_DUP_ENTRY +UPDATE t1 SET c1=8385958 WHERE c2='34 22:59:59'; + +#Update with invalid values +UPDATE t1 SET c2='def' WHERE c1=59; +--sorted_result +SELECT c2 FROM t1; +--error ER_PARSE_ERROR +UPDATE t4 SET c1=11:11:11 WHERE c2=NULL; +--sorted_result +SELECT c1 FROM t4; + +#Multi table update +UPDATE t1,t2,t3,t4 SET t1.c2=t2.c1+t2.c2,t3.c2=t4.c1*2 WHERE t1.c1='00:13:13' AND t2.c1=080808 AND t4.c1='00:04:00' AND t3.c2=020202; + +# Update using various access methods + +# Update using Const +# EXPLAIN SELECT * FROM t1 WHERE c1='00:09:09' AND c2='00:09:09'; +UPDATE t1 SET t1.c1='00:12:12' WHERE c1='00:09:09' AND c2='00:09:09'; +--sorted_result +SELECT * FROM t1; + +# Update using range +# EXPLAIN SELECT * FROM t1 WHERE c1 BETWEEN 080000 AND 100000; +UPDATE t1 SET t1.c2='99999.99999' WHERE c1 BETWEEN 080000 AND 100000; +--sorted_result +SELECT * FROM t1; +# EXPLAIN SELECT * FROM t1 WHERE c1 IN (222222,8385955,1500000); +UPDATE t1 SET c1=c1+1,c2=c2-1 WHERE c1 IN (222222,8385955,1500000) ORDER BY c1; +--sorted_result +SELECT * FROM t1; + +# Update using eq_ref +# EXPLAIN SELECT * FROM t2,t3 WHERE t2.c1=t3.c1 AND t2.c3=t3.c3; +UPDATE t1,t2 SET t1.c2='22222.22222' WHERE t1.c1=t2.c1 AND t1.c2=t2.c2; + +--sorted_result +SELECT * FROM t1; +--sorted_result +SELECT * FROM t2; +--sorted_result +SELECT * FROM t3; +--sorted_result +SELECT * FROM t4; +#Drop tables; +DROP TABLE IF EXISTS t1,t2,t3,t4; +SET sql_mode=default; diff --git a/mysql-test/suite/tianchi/t/ctc_varchar.test b/mysql-test/suite/tianchi/t/ctc_varchar.test new file mode 100644 index 0000000..bfd22d1 --- /dev/null +++ b/mysql-test/suite/tianchi/t/ctc_varchar.test @@ -0,0 +1,184 @@ +--disable_warnings +drop table if exists DEMO; +drop table if exists t1; +--enable_warnings + +create table t1 (a int, b varchar(9000) default ''); +show create table t1; +insert into t1 values (1, repeat('a',8700)), (2, repeat('b',8800)), (3, repeat('c',9000)), (4, repeat('a',8700)); +select count(*) from t1; +alter table t1 add index idx (a); +select a from t1 where a=1; +alter table t1 add index idb (b(768)); +select count(b) from t1 where b=repeat('a',8700); +alter table t1 add column c varchar(6400) default 'adbwedewdwed'; +select c from t1; +drop table t1; + + +create table t1 (a int, b varchar(6000) default ''); +show create table t1; +insert into t1 values (1, repeat('a',5700)), (2, repeat('b',5800)), (3, repeat('c',6000)), (4, repeat('b',5800)); +select count(*) from t1; +alter table t1 add index idx (a); +select a from t1 where a=1; +alter table t1 add index idb (b(768)); +select count(b) from t1 where b=repeat('b',5800); +alter table t1 add column c varchar(6400) default 'adbwedewdwed'; +select c from t1; +drop table t1; + +create table t1 (a int, b varchar(600) default ''); +show create table t1; +insert into t1 values (1, repeat('a',570)), (2, repeat('b',580)), (3, repeat('c',600)), (4, repeat('c',600)); +select count(*) from t1; +alter table t1 add index idx (a); +select a from t1 where a=1; +alter table t1 add index idb (b(200)); +select count(b) from t1 where b=repeat('c',600); +alter table t1 add column c varchar(6400) default 'adbwedewdwed'; +select c from t1; +drop table t1; + +create table t1(i int,a varchar(10),b varchar(1000),c varchar(10000)); +show create table t1; +insert into t1(i,a,b,c) values(1,'a',repeat('a',1000),repeat('a',10000)); +select length(c) from t1; +alter table t1 drop b, drop c; +select * from t1; +alter table t1 add column b varchar(10000),add column c varchar(1000); +show create table t1; +DROP PROCEDURE IF EXISTS insert_data_test1; +DELIMITER //; +CREATE PROCEDURE insert_data_test1() +BEGIN + DECLARE k INT DEFAULT 1; + WHILE k <= 10000 DO + INSERT INTO t1(i,b,c,a) values(k,repeat('a',10000),repeat('a',1000),'a'); + SET k = k + 1; + END WHILE; +END// +DELIMITER ;// +CALL insert_data_test1(); +select length(b),length(c) from t1 limit 9990,10000; +alter table t1 drop c; +select length(b) from t1 limit 9990,10000; +DROP PROCEDURE insert_data_test1; +drop table t1; + +create table t1(i int,a varchar(10),b varchar(10000),c varchar(1000)); +show create table t1; +insert into t1(i,a,b,c) values(1,'a',repeat('a',10000),repeat('a',1000)); +select length(b) from t1; +alter table t1 drop a, drop c; +select length(b) from t1; +alter table t1 add column a varchar(1000),add column c varchar(10); +show create table t1; +DROP PROCEDURE IF EXISTS insert_data_test1; +DELIMITER //; +CREATE PROCEDURE insert_data_test1() +BEGIN + DECLARE k INT DEFAULT 1; + WHILE k <= 10000 DO + INSERT INTO t1(i,b,c,a) values(k,repeat('a',10000),'a',repeat('a',1000)); + SET k = k + 1; + END WHILE; +END// +DELIMITER ;// +CALL insert_data_test1(); +select length(b),length(a) from t1 limit 9990,10000; +alter table t1 drop c; +select length(b) from t1 limit 9990,10000; +DROP PROCEDURE insert_data_test1; +drop table t1; + +create table t1(a tinytext, b text, c mediumtext, d longtext); +show create table t1; +alter table t1 modify a varchar(10000); +show create table t1; +alter table t1 modify a tinytext; +show create table t1; +alter table t1 modify b varchar(10000); +show create table t1; +alter table t1 modify b text; +show create table t1; +alter table t1 modify c varchar(10000); +show create table t1; +alter table t1 modify c mediumtext; +show create table t1; +alter table t1 modify d varchar(10000); +show create table t1; +alter table t1 modify d longtext; +show create table t1; +DROP PROCEDURE IF EXISTS insert_data_test1; +DELIMITER //; +CREATE PROCEDURE insert_data_test1() +BEGIN + DECLARE k INT DEFAULT 1; + WHILE k <= 10000 DO + INSERT INTO t1(a,b,c,d) values(repeat('a',255),repeat('b',1000),repeat('c',1000),repeat('d',1000)); + SET k = k + 1; + END WHILE; +END// +DELIMITER ;// +CALL insert_data_test1(); +select length(a),length(b),length(c),length(d) from t1 limit 9996,10000; +truncate table t1; +alter table t1 modify a varchar(1000); +show create table t1; +DROP PROCEDURE IF EXISTS insert_data_test1; +DELIMITER //; +CREATE PROCEDURE insert_data_test1() +BEGIN + DECLARE k INT DEFAULT 1; + WHILE k <= 10000 DO + INSERT INTO t1(a,b,c,d) values(repeat('a',1000),repeat('b',1000),repeat('c',1000),repeat('d',1000)); + SET k = k + 1; + END WHILE; +END// +DELIMITER ;// +CALL insert_data_test1(); +select length(a),length(b),length(c),length(d) from t1 limit 9986,9990; +drop table t1; +create table t1(a varchar(10000), b varchar(100)); +show create table t1; +DROP PROCEDURE IF EXISTS insert_data_test1; +DELIMITER //; +CREATE PROCEDURE insert_data_test1() +BEGIN + DECLARE k INT DEFAULT 1; + WHILE k <= 10000 DO + INSERT INTO t1(a,b) values(repeat('a',10000),repeat('b',100)); + SET k = k + 1; + END WHILE; +END// +DELIMITER ;// +CALL insert_data_test1(); +truncate table t1; +alter table t1 modify a tinytext; +alter table t1 modify a text; +alter table t1 modify a mediumtext; +alter table t1 modify a longtext; +alter table t1 modify b tinytext; +alter table t1 modify b text; +alter table t1 modify b mediumtext; +alter table t1 modify b longtext; +show create table t1; +DROP PROCEDURE insert_data_test1; +drop table t1; + +create table t1(a int, b text, key(a)); +show create table t1; +insert into t1 values(1,repeat('a',3900)),(2,repeat('b',3700)),(3,repeat('e',4700)); +CREATE INDEX idxb ON t1(b(700)); +show create table t1; +select length(b) from t1 where b=repeat('b',3700); +select a,length(b) from t1 where a<3; +alter table t1 add column c blob; +alter table t1 add index idxc(c(280)); +show create table t1; +insert into t1 values(4,repeat('a',3900),repeat('o',2900)),(5,repeat('b',3700),repeat('p',5900)),(6,repeat('e',4700),repeat('q',6700)); +select length(b) from t1 where b=repeat('b',3700); +select length(c) from t1 where c=repeat('p',5900); +select a,length(b),length(c) from t1 where a>=1 and a<5; +drop table t1; diff --git a/mysql-test/suite/tianchi/t/recreate_test_db.test b/mysql-test/suite/tianchi/t/recreate_test_db.test new file mode 100644 index 0000000..87a38a4 --- /dev/null +++ b/mysql-test/suite/tianchi/t/recreate_test_db.test @@ -0,0 +1,4 @@ +--disable_warnings +drop database if exists test; +create database test; +--enable_warnings diff --git a/storage/tianchi/CMakeLists.txt b/storage/tianchi/CMakeLists.txt new file mode 100644 index 0000000..a03df6d --- /dev/null +++ b/storage/tianchi/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License, version 2.0, +# as published by the Free Software Foundation. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License, version 2.0, for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +SET(TSE_PLUGIN_DYNAMIC "ha_ctc") +SET(TSE_SOURCES tse_log.h ha_tse.cc ha_tse.h ha_tsepart.h ha_tsepart.cc ha_tse_ddl.cc ha_tse_ddl.h tse_ddl_util.cc tse_ddl_util.h datatype_cnvrtr.cc datatype_cnvrtr.h tse_error.cc tse_error.h + decimal_convert.cc decimal_convert.h tse_cbo.cc tse_cbo.h datatype_cnvrt_4_index_search.cc datatype_cnvrt_4_index_search.h tse_ddl_rewriter_plugin.cc + ctc_meta_data.cc ctc_meta_data.h tse_stats.h tse_stats.cc tse_srv.h tse_util.h tse_util.cc protobuf/tc_db.pb-c.c protobuf/tc_db.pb-c.h) +option(WITH_DAAC OFF) +IF (WITH_DAAC) + add_definitions(-DWITH_DAAC) + message(STATUS "ADD WITH DAAC") + list(APPEND TSE_SOURCES mysql_daac_plugin.cc) +ELSE () + list(APPEND TSE_SOURCES tse_srv_mq_stub.cc tse_srv_mq_module.cc tse_srv_mq_module.h srv_mq_msg.h message_queue/dsw_shm.h + message_queue/dsw_list.h message_queue/dsw_message.h message_queue/dsw_typedef.h) +ENDIF () +ADD_DEFINITIONS(-DMYSQL_SERVER) +ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) +STRING_APPEND(CMAKE_CXX_FLAGS " -Wno-implicit-fallthrough") +STRING_APPEND(CMAKE_CXX_FLAGS " -Wno-stringop-overflow") +STRING_APPEND(CMAKE_CXX_FLAGS " -Wunused-variable") +STRING_APPEND(CMAKE_CXX_FLAGS " -Wunused-parameter") +STRING_APPEND(CMAKE_CXX_FLAGS " -Wunused-but-set-variable") +# STRING_APPEND(CMAKE_CXX_FLAGS " -Wstringop-truncation") + +add_compile_options(-fstack-protector) +add_compile_options(-fvisibility=hidden) +SET(CMAKE_SKIP_RPATH TRUE) + +STRING_APPEND(CMAKE_CXX_FLAGS " -Wl,-z,now") +SET(DAAC_LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../daac_lib) +SET(MYSQL_CLIENT_STATIC_LIB_PATH ${CMAKE_BINARY_DIR}/archive_output_directory/) +LINK_DIRECTORIES(${DAAC_LIB_PATH}) +LINK_DIRECTORIES(${MYSQL_CLIENT_STATIC_LIB_PATH}) +INCLUDE_DIRECTORIES(SYSTEM ${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR}) + +SET(TSE_PROXY_SOURCES tse_proxy_util.cc tse_proxy_util.h tse_mysql_proxy.cc) +SET(TSE_PROXY_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-Bsymbolic") +add_library(ctc_proxy SHARED ${TSE_PROXY_SOURCES}) +target_link_libraries(ctc_proxy libmysqlclient.a) +# ctc_proxy link libmysqlclient.a function symbol rather than mysqld`s +set_target_properties(ctc_proxy PROPERTIES COMPILE_FLAGS ${TSE_PROXY_CXX_FLAGS} LINK_FLAGS " -Wl,-Bsymbolic" + LIBRARY_OUTPUT_DIRECTORY ${DAAC_LIB_PATH}) + +IF (WITH_DAAC) + IF (WITH_TSE_STORAGE_ENGINE AND NOT WITHOUT_TSE_STORAGE_ENGINE) + MYSQL_ADD_PLUGIN(ctc + ${TSE_SOURCES} + STORAGE_ENGINE + MANDATORY + LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy daac + ) + ELSEIF (NOT WITHOUT_TSE_STORAGE_ENGINE) + MYSQL_ADD_PLUGIN(ctc + ${TSE_SOURCES} + STORAGE_ENGINE + MODULE_ONLY + LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy daac + ) + ENDIF () +ELSE () + IF (WITH_TSE_STORAGE_ENGINE AND NOT WITHOUT_TSE_STORAGE_ENGINE) + MYSQL_ADD_PLUGIN(ctc + ${TSE_SOURCES} + STORAGE_ENGINE + DEFAULT + LINK_LIBRARIES message_queue libprotobuf-c.a libsecurec.so ctc_proxy + ) + ELSEIF (NOT WITHOUT_TSE_STORAGE_ENGINE) + MYSQL_ADD_PLUGIN(ctc + ${TSE_SOURCES} + STORAGE_ENGINE + MODULE_ONLY + LINK_LIBRARIES message_queue libprotobuf-c.a libsecurec.so ctc_proxy + ) + ENDIF () +ENDIF () + diff --git a/storage/tianchi/ctc_meta_data.cc b/storage/tianchi/ctc_meta_data.cc new file mode 100644 index 0000000..96f025f --- /dev/null +++ b/storage/tianchi/ctc_meta_data.cc @@ -0,0 +1,779 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "ctc_meta_data.h" +#include +#include +#include +#include +#include +#include +#include +#include "mysql.h" +#include "sql/mysqld.h" // mysql_port, my_localhost +#include "tse_log.h" +#include "tse_srv.h" +#include "tse_util.h" +#include "tse_proxy_util.h" +#include "sql/sql_table.h" +#include "my_dir.h" +#include "sql/sql_handler.h" +#include "sql/sql_base.h" +#include "sql/sql_class.h" +#include "sql/dd/cache/dictionary_client.h" +#include "sql/mysqld_thd_manager.h" +#include "sql/dd/types/procedure.h" +#include "sql/dd/types/function.h" +#include "sql/dd/types/routine.h" +#include "sql/mdl.h" +#include "sql/dd/types/event.h" +#include "sql/dd/types/resource_group.h" +#include "sql/dd/types/trigger.h" +#include "sql/auth/auth_common.h" +#include "sql/sys_vars_shared.h" // intern_find_sys_var +#include "sql/sql_lex.h" // lex_start/lex_end +#include "sql/handler.h" // ha_tse_commit +#include "sql/auth/auth_acls.h" +#include "sql/sp_cache.h" // sp_cache_invalidate +#include "sql/sp_head.h" // Stored_program_creation_ctx +#include "sql/sp_pcontext.h" // sp_pcontext + +using namespace std; + +extern uint32_t tse_instance_id; +static map g_tse_mdl_thd_map; +static mutex m_tse_mdl_thd_mutex; +static map *> g_tse_mdl_ticket_maps; +static mutex m_tse_mdl_ticket_mutex; +bool no_create_dir = true; + +class Release_all_ctc_explicit_locks : public MDL_release_locks_visitor { + public: + bool release(MDL_ticket *ticket) override { + const MDL_key *mdl_key = ticket->get_key(); + tse_log_system("[TSE_MDL_THD]: Release ticket info, db_name:%s, name:%s, namespace:%d, ticket_type:%d", + mdl_key->db_name(), mdl_key->name(), mdl_key->mdl_namespace(), ticket->get_type()); + return ticket->get_type() == MDL_EXCLUSIVE; + } +}; + +static void release_ctc_thd_and_explicit_locks(THD *thd) { + my_thread_init(); + thd->store_globals(); + + Release_all_ctc_explicit_locks lock_visitor; + thd->mdl_context.release_locks(&lock_visitor); + + thd->release_resources(); + delete thd; + + my_thread_end(); +} + +static void release_ctc_thd_tickets(THD *thd) { + lock_guard lock(m_tse_mdl_ticket_mutex); + auto ticket_map_iter = g_tse_mdl_ticket_maps.find(thd); + if (ticket_map_iter == g_tse_mdl_ticket_maps.end()) { + return; + } + + map *tse_mdl_ticket_map = ticket_map_iter->second; + if (tse_mdl_ticket_map == nullptr) { + g_tse_mdl_ticket_maps.erase(thd); + return; + } + + tse_mdl_ticket_map->clear(); + delete tse_mdl_ticket_map; + g_tse_mdl_ticket_maps.erase(thd); +} + +static void release_tse_mdl_thd_by_key(uint64_t mdl_thd_key) { + /* 存在并发场景 map操作加锁 */ + lock_guard lock(m_tse_mdl_thd_mutex); + auto iter = g_tse_mdl_thd_map.find(mdl_thd_key); + if (iter == g_tse_mdl_thd_map.end()) { + return; + } + + THD *thd = g_tse_mdl_thd_map[mdl_thd_key]; + assert(thd); + release_ctc_thd_tickets(thd); + release_ctc_thd_and_explicit_locks(thd); + + tse_log_system("[TSE_MDL_THD]: Close mdl thd by key=%lu", mdl_thd_key); + + g_tse_mdl_thd_map.erase(mdl_thd_key); +} + +static void ctc_reload_acl_caches() { + THD *reload_acl_thd = new (std::nothrow) THD; + my_thread_init(); + reload_acl_thd->set_new_thread_id(); + reload_acl_thd->thread_stack = (char *)&reload_acl_thd; + reload_acl_thd->store_globals(); + reload_acl_thd->set_query("tse_mdl_thd_notify", 18); + + reload_acl_caches(reload_acl_thd, false); + tse_log_system("[TSE_RELOAD_ACL]:reload acl caches thd_id:%u", reload_acl_thd->thread_id()); + + reload_acl_thd->release_resources(); + delete reload_acl_thd; + + my_thread_end(); +} + +static void release_tse_mdl_thd_by_cantian_id(uint16_t cantian_inst_id) { + ctc_reload_acl_caches(); + + lock_guard lock(m_tse_mdl_thd_mutex); + for (auto iter = g_tse_mdl_thd_map.begin(); iter != g_tse_mdl_thd_map.end(); ) { + if (tse_get_cantian_id_from_conn_key(iter->first) == cantian_inst_id) { + THD *thd = iter->second; + assert(thd); + release_ctc_thd_tickets(thd); + release_ctc_thd_and_explicit_locks(thd); + tse_log_system("[TSE_MDL_THD]: Close mdl thd by cantian_id:%u", cantian_inst_id); + iter = g_tse_mdl_thd_map.erase(iter); + } else { + ++iter; + } + } +} + +static void release_tse_mdl_thd_by_inst_id(uint32_t mysql_inst_id) { + lock_guard lock(m_tse_mdl_thd_mutex); + for (auto iter = g_tse_mdl_thd_map.begin(); iter != g_tse_mdl_thd_map.end(); ) { + if (tse_get_inst_id_from_conn_key(iter->first) == mysql_inst_id) { + THD *thd = iter->second; + assert(thd); + release_ctc_thd_tickets(thd); + release_ctc_thd_and_explicit_locks(thd); + tse_log_system("[TSE_MDL_THD]: Close mdl thd by inst_id:%u", mysql_inst_id); + iter = g_tse_mdl_thd_map.erase(iter); + } else { + ++iter; + } + } +} + +static void ctc_init_thd(THD **thd, uint64_t thd_key) { + lock_guard lock(m_tse_mdl_thd_mutex); + + if (g_tse_mdl_thd_map.find(thd_key) != g_tse_mdl_thd_map.end()) { + (*thd) = g_tse_mdl_thd_map[thd_key]; + my_thread_init(); + (*thd)->store_globals(); + } else { + THD* new_thd = new (std::nothrow) THD; + my_thread_init(); + new_thd->set_new_thread_id(); + new_thd->thread_stack = (char *)&new_thd; + new_thd->store_globals(); + new_thd->set_query("tse_mdl_thd_notify", 18); + g_tse_mdl_thd_map[thd_key] = new_thd; + (*thd) = new_thd; + } +} + +template +typename std::enable_if::type + invalidate_routine(T *thd, const char *schema_name, const char *routine_name, uint8 type) { + MDL_ticket *schema_ticket = nullptr; + MDL_ticket *routine_ticket = nullptr; + + tse_log_system("[INVALIDATE_ROUTINE]: enter invalidate_routine. schema_name:%s, routine_name:%s", schema_name, routine_name); + if(!thd->mdl_context.owns_equal_or_stronger_lock( + MDL_key::SCHEMA, schema_name, "", MDL_INTENTION_EXCLUSIVE)) { + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, schema_name, "", + MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + return true; + } + schema_ticket = mdl_request.ticket; + } + + enum_sp_type sptype; + MDL_key mdl_key; + if (type == T::OBJ_RT_PROCEDURE) { + dd::Routine::create_mdl_key(dd::Routine::RT_PROCEDURE, schema_name, routine_name, &mdl_key); + sptype = enum_sp_type::PROCEDURE; + } else { + dd::Routine::create_mdl_key(dd::Routine::RT_FUNCTION, schema_name, routine_name, &mdl_key); + sptype = enum_sp_type::FUNCTION; + } + + if(!thd->mdl_context.owns_equal_or_stronger_lock(&mdl_key, MDL_EXCLUSIVE)) { + MDL_request mdl_request; + MDL_REQUEST_INIT_BY_KEY(&mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + tse_log_error("[INVALIDATE_ROUTINE]: acquire routine/procedure mdl fail. schema_name:%s, routine_name:%s", schema_name, routine_name); + return true; + } + routine_ticket = mdl_request.ticket; + } + + dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); + const dd::Routine *routine = nullptr; + bool ignored MY_ATTRIBUTE((unused)); + if (type == T::OBJ_RT_PROCEDURE) { + ignored = thd->dd_client()->template acquire(schema_name, routine_name, &routine); + } else { + ignored = thd->dd_client()->template acquire(schema_name, routine_name, &routine); + } + if (routine) { + thd->dd_client()->invalidate(routine); + } + + // Invalidate routine cache. + LEX_STRING lex_routine_name = { const_cast(routine_name), strlen(routine_name) }; + sp_name *name = new (thd->mem_root) sp_name(to_lex_cstring(schema_name), lex_routine_name, true); + sp_cache_invalidate(); + sp_head *sp; + sp_cache **spc = (sptype == enum_sp_type::FUNCTION ? &thd->sp_func_cache + : &thd->sp_proc_cache); + sp = sp_cache_lookup(spc, name); + if (sp) { + sp_cache_flush_obsolete(spc, &sp); + } + + if (routine_ticket) thd->mdl_context.release_lock(routine_ticket); + if (schema_ticket) thd->mdl_context.release_lock(schema_ticket); + + tse_log_system("[INVALIDATE_ROUTINE]: leave invalidate_routine. schema_name:%s, routine_name:%s", schema_name, routine_name); + return false; +} + +template +typename std::enable_if::type + invalidate_routine(T *thd MY_ATTRIBUTE((unused)), const char *schema_name MY_ATTRIBUTE((unused)), + const char *routine_name MY_ATTRIBUTE((unused)), uint8 type MY_ATTRIBUTE((unused))) { + return false; +} + +template +typename std::enable_if::type + invalidate_table(T *thd, const char *schema_name, const char *table_name) { + MDL_ticket *schema_ticket = nullptr; + MDL_ticket *table_ticket = nullptr; + + tse_log_system("[INVALIDATE_TABLE]: enter invalidate_table, schema:%s, table:%s", schema_name, table_name); + if(!thd->mdl_context.owns_equal_or_stronger_lock( + MDL_key::SCHEMA, schema_name, "", MDL_INTENTION_EXCLUSIVE)) { + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, schema_name, "", + MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + tse_log_error("[INVALIDATE_TABLE]: acquire schema mdl lock fail. schema:%s, table:%s ", schema_name, table_name); + return true; + } + schema_ticket = mdl_request.ticket; + } + tse_log_system("[INVALIDATE_TABLE]: enter invalidate_table table, schema:%s, table:%s", schema_name, table_name); + if(!thd->mdl_context.owns_equal_or_stronger_lock( + MDL_key::TABLE, schema_name, table_name, MDL_EXCLUSIVE)) { + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, schema_name, table_name, + MDL_EXCLUSIVE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + tse_log_error("[INVALIDATE_TABLE]: acquire table mdl lock fail. schema:%s, table:%s ", schema_name, table_name); + return true; + } + table_ticket = mdl_request.ticket; + } + + dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); + tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, schema_name, table_name, false); + + bool ignored MY_ATTRIBUTE((unused)); + ignored = thd->dd_client()->invalidate(schema_name, table_name); + + if (schema_ticket) thd->mdl_context.release_lock(schema_ticket); + if (table_ticket) thd->mdl_context.release_lock(table_ticket); + + tse_log_system("[INVALIDATE_TABLE]: leave invalidate_table, schema:%s, table:%s", schema_name, table_name); + return false; +} + +template +typename std::enable_if::type + invalidate_table(T *thd MY_ATTRIBUTE((unused)), const char *schema_name MY_ATTRIBUTE((unused)), + const char *table_name MY_ATTRIBUTE((unused))) { + return false; +} + +template +typename std::enable_if::type + invalidate_schema(T *thd, const char *schema_name) { + MDL_ticket *schema_ticket = nullptr; + + tse_log_system("[INVALIDATE_SCHEMA]:enter invalidate_schema, schema:%s", schema_name); + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, schema_name, "", + MDL_EXCLUSIVE, MDL_EXPLICIT); + + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + tse_log_error("[INVALIDATE_SCHEMA]: acquire schema(%s) mdl lock fail.", schema_name); + return true; + } + schema_ticket = mdl_request.ticket; + + dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); + + const dd::Schema *schema = nullptr; + bool ignored MY_ATTRIBUTE((unused)); + ignored = thd->dd_client()->acquire(schema_name, &schema); + if (schema) { + thd->dd_client()->invalidate(schema); + } + + if (schema_ticket) thd->mdl_context.release_lock(schema_ticket); + + tse_log_system("leave invalidate_schema, schema:%s", schema_name); + return false; +} + +template +typename std::enable_if::type + invalidate_schema(T *thd, const char *schema_name) { + return false; +} + +template +typename std::enable_if::type + invalidate_tablespace(T *thd, const char *tablespace_name) { + MDL_ticket *tablespace_ticket = nullptr; + + tse_log_system("[INVALIDATE_TABLESPACE]: enter invalidate_tablespace, tablespace_name:%s", tablespace_name); + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLESPACE, tablespace_name, "", + MDL_EXCLUSIVE, MDL_EXPLICIT); + + if (thd->mdl_context.acquire_lock(&mdl_request, CTC_MDL_TIMEOUT)) { + assert(thd->killed || thd->is_error()); + tse_log_error("[INVALIDATE_TABLESPACE]: acquire tablespace mdl lock fail. tablespace_name:%s", tablespace_name); + return true; + } + tablespace_ticket = mdl_request.ticket; + + dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); + + const dd::Tablespace *tablespace = nullptr; + bool ignored MY_ATTRIBUTE((unused)); + ignored = thd->dd_client()->acquire(tablespace_name, &tablespace); + if (tablespace) { + thd->dd_client()->invalidate(tablespace); + } + thd->dd_client()->template dump(); + + if (tablespace_ticket) thd->mdl_context.release_lock(tablespace_ticket); + + tse_log_system("[INVALIDATE_TABLESPACE]:leave invalidate_tablespace, tablespace_name:%s", tablespace_name); + return false; +} + +template +typename std::enable_if::type + invalidate_tablespace(T *thd MY_ATTRIBUTE((unused)), const char *tablespace_name MY_ATTRIBUTE((unused))) { + return false; +} + +template +static typename std::enable_if::type + tse_invalidate_mysql_dd_cache_impl(tianchi_handler_t *tch, tse_invalidate_broadcast_request *broadcast_req, int *err_code) { + UNUSED_PARAM(err_code); + // 相同节点不用执行 + if(broadcast_req->mysql_inst_id == tse_instance_id) { + tse_log_note("tse_invalidate_mysql_dd_cache curnode not need execute,mysql_inst_id:%u", broadcast_req->mysql_inst_id); + return 0; + } + + bool error = false; + T *thd = nullptr; + uint64_t thd_key = tse_get_conn_key(tch->inst_id, tch->thd_id, true); + ctc_init_thd(&thd, thd_key); + + if (broadcast_req->is_dcl == true) { + reload_acl_caches(thd, false); + tse_log_system("[TSE_INVALID_DD]: remote invalidate acl cache, mysql_inst_id=%u", broadcast_req->mysql_inst_id); + } else { + invalidate_obj_entry_t *obj = NULL; + uint32_t offset = 0; + char *buff = broadcast_req->buff; + uint32_t buff_len = broadcast_req->buff_len; + + vector invalidate_routine_list; + vector invalidate_schema_list; + while (offset < buff_len) { + obj = (invalidate_obj_entry_t *)(buff + offset); + printf("\n\n\ntype: %u, first: %s, second: %s\n\n\n", obj->type, obj->first, obj->second); + switch (obj->type) { + case T::OBJ_ABSTRACT_TABLE: + error = invalidate_table(thd, obj->first, obj->second); + break; + case T::OBJ_RT_PROCEDURE: + case T::OBJ_RT_FUNCTION: + invalidate_routine_list.emplace_back(obj); + break; + case T::OBJ_SCHEMA: + invalidate_schema_list.emplace_back(obj); + break; + case T::OBJ_TABLESPACE: + error = invalidate_tablespace(thd, obj->first); + break; + case T::OBJ_EVENT: + case T::OBJ_COLUMN_STATISTICS: + case T::OBJ_RESOURCE_GROUP: + case T::OBJ_SPATIAL_REFERENCE_SYSTEM: + case T::OBJ_CHARSET: + case T::OBJ_COLLATION: + default: + break; + } + offset += sizeof(invalidate_obj_entry_t); + } + for (auto invalidate_it : invalidate_routine_list) { + error = invalidate_routine(thd, invalidate_it->first, invalidate_it->second, invalidate_it->type); + } + for (auto invalidate_it : invalidate_schema_list) { + error = invalidate_schema(thd, invalidate_it->first); + } + } + + thd->restore_globals(); + my_thread_end(); + + tse_log_system("[TSE_INVALID_DD]: remote invalidate dd cache success, mysql_inst_id=%u", broadcast_req->mysql_inst_id); + return error; +} + + +template +static typename std::enable_if::type + tse_invalidate_mysql_dd_cache_impl(tianchi_handler_t *tch MY_ATTRIBUTE((unused)), + tse_invalidate_broadcast_request *broadcast_req MY_ATTRIBUTE((unused)), + int *err_code MY_ATTRIBUTE((unused))) { + return 0; +} + +int tse_invalidate_mysql_dd_cache(tianchi_handler_t *tch, tse_invalidate_broadcast_request *broadcast_req, int *err_code) { + return (int)tse_invalidate_mysql_dd_cache_impl(tch, broadcast_req, err_code); +} + +static void tse_init_mdl_request(tse_lock_table_info *lock_info, MDL_request *mdl_request) { + MDL_key mdl_key; + dd::String_type schema_name = dd::String_type(lock_info->db_name); + dd::String_type name = dd::String_type(lock_info->table_name); + MDL_key::enum_mdl_namespace tse_mdl_namespace = (MDL_key::enum_mdl_namespace)lock_info->mdl_namespace; + + switch (tse_mdl_namespace) { + case MDL_key::FUNCTION: + dd::Function::create_mdl_key(schema_name, name, &mdl_key); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + case MDL_key::PROCEDURE: + dd::Procedure::create_mdl_key(schema_name, name, &mdl_key); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + case MDL_key::EVENT: + dd::Event::create_mdl_key(schema_name, name, &mdl_key); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + case MDL_key::RESOURCE_GROUPS: + dd::Resource_group::create_mdl_key(schema_name, &mdl_key); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + case MDL_key::TRIGGER: + dd::Trigger::create_mdl_key(schema_name, name, &mdl_key); + MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + default: + MDL_REQUEST_INIT(mdl_request, tse_mdl_namespace, lock_info->db_name, lock_info->table_name, + MDL_EXCLUSIVE, MDL_EXPLICIT); + break; + } + return; +} + +int tse_mdl_lock_thd(tianchi_handler_t *tch, tse_lock_table_info *lock_info, int *err_code) { + bool is_same_node = (tch->inst_id == tse_instance_id); + uint64_t mdl_thd_key = tse_get_conn_key(tch->inst_id, tch->thd_id, true); + + if (is_same_node) { + return false; + } + + THD *thd = nullptr; + ctc_init_thd(&thd, mdl_thd_key); + + MDL_request tse_mdl_request; + tse_init_mdl_request(lock_info, &tse_mdl_request); + + if (thd->mdl_context.acquire_lock(&tse_mdl_request, 10)) { + *err_code = ER_LOCK_WAIT_TIMEOUT; + tse_log_error("[TSE_MDL_LOCK]:Get mdl lock fail. namespace:%d, db_name:%s, table_name:%s", + lock_info->mdl_namespace, lock_info->db_name, lock_info->table_name); + return true; + } + + lock_guard lock(m_tse_mdl_ticket_mutex); + auto iter = g_tse_mdl_ticket_maps.find(thd); + map *tse_mdl_ticket_map = nullptr; + if (iter == g_tse_mdl_ticket_maps.end()) { + tse_mdl_ticket_map = new map; + g_tse_mdl_ticket_maps[thd] = tse_mdl_ticket_map; + } else { + tse_mdl_ticket_map = g_tse_mdl_ticket_maps[thd]; + } + string mdl_ticket_key; + mdl_ticket_key.assign(((const char*)(tse_mdl_request.key.ptr())), tse_mdl_request.key.length()); + assert(mdl_ticket_key.length() > 0); + tse_mdl_ticket_map->insert(map::value_type(mdl_ticket_key, tse_mdl_request.ticket)); + + thd->restore_globals(); + my_thread_end(); + + return false; +} + +void ctc_mdl_unlock_thd_by_ticket(THD* thd, MDL_request *tse_release_request) { + lock_guard lock(m_tse_mdl_ticket_mutex); + auto ticket_map_iter = g_tse_mdl_ticket_maps.find(thd); + if (ticket_map_iter == g_tse_mdl_ticket_maps.end()) { + return; + } + + map *tse_mdl_ticket_map = ticket_map_iter->second; + if (tse_mdl_ticket_map == nullptr) { + g_tse_mdl_ticket_maps.erase(thd); + return; + } + + string mdl_ticket_key; + mdl_ticket_key.assign(((const char*)(tse_release_request->key.ptr())), tse_release_request->key.length()); + auto ticket_iter = tse_mdl_ticket_map->find(mdl_ticket_key); + if (ticket_iter == tse_mdl_ticket_map->end()) { + return; + } + + MDL_ticket *ticket = ticket_iter->second; + thd->mdl_context.release_all_locks_for_name(ticket); + tse_mdl_ticket_map->erase(mdl_ticket_key); + if (tse_mdl_ticket_map->empty()) { + delete tse_mdl_ticket_map; + g_tse_mdl_ticket_maps.erase(thd); + } +} + +void tse_mdl_unlock_thd(tianchi_handler_t *tch, tse_lock_table_info *lock_info) { + bool is_same_node = (tch->inst_id == tse_instance_id); + uint64_t mdl_thd_key = tse_get_conn_key(tch->inst_id, tch->thd_id, true); + + if (is_same_node) { + return; + } + + auto iter = g_tse_mdl_thd_map.find(mdl_thd_key); + if (iter == g_tse_mdl_thd_map.end()) { + return; + } + THD* thd = iter->second; + assert(thd); + my_thread_init(); + thd->store_globals(); + + MDL_request tse_release_request; + tse_init_mdl_request(lock_info, &tse_release_request); + ctc_mdl_unlock_thd_by_ticket(thd, &tse_release_request); + + thd->restore_globals(); + my_thread_end(); + return; +} + +int close_tse_mdl_thd(uint32_t thd_id, uint32_t mysql_inst_id) { + if (thd_id == 0) { + if ((uint16_t)mysql_inst_id == (uint16_t)CANTIAN_DOWN_MASK) { + /* 清理整个参天节点相关的THD */ + tse_log_system("[TSE_MDL_THD]:Close All MDL THD on bad node by cantian_instance_id:%u", + (uint16_t)(mysql_inst_id >> 16)); + release_tse_mdl_thd_by_cantian_id((uint16_t)(mysql_inst_id >> 16)); + } else { + /* 清理整个mysqld节点相关的THD */ + tse_log_system("[TSE_MDL_THD]:Close All MDL THD by tse_instance_id:%u", mysql_inst_id); + release_tse_mdl_thd_by_inst_id(mysql_inst_id); + } + } else { + /* 通过把mysql_inst_id左移32位 与 thd_id拼接在一起 用来唯一标识一个THD */ + uint64_t mdl_thd_key = tse_get_conn_key(mysql_inst_id, thd_id, true); + tse_log_note("[TSE_MDL_THD]: Close THD by conn_id=%u, tse_instance_id=%u, proxy_conn_map_key=%lu", + thd_id, mysql_inst_id, mdl_thd_key); + release_tse_mdl_thd_by_key(mdl_thd_key); + } + return 0; +} + +static void ctc_get_set_var_item(THD* new_thd, sys_var* sysvar, Item** res MY_ATTRIBUTE((unused)), string& var_value, + bool is_null_value) { + switch (sysvar->show_type()) { + case SHOW_INT: + case SHOW_LONG: + case SHOW_LONGLONG: + case SHOW_HA_ROWS: + *res = new (new_thd->mem_root) + Item_uint(var_value.c_str(), (uint)var_value.length()); + break; + case SHOW_SIGNED_INT: + case SHOW_SIGNED_LONG: + case SHOW_SIGNED_LONGLONG: + *res = new (new_thd->mem_root) + Item_int(var_value.c_str(), (uint)var_value.length()); + break; + case SHOW_BOOL: + case SHOW_MY_BOOL: + if(var_value == "1" || var_value == "0") { + *res = new (new_thd->mem_root) + Item_int(var_value.c_str(), (uint)var_value.length()); + } else { + *res = new (new_thd->mem_root) + Item_string(var_value.c_str(), var_value.length(), + &my_charset_utf8mb4_bin); + } + break; + case SHOW_CHAR: + case SHOW_LEX_STRING: + *res = new (new_thd->mem_root) + Item_string(var_value.c_str(), var_value.length(), + &my_charset_utf8mb4_bin); + break; + case SHOW_CHAR_PTR: + if (is_null_value) + *res = new (new_thd->mem_root) Item_null(); + else + *res = new (new_thd->mem_root) + Item_string(var_value.c_str(), var_value.length(), + &my_charset_utf8mb4_bin); + break; + case SHOW_DOUBLE: + *res = new (new_thd->mem_root) + Item_float(var_value.c_str(), (uint)var_value.length()); + break; + default: + my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), sysvar->name.str); + } +} + +static void ctc_set_var_type(uint32_t option, set_var *var) { + if ((option & TSE_SET_VARIABLE_PERSIST) > 0) { + var->type = OPT_PERSIST; + } + if ((option & TSE_SET_VARIABLE_PERSIST_ONLY) > 0) { + var->type = OPT_PERSIST_ONLY; + } +} + +static void ctc_init_thd_priv(THD** thd, Sctx_ptr *ctx) { + my_thread_init(); + THD* new_thd = new (std::nothrow) THD; + new_thd->set_new_thread_id(); + new_thd->thread_stack = (char *)&new_thd; + new_thd->store_globals(); + lex_start(new_thd); + new_thd->security_context()->skip_grants(); + new_thd->set_query("tse_mdl_thd_notify", 18); + + const std::vector priv_list = { + "ENCRYPTION_KEY_ADMIN", "ROLE_ADMIN", "SYSTEM_VARIABLES_ADMIN", + "AUDIT_ADMIN"}; + const ulong static_priv_list = (SUPER_ACL | FILE_ACL); + + Security_context_factory default_factory( + new_thd, "bootstrap", "localhost", Default_local_authid(new_thd), + Grant_temporary_dynamic_privileges(new_thd, priv_list), + Grant_temporary_static_privileges(new_thd, static_priv_list), + Drop_temporary_dynamic_privileges(priv_list)); + + (*ctx) = default_factory.create(); + /* attach this auth id to current security_context */ + new_thd->set_security_context(ctx->get()); + new_thd->real_id = my_thread_self(); + (*thd) = new_thd; +} + +int ctc_set_sys_var(tse_ddl_broadcast_request *broadcast_req) { + Sctx_ptr ctx; + THD *new_thd = nullptr; + ctc_init_thd_priv(&new_thd, &ctx); + + Item *res = nullptr; + set_var *var = nullptr; + sys_var *sysvar = nullptr; + string base_name_src = broadcast_req->db_name; + string var_name = broadcast_req->user_name; + string var_value = broadcast_req->user_ip; + List tmp_var_list; + + bool is_default_value = ((broadcast_req->options) & (TSE_SET_VARIABLE_TO_DEFAULT)) > 0; + bool is_null_value = ((broadcast_req->options) & (TSE_SET_VARIABLE_TO_NULL)) > 0; + + LEX_CSTRING base_name = {nullptr, 0}; + if (strlen(base_name_src.c_str())) { + base_name = {base_name_src.c_str(), strlen(base_name_src.c_str())}; + } + + sysvar = intern_find_sys_var(var_name.c_str(), var_name.length()); + if (sysvar == nullptr) { + assert(0); + } + ctc_get_set_var_item(new_thd, sysvar, &res, var_value, is_null_value); + + if (is_default_value) { + if (res) { + res->cleanup(); + } + res = nullptr; + } + + var = new (new_thd->mem_root) set_var(OPT_GLOBAL, sysvar, base_name, res); + ctc_set_var_type(broadcast_req->options, var); + tmp_var_list.push_back(var); + int ret = sql_set_variables(new_thd, &tmp_var_list, false); + if (ret != 0) { + tse_log_error("ctc_set_sys_var failed in sql_set_variables, error_code:%d", ret); + if (ret != -1) { + assert(ret == 0); + } + } + + tmp_var_list.clear(); + if (res) { + res->cleanup(); + } + new_thd->free_items(); + lex_end(new_thd->lex); + new_thd->release_resources(); + delete new_thd; + + my_thread_end(); + + return ret; +} \ No newline at end of file diff --git a/storage/tianchi/ctc_meta_data.h b/storage/tianchi/ctc_meta_data.h new file mode 100644 index 0000000..f4c383e --- /dev/null +++ b/storage/tianchi/ctc_meta_data.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __CTC_META_DATA_H__ +#define __CTC_META_DATA_H__ + +#include +#include "tse_srv.h" + +#pragma GCC visibility push(default) + +#define CTC_MDL_TIMEOUT (31536000) + +int close_tse_mdl_thd(uint32_t thd_id, uint32_t mysql_inst_id); +int tse_mdl_lock_thd(tianchi_handler_t *tch, tse_lock_table_info *lock_info, int *err_code); +void tse_mdl_unlock_thd(tianchi_handler_t *tch, tse_lock_table_info *lock_info); +int ctc_set_sys_var(tse_ddl_broadcast_request *broadcast_req); + +#pragma GCC visibility pop + +#endif // __CTC_META_DATA_H__ \ No newline at end of file diff --git a/storage/tianchi/datatype_cnvrt_4_index_search.cc b/storage/tianchi/datatype_cnvrt_4_index_search.cc new file mode 100644 index 0000000..7b61c31 --- /dev/null +++ b/storage/tianchi/datatype_cnvrt_4_index_search.cc @@ -0,0 +1,218 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "sql/field.h" +#include "typelib.h" +#include "tse_log.h" +#include "tse_error.h" +#include "datatype_cnvrt_4_index_search.h" + +constexpr uint8 OFFSET_VARCHAR_TYPE = 2; + +static void tse_convert_mysql_key_to_cantian(KEY_PART_INFO &key_part, const uint8_t *key, uint16_t key_len, uint32_t *data_field_len, + uint8_t **use_key, uint32_t *use_key_len, bool *is_key_null) { + if (key_len == 0) { + return; + } + + Field *field = key_part.field; + uint16_t offset = 0; + if (field->is_nullable()) { + offset = 1; + } + bool check_blob = false; + // convert tse index datatype + uint32_t data_len = field->key_length(); + if (field->type() == MYSQL_TYPE_VARCHAR) { + *data_field_len = offset + data_len + OFFSET_VARCHAR_TYPE; + } else if (field->is_flag_set(BLOB_FLAG) && + field->part_of_prefixkey.to_ulonglong() && + !field->part_of_key_not_extended.to_ulonglong()) { + *data_field_len = key_part.store_length; + check_blob = true; + } else { + *data_field_len = offset + data_len; + } + + if (field->is_nullable() && key[0] == 1) { + *is_key_null = true; + *use_key_len = 0; + return; + } + + if (field->type() == MYSQL_TYPE_VARCHAR || check_blob) { + // 2:the first two digits of the key pointer record the length. + *use_key = const_cast(key + offset + OFFSET_VARCHAR_TYPE); + *use_key_len = *(uint16_t *)const_cast(key + offset); + } else if (field->real_type() == MYSQL_TYPE_STRING) { + // strip the pad_char + *use_key = const_cast(key + offset); + while (data_len > 0 && key[data_len + offset - 1] == field->charset()->pad_char) { + data_len--; + } + *use_key_len = data_len; + } else { + *use_key = const_cast(key + offset); + *use_key_len = data_len; + } + + return; +} + +static void tse_index_make_up_key_length(int *key, uint8_t **origin_key, uint32_t *origin_key_len, uint32_t length) { + int tmp_key = 0; + uint8_t *tmp_key_ptr = (uint8_t *)&tmp_key; + memcpy(tmp_key_ptr, *origin_key, *origin_key_len); + + // 通过符号位补齐高位字段 + if ((*origin_key_len == 1 && (tmp_key & 0x80)) || // 1表示MYSQL_TYPE_TINY类型,0x80用于获取origin_key的符号位 + (*origin_key_len == 2 && (tmp_key & 0x8000)) || // 2表示MYSQL_TYPE_SHORT类型,0x8000用于获取origin_key的符号位 + (*origin_key_len == 3 && (tmp_key & 0x800000))) { // 3表示MMYSQL_TYPE_INT24类型,0x800000用于获取origin_key的符号位 + *key = 0xFFFFFFFF; // 将key的bit位全赋值为1 + } else { + *key = 0; + } + + memcpy(key, *origin_key, *origin_key_len); + *origin_key = reinterpret_cast(key); + *origin_key_len = length; + + return; +} + +int tse_fill_index_key_info(TABLE *table, const uchar *key, uint key_len, const key_range *end_range, + index_key_info_t *index_key_info) { + const uchar *my_key = nullptr; + const uchar *end_key = key + key_len; + if (end_range != nullptr) { + my_key = end_range->key; + } + + index_key_info->key_num = 0; + do { + if (index_key_info->key_num >= table->key_info[index_key_info->active_index].actual_key_parts) { + tse_log_error("tse_fill_index_key_info: colunm id(%d) is bigger than table key parts(%d).", + index_key_info->key_num, table->key_info[index_key_info->active_index].actual_key_parts); + return ERR_GENERIC_INTERNAL_ERROR; + } + + KEY_PART_INFO key_part = table->key_info[index_key_info->active_index].key_part[index_key_info->key_num]; + uint32_t data_field_len = 0; + tse_convert_mysql_key_to_cantian(key_part, key, key_len, &data_field_len, + &index_key_info->key_info[index_key_info->key_num].left_key, + &index_key_info->key_info[index_key_info->key_num].left_key_len, + &index_key_info->key_info[index_key_info->key_num].is_key_null); + + if (end_range != nullptr && my_key < end_range->key + end_range->length) { + tse_convert_mysql_key_to_cantian(key_part, my_key, end_range->length, &data_field_len, + &index_key_info->key_info[index_key_info->key_num].right_key, + &index_key_info->key_info[index_key_info->key_num].right_key_len, + &index_key_info->key_info[index_key_info->key_num].is_key_null); + } + + key += data_field_len; + if (end_range != nullptr && my_key < end_range->key + end_range->length) { + my_key += data_field_len; + } + + ++index_key_info->key_num; + } while ((key < end_key) && (key_len != 0)); + + for (uint i = index_key_info->key_num; i < table->key_info[index_key_info->active_index].actual_key_parts; ++i) { + index_key_info->key_info[i].is_key_null = true; + } + + return CT_SUCCESS; +} + +int tse_convert_key_from_mysql_to_cantian(Field *field, uint8_t **mysql_ptr, dec4_t *cantian_ptr, uint32_t *len) +{ + int ret = CT_SUCCESS; + const field_cnvrt_aux_t *mysql_info = get_auxiliary_for_field_convert(field, field->type()); + // 针对tiny和short类型,对应到daac是int类型,所以key length需要按照daac大小的存储 + if (mysql_info->mysql_field_type == MYSQL_TYPE_TINY || mysql_info->mysql_field_type == MYSQL_TYPE_SHORT || + mysql_info->mysql_field_type == MYSQL_TYPE_INT24) { + tse_index_make_up_key_length(reinterpret_cast(cantian_ptr), mysql_ptr, len, sizeof(int)); + + return ret; + } + + if (field->type() == MYSQL_TYPE_BIT) { + *(int64_t *)cantian_ptr = bit_cnvt_mysql_cantian(*mysql_ptr, field); + *len = TSE_BYTE_8; + *mysql_ptr = reinterpret_cast(cantian_ptr); + return ret; + } + + if (field->type() == MYSQL_TYPE_FLOAT) { + double temp; + temp = **(float **)mysql_ptr; + memcpy((void *)cantian_ptr, &temp, sizeof(double)); + *mysql_ptr = reinterpret_cast(cantian_ptr); + *len = sizeof(double); + + return ret; + } + + if (mysql_info->sql_data_type == DATETIME_DATA) { + ret = convert_datetime_to_cantian(mysql_info, reinterpret_cast(cantian_ptr), *mysql_ptr, field); + if (ret != CT_SUCCESS) { + tse_log_error("tse convert index datatime to cantian failed."); + return ret; + } + + *mysql_ptr = reinterpret_cast(cantian_ptr); + *len = sizeof(date_t); + return ret; + } + + if (field->type() == MYSQL_TYPE_DECIMAL || field->type() == MYSQL_TYPE_NEWDECIMAL) { + ret = decimal_mysql_to_cantian(*mysql_ptr, reinterpret_cast(cantian_ptr), field, len); + if (ret != CT_SUCCESS) { + tse_log_error("tse convert index decimal to cantian failed."); + return ret; + } + + *mysql_ptr = reinterpret_cast(cantian_ptr); + } + + return ret; +} + +int tse_convert_index_datatype(TABLE *table, index_key_info_t *index_key_info, bool has_right_key, dec4_t *data) { + int ret; + + for (int i = 0; i < index_key_info->key_num; ++i) { + Field *field = table->key_info[index_key_info->active_index].key_part[i].field; + if (index_key_info->key_info[i].left_key_len != 0) { + ret = tse_convert_key_from_mysql_to_cantian(field, &index_key_info->key_info[i].left_key, data++, &index_key_info->key_info[i].left_key_len); + if (ret != CT_SUCCESS) { + tse_log_error("tse_convert_key_from_mysql_to_cantian: convert mysql index search left key failed, ret(%d).", ret); + return ret; + } + } + + if (has_right_key && index_key_info->key_info[i].right_key_len != 0) { + ret = tse_convert_key_from_mysql_to_cantian(field, &index_key_info->key_info[i].right_key, data++, &index_key_info->key_info[i].right_key_len); + if (ret != CT_SUCCESS) { + tse_log_error("tse_convert_key_from_mysql_to_cantian: convert mysql index search right key failed, ret(%d).", ret); + return ret; + } + } + } + + return CT_SUCCESS; +} \ No newline at end of file diff --git a/storage/tianchi/datatype_cnvrt_4_index_search.h b/storage/tianchi/datatype_cnvrt_4_index_search.h new file mode 100644 index 0000000..831a441 --- /dev/null +++ b/storage/tianchi/datatype_cnvrt_4_index_search.h @@ -0,0 +1,25 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "sql/dd/types/table.h" +#include "tse_srv.h" +#include "datatype_cnvrtr.h" +#include "decimal_convert.h" + +int tse_fill_index_key_info(TABLE *table, const uchar *key, uint key_len, const key_range *end_range, + index_key_info_t *index_key_info); + +int tse_convert_index_datatype(TABLE *table, index_key_info_t *index_key_info, bool has_right_key, dec4_t *data); diff --git a/storage/tianchi/datatype_cnvrtr.cc b/storage/tianchi/datatype_cnvrtr.cc new file mode 100644 index 0000000..f9fc4a5 --- /dev/null +++ b/storage/tianchi/datatype_cnvrtr.cc @@ -0,0 +1,1824 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "field_types.h" +#include "sql/field.h" +#include "sql/sql_class.h" +#include "my_bitmap.h" +#include "datatype_cnvrtr.h" +#include "sql/tztime.h" // my_tz_find, my_tz_OFFSET0 +#include "m_string.h" +#include "myisampack.h" // mi_int2store +#include "tse_error.h" +#include "tse_log.h" +#include "decimal_convert.h" +#include "tse_srv.h" +#include "sql/json_dom.h" + +#define LOWER_LENGTH_BYTES (uint8)0x01 // Bytes that are used to represent the length of variable length data + +#define UNITS_PER_DAY 86400000000LL +#define SECONDS_PER_HOUR 3600U +#define SECONDS_PER_MIN 60U +#define CM_BASELINE_DAY ((int32)730120) /* == days_before_year(CM_BASELINE_YEAY) + 1 */ +#define DAYS_1 365 +#define DAYS_4 (DAYS_1 * 4 + 1) +#define DAYS_100 (DAYS_4 * 25 - 1) +#define DAYS_400 (DAYS_100 * 4 + 1) +#define IS_LEAP_YEAR(year) (((year) % 4 == 0) && (((year) % 100 != 0) || ((year) % 400 == 0)) ? 1 : 0) +#define SECONDS_PER_DAY 86400U +#define CM_MIN_YEAR 1 +#define CM_MAX_YEAR 9999 +/** Check whether the year is valid */ +#define CM_IS_VALID_YEAR(year) ((year) >= CM_MIN_YEAR && (year) <= CM_MAX_YEAR) +#define CT_SPRS_COLUMNS (uint32)1024 +#define CM_ALIGN16(size) ((((size)&0x0F) == 0) ? (size) : ((size) + 0x10 - ((size)&0x0F))) +#define OFFSET_OF offsetof +#define IS_SPRS_ROW(row) ((row)->column_count == 0) + +uint16 g_cantian_month_days[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +#define CM_MONTH_DAYS(year, mon) (g_cantian_month_days[IS_LEAP_YEAR(year)][(mon) - 1]) + +/** + Obtains the mapping between MySQL data types and Cantian data types, including the storage format + and DDL transmission on the Cantian side.according to the field type (not real_type()). + MYSQL_TYPE_ENUM -> MYSQL_TYPE_TINY(0-255),MYSQL_TYPE_SHORT(>255) + MYSQL_TYPE_SET -> MYSQL_TYPE_TINY(0-8),MYSQL_TYPE_SHORT(8-16),MYSQL_TYPE_INT24(16-32),MYSQL_TYPE_LONGLONG(32-64) + Tips:if add new val in enum_field_types, should update this array! +*/ +static field_cnvrt_aux_t g_field_cnvrt_aux_array[] = { + {MYSQL_TYPE_DECIMAL, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_DECIMAL }, + {MYSQL_TYPE_TINY, CANTIAN_COL_BITS_4, NUMERIC_DATA, TSE_DDL_TYPE_LONG }, + {MYSQL_TYPE_SHORT, CANTIAN_COL_BITS_4, NUMERIC_DATA, TSE_DDL_TYPE_LONG }, + {MYSQL_TYPE_LONG, CANTIAN_COL_BITS_4, NUMERIC_DATA, TSE_DDL_TYPE_LONG }, + {MYSQL_TYPE_FLOAT, CANTIAN_COL_BITS_8, NUMERIC_DATA, TSE_DDL_TYPE_DOUBLE }, + {MYSQL_TYPE_DOUBLE, CANTIAN_COL_BITS_8, NUMERIC_DATA, TSE_DDL_TYPE_DOUBLE }, + {MYSQL_TYPE_NULL, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_NULL }, + {MYSQL_TYPE_TIMESTAMP, CANTIAN_COL_BITS_8, DATETIME_DATA, TSE_DDL_TYPE_TIMESTAMP }, + {MYSQL_TYPE_LONGLONG, CANTIAN_COL_BITS_8, NUMERIC_DATA, TSE_DDL_TYPE_LONGLONG }, + {MYSQL_TYPE_INT24, CANTIAN_COL_BITS_4, NUMERIC_DATA, TSE_DDL_TYPE_LONG }, + {MYSQL_TYPE_DATE, CANTIAN_COL_BITS_8, DATETIME_DATA, TSE_DDL_TYPE_DATE }, + {MYSQL_TYPE_TIME, CANTIAN_COL_BITS_8, DATETIME_DATA, TSE_DDL_TYPE_TIME }, + {MYSQL_TYPE_DATETIME, CANTIAN_COL_BITS_8, DATETIME_DATA, TSE_DDL_TYPE_DATETIME }, + {MYSQL_TYPE_YEAR, CANTIAN_COL_BITS_8, DATETIME_DATA, TSE_DDL_TYPE_YEAR }, + {MYSQL_TYPE_NEWDATE, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_NEWDATE }, + {MYSQL_TYPE_VARCHAR, CANTIAN_COL_BITS_VAR, STRING_DATA, TSE_DDL_TYPE_VARCHAR }, + {MYSQL_TYPE_BIT, CANTIAN_COL_BITS_8, NUMERIC_DATA, TSE_DDL_TYPE_LONGLONG }, + {MYSQL_TYPE_TIMESTAMP2, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_TIMESTAMP2 }, + {MYSQL_TYPE_DATETIME2, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_DATETIME2 }, + {MYSQL_TYPE_TIME2, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_TIME2 }, + {MYSQL_TYPE_TYPED_ARRAY, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_TYPED_ARRAY}, + // > MYSQL_TYPE_INVALID + {MYSQL_TYPE_JSON, CANTIAN_COL_BITS_VAR, LOB_DATA, TSE_DDL_TYPE_JSON }, + {MYSQL_TYPE_NEWDECIMAL, CANTIAN_COL_BITS_VAR, NUMERIC_DATA, TSE_DDL_TYPE_NEWDECIMAL }, + {MYSQL_TYPE_TINY_BLOB, CANTIAN_COL_BITS_VAR, LOB_DATA, TSE_DDL_TYPE_TINY_BLOB }, + {MYSQL_TYPE_MEDIUM_BLOB, CANTIAN_COL_BITS_VAR, LOB_DATA, TSE_DDL_TYPE_MEDIUM_BLOB}, + {MYSQL_TYPE_LONG_BLOB, CANTIAN_COL_BITS_VAR, LOB_DATA, TSE_DDL_TYPE_LONG_BLOB }, + {MYSQL_TYPE_BLOB, CANTIAN_COL_BITS_VAR, LOB_DATA, TSE_DDL_TYPE_BLOB }, + // The following two types not used for datatype convert, Unconfirmed scenarios in which this feature will be used. + {MYSQL_TYPE_VAR_STRING, CANTIAN_COL_BITS_NULL, UNKNOW_DATA, TSE_DDL_TYPE_VAR_STRING }, + {MYSQL_TYPE_STRING, CANTIAN_COL_BITS_VAR, STRING_DATA, TSE_DDL_TYPE_STRING } +}; +/** + get idx in g_field_cnvrt_aux_array. + Tips: when add new val in g_field_cnvrt_aux_array, should also update this func! +*/ +int32_t get_idx_for_field_convert(enum_field_types mysql_field_type) +{ + if (mysql_field_type < MYSQL_TYPE_INVALID) { + return mysql_field_type; + } + if (mysql_field_type >= MYSQL_TYPE_JSON && mysql_field_type <= MYSQL_TYPE_NEWDECIMAL) { + return mysql_field_type - MYSQL_TYPE_JSON + (MYSQL_TYPE_TYPED_ARRAY - MYSQL_TYPE_DECIMAL + 1); + } + if (mysql_field_type >= MYSQL_TYPE_TINY_BLOB && mysql_field_type <= MYSQL_TYPE_STRING) { + return mysql_field_type - MYSQL_TYPE_TINY_BLOB + (MYSQL_TYPE_TYPED_ARRAY - MYSQL_TYPE_DECIMAL + 1) + + (MYSQL_TYPE_NEWDECIMAL - MYSQL_TYPE_JSON + 1) ; + } + return -1; +} + +const field_cnvrt_aux_t* get_auxiliary_for_field_convert(Field *field, enum_field_types mysql_field_type) +{ + if (mysql_field_type < MYSQL_TYPE_INVALID) { + return &g_field_cnvrt_aux_array[mysql_field_type]; + } + enum_field_types mysql_real_type = mysql_field_type; + if (field->real_type() == MYSQL_TYPE_ENUM || + field->real_type() == MYSQL_TYPE_SET) { + uint field_len = field->pack_length(); + switch (field_len) { + case 1: + mysql_real_type = MYSQL_TYPE_TINY; + break; + case 2: + mysql_real_type = MYSQL_TYPE_SHORT; + break; + case 3: + mysql_real_type = MYSQL_TYPE_INT24; + break; + case 4: + mysql_real_type = MYSQL_TYPE_LONG; + break; + case 8: + default: + mysql_real_type = MYSQL_TYPE_LONGLONG; + break; + } + } + int32_t idx = get_idx_for_field_convert(mysql_real_type); + if (idx == -1) { + return nullptr; + } + field_cnvrt_aux_t* ret = &g_field_cnvrt_aux_array[idx]; + + if (field->is_flag_set(BLOB_FLAG)) { + if (field->charset() == &my_charset_bin && + field->is_flag_set(BINARY_FLAG)) { + ret->ddl_field_type = TSE_DDL_TYPE_BLOB; + } else { + ret->ddl_field_type = TSE_DDL_TYPE_CLOB; + } + } + + return ret; +} + +static inline void cm_decode_leap(date_detail_t *detail, int32 *d) +{ + uint32 hundred_count; + int32 days = *d; + + while (days >= DAYS_400) { + detail->year += 400; + days -= DAYS_400; + } + + for (hundred_count = 1; days >= DAYS_100 && hundred_count < 4; hundred_count++) { + detail->year += 100; + days -= DAYS_100; + } + + while (days >= DAYS_4) { + detail->year += 4; + days -= DAYS_4; + } + + while (days > DAYS_1) { + if (IS_LEAP_YEAR(detail->year)) { + days--; + } + + detail->year++; + days -= DAYS_1; + } + + *d = days; +} + +static void cm_set_all_zero_detail(date_detail_t *detail) +{ + detail->year = 0; + detail->mon = 0; + detail->day = 0; + detail->hour = 0; + detail->min = 0; + detail->sec = 0; + detail->millisec = 0; + detail->microsec = 0; + detail->nanosec = 0; + return; +} + +/** + @brief + decode cantian date +*/ +void cm_decode_date(date_t date, date_detail_t *detail) +{ + int32 i; + int32 days; + uint16 *day_tab = NULL; + int64 time; + + if (detail == nullptr) { + assert(0); + } + + if (date == CM_ALL_ZERO_DATETIME) { + cm_set_all_zero_detail(detail); + return; + } + + // decode time + time = date; + date /= UNITS_PER_DAY; + time -= date * UNITS_PER_DAY; + + if (time < 0) { + time += UNITS_PER_DAY; + date -= 1; + } + + detail->microsec = (uint16)(time % MICROSECS_PER_MILLISEC); + time /= MICROSECS_PER_MILLISEC; + + detail->millisec = (uint16)(time % MILLISECS_PER_SECOND); + time /= MILLISECS_PER_SECOND; + + detail->hour = (uint8)(time / SECONDS_PER_HOUR); + time -= (uint32)detail->hour * SECONDS_PER_HOUR; + + detail->min = (uint8)(time / SECONDS_PER_MIN); + time -= (uint32)detail->min * SECONDS_PER_MIN; + + detail->sec = (uint8)time; + + // "days -> (year, month, day), considering 01-Jan-0001 as day 1." + days = (int32)(date + CM_BASELINE_DAY); // number of days since 1.1.1 to the date + detail->year = 1; + + cm_decode_leap(detail, &days); + + if (days == 0) { + detail->year--; + detail->mon = 12; + detail->day = 31; + } else { + day_tab = g_cantian_month_days[IS_LEAP_YEAR(detail->year)]; + detail->mon = 1; + + i = 0; + while (days > (int32)day_tab[i]) { + days -= (int32)day_tab[i]; + i++; + } + + detail->mon = (uint8)(detail->mon + i); + detail->day = (uint8)(days); + } +} + +/* "year -> number of days before January 1st of year" */ +static inline int32 days_before_year(int32 year) +{ + --year; + return year * 365 + year / 4 - year / 100 + year / 400; +} + +static inline int32 total_days_before_date(const date_detail_t *detail) +{ + int32 i; + int32 total_days; + + if (detail == nullptr) { + assert(0); + } + + // compute total days + total_days = days_before_year((int32)detail->year) - CM_BASELINE_DAY; + uint16 *day_tab = (uint16 *)g_cantian_month_days[IS_LEAP_YEAR(detail->year)]; + for (i = 0; i < (int32)(detail->mon - 1); i++) { + total_days += (int32)day_tab[i]; + } + total_days += detail->day; + + return total_days; +} +/** + @brief + encode cantian date +*/ +void cm_encode_date(const date_detail_t *detail, date_t *date) +{ + int32 total_days; + + if (detail == nullptr) { + assert(0); + } + + if (check_zero_date(*detail)) { + *date = CM_ALL_ZERO_DATETIME; + return; + } + + assert(CM_IS_VALID_YEAR(detail->year)); + assert(detail->mon >= 1 && detail->mon <= 12); + assert(detail->day >= 1 && detail->day <= 31); + assert(detail->hour <= 23); + assert(detail->min <= 59); + assert(detail->sec <= 59); + assert(detail->microsec <= 999); + assert(detail->millisec <= 999); + + // compute total days + total_days = total_days_before_date(detail); + + // encode the date into an integer with 1 nanosecond as the the minimum unit + *date = (int64)total_days * SECONDS_PER_DAY; + *date += (uint32)detail->hour * SECONDS_PER_HOUR; + *date += (uint32)detail->min * SECONDS_PER_MIN; + *date += detail->sec; + *date = *date * MILLISECS_PER_SECOND + detail->millisec; + *date = *date * MICROSECS_PER_MILLISEC + detail->microsec; + return; +} + +/** + @brief + Reads a uint32_t stored in the little-endian format. + @param[in] buf from where to read. + @return the value in uint32_t format. +*/ +static inline uint32_t read_from_2_little_endian(const uint8_t *buf) +{ + return ((uint32_t)(buf[0]) | ((uint32_t)(buf[1]) << 8)); +} + +/** + @brief + decimal is stored by my_decimal struct in mysql , and stored by dec4_t in cantian; + mysql->cantian: mysql_ptr -> my_decimal -> str -> dec8_t -> dec4_t + decimal(prec,scale):prec indicates the maximum number of significant digits, + scale indicates the maximum number of decimal places that can be stored. +*/ +int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field, uint32 *length) +{ + int ret = 0; + const int scale = mysql_field->decimals(); + Field_new_decimal *f = (Field_new_decimal *)mysql_field; + const int prec = f->precision; + my_decimal d; + ret = binary2my_decimal(E_DEC_FATAL_ERROR, mysql_ptr, &d, prec, scale); + if (ret != E_DEC_OK) { + tse_log_error("[mysql2cantians]Decimal data type convert binary to my_decimal failed!"); + return ret; + } + char buff[DECIMAL_MAX_STR_LENGTH + 1]; + int len = sizeof(buff); + ret = decimal2string(&d, buff, &len); + if (ret != E_DEC_OK) { + tse_log_error("[mysql2cantian]Decimal data type convert my_decimal to string failed!"); + return ret; + } + dec8_t d8; + if (ct_cm_str_to_dec8(buff, &d8) != CT_SUCCESS_STATUS) { + tse_log_error("[mysql2cantian]Decimal data type convert str to dec8 failed!"); + assert(0); + } + cm_dec_8_to_4((dec4_t *)cantian_ptr, &d8); + *length = (uint32)cm_dec4_stor_sz((dec4_t *)cantian_ptr); + return ret; +} + +void decimal_cantian_to_mysql(uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field) +{ + dec4_t *d4 = (dec4_t *)(char *)cantian_ptr; + dec8_t dec; + ct_cm_dec_4_to_8(&dec, d4, (uint32)cm_dec4_stor_sz(d4)); + char str[DEC_MAX_NUM_SAVING_PREC]; + if (ct_cm_dec8_to_str(&dec, DEC_MAX_NUM_SAVING_PREC, str) != CT_SUCCESS_STATUS) { + tse_log_error("[cantian2mysql]Decimal data type convert dec8 to str failed!"); + assert(0); + } + + my_decimal decimal_value; + const char *decimal_data = str; + const char *end = strend(decimal_data); + if (string2decimal(decimal_data, &decimal_value, &end) != E_DEC_OK) { + tse_log_error("[cantian2mysql]Decimal data type convert str to my_decimal failed!"); + assert(0); + } + + const int prec = ((Field_new_decimal *)mysql_field)->precision; + const int scale = mysql_field->decimals(); + if (my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_value, mysql_ptr, prec, scale) != E_DEC_OK) { + tse_log_error("[cantian2mysql]Decimal data type convert my_decimal to binary failed!"); + assert(0); + } +} + +static inline uint32 get_lob_locator_size(void* locator) +{ + lob_locator_t *lob = (lob_locator_t *)locator; + if (lob->head.is_outline) { + return sizeof(lob_locator_t); + } + return (uint32)(lob->head.size + OFFSET_OF(lob_locator_t, data)); +} + +static inline uint32_t get_blob_buffer_size(uint32_t remain_size) +{ + if (remain_size < LOB_DATA_SIZE_100K) { + return g_blob_field_buffer_size_map.at(LOB_DATA_SIZE_100K); + } + + if (remain_size < LOB_DATA_SIZE_1M) { + return g_blob_field_buffer_size_map.at(LOB_DATA_SIZE_1M); + } + + if (remain_size < LOB_DATA_SIZE_8M) { + return g_blob_field_buffer_size_map.at(LOB_DATA_SIZE_8M); + } + + return LOB_DATA_SIZE_8M; +} + +/** + @brief + blob data is stored in mysql Field_blob struct, which is in one piece of continuous memory + we can get the ptr and length from Field_blob get_blob_data and get_length interface, + then invoke the Cantian tse_knl_write_lob interface, write blob data to tse storage engine + piece by piece. It's important to note that one piece of blob data preferably greater than 4000, + because the tse storage engine is store blob data inline when blob data length less than 4000, + otherwise the blob data store outline. +*/ +int convert_blob_to_cantian(uchar *cantian_ptr, uint32 &cantian_offset, + uchar *blob_str, uint32 remain_size, + tianchi_handler_t &tch, uint column_id, uint32_t &field_len) { + uint32_t buffer_size = get_blob_buffer_size(remain_size); + assert(buffer_size >= TSE_LOB_LOCATOR_BUF_SIZE); + + lob_text_t piece_lob; + uint32_t offset = 0; + lob_locator_t *lob_locator = nullptr; + uint32 locator_size = OFFSET_OF(lob_locator_t, data) + remain_size; + locator_size = locator_size > TSE_LOB_LOCATOR_BUF_SIZE ? TSE_LOB_LOCATOR_BUF_SIZE : locator_size; + lob_locator = (lob_locator_t *)my_malloc(PSI_NOT_INSTRUMENTED, locator_size, MYF(MY_WME)); + if (lob_locator == nullptr) { + tse_log_error("[mysql2cantian]Apply for lob locator:%u Failed", locator_size); + my_error(ER_OUT_OF_RESOURCES, MYF(0), "LOB LOCATOR"); + field_len = 0; + return HA_ERR_SE_OUT_OF_MEMORY; + } + memset(lob_locator, 0xFF, locator_size); + lob_locator->head.size = 0; + // for inline + if (remain_size <= TSE_LOB_MAX_INLINE_SIZE) { + lob_locator->head.type = 0; + lob_locator->head.is_outline = false; + lob_locator->head.size = remain_size; + memcpy(lob_locator->data, blob_str, remain_size); + remain_size = 0; + } + // for outline + bool force_outline = false; + while (remain_size > 0) { + piece_lob.str = (char *) blob_str + offset; + piece_lob.len = remain_size > buffer_size ? buffer_size : remain_size; + int ret = tse_knl_write_lob(&tch, (char *)lob_locator, locator_size, column_id, + (void *)piece_lob.str, (uint32_t)piece_lob.len, force_outline); + if (ret != CT_SUCCESS) { + tse_log_error("[mysql2cantian]tse_knl_write_lob Failed:%d", ret); + my_free(lob_locator); + lob_locator = nullptr; + field_len = 0; + return convert_tse_error_code_to_mysql((ct_errno_t)ret); + } + if (!force_outline) { + force_outline = true; + } + remain_size -= piece_lob.len; + offset += piece_lob.len; + } + // get cantian Field_len and store the length + field_len = get_lob_locator_size(lob_locator); + // store the length data + *(uint16_t *)&cantian_ptr[cantian_offset] = field_len; + cantian_offset += sizeof(uint16_t); + // copy data + memcpy(&cantian_ptr[cantian_offset], lob_locator, field_len); + + my_free(lob_locator); + lob_locator = nullptr; + return CT_SUCCESS; +} + +void convert_json_to_mysql(Field *mysql_field) +{ + // json binary serialize + if (mysql_field->type() == MYSQL_TYPE_JSON) { + Field_json *json = (Field_json *)mysql_field; + Json_wrapper wr; + if (bitmap_is_set(json->table->read_set, mysql_field->field_index()) && json->val_json(&wr)) { + tse_log_error("[convert_json_to_mysql] get json value failed"); + assert(0); + } + } + return; +} +/** + @brief + The blob data stored in the TSE storage engine can be in-line or out-line scenarios. + However, you can query the blob data by calling the tse_knl_read_lob interface in + sharding mode. Then you need to assemble the fragmented data into a whole memory block + and insert it into the MySQL by delivery the address of lob buf. +*/ +void convert_blob_to_mysql(uchar *cantian_ptr, Field *mysql_field, tianchi_handler_t &tch, uint8_t *mysql_ptr) +{ + bitmap_set_bit(mysql_field->table->read_set, mysql_field->field_index()); + lob_locator_t *locator = (lob_locator_t *)(uint8*)cantian_ptr; + uint32_t blob_len = locator->head.size; + char *blob_buf = (char *)my_malloc(PSI_NOT_INSTRUMENTED, blob_len * sizeof(char), MYF(MY_WME)); + if (blob_len == 0) { + tse_log_note("[cantian2mysql]data type %d for 0 length", mysql_field->type()); + // Insert in Mysql when the data is empty + memcpy(mysql_ptr, &blob_buf, sizeof(char *)); + convert_json_to_mysql(mysql_field); + return; + } + + if (blob_buf == nullptr) { + tse_log_error("[cantian2mysql]Apply for blob buf:%u Failed", blob_len); + my_error(ER_OUT_OF_RESOURCES, MYF(0), "BLOB DATA"); + return; + } + + if (!locator->head.is_outline) { + memcpy(blob_buf, locator->data, blob_len); + memcpy(mysql_ptr, &blob_buf, sizeof(char *)); + convert_json_to_mysql(mysql_field); + return; + } + + uint32_t buffer_size = get_blob_buffer_size(locator->head.size); + uint32_t piece_len = buffer_size; + uint32_t offset = 0; + uint32_t read_size = 0; + + uint32_t remain_size = blob_len; + bool read_flag = true; + // read blob data piece by piece + while (remain_size > 0) { + piece_len = remain_size > buffer_size ? buffer_size : remain_size; + int ret = tse_knl_read_lob(&tch, (char *)locator, offset, blob_buf + offset, piece_len, &read_size); + if (ret != CT_SUCCESS) { + tse_log_error("[cantian2mysql]tse_knl_read_lob Failed : %d", ret); + read_flag = false; + break; + } + if (read_size <= 0) { + tse_log_note("[cantian2mysql]tse_knl_read_lob read lob length is %d,stop read!", read_size); + read_flag = false; + break; + } + remain_size -= read_size; + offset += read_size; + } + + if (!read_flag) { + my_free(blob_buf); + blob_buf = nullptr; + } + // Insert in Mysql,notify:do not free blob_buf + memcpy(mysql_ptr, &blob_buf, sizeof(char *)); + convert_json_to_mysql(mysql_field); + return; +} + +static inline void row_set_column_bits2(row_head_t *row, uint8_t bits, + uint32_t col_id) +{ + uint32_t map_id; + uint8_t *bitmap = nullptr; + + map_id = col_id >> 2; + bitmap = row->bitmap; + + // erase bits + bitmap[map_id] &= ~(0x03 << ((col_id & 0x03) << 1)); + + // set bits + bitmap[map_id] |= bits << (((uint8_t)(col_id & 0x03)) << 1); +} + +static inline uint8_t row_get_column_bits2(row_head_t *row, uint32_t id) +{ + uint32_t map_id; + uint8_t *bitmap = nullptr; + + map_id = id >> 2; + bitmap = row->bitmap; + + return (uint8_t)(bitmap[map_id] >> ((id & 0x03) << 1)) & (uint8_t)0x03; +} + +static inline uint16 col_bitmap_ex_size(uint16 cols) +{ + if (cols >= CT_SPRS_COLUMNS) { + return (uint16)(CM_ALIGN16(cols - 4) / 4); + } else { + return (uint16)((cols <= 12) ? 0 : (CM_ALIGN16(cols - 12) / 4)); + } +} + +void cal_gcol_cnts_for_update(Field **field, uint column_id, uint32_t *virtual_gcol_cnt) +{ + *virtual_gcol_cnt = 0; + for (uint i = 0; i < column_id; i++) { + Field *mysql_field = *(field + i); + if (mysql_field->is_gcol()) { + *virtual_gcol_cnt += 1; + } + } +} + +longlong bit_cnvt_mysql_cantian(const uchar *ptr, Field *mysql_field) +{ + ulonglong bits = 0; + Field_bit *field = (Field_bit *)mysql_field; + uint bytes_in_rec = field->bytes_in_rec; + if (field->bit_len) { + bits = get_rec_bits(field->bit_ptr, field->bit_ofs, field->bit_len); + bits <<= (bytes_in_rec * 8); + } + switch (bytes_in_rec) { + case 0: + return bits; + case 1: + return bits | (ulonglong)ptr[0]; + case 2: + return bits | mi_uint2korr(ptr); + case 3: + return bits | mi_uint3korr(ptr); + case 4: + return bits | mi_uint4korr(ptr); + case 5: + return bits | mi_uint5korr(ptr); + case 6: + return bits | mi_uint6korr(ptr); + case 7: + return bits | mi_uint7korr(ptr); + default: + return mi_uint8korr(ptr + bytes_in_rec - sizeof(longlong)); + } +} + +void bit_cnvt_cantian_mysql(const uchar *cantian_ptr, uchar *mysql_ptr, Field *mysql_field) +{ + ulonglong bits = 0; + Field_bit *field = (Field_bit *)mysql_field; + uint bytes_in_rec = field->bytes_in_rec; + if (field->bit_len) { + bits = get_rec_bits(field->bit_ptr, field->bit_ofs, field->bit_len); + bits <<= (bytes_in_rec * 8); + } + switch (bytes_in_rec) { + case 0: + return; + case 1: + *(uint8 *)mysql_ptr = bits | (ulonglong)cantian_ptr[0]; + return; + case 2: + *(uint16 *)mysql_ptr = bits | mi_uint2korr(cantian_ptr); + return; + case 3: + *(uint32 *)mysql_ptr = bits | mi_uint3korr(cantian_ptr); + return; + case 4: + *(uint32 *)mysql_ptr = bits | mi_uint4korr(cantian_ptr); + return; + case 5: + *(ulonglong *)mysql_ptr = bits | mi_uint5korr(cantian_ptr); + return; + case 6: + *(ulonglong *)mysql_ptr = bits | mi_uint6korr(cantian_ptr); + return; + case 7: + *(ulonglong *)mysql_ptr = bits | mi_uint7korr(cantian_ptr); + return; + default: + *(ulonglong *)mysql_ptr = mi_uint8korr(cantian_ptr + bytes_in_rec - sizeof(longlong)); + return; + } +} + +/** + @brief + convert numeric data from mysql to cantian +*/ +int convert_numeric_to_cantian(const field_cnvrt_aux_t *mysql_info, const uchar *mysql_ptr, uchar *cantian_ptr, + Field *mysql_field, uint32_t *length) +{ + int res = 0; + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_TINY: + *(int32_t *)cantian_ptr = *(const int8_t *)mysql_ptr; + break; + case MYSQL_TYPE_SHORT: + *(int32_t *)cantian_ptr = *(const int16_t *)mysql_ptr; + break; + case MYSQL_TYPE_INT24: + *(int32_t *)cantian_ptr = sint3korr(mysql_ptr); + break; + case MYSQL_TYPE_LONG: + *(int32_t *)cantian_ptr = *(const int32_t *)mysql_ptr; + break; + case MYSQL_TYPE_FLOAT: + *(double *)cantian_ptr = *(const float *)mysql_ptr; + break; + case MYSQL_TYPE_DOUBLE: + *(double *)cantian_ptr = *(const double *)mysql_ptr; + break; + case MYSQL_TYPE_BIT: + *(int64_t *)cantian_ptr = bit_cnvt_mysql_cantian(mysql_ptr, mysql_field); + break; + case MYSQL_TYPE_LONGLONG: + *(int64_t *)cantian_ptr = *(const int64_t *)mysql_ptr; + break; + case MYSQL_TYPE_NEWDECIMAL: + res = decimal_mysql_to_cantian(mysql_ptr, cantian_ptr, mysql_field, length); + break; + default: + tse_log_error("[mysql2cantian]unsupport numeric datatype %d", mysql_info->mysql_field_type); + assert(0); + break; + } + return res; +} + +/** + @brief + Decode year value from YEAR type which in Mysql format, and fill in other fields. + @note + In Mysql Format,The value of the YEAR type ranges from 1901 to 2155, and 0000. + For the value of year in the CantianDB must range from 1 to 9999, + the year field of MYSQL_TIME class uses 1900 instead of 0000. + @param[out] ltime The variable to convert to. + @param mysql_field mysql field class +*/ +static void decode_mysql_year_type(MYSQL_TIME& ltime, const uchar *mysql_ptr) +{ + // 1900 is officially defined by MySQL + ltime.year = (unsigned int)*mysql_ptr == 0 ? 0 : (unsigned int)*mysql_ptr + 1900; + ltime.month = ltime.year == 0 ? 0 : 1; + ltime.day = ltime.year == 0 ? 0 : 1; + ltime.hour = 0; + ltime.minute = 0; + ltime.second = 0; + ltime.second_part = 0; + ltime.neg = false; +} + +/** + @brief + Decode time value from TIME type which in Mysql format, and fill in other fields. + @note In Mysql Format,The value of the TIME type ranges from -838:59:59.000000 to 838:59:59.000000. + For the value of hour in the CantianDB must range from 0 to 23, the tse just support + TIME type range from 00:00:00.000000 to 23:59:59.000000. + @param[out] ltime The variable to convert to. + @param mysql_ptr The value to convert from, mysql time data ptr. + @param mysql_field mysql field class +*/ +static void decode_mysql_time_type(MYSQL_TIME& ltime, const uchar *mysql_ptr, Field *mysql_field) +{ + // decode mysql data + uint dec = mysql_field->decimals(); + longlong tmp = my_time_packed_from_binary(mysql_ptr, dec); + TIME_from_longlong_time_packed(<ime, tmp); + + // fill in other fields + ltime.year = 1900; + ltime.month = 1; + ltime.day = 1; +} + +/** + @brief + Decode date value from DATE type which in Mysql format, and fill in other fields. + @note reverse implementation of my_date_to_binary in my_time.cc + @param[out] ltime The variable to convert to. + @param mysql_ptr The value to convert from, mysql date data ptr. +*/ +static void decode_mysql_date_type(MYSQL_TIME& ltime, const uchar *mysql_ptr) +{ + int tmp = *mysql_ptr + (((int)*(mysql_ptr + 1)) << 8) + (((int)*(mysql_ptr + 2)) << 16); + ltime.year = tmp / 16 / 32; + ltime.month = tmp / 32 % 16; + ltime.day = tmp % 32; +} + +/** + @brief + Decode datetime value from DATETIME type which in Mysql format, and fill in other fields. + @param[out] ltime The variable to convert to. + @param mysql_ptr The value to convert from, mysql datetime data ptr. + @param mysql_field mysql field class +*/ +static void decode_mysql_datetime_type(MYSQL_TIME& ltime, const uchar *mysql_ptr, Field *mysql_field) +{ + uint dec = mysql_field->decimals(); + longlong packed = my_datetime_packed_from_binary(mysql_ptr, dec); + TIME_from_longlong_datetime_packed(<ime, packed); +} + +/** + @brief + Decode timestamp value from TIMESTAMP type which in Mysql format, and fill in other fields. + @param[out] ltime The variable to convert to. + @param mysql_ptr The value to convert from, mysql timestamp data ptr. + @param mysql_field mysql field class +*/ +static void decode_mysql_timestamp_type(MYSQL_TIME& ltime, const uchar *mysql_ptr, Field *mysql_field) +{ + uint dec = mysql_field->decimals(); + struct timeval tm; + my_timestamp_from_binary(&tm, mysql_ptr, dec); + if (tm.tv_sec == 0) { + return; + } + my_tz_UTC->gmt_sec_to_TIME(<ime, tm); +} + +/** + @brief + Decode all date and time Type which in Mysql format, and output to MYSQL_TIME class. + @note In Mysql Format,The value of the TIME type ranges from -838:59:59.000000 to 838:59:59.000000. + For the value of hour in the CantianDB must range from 0 to 23, the tse just support + TIME type range from 00:00:00.000000 to 23:59:59.000000. + @param[out] ltime The variable to convert to. + @param mysql_info mysql field type info. + @param mysql_ptr The value to convert from, mysql data ptr. + @param mysql_field mysql field class. +*/ +void decode_mysql_datetime(MYSQL_TIME& ltime, const field_cnvrt_aux_t* mysql_info, + const uchar *mysql_ptr, Field *mysql_field) +{ + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_YEAR: + decode_mysql_year_type(ltime, mysql_ptr); + break; + case MYSQL_TYPE_TIME: + decode_mysql_time_type(ltime, mysql_ptr, mysql_field); + break; + case MYSQL_TYPE_DATE: + decode_mysql_date_type(ltime, mysql_ptr); + break; + case MYSQL_TYPE_DATETIME: + decode_mysql_datetime_type(ltime, mysql_ptr, mysql_field); + break; + case MYSQL_TYPE_TIMESTAMP: + decode_mysql_timestamp_type(ltime, mysql_ptr, mysql_field); + break; + default: + tse_log_error("[mysql2cantian datetime]unsupport datatype %d", mysql_info->mysql_field_type); + assert(false); + } +} + +bool check_zero_date(const date_detail_t& date_detail) +{ + if (!(date_detail.year || date_detail.mon || date_detail.day || date_detail.hour || date_detail.min || + date_detail.sec || date_detail.millisec || date_detail.microsec || date_detail.nanosec)) { + return true; + } + return false; +} + +bool check_zero_time_ltime(const MYSQL_TIME ltime) +{ + if (!(ltime.year || ltime.month || ltime.day || ltime.hour || ltime.minute || ltime.second || ltime.second_part)) { + return true; + } + return false; +} + +/** + @brief + Before use cm_encode_date interface, check whether the date_detail_t value is correct. +*/ +bool check_datetime_vaild(const date_detail_t& date_detail) +{ + if (check_zero_date(date_detail)) { + return true; + } + + if (!CM_IS_VALID_YEAR(date_detail.year)) { + return false; + } + + if (date_detail.mon < 1 || date_detail.mon > 12) { + return false; + } + + if ((date_detail.day < 1) || (date_detail.day > CM_MONTH_DAYS(date_detail.year, date_detail.mon))) { + return false; + } + + if ((date_detail.hour > 23) || (date_detail.min > 59) || (date_detail.sec > 59)) { + return false; + } + + if ((date_detail.millisec > 999) || (date_detail.microsec > 999)) { + return false; + } + return true; +} + +int assign_mysql_date_detail(enum_field_types mysql_field_type, MYSQL_TIME ltime, date_detail_t *date_detail) +{ + // Assigning Values for date_detail_t + if (mysql_field_type == MYSQL_TYPE_TIME) { + ltime.year = ltime.year == 0 ? 1900 : ltime.year; + ltime.month = ltime.month == 0 ? 1 : ltime.month; + ltime.day = ltime.day == 0 ? 1 : ltime.day; + } + date_detail->day = ltime.year == 0 ? 0 : ltime.day; + date_detail->mon = ltime.year == 0 ? 0 : ltime.month; + date_detail->year = ltime.year; + date_detail->sec = ltime.second; + date_detail->min = ltime.minute; + date_detail->hour = ltime.hour; + date_detail->millisec = (uint16_t)(ltime.second_part / MICROSECS_PER_MILLISEC); + date_detail->microsec = (uint16_t)(ltime.second_part % MICROSECS_PER_MILLISEC); + date_detail->nanosec = 0; + date_detail->tz_offset = 0; + return 0; +} + +void cnvrt_time_decimal(const uchar *src_ptr, int src_dec, uchar *des_ptr, int des_dec, uint32 length) +{ + // convert decimal for MYSQL_TYPE_TIME + MYSQL_TIME ltime; + uchar tmp_ptr[TSE_BYTE_8] = {0}; + longlong packed = my_time_packed_from_binary(src_ptr, src_dec); + TIME_from_longlong_time_packed(<ime, packed); + // fill in other fields + ltime.year = 1900; + ltime.month = 1; + ltime.day = 1; + longlong ll = TIME_to_longlong_time_packed(ltime); + my_time_packed_to_binary(ll, tmp_ptr, des_dec); + memcpy(des_ptr, tmp_ptr, length); + return; +} + +void cnvrt_datetime_decimal(const uchar *src_ptr, int src_dec, uchar *des_ptr, int des_dec, uint32 length) +{ + // convert decimal for MYSQL_TYPE_DATETIME + MYSQL_TIME ltime; + uchar tmp_ptr[TSE_BYTE_8] = {0}; + longlong packed = my_datetime_packed_from_binary(src_ptr, src_dec); + TIME_from_longlong_datetime_packed(<ime, packed); + longlong ll = TIME_to_longlong_datetime_packed(ltime); + my_datetime_packed_to_binary(ll, tmp_ptr, des_dec); + memcpy(des_ptr, tmp_ptr, length); + return; +} + +/** + @brief + convert datetime data from mysql to cantian +*/ +int convert_datetime_to_cantian(const field_cnvrt_aux_t* mysql_info, uchar *cantian_ptr, + const uchar *mysql_ptr, Field *mysql_field) +{ + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_TIME: + cnvrt_time_decimal(mysql_ptr, mysql_field->decimals(), cantian_ptr, DATETIME_MAX_DECIMALS, TSE_BYTE_8); + break; + + case MYSQL_TYPE_DATETIME: + cnvrt_datetime_decimal(mysql_ptr, mysql_field->decimals(), cantian_ptr, DATETIME_MAX_DECIMALS, TSE_BYTE_8); + break; + + case MYSQL_TYPE_DATE: + memset(cantian_ptr, 0, TSE_BYTE_8); + memcpy(cantian_ptr, mysql_ptr, mysql_field->pack_length()); + break; + + default: + // decode mysql MYSQL_TYPE_YEAR and MYSQL_TYPE_TIMESTAMP from binary + MYSQL_TIME ltime; + memset(<ime, 0, sizeof(MYSQL_TIME)); + decode_mysql_datetime(ltime, mysql_info, mysql_ptr, mysql_field); + + date_detail_t date_detail; + int ret = assign_mysql_date_detail(mysql_info->mysql_field_type, ltime, &date_detail); + if (ret != 0) { + return ret; + } + + // encode cantian datetime to binary + cm_encode_date(&date_detail, (date_t *)cantian_ptr); + } + return 0; +} + +/** + @brief + convert numeric data from cantian to mysql +*/ +static void convert_numeric_to_mysql(const field_cnvrt_aux_t *mysql_info, uchar *mysql_ptr, + uchar *cantian_ptr, Field *mysql_field) +{ + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_TINY: + *(int8_t *)mysql_ptr = *(int32_t *)cantian_ptr; + break; + case MYSQL_TYPE_SHORT: + *(int16_t *)mysql_ptr = *(int32_t *)cantian_ptr; + break; + case MYSQL_TYPE_INT24: + // MEDIUMINT is 3 bytes at mysql side, get 3 bytes data from cantian_ptr + memcpy(mysql_ptr, cantian_ptr, 3 * sizeof(char)); + break; + case MYSQL_TYPE_LONG: + *(int32_t *)mysql_ptr = *(int32_t *)cantian_ptr; + break; + case MYSQL_TYPE_FLOAT: + *(float *)mysql_ptr = *(double *)cantian_ptr; + break; + case MYSQL_TYPE_DOUBLE: + *(double *)mysql_ptr = *(double *)cantian_ptr; + break; + case MYSQL_TYPE_BIT: + bit_cnvt_cantian_mysql(cantian_ptr, mysql_ptr, mysql_field); + break; + case MYSQL_TYPE_LONGLONG: + *(int64_t *)mysql_ptr = *(int64_t *)cantian_ptr; + break; + case MYSQL_TYPE_NEWDECIMAL: + decimal_cantian_to_mysql(mysql_ptr, cantian_ptr, mysql_field); + break; + default: + tse_log_error("[cantian2mysql]unsupport numeric datatype %d", mysql_info->mysql_field_type); + assert(0); + break; + } +} +/** + 逻辑拷贝自datetime_with_no_zero_in_date_to_timeval,在mysql 8.0.28及后续版本中改函数第三个参数类型由timeval改为 my_timeval,为了兼容不同版本,这个地方函数由自己实现 + Converts a datetime in MYSQL_TIME representation to corresponding `struct + timeval` value. + + `ltime` must be previously checked for `TIME_NO_ZERO_IN_DATE`. + Things like '0000-01-01', '2000-00-01', '2000-01-00' are not allowed + and asserted. + + Things like '0000-00-00 10:30:30' or '0000-00-00 00:00:00.123456' + (i.e. empty date with non-empty time) return error. + + Zero datetime '0000-00-00 00:00:00.000000' is allowed and is mapped to + {tv_sec=0, tv_usec=0}. + + @note In case of error, tm value is not initialized. + + @note `warnings` is not initialized to zero, so new warnings are added to the + old ones. The caller must make sure to initialize `warnings`. + + @param[in] ltime Datetime value + @param[in] tz Time zone to convert to. + @param[out] tm Timeval value + @param[out] warnings Pointer to warnings. + + @return False on success, true on error. +*/ +bool tse_datetime_with_no_zero_in_date_to_timeval(const MYSQL_TIME *ltime, + const Time_zone &tz, + struct timeval *tm, + int *warnings) +{ + if (!ltime->month) { + /* Zero date */ + assert(!ltime->year && !ltime->day); + if (non_zero_time(*ltime)) { + /* + Return error for zero date with non-zero time, e.g.: + '0000-00-00 10:20:30' or '0000-00-00 00:00:00.123456' + */ + *warnings |= MYSQL_TIME_WARN_TRUNCATED; + return true; + } + tm->tv_sec = tm->tv_usec = 0; // '0000-00-00 00:00:00.000000' + return false; + } + + bool is_in_dst_time_gap = false; + if (!(tm->tv_sec = tz.TIME_to_gmt_sec(ltime, &is_in_dst_time_gap))) { + /* + Date was outside of the supported timestamp range. + For example: '3001-01-01 00:00:00' or '1000-01-01 00:00:00' + */ + *warnings |= MYSQL_TIME_WARN_OUT_OF_RANGE; + return true; + } else if (is_in_dst_time_gap) { + /* + Set MYSQL_TIME_WARN_INVALID_TIMESTAMP warning to indicate + that date was fine but pointed to winter/summer time switch gap. + In this case tm is set to the fist second after gap. + For example: '2003-03-30 02:30:00 MSK' -> '2003-03-30 03:00:00 MSK' + */ + *warnings |= MYSQL_TIME_WARN_INVALID_TIMESTAMP; + } + tm->tv_usec = ltime->second_part; + return false; +} +/** + 逻辑拷贝自my_timestamp_to_binary,在mysql 8.0.28及后续版本中改函数第一个参数类型由timeval改为 my_timeval,为了兼容不同版本,这个地方函数由自己实现 + Convert in-memory timestamp representation to on-disk representation. + + @param tm The value to convert. + @param [out] ptr The pointer to store the value to. + @param dec Precision. +*/ +static void tse_my_timestamp_to_binary(const struct timeval *tm, uchar *ptr, uint dec) +{ + assert(dec <= DATETIME_MAX_DECIMALS); + /* Stored value must have been previously properly rounded or truncated */ + assert((tm->tv_usec % + static_cast(log_10_int[DATETIME_MAX_DECIMALS - dec])) == 0); + mi_int4store(ptr, tm->tv_sec); + switch (dec) { + case 0: + default: + break; + case 1: + case 2: + ptr[4] = + static_cast(static_cast(tm->tv_usec / 10000)); + break; + case 3: + case 4: + mi_int2store(ptr + 4, tm->tv_usec / 100); + break; + /* Impossible second precision. Fall through */ + case 5: + case 6: + mi_int3store(ptr + 4, tm->tv_usec); + } +} +/** + @brief + convert datetime data from cantian to mysql +*/ +static void convert_datetime_to_mysql(const field_cnvrt_aux_t* mysql_info, + uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field) +{ + if (mysql_info->mysql_field_type == MYSQL_TYPE_DATE) { + memcpy(mysql_ptr, cantian_ptr, mysql_field->pack_length()); + return; + } + if (mysql_info->mysql_field_type == MYSQL_TYPE_TIME) { + cnvrt_time_decimal(cantian_ptr, DATETIME_MAX_DECIMALS, mysql_ptr, mysql_field->decimals(), mysql_field->pack_length()); + return; + } + if (mysql_info->mysql_field_type == MYSQL_TYPE_DATETIME) { + cnvrt_datetime_decimal(cantian_ptr, DATETIME_MAX_DECIMALS, mysql_ptr, mysql_field->decimals(), mysql_field->pack_length()); + return; + } + date_detail_t date_detail; + date_t date = *(int64 *)cantian_ptr; + + // decode cantian data from binary to date_detail_t + cm_decode_date(date, &date_detail); + + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_YEAR: + *(uint8_t *)mysql_ptr = date_detail.year == 0 ? (uint8_t)0 : (uint8_t)(date_detail.year - 1900); + break; + case MYSQL_TYPE_TIMESTAMP: { + // Assigning Values for MYSQL_TIME + MYSQL_TIME ltime; + ltime.day = date_detail.day; + ltime.month = date_detail.mon; + ltime.year = date_detail.year; + ltime.second = date_detail.sec; + ltime.minute = date_detail.min; + ltime.hour = date_detail.hour; + ltime.second_part = (unsigned long)(date_detail.millisec * MICROSECS_PER_MILLISEC) + date_detail.microsec; + ltime.neg = false; + ltime.time_zone_displacement = 0; + ltime.time_type = MYSQL_TIMESTAMP_DATETIME_TZ; + + struct timeval tm; + int warnings = 0; + int dec = mysql_field->decimals(); + + tse_datetime_with_no_zero_in_date_to_timeval(<ime, *my_tz_OFFSET0, &tm, &warnings); + // Assume that since the value was properly stored, there're no warnings + assert(!warnings); + tse_my_timestamp_to_binary(&tm, mysql_ptr, dec); + break; + } + default: + tse_log_error("[cantian2mysql datetime]unsupport datatype %d", mysql_info->mysql_field_type); + assert(0); + break; + } +} + +/** + @brief + calculate the length of variable data and out put the mysql ptr offset + @param[in] mysql_info mysql field type info. + @param[in] mysql_field mysql field class. + @param[in] mysql_ptr the value to read from, mysql data ptr. + @param[out] data_offset space occupied by variable-length data types + @return the data length of variable-length data type +*/ +static uint32_t calculate_variable_len(const field_cnvrt_aux_t* mysql_info, Field *mysql_field, + const uint8_t *mysql_ptr, uint8_t& data_offset) +{ + uint32_t field_len = 0; + // check if it's mysql variable len field + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_VARCHAR: + data_offset = (uint8_t)mysql_field->get_length_bytes(); + if (data_offset == 1) { + field_len = *(const uint8_t *)mysql_ptr; + } else if (data_offset == 2) { + field_len = read_from_2_little_endian(mysql_ptr); + } else { + tse_log_error("[mysql2cantian]get varchar data length error: %u", data_offset); + } + break; + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_BLOB: { + Field_blob *dst_blob = down_cast(mysql_field); + data_offset = dst_blob->row_pack_length(); + field_len = dst_blob->get_length((const uchar*)mysql_ptr); + break; + } + case MYSQL_TYPE_STRING: { + field_len = mysql_field->row_pack_length(); + // Char类型内存优化 + if (mysql_field->real_type() == MYSQL_TYPE_STRING) { + while (field_len > 0 && mysql_ptr[field_len - 1] == mysql_field->charset()->pad_char) { + field_len--; + } + } + data_offset = 0; + break; + } + case MYSQL_TYPE_NEWDECIMAL: { + // field_len indicates the max bytes occupied by the decimal(prec,scale) column of Cantian + int scale = mysql_field->decimals(); + Field_new_decimal *f = (Field_new_decimal *)mysql_field; + int prec = f->precision; + // the number of cells(dec4_t) used to store the decimal(prec,scale) = (Integer part + decimal part) + int ncells = ALIGN_UP(prec - scale, 4) + ALIGN_UP(scale, 4); + field_len = (1 + ncells) * sizeof(uint16_t); + data_offset = 0; + break; + } + default: + tse_log_error("[mysql2cantian calculate length]unknow data type: %d", mysql_info->mysql_field_type); + data_offset = 0; + break; + } + return field_len; +} +/** + @brief + Padding Byte Length According the data length, and return mysql ptr offset +*/ +static uint8_t padding_variable_byte(const field_cnvrt_aux_t* mysql_info, + uint8_t *mysql_ptr, uint32 field_len, Field *field) +{ + uint8_t mysql_offset = 0; + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_VARCHAR: + mysql_offset = field->get_length_bytes(); + if (mysql_offset == LOWER_LENGTH_BYTES) { + *mysql_ptr = (uint8_t)field_len; + } else { + *(uint16_t *)mysql_ptr = field_len; + } + break; + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_BLOB: { + // MYSQL_TYPE_X_BLOB corresponding to pack_length + // which include MYSQL_TYPE_TINY_BLOB,MYSQL_TYPE_BLOB + // MYSQL_TYPE_MEDIUM_BLOB and MYSQL_TYPE_LONG_BLOB + Field_blob *dst_blob = down_cast(field); + mysql_offset = dst_blob->row_pack_length(); + dst_blob->store_length(mysql_ptr, mysql_offset, field_len); + break; + } + default: + tse_log_debug("[cantian2mysql]mysql field type: %d do not need data head", mysql_info->mysql_field_type); + break; + } + return mysql_offset; +} + +static void get_map_and_field_len(uint32_t &field_len, const field_cnvrt_aux_t* mysql_info, + field_offset_and_len_t *field_offset_info, + Field *field, record_buf_info_t *record_buf) +{ + switch (mysql_info->cantian_map_type) { + case CANTIAN_COL_BITS_4: + field_len = 4; + break; + case CANTIAN_COL_BITS_8: + field_len = 8; + break; + case CANTIAN_COL_BITS_VAR: + // Cantian always use 2 bytes to store the data length for variable-length data type. + // But when the type is MYSQL_TYPE_BLOB,the field_len need to calculate by lob_locator_t obj follow. + // The value may greater than 65535 only when the data type is LOB_DATA. + // Therefore, uint16_t is sufficient here. + // In addition, you do not need to worry that two bytes are insufficient because data larger than 4000 on the + // Cantian side is stored outside the row. + if (mysql_info->sql_data_type != LOB_DATA) { + uint8_t mysql_data_length_bytes = 0; + field_len = calculate_variable_len(mysql_info, field, + &record_buf->mysql_record_buf[*field_offset_info->mysql_field_offset], + mysql_data_length_bytes); + *field_offset_info->mysql_field_offset += mysql_data_length_bytes; + if (!((mysql_info->sql_data_type == STRING_DATA) && + VARCHAR_AS_BLOB(field->row_pack_length()))) { + *(uint16_t *)&record_buf + ->cantian_record_buf[*field_offset_info->cantian_field_offset] = + field_len; + *field_offset_info->cantian_field_offset += sizeof(uint16_t); + } + } + break; + default: + tse_log_error("[mysql2cantian]unknow col bits: %d", mysql_info->cantian_map_type); + assert(0); + break; + } +} + +static int convert_data_from_mysql_to_cantian(const field_cnvrt_aux_t* mysql_info, Field *field, + record_buf_info_t *record_buf, uint16_t *serial_column_offset, + field_offset_and_len_t *field_offset_info, + uint32_t &field_len, tianchi_handler_t &tch, uint column_id) +{ + int res = 0; + switch (mysql_info->sql_data_type) { + case NUMERIC_DATA: + res = convert_numeric_to_cantian(mysql_info, &record_buf->mysql_record_buf[*field_offset_info->mysql_field_offset], + &record_buf->cantian_record_buf[*field_offset_info->cantian_field_offset], + field, &field_len); + // 如果是自增列,记录自增列在cantian_record_buf中的offset + if (field->is_flag_set(AUTO_INCREMENT_FLAG)) { + *serial_column_offset = *field_offset_info->cantian_field_offset; + } + + if (field->type() == MYSQL_TYPE_NEWDECIMAL) { + *(uint16_t *)&record_buf->cantian_record_buf[*field_offset_info->cantian_field_offset - sizeof(uint16_t)] = + field_len; + } + + break; + case DATETIME_DATA: + res = convert_datetime_to_cantian(mysql_info, + &record_buf->cantian_record_buf[*field_offset_info->cantian_field_offset], + &record_buf->mysql_record_buf[*field_offset_info->mysql_field_offset], field); + break; + case STRING_DATA: + if (!VARCHAR_AS_BLOB(field->row_pack_length())) { + memcpy(&record_buf + ->cantian_record_buf[*field_offset_info->cantian_field_offset], + &record_buf + ->mysql_record_buf[*field_offset_info->mysql_field_offset], + field_len); + } else { + res = convert_blob_to_cantian( + record_buf->cantian_record_buf, + *field_offset_info->cantian_field_offset, + &record_buf + ->mysql_record_buf[*field_offset_info->mysql_field_offset], + field_len, tch, column_id, field_len); + } + break; + case LOB_DATA: { + Field_blob *dst_blob = down_cast(field); + uchar *blob_str = dst_blob->get_blob_data(); + uint32_t remain_size = dst_blob->get_length(); + res = convert_blob_to_cantian(record_buf->cantian_record_buf, + *field_offset_info->cantian_field_offset, + blob_str, remain_size, tch, column_id, field_len); + } break; + case UNKNOW_DATA: + default: + tse_log_error("[mysql2cantian]unsupport sql_data_type %d", mysql_info->sql_data_type); + assert(0); + break; + } + return res; +} + +int mysql_record_to_cantian_record(const TABLE &table, record_buf_info_t *record_buf, tianchi_handler_t &tch, + uint16_t *serial_column_offset, std::vector *fields) +{ + *serial_column_offset = 0; + bool is_update = fields != nullptr; + bool has_gcol = table.has_gcol(); + uint n_fields = is_update ? fields->size() : table.s->fields; + // Count the number of generated columns + uint32 virtual_gcol_cnt = 0; + if (has_gcol) { + cal_gcol_cnts_for_update(table.field, n_fields, &virtual_gcol_cnt); + } + uint32 ex_maps = col_bitmap_ex_size(n_fields - virtual_gcol_cnt); + virtual_gcol_cnt = 0; + uint32 cantian_field_offset = sizeof(row_head_t) + ex_maps; + row_head_t *row_head = (row_head_t *)record_buf->cantian_record_buf; + + for (uint column_cnt = 0; column_cnt < n_fields; column_cnt++) { + uint column_id = is_update ? fields->at(column_cnt) : column_cnt; + Field *field = table.field[column_id]; + + if (field->is_virtual_gcol()) { + if (is_update) { + fields->erase(fields->begin() + column_cnt); + column_cnt--; + n_fields--; + } else { + virtual_gcol_cnt++; + } + continue; + } + + // mark as not intialized + uint8_t map = 0xFF; + if (field->is_nullable()) { + uint mysql_null_byte_offset = field->null_offset(); + uint mysql_null_bit_mask = field->null_bit; + /* If the field is null */ + if (record_buf->mysql_record_buf[mysql_null_byte_offset] & mysql_null_bit_mask) { + map = 0; + if (is_update && has_gcol) { + cal_gcol_cnts_for_update(table.field, column_id, &virtual_gcol_cnt); + row_set_column_bits2(row_head, map, column_cnt); + fields->at(column_cnt) -= virtual_gcol_cnt; + } else { + row_set_column_bits2(row_head, map, column_cnt - virtual_gcol_cnt); + } + continue; + } + } + + uint32_t field_len = 0; + uint mysql_field_offset = field->offset(table.record[0]); + + // Get map and field_len , according to mysql_field type + const field_cnvrt_aux_t* mysql_info = get_auxiliary_for_field_convert(field, field->type()); + assert(mysql_info != NULL); + map = mysql_info->cantian_map_type; + field_offset_and_len_t field_offset_info = {nullptr, nullptr, &cantian_field_offset, &mysql_field_offset}; + get_map_and_field_len(field_len, mysql_info, &field_offset_info, field, record_buf); + + field_offset_info = {nullptr, nullptr, &cantian_field_offset, &mysql_field_offset}; + int res = convert_data_from_mysql_to_cantian(mysql_info, field, record_buf, serial_column_offset, + &field_offset_info, field_len, tch, column_id); + if (res != 0) { + return res; + } + + // set cantian bitmap for this column + if (is_update && has_gcol) { + cal_gcol_cnts_for_update(table.field, column_id, &virtual_gcol_cnt); + row_set_column_bits2(row_head, map, column_cnt); + fields->at(column_cnt) -= virtual_gcol_cnt; + } else { + row_set_column_bits2(row_head, map, column_cnt - virtual_gcol_cnt); + } + + // Cantian align variable field (including prefix) to 4 bytes + if (map == 3) { + field_len += sizeof(uint16_t); + field_len = ROUND_UP(field_len, 4); + field_len -= sizeof(uint16_t); + } + // proceed to next column in cantian record + cantian_field_offset += field_len; + } + + *record_buf->cantian_record_buf_size = cantian_field_offset; + row_head->size = (uint16_t)cantian_field_offset; + row_head->column_count = is_update ? n_fields : n_fields - virtual_gcol_cnt; + row_head->flags = 0; + return 0; +} + +void copy_column_data_to_mysql(field_info_t *field_info, const field_cnvrt_aux_t* mysql_info, + tianchi_handler_t &tch, bool is_index_only) +{ + if (!bitmap_is_set(field_info->field->table->read_set, field_info->field->field_index()) && + tch.sql_command == SQLCOM_SELECT) { + return; + } + uchar *src = NULL; + uint16_t src_len = 0; + switch (mysql_info->sql_data_type) { + case NUMERIC_DATA: + convert_numeric_to_mysql( + mysql_info, field_info->mysql_cur_field, field_info->cantian_cur_field, field_info->field); + break; + case DATETIME_DATA: + convert_datetime_to_mysql( + mysql_info, field_info->mysql_cur_field, field_info->cantian_cur_field, field_info->field); + break; + case STRING_DATA: { + lob_locator_t *locator = NULL; + if (!VARCHAR_AS_BLOB(field_info->field->row_pack_length())) { + src = field_info->cantian_cur_field; + src_len = field_info->field_len; + } else { + convert_blob_to_mysql(field_info->cantian_cur_field, field_info->field, + tch, field_info->mysql_cur_field); + locator = (lob_locator_t *)(uint8 *)field_info->cantian_cur_field; + src_len = (uint32)locator->head.size; + assert(src_len); + src = *(uchar **)field_info->mysql_cur_field; + } + memcpy(field_info->mysql_cur_field, src, src_len); + // Char类型内存优化,mysql行数据尾部填充 + if (mysql_info->mysql_field_type == MYSQL_TYPE_STRING && + field_info->field->real_type() == MYSQL_TYPE_STRING && + field_info->field->row_pack_length() > field_info->field_len) { + memset(field_info->mysql_cur_field + field_info->field_len, field_info->field->charset()->pad_char, + field_info->field->row_pack_length() - field_info->field_len); + } + if (locator) { + my_free(src); + src = NULL; + } + } break; + case LOB_DATA: { + if (is_index_only) { + uint32_t blob_len = field_info->field_len; + char *blob_buf = (char *)my_malloc(PSI_NOT_INSTRUMENTED, blob_len * sizeof(char), MYF(MY_WME)); + memcpy(blob_buf, field_info->cantian_cur_field, blob_len); + memcpy(field_info->mysql_cur_field, &blob_buf, sizeof(char *)); + bitmap_set_bit(field_info->field->table->read_set, field_info->field->field_index()); + } else { + convert_blob_to_mysql(field_info->cantian_cur_field, field_info->field, tch, field_info->mysql_cur_field); + } + } + break; + case UNKNOW_DATA: + /* fall through */ + default: + tse_log_error("[cantian2mysql]unsupport datatype %d", mysql_info->sql_data_type); + assert(0); + break; + } +} + +bool parse_cantian_column_and_update_offset(Field *field, uint8 cantian_col_type, const field_cnvrt_aux_t* cnvrt_aux, + record_buf_info_t *record_buf, field_offset_and_len_t *size, bool is_index_only) +{ + if ((cnvrt_aux->mysql_field_type == MYSQL_TYPE_BLOB || cnvrt_aux->mysql_field_type == MYSQL_TYPE_JSON) + && ((Field_blob *)field)->is_null()) { + record_buf->mysql_record_buf[field->null_offset()] |= field->null_bit; + return true; + } + switch (cantian_col_type) { + case CANTIAN_COL_BITS_NULL: + // set null bit & continue to next field if current column is null + record_buf->mysql_record_buf[field->null_offset()] |= field->null_bit; + return true; + case CANTIAN_COL_BITS_4: + *size->field_len = 4; + *size->aligned_field_len = 4; + break; + case CANTIAN_COL_BITS_8: + *size->field_len = 8; + *size->aligned_field_len = 8; + break; + case CANTIAN_COL_BITS_VAR: + // all fields in cantian are 4 bytes aligned except index_only decimal + // for variable types there're two bytes in the front + // representing length of the following data + // is_index_only && decimal: There are no two bytes of field_len after the row_head and bitmap. + // is_index_only && other variable-length types: Two bytes with field_len after row_head and bitmap. + if (!field->table->s->tmp_table && is_index_only && cnvrt_aux->mysql_field_type == MYSQL_TYPE_NEWDECIMAL) { + uint off = *size->cantian_field_offset; + *size->field_len = cm_dec4_stor_sz((dec4_t *)((char*)record_buf->cantian_record_buf + off)); + *size->aligned_field_len = ROUND_UP(*size->field_len, 4); + } else { + *size->field_len = *((uint16_t *)&record_buf->cantian_record_buf[*size->cantian_field_offset]); + *size->cantian_field_offset += sizeof(uint16_t); + *size->aligned_field_len = ROUND_UP(*size->field_len + sizeof(uint16_t), 4) - sizeof(uint16_t); + } + + if (!is_index_only && + (cnvrt_aux->mysql_field_type == MYSQL_TYPE_BLOB || + cnvrt_aux->mysql_field_type == MYSQL_TYPE_JSON || + ((cnvrt_aux->mysql_field_type == MYSQL_TYPE_VARCHAR) && + VARCHAR_AS_BLOB(field->row_pack_length())))) { + // when the type is blob,the lob data length is not field_len + // which should decode from lob_locator_t struct, locator->head.size + lob_locator_t *locator = (lob_locator_t *)(uint8*)&record_buf->cantian_record_buf[*size->cantian_field_offset]; + uint32 lob_len = (uint32)locator->head.size; + *size->mysql_field_offset += padding_variable_byte(cnvrt_aux, + &record_buf->mysql_record_buf[*size->mysql_field_offset], + lob_len, field); + } else { + *size->mysql_field_offset += padding_variable_byte(cnvrt_aux, + &record_buf->mysql_record_buf[*size->mysql_field_offset], + *size->field_len, field); + } + break; + default: + tse_log_error("[cantian2mysql]unknow col bits: %u", cantian_col_type); + assert(0); + break; + } + return false; +} + +void convert_cantian_field_to_mysql_field(Field *field, field_offset_and_col_type *filed_offset, + record_buf_info_t *record_buf, tianchi_handler_t &tch, bool is_index_only) +{ + // Get auxiliary info for field convertion + const field_cnvrt_aux_t* cnvrt_aux_info = get_auxiliary_for_field_convert(field, field->type()); + assert(cnvrt_aux_info != NULL); + + uint16_t field_len = 0; + uint16_t aligned_field_len = 0; + field_offset_and_len_t size = {&field_len, &aligned_field_len, filed_offset->cantian_field_offset, + filed_offset->mysql_field_offset}; + if (parse_cantian_column_and_update_offset(field, filed_offset->cantian_col_type, cnvrt_aux_info, record_buf, + &size, is_index_only)) { + // continue to next column if current field is null + return; + } + + field_info_t field_info = {field, &record_buf->cantian_record_buf[*filed_offset->cantian_field_offset], + &record_buf->mysql_record_buf[*filed_offset->mysql_field_offset], field_len}; + copy_column_data_to_mysql(&field_info, cnvrt_aux_info, tch, is_index_only); + + // move cantian offset to next column + *filed_offset->cantian_field_offset += aligned_field_len; +} + +void cantian_record_to_mysql_record(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, + tianchi_handler_t &tch) +{ + row_head_t *row_head = (row_head_t*)record_buf->cantian_record_buf; + bool is_index_only = false; + tse_log_debug("size %u, column cnt %u, is_changed:%hu, is_deleted:%hu, " + "is_link:%hu, is_migr:%hu, self_chg:%hu, is_csf:%hu", + row_head->size, row_head->column_count, row_head->is_changed, + row_head->is_deleted, row_head->is_link, row_head->is_migr, + row_head->self_chg, row_head->is_csf); + + if (row_head->is_csf) { + tse_log_error("csf format is not supported yet"); + assert(0); + } + + if (IS_SPRS_ROW(row_head)) { + tse_log_error("sparse row not supported yet"); + assert(0); + } + + // cantian bitmap is 3 byte by default and may be larger + // for a table with more than 12 columns + uint n_fields = table.s->fields; + uint ex_maps = col_bitmap_ex_size(row_head->column_count); + uint cantian_field_offset = sizeof(row_head_t) + ex_maps; + uint virtual_gcol_cnt = 0; + // update offset if it's a migrated row + cantian_field_offset += (row_head->is_migr) ? 8 : 0; + // initialize null bitmap + memset(record_buf->mysql_record_buf, 0x00, table.s->null_bytes); + for (uint column_id = 0; column_id < n_fields; column_id++) { + // early return if current column exceeds the max column id we wanted + if (column_id > index->max_col_idx) { + return; + } + + Field *field = table.field[column_id]; + if (field->is_virtual_gcol()) { + virtual_gcol_cnt++; + continue; + } + uint mysql_field_offset = field->offset(table.record[0]); + uint8 cantian_col_type = (column_id - virtual_gcol_cnt >= row_head->column_count) ? + CANTIAN_COL_BITS_NULL : row_get_column_bits2((row_head_t *)record_buf->cantian_record_buf, column_id - virtual_gcol_cnt); + + field_offset_and_col_type filed_offset = {&cantian_field_offset, &mysql_field_offset, cantian_col_type}; + convert_cantian_field_to_mysql_field(field, &filed_offset, record_buf, tch, is_index_only); + } +} + + + +// @note that this cnvrt func can only be used for record fetched directly +// from index structures(i.e. circumstances like index-only) +void cantian_index_record_to_mysql_record(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, + tianchi_handler_t &tch) +{ + auto index_info = table.key_info[index->active_index]; + uint n_fields = index_info.actual_key_parts; + bool is_index_only = true; + + row_head_t *row_head = (row_head_t *)record_buf->cantian_record_buf; + uint ex_maps = col_bitmap_ex_size(row_head->column_count); + uint cantian_field_offset = sizeof(row_head_t) + ex_maps; + + // initialize null bitmap, the size of bitmap is decided by field num + memset(record_buf->mysql_record_buf, 0x00, table.s->null_bytes); + + // convert and copy data by columns + for (uint key_id = 0; key_id < n_fields; key_id++) { + Field *field = index_info.key_part[key_id].field; + uint mysql_field_offset = field->offset(table.record[0]); + uint8 cantian_col_type = row_get_column_bits2((row_head_t *)record_buf->cantian_record_buf, key_id); + field_offset_and_col_type filed_offset = {&cantian_field_offset, &mysql_field_offset, cantian_col_type}; + uint col_id = field->field_index(); + convert_cantian_field_to_mysql_field(field, &filed_offset, record_buf, tch, is_index_only); + + // early return if current column exceeds the last column id we wanted + if (col_id == index->max_col_idx) { + return; + } + } +} + +int isolation_level_to_cantian(enum_tx_isolation isolation_level) +{ + switch (isolation_level) { + case ISO_READ_UNCOMMITTED: + case ISO_READ_COMMITTED: + return (ISOLATION_READ_COMMITTED); + case ISO_REPEATABLE_READ: + case ISO_SERIALIZABLE: + return (ISOLATION_SERIALIZABLE); + default: + assert(0); + return (0); + } +} + +int get_cantian_record_length(const TABLE *table) +{ + Field *mysql_field = NULL; + uint total_record_length = sizeof(row_head_t) + col_bitmap_ex_size(table->s->fields); + uint16_t field_len; + + for (Field **field = table->field; *field; field++) { + mysql_field = *field; + field_len = 0; + switch (mysql_field->type()) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + field_len = 4; + break; + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_TIME: + field_len = 8; + break; + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_STRING: + field_len = ROUND_UP(mysql_field->row_pack_length() + sizeof(uint16_t), 4); + break; + case MYSQL_TYPE_NEWDECIMAL: { + int scale = mysql_field->decimals(); + Field_new_decimal *f = (Field_new_decimal *)mysql_field; + int prec = f->precision; + int ncells = ALIGN_UP(prec - scale, 4) + ALIGN_UP(scale, 4); + field_len = ROUND_UP((1 + ncells) * sizeof(uint16_t) + sizeof(uint16_t), 4); + } + break; + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + // assume they're all outline-stored + field_len = ROUND_UP(sizeof(lob_locator_t) + sizeof(uint16_t), 4); + break; + default: + tse_log_error("unsupported column type %d", mysql_field->type()); + return -1; + } + total_record_length += field_len; + } // for field + return total_record_length; +} diff --git a/storage/tianchi/datatype_cnvrtr.h b/storage/tianchi/datatype_cnvrtr.h new file mode 100644 index 0000000..6583548 --- /dev/null +++ b/storage/tianchi/datatype_cnvrtr.h @@ -0,0 +1,242 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "ha_tse.h" +#include "my_inttypes.h" +#include +#include "sql/my_decimal.h" +#include "sql/sql_time.h" + +#ifndef DATATYPE_CNVRTR_H +#define DATATYPE_CNVRTR_H + +#define get_rec_bits(bit_ptr, bit_ofs, bit_len) \ + (((((uint16)(bit_ptr)[1] << 8) | (uint16)(bit_ptr)[0]) >> (bit_ofs)) & \ + ((1 << (bit_len)) - 1)) + +/* + * the internal data structure for storing timezone information. + * the purpose of it is to save space when transforming the information via network, + * or storing the information with TIMESTAMP WITH TIMEZONE data. + * + * the timezone_info_t stands for the offset (in minutes) of a timezone. + * for instance, the content of timezone_info_t for CMT(GMT+8:00) is 480 + * while EST(GMT-5:00) is -300 + */ +typedef int16 timezone_info_t; +/* + * The date type is represented by a 64-bit signed integer. The minimum unit + * is 1 microsecond. This indicates the precision can reach up to 6 digits after + * the decimal point. + */ + +typedef int64 date_t; +#define TSE_BYTE_8 8 +#define CANTIAN_COL_BITS_NULL (uint8)0x00 // NULL in Cantian Storage +#define CANTIAN_COL_BITS_4 (uint8)0x01 // 4 Bytes in Cantian Storage +#define CANTIAN_COL_BITS_8 (uint8)0x02 // 8 Bytes in Cantian Storage +#define CANTIAN_COL_BITS_VAR (uint8)0x03 // Variable Bytes in Cantian Storage +#define TSE_LOB_LOCATOR_BUF_SIZE (uint32)4012 +#define TSE_LOB_MAX_INLINE_SIZE (TSE_LOB_LOCATOR_BUF_SIZE - offsetof(lob_locator_t, data)) +#define ALIGN_UP(x, align) ((x) / (align) + ((x) % (align) ? 1 : 0)) +#define ROUND_UP(x, align) ((x) / (align) + ((x) % (align) ? 1 : 0)) * (align) +#define MICROSECS_PER_MILLISEC 1000U +#define MILLISECS_PER_SECOND 1000U +#define LOB_DATA_SIZE_100K (1024 * 100) +#define LOB_DATA_SIZE_1M (1024 * 1024) +#define LOB_DATA_SIZE_8M (1024 * 1024 * 8) +/* LOB_DATA_BUFFER_SIZE must bigger than 4000,Otherwise, incorrect data may be written to the row. */ +#define LOB_DATA_BUFFER_SIZE_8K (1024 * 8) +#define TSE_DDL_MAX_VARCHAR_COLUMN_SIZE 8000 +#define VARCHAR_AS_BLOB(len) ((len) > TSE_DDL_MAX_VARCHAR_COLUMN_SIZE) + +#define CM_ALL_ZERO_DATETIME ((date_t)-63113904000000000LL) /* == cm_encode_date(00-00-00 00:00:00.000000) */ +longlong bit_cnvt_mysql_cantian(const uchar *ptr, Field *mysql_field); +void bit_cnvt_cantian_mysql(const uchar *cantian_ptr, uchar *mysql_ptr, Field *mysql_field); +enum enum_sql_data_types +{ + UNKNOW_DATA = 0, + NUMERIC_DATA, + DATETIME_DATA, + STRING_DATA, + LOB_DATA +}; + +#pragma pack(4) +// row format +typedef struct st_row_head { + union { + struct { + uint16_t + size; // row size, must be the first member variable in row_head_t + uint16_t column_count : 10; // column count + uint16_t flags : 6; // total flags + }; + + struct { + uint16_t aligned1; // aligned row size + uint16_t aligned2 : 10; // aligned column_count + uint16_t is_deleted : 1; // deleted flag + uint16_t is_link : 1; // link flag + uint16_t is_migr : 1; // migration flag + uint16_t self_chg : 1; // statement self changed flag for PCR + uint16_t is_changed : 1; // changed flag after be locked + uint16_t is_csf : 1; // CSF(Compact Stream Format) + }; + }; + + union { + struct { + uint16_t sprs_count; // sparse column count + uint8_t sprs_itl_id; // sparse itl_id; + uint8_t sprs_bitmap[1]; // sparse bitmap + }; + + struct { + uint8_t itl_id; // row itl_id + uint8_t bitmap[3]; // bitmap is no used for CSF + }; + }; +} row_head_t; // following is bitmap of column +#pragma pack() + +#pragma pack(4) +/* To represent all parts of a date type */ +typedef struct st_date_detail { + uint16 year; + uint8 mon; + uint8 day; + uint8 hour; + uint8 min; + uint8 sec; + uint16 millisec; /* millisecond: 0~999, 1000 millisec = 1 sec */ + uint16 microsec; /* microsecond: 0~999, 1000 microsec = 1 millisec */ + uint16 nanosec; /* nanosecond: 0~999, 1000 nanoseconds = 1 millisec */ + timezone_info_t tz_offset; /* time zone */ +} date_detail_t; +#pragma pack() + +// lob data define +#pragma pack(4) +typedef struct st_lob_head { + /* size + type must be defined first!!! */ + uint32 size; + uint32 type; + uint32 is_outline : 1; + uint32 unused : 31; +} lob_head_t; +typedef struct st_lob_locator { + lob_head_t head; + union { + uint8 pading[32]; + uint8 data[0]; + }; +} lob_locator_t; +#pragma pack() + +typedef struct st_lob_text { + char *str; + unsigned int len; +} lob_text_t; + +typedef enum en_isolation_level { + ISOLATION_READ_COMMITTED = 1, // read committed isolation level(default) + ISOLATION_SERIALIZABLE = 3, // serializable isolation level + // value 2 is internal isolation level of daac, ignore for now +} isolation_level_t; + +typedef struct st_mysql_to_cantian_field_convert { + enum_field_types mysql_field_type; + uint8_t cantian_map_type; + enum_sql_data_types sql_data_type; + enum_tse_ddl_field_types ddl_field_type; +} field_cnvrt_aux_t; + +typedef struct { + Field *field; + uchar *cantian_cur_field; + uchar *mysql_cur_field; + uint16_t field_len; +} field_info_t; + +typedef struct { + uint16_t *field_len; + uint16_t *aligned_field_len; + uint *cantian_field_offset; + uint *mysql_field_offset; +} field_offset_and_len_t; + +typedef struct { + uchar *cantian_record_buf; + uchar *mysql_record_buf; + int *cantian_record_buf_size; +} record_buf_info_t; + +typedef struct { + uint active_index; + uint max_col_idx = UINT_MAX; +} index_info_t; + +typedef struct { + uint *cantian_field_offset; + uint *mysql_field_offset; + uint8 cantian_col_type; +} field_offset_and_col_type; + +static std::unordered_map g_blob_field_buffer_size_map = +{ + {LOB_DATA_SIZE_100K, LOB_DATA_BUFFER_SIZE_8K}, + {LOB_DATA_SIZE_1M, LOB_DATA_SIZE_100K}, + {LOB_DATA_SIZE_8M, LOB_DATA_SIZE_1M}, +}; + +typedef void (*cnvrt_to_mysql_fn)(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, + tianchi_handler_t &tch); + +void cantian_record_to_mysql_record(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, + tianchi_handler_t &tch); +int mysql_record_to_cantian_record(const TABLE &table, record_buf_info_t *record_buf, + tianchi_handler_t &tch, uint16_t *serial_column_offset, + std::vector *fields=nullptr); +void cal_gcol_cnts_for_update(Field **field, uint column_id, uint32_t *virtual_gcol_cnt); +void cantian_index_record_to_mysql_record(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, + tianchi_handler_t &tch); +int isolation_level_to_cantian( + enum_tx_isolation isolation_level); + +int get_cantian_record_length(const TABLE *table); + +const field_cnvrt_aux_t* get_auxiliary_for_field_convert(Field *field, enum_field_types mysql_field_type); + +bool check_datetime_vaild(const date_detail_t& date_detail); + +void decode_mysql_datetime(MYSQL_TIME& ltime, const field_cnvrt_aux_t* mysql_info, + const uchar *mysql_ptr, Field *mysql_field); + +int convert_datetime_to_cantian(const field_cnvrt_aux_t* mysql_info , uchar *cantian_ptr, + const uchar *mysql_ptr, Field *mysql_field); +int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field, uint32 *length); +int convert_numeric_to_cantian(const field_cnvrt_aux_t *mysql_info, const uchar *mysql_ptr, uchar *cantian_ptr, + Field *mysql_field, uint32_t *length); +void cm_encode_date(const date_detail_t *detail, date_t *date); +int assign_mysql_date_detail(enum_field_types mysql_field_type, MYSQL_TIME ltime, date_detail_t *date_detail); + +bool tse_datetime_with_no_zero_in_date_to_timeval(const MYSQL_TIME *ltime, const Time_zone &tz, + struct timeval *tm, int *warnings); +bool check_zero_date(const date_detail_t& datetime); +bool check_zero_time_ltime(const MYSQL_TIME ltime); +#endif diff --git a/storage/tianchi/decimal_convert.cc b/storage/tianchi/decimal_convert.cc new file mode 100644 index 0000000..7da8a6c --- /dev/null +++ b/storage/tianchi/decimal_convert.cc @@ -0,0 +1,756 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "decimal_convert.h" +#include +#include "stdlib.h" +#include "tse_log.h" +// half of g_1ten_powers, used for rounding a decimal +const uint32 ct_5ten_powers[10] = { + 0u, // 0 + 5u, // 5 x 10^0 + 50u, // 5 x 10^1 + 500u, // 5 x 10^2 + 5000u, // 5 x 10^3 + 50000u, // 5 x 10^4 + 500000u, // 5 x 10^5 + 5000000u, // 5 x 10^6 + 50000000u, // 5 x 10^7 + 500000000u, // 5 x 10^8 +}; +const uint32 ct_1ten_powers[10] = { + 1u, // 10^0 + 10u, // 10^1 + 100u, // 10^2 + 1000u, // 10^3 + 10000u, // 10^4 + 100000u, // 10^5 + 1000000u, // 10^6 + 10000000u, // 10^7 + 100000000u, // 10^8 + 1000000000u // 10^9 +}; +static int32 cm_dec8_calc_prec(const dec8_t *dec); +static inline void ct_cm_str2text(char *str, text_t *text) { + text->str = str; + text->len = (str == NULL) ? 0 : (uint32)strlen(str); +} +status_t ct_cm_str_to_dec8(const char *str, dec8_t *dec) { + text_t text; + ct_cm_str2text(const_cast(str), &text); + return ct_cm_text_to_dec8(&text, dec); +} +/** + * Translates a text_t representation of a decimal into a decimal + */ +status_t ct_cm_text_to_dec8(const text_t *dec_text, dec8_t *dec) { + num_errno_t err_no; + num_part_t np; + np.excl_flag = NF_NONE; + err_no = ct_cm_split_num_text(dec_text, &np); + if (err_no != NERR_SUCCESS) { + tse_log_error("Decimal data type convert text to dec8 failed!"); + return CT_ERROR; + } + err_no = ct_cm_numpart_to_dec8(&np, dec); + if (err_no != NERR_SUCCESS) { + tse_log_error("Decimal data type convert numpart to dec8 failed!"); + return CT_ERROR; + } + return CT_SUCCESS_STATUS; +} +/** + * Quickly find the precision of a cells + * @note (1) The cell u0 should be specially treated; + * (2) The tailing zeros will not be counted. If all cell except u0 are + * zeros, then the precision of u0 is re-counted by ignoring tailing + * zeros e.g. | u0 = 1000 | u1 = 0 | u2 = 0 |..., the precision 1 will be + * returned. + */ +static int32 cm_dec8_calc_prec(const dec8_t *dec) { + int32 i, j; + uint32 u; + int32 prec = 0; + if (dec->ncells == 0) { + return 0; + } + /* Step 1: Find the precision of remaining cells starting from backend */ + for (i = dec->ncells - 1; i > 0; --i) { + if (dec->cells[i] > 0) { // found the last non-zero cell (dec->cells[i]>0) + // count digits in this cell by ignoring tailing zeros + j = 0; + u = dec->cells[i]; + while (u != 0 && u % 10 == 0) { + ++j; + u /= 10; + } + prec += (i * DEC8_CELL_DIGIT - j); + break; + } + } + /* Step 2: Count the precision of u0 */ + if (i == 0) { // if u1, u2, ... are zeros, then the precision of u0 should + // remove tailing zeros + u = dec->cells[0]; + while (u != 0 && u % 10 == 0) { // remove tailing zeros + u /= 10; + } + prec = (int32)cm_count_u32digits((c8typ_t)u); + } else { + prec += (int32)cm_count_u32digits(dec->cells[0]); + } + return prec; +} +/** recording the significand digits into num_part */ +static inline void ct_cm_record_digit(num_part_t *np, int32 *precision, + int32 *prec_offset, int32 pos, char c) { + if (*precision >= 0) { + ++(*precision); + if (*precision > (DEC_MAX_NUM_SAVING_PREC + 1)) { + // if the buff is full, ignoring the later digits + return; + } else if (*precision == (DEC_MAX_NUM_SAVING_PREC + 1)) { + // mark the rounding mode is needed + np->do_round = (c >= '5'); + return; + } + } else { + *precision = 1; + } + if (*precision == 1) { + // if found the first significant digit, records its position + *prec_offset = pos; + } + CM_TEXT_APPEND(&np->digit_text, c); +} +static inline void cm_dec8_rebuild(dec8_t *rs, uint32 cell0) { + /* decide the number of cells */ + if (rs->ncells < DEC8_CELL_SIZE) { + rs->ncells++; + } + /* right shift cell data by 1 */ + uint32 i = rs->ncells; + while (i-- > 1) { + rs->cells[i] = rs->cells[i - 1]; + } + /* put the carry into cells[0] */ + rs->cells[0] = (c8typ_t)cell0; + rs->expn++; +} +/** CM_MAX_EXPN must greater than the maximal exponent that DB can capacity. + * In current system, the maximal exponent is 308 for double. Therefore, the + * value is set to 99999999 is reasonable. */ +#define CM_MAX_EXPN 99999999 +/** + * Parse an exponent from the numeric text *dec_text*, i is the offset + * of exponent. When unexpected character occur or the exponent overflow, + * an error will be returned. + */ +static inline num_errno_t ct_cm_parse_num_expn(text_t *expn_text, int32 *expn) { + char c; + int32 tmp_exp; + bool32 is_negexp = CT_FALSE; + uint32 i = 0; + // handle the sign of exponent + c = expn_text->str[i]; + if (CM_IS_SIGN_CHAR(c)) { + is_negexp = (c == '-'); + c = expn_text->str[++i]; // move to next character + } + if (i >= expn_text->len) { /* if no exponent digits, return error */ + CT_THROW((i >= expn_text->len), NERR_NO_EXPN_DIGIT); + } + // skip leading zeros in the exponent + while (CM_IS_ZERO(c)) { + ++i; + if (i >= expn_text->len) { + *expn = 0; + return NERR_SUCCESS; + } + c = expn_text->str[i]; + } + // too many nonzero exponent digits + tmp_exp = 0; + for (;;) { + CT_THROW((!CM_IS_DIGIT(c)), NERR_EXPN_WITH_NCHAR); + if (tmp_exp < CM_MAX_EXPN) { // to avoid int32 overflow + tmp_exp = tmp_exp * CM_DEFAULT_DIGIT_RADIX + CM_C2D(c); + } + ++i; + if (i >= expn_text->len) { + break; + } + c = expn_text->str[i]; + } + // check exponent overflow on positive integer + CT_THROW((!is_negexp && tmp_exp > CM_MAX_EXPN), NERR_OVERFLOW); + *expn = is_negexp ? -tmp_exp : tmp_exp; + return NERR_SUCCESS; +} +/** calculate expn of the significand digits */ +static inline int32 ct_cm_calc_significand_expn(int32 dot_offset, + int32 prec_offset, + int32 precision) { + // Step 3.1. compute the sci_exp + if (dot_offset >= 0) { /* if a dot exists */ + /* Now, prec_offset records the distance from the first significant digit to + * the dot. + * dot_offset > 0 means dot is counted, thus this means the sci_exp should + * subtract one. */ + dot_offset -= prec_offset; + return ((dot_offset > 0) ? dot_offset - 1 : dot_offset); + } else { + return precision - 1; + } +} +num_errno_t ct_cm_split_num_text(const text_t *num_text, num_part_t *np) { + int32 i; + char c; + text_t text; /** the temporary text */ + int32 dot_offset = -1; /** '.' offset, -1 if none */ + int32 prec_offset = + -1; /** the offset of the first significant digit, -1 if none */ + int32 precision = -1; /* see comments of the function */ + bool32 leading_flag = CT_TRUE; /** used to ignore leading zeros */ + /* When the number of significant digits exceeds the dight_buf + * Then, a round happens when the MAX_NUMERIC_BUFF+1 significant + * digit is equal and greater than '5' */ + // CM_POINTER3(text, np, buf); + if (np == NULL) { + assert(0); + } + np->digit_text.len = 0; + np->has_dot = CT_FALSE; + np->has_expn = CT_FALSE; + np->do_round = CT_FALSE; + np->is_neg = CT_FALSE; + np->sci_expn = 0; + text = *num_text; + ct_cm_trim_text(&text); + CT_THROW((text.len == 0 || text.len >= SIZE_M(1)), + NERR_INVALID_LEN); // text.len > 2^15 + i = 0; + /* Step 1. fetch the sign of the decimal */ + if (text.str[i] == '-') { // leading minus means negative + // if negative sign is not allowed + CT_THROW((np->excl_flag & NF_NEGATIVE_SIGN), NERR_UNALLOWED_NEG); + np->is_neg = CT_TRUE; + i++; + } else if (text.str[i] == '+') { // leading + allowed + i++; + } + /* check again */ + CT_THROW((i >= (int32)text.len), NERR_NO_DIGIT); + /* Step 2. parse the scale, exponent, precision, Significant value of the + * decimal */ + for (; i < (int32)text.len; ++i) { + c = text.str[i]; + if (leading_flag) { // ignoring leading zeros + if (CM_IS_ZERO(c)) { + precision = 0; + continue; + } else if (c != '.') { + leading_flag = CT_FALSE; + } + } + if (CM_IS_DIGIT(c)) { // recording the significand + ct_cm_record_digit(np, &precision, &prec_offset, i, c); + continue; + } + if (CM_IS_DOT(c)) { + CT_THROW((np->excl_flag & NF_DOT), NERR_UNALLOWED_DOT); + CT_THROW((dot_offset >= 0), NERR_MULTIPLE_DOTS); + dot_offset = i; // + np->has_dot = CT_TRUE; + continue; + } + // begin to handle and fetch exponent + CT_THROW((!CM_IS_EXPN_CHAR(c)), NERR_UNEXPECTED_CHAR); + // Exclude: 'E0012', '.E0012', '-E0012', '+.E0012', .etc + CT_THROW((precision < 0), NERR_UNEXPECTED_CHAR); + CT_THROW((np->excl_flag & NF_EXPN), NERR_UNALLOWED_EXPN); + // redirect text pointing to expn part + text.str += (i + 1); + text.len -= (i + 1); + num_errno_t nerr = ct_cm_parse_num_expn(&text, &np->sci_expn); + CT_THROW((nerr != NERR_SUCCESS), nerr); + np->has_expn = CT_TRUE; + break; + } // end for + CT_THROW((precision < 0), NERR_NO_DIGIT); + if (precision == 0) { + CM_ZERO_NUMPART(np); + return NERR_SUCCESS; + } + // Step 3: Calculate the scale of the total number text + np->sci_expn += + ct_cm_calc_significand_expn(dot_offset, prec_offset, precision); + if (np->digit_text.len > num_text->len || + np->digit_text.len >= CT_MAX_NUM_PART_BUFF) { + return NERR_ERROR; + } + return NERR_SUCCESS; +} +/* + * Convert a cell text into a cell of big integer by specifying the + * length digits in u0 (i.e., len_u0), and return the number of non-zero cells + * Performance sensitivity.CM_ASSERT should be guaranteed by caller, i.g. + * cells[0] > 0 + */ +static inline int32 cm_digitext_to_cell8s(digitext_t *dtext, cell8_t cells, + int32 len_u0) { + uint32 i, k; + text_t cell_text; + // make u0 + cell_text.str = dtext->str; + cell_text.len = (uint32)len_u0; + cells[0] = (c8typ_t)cm_celltext2uint32(&cell_text); + // make u1, u2, ..., uk + k = 1; + for (i = (uint32)len_u0; k < DEC8_CELL_SIZE && i < dtext->len; k++) { + cell_text.str = dtext->str + i; + cell_text.len = (uint32)DEC8_CELL_DIGIT; + cells[k] = (c8typ_t)cm_celltext2uint32(&cell_text); + i += DEC8_CELL_DIGIT; + } + // the tailing cells of significant cells may be zeros, for returning + // accurate ncells, they should be ignored. + while (cells[k - 1] == 0) { + --k; + } + return (int32)k; +} +/** + * Convert a digit text with a scientific exponent into a decimal + * The digit text may be changed when adjust the scale of decimal to be + * an integral multiple of DEC_CELL_DIGIT, by appending zeros. + * @return the precision of u0 + * @note + * Performance sensitivity.CM_ASSERT should be guaranteed by caller, + * i.g. dtext->len > 0 && dtext->len <= (uint32)DEC_MAX_ALLOWED_PREC + */ +static inline int32 cm_digitext_to_dec8(dec8_t *dec, digitext_t *dtext, + int32 sci_exp) { + int32 delta; + int32 len_u0; // the length of u0 + len_u0 = (int32)dtext->len % DEC8_CELL_DIGIT; + ++sci_exp; // increase the sci_exp to obtain the position of dot + delta = sci_exp - len_u0; + delta += (int32)DEC8_CELL_DIGIT << 16; // make delta to be positive + delta %= DEC8_CELL_DIGIT; // get the number of appending zeros + len_u0 = (len_u0 + delta) % DEC8_CELL_DIGIT; + if (len_u0 == 0) { + len_u0 = DEC8_CELL_DIGIT; + } + while (delta-- > 0) { + CM_TEXT_APPEND(dtext, '0'); + } + if (dtext->len < CT_MAX_DEC_OUTPUT_ALL_PREC) { + CM_NULL_TERM(dtext); + } + dec->ncells = (uint8)cm_digitext_to_cell8s(dtext, dec->cells, len_u0); + dec->expn = SEXP_2_D8EXP(sci_exp - len_u0); + return len_u0; +} +static inline void cm_do_numpart_round8( + const num_part_t *np MY_ATTRIBUTE((unused)), dec8_t *dec, uint32 prec0) { + c8typ_t carry = ct_1ten_powers[prec0 % DEC8_CELL_DIGIT]; + uint32 i = dec->ncells; + + while (i-- > 0) { + dec->cells[i] += carry; + carry = (dec->cells[i] >= DEC8_CELL_MASK); + if (carry == 0) { + return; + } + dec->cells[i] -= DEC8_CELL_MASK; + } + if (carry > 0) { + cm_dec8_rebuild(dec, 1); + } +} +num_errno_t ct_cm_numpart_to_dec8(num_part_t *np, dec8_t *dec) { + if (NUMPART_IS_ZERO(np)) { + cm_zero_dec8(dec); + return NERR_SUCCESS; + } + // Step 3.2. check overflow by comparing scientific scale and MAX_NUMERIC_EXPN + if (np->sci_expn > MAX_NUMERIC_EXPN) { // overflow return Error + return NERR_OVERFLOW; + } else if (np->sci_expn < MIN_NUMERIC_EXPN) { // underflow return 0 + cm_zero_dec8(dec); + return NERR_SUCCESS; + } + // Step 4: make the final decimal value + dec->sign = (uint8)np->is_neg; + int32 prec0 = cm_digitext_to_dec8(dec, &np->digit_text, np->sci_expn); + if (np->do_round) { // when round happens, the dec->cells should increase 1 + cm_do_numpart_round8(np, dec, (uint32)prec0); + cm_dec8_trim_zeros(dec); // rounding may change the precision + } + return NERR_SUCCESS; +} +/** + * Convert a decimal into C-string, and return the ac + */ +status_t ct_cm_dec8_to_str(const dec8_t *dec, int max_len, char *str) { + text_t text; + text.str = str; + text.len = 0; + CT_RETURN_IF_ERROR(ct_cm_dec8_to_text(dec, max_len, &text)); + str[text.len] = '\0'; + return CT_SUCCESS_STATUS; +} +/** + * Convert the significant digits of cells into text with a maximal len + * @note The tailing zeros are removed when outputting + */ +static void cm_cell8s_to_text(const cell8_t cells, uint32 ncell, text_t *text, + int32 max_len) { + uint32 i; + int iret_snprintf; + iret_snprintf = snprintf(text->str, DEC8_CELL_DIGIT + 1, "%u", cells[0]); + if (iret_snprintf == -1) { + assert(0); + } + text->len = (uint32)iret_snprintf; + for (i = 1; (text->len < (uint32)max_len) && (i < ncell); ++i) { + iret_snprintf = snprintf(CM_GET_TAIL(text), DEC8_CELL_DIGIT + 1, + DEC8_CELL_FMT, (uint32)cells[i]); + if (iret_snprintf == -1) { + assert(0); + } + text->len += (uint32)iret_snprintf; + } + // truncate redundant digits + if (text->len > (uint32)max_len) { + text->len = (uint32)max_len; + } + // truncate tailing zeros + for (i = (uint32)text->len - 1; i > 0; --i) { + if (!CM_IS_ZERO(text->str[i])) { + break; + } + --text->len; + } + CM_NULL_TERM(text); +} +/* Copy the data a decimal */ +static inline void cm_dec8_copy(dec8_t *dst, const dec8_t *src) { + if (SECUREC_UNLIKELY(dst == src)) { + return; + } + dst->head = src->head; + /* Another way to Copy the data of decimals is to use loops, for example: + * uint32 i = src->ncells; + * while (i-- > 0) + * dst->cells[i] = src->cells[i]; + * However, this function is performance sensitive, and not too safe when + * src->ncells is abnormal. By actural testing, using switch..case here + * the performance can improve at least 1.5%. The testing results are + * WHILE LOOP : 5.64% cm_dec8_copy + * SWITCH CASE : 4.14% cm_dec8_copy + * Another advantage is that the default branch of SWITCH CASE can be used + * to handle abnormal case, which reduces an IF statement. + */ + switch (src->ncells) { + case 7: + dst->cells[6] = src->cells[6]; + /* fall-through */ + case 6: + dst->cells[5] = src->cells[5]; + /* fall-through */ + case 5: + dst->cells[4] = src->cells[4]; + /* fall-through */ + case 4: + dst->cells[3] = src->cells[3]; + /* fall-through */ + case 3: + dst->cells[2] = src->cells[2]; + /* fall-through */ + case 2: + dst->cells[1] = src->cells[1]; + /* fall-through */ + case 1: + dst->cells[0] = src->cells[0]; + /* fall-through */ + case 0: + break; + default: + cm_zero_dec8(dst); + break; + } +} +/** + * Product a cell array with the digit at pos (starting from left) is k + */ +static inline bool32 cm_dec8_make_round(const dec8_t *dec, uint32 pos, + dec8_t *dx) { + int32 i; + uint32 carry, j; + cm_dec8_copy(dx, dec); + if (pos >= DEC8_MAX_ALLOWED_PREC) { + return CT_FALSE; + } + i = (int32)(pos / DEC8_CELL_DIGIT); + j = pos % DEC8_CELL_DIGIT; + + carry = (uint32)ct_5ten_powers[DEC8_CELL_DIGIT - j]; + for (; i >= 0; i--) { + dx->cells[i] += carry; + carry = (dx->cells[i] >= DEC8_CELL_MASK); + if (!carry) { + return CT_FALSE; + } + dx->cells[i] -= DEC8_CELL_MASK; + } + if (carry > 0) { + cm_dec8_rebuild(dx, 1); + } + return carry; +} +/** + * Round a decimal to a text with the maximal length max_len + * If the precision is greater than max_len, a rounding mode is used. + * The rounding mode may cause a change on precision, e.g., the 8-precision + * decimal 99999.999 rounds to 7-precision decimal is 100000.00, and then + * its actual precision is 8. The function will return the change. If + * no change occurs, zero is returned. + * @note + * Performance sensitivity.CM_ASSERT should be guaranteed by caller, + * i.g. 1.max_len > 0 2.dec->cells[0] > 0 + */ +static int32 cm_dec8_round_to_text(const dec8_t *dec, int32 max_len, + text_t *text_out) { + dec8_t txtdec; + uint32 prec_u0; + int32 prec; + prec = cm_dec8_calc_prec(dec); + if (prec <= max_len) { // total prec under the max_len + cm_cell8s_to_text(dec->cells, dec->ncells, text_out, prec); + return 0; + } + /** if prec > max_len, the rounding mode is applied */ + prec_u0 = cm_count_u32digits(dec->cells[0]); + // Rounding model begins by adding with {5[(prec - max_len) zeros]} + // Obtain the pos of 5 for rounding, then prec is used to represent position + prec = DEC8_POS_N_BY_PREC0(max_len, prec_u0); + // add for rounding and check whether the carry happens, and capture the + // changes of the precision + if (cm_dec8_make_round(dec, (uint32)prec, &txtdec)) { + // if carry happens, the change must exist + cm_cell8s_to_text(txtdec.cells, dec->ncells + 1, text_out, max_len); + return 1; + } else { + cm_cell8s_to_text(txtdec.cells, dec->ncells, text_out, max_len); + return (cm_count_u32digits(txtdec.cells[0]) > prec_u0) ? 1 : 0; + } +} +#define DEC_EXPN_BUFF_SZ 16 +/** + * Output a decimal type in scientific format, e.g., 2.34566E-20 + */ +static inline status_t cm_dec8_to_sci_text(text_t *text, const dec8_t *dec, + int32 max_len) { + int32 i; + char obuff[CT_NUMBER_BUFFER_SIZE]; /** output buff */ + text_t cell_text = {.str = obuff, .len = 0}; + char sci_buff[DEC_EXPN_BUFF_SZ]; + int32 sci_exp; /** The scientific scale of the dec */ + int32 placer; + int iret_snprintf; + sci_exp = DEC8_GET_SEXP(dec); + // digits of sci_exp + sign(dec) + dot + E + sign(expn) + placer = (int32)dec->sign + 3; + placer += (int32)cm_count_u32digits((c8typ_t)abs(sci_exp)); + if (max_len <= placer) { + return CT_ERROR; + } + /* The round of a decimal may increase the precision by 1 */ + if (cm_dec8_round_to_text(dec, max_len - placer, &cell_text) > 0) { + ++sci_exp; + } + // compute the exponent placer + iret_snprintf = snprintf(sci_buff, DEC_EXPN_BUFF_SZ - 1, "E%+d", sci_exp); + if (iret_snprintf != EOK) { + return CT_ERROR; + } + placer = iret_snprintf; + // Step 1. output sign + text->len = 0; + if (dec->sign == DEC_SIGN_MINUS) { + CM_TEXT_APPEND(text, '-'); + } + CM_TEXT_APPEND(text, cell_text.str[0]); + CM_TEXT_APPEND(text, '.'); + for (i = 1; (int32)text->len < max_len - placer; ++i) { + if (i < (int32)cell_text.len) { + CM_TEXT_APPEND(text, cell_text.str[i]); + } else { + CM_TEXT_APPEND(text, '0'); + } + } + iret_snprintf = + snprintf(&text->str[text->len], DEC_EXPN_BUFF_SZ - 1, "%s", sci_buff); + if (iret_snprintf != EOK) { + return CT_ERROR; + } + text->len += (uint32)iret_snprintf; + return CT_SUCCESS_STATUS; +} +static inline void cm_concat_text(text_t *text, const text_t *part) { + for (uint32 i = 0; i < part->len; ++i) { + CM_TEXT_APPEND(text, part->str[i]); + } +} +/** + * Append num characters c to the text; if num<=0, do nothing; + * @note the user must ensure sufficient space to store them + */ +static inline void cm_text_appendc(text_t *text, int32 num, char c) { + while (num-- > 0) { + CM_TEXT_APPEND(text, c); + } +} +static inline status_t cm_concat_ntext(text_t *dst, const text_t *src, + int32 num) { + if (num <= 0) { + return CT_SUCCESS_STATUS; + } + if ((uint32)num > src->len) { + num = (int32)src->len; + } + if (num != 0) { + memcpy(CM_GET_TAIL(dst), src->str, num); + } + dst->len += (uint32)num; + return CT_SUCCESS_STATUS; +} +/** + * @note + * Performance sensitivity.CM_ASSERT should be guaranteed by caller, i.g. + * dot_pos <= max_len - dec->sign + */ +static inline status_t cm_dec8_to_plain_text(text_t *text, const dec8_t *dec, + int32 max_len, int32 sci_exp, + int32 prec) { + int32 dot_pos; + char obuff[CT_NUMBER_BUFFER_SIZE]; /** output buff */ + text_t cell_text; + cell_text.str = obuff; + cell_text.len = 0; + // clear text & output sign + text->len = 0; + if (dec->sign == DEC_SIGN_MINUS) { + CM_TEXT_APPEND(text, '-'); + } + dot_pos = sci_exp + 1; + if (prec <= dot_pos) { + (void)cm_dec8_round_to_text(dec, max_len - dec->sign, + &cell_text); // subtract sign + cm_concat_text(text, &cell_text); + cm_text_appendc(text, dot_pos - prec, '0'); + CM_NULL_TERM(text); + return CT_SUCCESS_STATUS; + } + /* get the position of dot w.r.t. the first significant digit */ + if (dot_pos == max_len - dec->sign) { + /* handle the border case with dot at the max_len position, + * then the dot is not outputted. Suppose max_len = 10, + * (1). 1234567890.222 --> 1234567890 is outputted + * If round mode products carry, e.g. the rounded value of + * 9999999999.9 is 10000000000, whose length is 11 and greater than + * max_len, then the scientific format is used to print the decimal + */ + if (cm_dec8_round_to_text(dec, dot_pos, &cell_text) > 0) { + CM_TEXT_CLEAR(text); + return cm_dec8_to_sci_text(text, dec, max_len); + } + cm_concat_text(text, &cell_text); + cm_text_appendc(text, max_len - (int32)text->len, '0'); + } else if (dot_pos == max_len - dec->sign - 1) { + /* handle the border case with dot at the max_len - 1 position, + * then only max_len-1 is print but the dot is emitted. Assume + * max_len = 10, the following cases output: + * (1). 123456789.2345 ==> 123456789 (.2345 is abandoned) + * (2). 987654321.56 ==> 987654322 (.56 is rounded to 1) + * If a carry happens, e.g., 999999999.6 ==> 1000000000, max_len + * number of digits will be printed. + * */ + int32 change = cm_dec8_round_to_text(dec, dot_pos, &cell_text); + cm_concat_text(text, &cell_text); + cm_text_appendc(text, max_len + change - ((int32)text->len + 1), '0'); + } else if (dot_pos >= 0) { /* dot is inside of cell_text and may be output */ + // round mode may product carry, and thus may affect the dot_pos + dot_pos += cm_dec8_round_to_text(dec, max_len - dec->sign - 1, + &cell_text); // subtract sign & dot + if ((int32)cell_text.len <= dot_pos) { + cm_concat_text(text, &cell_text); + cm_text_appendc(text, dot_pos - (int32)cell_text.len, '0'); + } else { + cm_concat_ntext(text, &cell_text, dot_pos); + CM_TEXT_APPEND(text, '.'); + // copy remaining digits + cell_text.str += (uint32)dot_pos; + cell_text.len -= (uint32)dot_pos; + cm_concat_text(text, &cell_text); + } + } else { // dot_pos < 0 + /* dot is in the most left & add |dot_pos| zeros between dot and cell_text + * Thus, the maxi_len should consider sign, dot, and the adding zeros */ + dot_pos += cm_dec8_round_to_text(dec, max_len - dec->sign - 1 + dot_pos, + &cell_text); + CM_TEXT_APPEND(text, '.'); + cm_text_appendc(text, -dot_pos, '0'); + cm_concat_ntext(text, &cell_text, max_len - (int32)text->len); + } + CM_NULL_TERM(text); + return CT_SUCCESS_STATUS; +} +/** + * Convert a decimal into a text with a given maximal precision + * @note + * Performance sensitivity.CM_ASSERT should be guaranteed by caller, + * i.g. 1.dec->sign == DEC_SIGN_PLUS 2.dec->expn == 0 3.dec->cells[0] > 0 + */ +status_t ct_cm_dec8_to_text(const dec8_t *dec, int32 max_len, text_t *text) { + int32 sci_exp; /** The scientific scale of the dec */ + int32 prec; + if (dec == NULL || text == NULL) { + assert(0); + } + max_len = MIN(max_len, (int32)(CT_NUMBER_BUFFER_SIZE - 1)); + if (dec->ncells == 0) { + text->str[0] = '0'; + text->len = 1; + return CT_SUCCESS_STATUS; + } + // Compute the final scientific scale of the dec, i.e., format of d.xxxx , d > + // 0. Each decimal has an unique scientific representation. + sci_exp = DEC8_GET_SEXP(dec); + // get the total precision of the decimal + prec = cm_dec8_calc_prec(dec); + // Scientific representation when the scale exceeds the maximal precision + // or have many leading zeros and have many significant digits + // When sci_exp < 0, the length for '.' should be considered + if ((sci_exp < -6 && -sci_exp + prec + (int32)dec->sign > max_len) || + (sci_exp > 0 && sci_exp + 1 + (int32)dec->sign > max_len)) { + return cm_dec8_to_sci_text(text, dec, max_len); + } + // output plain text + return cm_dec8_to_plain_text(text, dec, max_len, sci_exp, prec); +} diff --git a/storage/tianchi/decimal_convert.h b/storage/tianchi/decimal_convert.h new file mode 100644 index 0000000..d0fe46f --- /dev/null +++ b/storage/tianchi/decimal_convert.h @@ -0,0 +1,357 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "my_dbug.h" +#include "my_inttypes.h" +#include "string.h" + +#ifndef DECIMAL_CONVERT_H +#define DECIMAL_CONVERT_H +#define DEC8_EXPN_UNIT 8 +/* The number of cells (an uint32) used to store the decimal type. */ +#define DEC8_CELL_SIZE (uint8)9 +#define DEC4_CELL_SIZE (uint8)18 +#define CT_MAX_DEC_OUTPUT_ALL_PREC (int32)72 +#define CT_FALSE (uint8)0 +#define CT_TRUE (uint8)1 +#define MAX_NUMERIC_EXPN (int32)127 +#define MIN_NUMERIC_EXPN (int32) - 127 +#define MAX_NUMERIC_BUFF 65 +#define CT_NUMBER_BUFFER_SIZE (uint32)128 +#define SEXP_2_D8EXP(sci_exp) (int16)((sci_exp) / DEC8_EXPN_UNIT) +/* The number of digits that an element of an int256, i.e., an uint32 +can encode. This indicates each uint32 can record at most DEC_ELEM_DIGIT +digits. Its value 9 is the upper, since 10^(9+1) < 2^32 < 10^11 */ +#define DEC8_CELL_DIGIT 8 +/* The the mask used to handle each cell. It is equal to 10^DEC_CELL_DIGIT */ +#define DEC8_CELL_MASK 100000000U +/* The the mask used to handle each cell. It is equal to 10^DEC4_CELL_DIGIT */ +#define DEC4_CELL_MASK 10000U + +/* the maximal precision that stored into DB */ +#define DEC_MAX_NUM_SAVING_PREC (int32)72 + +#define SIZE_K(n) (uint32)((n)*1024) +#define SIZE_M(n) (1024 * SIZE_K(n)) +/** The format to print a cell */ +#define DEC8_CELL_FMT "%08u" +#define CM_DEFAULT_DIGIT_RADIX 10 +#define CM_IS_ZERO(c) ((c) == '0') +#define CM_IS_DIGIT(c) ((c) >= '0' && ((c) <= '9')) +#define CM_IS_DOT(c) ((c) == '.') +#define CM_IS_EXPN_CHAR(c) ((c) == 'e' || ((c) == 'E')) +#define CM_IS_SIGN_CHAR(c) ((c) == '-' || ((c) == '+')) +#define ZERO_DEC_HEAD(dec) (dec)->head = 0 +#undef MIN +#define MIN(A, B) ((B) < (A) ? (B) : (A)) +/** Convert a digital char into numerical digit */ +#define CM_C2D(c) ((c) - '0') +#define D8EXP_2_SEXP(dexp) ((dexp)*DEC8_EXPN_UNIT) +/* DEC_MAX_ALLOWED_PREC = DEC_CELL_SIZE * DEC_CELL_DIGIT indicates the maximal +precision that a decimal can capture at most */ +#define DEC8_MAX_ALLOWED_PREC (DEC8_CELL_SIZE * DEC8_CELL_DIGIT) +/** Append a char at the end of text */ +#define CM_TEXT_APPEND(text, c) (text)->str[(text)->len++] = (c) +#define NUMPART_IS_ZERO(np) \ + ((np)->digit_text.len == 1 && CM_IS_ZERO((np)->digit_text.str[0])) +/* Get the scientific exponent of a decimal6 */ +/* Get the scientific exponent of a decimal when given its exponent and + * precision */ +#define DEC8_GET_SEXP_BY_PREC0(sexp, prec0) ((int32)(sexp) + (int32)(prec0)-1) +/* Get the scientific exponent of a decimal when given its exponent and cell0 */ +#define DEC8_GET_SEXP_BY_CELL0(sexp, c8_0) \ + DEC8_GET_SEXP_BY_PREC0(sexp, cm_count_u32digits(c8_0)) +#define DEC8_GET_SEXP(dec) \ + DEC8_GET_SEXP_BY_CELL0(D8EXP_2_SEXP((dec)->expn), ((dec)->cells[0])) +/* Get the position of n-th digit of an dec8, when given precision + * of cell0 (i.e., the position of the dot). + * @note Both n and the pos begin with 0 */ +#define DEC8_POS_N_BY_PREC0(n, prec0) \ + ((n) + (int32)DEC8_CELL_DIGIT - (int32)(prec0)) +/* Get the tail address of a text */ +#define CM_GET_TAIL(text) ((text)->str + (text)->len) +/** Clear all characters of the text */ +#define CM_TEXT_CLEAR(text) (text)->len = 0 +/* if the condition is true, throw return the value. + * Note: this Macro used to reduce Circle Complexity */ +#define CT_THROW(cond, value) \ + do { \ + if (cond) { \ + return (value); \ + } \ + } while (0) +#define CM_ZERO_NUMPART(np) \ + do { \ + (np)->digit_text.str[0] = '0'; \ + (np)->digit_text.str[1] = '\0'; \ + (np)->digit_text.len = 1; \ + } while (0) +#define CM_NULL_TERM(text) \ + { (text)->str[(text)->len] = '\0'; } +#define CT_RETURN_IF_ERROR(ret) \ + do { \ + status_t _status_ = (ret); \ + if (_status_ != CT_SUCCESS_STATUS) { \ + return _status_; \ + } \ + } while (0) +/* To decide whether a decimal is zero */ +#define DECIMAL_IS_ZERO(dec) ((dec)->ncells == 0) +/* +/- */ +#define DEC_SIGN_PLUS (uint8)0 +#define DEC_SIGN_MINUS (uint8)1 +typedef uint32 c8typ_t; +typedef uint64 cc8typ_t; +typedef c8typ_t cell8_t[DEC8_CELL_SIZE]; +typedef unsigned int bool32; +typedef struct st_dec8 { + union { + struct { + uint8 sign; /* 0: for positive integer; 1: for negative integer */ + uint8 ncells; /* number of cells, 0: for unspecified precision */ + int16 expn; /* the exponent of the number */ + }; + c8typ_t head; + }; + cell8_t cells; +} dec8_t; +#pragma pack(4) +typedef struct st_text { + char *str; + uint32 len; +} text_t; +#pragma pack() +typedef uint16 c4typ_t; +typedef uint32 cc4typ_t; +typedef c4typ_t cell4_t[DEC4_CELL_SIZE]; +#pragma pack(2) +typedef struct st_dec4 { + union { + struct { + uint8 sign : 1; /* 0: for positive integer; 1: for negative integer */ + uint8 ncells : 7; /* number of cells, 0: for unspecified precision */ + int8 expn; /* the exponent of the number */ + }; + c4typ_t head; + }; + cell4_t cells; + text_t num_text; // only for bind param +} dec4_t; +#pragma pack() +typedef enum en_status { + CT_ERROR = -1, + CT_SUCCESS_STATUS = 0, + CT_TIMEDOUT = 1, +} status_t; +typedef enum en_num_errno { + NERR_SUCCESS = 0, // CT_SUCCESS + NERR_ERROR, /* error without concrete reason */ + NERR_INVALID_LEN, + NERR_NO_DIGIT, + NERR_UNEXPECTED_CHAR, + NERR_NO_EXPN_DIGIT, + NERR_EXPN_WITH_NCHAR, + NERR_EXPN_TOO_LONG, + NERR_EXPN_OVERFLOW, + NERR_OVERFLOW, + NERR_UNALLOWED_NEG, + NERR_UNALLOWED_DOT, + NERR_UNALLOWED_EXPN, + NERR_MULTIPLE_DOTS, + NERR_EXPECTED_INTEGER, + NERR_EXPECTED_POS_INT, + NERR__NOT_USED__ /* for safely accessing the error information */ +} num_errno_t; +typedef enum en_num_flag { + NF_NONE = 0x0, + NF_NEGATIVE_SIGN = 0x0001, /* `-` */ + NF_POSTIVE_SIGN = 0x0002, /* `+` */ + NF_SIGN = NF_NEGATIVE_SIGN | NF_POSTIVE_SIGN, /* `+` */ + NF_DOT = 0x0004, /* `.` */ + NF_EXPN = 0x0008, /* `E` or `e` */ + NF_SZ_INDICATOR = 0x0010, /* B, K, M, G, T, P, E */ + NF_ALL = 0xFFFF +} num_flag_t; +#define CT_MAX_NUM_PART_BUFF (CT_MAX_DEC_OUTPUT_ALL_PREC) +typedef struct st_digitext { + char str[CT_MAX_NUM_PART_BUFF]; + uint32 len; +} digitext_t; +typedef struct st_num_part { + bool32 is_neg; + bool32 has_dot; + bool32 has_expn; + bool32 do_round; + int32 sci_expn; + /* indicating which num flag should be excluded, it should be specified + * before parsing. */ + uint32 excl_flag; + digitext_t digit_text; + /* for parse size type (unsigned integer with [K|M|G|T|P...]) */ + char sz_indicator; +} num_part_t; +#if defined(SECUREC_NEED_BUILTIN_EXPECT_DECLARE) +long __builtin_expect(long exp, long c); +#endif +#define SECUREC_LIKELY(x) __builtin_expect(!!(x), 1) +#define SECUREC_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define SECUREC_LIKELY(x) (x) +#define SECUREC_UNLIKELY(x) (x) +#endif +/* success */ +#ifndef EOK +#define EOK 0 +#endif +status_t ct_cm_str_to_dec8(const char *str, dec8_t *dec); +status_t ct_cm_text_to_dec8(const text_t *text, dec8_t *dec); +num_errno_t ct_cm_split_num_text(const text_t *num_text, num_part_t *np); +num_errno_t ct_cm_numpart_to_dec8(num_part_t *np, dec8_t *dec); +status_t ct_cm_dec8_to_str(const dec8_t *dec, int max_len, char *str); +status_t ct_cm_dec8_to_text(const dec8_t *dec, int32 max_len, text_t *text); +static inline void ct_cm_rtrim_text(text_t *text) { + int32 index; + if (text->str == NULL) { + text->len = 0; + return; + } else if (text->len == 0) { + return; + } + index = (int32)text->len - 1; + while (index >= 0) { + if ((uchar)text->str[index] > (uchar)' ') { + text->len = (uint32)(index + 1); + return; + } + --index; + } +} +static inline void ct_cm_ltrim_text(text_t *text) { + if (text->str == NULL) { + text->len = 0; + return; + } else if (text->len == 0) { + return; + } + while (text->len > 0) { + if ((uchar)*text->str > ' ') { + break; + } + text->str++; + text->len--; + } +} +static inline void ct_cm_trim_text(text_t *text) { + ct_cm_ltrim_text(text); + ct_cm_rtrim_text(text); +} +static inline uint32 cm_count_u32digits(uint32 u32) { + // Binary search + if (u32 >= 100000u) { + if (u32 >= 10000000u) { + return (u32 < 100000000u) ? 8 : ((u32 >= 1000000000u) ? 10 : 9); + } + return (u32 >= 1000000u) ? 7 : 6; + } + if (u32 >= 1000u) { + return (uint32)((u32 >= 10000u) ? 5 : 4); + } + return (uint32)((u32 >= 100u) ? 3 : ((u32 >= 10u) ? 2 : 1)); +} +static inline void cm_zero_dec8(dec8_t *dec) { ZERO_DEC_HEAD(dec); } +/** + * Convert a single cell text into uint32. A single cell text is a text of + * digits, with the number of text is no more than 9 + */ +static inline uint32 cm_celltext2uint32(const text_t *cellt) { + uint32 val = 0; + for (uint32 i = 0; i < cellt->len; ++i) { + val = val * 10 + (uint32)(uint8)CM_C2D(cellt->str[i]); + } + return val; +} +static inline void cm_dec8_trim_zeros(dec8_t *dec) { + while (dec->ncells > 0 && dec->cells[dec->ncells - 1] == 0) { + --dec->ncells; + } +} +static inline void cm_zero_dec4(dec4_t *dec) { ZERO_DEC_HEAD(dec); } +static inline uint32 cm_dec4_stor_sz(const dec4_t *d4) { + return ((uint32)(1 + (d4)->ncells)) * sizeof(c4typ_t); +} +// Decode a decimal from a void data with size +static inline void ct_cm_dec_4_to_8(dec8_t *d8, const dec4_t *d4, + uint32 sz_byte) { + // check validation again + if ((uint32)cm_dec4_stor_sz(d4) > sz_byte) { + assert(0); + } + if (DECIMAL_IS_ZERO(d4)) { + cm_zero_dec8(d8); + return; + } + uint32 i4 = 0; + uint32 i8 = 0; + d8->sign = d4->sign; + if (d4->expn < 0) { + d8->expn = (d4->expn - 1) / 2; + } else { + d8->expn = d4->expn / 2; + } + if (!(d4->expn & 1)) { + d8->cells[0] = d4->cells[0]; + i4 = 1; + i8 = 1; + } + for (; i4 < d4->ncells; i4 += 2, i8++) { + d8->cells[i8] = (c8typ_t)d4->cells[i4] * DEC4_CELL_MASK; + if (i4 + 1 < d4->ncells) { + d8->cells[i8] += d4->cells[i4 + 1]; + } + } + d8->ncells = i8; +} +static inline void cm_dec_8_to_4(dec4_t *d4, const dec8_t *d8) { + if (DECIMAL_IS_ZERO(d8)) { + cm_zero_dec4(d4); + return; + } + uint32 i8 = 0; + uint32 i4 = 0; + d4->sign = d8->sign; + d4->expn = (int8)(d8->expn * 2 + 1); + if (d8->cells[0] < DEC4_CELL_MASK) { + d4->cells[0] = (c4typ_t)d8->cells[0]; + d4->expn--; + i4++; + i8++; + } + for (; i8 < d8->ncells; i8++, i4 += 2) { + d4->cells[i4] = d8->cells[i8] / DEC4_CELL_MASK; + d4->cells[i4 + 1] = d8->cells[i8] % DEC4_CELL_MASK; + } + + if (i4 > DEC4_CELL_SIZE) { + assert(0); + } + + // remove tailing zero if exits + if (d4->cells[i4 - 1] == 0) { + i4--; + } + d4->ncells = (uint8)i4; +} diff --git a/storage/tianchi/ha_tse.cc b/storage/tianchi/ha_tse.cc new file mode 100644 index 0000000..c0b5332 --- /dev/null +++ b/storage/tianchi/ha_tse.cc @@ -0,0 +1,5241 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// @file storage/tianchi/ha_tse.cc +// description: TIANCHI handler implementation for MySQL storage engine API. +// this module should use tse_srv rather than knl_intf + +/** + @file ha_tse.cc + + @details + The tse storage engine is set up to use table locks. It + implements an tse "SHARE" that is inserted into a hash by table + name. You can use this to store information of state that any + tse handler object will be able to see when it is using that + table. + + Please read the object definition in ha_tse.h before reading the rest + of this file. + + @note + When you create an TSE table, the MySQL Server creates a table .frm + (format) file in the database directory, using the table name as the file + name as is customary with MySQL. No other files are created. To get an idea + of what occurs, here is an tse select that would do a scan of an entire + table: + @code + ha_tse::store_lock + ha_tse::external_lock + ha_tse::info + ha_tse::rnd_init + ha_tse::extra + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::rnd_next + ha_tse::extra + ha_tse::external_lock + ha_tse::extra + ENUM HA_EXTRA_RESET Reset database to after open + @endcode + + Here you see that the tse storage engine has 9 rows called before + rnd_next signals that it has reached the end of its data. Also note that + the table in question was already opened; had it not been open, a call to + ha_tse::open() would also have been necessary. Calls to + ha_tse::extra() are hints as to what will be occurring to the request. + + A Longer Dse can be found called the "Skeleton Engine" which can be + found on TangentOrg. It has both an engine and a full build environment + for building a pluggable storage engine. + + Happy coding!
+ -Brian +*/ + +#include "ha_tse.h" +#include "ha_tse_ddl.h" +#include "ha_tsepart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "field_types.h" +#include "my_base.h" +#include "my_macros.h" +#include "my_pointer_arithmetic.h" +#include "my_psi_config.h" +#include "mysql/plugin.h" +#include "sql/current_thd.h" +#include "sql/dd/types/table.h" +#include "sql/discrete_interval.h" // Discrete_interval +#include "sql/field.h" +#include "sql/create_field.h" +#include "sql/sql_base.h" // enum_tdc_remove_table_type +#include "sql/sql_class.h" +#include "sql/sql_lex.h" +#include "sql/sql_insert.h" +#include "sql/sql_plugin.h" +#include "sql/sql_initialize.h" // opt_initialize_insecure +#include "sql/abstract_query_plan.h" + +#include "tse_stats.h" +#include "tse_error.h" +#include "tse_log.h" +#include "tse_srv_mq_module.h" +#include "tse_util.h" +#include "protobuf/tc_db.pb-c.h" +#include "typelib.h" +#include "datatype_cnvrt_4_index_search.h" +#include "sql/mysqld.h" +#include "sql/plugin_table.h" +#include "sql/dd/object_id.h" +#include "sql/dd/cache/dictionary_client.h" +#include "sql/dd/dd_schema.h" +#include "sql/sql_table.h" +#include "sql/mysqld_thd_manager.h" +#include "sql/sql_backup_lock.h" + +//------------------------------------------------------------------------------// +// SYSTEM VARIABLES // +//------------------------------------------------------------------------------// +/* + * SYSTEM VARIABLES CAN BE DISPLAYED AS: + * mysql> SHOW GLOBAL VARIABLES like'%ctc%' + */ + +static void ctc_stats_enabled_update(THD *, SYS_VAR *, void *var_ptr, const void *save) { + bool val = *static_cast(var_ptr) = *static_cast(save); + ctc_stats::get_instance().set_stats_enabled(val); +} + +/* 创库的表空间datafile自动扩展, 默认开 */ +bool tse_db_datafile_autoextend = true; +static MYSQL_SYSVAR_BOOL(db_datafile_autoextend, tse_db_datafile_autoextend, PLUGIN_VAR_NOCMDARG, + "Indicates whether to automatically extend the tablespace data files of the TSE database.", nullptr, nullptr, true); +/* 创库的表空间datafile大小, 单位M, 默认32M, 最小1M, 最大8T */ +uint32_t tse_db_datafile_size = 32; +static MYSQL_SYSVAR_UINT(db_datafile_size, tse_db_datafile_size, PLUGIN_VAR_RQCMDARG, + "Size of the tablespace data file of the TSE database, in MB.", nullptr, nullptr, 32, 1, 8192 * 1024, 0); +/* 创库的表空间datafile自动扩展大小, 单位M, 默认8M, 最小1M, 最大8T */ +uint32_t tse_db_datafile_extend_size = 8; +static MYSQL_SYSVAR_UINT(db_datafile_extend_size, tse_db_datafile_extend_size, PLUGIN_VAR_RQCMDARG, + "Size of the TSE database tablespace data file automatically extended, in MB.", nullptr, nullptr, 8, 1, 8192 * 1024, 0); + +bool tse_concurrent_ddl = true; +static MYSQL_SYSVAR_BOOL(concurrent_ddl, tse_concurrent_ddl, PLUGIN_VAR_RQCMDARG, + "Indicates whether to ban concurrent DDL.", nullptr, nullptr, true); + +static mutex m_tse_metadata_normalization_mutex; +int32_t ctc_metadata_normalization = (int32_t)metadata_switchs::DEFAULT; +static MYSQL_SYSVAR_INT(metadata_normalization, ctc_metadata_normalization, PLUGIN_VAR_READONLY, + "Option for Mysql-Cantian metadata normalization.", nullptr, nullptr, -1, -1, 3, 0); + +int32_t ctc_max_cursors_no_autocommit = 128; +static MYSQL_SYSVAR_INT(max_cursors_no_autocommit, ctc_max_cursors_no_autocommit, PLUGIN_VAR_RQCMDARG, + "Size of max cursors for no autocommit in commit/rollback.", nullptr, nullptr, 128, 0, 8192, 0); + +static MYSQL_THDVAR_UINT(lock_wait_timeout, PLUGIN_VAR_RQCMDARG, + "Timeout in seconds an TSE transaction may wait " + "for a lock before being rolled back. Unit is " + "millisecond and values 0 means disable the timeout.", + nullptr, nullptr, 50000, 0, 1024 * 1024 * 1024, 0); + +static MYSQL_THDVAR_UINT(prefetch_buf_size, PLUGIN_VAR_READONLY, + "the maximum buf size of data/index prefetch", nullptr, + nullptr, 192 * 1024, 0, 192 * 1024, 0); + +static MYSQL_THDVAR_DOUBLE(sampling_ratio, PLUGIN_VAR_RQCMDARG, + "sampling ratio used for analyzing tables", nullptr, + nullptr, 100, 0.000001, 100, 0); + +__attribute__((visibility("default"))) uint32_t tse_instance_id = 0; +static MYSQL_SYSVAR_UINT(instance_id, tse_instance_id, PLUGIN_VAR_READONLY, + "mysql instance id which is used for daac", nullptr, + nullptr, 0, 0, UINT32_MAX, 0); + +bool tse_enable_x_lock_instance = false; +static MYSQL_SYSVAR_BOOL(enable_x_lock_instance, tse_enable_x_lock_instance, PLUGIN_VAR_NOCMDARG, + "LCOK INSTANCE FOR BACKUP add X latch on the cantian side", nullptr, nullptr, false); + +char *ctc_version_str = const_cast(CTC_VERSION_STR); +static MYSQL_SYSVAR_STR(version, ctc_version_str, + PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY | + PLUGIN_VAR_NOPERSIST, + "ctc plugin version", nullptr, nullptr, CTC_VERSION_STR); + +bool ctc_stats_enabled = false; +static MYSQL_SYSVAR_BOOL(stats_enabled, ctc_stats_enabled, PLUGIN_VAR_NOCMDARG, + "If statistical the costs of ctc interfaces.", nullptr, ctc_stats_enabled_update, false); + +uint32_t ctc_autoinc_lock_mode = CTC_AUTOINC_NO_LOCKING; +static MYSQL_SYSVAR_UINT(autoinc_lock_mode, ctc_autoinc_lock_mode, PLUGIN_VAR_RQCMDARG, + "The AUTOINC lock modes supported by CTC.", nullptr, nullptr, CTC_AUTOINC_NO_LOCKING, + CTC_AUTOINC_OLD_STYLE_LOCKING, CTC_AUTOINC_NO_LOCKING, 0); + +// All global and session system variables must be published to mysqld before +// use. This is done by constructing a NULL-terminated array of the variables +// and linking to it in the plugin public interface. +static SYS_VAR *tse_system_variables[] = { + MYSQL_SYSVAR(lock_wait_timeout), + MYSQL_SYSVAR(instance_id), + MYSQL_SYSVAR(prefetch_buf_size), + MYSQL_SYSVAR(sampling_ratio), + MYSQL_SYSVAR(enable_x_lock_instance), + MYSQL_SYSVAR(db_datafile_autoextend), + MYSQL_SYSVAR(db_datafile_size), + MYSQL_SYSVAR(db_datafile_extend_size), + MYSQL_SYSVAR(concurrent_ddl), + MYSQL_SYSVAR(metadata_normalization), + MYSQL_SYSVAR(max_cursors_no_autocommit), + MYSQL_SYSVAR(version), + MYSQL_SYSVAR(stats_enabled), + MYSQL_SYSVAR(autoinc_lock_mode), + nullptr +}; + +/** Operations for altering a table that CTC does not care about */ +static const Alter_inplace_info::HA_ALTER_FLAGS CTC_INPLACE_IGNORE = + Alter_inplace_info::ALTER_COLUMN_DEFAULT | + Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT | + Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE | + Alter_inplace_info::ALTER_RENAME | + Alter_inplace_info::CHANGE_INDEX_OPTION | + Alter_inplace_info::ADD_CHECK_CONSTRAINT | + Alter_inplace_info::DROP_CHECK_CONSTRAINT | + Alter_inplace_info::SUSPEND_CHECK_CONSTRAINT | + Alter_inplace_info::ALTER_COLUMN_VISIBILITY; + +/** Operations that CTC cares about and can perform without rebuild */ +static const Alter_inplace_info::HA_ALTER_FLAGS CTC_ALTER_NOREBUILD = + Alter_inplace_info::ADD_INDEX | + Alter_inplace_info::ADD_UNIQUE_INDEX | + Alter_inplace_info::ADD_SPATIAL_INDEX | + Alter_inplace_info::DROP_FOREIGN_KEY | + Alter_inplace_info::ADD_FOREIGN_KEY | + Alter_inplace_info::DROP_INDEX | + Alter_inplace_info::DROP_UNIQUE_INDEX | + Alter_inplace_info::RENAME_INDEX | + Alter_inplace_info::ALTER_COLUMN_NAME | + Alter_inplace_info::ALTER_INDEX_COMMENT | + Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH; + +/** Operations for rebuilding a table in place */ +static const Alter_inplace_info::HA_ALTER_FLAGS CTC_ALTER_REBUILD = + Alter_inplace_info::ADD_PK_INDEX | + Alter_inplace_info::DROP_PK_INDEX | + Alter_inplace_info::CHANGE_CREATE_OPTION | + Alter_inplace_info::ALTER_COLUMN_NULLABLE | + Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE | + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | + Alter_inplace_info::DROP_STORED_COLUMN | + Alter_inplace_info::ADD_STORED_BASE_COLUMN | + Alter_inplace_info::RECREATE_TABLE; + +static const Alter_inplace_info::HA_ALTER_FLAGS CTC_ALTER_COL_ORDER = + Alter_inplace_info::DROP_COLUMN | + Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER | + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER; + +static const Alter_inplace_info::HA_ALTER_FLAGS PARTITION_OPERATIONS = + Alter_inplace_info::ADD_PARTITION | Alter_inplace_info::COALESCE_PARTITION; + +static const Alter_inplace_info::HA_ALTER_FLAGS COLUMN_TYPE_OPERATIONS = + Alter_inplace_info::ALTER_STORED_COLUMN_TYPE | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH; + +//------------------------------------------------------------------------------ +constexpr int max_prefetch_num = MAX_PREFETCH_REC_NUM; + +// ref MAX_RECORD_BUFFER_SIZE, used for private record buffer assigned for each handler +constexpr int MAX_RECORD_BUFFER_SIZE_TSE = (3 * TSE_BUF_LEN); +constexpr uint64 INVALID_VALUE64 = 0xFFFFFFFFFFFFFFFFULL; + +bool is_log_table = false; + +#define ARRAY_SIZE_TWO 2 + +static int tse_rollback_savepoint(handlerton *hton, THD *thd, void *savepoint); +handlerton *tse_hton; + +int ha_tse_get_inst_id() { return tse_instance_id; } + +void ha_tse_set_inst_id(uint32_t inst_id) { tse_instance_id = inst_id; } + +handlerton *get_tse_hton() { return tse_hton; } + +/* +* Check whether it is CREATE TABLE ... SELECT +* reference: populate_table + */ +static inline bool is_create_table_check(MYSQL_THD thd) { + if (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + thd->lex->is_exec_started()) { + return true; + } + return false; +} + +static bool user_var_set(MYSQL_THD thd, string target_str) { + user_var_entry *var_entry; + var_entry = find_or_nullptr(thd->user_vars, target_str); + if (var_entry != nullptr && var_entry->ptr() != nullptr) { + tse_log_debug("thd (%d) has user variable %s", thd->thread_id(), target_str.data()); + return true; + } + return false; +} + +dml_flag_t tse_get_dml_flag(THD *thd, bool is_replace, bool auto_inc_used, + bool has_explicit_autoinc, bool dup_update) { + dml_flag_t flag; + flag.ignore = thd->lex->is_ignore(); + flag.no_foreign_key_check = (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) ? 1 : 0; + flag.no_cascade_check = false; + flag.dd_update = (thd->variables.option_bits & OPTION_DD_UPDATE_CONTEXT) ? 1 : 0; + flag.is_replace = is_replace; + flag.no_logging = (thd->in_sub_stmt && (thd->in_sub_stmt & SUB_STMT_TRIGGER)) ? 1 : 0; + flag.auto_inc_used = auto_inc_used; + flag.has_explicit_autoinc = has_explicit_autoinc; + flag.autoinc_lock_mode = ctc_autoinc_lock_mode; + flag.dup_update= dup_update; + flag.auto_inc_step = thd->variables.auto_increment_increment; + flag.auto_inc_offset = thd->variables.auto_increment_offset; + flag.auto_increase = false; + flag.is_create_select = is_create_table_check(thd); + return flag; +} + +bool is_initialize() { + return opt_initialize || opt_initialize_insecure; +} + +bool is_starting() { + return !mysqld_server_started && !is_initialize(); +} + +bool is_work_flow() { + return mysqld_server_started && !is_initialize(); +} + +bool is_ctc_mdl_thd(THD* thd) { + if (thd->query().str && string(thd->query().str) == "tse_mdl_thd_notify") { + return true; + } + return false; +} + +// 是否为元数据归一的初始化流程 +bool is_meta_version_initialize() { + bool is_meta_normalization = CHECK_HAS_MEMBER(handlerton, get_metadata_switch); + if (is_meta_normalization && is_initialize()) { + return true; + } + return false; +} + +bool is_alter_table_scan(bool m_error_if_not_empty) { + return m_error_if_not_empty; +} + +bool ddl_enabled_normal(MYSQL_THD thd) { + return !user_var_set(thd, "ctc_ddl_local_enabled") && + (tse_concurrent_ddl == true || + (tse_concurrent_ddl == false && user_var_set(thd, "ctc_ddl_enabled"))); +} + +bool engine_ddl_passthru(MYSQL_THD thd) { + // 元数据归一初始化场景,接口流程需要走到参天 + if (is_meta_version_initialize()) { + return false; + } + + return is_initialize() || !mysqld_server_started || user_var_set(thd, "ctc_ddl_local_enabled"); +} + +bool ha_tse::is_replay_ddl(MYSQL_THD thd) { + char db_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(table->s->normalized_path.str, db_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(db_name, db_name, SMALL_RECORD_SIZE); + if (mysql_system_db.find(db_name) != mysql_system_db.end()) { + return false; + } + + if (user_var_set(thd, "ctc_ddl_local_enabled") && user_var_set(thd, "ctc_replay_ddl")) { + return true; + } + + return false; +} + +static int tse_reg_instance() { + uint32_t inst_id = MYSQL_PROC_START; + uint32_t count = 0; + ct_errno_t ret = CT_SUCCESS; + + while (count++ < TSE_START_TIMEOUT) { + ret = (ct_errno_t)tse_alloc_inst_id(&inst_id); + if (ret == CT_SUCCESS) { + ha_tse_set_inst_id(inst_id); + tse_log_system("[TSE_INIT]:tse reg instance success, inst_id:%u", + ha_tse_get_inst_id()); + break; + } + tse_log_system("[TSE_INIT]:tse reg instance failed and sleep %u/%u", count, + TSE_START_TIMEOUT); + sleep(1); + } + return convert_tse_error_code_to_mysql(ret); +} + +static void tse_unreg_instance() { + // 元数据归一流程初始化阶段下发参天, 主干不下发 + if (opt_initialize_insecure && !CHECK_HAS_MEMBER(handlerton, get_inst_id)) { + return; + } + + uint32_t inst_id; + inst_id = ha_tse_get_inst_id(); + ct_errno_t ret = (ct_errno_t)tse_release_inst_id(inst_id); + if (ret != CT_SUCCESS) { + tse_log_error("tse release instance id:%u failed, ret:%d", + ha_tse_get_inst_id(), ret); + } else { + tse_log_system("tse release instance id:%u success", ha_tse_get_inst_id()); + } +} + +/* +* Check if the ALTER TABLE operations need table copy +* reference: is_inplace_alter_impossible() +* Alter_info::ALTER_TABLE_ALGORITHM_COPY tag set at ha_tse::create or spcified by ALGORITHMY = COPY +*/ +bool is_alter_table_copy(MYSQL_THD thd, const char *name) { + if (!thd->lex->alter_info) { + return false; + } + + if (thd->lex->alter_info->requested_algorithm == Alter_info::ALTER_TABLE_ALGORITHM_COPY) { + if (name == nullptr) { + return true; + } + + // COPY 算法时,正常表open接口下发参天, #sql开头的表直接返回,不下发参天 + if (is_prefix(name, tmp_file_prefix)) { + return true; + } + } + + return false; +} + +static bool is_lock_table(MYSQL_THD thd) { + if (thd->lex->sql_command == SQLCOM_LOCK_TABLES) { + return true; + } + return false; +} + +static bool check_cmp_result(Item *term) { + Item_field *item_field = (Item_field *)(((Item_func *)term)->arguments()[0]); + Item_field *item_field_next = (Item_field *)(((Item_func *)term)->arguments()[1]); + Item::Type type = (((Item_func *)term)->arguments()[1])->type(); + + if (type == Item::NULL_ITEM) { + return true; + } + if (item_field->data_type() == MYSQL_TYPE_YEAR) { + return type == Item::INT_ITEM && item_field_next->cmp_context == INT_RESULT; + } + + if (is_temporal_type(item_field->data_type())) { + if (!((((Item_func *)term)->arguments()[1])->basic_const_item() && item_field_next->cmp_context == INT_RESULT)) { + return false; + } + if (item_field->data_type() == MYSQL_TYPE_TIMESTAMP) { + MYSQL_TIME ltime; + if (((Item_date_literal *)(((Item_func_eq *)term)->arguments()[1]))->get_date(<ime, TIME_FUZZY_DATE)) { + return false; + } + if (non_zero_date(ltime)) { + return ltime.year && ltime.month && ltime.day; + } + } + return true; + } + + if (is_string_type(item_field->data_type())) { + return type == Item::STRING_ITEM && item_field_next->cmp_context == STRING_RESULT; + } + + if (is_integer_type(item_field->data_type())) { + return (type == Item::INT_ITEM && item_field_next->cmp_context == INT_RESULT) || type == Item::CACHE_ITEM; + } + + if (is_numeric_type(item_field->data_type())) { + return (type == Item::REAL_ITEM || type == Item::DECIMAL_ITEM) && item_field_next->cmp_context != STRING_RESULT; + } + + return false; +} + +static bool is_supported_datatype_cond(enum_field_types datatype) { + switch (datatype) { + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TYPED_ARRAY: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: { + return false; + } + default: + return true; + } +} + +static bool is_supported_func_item(Item *term) { + Item_func::Functype functype = ((Item_func *)term)->functype(); + // filter unspported func + if (functype != Item_func::EQ_FUNC && + functype != Item_func::EQUAL_FUNC && + functype != Item_func::NE_FUNC && + functype != Item_func::LT_FUNC && + functype != Item_func::LE_FUNC && + functype != Item_func::GE_FUNC && + functype != Item_func::GT_FUNC && + functype != Item_func::LIKE_FUNC && + functype != Item_func::ISNULL_FUNC && + functype != Item_func::ISNOTNULL_FUNC) { + return false; + } + + Item::Type type = (((Item_func *)term)->arguments()[0])->type(); + // filter expressions + if (type != Item::FIELD_ITEM) { + return false; + } + + Item_field *item_field = (Item_field *)(((Item_func *)term)->arguments()[0]); + + // filter generated column + if (item_field->field->is_gcol() || !item_field->field->part_of_prefixkey.is_clear_all()) { + return false; + } + + // filter unsupport datatype + if (!is_supported_datatype_cond(item_field->field->real_type())) { + return false; + } + + // filter binary + if (item_field->data_type() == MYSQL_TYPE_STRING) { + if (item_field->collation.collation->pad_char == '\0') { + return false; + } + } + + if (functype == Item_func::ISNULL_FUNC || functype == Item_func::ISNOTNULL_FUNC) { + return true; + } + + if (functype == Item_func::LIKE_FUNC) { + Item_func_like *like_func = (Item_func_like *)((Item_func *)term); + if (like_func->escape_was_used_in_parsing() || !is_string_type(item_field->data_type())) { + return false; + } + } + + if (item_field->cmp_context == INVALID_RESULT) { + return false; + } + + return check_cmp_result(term); +} + +int create_and_conditions(Item_cond *cond, List pushed_list, + List remainder_list, Item *&pushed_cond, + Item *&remainder_cond) { + if (remainder_list.is_empty()) { + // Entire cond pushed, no remainder + pushed_cond = cond; + remainder_cond = nullptr; + return 0; + } + if (pushed_list.is_empty()) { + // Nothing pushed, entire 'cond' is remainder + pushed_cond = nullptr; + remainder_cond = cond; + return 0; + } + + // Condition was partly pushed, with some remainder + if (pushed_list.elements == 1) { + // Single boolean term pushed, return it + pushed_cond = pushed_list.head(); + } else { + // Construct an AND'ed condition of pushed boolean terms + pushed_cond = new Item_cond_and(pushed_list); + if (pushed_cond == nullptr) { + return 1; + } + } + + if (remainder_list.elements == 1) { + // A single boolean term as remainder, return it + remainder_cond = remainder_list.head(); + } else { + // Construct a remainder as an AND'ed condition of the boolean terms + remainder_cond = new Item_cond_and(remainder_list); + if (remainder_cond == nullptr) { + return 1; + } + } + return 0; +} + +int create_or_conditions(Item_cond *cond, List pushed_list, + List remainder_list, Item *&pushed_cond, + Item *&remainder_cond) { + assert(pushed_list.elements == cond->argument_list()->elements); + + if (remainder_list.is_empty()) { + // Entire cond pushed, no remainder + pushed_cond = cond; + remainder_cond = nullptr; + } else { + // When condition was partially pushed, we need to reevaluate + // original OR-cond on the server side: + remainder_cond = cond; + + // Construct an OR condition of pushed terms + pushed_cond = new Item_cond_or(pushed_list); + if (pushed_cond == nullptr){ + return 1; + } + } + return 0; +} + +void cond_push_boolean_term(Item *term, Item *&pushed_cond, Item *&remainder_cond) { + if (term->type() == Item::COND_ITEM) { + List pushed_list; + List remainder_list; + Item_cond *cond = (Item_cond *)term; + if (cond->functype() == Item_func::COND_AND_FUNC) { + List_iterator li(*cond->argument_list()); + Item *boolean_term; + while ((boolean_term = li++)) { + Item *pushed = nullptr, *remainder = nullptr; + cond_push_boolean_term(boolean_term, pushed, remainder); + if (pushed != nullptr) pushed_list.push_back(pushed); + if (remainder != nullptr) remainder_list.push_back(remainder); + } + + if (create_and_conditions(cond, pushed_list, remainder_list, pushed_cond, remainder_cond)) { + pushed_cond = nullptr; + remainder_cond = cond; + return; + } + } else { + assert(cond->functype() == Item_func::COND_OR_FUNC); + List_iterator li(*cond->argument_list()); + Item *boolean_term; + while ((boolean_term = li++)) { + Item *pushed = nullptr, *remainder = nullptr; + cond_push_boolean_term(boolean_term, pushed, remainder); + if (pushed == nullptr) { + // Failure of pushing one of the OR-terms fails entire OR'ed cond + pushed_cond = nullptr; + remainder_cond = cond; + return; + } + + if (pushed != nullptr) pushed_list.push_back(pushed); + if (remainder != nullptr) remainder_list.push_back(remainder); + } + + if (create_or_conditions(cond, pushed_list, remainder_list, pushed_cond, + remainder_cond)) { + // Failed, discard pushed conditions. + pushed_cond = nullptr; + remainder_cond = cond; + return; + } + } + } else if (term->type() == Item::FUNC_ITEM) { + if (is_supported_func_item(term)) { + pushed_cond = term; + remainder_cond = nullptr; + return; + } + pushed_cond = nullptr; + remainder_cond = term; + return; + } else { + pushed_cond = nullptr; + remainder_cond = term; + return; + } +} + +void ha_tse::prep_cond_push(const Item *cond) { + Item *item = const_cast(cond); + Item *pushed_cond = nullptr; + Item *remainder = nullptr; + cond_push_boolean_term(item, pushed_cond, remainder); + m_pushed_conds = pushed_cond; + m_remainder_conds = remainder; +} + +// 返回值检测设置 +void ha_tse::check_error_code_to_mysql(THD *thd, ct_errno_t *ret) { + bool no_foreign_key_check = thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS; + //判断ret是否返回死锁,死锁则回滚 + if (*ret == ERR_DEAD_LOCK) { + thd_mark_transaction_to_rollback(thd, 1); + return; + } else if(no_foreign_key_check == false) { + return; + } + + static set g_ctc_ignore_foreign_key_check_ret_value = { + ERR_CONSTRAINT_VIOLATED_NO_FOUND, ERR_ROW_IS_REFERENCED}; + if (g_ctc_ignore_foreign_key_check_ret_value.count(*ret) > 0) { + tse_log_system("ctc_ignore_foreign_key_check catching."); + *ret = CT_SUCCESS; + } +} + +bool ha_tse::check_unsupported_operation(THD *thd, HA_CREATE_INFO *create_info) { + // 不支持的操作 + if (thd->lex->alter_info && (thd->lex->alter_info->flags & + Alter_info::ALTER_EXCHANGE_PARTITION)) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "The current operation is not supported."); + return true; + } + + if (create_info != nullptr && (create_info->options & HA_LEX_CREATE_TMP_TABLE) && !IS_METADATA_NORMALIZATION()) { + my_error(ER_NOT_ALLOWED_COMMAND, MYF(0)); + return HA_ERR_UNSUPPORTED; + } + + return false; +} + +enum dd_index_keys { + /** Index identifier */ + DD_INDEX_ID, + /** Space id */ + DD_INDEX_SPACE_ID, + /** Table id */ + DD_TABLE_ID, + /** Root page number */ + DD_INDEX_ROOT, + /** Creating transaction ID */ + DD_INDEX_TRX_ID, + /** Sentinel */ + DD_INDEX__LAST +}; + +/** CTC private keys for dd::Table */ +enum dd_table_keys { + /** Auto-increment counter */ + DD_TABLE_AUTOINC, + /** DATA DIRECTORY (static metadata) */ + DD_TABLE_DATA_DIRECTORY, + /** Dynamic metadata version */ + DD_TABLE_VERSION, + /** Discard flag. Please don't use it directly, and instead use + dd_is_discarded and dd_set_discarded functions. Discard flag is defined + for both dd::Table and dd::Partition and it's easy to confuse. + The functions will choose right implementation for you, depending on + whether the argument is dd::Table or dd::Partition. */ + DD_TABLE_DISCARD, + /** Columns before first instant ADD COLUMN */ + DD_TABLE_INSTANT_COLS, + /** Sentinel */ + DD_TABLE__LAST +}; + +const char *const dd_index_key_strings[DD_INDEX__LAST] = { + "id", "space_id", "table_id", "root", "trx_id"}; + +static constexpr dd::Object_id g_dd_dict_space_id = 1; + +/** CTC private key strings for dd::Table. @see dd_table_keys */ +const char *const dd_table_key_strings[DD_TABLE__LAST] = { + "autoinc", "data_directory", "version", "discard", "instant_col"}; + +static void dd_set_autoinc(dd::Properties &se_private_data, uint64 autoinc) { + /* The value of "autoinc" here is the AUTO_INCREMENT attribute + specified at table creation. AUTO_INCREMENT=0 will silently + be treated as AUTO_INCREMENT=1. Likewise, if no AUTO_INCREMENT + attribute was specified, the value would be 0. */ + + if (autoinc > 0) { + /* CTC persists the "previous" AUTO_INCREMENT value. */ + autoinc--; + } + + uint64 version = 0; + + if (se_private_data.exists(dd_table_key_strings[DD_TABLE_AUTOINC])) { + /* Increment the dynamic metadata version, so that any previously buffered persistent dynamic metadata + will be ignored after this transaction commits. */ + + if (!se_private_data.get(dd_table_key_strings[DD_TABLE_VERSION], + &version)) { + version++; + } else { + /* incomplete se_private_data */ + assert(0); + } + } + + se_private_data.set(dd_table_key_strings[DD_TABLE_VERSION], version); + se_private_data.set(dd_table_key_strings[DD_TABLE_AUTOINC], autoinc); +} + +bool ha_tse::get_se_private_data(dd::Table *dd_table, bool reset) { + static uint n_tables = 1024; + static uint n_indexes = 0; + static uint n_pages = 4; + + DBUG_TRACE; + assert(dd_table != nullptr); + + if (reset) { + n_tables = 0; + n_indexes = 0; + n_pages = 4; + } + + if ((*(const_cast(dd_table))->columns().begin()) + ->is_auto_increment()) { + dd_set_autoinc(dd_table->se_private_data(), 0); + } + + dd_table->set_se_private_id(++n_tables); + dd_table->set_tablespace_id(g_dd_dict_space_id); + + /* Set the table id for each column to be conform with the + implementation in dd_write_table(). */ + for (auto dd_column : *dd_table->table().columns()) { + dd_column->se_private_data().set(dd_index_key_strings[DD_TABLE_ID], + n_tables); + } + + for (dd::Index *i : *dd_table->indexes()) { + i->set_tablespace_id(g_dd_dict_space_id); + + dd::Properties &p = i->se_private_data(); + + p.set(dd_index_key_strings[DD_INDEX_ROOT], n_pages++); + p.set(dd_index_key_strings[DD_INDEX_ID], ++n_indexes); + p.set(dd_index_key_strings[DD_INDEX_TRX_ID], 0); + p.set(dd_index_key_strings[DD_INDEX_SPACE_ID], 0); + p.set(dd_index_key_strings[DD_TABLE_ID], n_tables); + } + + return false; +} + +static handler *tse_create_handler(handlerton *hton, TABLE_SHARE *table, bool partitioned, MEM_ROOT *mem_root) { + if (partitioned) { + ha_tsepart *file = new (mem_root) ha_tsepart(hton, table); + if (file && (file->initialize() || file->init_partitioning(mem_root))) { + delete file; + return nullptr; + } + + return file; + } + + ha_tse *file = new (mem_root) ha_tse(hton, table); + if (file && file->initialize()) { + delete file; + return nullptr; + } + + return file; +} + +static bool tse_check_if_log_table(const char* db_name, const char* table_name) { + LEX_CSTRING cstr_db_name = {db_name, strlen(db_name)}; + LEX_CSTRING cstr_table_name = {table_name, strlen(table_name)}; + if (cstr_db_name.length == MYSQL_SCHEMA_NAME.length && !my_strcasecmp(system_charset_info, cstr_db_name.str, MYSQL_SCHEMA_NAME.str)) { + if (cstr_table_name.length == GENERAL_LOG_NAME.length && !my_strcasecmp(system_charset_info, cstr_table_name.str, GENERAL_LOG_NAME.str)) { + return true; + } + if (cstr_table_name.length == SLOW_LOG_NAME.length && !my_strcasecmp(system_charset_info, cstr_table_name.str, SLOW_LOG_NAME.str)) { + return true; + } + } + return false; +} + +/** + @brief Check if the given db.tablename is a system table for this SE. + + @param db Database name to check. + @param table_name table name to check. + @param is_sql_layer_system_table if the supplied db.table_name is a SQL + layer system table. + + @retval true Given db.table_name is supported system table. + @retval false Given db.table_name is not a supported system table. +*/ +static bool tse_is_supported_system_table(const char *db MY_ATTRIBUTE((unused)), + const char *table_name MY_ATTRIBUTE((unused)), + bool is_sql_layer_system_table MY_ATTRIBUTE((unused))) { + if (IS_METADATA_NORMALIZATION()) { + return true; + } + + return false; +} + +/** + @brief Forms a precise type from the < 4.1.2 format precise type plus the + charset-collation code. + @param old_prtype: the MySQL type code and the flags DATA_BINARY_TYPE etc. + @param charset_coll: MySQL charset-collation code + + @return precise type, including the charset-collation code. + */ +uint tse_dtype_form_prtype(uint old_prtype, uint charset_coll) { + return (old_prtype + (charset_coll << 16)); +} + +uint get_tse_type_from_mysql_dd_type(uint *unsigned_flag, uint *binary_type, uint *charset_no, + dd::enum_column_types dd_type, + const CHARSET_INFO *field_charset, + bool is_unsigned) { + *unsigned_flag = 0; + *binary_type = DATA_BINARY_TYPE; + *charset_no = 0; + + switch (dd_type) { + case dd::enum_column_types::ENUM: + case dd::enum_column_types::SET: + /* SQL-layer has its own unsigned flag set to zero, even though + internally this is an unsigned integer type. */ + *unsigned_flag = DATA_UNSIGNED; + /* ENUM and SET are handled as string types by SQL-layer, + hence the charset check. */ + if (field_charset != &my_charset_bin) *binary_type = 0; + return (DATA_INT); + case dd::enum_column_types::VAR_STRING: /* old <= 4.1 VARCHAR. */ + case dd::enum_column_types::VARCHAR: /* new >= 5.0.3 true VARCHAR. */ + *charset_no = field_charset->number; + if (field_charset == &my_charset_bin) { + return (DATA_BINARY); + } else { + *binary_type = 0; + if (field_charset == &my_charset_latin1) { + return (DATA_VARCHAR); + } else { + return (DATA_VARMYSQL); + } + } + case dd::enum_column_types::BIT: + /* MySQL always sets unsigned flag for both its BIT types. */ + *unsigned_flag = DATA_UNSIGNED; + *charset_no = my_charset_bin.number; + return (DATA_FIXBINARY); + case dd::enum_column_types::STRING: + *charset_no = field_charset->number; + if (field_charset == &my_charset_bin) { + return (DATA_FIXBINARY); + } else { + *binary_type = 0; + if (field_charset == &my_charset_latin1) { + return (DATA_CHAR); + } else { + return (DATA_MYSQL); + } + } + case dd::enum_column_types::DECIMAL: + case dd::enum_column_types::FLOAT: + case dd::enum_column_types::DOUBLE: + case dd::enum_column_types::NEWDECIMAL: + case dd::enum_column_types::LONG: + case dd::enum_column_types::LONGLONG: + case dd::enum_column_types::TINY: + case dd::enum_column_types::SHORT: + case dd::enum_column_types::INT24: + /* Types based on Field_num set unsigned flag from value stored + in the data-dictionary (YEAR being the exception). */ + if (is_unsigned) *unsigned_flag = DATA_UNSIGNED; + switch (dd_type) { + case dd::enum_column_types::DECIMAL: + return (DATA_DECIMAL); + case dd::enum_column_types::FLOAT: + return (DATA_FLOAT); + case dd::enum_column_types::DOUBLE: + return (DATA_DOUBLE); + case dd::enum_column_types::NEWDECIMAL: + *charset_no = my_charset_bin.number; + return (DATA_FIXBINARY); + default: + break; + } + return (DATA_INT); + case dd::enum_column_types::DATE: + case dd::enum_column_types::NEWDATE: + case dd::enum_column_types::TIME: + case dd::enum_column_types::DATETIME: + return (DATA_INT); + case dd::enum_column_types::YEAR: + case dd::enum_column_types::TIMESTAMP: + /* MySQL always sets unsigned flag for YEAR and old TIMESTAMP type. */ + *unsigned_flag = DATA_UNSIGNED; + return (DATA_INT); + case dd::enum_column_types::TIME2: + case dd::enum_column_types::DATETIME2: + case dd::enum_column_types::TIMESTAMP2: + *charset_no = my_charset_bin.number; + return (DATA_FIXBINARY); + case dd::enum_column_types::GEOMETRY: + /* Field_geom::binary() is always true. */ + return (DATA_GEOMETRY); + case dd::enum_column_types::TINY_BLOB: + case dd::enum_column_types::MEDIUM_BLOB: + case dd::enum_column_types::BLOB: + case dd::enum_column_types::LONG_BLOB: + *charset_no = field_charset->number; + if (field_charset != &my_charset_bin) *binary_type = 0; + return (DATA_BLOB); + case dd::enum_column_types::JSON: + /* JSON fields are stored as BLOBs. + Field_json::binary() always returns true even though data in + such columns are stored in UTF8. */ + *charset_no = my_charset_utf8mb4_bin.number; + return (DATA_BLOB); + case dd::enum_column_types::TYPE_NULL: + /* Compatibility with get_innobase_type_from_mysql_type(). */ + *charset_no = field_charset->number; + if (field_charset != &my_charset_bin) *binary_type = 0; + break; + default: + return -1; + } + return (0); +} + +void tse_dict_mem_fill_column_struct(dict_col *column, uint mtype, uint prtype, uint col_len) { + column->mtype = (unsigned int)mtype; + column->prtype = (unsigned int)prtype; + column->len = (unsigned int)col_len; +} + +/** Constructs fake dict_col describing column for foreign key type +compatibility check from column description in Ha_fk_column_type form. + + @note dict_col_t which is produced by this call is not valid for general purposes. + @param[out] col dict_col filled by this function + @param[in] fk_col_type foreign key type information +*/ +static void tse_fill_fake_column_struct( + dict_col *col, const Ha_fk_column_type *fk_col_type) { + uint unsigned_type; + uint binary_type; + uint charset_no; + + uint mtype = get_tse_type_from_mysql_dd_type(&unsigned_type, &binary_type, &charset_no, fk_col_type->type, + fk_col_type->field_charset, fk_col_type->is_unsigned); + + uint fake_prtype = tse_dtype_form_prtype(unsigned_type | binary_type, charset_no); + /* Fake prtype only contains info which is relevant for foreign key + type compatibility check, especially the info used in tse_cmp_cols_are_equal. */ + + uint col_len = calc_pack_length(fk_col_type->type, fk_col_type->char_length, fk_col_type->elements_count, + true, fk_col_type->numeric_scale, fk_col_type->is_unsigned); + + memset(col, 0, sizeof(dict_col)); + tse_dict_mem_fill_column_struct(col, mtype, fake_prtype, col_len); +} + +/** Checks if a data main type is a string type. Also a BLOB is considered a + string type. + @return true if string type */ +bool tse_dtype_is_string_type(uint mtype) { + if (mtype <= DATA_BLOB || mtype == DATA_MYSQL || mtype == DATA_VARMYSQL) { + return (true); + } + + return (false); +} + +/** Checks if a type is a binary string type. Note that for tables created with + < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For + those DATA_BLOB columns this function currently returns FALSE. + @param mtype main data type + @param prtype precise type + @return true if binary string type +*/ +bool tse_dtype_is_binary_string_type(uint mtype, uint prtype) { + if ((mtype == DATA_FIXBINARY) || (mtype == DATA_BINARY) || + (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) { + return (true); + } + + return (false); +} + +/** Checks if a type is a non-binary string type. That is, dtype_is_string_type + is TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created + with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. + For those DATA_BLOB columns this function currently returns TRUE. + @param mtype main data type + @param prtype precise type + @return true if non-binary string type + */ +bool tse_dtype_is_non_binary_string_type(uint mtype, uint prtype) { + if (tse_dtype_is_string_type(mtype) == true && + tse_dtype_is_binary_string_type(mtype, prtype) == false) { + return (true); + } + + return (false); +} + +/** Gets the MySQL charset-collation code for MySQL string types. + @return MySQL charset-collation code */ +static inline uint tse_dtype_get_charset_coll(uint prtype) { + return ((prtype >> 16) & CHAR_COLL_MASK); +} + +bool tse_cmp_cols_are_equal(const dict_col *col1, const dict_col *col2, + bool check_charsets) { + if (tse_dtype_is_non_binary_string_type(col1->mtype, col1->prtype) && + tse_dtype_is_non_binary_string_type(col2->mtype, col2->prtype)) { + /* Both are non-binary string types: they can be compared if + and only if the charset-collation is the same */ + + if (check_charsets) { + return (tse_dtype_get_charset_coll(col1->prtype) == + tse_dtype_get_charset_coll(col2->prtype)); + } else { + return (true); + } + } + + if (tse_dtype_is_binary_string_type(col1->mtype, col1->prtype) && + tse_dtype_is_binary_string_type(col2->mtype, col2->prtype)) { + /* Both are binary string types: they can be compared */ + return (true); + } + + if (col1->mtype != col2->mtype) { + return (false); + } + + if (col1->mtype == DATA_INT && + (col1->prtype & DATA_UNSIGNED) != (col2->prtype & DATA_UNSIGNED)) { + /* The storage format of an unsigned integer is different + from a signed integer: in a signed integer we OR + 0x8000... to the value of positive integers. */ + return (false); + } + return (col1->mtype != DATA_INT || col1->len == col2->len); +} + + +/** Check if types of child and parent columns in foreign key are compatible. + @param[in] check_charsets Indicates whether we need to check that charsets of string columns + match. Which is true in most cases. + @return True if types are compatible, False if not. +*/ +static bool tse_check_fk_column_compat(const Ha_fk_column_type *child_column_type, + const Ha_fk_column_type *parent_column_type, bool check_charsets) { + dict_col dict_child_col, dict_parent_col; + + tse_fill_fake_column_struct(&dict_child_col, child_column_type); + tse_fill_fake_column_struct(&dict_parent_col, parent_column_type); + + return (tse_cmp_cols_are_equal(&dict_child_col, &dict_parent_col, check_charsets)); +} + +/* + Return a session context for current thread. + Initialize one if session context is not exists. + A session context is one-to-one mapping of thread. +*/ +thd_sess_ctx_s *get_or_init_sess_ctx(handlerton *hton, THD *thd) { + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + if (sess_ctx == nullptr) { + sess_ctx = (thd_sess_ctx_s *)my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(thd_sess_ctx_s), MYF(MY_WME)); + if (sess_ctx == nullptr) { + return nullptr; + } + + memset(sess_ctx, 0xFF, sizeof(thd_sess_ctx_s)); + sess_ctx->is_tse_trx_begin = 0; + sess_ctx->sql_stat_start = 0; + sess_ctx->cursors_map = new unordered_map; + sess_ctx->invalid_cursors = nullptr; + assert(sess_ctx->cursors_map->size() == 0); + sess_ctx->msg_buf = nullptr; + thd_set_ha_data(thd, hton, sess_ctx); + } + return sess_ctx; +} + +/* + Called by handlerton functions to get a new tianchi handler. + This tianchi handler will be only use for one time and initialized with session context. + Handlerton functions need it since they don't have m_tch member. +*/ +int get_tch_in_handler_data(handlerton *hton, THD *thd, tianchi_handler_t &tch, bool alloc_msg_buf) { + memset(&tch, 0, sizeof(tch)); + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(hton, thd); + if (sess_ctx == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (sess_ctx->thd_id != thd->thread_id()) { + sess_ctx->sess_addr = INVALID_VALUE64; + sess_ctx->thd_id = thd->thread_id(); + sess_ctx->bind_core = 0; + sess_ctx->is_tse_trx_begin = 0; + sess_ctx->sql_stat_start = 0; + } + + tch.inst_id = tse_instance_id; + tch.ctx_addr = INVALID_VALUE64; + tch.sess_addr = sess_ctx->sess_addr; + tch.thd_id = sess_ctx->thd_id; + tch.bind_core = sess_ctx->bind_core; + tch.sql_command = (uint8_t)thd->lex->sql_command; + tch.query_id = thd->query_id; + tch.sql_stat_start = sess_ctx->sql_stat_start; + tch.pre_sess_addr = 0; +#ifndef WITH_DAAC + tch.msg_buf = sess_ctx->msg_buf; + + if (sess_ctx->msg_buf == nullptr && alloc_msg_buf) { + void *shm_inst = get_one_shm_inst(&tch); + sess_ctx->msg_buf = (void*)shm_alloc((shm_seg_s *)shm_inst, sizeof(dsw_message_block_t)); + sem_init(&(((dsw_message_block_t*)(sess_ctx->msg_buf))->head.sem), 1, 0); + tch.msg_buf = sess_ctx->msg_buf; + } +#endif + return 0; +} + +static void ctc_copy_cursors_to_free(thd_sess_ctx_s *sess_ctx, uint64_t *cursors, uint32_t left) { + uint32_t idx = 0; + if (sess_ctx->invalid_cursors) { + uint32_t invalid_csize = sess_ctx->invalid_cursors->size(); + memcpy(cursors, &(*sess_ctx->invalid_cursors)[0], invalid_csize * sizeof(uint64_t)); + sess_ctx->invalid_cursors->clear(); + idx = invalid_csize; + } + if (left == 0) { + unordered_map::iterator it; + for (it = sess_ctx->cursors_map->begin(); it != sess_ctx->cursors_map->end(); it++) { + cursors[idx++] = it->second; + } + sess_ctx->cursors_map->clear(); + } +} + +void update_sess_ctx_cursor_by_tch(tianchi_handler_t &tch, handlerton *hton, THD *thd) { + if (tch.cursor_addr == INVALID_VALUE64) { + return; + } + + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + assert(sess_ctx != nullptr); + unordered_map::iterator it; + it = sess_ctx->cursors_map->find(&tch); + if (it != sess_ctx->cursors_map->end()) { + uint64_t current_cursor = it->second; + if (current_cursor == tch.cursor_addr) { + return; + } + if (sess_ctx->invalid_cursors == nullptr) { + sess_ctx->invalid_cursors = new vector; + } + sess_ctx->invalid_cursors->push_back(current_cursor); + } + (*sess_ctx->cursors_map)[&tch] = tch.cursor_addr; + + if (sess_ctx->invalid_cursors == nullptr) { + return; + } + int32_t total_csize = sess_ctx->cursors_map->size() + sess_ctx->invalid_cursors->size(); + if (total_csize >= SESSION_CURSOR_NUM) { + uint32_t free_csize = sess_ctx->invalid_cursors->size(); + uint64_t *cursors = (uint64_t *)tse_alloc_buf(&tch, sizeof(uint64_t) * free_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 1); + assert(sess_ctx->invalid_cursors->empty()); + tse_log_system("[FREE CURSORS] free %d cursors in advance.", free_csize); + tse_free_session_cursors(&tch, cursors, free_csize); + tse_free_buf(&tch, (uint8_t *)cursors); + } +} + +/* + Since session address and sql_stat_start may be changed in tch after processing in cantian, + call this method if session address or sql_stat_start may be updated in tch. +*/ +void update_sess_ctx_by_tch(tianchi_handler_t &tch, handlerton *hton, THD *thd) { + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(hton, thd); + if (sess_ctx == nullptr) { + tse_log_error("update_sess_ctx_by_tch failed, thd_sess_ctx_s my_malloc error!"); + return; + } + + sess_ctx->thd_id = tch.thd_id; + sess_ctx->sess_addr = tch.sess_addr; + sess_ctx->bind_core = tch.bind_core; + sess_ctx->sql_stat_start = tch.sql_stat_start; +} + +/* + 1. Make sure that session address is invalid everytime thd's been updated. + 2. Call this method if the following tse interface may be the + first call of a dml sql (may use sql_stat_start). +*/ +void update_member_tch(tianchi_handler_t &tch, handlerton *hton, THD *thd, bool alloc_msg_buf) { + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + if (sess_ctx == nullptr || sess_ctx->thd_id != thd->thread_id()) { + tch.thd_id = thd->thread_id(); + tch.sess_addr = INVALID_VALUE64; + tch.bind_core = 0; + tch.sql_command = (uint8_t)thd->lex->sql_command; + tch.query_id = thd->query_id; + tch.sql_stat_start = 0; + tch.cursor_ref = 0; + tch.pre_sess_addr = 0; + tch.msg_buf = nullptr; + return; + } + + tch.cursor_addr = (tch.sess_addr == sess_ctx->sess_addr) ? tch.cursor_addr : INVALID_VALUE64; + tch.sess_addr = sess_ctx->sess_addr; + tch.thd_id = sess_ctx->thd_id; + tch.bind_core = sess_ctx->bind_core; + tch.sql_command = (uint8_t)thd->lex->sql_command; + tch.query_id = thd->query_id; + tch.sql_stat_start = sess_ctx->sql_stat_start; + tch.pre_sess_addr = 0; +#ifndef WITH_DAAC + tch.msg_buf = sess_ctx->msg_buf; + + if (sess_ctx->msg_buf == nullptr && alloc_msg_buf) { + void *shm_inst = get_one_shm_inst(&tch); + sess_ctx->msg_buf = (void*)shm_alloc((shm_seg_s *)shm_inst, sizeof(dsw_message_block_t)); + sem_init(&(((dsw_message_block_t*)(sess_ctx->msg_buf))->head.sem), 1, 0); + tch.msg_buf = sess_ctx->msg_buf; + } +#endif +#ifdef METADATA_NORMALIZED + if (thd->is_reading_dd) { + tch.sql_stat_start = 1; + } +#endif +} + +// called in disconnect when current thd is no longer used +void release_sess_ctx(thd_sess_ctx_s *sess_ctx, handlerton *hton, THD *thd) { + assert(sess_ctx); + delete sess_ctx->cursors_map; + sess_ctx->cursors_map = nullptr; + if (sess_ctx->invalid_cursors) { + delete sess_ctx->invalid_cursors; + sess_ctx->invalid_cursors = nullptr; + } +#ifndef WITH_DAAC + if (sess_ctx->msg_buf != nullptr) { + sem_destroy(&(((dsw_message_block_t*)(sess_ctx->msg_buf))->head.sem)); + shm_free(nullptr, sess_ctx->msg_buf); + sess_ctx->msg_buf = nullptr; + } +#endif + my_free(sess_ctx); + thd_set_ha_data(thd, hton, nullptr); +} + +/** Creates an TSE transaction struct for the thd if it does not yet have + one. Starts a new TSE transaction if a transaction is not yet started. And + assigns a new snapshot for a consistent read if the transaction does not yet + have one. + @return 0 */ +static int tse_start_trx_and_assign_scn( + handlerton *hton, /*!< in: TSE handlerton */ + THD *thd) /*!< in: MySQL thread handle of the user for + whom the transaction should be committed */ +{ + DBUG_TRACE; + + if (engine_ddl_passthru(thd) && is_alter_table_copy(thd)) { + return 0; + } + + /* Assign a read view if the transaction does not have it yet. + Do this only if transaction is using REPEATABLE READ isolation + level. */ + enum_tx_isolation mysql_isolation = thd_get_trx_isolation(thd); + if (mysql_isolation != ISO_REPEATABLE_READ) { + push_warning_printf(thd, Sql_condition::SL_WARNING, HA_ERR_UNSUPPORTED, + "CTC: WITH CONSISTENT SNAPSHOT" + " was ignored because this phrase" + " can only be used with" + " REPEATABLE READ isolation level."); + return 0; + } + + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(tse_hton, thd); + // get_tch_in_handler_data若成功返回,则sess_ctx肯定不为空 + assert(sess_ctx != nullptr); + assert(sess_ctx->is_tse_trx_begin == 0); + + uint32_t autocommit = !thd->in_multi_stmt_transaction_mode(); + int isolation_level = isolation_level_to_cantian(mysql_isolation); + uint32_t lock_wait_timeout = THDVAR(thd, lock_wait_timeout); + tianchi_trx_context_t trx_context = {isolation_level, autocommit, lock_wait_timeout, false}; + bool is_mysql_local = user_var_set(thd, "ctc_ddl_local_enabled"); + ct_errno_t ret = (ct_errno_t)tse_trx_begin(&tch, trx_context, is_mysql_local); + if (ret != CT_SUCCESS) { + tse_log_error("start trx failed with error code: %d", ret); + return convert_tse_error_code_to_mysql(ret); + } + update_sess_ctx_by_tch(tch, hton, thd); + sess_ctx->is_tse_trx_begin = 1; + trans_register_ha(thd, !autocommit, hton, nullptr); + return 0; +} + +template +static typename std::enable_if::type + invalidate_remote_dd(T *thd, tianchi_handler_t *tch) +{ + tse_invalidate_broadcast_request req; + req.mysql_inst_id = tse_instance_id; + req.buff_len = 0; + req.is_dcl = false; + invalidate_obj_entry_t *obj = NULL; + + for (auto invalidate_it : thd->invalidates()) { + switch (invalidate_it.second) { + case T::OBJ_ABSTRACT_TABLE: + case T::OBJ_EVENT: + case T::OBJ_COLUMN_STATISTICS: + case T::OBJ_RT_PROCEDURE: + case T::OBJ_RT_FUNCTION: + obj = (invalidate_obj_entry_t *)((char *)req.buff + req.buff_len); + obj->type = invalidate_it.second; + strncpy(obj->first, invalidate_it.first.first.c_str(), SMALL_RECORD_SIZE - 1); + strncpy(obj->second, invalidate_it.first.second.c_str(), SMALL_RECORD_SIZE - 1); + req.buff_len += sizeof(invalidate_obj_entry_t); + printf("\n\n----------------------------------------------\n"); + printf("invalidate %d, %s, %s", invalidate_it.second, invalidate_it.first.first.c_str(), invalidate_it.first.second.c_str()); + printf("\n----------------------------------------------\n\n"); + break; + case T::OBJ_SCHEMA: + case T::OBJ_TABLESPACE: + case T::OBJ_RESOURCE_GROUP: + case T::OBJ_SPATIAL_REFERENCE_SYSTEM: + obj = (invalidate_obj_entry_t *)((char *)req.buff + req.buff_len); + obj->type = invalidate_it.second; + strncpy(obj->first, invalidate_it.first.first.c_str(), SMALL_RECORD_SIZE - 1); + strncpy(obj->second, "", SMALL_RECORD_SIZE - 1); + req.buff_len += sizeof(invalidate_obj_entry_t); + printf("\n\n----------------------------------------------\n"); + printf("invalidate %d, %s, %s", invalidate_it.second, invalidate_it.first.first.c_str(), invalidate_it.first.second.c_str()); + printf("\n----------------------------------------------\n\n"); + break; + case T::OBJ_CHARSET: + case T::OBJ_COLLATION: + printf("\n\n----------------------------------------------\n"); + printf("invalidate %d, %s, %s", invalidate_it.second, invalidate_it.first.first.c_str(), invalidate_it.first.second.c_str()); + printf("\n----------------------------------------------\n\n"); + break; + default: + break; + } + } + (void)tse_broadcast_mysql_dd_invalidate(tch, &req); +} + +template +static typename std::enable_if::type + invalidate_remote_dd(T *thd MY_ATTRIBUTE((unused)), tianchi_handler_t *tch MY_ATTRIBUTE((unused))) { + // do nothing +} + +bool invalidate_remote_dcl_cache(tianchi_handler_t *tch) +{ + tse_invalidate_broadcast_request req; + req.mysql_inst_id = tse_instance_id; + req.buff_len = 0; + req.is_dcl = true; + bool result = tse_broadcast_mysql_dd_invalidate(tch, &req); + return result; +} + +static void tse_register_trx(handlerton *hton, THD *thd) { + trans_register_ha(thd, false, hton, nullptr); + if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + trans_register_ha(thd, true, hton, nullptr); + } +} + +// 利用SFINAE特性,控制是否调用thd->is_empty() +template +static typename std::enable_if::type + commit_preprocess(T* thd, tianchi_handler_t *tch) { + if (is_work_flow() && !thd->is_empty()) { + (void)invalidate_remote_dd(thd, tch); + thd->clear(); + } +} + +template +static typename std::enable_if::type + commit_preprocess(T* thd MY_ATTRIBUTE((unused)), tianchi_handler_t *tch MY_ATTRIBUTE((unused))) { + // no action here +} + +template +static typename std::enable_if::type +attachable_trx_update_pre_addr(T *tse_hton, THD *thd, tianchi_handler_t *tch, bool set_to_pre_addr) { + if (thd->is_attachable_transaction_active() && (thd->tx_isolation == ISO_READ_UNCOMMITTED) + && (tse_hton->pre_sess_addr != 0) && thd->query_plan.get_command() == SQLCOM_RENAME_TABLE) { + tch->pre_sess_addr = set_to_pre_addr ? tse_hton->pre_sess_addr : 0; + } +} + +template +static typename std::enable_if::type +attachable_trx_update_pre_addr(T *tse_hton MY_ATTRIBUTE((unused)), THD *thd MY_ATTRIBUTE((unused)), + tianchi_handler_t *tch MY_ATTRIBUTE((unused)), bool set_to_pre_addr MY_ATTRIBUTE((unused))) { +} + +static void tse_free_cursors_no_autocommit(THD *thd, tianchi_handler_t *tch, thd_sess_ctx_s *sess_ctx) { + if (!thd->in_multi_stmt_transaction_mode()) { + return; + } + + int32_t total_csize = sess_ctx->cursors_map->size(); + if (sess_ctx->invalid_cursors != nullptr) { + total_csize += sess_ctx->invalid_cursors->size(); + } + + if (total_csize <= ctc_max_cursors_no_autocommit) { + return; + } + + uint64_t *cursors = (uint64_t *)tse_alloc_buf(tch, sizeof(uint64_t) * total_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 0); + tse_free_session_cursors(tch, cursors, total_csize); + tse_free_buf(tch, (uint8_t *)cursors); +} + +/** + Commits a transaction in an tse database or marks an SQL statement ended. + @param: hton in, tse handlerton + @param: thd in, MySQL thread handle of the user for whom the transaction + should be committed + @param: commit_trx in, true - commit transaction false - the current SQL + statement ended + @return 0 or deadlock error if the transaction was aborted by another + higher priority transaction. +*/ +static int tse_commit(handlerton *hton, THD *thd, bool commit_trx) { + DBUG_TRACE; + + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd) || is_lock_table(thd))) { + return 0; + } + + tianchi_handler_t tch; + bool is_ddl_commit = false; + bool will_commit = commit_trx || (!thd->in_multi_stmt_transaction_mode()); + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch, will_commit)); + ct_errno_t ret = CT_SUCCESS; + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + assert(sess_ctx != nullptr); + + if (will_commit) { + commit_preprocess(thd, &tch); + attachable_trx_update_pre_addr(tse_hton, thd, &tch, true); + + int32_t total_csize = sess_ctx->cursors_map->size(); + if (sess_ctx->invalid_cursors != nullptr) { + total_csize += sess_ctx->invalid_cursors->size(); + } + uint64_t *cursors = (uint64_t *)tse_alloc_buf(&tch, sizeof(uint64_t) * total_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 0); + ret = (ct_errno_t)tse_trx_commit(&tch, cursors, total_csize, &is_ddl_commit); + tse_free_buf(&tch, (uint8_t *)cursors); + if (ret != CT_SUCCESS) { + tse_log_error("commit atomic ddl failed with error code: %d", ret); + return convert_tse_error_code_to_mysql(ret); + } + if (is_ddl_commit) { + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + string sql = string(thd->query().str).substr(0, thd->query().length); + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, tse_instance_id, thd->lex->sql_command); + if (thd->db().str != NULL && thd->db().length > 0) { + strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + } + broadcast_req.options &= (~TSE_NOT_NEED_CANTIAN_EXECUTE); + ret = (ct_errno_t)tse_execute_mysql_ddl_sql(&tch, &broadcast_req, false); + DBUG_EXECUTE_IF("core_after_ddl_cantian_commit_broadcast", { assert(0); }); + tse_log_system("[TSE_BROARDCAST_ATOMIC_DDL]:ret:%d, query:%s, user_name:%s, err_code:%d, broadcast_inst_id:%u, " + "conn_id:%u, tse_inst_id:%u", ret, broadcast_req.sql_str, broadcast_req.user_name, + broadcast_req.err_code, broadcast_req.mysql_inst_id, tch.thd_id, tch.inst_id); + assert (ret == CT_SUCCESS); + } + sess_ctx->is_tse_trx_begin = 0; + } else { + tse_free_cursors_no_autocommit(thd, &tch, sess_ctx); + } + + if (!commit_trx) { + sess_ctx->sql_stat_start = 1; // indicate cantian for a new sql border + tch.sql_stat_start = 1; + } + return 0; +} + +/** + Rollback a transaction in an tse database or marks an SQL statement ended. + @param: hton in, tse handlerton + @param: thd in, handle to the MySQL thread of the user whose transaction + should be rolled back be committed + @param: commit_trx in, TRUE - rollback entire transaction FALSE - rollback the + current statement only statement ended + @return 0 or deadlock error if the transaction was aborted by another + higher priority transaction. + @note: +*/ +static int tse_rollback(handlerton *hton, THD *thd, bool rollback_trx) { + DBUG_TRACE; + + if (thd->lex->sql_command == SQLCOM_DROP_TABLE) { + tse_log_error("[CTC_TRX]:rollback when drop table, rollback_trx=%d", rollback_trx); + } + + bool will_rollback = rollback_trx || !thd->in_multi_stmt_transaction_mode(); + ct_errno_t ret = CT_SUCCESS; + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + assert(sess_ctx != nullptr); + + if (will_rollback) { + int32_t total_csize = sess_ctx->cursors_map->size(); + if (sess_ctx->invalid_cursors != nullptr) { + total_csize += sess_ctx->invalid_cursors->size(); + } + uint64_t *cursors = (uint64_t *)tse_alloc_buf(&tch, sizeof(uint64_t) * total_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 0); + ret = (ct_errno_t)tse_trx_rollback(&tch, cursors, total_csize); + + if (ret != CT_SUCCESS) { + tse_free_buf(&tch, (uint8_t *)cursors); + tse_log_error("rollback trx failed with error code: %d", ret); + return convert_tse_error_code_to_mysql(ret); + } + tse_free_buf(&tch, (uint8_t *)cursors); + sess_ctx->is_tse_trx_begin = 0; + } else if (sess_ctx->sql_stat_start == 0) { + int32_t total_csize = sess_ctx->cursors_map->size(); + if (sess_ctx->invalid_cursors != nullptr) { + total_csize += sess_ctx->invalid_cursors->size(); + } + uint64_t *cursors = (uint64_t *)tse_alloc_buf(&tch, sizeof(uint64_t) * total_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 0); + (void)tse_srv_rollback_savepoint(&tch, cursors, total_csize, TSE_SQL_START_INTERNAL_SAVEPOINT); + tse_free_buf(&tch, (uint8_t *)cursors); + } else { + tse_free_cursors_no_autocommit(thd, &tch, sess_ctx); + } + + if (!rollback_trx) { + sess_ctx->sql_stat_start = 1; // indicate cantian for a new sql border + tch.sql_stat_start = 1; + } + + return 0; +} + +static int tse_close_connect(handlerton *hton, THD *thd) { + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + + if (thd->is_attachable_transaction_active() || is_initialize() || is_ctc_mdl_thd(thd)) { + tch.is_broadcast = false; + } else { + tch.is_broadcast = true; + } + + int ret = tse_close_session(&tch); + release_sess_ctx(sess_ctx, hton, thd); + return convert_tse_error_code_to_mysql((ct_errno_t)ret); +} + +static void tse_kill_connection(handlerton *hton, THD *thd) { + tianchi_handler_t tch; + int ret = get_tch_in_handler_data(hton, thd, tch); + assert(ret == 0); + if (tch.sess_addr == INVALID_VALUE64) { + tse_log_system("[TSE_KILL_SESSION]:trying to kill a thd without session assigned, conn_id=%u, instid=%u", + tch.thd_id, tch.inst_id); + return; + } + + if (is_ddl_sql_cmd(thd->lex->sql_command)) { + return; + } + + tse_kill_session(&tch); + tse_log_system("[TSE_KILL_SESSION]:conn_id:%u, tse_instance_id:%u", tch.thd_id, tch.inst_id); +} + +static int tse_pre_create_db4cantian(THD *thd, tianchi_handler_t *tch) { + char user_name[SMALL_RECORD_SIZE]; + tse_copy_name(user_name, thd->lex->name.str, SMALL_RECORD_SIZE); + int error_code = 0; + char error_message[ERROR_MESSAGE_LEN] = {0}; + + tse_log_system("[TSE_INIT]:tse_pre_create_db4cantian begin"); + DBUG_EXECUTE_IF("core_before_create_tablespace_and_db", { assert(0); }); // 有锁的问题 + string sql = string(thd->query().str).substr(0, thd->query().length); + + tse_db_infos_t db_infos; + db_infos.name = user_name; + db_infos.datafile_size = tse_db_datafile_size; + db_infos.datafile_autoextend = tse_db_datafile_autoextend; + db_infos.datafile_extend_size = tse_db_datafile_extend_size; + int ret = tse_pre_create_db(tch, sql.c_str(), &db_infos, &error_code, error_message); + + DBUG_EXECUTE_IF("core_after_create_tablespace_and_db", { assert(0); }); // 元数据不一致的问题 + + tse_log_system("[TSE_PRE_CREATE_DB]:ret:%d, database:%s, error_code:%d, error_message:%s, conn_id:%u, tse_instance_id:%u", + ret, thd->lex->name.str, error_code, error_message, tch->thd_id, tch->inst_id); + + if (ret != CT_SUCCESS) { + /* 如果参天上报tablespace或user已存在,且创库命令包含if not exists关键字,则忽略此错误 */ + if (error_code == ERR_USER_NOT_EMPTY_4MYSQL) { + if (thd->lex->create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) { + return CT_SUCCESS; + } + my_printf_error(ER_DB_CREATE_EXISTS, "Can't create database '%s'; database exists", MYF(0), thd->lex->name.str); + return ER_DB_CREATE_EXISTS; + } + + if (error_code != 0) { + my_error(ER_CANT_CREATE_DB, MYF(0), thd->lex->name.str, error_code, error_message); + } + } + tse_log_system("[TSE_INIT]:tse_pre_create_db4cantian end, ret=%d", ret); + return ret; +} + +static void tse_lock_table_handle_error(int err_code, tse_lock_table_info *lock_info, tianchi_handler_t &tch, THD *thd) { + DBUG_EXECUTE_IF("tse_lock_table_fail_DDL_LOCKED", { err_code = ERR_USER_DDL_LOCKED; }); + DBUG_EXECUTE_IF("tse_lock_table_fail_VERSION_NOT_MATCH", { err_code = TSE_DDL_VERSION_NOT_MATCH; }); + DBUG_EXECUTE_IF("tse_lock_table_fail_DISALLOW_OPERATION", { err_code = ER_DISALLOWED_OPERATION; }); + + switch (err_code) { + case ERR_USER_DDL_LOCKED: + my_printf_error(ER_DISALLOWED_OPERATION, "Instance has been locked, disallow this operation", MYF(0)); + tse_log_system("[TSE_MDL_LOCK]: Instance has been locked, disallow this operation," + "lock_info=(%s, %s), sql=%s, conn_id=%u, tse_instance_id=%u", + lock_info->db_name, lock_info->table_name, thd->query().str, tch.thd_id, tch.inst_id); + break; + + case TSE_DDL_VERSION_NOT_MATCH: + my_printf_error(ER_DISALLOWED_OPERATION, "Version not match. Please make sure cluster on the same version.", MYF(0)); + tse_log_system("[TSE_MDL_LOCK]: Version not match,lock_info=(%s, %s), sql=%s", lock_info->db_name, lock_info->table_name, thd->query().str); + break; + + default: + my_printf_error(err_code, "The table or database is being used. Please try again later.", MYF(0)); + tse_log_error("[TSE_MDL_LOCK]: Lock failed, err=%d, lock_info=(%s, %s), sql=%s, conn_id=%u, tse_instance_id=%u", + err_code, lock_info->db_name, lock_info->table_name, thd->query().str, tch.thd_id, tch.inst_id); + break; + } + + return; +} + +static int tse_notify_pre_event(THD *thd, handlerton *tse_hton, tianchi_handler_t &tch, tse_lock_table_info *lock_info) { + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(tse_hton, thd); + assert(sess_ctx != nullptr); + + int ret = 0; + int err_code = 0; + const char *cur_db_name = TSE_GET_THD_DB_NAME(thd); + enum_sql_command sql_command = thd->lex->sql_command; + if (sql_command == SQLCOM_CREATE_DB || sql_command == SQLCOM_DROP_DB || sql_command == SQLCOM_ALTER_DB) { + cur_db_name = nullptr; + } + + if (is_work_flow()) { + ret = tse_lock_table(&tch, cur_db_name, lock_info, &err_code); + + DBUG_EXECUTE_IF("tse_lock_table_fail", { ret = -1; }); + if (ret != 0) { + tse_lock_table_handle_error(err_code, lock_info, tch, thd); + return ret; + } + } + + switch (sql_command) { + case SQLCOM_CREATE_DB:{ + ret = tse_pre_create_db4cantian(thd, &tch); + break; + } + case SQLCOM_DROP_DB:{ + char err_msg[ERROR_MESSAGE_LEN] = {0}; + ret = tse_drop_db_pre_check(&tch, lock_info->db_name, &err_code, err_msg); + if (ret != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "Can't drop database '%s' (errno: %d - %s)", MYF(0), + lock_info->db_name, err_code, err_msg); + } + break; + } + default: + break; + } + return ret; +} + +static int tse_notify_post_event(THD *thd, handlerton *tse_hton, tianchi_handler_t &tch, tse_lock_table_info *lock_info) { + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(tse_hton, thd); + assert(sess_ctx != nullptr); + + DBUG_EXECUTE_IF("core_before_tse_unlock_table", { assert(0); }); // 解锁前core + + int ret = 0; + if (is_work_flow()) { + if ((MDL_key::enum_mdl_namespace)lock_info->mdl_namespace == MDL_key::ACL_CACHE) { + invalidate_remote_dcl_cache(&tch); + tse_log_system("[CTC_ACL_CACHE]:invalidate dcl cache."); + + if (thd->is_error()) { + tse_log_system("TSE_POST_EVENT]: no need to record sql str since thd has an error."); + return ret; + } + if (is_dcl_sql_cmd(thd->lex->sql_command) && ctc_record_sql(thd, true)) { + tse_log_error("[TSE_POST_EVENT]:record dcl sql str failed. sql:%s", thd->query().str); + } + + return ret; + } + + tse_log_system("[UNLOCK_TABLE]: tse_unlock_table lock_info=(%s, %s), sql=%s", lock_info->db_name, lock_info->table_name, thd->query().str); + ret = tse_unlock_table(&tch, tse_instance_id, lock_info); + + if (ret != 0) { + tse_log_error("[TSE_MDL_LOCK]: unlock failed, ret: %d, sql: %s, conn_id: %u, tse_instance_id: %u", + ret, thd->query().str, tch.thd_id, tch.inst_id); + } + } + return ret; +} + +/** + Notify/get permission from interested storage engines before acquiring + exclusive lock for the key. + + The returned argument 'victimized' specify reason for lock + not granted. If 'true', lock was refused in an attempt to + resolve a possible MDL->GSL deadlock. Locking may then be retried. + + @return False if notification was successful and it is OK to acquire lock, + True if one of SEs asks to abort lock acquisition. +*/ +static bool tse_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key, + ha_notification_type notification_type, + bool *victimized MY_ATTRIBUTE((unused))) { + if (is_ctc_mdl_thd(thd) || (notification_type == HA_NOTIFY_PRE_EVENT && + mdl_key->mdl_namespace() == MDL_key::ACL_CACHE)) { + return false; + } + /* + we can not check sql length while using prepare statement, + so we need to check the sql length before ddl sql again + */ + if (!IS_METADATA_NORMALIZATION() && thd->query().str && tse_check_ddl_sql_length(thd->query().str)) { + return true; + } + + if (engine_ddl_passthru(thd)) { + return false; + } + + if (!IS_METADATA_NORMALIZATION()) { + if (!ddl_enabled_normal(thd)) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "DDL not allowed in this mode, Please check the value of @@ctc_concurrent_ddl."); + return true; + } + + if (thd->lex->query_tables == nullptr && mdl_key->mdl_namespace() != MDL_key::SCHEMA) { + return false; + } + + if (mysql_system_db.find(mdl_key->db_name()) != mysql_system_db.end()) { + return false; + } + } + + int ret = 0; + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(tse_hton, thd, tch)); + + tse_lock_table_info lock_info = {{0}, {0}, {0}, {0}, thd->lex->sql_command, (int32_t)mdl_key->mdl_namespace()}; + FILL_USER_INFO_WITH_THD(lock_info, thd); + strncpy(lock_info.db_name, mdl_key->db_name(), SMALL_RECORD_SIZE); + strncpy(lock_info.table_name, mdl_key->name(), SMALL_RECORD_SIZE); + + if (notification_type == HA_NOTIFY_PRE_EVENT) { + ret = tse_notify_pre_event(thd, tse_hton, tch, &lock_info); + update_sess_ctx_by_tch(tch, tse_hton, thd); + } else { + ret = tse_notify_post_event(thd, tse_hton, tch, &lock_info); + } + + if (ret != 0) { + tse_unlock_table(&tch, tse_instance_id, &lock_info); + return true; + } + + return false; +} + +static const unsigned int MAX_SAVEPOINT_NAME_LEN = 64; +static const int BASE36 = 36; // 0~9 and a~z, total 36 encoded character + +/** + Sets a transaction savepoint. + @param: hton in, tse handlerton + @param: thd in, handle to the MySQL thread + @param: savepoint in, savepoint data + @return: 0 if succeeds +*/ +static int tse_set_savepoint(handlerton *hton, THD *thd, void *savepoint) { + DBUG_TRACE; + + char name[MAX_SAVEPOINT_NAME_LEN]; + longlong2str((unsigned long long)savepoint, name, BASE36); + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + if (!strcmp(name, TSE_SQL_START_INTERNAL_SAVEPOINT)) { + my_error(ER_DISALLOWED_OPERATION, MYF(0), "this savepoint has been used by sys db!"); + return ER_DISALLOWED_OPERATION; + } + ct_errno_t ret = (ct_errno_t)tse_srv_set_savepoint(&tch, name); + if (ret != CT_SUCCESS) { + tse_log_error("set trx savepoint failed with error code: %d", ret); + } + return convert_tse_error_code_to_mysql(ret); +} + +/** + Rollback to a transaction savepoint. + @param: hton in, tse handlerton + @param: thd in, handle to the MySQL thread + @param: savepoint in, savepoint data + @return: 0 if succeeds +*/ +static int tse_rollback_savepoint(handlerton *hton, THD *thd, void *savepoint) { + DBUG_TRACE; + + char name[MAX_SAVEPOINT_NAME_LEN]; + longlong2str((unsigned long long)savepoint, name, BASE36); + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); + assert(sess_ctx != nullptr); + int32_t total_csize = sess_ctx->cursors_map->size(); + if (sess_ctx->invalid_cursors != nullptr) { + total_csize += sess_ctx->invalid_cursors->size(); + } + uint64_t *cursors = (uint64_t *)tse_alloc_buf(&tch, sizeof(uint64_t) * total_csize); + assert((total_csize == 0) ^ (cursors != nullptr)); + ctc_copy_cursors_to_free(sess_ctx, cursors, 0); + ct_errno_t ret = (ct_errno_t)tse_srv_rollback_savepoint(&tch, cursors, total_csize, name); + tse_free_buf(&tch, (uint8_t *)cursors); + if (ret != CT_SUCCESS) { + tse_log_error("rollback to trx savepoint failed with error code: %d", ret); + } + return convert_tse_error_code_to_mysql(ret); +} + +/** + Release a transaction savepoint. + @param: hton in, tse handlerton + @param: thd in, handle to the MySQL thread + @param: savepoint in, savepoint data + @return: 0 if succeeds +*/ +static int tse_release_savepoint(handlerton *hton, THD *thd, void *savepoint) { + DBUG_TRACE; + + /** + * SQLCOM_SAVEPOINT命令如果发现之前已保存有重名的savepoint,mysql会触发调用tse_release_savepoint, + * 该种场景下就不需要再调用tse_srv_release_savepoint了,knl_set_savepoint接口内部会去掉重名的savepoint; + * + * tse_srv_release_savepoint底层调到knl_release_savepoint,会把当前savepoint及其之后的全都release掉, + * 与innodb行为不一致,在某些场景下会引发缺陷 + */ + if (thd->query_plan.get_command() == SQLCOM_SAVEPOINT) { + return 0; + } + + char name[MAX_SAVEPOINT_NAME_LEN]; + longlong2str((unsigned long long)savepoint, name, BASE36); + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + ct_errno_t ret = (ct_errno_t)tse_srv_release_savepoint(&tch, name); + if (ret != CT_SUCCESS) { + tse_log_error("release trx savepoint failed with error code: %d", ret); + } + return convert_tse_error_code_to_mysql(ret); +} + +/** + fill prefetch buffer by calling batch-read intfs + @param: buf out, return one record in mysql format in order to reduce memcpy + times + @return: 0 if succeeds +*/ +int ha_tse::prefetch_and_fill_record_buffer(uchar *buf, tse_prefetch_fn prefetch) { + // update max col id needed by executor + set_max_col_index_4_reading(); + uint32_t fetched_num; + assert(m_rec_buf != nullptr); + + ct_errno_t ret = (ct_errno_t)prefetch(&m_tch, m_prefetch_buf, m_record_lens, + &fetched_num, m_rowids, m_cantian_rec_len); + check_error_code_to_mysql(ha_thd(), &ret); + if (ret != CT_SUCCESS) { + return convert_tse_error_code_to_mysql(ret); + } + if (fetched_num == 0) { + return HA_ERR_END_OF_FILE; + } + actual_fetched_nums = fetched_num; + reset_rec_buf(true); + + cur_off_in_prefetch_buf = 0; + cur_fill_buf_index = 0; + uint32_t filled_num = fetched_num <= (m_rec_buf->max_records() + 1) ? fetched_num : m_rec_buf->max_records() + 1; + // convert record to mysql format and save in prefetch buffer + for (uint32_t i = 0; i < filled_num; i++) { + uint8_t *tmpRecBuf = (i == 0) ? buf : m_rec_buf->add_record(); + if (max_col_index != INVALID_MAX_UINT32) { + record_buf_info_t record_buf = {m_prefetch_buf + cur_off_in_prefetch_buf, tmpRecBuf, nullptr}; + index_info_t index = {active_index, max_col_index}; + cnvrt_to_mysql_record(*table, &index, &record_buf, m_tch); + } + cur_off_in_prefetch_buf += m_record_lens[cur_fill_buf_index++]; + } + + bool is_out_of_range = (cur_off_in_prefetch_buf <= (uint64_t)(MAX_RECORD_SIZE - m_cantian_rec_len)) && + actual_fetched_nums < MAX_PREFETCH_REC_NUM; + m_rec_buf->set_out_of_range(is_out_of_range); + + return 0; +} + + +void ha_tse::fill_record_to_rec_buffer() { + m_rec_buf->clear(); + for (uint32_t i = 0; i < m_rec_buf->max_records() && cur_fill_buf_index < actual_fetched_nums; i++) { + uint8_t *tmpRecBuf = m_rec_buf->add_record(); + if (max_col_index != INVALID_MAX_UINT32) { + record_buf_info_t record_buf = {m_prefetch_buf + cur_off_in_prefetch_buf, tmpRecBuf, nullptr}; + index_info_t index = {active_index, max_col_index}; + cnvrt_to_mysql_record(*table, &index, &record_buf, m_tch); + } + cur_off_in_prefetch_buf += m_record_lens[cur_fill_buf_index++]; + } + + bool is_out_of_range = (cur_off_in_prefetch_buf <= (uint64_t)(MAX_RECORD_SIZE - m_cantian_rec_len)) && + actual_fetched_nums < MAX_PREFETCH_REC_NUM; + m_rec_buf->set_out_of_range(is_out_of_range); +} + +void ha_tse::reset_rec_buf(bool is_prefetch) { + cur_pos_in_buf = INVALID_MAX_UINT32; + if (is_prefetch) { + cur_pos_in_buf = 0; + } + if (!m_rec_buf) { + return; + } + m_rec_buf->reset(); +} + +void ha_tse::set_max_col_index_4_reading() { + max_col_index = table->read_set->n_bits - 1; + // max_col_index equals to num_of_cols - 1 in table if it's not a read-only + // scan + if (!bitmap_is_clear_all(table->write_set)) { + return; + } + if (bitmap_is_clear_all(table->read_set)) { + max_col_index = INVALID_MAX_UINT32; + return; + } + // find max col index needed by optimizer according to read_set + // max_col_index is needed by cantian2mysql func to get a early return for + // fullfilling record_buffer + if (m_is_covering_index && active_index != MAX_KEY) { // index_only + auto index_info = (*table).key_info[active_index]; + uint key_fields = index_info.actual_key_parts; + for (int key_id = key_fields -1; key_id >= 0; key_id--) { + uint col_id = index_info.key_part[key_id].field->field_index(); + if (bitmap_is_set(table->read_set, col_id)) { + max_col_index = col_id; + break; + } + } + } else { + while (!bitmap_is_set(table->read_set, max_col_index)) { + max_col_index--; + } + } + +} + +bool ha_tse::pre_check_for_cascade(bool is_update) { + TABLE_SHARE_FOREIGN_KEY_PARENT_INFO *fk = table->s->foreign_key_parent; + + for (uint i = 0; i < table->s->foreign_key_parents; i++) { + if (is_update) { + if (dd::Foreign_key::RULE_CASCADE != fk[i].update_rule && + dd::Foreign_key::RULE_SET_NULL != fk[i].update_rule) { + return false; + } + } else { + if (dd::Foreign_key::RULE_CASCADE != fk[i].delete_rule && + dd::Foreign_key::RULE_SET_NULL != fk[i].delete_rule) { + return false; + } + } + } + return true; +} + +ha_tse::ha_tse(handlerton *hton, TABLE_SHARE *table_arg) + : handler(hton, table_arg), m_rec_buf(nullptr), m_share(nullptr) { + ref_length = ROW_ID_LENGTH; +} + +ha_tse::~ha_tse() { + if (m_tse_buf != nullptr) { + tse_free_buf(&m_tch, m_tse_buf); + m_tse_buf = nullptr; + } + + if (m_rec_buf_data != nullptr) { + my_free(m_rec_buf_data); + m_rec_buf_data = nullptr; + } + + if (m_rec_buf != nullptr) { + delete m_rec_buf; + m_rec_buf = nullptr; + } + + if (m_prefetch_buf != nullptr) { + my_free(m_prefetch_buf); + m_prefetch_buf = nullptr; + } + + if (m_cond != nullptr) { + free_m_cond(m_tch, &m_cond); + } + free_blob_addrs(); +} + +int ha_tse::initialize() { + THD *thd = ha_thd(); + int ret = get_tch_in_handler_data(ht, thd, m_tch); + if (ret != 0) { + tse_log_error("alloc session context mem error."); + return ret; + } + m_tch.inst_id = ha_tse_get_inst_id(); + m_tch.cursor_addr = INVALID_VALUE64; + m_tch.cursor_ref = 0; + m_tch.cursor_valid = false; + m_tch.part_id = (uint32_t)0xFFFFFFFF; + + m_tse_buf = tse_alloc_buf(&m_tch, BIG_RECORD_SIZE); + if (m_tse_buf == nullptr) { + tse_log_warning("alloc shm mem failed, m_tse_buf size(%u)", BIG_RECORD_SIZE); + } + + m_rec_buf_data = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, MAX_RECORD_BUFFER_SIZE_TSE, MYF(MY_WME)); + if (m_rec_buf_data == nullptr) { + tse_log_error("alloc mem failed, m_rec_buf_data size(%u)", MAX_RECORD_BUFFER_SIZE_TSE); + return HA_ERR_OUT_OF_MEM; + } + + // size is limited by struct defined in shared mem + m_prefetch_buf = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, MAX_RECORD_SIZE, MYF(MY_WME)); + if (m_prefetch_buf == nullptr) { + tse_log_error("alloc mem failed, m_prefetch_buf size(%u)", MAX_RECORD_SIZE); + return HA_ERR_OUT_OF_MEM; + } + + return CT_SUCCESS; +} + +bool tse_is_temporary(const dd::Table *table_def) { + return table_def ? table_def->is_temporary() : true; +} + +/** + @brief + Used for opening tables. The name will be the name of the file. + + @details + A table is opened when it needs to be opened; e.g. when a request comes in + for a SELECT on the table (tables are not open and closed for each request, + they are cached). + + Called from handler.cc by handler::ha_open(). The server opens all tables by + calling ha_open() which then calls the handler specific open(). + + @see + handler::ha_open() in handler.cc + + @param name Full path of table name (name of the + file). + @param mode Open mode flags. + @param test_if_locked ? + @param table_def dd::Table object describing table + being open. Can be NULL for temporary + tables created by optimizer. + + @retval >0 Error. + @retval 0 Success. +*/ + +EXTER_ATTACK int ha_tse::open(const char *name, int, uint test_if_locked, const dd::Table *table_def) { + DBUG_TRACE; + assert(table_share == table->s); + THD *thd = ha_thd(); + + if (!(test_if_locked & (HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE))) { + if (table_share->m_part_info == nullptr) { + if (!(m_share = get_share())) { + return HA_ERR_OUT_OF_MEM; + } + } + lock_shared_ha_data(); + ct_errno_t ret = (ct_errno_t)initialize_cbo_stats(); + unlock_shared_ha_data(); + if (ret != CT_SUCCESS) { + if (table_share->m_part_info == nullptr) { + free_share(); + } + return convert_tse_error_code_to_mysql(ret); + } + } + + if (is_replay_ddl(thd)) { + return 0; + } + // rename table的故障场景下,参天的表不存在,需要忽略open close table的错误 + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd, table->s->table_name.str) || is_lock_table(thd))) { + return 0; + } + + char user_name[SMALL_RECORD_SIZE] = {0}; + char table_name[SMALL_RECORD_SIZE] = {0}; + bool is_tmp_table = tse_is_temporary(table_def); + tse_split_normalized_name(name, user_name, SMALL_RECORD_SIZE, table_name, SMALL_RECORD_SIZE, &is_tmp_table); + if (!is_tmp_table) { + tse_copy_name(table_name, table->s->table_name.str, SMALL_RECORD_SIZE); + } + + m_cantian_rec_len = get_cantian_record_length(table); + assert(m_cantian_rec_len <= CT_MAX_RECORD_LENGTH); + m_max_batch_num = MAX_RECORD_SIZE / m_cantian_rec_len; + m_max_batch_num = m_max_batch_num > UINT_MAX ? UINT_MAX : m_max_batch_num; // restricted by uint32 + + update_member_tch(m_tch, tse_hton, thd); + key_used_on_scan = table_share->primary_key; + + // table_def can be null while index_merge using union, we can not get table_name by table_def + ct_errno_t ret = (ct_errno_t)tse_open_table(&m_tch, table_name, user_name); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + + check_error_code_to_mysql(ha_thd(), &ret); + if (ret != CT_SUCCESS && !(test_if_locked & (HA_OPEN_TMP_TABLE | HA_OPEN_INTERNAL_TABLE)) + && table_share->m_part_info == nullptr) { + free_share(); + } + + return convert_tse_error_code_to_mysql(ret); +} + +/** + @brief + Closes a table. + + @details + Called from sql_base.cc, sql_select.cc, and table.cc. In sql_select.cc it is + only used to close up temporary tables or during the process where a + temporary table is converted over to being a myisam table. + + For sql_base.cc look at close_data_tables(). + + @see + sql_base.cc, sql_select.cc and table.cc +*/ + +int ha_tse::close(void) { + DBUG_TRACE; + THD *thd = ha_thd(); + + if (get_server_state() != SERVER_OPERATING && thd == nullptr) { + return 0; + } + + if (m_share && table_share->m_part_info == nullptr) { + free_share(); + } + + if (is_replay_ddl(thd)) { + return 0; + } + + // rename table的故障场景下,参天的表不存在,需要忽略open close table的错误 + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd, table->s->table_name.str))) { + return 0; + } + + update_member_tch(m_tch, tse_hton, thd); + if (m_tch.ctx_addr == INVALID_VALUE64) { + tse_log_warning("[TSE_CLOSE_TABLE]:Close a table that is not open."); + return 0; + } + + ct_errno_t ret = (ct_errno_t)tse_close_table(&m_tch); + check_error_code_to_mysql(ha_thd(), &ret); + m_tch.ctx_addr = INVALID_VALUE64; + return convert_tse_error_code_to_mysql(ret); +} + +int ha_tse::handle_auto_increment(bool &has_explicit_autoinc) { + THD *thd = ha_thd(); + const Discrete_interval *insert_id_info; + insert_id_for_cur_row = 0; + /* + 1. Value set by 'SET INSERT_ID=#' + 2. Partition table use auto_inc column as part key, update to 0 + */ + if ((insert_id_info = thd->auto_inc_intervals_forced.get_next()) != nullptr) { + // store insert_id to auto_inc col, reset insert_id + ulonglong forced_val = insert_id_info->minimum(); + table->next_number_field->store(forced_val, true); + thd->auto_inc_intervals_forced.clear(); + has_explicit_autoinc = true; + insert_id_for_cur_row = forced_val; + return CT_SUCCESS; + } + + /* + if has explicit auto_inc value + 1. specify value that is neither null nor zero + 2. specify zero but in NO_AUTO_VALUE_ON_ZERO sql mode + */ + if (table->next_number_field->val_int() != 0 || + (table->autoinc_field_has_explicit_non_null_value && + thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)) { + if (thd->is_error() && + thd->get_stmt_da()->mysql_errno() == ER_TRUNCATED_WRONG_VALUE) { + return HA_ERR_AUTOINC_ERANGE; + } + has_explicit_autoinc = true; + return CT_SUCCESS; + } + + has_explicit_autoinc = false; + return CT_SUCCESS; +} + +/** + @brief + write_row() inserts a row. No extra() hint is given currently if a bulk load + is happening. buf() is a byte array of data. You can use the field + information to extract the data from the native byte array type. + + @details + Dse of this would be: + @code + for (Field **field=table->field ; *field ; field++) + { + ... + } + @endcode + + See ha_tina.cc for an tse of extracting all of the data as strings. + ha_berekly.cc has an tse of how to store it intact by "packing" it + for ha_berkeley's own native storage type. + + See the note for update_row() on auto_increments. This case also applies to + write_row(). + + Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, + sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc. + + @see + item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, + sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc and sql_update.cc +*/ +#ifdef METADATA_NORMALIZED +EXTER_ATTACK int ha_tse::write_row(uchar *buf, bool write_through) { +#endif +#ifndef METADATA_NORMALIZED +EXTER_ATTACK int ha_tse::write_row(uchar *buf) { +#endif + DBUG_TRACE; + THD *thd = ha_thd(); + + if (engine_ddl_passthru(thd) && is_create_table_check(thd)) { + return CT_SUCCESS; + } + + int cantian_record_buf_size = TSE_BUF_LEN; + uint16_t serial_column_offset = 0; + int error_result = CT_SUCCESS; + bool auto_inc_used = false; + bool has_explicit_autoinc = false; + ha_statistic_increment(&System_status_var::ha_write_count); + + // if has auto_inc column + if (table->next_number_field && buf == table->record[0]) { + error_result = handle_auto_increment(has_explicit_autoinc); + if (error_result != CT_SUCCESS) { + return error_result; + } + auto_inc_used = true; + } + + if (!m_rec_buf_4_writing) { + dml_flag_t flag = tse_get_dml_flag(thd, false, auto_inc_used, has_explicit_autoinc, false); +#ifdef METADATA_NORMALIZED + flag.write_through = write_through; +#endif +#ifndef METADATA_NORMALIZED + flag.write_through = false; +#endif + error_result = convert_mysql_record_and_write_to_cantian(buf, &cantian_record_buf_size, &serial_column_offset, flag); + return error_result; + } + + // flush records to engine if buffer is full + if (m_rec_buf_4_writing->records() == m_rec_buf_4_writing->max_records()) { + error_result = bulk_insert(); + if (error_result != CT_SUCCESS) { + delete m_rec_buf_4_writing; + m_rec_buf_4_writing = nullptr; + return error_result; + } + + m_rec_buf_4_writing->reset(); + } + + uchar *cur_write_pos = m_rec_buf_4_writing->add_record(); + memset(cur_write_pos, 0, sizeof(row_head_t)); + record_buf_info_t record_buf = {cur_write_pos, buf, &cantian_record_buf_size}; + + update_member_tch(m_tch, tse_hton, thd, false); + error_result = mysql_record_to_cantian_record(*table, &record_buf, m_tch, &serial_column_offset); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); // update for tse_knl_write_lob in mysql_record_to_cantian_record + + if (error_result != 0) { + m_rec_buf_4_writing->reset(); + return error_result; + } + assert(cantian_record_buf_size <= m_cantian_rec_len); + + return CT_SUCCESS; +} + + +int ha_tse::convert_mysql_record_and_write_to_cantian(uchar *buf, int *cantian_record_buf_size, + uint16_t *serial_column_offset, dml_flag_t flag) { + int error_result; + ct_errno_t ret; + uint64_t cur_last_insert_id = 0; + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + memset(tse_buf, 0, sizeof(row_head_t)); + record_buf_info_t record_buf = {tse_buf, buf, cantian_record_buf_size}; + + update_member_tch(m_tch, tse_hton, ha_thd()); + error_result = mysql_record_to_cantian_record(*table, &record_buf, m_tch, serial_column_offset); + update_sess_ctx_by_tch(m_tch, tse_hton, ha_thd()); // update for tse_knl_write_lob in mysql_record_to_cantian_record + + if (error_result != 0) { + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return error_result; + } + update_member_tch(m_tch, tse_hton, ha_thd()); + record_info_t record_info = { tse_buf, (uint16_t)*cantian_record_buf_size }; + ret = (ct_errno_t)tse_write_row(&m_tch, &record_info, *serial_column_offset, &cur_last_insert_id, flag); + update_sess_ctx_by_tch(m_tch, tse_hton, ha_thd()); + check_error_code_to_mysql(ha_thd(), &ret); + + if (table->next_number_field && buf == table->record[0] && !flag.has_explicit_autoinc) { + table->next_number_field->store(cur_last_insert_id, true); + insert_id_for_cur_row = cur_last_insert_id; + } + + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + + return convert_tse_error_code_to_mysql(ret); +} + +int ha_tse::bulk_insert_low(dml_flag_t flag, uint *dup_offset) { + record_info_t record_info = {m_rec_buf_data, (uint16_t)m_cantian_rec_len}; + return tse_bulk_write(&m_tch, &record_info, m_rec_buf_4_writing->records(), dup_offset, flag, nullptr); +} + +int ha_tse::bulk_insert() { + ct_errno_t ret; + uint dup_offset = 0; + THD *thd = ha_thd(); + dml_flag_t flag = tse_get_dml_flag(thd, false, false, false, false); + update_member_tch(m_tch, tse_hton, thd); + ret = (ct_errno_t)bulk_insert_low(flag, &dup_offset); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + check_error_code_to_mysql(thd, &ret); + + if (ret != CT_SUCCESS) { + // refresh table->record[0] to make sure that duplicated contents are correctly set in output + if (ret == ERR_DUPLICATE_KEY) { + record_buf_info_t record_buf = {m_rec_buf_4_writing->record(dup_offset), table->record[0], nullptr}; + index_info_t index = {UINT_MAX, UINT_MAX}; + cantian_record_to_mysql_record(*table, &index, &record_buf, m_tch); + } + return convert_tse_error_code_to_mysql(ret); + } + return CT_SUCCESS; +} + +void ha_tse::start_bulk_insert(ha_rows rows) { + assert(m_rec_buf_4_writing == nullptr); + + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd))) { + return; + } + + if (rows == 1 || m_is_insert_dup || m_is_replace || m_ignore_dup || table->s->blob_fields > 0 || + table->next_number_field || m_rec_buf_data == nullptr) { + m_rec_buf_4_writing = nullptr; + return; + } + m_rec_buf_4_writing = new Record_buffer{m_max_batch_num, (size_t)m_cantian_rec_len, m_rec_buf_data}; +} + +int ha_tse::end_bulk_insert() { + if (engine_ddl_passthru(ha_thd()) && is_create_table_check(ha_thd())) { + return 0; + } + + if (m_rec_buf_4_writing == nullptr) { + return 0; + } + + int ret = 0; + if (m_rec_buf_4_writing->records() != 0) { + ret = bulk_insert(); + if (ret != 0) { + set_my_errno(ret); + } + } + + delete m_rec_buf_4_writing; + m_rec_buf_4_writing = nullptr; + return ret; +} + +int tse_cmp_key_values(TABLE *table, const uchar *old_data, const uchar *new_data, uint key_nr) { + if (key_nr == MAX_KEY) { + return 0; + } + + KEY *key_info = table->key_info + key_nr; + KEY_PART_INFO *key_part = key_info->key_part; + KEY_PART_INFO *key_part_end = key_part + key_info->user_defined_key_parts; + + for (; key_part != key_part_end; key_part++) { + Field *field = key_part->field; + if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART)) { + if (field->cmp_binary((old_data + key_part->offset), (new_data + key_part->offset), (ulong)key_part->length)) { + return 1; + } + } else if (memcmp(old_data + key_part->offset, new_data + key_part->offset, key_part->length)) { + return 1; + } + } + + return 0; +} + +/** + @brief + Yes, update_row() does what you expect, it updates a row. old_data will have + the previous row record in it, while new_data will have the newest data in it. + Keep in mind that the server can do updates based on ordering if an ORDER BY + clause was used. Consecutive ordering is not guaranteed. + + @details + Currently new_data will not have an updated auto_increament record. You can + do this for tse by doing: + + @code + + if (table->next_number_field && record == table->record[0]) + update_auto_increment(); + + @endcode + + Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc. + + @see + sql_select.cc, sql_acl.cc, sql_update.cc and sql_insert.cc +*/ +EXTER_ATTACK int ha_tse::update_row(const uchar *old_data, uchar *new_data) { + DBUG_TRACE; + + THD *thd = ha_thd(); + m_is_replace = (thd->lex->sql_command == SQLCOM_REPLACE || + thd->lex->sql_command == SQLCOM_REPLACE_SELECT) ? true : m_is_replace; + if (thd->lex->sql_command == SQLCOM_REPLACE || thd->lex->sql_command == SQLCOM_REPLACE_SELECT) { + uint key_nr = table->file->errkey; + if (key_nr < MAX_KEY && tse_cmp_key_values(table, old_data, new_data, key_nr) != 0) { + return HA_ERR_KEY_NOT_FOUND; + } + } + + int cantian_new_record_buf_size = TSE_BUF_LEN; + uint16_t serial_column_offset = 0; + ha_statistic_increment(&System_status_var::ha_update_count); + + + vector upd_fields; + for (uint16_t i = 0; i < table->write_set->n_bits; i++) { + if (m_tch.change_data_capture || bitmap_is_set(table->write_set, i)) { + upd_fields.push_back(i); + } + } + + if (upd_fields.size() == 0) { + return HA_ERR_RECORD_IS_THE_SAME; + } + + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + memset(tse_buf, 0, sizeof(row_head_t)); + + record_buf_info_t record_buf = {tse_buf, new_data, &cantian_new_record_buf_size}; + ct_errno_t ret = (ct_errno_t)mysql_record_to_cantian_record(*table, &record_buf, + m_tch, &serial_column_offset, &upd_fields); + if (ret != CT_SUCCESS) { + return ret; + } + // return if only update gcol + if (upd_fields.size() == 0) { + return 0; + } + // (m_ignore_dup && m_is_replace) -> special case for load data ... replace into + bool dup_update = m_is_insert_dup || (m_ignore_dup && m_is_replace); + dml_flag_t flag = tse_get_dml_flag(thd, m_is_replace, false, false, dup_update); + if (!flag.no_foreign_key_check) { + flag.no_cascade_check = flag.dd_update ? true : pre_check_for_cascade(true); + } + ret = (ct_errno_t)tse_update_row(&m_tch, cantian_new_record_buf_size, tse_buf, + &upd_fields[0], upd_fields.size(), flag); + check_error_code_to_mysql(thd, &ret); + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return convert_tse_error_code_to_mysql(ret); +} + +/** + @brief + This will delete a row. buf will contain a copy of the row to be deleted. + The server will call this right after the current row has been called (from + either a previous rnd_nexT() or index call). + + @details + If you keep a pointer to the last row or can access a primary key it will + make doing the deletion quite a bit easier. Keep in mind that the server does + not guarantee consecutive deletions. ORDER BY clauses can be used. + + Called in sql_acl.cc and sql_udf.cc to manage internal table + information. Called in sql_delete.cc, sql_insert.cc, and + sql_select.cc. In sql_select it is used for removing duplicates + while in insert it is used for REPLACE calls. + + @see + sql_acl.cc, sql_udf.cc, sql_delete.cc, sql_insert.cc and sql_select.cc +*/ + +int ha_tse::delete_row(const uchar *buf) { + DBUG_TRACE; + UNUSED_PARAM(buf); + ha_statistic_increment(&System_status_var::ha_delete_count); + THD *thd = ha_thd(); + m_is_replace = (thd->lex->sql_command == SQLCOM_REPLACE || + thd->lex->sql_command == SQLCOM_REPLACE_SELECT) ? true : m_is_replace; + // m_is_insert_dup for on duplicate key update in partiton table when new row is in different partition + dml_flag_t flag = tse_get_dml_flag(thd, m_is_replace || m_is_insert_dup, false, false, false); + if (!flag.no_foreign_key_check) { + flag.no_cascade_check = flag.dd_update ? true : pre_check_for_cascade(false); + } + ct_errno_t ret = (ct_errno_t)tse_delete_row(&m_tch, table->s->reclength, flag); + check_error_code_to_mysql(thd, &ret); + return convert_tse_error_code_to_mysql(ret); +} + +bool ha_tse::is_record_buffer_wanted(ha_rows *const max_rows) const { + *max_rows = 0; + return false; +} + +// @ref set_record_buffer +void ha_tse::set_prefetch_buffer() { + if (m_rec_buf) { + delete m_rec_buf; + m_rec_buf = nullptr; + } + if (!can_prefetch_records()) { + return; + } + + // calculate how many rows to fetch + uint32_t mysql_rec_length = table->s->rec_buff_length; + // max rows that internal buf can support + ha_rows max_rows = max_prefetch_num; + // max rows that record buffer can support + max_rows = (max_rows > MAX_RECORD_BUFFER_SIZE_TSE / mysql_rec_length) ? + MAX_RECORD_BUFFER_SIZE_TSE / mysql_rec_length : max_rows; + // max rows that limited by array in shared mem intf + max_rows = (max_rows > max_prefetch_num - 1) ? max_prefetch_num - 1 : max_rows; + + m_rec_buf = new Record_buffer{max_rows, mysql_rec_length, m_rec_buf_data}; + tse_log_note("prefetch record %llu", max_rows); + return; +} + +/* + All table scans call this first. + The order of a table scan is: + + ha_tina::store_lock + ha_tina::external_lock + ha_tina::info + ha_tina::rnd_init + ha_tina::extra + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::rnd_next + ha_tina::extra + ha_tina::external_lock + ha_tina::extra + ENUM HA_EXTRA_RESET Reset database to after open + + Each call to ::rnd_next() represents a row returned in the can. When no more + rows can be returned, rnd_next() returns a value of HA_ERR_END_OF_FILE. + The ::info() call is just for the optimizer. + +*/ + +// @ref row_prebuilt_t::can_prefetch_records() +bool ha_tse::can_prefetch_records() const { + // do not prefetch if it's not a read-only scan + THD *thd = ha_thd(); + if (thd->lex->sql_command != SQLCOM_SELECT) { + return false; + } + + // do not prefetch if we have column that may be extremely huge + if (table->s->blob_fields) { + return false; + } + + // do not prefetch, for with recursive & big_tables + if (thd->lex->all_query_blocks_list && thd->lex->all_query_blocks_list->is_recursive()) { + return false; + } + + return true; +} + +/** + @brief + After malloc outline memory for blob field (in convert_blob_to_mysql), + we need to push them into m_blob_addrs and free them after usage. + + @details + Our purpose is to free the memory we malloc for the current buf that mysql pass to ctc, + so we need to move the field to the current buf we get (either record[0] or record[1], depends on mysql). + Like with DUP_REPLACE (replace into) / DUP_UPDATE (on duplicate key update) sql, + write_record (sql_insert.cc) will use table->record[1] for read instead of table->record[0]. + + @see + sql_insert.cc, reference ha_federated::convert_row_to_internal_format in ha_federated.cc. +*/ +void ha_tse::update_blob_addrs(uchar *record) { + ptrdiff_t old_ptr = (ptrdiff_t)(record - table->record[0]); + for (uint i = 0; i < table->s->blob_fields; i++) { + uint field_no = table->s->blob_field[i]; + if (!bitmap_is_set(table->read_set, field_no)) { + continue; + } + + if (table->field[field_no]->is_virtual_gcol()) { + continue; + } + + Field_blob *blob_field = down_cast(table->field[field_no]); + blob_field->move_field_offset(old_ptr); + + if (blob_field->is_null()) { + blob_field->move_field_offset(-old_ptr); + continue; + } + + m_blob_addrs.push_back(blob_field->get_blob_data()); + blob_field->move_field_offset(-old_ptr); + } +} + +void ha_tse::free_blob_addrs() { + for (auto addr : m_blob_addrs) { + my_free(addr); + } + m_blob_addrs.clear(); +} + +void free_m_cond(tianchi_handler_t m_tch, tse_conds **conds) { + tse_conds *cond = *conds; + if (cond == nullptr) { + return; + } + if (cond->cond_list == nullptr) { + if (cond->field_info.field_value != nullptr) { + tse_free_buf(&m_tch, (uint8_t *)(cond->field_info.field_value)); + cond->field_info.field_value = nullptr; + } + tse_free_buf(&m_tch, (uint8_t *)cond); + *conds = nullptr; + return; + } + tse_conds *node = cond->cond_list->first; + int size = cond->cond_list->elements; + for (int i = 0; i < size; i++) { + tse_conds *tmp = node->next; + free_m_cond(m_tch, &node); + if (tmp == nullptr) { + cond->cond_list->last = nullptr; + tse_free_buf(&m_tch, (uint8_t *)(cond->cond_list)); + cond->cond_list = nullptr; + tse_free_buf(&m_tch, (uint8_t *)cond); + *conds = nullptr; + } + node = tmp; + } +} + +int tse_fill_conds(tianchi_handler_t m_tch, const Item *pushed_cond, Field **field, + tse_conds *m_cond, bool no_backslash) { + memset(m_cond, 0, sizeof(tse_conds)); + Item *items = const_cast(pushed_cond); + return dfs_fill_conds(m_tch, items, field, m_cond, no_backslash); +} + +/** + @brief + rnd_init() is called when the system wants the storage engine to do a table + scan. See the tse in the introduction at the top of this file to see when + rnd_init() is called. + + @details + Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, + sql_table.cc, and sql_update.cc. + + @see + filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and + sql_update.cc +*/ + +int ha_tse::rnd_init(bool) { + DBUG_TRACE; + m_index_sorted = false; + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd) || + is_alter_table_scan(m_error_if_not_empty))) { + return 0; + } + + set_prefetch_buffer(); + expected_cursor_action_t action = EXP_CURSOR_ACTION_SELECT; + if (m_select_lock == lock_mode::EXCLUSIVE_LOCK) { + enum_sql_command sql_command = (enum_sql_command)thd_sql_command(ha_thd()); + if (sql_command == SQLCOM_DELETE) { + action = EXP_CURSOR_ACTION_DELETE; + } else if (sql_command != SQLCOM_ALTER_TABLE){ // action can't be set to update when alter operation using copy algorithm + action = EXP_CURSOR_ACTION_UPDATE; + } + } + update_member_tch(m_tch, tse_hton, ha_thd()); + m_tch.cursor_valid = false; + ct_errno_t ret = (ct_errno_t)tse_rnd_init(&m_tch, action, get_select_mode(), m_cond); + update_sess_ctx_by_tch(m_tch, tse_hton, ha_thd()); + + if (!(table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE) + || !is_log_table) { + update_sess_ctx_cursor_by_tch(m_tch, tse_hton, thd); + } + + check_error_code_to_mysql(ha_thd(), &ret); + cnvrt_to_mysql_record = cantian_record_to_mysql_record; + reset_rec_buf(); + return convert_tse_error_code_to_mysql(ret); +} + +/** + @brief + This is called for each row of the table scan. When you run out of records + you should return HA_ERR_END_OF_FILE. Fill buff up with the row information. + The Field structure for the table is the key to getting data into buf + in a manner that will allow the server to understand it. + + @details + Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, + sql_table.cc, and sql_update.cc. + + @see + filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and + sql_update.cc +*/ +int ha_tse::rnd_next(uchar *buf) { + DBUG_TRACE; + + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd) || + is_alter_table_scan(m_error_if_not_empty))) { + return HA_ERR_END_OF_FILE; + } + + ha_statistic_increment(&System_status_var::ha_read_rnd_next_count); + + if (!m_rec_buf || m_rec_buf->max_records() == 0) { + int ret = CT_SUCCESS; + ct_errno_t ct_ret = CT_SUCCESS; + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + + record_info_t record_info = {tse_buf, 0}; + ct_ret = (ct_errno_t)tse_rnd_next(&m_tch, &record_info); + ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_END_OF_FILE); + + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return ret; + } + + // initial fetch + if (m_rec_buf->records() != 0) { + if (cur_pos_in_buf >= actual_fetched_nums - 1) { + // records in rec buf are not enough + // reset cur_pos_in_buf + cur_pos_in_buf = INVALID_MAX_UINT32; + if (m_rec_buf->is_out_of_range()) { + set_my_errno(HA_ERR_END_OF_FILE); + return HA_ERR_END_OF_FILE; + } + } else { + // directly fetch record from rec buf + uint8_t *curRecordStart = m_rec_buf->record(cur_pos_in_buf % m_rec_buf->max_records()); + memcpy(buf, curRecordStart, m_rec_buf->record_size()); + cur_pos_in_buf += 1; + if (cur_pos_in_buf % m_rec_buf->max_records() == 0) { + fill_record_to_rec_buffer(); + } + return 0; + } + } + + int mysql_ret = prefetch_and_fill_record_buffer(buf, tse_rnd_prefetch); + if (mysql_ret != 0) { + set_my_errno(mysql_ret); + return mysql_ret; + } + return 0; +} + +/** + @brief + position() is called after each call to rnd_next() if the data needs + to be ordered. You can do something like the following to store + the position: + @code + my_store_ptr(ref, ref_length, current_position); + @endcode + + @details + The server uses ref to store data. ref_length in the above case is + the size needed to store current_position. ref is just a byte array + that the server will maintain. If you are using offsets to mark rows, then + current_position should be the offset. If it is a primary key like in + BDB, then it needs to be a primary key. + + Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc. + + @see + filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc +*/ +void ha_tse::position(const uchar *) { + if (cur_pos_in_buf == INVALID_MAX_UINT32) { + tse_position(&m_tch, ref, ref_length); + return; + } + assert(cur_pos_in_buf < max_prefetch_num); + memcpy(ref, &m_rowids[cur_pos_in_buf], ref_length); +} + +/** + @brief + This is like rnd_next, but you are given a position to use + to determine the row. The position will be of the type that you stored in + ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key + or position you saved when position() was called. + + @details + Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and + sql_update.cc. + + @see + filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc +*/ +EXTER_ATTACK int ha_tse::rnd_pos(uchar *buf, uchar *pos) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_rnd_count); + int ret = CT_SUCCESS; + ct_errno_t ct_ret = CT_SUCCESS; + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + + record_info_t record_info = {tse_buf, 0}; + uint key_len = ref_length; + if (IS_TSE_PART(m_tch.part_id)) { + key_len -= PARTITION_BYTES_IN_POS; + } + ct_ret = (ct_errno_t)tse_rnd_pos(&m_tch, key_len, pos, &record_info); + ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_KEY_NOT_FOUND); + + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return ret; +} + +/** + @brief + ::info() is used to return information to the optimizer. See my_base.h for + the complete description. + + @details + Currently this table handler doesn't implement most of the fields really + needed. SHOW also makes use of this data. + + You will probably want to have the following in your code: + @code + if (records < 2) + records = 2; + @endcode + The reason is that the server will optimize for cases of only a single + record. If, in a table scan, you don't know the number of records, it + will probably be better to set records to two so you can return as many + records as you need. Along with records, a few more variables you may wish + to set are: + records + deleted + data_file_length + index_file_length + delete_length + check_time + Take a look at the public variables in handler.h for more information. + + Called in filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, + sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, + sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, + sql_show.cc, sql_table.cc, sql_union.cc, and sql_update.cc. + + @see + filesort.cc, ha_heap.cc, item_sum.cc, opt_sum.cc, sql_delete.cc, + sql_delete.cc, sql_derived.cc, sql_select.cc, sql_select.cc, sql_select.cc, + sql_select.cc, sql_select.cc, sql_show.cc, sql_show.cc, sql_show.cc, + sql_show.cc, sql_table.cc, sql_union.cc and sql_update.cc +*/ + +void ha_tse::info_low() { + if (m_share && m_share->cbo_stats != nullptr) { + stats.records = m_share->cbo_stats->estimate_rows; + } +} + +int ha_tse::info(uint flag) { + DBUG_TRACE; + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd))) { + return 0; + } + + ct_errno_t ret = CT_SUCCESS; + if (flag & HA_STATUS_VARIABLE) { + if (thd->lex->sql_command == SQLCOM_DELETE && + thd->lex->query_block->where_cond() == nullptr) { + records(&stats.records); + return 0; + } + ret = (ct_errno_t)get_cbo_stats_4share(); + if (ret != CT_SUCCESS) { + return convert_tse_error_code_to_mysql(ret); + } + } + + info_low(); + if (stats.records < 2) { + /* This is a lie, but you don't want the optimizer to see zero or 1 */ + stats.records = 3; + } + + if (flag & HA_STATUS_ERRKEY) { + char index_name[TSE_MAX_KEY_NAME_LENGTH + 1]; + ret = (ct_errno_t)tse_get_index_name(&m_tch, index_name); + + if (ret == CT_SUCCESS) { + for (uint i = 0; i < table->s->keys; i++) { + if (strncmp(table->key_info[i].name, index_name, strlen(index_name)) == 0) { + table->file->errkey = i; + break; + } + } + if (table->file->errkey == UINT_MAX) { + return HA_ERR_KEY_NOT_FOUND; + } + } + } + + return convert_tse_error_code_to_mysql(ret); +} + +int ha_tse::analyze(THD *thd, HA_CHECK_OPT *) { + + if (engine_ddl_passthru(thd)) { + if (m_share) { + m_share->need_fetch_cbo = true; + } + return 0; + } + + if (table->s->tmp_table) { + return HA_ADMIN_OK; + } + + char user_name_str[SMALL_RECORD_SIZE]; + tse_copy_name(user_name_str, thd->lex->query_tables->get_db_name(), SMALL_RECORD_SIZE); + + ct_errno_t ret = (ct_errno_t)tse_analyze_table( + &m_tch, user_name_str, thd->lex->query_tables->table_name, THDVAR(thd, sampling_ratio)); + check_error_code_to_mysql(thd, &ret); + if (ret == CT_SUCCESS && m_share && table_share->m_part_info == nullptr) { + m_share->need_fetch_cbo = true; + } + return convert_tse_error_code_to_mysql(ret); +} + +int ha_tse::optimize(THD *thd, HA_CHECK_OPT *) +{ + if (engine_ddl_passthru(thd)) { + return 0; + } + tse_ddl_stack_mem stack_mem(0); + update_member_tch(m_tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ct_errno_t ret = (ct_errno_t)fill_rebuild_index_req(table, thd, &ddl_ctrl, &stack_mem); + if (ret != 0) { + return convert_tse_error_code_to_mysql(ret); + } + + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + tse_register_trx(tse_hton, thd); + ret = (ct_errno_t)tse_alter_table(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_ddl_hook_cantian_error("tse_optimize_table_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + + return tse_ddl_handle_fault("tse_optimize table", thd, &ddl_ctrl, ret); +} + +/** + @brief + extra() is called whenever the server wishes to send a hint to + the storage engine. The myisam engine implements the most hints. + ha_innodb.cc has the most exhaustive list of these hints. + + @see + ha_innodb.cc +*/ +int ha_tse::extra(enum ha_extra_function operation) { + DBUG_TRACE; + + switch (operation) { + case HA_EXTRA_WRITE_CAN_REPLACE: + m_is_replace = true; + break; + case HA_EXTRA_WRITE_CANNOT_REPLACE: + m_is_replace = false; + break; + case HA_EXTRA_IGNORE_DUP_KEY: + m_ignore_dup = true; + break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + m_ignore_dup = false; + m_is_insert_dup = false; + break; + case HA_EXTRA_INSERT_WITH_UPDATE: + m_is_insert_dup = true; + break; + case HA_EXTRA_KEYREAD: + m_is_covering_index = true; + break; + case HA_EXTRA_NO_KEYREAD: + default: + m_is_covering_index = false; + break; + } + return 0; +} + +int ha_tse::reset() { + m_is_replace = false; + m_is_insert_dup = false; + m_is_covering_index = false; + m_ignore_dup = false; + m_error_if_not_empty = false; + free_blob_addrs(); + m_pushed_conds = nullptr; + m_remainder_conds = nullptr; + if (m_cond != nullptr) { + free_m_cond(m_tch, &m_cond); + } + + return 0; +} + +int ha_tse::rnd_end() { + DBUG_TRACE; + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd) && (is_alter_table_copy(thd) || is_create_table_check(thd) || + is_alter_table_scan(m_error_if_not_empty))) { + return 0; + } + + int ret = CT_SUCCESS; + if ((table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE) || + is_log_table) { + ct_errno_t tse_ret = (ct_errno_t)tse_rnd_end(&m_tch); + check_error_code_to_mysql(ha_thd(), &tse_ret); + ret = convert_tse_error_code_to_mysql(tse_ret); + } + + m_tch.cursor_valid = false; + m_tch.cursor_addr = INVALID_VALUE64; + return ret; +} + +int ha_tse::index_init(uint index, bool sorted) { + DBUG_TRACE; + set_prefetch_buffer(); + update_member_tch(m_tch, tse_hton, ha_thd(), false); + m_index_sorted = sorted; + active_index = index; + reset_rec_buf(); + if (m_tch.cursor_ref <= 0) { + m_tch.cursor_ref = 0; + m_tch.cursor_addr = INVALID_VALUE64; + } + m_tch.cursor_ref++; + m_tch.cursor_valid = false; + return 0; +} + +int ha_tse::index_end() { + DBUG_TRACE; + + active_index = MAX_KEY; + + int ret = CT_SUCCESS; + if (table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE) { + ret = (ct_errno_t)tse_index_end(&m_tch); + assert(ret == CT_SUCCESS); + } + + m_tch.cursor_ref--; + if (m_tch.cursor_ref <= 0) { + m_tch.cursor_valid = false; + } + return ret; +} + +int ha_tse::process_cantian_record(uchar *buf, record_info_t *record_info, ct_errno_t ct_ret, int rc_ret) { + int ret = CT_SUCCESS; + check_error_code_to_mysql(ha_thd(), &ct_ret); + if (ct_ret != CT_SUCCESS) { + ret = convert_tse_error_code_to_mysql(ct_ret); + return ret; + } + + if (record_info->record_len == 0) { + set_my_errno(rc_ret); + ret = rc_ret; + return ret; + } + + record_buf_info_t record_buf = {record_info->record, buf, nullptr}; + index_info_t index = {active_index, UINT_MAX}; + cnvrt_to_mysql_record(*table, &index, &record_buf, m_tch); + update_blob_addrs(buf); + + return ret; +} + +EXTER_ATTACK int ha_tse::index_read(uchar *buf, const uchar *key, uint key_len, ha_rkey_function find_flag) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_key_count); + + // reset prefetch buf if calling multiple index_read continuously without index_init as interval + if (m_rec_buf && m_rec_buf->records() > 0) { + reset_rec_buf(); + } + + cnvrt_to_mysql_record = m_is_covering_index ? cantian_index_record_to_mysql_record : cantian_record_to_mysql_record; + m_action = m_is_covering_index ? EXP_CURSOR_ACTION_INDEX_ONLY : EXP_CURSOR_ACTION_SELECT; + if (m_select_lock == lock_mode::EXCLUSIVE_LOCK) { + enum_sql_command sql_command = (enum_sql_command)thd_sql_command(ha_thd()); + if (sql_command == SQLCOM_DELETE) { + m_action = EXP_CURSOR_ACTION_DELETE; + } else if (sql_command != SQLCOM_ALTER_TABLE) { + m_action = EXP_CURSOR_ACTION_UPDATE; + m_is_covering_index = false; + cnvrt_to_mysql_record = cantian_record_to_mysql_record; + } + } + + index_key_info_t index_key_info; + memset(&index_key_info.key_info, 0, sizeof(index_key_info.key_info)); + index_key_info.find_flag = find_flag; + index_key_info.action = m_action; + index_key_info.active_index = active_index; + index_key_info.sorted = m_index_sorted; + index_key_info.need_init = !m_tch.cursor_valid; + int len = strlen(table->key_info[active_index].name); + memcpy(index_key_info.index_name, table->key_info[active_index].name, len + 1); + + int ret = tse_fill_index_key_info(table, key, key_len, end_range, &index_key_info); + if (ret != CT_SUCCESS) { + tse_log_error("ha_tse::index_read: fill index key info failed, ret(%d).", ret); + return ret; + } + + bool has_right_key = false; + if (end_range != nullptr && end_range->length != 0) { + has_right_key = true; + } + + dec4_t d4[MAX_KEY_COLUMNS * 2]; + ret = tse_convert_index_datatype(table, &index_key_info, has_right_key, d4); + if (ret != CT_SUCCESS) { + tse_log_error("ha_tse::index_read: convert data type for index search failed, ret(%d).", ret); + return ret; + } + + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + + update_member_tch(m_tch, tse_hton, ha_thd()); + record_info_t record_info = {tse_buf, 0}; + + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, true); + ct_errno_t ct_ret = (ct_errno_t)tse_index_read(&m_tch, &record_info, &index_key_info, + get_select_mode(), m_cond, m_is_replace || m_is_insert_dup); + update_sess_ctx_by_tch(m_tch, tse_hton, ha_thd()); + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, false); + if (index_key_info.need_init) { + if (!(table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE)) { + update_sess_ctx_cursor_by_tch(m_tch, tse_hton, ha_thd()); + } + index_key_info.need_init = false; + } + + ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_KEY_NOT_FOUND); + + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return ret; +} + +EXTER_ATTACK int ha_tse::index_read_last(uchar *buf, const uchar *key_ptr, uint key_len) { + return index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST); +} + +int ha_tse::index_fetch(uchar *buf) { + DBUG_TRACE; + int mysql_ret = 0; + + if (!m_rec_buf || m_rec_buf->max_records() == 0) { + int ret = CT_SUCCESS; + ct_errno_t ct_ret = CT_SUCCESS; + uchar *tse_buf = m_tse_buf ? m_tse_buf : tse_alloc_buf(&m_tch, BIG_RECORD_SIZE_DYNAMIC); + if (tse_buf == nullptr) { + return convert_tse_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + + record_info_t record_info = {tse_buf, 0}; + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, true); + ct_ret = (ct_errno_t)tse_general_fetch(&m_tch, &record_info); + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, false); + ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_END_OF_FILE); + // 如果m_tse_buf为空,说明tse_buf是动态申请的,在函数退出之前要释放掉 + if (m_tse_buf == nullptr) { + tse_free_buf(&m_tch, tse_buf); + } + return ret; + } + + // initial fetch + if (m_rec_buf->records() != 0) { + if (cur_pos_in_buf >= actual_fetched_nums - 1) { + // records in rec buf are not enough + // reset cur_pos_in_buf + cur_pos_in_buf = INVALID_MAX_UINT32; + if (m_rec_buf->is_out_of_range()) { + set_my_errno(HA_ERR_END_OF_FILE); + return HA_ERR_END_OF_FILE; + } + } else { + // directly fetch record from rec buf + uint8_t *curRecordStart = m_rec_buf->record(cur_pos_in_buf % m_rec_buf->max_records()); + memcpy(buf, curRecordStart, m_rec_buf->record_size()); + cur_pos_in_buf += 1; + if (cur_pos_in_buf % m_rec_buf->max_records() == 0) { + fill_record_to_rec_buffer(); + } + return CT_SUCCESS; + } + } + + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, true); + mysql_ret = prefetch_and_fill_record_buffer(buf, tse_general_prefetch); + attachable_trx_update_pre_addr(tse_hton, ha_thd(), &m_tch, false); + + if (mysql_ret != 0) { + set_my_errno(mysql_ret); + return mysql_ret; + } + return CT_SUCCESS; +} + +int ha_tse::index_next_same(uchar *buf, const uchar *, uint) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_next_count); + return index_fetch(buf); +} + +/** + @brief + Used to read forward through the index. +*/ +int ha_tse::index_next(uchar *buf) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_next_count); + return index_fetch(buf); +} + +/** + @brief + Used to read backwards through the index. +*/ +int ha_tse::index_prev(uchar *buf) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_prev_count); + return index_fetch(buf); +} + +/** + @brief + index_first() asks for the first key in the index. + + @details + Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc. + + @see + opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc +*/ +int ha_tse::index_first(uchar *buf) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_first_count); + int error = index_read(buf, nullptr, 0, HA_READ_AFTER_KEY); + /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */ + if (error == HA_ERR_KEY_NOT_FOUND) { + error = HA_ERR_END_OF_FILE; + } + return error; +} + +/** + @brief + index_last() asks for the last key in the index. + + @details + Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc. + + @see + opt_range.cc, opt_sum.cc, sql_handler.cc and sql_select.cc +*/ +int ha_tse::index_last(uchar *buf) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_last_count); + int error = index_read(buf, nullptr, 0, HA_READ_BEFORE_KEY); + /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */ + if (error == HA_ERR_KEY_NOT_FOUND) { + error = HA_ERR_END_OF_FILE; + } + return error; +} + +/** + @brief + Used to delete all rows in a table, including cases of truncate and cases + where the optimizer realizes that all rows will be removed as a result of an + SQL statement. + + @details + Called from item_sum.cc by Item_func_group_concat::clear(), + Item_sum_count_distinct::clear(), and Item_func_group_concat::clear(). + Called from sql_delete.cc by mysql_delete(). + Called from sql_select.cc by JOIN::reinit(). + Called from sql_union.cc by st_select_lex_unit::exec(). + + @see + Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and + Item_func_group_concat::clear() in item_sum.cc; + mysql_delete() in sql_delete.cc; + JOIN::reinit() in sql_select.cc and + st_select_lex_unit::exec() in sql_union.cc. +*/ +int ha_tse::delete_all_rows() { + DBUG_TRACE; + THD *thd = ha_thd(); + update_member_tch(m_tch, tse_hton, thd); + dml_flag_t flag = tse_get_dml_flag(thd, false, false, false, false); + if (!flag.no_foreign_key_check) { + flag.no_cascade_check = pre_check_for_cascade(false); + } + ct_errno_t ret = (ct_errno_t)tse_delete_all_rows(&m_tch, flag); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + check_error_code_to_mysql(thd, &ret); + if (thd->lex->is_ignore() && ret == ERR_ROW_IS_REFERENCED) { + return 0; + } + return convert_tse_error_code_to_mysql(ret); +} + +/** + @brief + max_supported_keys() is called when create indexes; + + @details + To get the the maximum number of indexes per table of DAAC +*/ +uint ha_tse::max_supported_keys() const { + return TSE_MAX_KEY_NUM; +} + +/** + @brief + max_supported_key_length() is called when create indexes; + + @details + To get the max possible key length of DAAC +*/ +uint ha_tse::max_supported_key_length() const { + return TSE_MAX_KEY_LENGTH; +} + +/** + @brief + max_supported_key_parts() is called when create indexes; + + @details + To get the maximum columns of a composite index +*/ +uint ha_tse::max_supported_key_parts() const { + return TSE_MAX_KEY_PARTS; +} + +/** + @brief + max_supported_key_part_length() is called when create indexes; + + @details + To get the maximum supported indexed columns length +*/ +uint ha_tse::max_supported_key_part_length( + HA_CREATE_INFO *create_info MY_ATTRIBUTE((unused))) const { + return TSE_MAX_KEY_PART_LENGTH; +} + +enum_alter_inplace_result ha_tse::check_if_supported_inplace_alter( + TABLE *altered_table, Alter_inplace_info *ha_alter_info) { + DBUG_TRACE; + THD *thd = ha_thd(); + + // remote node execute ALTER statement using default way + if (engine_ddl_passthru(thd)) { + return HA_ALTER_INPLACE_EXCLUSIVE_LOCK; + } + + m_error_if_not_empty = ha_alter_info->error_if_not_empty; + if (ha_alter_info->handler_flags & ~(CTC_INPLACE_IGNORE | CTC_ALTER_NOREBUILD | CTC_ALTER_REBUILD)) { + if (ha_alter_info->handler_flags & COLUMN_TYPE_OPERATIONS) { + ha_alter_info->unsupported_reason = my_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE); + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + } + + /* Only support NULL -> NOT NULL change if strict table sql_mode is set. */ + if ((ha_alter_info->handler_flags & Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE) && + !thd_is_strict_mode(thd)) { + ha_alter_info->unsupported_reason = my_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_NOT_NULL); + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + + // alter table add column containing stored generated column: json_array() as default + if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_STORED_GENERATED_COLUMN) { + ha_alter_info->unsupported_reason = my_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON); + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + + if (ha_alter_info->handler_flags & CTC_ALTER_COL_ORDER) { + ha_alter_info->unsupported_reason = "Altering column order or drop column"; + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + + if ((ha_alter_info->handler_flags & Alter_inplace_info::ALTER_RENAME) && + (strcmp(altered_table->s->db.str, table->s->db.str) != 0)) { + ha_alter_info->unsupported_reason = "Table is renamed cross database"; + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + + // alter table add NOT NULL column + if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_STORED_BASE_COLUMN) { + uint32_t old_table_fields = table->s->fields; + uint32_t new_table_fields = altered_table->s->fields; + uint32_t drop_list_size = ha_alter_info->alter_info->drop_list.size(); + uint32_t create_list_size = ha_alter_info->alter_info->create_list.size(); + uint32_t index_drop_count = ha_alter_info->index_drop_count; + + // if this table have any added columns + uint32_t add_column_size = new_table_fields - old_table_fields + (drop_list_size - index_drop_count); + + tse_log_system("[SUPPORT_INPLACE]:old_table_fields:%u new_table_fields:%u drop_list_size:%u create_list_size:%u add_column_size:%u, index_drop_count:%u", + old_table_fields, new_table_fields, drop_list_size, create_list_size, add_column_size, index_drop_count); + + for (int i = add_column_size; i > 0; i--) { + int32_t add_column_idx = create_list_size - i; + if (add_column_idx < 0) { + assert(0); + tse_log_error("[SUPPORT_INPLACE]: add_column_idx smaller than 0."); + break; + } + + bool is_nullable = ha_alter_info->alter_info->create_list[add_column_idx]->is_nullable; // NOT NULL + bool is_have_default_val = ha_alter_info->alter_info->create_list[add_column_idx]->constant_default == nullptr ? false : true; + if (!is_nullable && !is_have_default_val) { + ha_alter_info->unsupported_reason = my_get_err_msg(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON); + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + } + } + + if (ha_alter_info->handler_flags & Alter_inplace_info::REORGANIZE_PARTITION) { + ha_alter_info->unsupported_reason = "Reorganize Partition"; + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + + if ((ha_alter_info->handler_flags & PARTITION_OPERATIONS) != 0 && + altered_table->part_info->get_full_clone(thd)->part_type == partition_type::HASH) { + ha_alter_info->unsupported_reason = "INPLACE is not supported for this operation."; + return HA_ALTER_INPLACE_NOT_SUPPORTED; + } + return HA_ALTER_INPLACE_EXCLUSIVE_LOCK; +} + +/** + @brief + Construct tse range key based on mysql range key +*/ +void ha_tse::set_tse_range_key(tse_range_key *tse_range_key, key_range *mysql_range_key, tse_cmp_type_t default_type) { + if (!mysql_range_key) { + tse_range_key->cmp_type = CMP_TYPE_UNKNOWN; + tse_range_key->len = 0; + return; + } + + tse_range_key->col_map = mysql_range_key->keypart_map; + tse_range_key->key = (const char *)mysql_range_key->key; + tse_range_key->len = mysql_range_key->length; + if (mysql_range_key->flag == HA_READ_KEY_EXACT) { + tse_range_key->cmp_type = CMP_TYPE_EQUAL; + } else { + tse_range_key->cmp_type = default_type; + } +} + +/** + @brief + Given a starting key and an ending key, estimate the number of rows that + will exist between the two keys. + + @details + end_key may be empty, in which case determine if start_key matches any rows. + + Called from opt_range.cc by check_quick_keys(). + + @see + check_quick_keys() in opt_range.cc +*/ +ha_rows ha_tse::records_in_range(uint inx, key_range *min_key, + key_range *max_key) { + DBUG_TRACE; + tse_range_key tse_min_key; + tse_range_key tse_max_key; + set_tse_range_key(&tse_min_key, min_key, CMP_TYPE_GREAT); + set_tse_range_key(&tse_max_key, max_key, CMP_TYPE_LESS); + + uint64_t n_rows = 0; + part_info_t part_info = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; + + if (m_share) { + double density = calc_density_one_table(inx, &tse_min_key, &tse_max_key, part_info, m_share->cbo_stats, *table); + /* + * This is a safe-guard logic since we don't handle tse call error in this method, + * we need this to make sure that our optimizer continue to work even when we + * miscalculated the density, and it's still prefer index read + */ + n_rows += m_share->cbo_stats->estimate_rows * density; + } + + /* + * The MySQL optimizer seems to believe an estimate of 0 rows is + * always accurate and may return the result 'Empty set' based on that + */ + if (n_rows == 0) { + n_rows = 1; + } + return n_rows; +} + +int ha_tse::records(ha_rows *num_rows) /*!< out: number of rows */ +{ + DBUG_TRACE; + uint64_t n_rows = 0; + ct_errno_t ret = CT_SUCCESS; + + THD *thd = ha_thd(); + update_member_tch(m_tch, tse_hton, thd); + char *index_name = nullptr; + if (active_index != MAX_KEY) { + index_name = const_cast (table->key_info[active_index].name); + } + + /* Count the records */ + ret = (ct_errno_t)tse_scan_records(&m_tch, &n_rows, index_name); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + + assert(ret == CT_SUCCESS); + if (ret != CT_SUCCESS) { + tse_log_error("scan records failed with error code: %d", ret); + return convert_tse_error_code_to_mysql(ret); + } + + *num_rows = n_rows; + return 0; +} + +int ha_tse::records_from_index(ha_rows *num_rows, uint inx) +{ + active_index = inx; + int ret = records(num_rows); + active_index = MAX_KEY; + return ret; +} + +/** + @brief + The idea with handler::store_lock() is: The statement decides which locks + should be needed for the table. For updates/deletes/inserts we get WRITE + locks, for SELECT... we get read locks. + + @details + Before adding the lock into the table lock handler (see thr_lock.c), + mysqld calls store lock with the requested locks. Store lock can now + modify a write lock to a read lock (or some other lock), ignore the + lock (if we don't want to use MySQL table locks at all), or add locks + for many tables (like we do when we are using a MERGE handler). + + Berkeley DB, for tse, changes all WRITE locks to TL_WRITE_ALLOW_WRITE + (which signals that we are doing WRITES, but are still allowing other + readers and writers). + + When releasing locks, store_lock() is also called. In this case one + usually doesn't have to do anything. + + In some exceptional cases MySQL may send a request for a TL_IGNORE; + This means that we are requesting the same lock as last time and this + should also be ignored. (This may happen when someone does a flush + table when we have opened a part of the tables, in which case mysqld + closes and reopens the tables and tries to get the same locks at last + time). In the future we will probably try to remove this. + + Called from lock.cc by get_lock_data(). + + @note + In this method one should NEVER rely on table->in_use, it may, in fact, + refer to a different thread! (this happens if get_lock_data() is called + from mysql_lock_abort_for_thread() function) + + @see + get_lock_data() in lock.cc +*/ +THR_LOCK_DATA **ha_tse::store_lock(THD *, THR_LOCK_DATA **to, + enum thr_lock_type lock_type) { + /* + This method should not be called for internal temporary tables + as they don't have properly initialized THR_LOCK and THR_LOCK_DATA + structures. + daac engine dose not need mysql lock type, need long testing on this. + May need map mysql lock type to daac lock type in the future after figure + out they lock meaning. + */ + DBUG_TRACE; + + // SELECT FOR SHARE / SELECT FOR UPDATE use exclusive lock + if (lock_type == TL_READ_WITH_SHARED_LOCKS || (lock_type >= TL_WRITE_ALLOW_WRITE && lock_type <= TL_WRITE_ONLY)) { + m_select_lock = lock_mode::EXCLUSIVE_LOCK; + } else { + m_select_lock = lock_mode::SHARED_LOCK; + } + + return to; +} + +/** + @brief + As MySQL will execute an external lock for every new table it uses when it + starts to process an SQL statement (an exception is when MySQL calls + start_stmt directly for the handle when thread has table lock explicitly), + we will use this function to indicate CTC that a new SQL statement has started. + + @details + Called from lock.cc by lock_external() and unlock_external(). Also called + from sql_table.cc by copy_data_between_tables(). + + @see + lock.cc by lock_external() and unlock_external() in lock.cc; + the section "locking functions for mysql" in lock.cc; + copy_data_between_tables() in sql_table.cc. +*/ +int ha_tse::external_lock(THD *thd, int lock_type) { + /* + cantian dose not need mysql lock type, need long testing on this. + May need map mysql lock type to cantian lock type in the future after figure + out they lock meaning. + */ + DBUG_TRACE; + + if (IS_METADATA_NORMALIZATION() && + tse_check_if_log_table(table_share->db.str, table_share->table_name.str)) { + is_log_table = true; + return 0; + } + is_log_table = false; + + if (engine_ddl_passthru(thd) && (is_create_table_check(thd) || is_alter_table_copy(thd))) { + return 0; + } + + // F_RDLCK:0, F_WRLCK:1, F_UNLCK:2 + if (lock_type == F_UNLCK) { + m_select_lock = lock_mode::NO_LOCK; + return 0; + } + + return start_stmt(thd, TL_IGNORE); +} + +/** + @brief + When thread has table lock explicitly, MySQL will execute an external lock + for every new table it uses instead of external lock. + 1. Without explicit table lock, MySQL execute external_lock, + we make external_lock to call start_stmt for tse_trx_begin. + 2. With explicit table lock, MySQL execute start_stmt directly. + We will use this function to indicate CTC that a new SQL statement has started. + + @details + Called from ha_tse::external_lock(). + Called from sql_base.cc by check_lock_and_start_stmt(). + + @see + sql_base.cc by check_lock_and_start_stmt(). +*/ +int ha_tse::start_stmt(THD *thd, thr_lock_type) { + DBUG_TRACE; + + trans_register_ha(thd, false, ht, nullptr); // register trans to STMT + + update_member_tch(m_tch, tse_hton, thd, false); + thd_sess_ctx_s *sess_ctx = get_or_init_sess_ctx(tse_hton, thd); + if (sess_ctx == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + sess_ctx->thd_id = thd->thread_id(); + if (!thd->in_sub_stmt) { + sess_ctx->sql_stat_start = 1; // indicate cantian for a new sql border + m_tch.sql_stat_start = 1; + } + + // lock tables不开启事务 + if (thd->query_plan.get_command() == SQLCOM_LOCK_TABLES) { + return 0; + } + + // if session level transaction we only start one time + if (sess_ctx->is_tse_trx_begin) { + assert(m_tch.sess_addr != INVALID_VALUE64); + assert(m_tch.thd_id == thd->thread_id()); + return 0; + } + + uint32_t lock_wait_timeout = THDVAR(thd, lock_wait_timeout); + uint32_t autocommit = !thd->in_multi_stmt_transaction_mode(); + int isolation_level = isolation_level_to_cantian(thd_get_trx_isolation(thd)); + + tianchi_trx_context_t trx_context = {isolation_level, autocommit, lock_wait_timeout, m_select_lock == lock_mode::EXCLUSIVE_LOCK}; + + bool is_mysql_local = user_var_set(thd, "ctc_ddl_local_enabled"); + ct_errno_t ret = (ct_errno_t)tse_trx_begin(&m_tch, trx_context, is_mysql_local); + + check_error_code_to_mysql(ha_thd(), &ret); + + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + + if (ret != CT_SUCCESS) { + tse_log_error("start trx failed with error code: %d", ret); + return convert_tse_error_code_to_mysql(ret); + } + + sess_ctx->is_tse_trx_begin = 1; + if (!autocommit) { + trans_register_ha(thd, true, ht, nullptr); + } + return 0; +} + +/** Return partitioning flags. */ +static uint tse_partition_flags() { + return (HA_CANNOT_PARTITION_FK | HA_TRUNCATE_PARTITION_PRECLOSE); +} + +struct st_mysql_storage_engine tse_storage_engine = { + MYSQL_HANDLERTON_INTERFACE_VERSION}; + +static bool tse_get_tablespace_statistics( + const char *tablespace_name, const char *file_name, + const dd::Properties &ts_se_private_data, ha_tablespace_statistics *stats) { + UNUSED_PARAM(tablespace_name); + UNUSED_PARAM(file_name); + UNUSED_PARAM(ts_se_private_data); + UNUSED_PARAM(stats); + return true; +} + +EXTER_ATTACK bool tse_drop_database_with_err(handlerton *hton, char *path) { + THD *thd = current_thd; + assert(thd != nullptr); + + if (engine_ddl_passthru(thd)) { + return false; + } + + tianchi_handler_t tch; + int res = get_tch_in_handler_data(hton, thd, tch); + assert(res == 0); + + char db_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(path, db_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + int error_code = 0; + char error_message[ERROR_MESSAGE_LEN] = {0}; + /* tse_drop_tablespace_and_user接口内部新建session并自己释放 */ + string sql = string(thd->query().str).substr(0, thd->query().length); + int ret = tse_drop_tablespace_and_user( + &tch, db_name, sql.c_str(), + thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, &error_code, error_message); + update_sess_ctx_by_tch(tch, hton, thd); + tse_log_system("[TSE_DROP_DB]: ret:%d, database(%s), error_code:%d, error_message:%s", + ret, db_name, error_code, error_message); + if (ret != CT_SUCCESS) { + tse_log_error("drop database failed with error code: %d", convert_tse_error_code_to_mysql((ct_errno_t)ret)); + cm_assert(0); + } + return false; +} + +EXTER_ATTACK void tse_drop_database(handlerton *hton, char *path) { + (void)tse_drop_database_with_err(hton, path); +} + +static int tse_check_tx_isolation() { + // 检查GLOBAL变量 + enum_tx_isolation tx_isol = (enum_tx_isolation)global_system_variables.transaction_isolation; + if (tx_isol == ISO_SERIALIZABLE || tx_isol == ISO_READ_UNCOMMITTED) { + tse_log_error("TSE init failed. GLOBAL transaction isolation can not " + "be SERIALIZABLE and READ-UNCOMMITTED. Please check system variable or my.cnf file."); + return HA_ERR_INITIALIZATION; + } + + // 检查SESSION 变量 + THD *thd = current_thd; + if (thd && (thd->tx_isolation == ISO_SERIALIZABLE || thd->tx_isolation == ISO_READ_UNCOMMITTED)) { + tse_log_error("TSE init failed. SESSION transaction isolation can not " + "be SERIALIZABLE and READ-UNCOMMITTED. Please check system variable or my.cnf file."); + return HA_ERR_INITIALIZATION; + } + return 0; +} + +static int tse_create_db(THD *thd, handlerton *hton) { + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + + DBUG_EXECUTE_IF("core_before_create_tablespace_and_db", { assert(0); }); // 有锁的问题 + + string sql = string(thd->query().str).substr(0, thd->query().length); + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, tse_instance_id, tch.sql_command); + broadcast_req.options &= (~TSE_NOT_NEED_CANTIAN_EXECUTE); + int ret = tse_execute_mysql_ddl_sql(&tch, &broadcast_req, false); + + DBUG_EXECUTE_IF("core_after_create_tablespace_and_db", { assert(0); }); // 元数据不一致的问题 + tse_log_system("[TSE_BROARDCAST_CREATE_DB]:ret:%d, query:%s, user_name:%s, err_code:%d, broadcast_inst_id:%u, " + "conn_id:%u, tse_inst_id:%u", ret, broadcast_req.sql_str, broadcast_req.user_name, + broadcast_req.err_code, broadcast_req.mysql_inst_id, tch.thd_id, tch.inst_id); + update_sess_ctx_by_tch(tch, hton, thd); + assert(ret == CT_SUCCESS); + + return ret; +} + +bool tse_binlog_log_query_with_err(handlerton *hton, THD *thd, + enum_binlog_command binlog_command, + const char *query, uint query_length, + const char *db, const char *table_name) { + UNUSED_PARAM(query); + UNUSED_PARAM(query_length); + UNUSED_PARAM(db); + UNUSED_PARAM(table_name); + if (engine_ddl_passthru(thd)) { + return false; + } + + if (binlog_command == LOGCOM_CREATE_DB) { + return tse_create_db(thd, hton); + } + return false; +} + +void tse_binlog_log_query(handlerton *hton, THD *thd, + enum_binlog_command binlog_command, + const char *query, uint query_length, + const char *db, const char *table_name) { + (void)tse_binlog_log_query_with_err(hton, thd, binlog_command, query, query_length, db, table_name); +} + +/** Return 0 on success and non-zero on failure. +@param[in] hton the ctc handlerton +@param[in] thd the MySQL query thread of the caller +@param[in] stat_print print function +@param[in] stat_type status to show */ +static bool ctc_show_status(handlerton *, THD *thd, stat_print_fn *stat_print, enum ha_stat_type stat_type) { + if (stat_type == HA_ENGINE_STATUS) { + ctc_stats::get_instance().print_stats(thd, stat_print); + } + + return false; +} + +void tse_set_metadata_switch() { // MySQL为元数据归一版本 + lock_guard lock(m_tse_metadata_normalization_mutex); + if (ctc_metadata_normalization != (int32_t)metadata_switchs::DEFAULT) { + return; + } + bool cantian_metadata_switch = false; + bool cantian_cluster_ready = false; + int ret = tse_search_metadata_status(&cantian_metadata_switch, &cantian_cluster_ready); + if (ret != CT_SUCCESS || !cantian_cluster_ready) { + ctc_metadata_normalization = (int32_t)metadata_switchs::CLUSTER_NOT_READY; + tse_log_error("[tse_set_metadata_switch] tse_search_metadata_status failed with error code: %d, cantian_cluster_ready: %d", ret, cantian_cluster_ready); + return; + } + tse_log_system("[tse_set_metadata_switch] mysql_metadata_switch: 1, cantian_metadata_switch: %d, cantian_cluster_ready: %d", cantian_metadata_switch, cantian_cluster_ready); + ctc_metadata_normalization = cantian_metadata_switch ? (int32_t)metadata_switchs::MATCH_META : (int32_t)metadata_switchs::NOT_MATCH; +} + +int32_t tse_get_metadata_switch() { + if (ctc_metadata_normalization != (int32_t)metadata_switchs::DEFAULT) { + return ctc_metadata_normalization; + } + + lock_guard lock(m_tse_metadata_normalization_mutex); + if (ctc_metadata_normalization != (int32_t)metadata_switchs::DEFAULT) { + return ctc_metadata_normalization; + } + bool mysql_metadata_switch = CHECK_HAS_MEMBER(handlerton, get_metadata_switch); + bool cantian_metadata_switch = false; + bool cantian_cluster_ready = false; + int ret = tse_search_metadata_status(&cantian_metadata_switch, &cantian_cluster_ready); + if (ret != CT_SUCCESS || !cantian_cluster_ready) { + ctc_metadata_normalization = (int32_t)metadata_switchs::CLUSTER_NOT_READY; + tse_log_error("[tse_get_metadata_switch] tse_search_metadata_status failed with error code: %d, cantian_metadata_switch: %d, cantian_cluster_ready: %d", ret, cantian_metadata_switch, cantian_cluster_ready); + return ctc_metadata_normalization; + } + tse_log_system("[tse_get_metadata_switch] cantian_metadata_switch: %d, cantian_cluster_ready: %d", cantian_metadata_switch, cantian_cluster_ready); + ctc_metadata_normalization = (mysql_metadata_switch == cantian_metadata_switch) ? (mysql_metadata_switch ? (int32_t)metadata_switchs::MATCH_META : (int32_t)metadata_switchs::MATCH_NO_META) : (int32_t)metadata_switchs::NOT_MATCH; + + return ctc_metadata_normalization; +} + + +/** + Check metadata init status in CTC. +*/ +static int tse_get_metadata_status() { + DBUG_TRACE; + + bool is_exists; + int ret = 0; + + ct_errno_t begin = (ct_errno_t)tse_check_db_table_exists("mysql", "", &is_exists); + if (begin != CT_SUCCESS) { + tse_log_error("check metadata init start failed with error code: %d", begin); + return convert_tse_error_code_to_mysql(begin); + } + ret = is_exists ? 1 : 0; + + ct_errno_t end = (ct_errno_t)tse_check_db_table_exists("sys", "sys_config", &is_exists); + if (end != CT_SUCCESS) { + tse_log_error("check metadata init end failed with error code: %d", end); + return convert_tse_error_code_to_mysql(end); + } + ret = is_exists ? 2 : ret; + + return ret; +} + +static int tse_init_tablespace(List *tablespaces) +{ + DBUG_TRACE; + const size_t len = 30 + sizeof("id=;flags=;server_version=;space_version=;state=normal"); + const char *fmt = "id=%u;flags=%u;server_version=%u;space_version=%u;state=normal"; + static char se_private_data_dd[len]; + snprintf(se_private_data_dd, len, fmt, 8, 0, 0, 0); + + static Plugin_tablespace dd_space((const char *)"mysql", "", se_private_data_dd, "", (const char *)"CTC"); + static Plugin_tablespace::Plugin_tablespace_file dd_file((const char *)"mysql.ibd", ""); + dd_space.add_file(&dd_file); + tablespaces->push_back(&dd_space); + return 0; +} + +static bool tse_ddse_dict_init( + dict_init_mode_t dict_init_mode, uint version, + List *tables, + List *tablespaces) { + DBUG_TRACE; + tse_log_system("[CTC_INIT]:begin init!"); + + assert(tables && tables->is_empty()); + assert(tablespaces && tablespaces->is_empty()); + assert(dict_init_mode == DICT_INIT_CREATE_FILES || dict_init_mode == DICT_INIT_CHECK_FILES); + assert(version < 1000000000); + + if (tse_init_tablespace(tablespaces)) { + return true; + } + + /* Instantiate table defs only if we are successful so far. */ + dd::Object_table *innodb_dynamic_metadata = + dd::Object_table::create_object_table(); + innodb_dynamic_metadata->set_hidden(true); + dd::Object_table_definition *def = + innodb_dynamic_metadata->target_table_definition(); + def->set_table_name("innodb_dynamic_metadata"); + def->add_field(0, "table_id", "table_id BIGINT UNSIGNED NOT NULL"); + def->add_field(1, "version", "version BIGINT UNSIGNED NOT NULL"); + def->add_field(2, "metadata", "metadata BLOB NOT NULL"); + def->add_index(0, "index_pk", "PRIMARY KEY (table_id)"); + /* Options and tablespace are set at the SQL layer. */ + + /* Changing these values would change the specification of innodb statistics + tables. */ + static constexpr size_t DB_NAME_FIELD_SIZE = 64; + static constexpr size_t TABLE_NAME_FIELD_SIZE = 199; + + /* Set length for database name field. */ + std::ostringstream db_name_field; + db_name_field << "database_name VARCHAR(" << DB_NAME_FIELD_SIZE + << ") NOT NULL"; + std::string db_field = db_name_field.str(); + + /* Set length for table name field. */ + std::ostringstream table_name_field; + table_name_field << "table_name VARCHAR(" << TABLE_NAME_FIELD_SIZE + << ") NOT NULL"; + std::string table_field = table_name_field.str(); + + dd::Object_table *innodb_table_stats = + dd::Object_table::create_object_table(); + innodb_table_stats->set_hidden(false); + def = innodb_table_stats->target_table_definition(); + def->set_table_name("innodb_table_stats"); + def->add_field(0, "database_name", db_field.c_str()); + def->add_field(1, "table_name", table_field.c_str()); + def->add_field(2, "last_update", + "last_update TIMESTAMP NOT NULL \n" + " DEFAULT CURRENT_TIMESTAMP \n" + " ON UPDATE CURRENT_TIMESTAMP"); + def->add_field(3, "n_rows", "n_rows BIGINT UNSIGNED NOT NULL"); + def->add_field(4, "clustered_index_size", + "clustered_index_size BIGINT UNSIGNED NOT NULL"); + def->add_field(5, "sum_of_other_index_sizes", + "sum_of_other_index_sizes BIGINT UNSIGNED NOT NULL"); + def->add_index(0, "index_pk", "PRIMARY KEY (database_name, table_name)"); + /* Options and tablespace are set at the SQL layer. */ + + dd::Object_table *innodb_index_stats = + dd::Object_table::create_object_table(); + innodb_index_stats->set_hidden(false); + def = innodb_index_stats->target_table_definition(); + def->set_table_name("innodb_index_stats"); + def->add_field(0, "database_name", db_field.c_str()); + def->add_field(1, "table_name", table_field.c_str()); + def->add_field(2, "index_name", "index_name VARCHAR(64) NOT NULL"); + def->add_field(3, "last_update", + "last_update TIMESTAMP NOT NULL" + " DEFAULT CURRENT_TIMESTAMP" + " ON UPDATE CURRENT_TIMESTAMP"); + /* + There are at least: stat_name='size' + stat_name='n_leaf_pages' + stat_name='n_diff_pfx%' + */ + def->add_field(4, "stat_name", "stat_name VARCHAR(64) NOT NULL"); + def->add_field(5, "stat_value", "stat_value BIGINT UNSIGNED NOT NULL"); + def->add_field(6, "sample_size", "sample_size BIGINT UNSIGNED"); + def->add_field(7, "stat_description", + "stat_description VARCHAR(1024) NOT NULL"); + def->add_index(0, "index_pk", + "PRIMARY KEY (database_name, table_name, " + "index_name, stat_name)"); + /* Options and tablespace are set at the SQL layer. */ + + dd::Object_table *innodb_ddl_log = dd::Object_table::create_object_table(); + innodb_ddl_log->set_hidden(true); + def = innodb_ddl_log->target_table_definition(); + def->set_table_name("innodb_ddl_log"); + def->add_field(0, "id", "id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT"); + def->add_field(1, "thread_id", "thread_id BIGINT UNSIGNED NOT NULL"); + def->add_field(2, "type", "type INT UNSIGNED NOT NULL"); + def->add_field(3, "space_id", "space_id INT UNSIGNED"); + def->add_field(4, "page_no", "page_no INT UNSIGNED"); + def->add_field(5, "index_id", "index_id BIGINT UNSIGNED"); + def->add_field(6, "table_id", "table_id BIGINT UNSIGNED"); + def->add_field(7, "old_file_path", + "old_file_path VARCHAR(512) COLLATE UTF8_BIN"); + def->add_field(8, "new_file_path", + "new_file_path VARCHAR(512) COLLATE UTF8_BIN"); + def->add_index(0, "index_pk", "PRIMARY KEY(id)"); + def->add_index(1, "index_k_thread_id", "KEY(thread_id)"); + /* Options and tablespace are set at the SQL layer. */ + + tables->push_back(innodb_dynamic_metadata); + tables->push_back(innodb_table_stats); + tables->push_back(innodb_index_stats); + tables->push_back(innodb_ddl_log); + + tse_log_system("[CTC_INIT]:end init dict!"); + + return false; +} + +/** Set of ids of DD tables */ +static set s_dd_table_ids; + +static bool is_dd_table_id(uint16_t id) { + DBUG_TRACE; + return (s_dd_table_ids.find(id) != s_dd_table_ids.end()); +} + +static void tse_dict_register_dd_table_id(dd::Object_id dd_table_id) { + DBUG_TRACE; + s_dd_table_ids.insert(dd_table_id); + return; +} + +static bool tse_dict_recover(dict_recovery_mode_t dict_recovery_mode, uint version){ + DBUG_TRACE; + switch (dict_recovery_mode) { + case DICT_RECOVERY_INITIALIZE_SERVER: + return false; + case DICT_RECOVERY_INITIALIZE_TABLESPACES: + return false; + case DICT_RECOVERY_RESTART_SERVER: + return false; + } + assert(version < 0xFFFFFFFF); + return false; +} + +static bool tse_dict_get_server_version(uint *version) { + DBUG_TRACE; + *version = MYSQL_VERSION_ID; + return false; +} + +static bool tse_dict_set_server_version() { + DBUG_TRACE; + return false; +} + +static void tse_dict_cache_reset(const char *, const char *) { + DBUG_TRACE; + return; +} + +static void tse_dict_cache_reset_tables_and_tablespaces() { + DBUG_TRACE; + return; +} + +static int tse_op_before_load_meta(THD *thd) { + bool need_forward = true; + return tse_check_lock_instance(thd, need_forward); +} + +static int tse_op_after_load_meta(THD *thd) { + return tse_check_unlock_instance(thd); +} + +static bool tse_dict_readonly() { + return false; +} + +template +static typename std::enable_if::type set_hton_members(T *tse_hton) { + tse_hton->get_inst_id = ha_tse_get_inst_id; + tse_hton->get_metadata_switch = tse_get_metadata_switch; + tse_hton->set_metadata_switch = tse_set_metadata_switch; + tse_hton->get_metadata_status = tse_get_metadata_status; + tse_hton->op_before_load_meta = tse_op_before_load_meta; + tse_hton->op_after_load_meta = tse_op_after_load_meta; + tse_hton->drop_database = tse_drop_database_with_err; + tse_hton->binlog_log_query = tse_binlog_log_query_with_err; +} + +template +static typename std::enable_if::type set_hton_members(T *tse_hton) { + tse_hton->drop_database = tse_drop_database; + tse_hton->binlog_log_query = tse_binlog_log_query; +} + +extern int (*tse_init)(); +extern int (*tse_deinit)(); + +static int tse_init_func(void *p) { + DBUG_TRACE; + tse_hton = (handlerton *)p; + tse_hton->state = SHOW_OPTION_YES; + tse_hton->db_type = (legacy_db_type)30; + tse_hton->create = tse_create_handler; + tse_hton->is_supported_system_table = tse_is_supported_system_table; + tse_hton->check_fk_column_compat = tse_check_fk_column_compat; + tse_hton->commit = tse_commit; + tse_hton->rollback = tse_rollback; + tse_hton->savepoint_set = tse_set_savepoint; + tse_hton->savepoint_rollback = tse_rollback_savepoint; + tse_hton->savepoint_release = tse_release_savepoint; + tse_hton->close_connection = tse_close_connect; + tse_hton->kill_connection = tse_kill_connection; + tse_hton->notify_exclusive_mdl = tse_notify_exclusive_mdl; + tse_hton->start_consistent_snapshot = tse_start_trx_and_assign_scn; + tse_hton->partition_flags = tse_partition_flags; + tse_hton->flags = HTON_SUPPORTS_FOREIGN_KEYS | HTON_CAN_RECREATE | HTON_SUPPORTS_ATOMIC_DDL; + // TODO: HTON_SUPPORTS_TABLE_ENCRYPTION 表空间 tablespace加密功能暂时不做支持,后面会考虑添加。 + tse_hton->foreign_keys_flags = HTON_FKS_WITH_PREFIX_PARENT_KEYS | + HTON_FKS_NEED_DIFFERENT_PARENT_AND_SUPPORTING_KEYS | + HTON_FKS_WITH_EXTENDED_PARENT_KEYS; + tse_hton->alter_tablespace = tsebase_alter_tablespace; + tse_hton->file_extensions = nullptr; + tse_hton->get_tablespace_statistics = tse_get_tablespace_statistics; + tse_hton->show_status = ctc_show_status; + tse_hton->ddse_dict_init = tse_ddse_dict_init; + tse_hton->dict_register_dd_table_id = tse_dict_register_dd_table_id; + tse_hton->dict_recover = tse_dict_recover; + tse_hton->dict_get_server_version = tse_dict_get_server_version; + tse_hton->dict_set_server_version = tse_dict_set_server_version; + tse_hton->dict_cache_reset = tse_dict_cache_reset; + tse_hton->dict_cache_reset_tables_and_tablespaces = tse_dict_cache_reset_tables_and_tablespaces; + tse_hton->is_dict_readonly = tse_dict_readonly; + set_hton_members(tse_hton); + + if (strcmp(MYSQL_SERVER_VERSION, "8.0.26") != 0) { + tse_log_error("[CTC_INIT]:server version mismatch, expected v8.0.26, but current v%s, CTC plugin register failed!", + MYSQL_SERVER_VERSION); + return HA_ERR_INITIALIZATION; + } + + int ret = tse_init(); + if (ret != 0) { + tse_log_error("[CTC_INIT]: ctc storage engine plugin init failed:%d", ret); + return HA_ERR_INITIALIZATION; + } + + // 元数据归一流程初始化下发参天 + // 主干非initialize_insecure模式,需要注册共享内存接收线程并等待参天启动完成 + if (!opt_initialize_insecure || CHECK_HAS_MEMBER(handlerton, get_inst_id)) { + ret = srv_wait_instance_startuped(); + if (ret != 0) { + tse_log_error("wait cantian instance startuped failed:%d", ret); + return HA_ERR_INITIALIZATION; + } + + ret = tse_reg_instance(); + if (ret != 0) { + tse_log_error("[CTC_INIT]:ctc_reg_instance failed:%d", ret); + return HA_ERR_INITIALIZATION; + } + } + + ret = tse_check_tx_isolation(); + if (ret != 0) { + tse_log_error("[CTC_INIT]:ctc_check_tx_isolation failed:%d", ret); + return HA_ERR_INITIALIZATION; + } + + tse_log_system("[CTC_INIT]:SUCCESS!"); + return 0; +} + +static int tse_deinit_func(void *p) { + // handler.cc:726 此处传的p固定为null, 不是handlerton,不能依赖这部分逻辑 + UNUSED_PARAM(p); + tse_log_system( + "tse_deinit_func tse_ddl_req_msg_mem_use_heap_cnt:%u, " + "tse_ddl_req_msg_mem_max_size:%u.", + (uint32_t)tse_ddl_stack_mem::tse_ddl_req_msg_mem_use_heap_cnt, + (uint32_t)tse_ddl_stack_mem::tse_ddl_req_msg_mem_max_size); + tse_unreg_instance(); + return tse_deinit(); +} + +static SHOW_VAR tse_status[] = { + {nullptr, nullptr, SHOW_UNDEF, SHOW_SCOPE_UNDEF}}; + +extern struct st_mysql_plugin g_tse_ddl_rewriter_plugin; + +const char *tse_hton_name = "CTC"; + +#pragma GCC visibility push(default) + +mysql_declare_plugin(ctc) g_tse_ddl_rewriter_plugin,{ + MYSQL_STORAGE_ENGINE_PLUGIN, + &tse_storage_engine, + tse_hton_name, + PLUGIN_AUTHOR_ORACLE, + "CTC storage engine", + PLUGIN_LICENSE_GPL, + tse_init_func, + nullptr, + tse_deinit_func, + CTC_CLIENT_VERSION_NUMBER, + tse_status, + tse_system_variables, + nullptr, + PLUGIN_OPT_ALLOW_EARLY, +} mysql_declare_plugin_end; + +#pragma GCC visibility pop + +void ha_tse::update_create_info(HA_CREATE_INFO *create_info) { + if ((create_info->used_fields & HA_CREATE_USED_AUTO) || !table->found_next_number_field) { + return; + } + + THD* thd = ha_thd(); + if (engine_ddl_passthru(thd) && is_create_table_check(thd)) { + return; + } + + int ret = 0; + if (m_tch.ctx_addr == INVALID_VALUE64) { + char user_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(table->s->normalized_path.str, user_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(user_name, user_name, SMALL_RECORD_SIZE); + update_member_tch(m_tch, tse_hton, thd); + ret = tse_open_table(&m_tch, table->s->table_name.str, user_name); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + if (ret != 0) { + create_info->auto_increment_value = (ulonglong)0; + } + } + + uint64_t inc_value = 0; + uint16_t auto_inc_step = thd->variables.auto_increment_increment; + uint16_t auto_inc_offset = thd->variables.auto_increment_offset; + update_member_tch(m_tch, tse_hton, thd); + dml_flag_t flag; + flag.auto_inc_offset = auto_inc_offset; + flag.auto_inc_step = auto_inc_step; + flag.auto_increase = false; + ret = tse_get_serial_value(&m_tch, &inc_value, flag); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + if (ret != 0) { + create_info->auto_increment_value = (ulonglong)0; + } else { + create_info->auto_increment_value = (ulonglong)inc_value; + stats.auto_increment_value = (ulonglong)inc_value; + } + +} + +/** + @brief + Used to delete a table. By the time delete_table() has been called all + opened references to this table will have been closed (and your globally + shared references released). The variable name will just be the name of + the table. You will need to remove any files you have created at this point. + + @details + If you do not implement this, the default delete_table() is called from + handler.cc and it will delete all files with the file extensions from + handlerton::file_extensions. + + Called from handler.cc by delete_table and ha_create_table(). Only used + during create if the table_flag HA_DROP_BEFORE_CREATE was specified for + the storage engine. + + @see + delete_table and ha_create_table() in handler.cc +*/ +EXTER_ATTACK int ha_tse::delete_table(const char *full_path_name, const dd::Table *table_def) { + THD *thd = ha_thd(); + ct_errno_t ret = CT_SUCCESS; + + if (engine_ddl_passthru(thd)) { + if (thd->locked_tables_mode) { + for (const dd::Foreign_key_parent *parent_fk : table_def->foreign_key_parents()) { + close_all_tables_for_name(thd, parent_fk->child_schema_name().c_str(), parent_fk->child_table_name().c_str(), true); + } + } + return ret; + } + + /* 删除db时 会直接删除参天用户 所有表也会直接被删除 无需再次下发 */ + if (thd->lex->sql_command == SQLCOM_DROP_DB) { + return ret; + } + + if (table_def != nullptr && table_def->is_persistent()) { + tse_register_trx(ht, thd); + } + + update_member_tch(m_tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + tse_ddl_stack_mem stack_mem(0); + int mysql_ret = fill_delete_table_req(full_path_name, table_def, thd, &ddl_ctrl, &stack_mem); + if (mysql_ret != CT_SUCCESS) { + return mysql_ret; + } + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + tse_log_note("tse_drop_table enter"); + ret = (ct_errno_t)tse_drop_table(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_log_note("tse_drop_table finish"); + tse_ddl_hook_cantian_error("tse_drop_table_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + return tse_ddl_handle_fault("tse_drop_table", thd, &ddl_ctrl, ret, full_path_name, HA_ERR_WRONG_TABLE_NAME); +} +static map> + g_tse_ddl_ignore_cantian_errors = { + {"tse_create_table_cantian_error", {ERR_DUPLICATE_TABLE}}, // 创建表,自动忽略参天表已经存在的错误 + {"tse_drop_table_cantian_error", {ERR_TABLE_OR_VIEW_NOT_EXIST}}, // 删除表,自动忽略参天表不存在的错误 + {"tse_rename_table_cantian_error", {ERR_TABLE_OR_VIEW_NOT_EXIST}}, // rename表,自动忽略参天表不存在的错误 + {"tse_alter_table_cantian_error", {ERR_OBJECT_EXISTS,ERR_COLUMN_NOT_EXIST}}}; + +void tse_ddl_hook_cantian_error(const char *tag, THD *thd, ddl_ctrl_t *ddl_ctrl, + ct_errno_t *ret) { + bool ignore_error = false; + + DBUG_EXECUTE_IF(tag, { + ignore_error = true; + *ret = (ct_errno_t)(*ret == 0 ? -1 : *ret); + }); + + if (!ignore_error) { + return; + } + + auto st = g_tse_ddl_ignore_cantian_errors.find(tag); + if (*ret != 0 && st != g_tse_ddl_ignore_cantian_errors.end() && st->second.count(*ret) > 0) { + tse_log_system( + "tag:%s cantian ret:%d ignore by ignore_cantian_error_code, " + "sql:%s, table_name:%s, error_message:%s", + tag, *ret, thd->query().str, thd->lex->query_tables->table_name, + ddl_ctrl->error_msg); + *ret = (ct_errno_t)0; + } +} +int tse_ddl_handle_fault(const char *tag, const THD *thd, + const ddl_ctrl_t *ddl_ctrl, ct_errno_t ret, + const char *param, int fix_ret) { + if (ret != CT_SUCCESS) { + tse_log_system("[TSE_DDL_RES]:tag ret:%d, msg_len:%u, sql:%s, param:%s, error_message:%s", + ret, (uint32_t)(ddl_ctrl->msg_len), thd->query().str, param == nullptr ? "" : + param, ddl_ctrl->error_msg); + RETURN_IF_OOM(ret); + int32_t error = convert_tse_error_code_to_mysql(ret); + if (error != HA_ERR_GENERIC) { + return error; + } else if (strlen(ddl_ctrl->error_msg) > 0) { + tse_print_cantian_err_msg(ddl_ctrl, ret); + } else { + my_error(ER_DISALLOWED_OPERATION, MYF(0), UN_SUPPORT_DDL, thd->query().str); + } + if (fix_ret != 0) { + return fix_ret; + } + return error; + } else { + tse_log_system("[TSE_DDL_RES]:%s success, ret: %d, sql:%s", tag, ret, thd->query().str); + return ret; + } +} + + /** + @brief + create() is called to create a table. The variable name will have the name + of the table. + + @details + When create() is called you do not need to worry about + opening the table. Also, the .frm file will have already been + created so adjusting create_info is not necessary. You can overwrite + the .frm file at this point if you wish to change the table + definition, but there are no methods currently provided for doing + so. + + Called from handle.cc by ha_create_table(). + + @see + ha_create_table() in handle.cc + */ + /** + Create table (implementation). + + @param [in] name Table name. + @param [in] form TABLE object describing the table to be + created. + @param [in] info HA_CREATE_INFO describing table. + @param [in,out] table_def dd::Table object describing the table + to be created. This object can be + adjusted by storage engine if it + supports atomic DDL (i.e. has + HTON_SUPPORTS_ATOMIC_DDL flag set). + These changes will be persisted in the + data-dictionary. Can be NULL for + temporary tables created by optimizer. + + @retval 0 Success. + @retval non-0 Error. + */ +EXTER_ATTACK int ha_tse::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info, + dd::Table *table_def) { + THD *thd = ha_thd(); + ct_errno_t ret = CT_SUCCESS; + if (check_unsupported_operation(thd, create_info)) { + tse_log_system("Unsupported operation. sql = %s", thd->query().str); + return HA_ERR_WRONG_COMMAND; + } + + /* + copy algorithm is used when ha_create is called by mysql_alter_table + */ + bool is_tmp_table = create_info->options & HA_LEX_CREATE_TMP_TABLE || tse_is_temporary(table_def); + if (thd->lex->sql_command != SQLCOM_CREATE_TABLE && thd->lex->sql_command != SQLCOM_CREATE_VIEW + && thd->lex->alter_info) { + if (is_tmp_table) { + tse_log_system("Unsupported operation. sql = %s", thd->query().str); + return HA_ERR_NOT_ALLOWED_COMMAND; + } + // do not move this under engine_ddl_passthru(thd) function + thd->lex->alter_info->requested_algorithm = Alter_info::ALTER_TABLE_ALGORITHM_COPY; + } + + if (engine_ddl_passthru(thd)) { + return ret; + } + + char db_name[SMALL_RECORD_SIZE] = {0}; + char table_name[SMALL_RECORD_SIZE] = {0}; + tse_split_normalized_name(name, db_name, SMALL_RECORD_SIZE, table_name, SMALL_RECORD_SIZE, &is_tmp_table); + if (!is_tmp_table) { + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(table_def->name().c_str())); + tse_copy_name(table_name, const_cast(table_def->name().c_str()), SMALL_RECORD_SIZE); + } + + if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { + tse_register_trx(ht, thd); + } + + if (thd->lex->sql_command == SQLCOM_TRUNCATE) { + return ha_tse_truncate_table(&m_tch, thd, db_name, table_name, is_tmp_table); + } + + if (get_cantian_record_length(form) > CT_MAX_RECORD_LENGTH) { + return HA_ERR_TOO_BIG_ROW; + } + + tse_ddl_stack_mem stack_mem(0); + update_member_tch(m_tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + + if (is_alter_table_copy(thd)) { + ddl_ctrl.is_alter_copy = true; + } + + uint32_t table_flags = 0; + if (is_tmp_table) { + table_flags |= TSE_TMP_TABLE; + if (create_info->options & HA_LEX_CREATE_INTERNAL_TMP_TABLE) { + table_flags |= TSE_INTERNAL_TMP_TABLE; + } + ddl_ctrl.table_flags = table_flags; + } + ret = (ct_errno_t)fill_create_table_req(create_info, table_def, db_name, table_name, form, thd, &ddl_ctrl, &stack_mem); + if (ret != CT_SUCCESS) { + return ret; + } + + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + ret = (ct_errno_t)tse_create_table(tse_ddl_req_msg_mem, &ddl_ctrl); + if (ret == ERR_FUNCTION_NOT_EXIST) { + char *err_msg; + char *field_name = strtok_r(ddl_ctrl.error_msg, ",", &err_msg); + char *func_name = strtok_r(NULL, ",", &err_msg); + if (func_name) { + // func_name非空的情况对应default function + my_error(ER_DEFAULT_VAL_GENERATED_NAMED_FUNCTION_IS_NOT_ALLOWED, MYF(0), + field_name, func_name); + return CT_ERROR; + } + } + tse_ddl_hook_cantian_error("tse_create_table_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + return tse_ddl_handle_fault("tse_create_table", thd, &ddl_ctrl, ret); +} + +/** Implementation of inplace_alter_table() +@tparam Table dd::Table or dd::Partition +@param[in] altered_table TABLE object for new version of table. +@param[in,out] ha_alter_info Structure describing changes to be done + by ALTER TABLE and holding data used + during in-place alter. +@param[in] old_dd_tab dd::Table object describing old version + of the table. +@param[in,out] new_dd_tab dd::Table object for the new version of the + table. Can be adjusted by this call. + Changes to the table definition will be + persisted in the data-dictionary at statement + commit time. +@retval true Failure +@retval false Success +*/ +bool ha_tse::inplace_alter_table(TABLE *altered_table, + Alter_inplace_info *ha_alter_info, + const dd::Table *old_table_def, + dd::Table *new_table_def) +{ + if (old_table_def == nullptr || new_table_def == nullptr) { + tse_log_error( + "inplace_alter_table old_table_def:%p, or new_table_def:%p is NULL", + old_table_def, new_table_def); + return true; + } + + THD *thd = ha_thd(); + Alter_info *alter_info = ha_alter_info->alter_info; + ct_errno_t ret = CT_SUCCESS; + + if (check_unsupported_operation(thd, nullptr)) { + tse_log_system("Unsupported operation. sql = %s", thd->query().str); + return true; + } + + if (get_cantian_record_length(altered_table) > CT_MAX_RECORD_LENGTH) { + return true; + } + /* Nothing to commit/rollback, mark all handlers committed! */ + ha_alter_info->group_commit_ctx = nullptr; + + if (engine_ddl_passthru(thd)) { + return false; + } + + tse_ddl_stack_mem stack_mem(0); + update_member_tch(m_tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + if (alter_info->flags & Alter_info::ALTER_RECREATE) { + ret = (ct_errno_t)fill_rebuild_index_req(altered_table, thd, &ddl_ctrl, &stack_mem); + } else { + ret = (ct_errno_t)fill_alter_table_req( + altered_table, ha_alter_info, old_table_def, new_table_def, thd, + &ddl_ctrl, &stack_mem); + } + if (ret != CT_SUCCESS) { + return true; + } + + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return true; + } + tse_register_trx(ht, thd); + ret = (ct_errno_t)tse_alter_table(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_ddl_hook_cantian_error("tse_alter_table_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + tse_ddl_handle_fault("tse_alter_table", thd, &ddl_ctrl, ret); + // 这个地方alter table需要特殊处理返回值 + if (ret != CT_SUCCESS) { + tse_alter_table_handle_fault(ret); + return true; + } + + return false; +} + +/** + @brief + + Renames a table from one name to another via an alter table call. + + @details + If you do not implement this, the default rename_table() is called from + handler.cc and it will delete all files with the file extensions from + handlerton::file_extensions. + + Called from sql_table.cc by mysql_rename_table(). + + @see + mysql_rename_table() in sql_table.cc +*/ +EXTER_ATTACK int ha_tse::rename_table(const char *from, const char *to, + const dd::Table *from_table_def, + dd::Table *to_table_def) { + THD *thd = ha_thd(); + ct_errno_t ret = CT_SUCCESS; + + if (engine_ddl_passthru(thd)) { + return false; + } + + if (is_dd_table_id(to_table_def->se_private_id())) { + my_error(ER_NOT_ALLOWED_COMMAND, MYF(0)); + return HA_ERR_UNSUPPORTED; + } + + tse_ddl_stack_mem stack_mem(0); + update_member_tch(m_tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + if (is_alter_table_copy(thd)) { + ddl_ctrl.is_alter_copy = true; + } + + ret = (ct_errno_t)fill_rename_table_req(from, to, from_table_def, to_table_def, thd, &ddl_ctrl, &stack_mem); + if (ret != CT_SUCCESS) { + return ret; + } + + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + tse_register_trx(ht, thd); + ret = (ct_errno_t)tse_rename_table(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_ddl_hook_cantian_error("tse_rename_table_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + return tse_ddl_handle_fault("tse_rename_table", thd, &ddl_ctrl, ret, to); +} + +int ha_tse::check(THD *, HA_CHECK_OPT *) +{ + return HA_ADMIN_OK; +} + +bool ha_tse::get_error_message(int error, String *buf) +{ + if (error == HA_ERR_ROW_IS_REFERENCED) { + buf->append(STRING_WITH_LEN("Record is referenced by child tables(")); + for (uint i = 0; i < table->s->foreign_key_parents; i++) { + buf->append(table->s->foreign_key_parent[i].referencing_table_db); + buf->append(STRING_WITH_LEN(".")); + buf->append(table->s->foreign_key_parent[i].referencing_table_name); + if (i != table->s->foreign_key_parents - 1) + buf->append(STRING_WITH_LEN(", ")); + } + buf->append(STRING_WITH_LEN(")")); + return false; + } + if (error == HA_ERR_NO_REFERENCED_ROW){ + buf->append(STRING_WITH_LEN("Referenced key value not found in parent tables(")); + for (uint i = 0; i < table->s->foreign_keys; i++) { + buf->append(table->s->foreign_key[i].referenced_table_db); + buf->append(STRING_WITH_LEN(".")); + buf->append(table->s->foreign_key[i].referenced_table_name); + if (i != table->s->foreign_keys - 1) + buf->append(STRING_WITH_LEN(", ")); + } + buf->append(STRING_WITH_LEN(")")); + } + return false; +} + +tse_select_mode_t ha_tse::get_select_mode() +{ + /* Set select mode for SKIP LOCKED / NOWAIT */ + if (table->pos_in_table_list == nullptr) { + return SELECT_ORDINARY; + } + tse_select_mode_t mode; + switch (table->pos_in_table_list->lock_descriptor().action) { + case THR_SKIP: + mode = SELECT_SKIP_LOCKED; + break; + case THR_NOWAIT: + mode = SELECT_NOWAIT; + break; + default: + mode = SELECT_ORDINARY; + break; + } + return mode; +} + +int ha_tse::initialize_cbo_stats() +{ + if (!m_share || m_share->cbo_stats != nullptr) { + return CT_SUCCESS; + } + m_share->cbo_stats = (tianchi_cbo_stats_t*)tse_alloc_buf(&m_tch, sizeof(tianchi_cbo_stats_t)); + if (m_share->cbo_stats == nullptr) { + tse_log_error("alloc shm mem failed, m_share->cbo_stats size(%lu)", sizeof(tianchi_cbo_stats_t)); + return ERR_ALLOC_MEMORY; + } + *m_share->cbo_stats = {0, 0, 0, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, 0, 0, 0, 0,{}}; + m_share->cbo_stats->tse_cbo_stats_table.num_distincts = + (uint32_t *)tse_alloc_buf(&m_tch, table->s->fields * sizeof(uint32_t)); + + m_share->cbo_stats->tse_cbo_stats_table.low_values = + (cache_variant_t *)tse_alloc_buf(&m_tch, table->s->fields * sizeof(cache_variant_t)); + + m_share->cbo_stats->tse_cbo_stats_table.high_values = + (cache_variant_t *)tse_alloc_buf(&m_tch, table->s->fields * sizeof(cache_variant_t)); + + if (m_share->cbo_stats->tse_cbo_stats_table.num_distincts == nullptr + || m_share->cbo_stats->tse_cbo_stats_table.low_values == nullptr + || m_share->cbo_stats->tse_cbo_stats_table.high_values == nullptr) { + tse_log_error("alloc shm mem error, size(%lu)", + table->s->fields * sizeof(uint32_t) + 2 * table->s->fields * sizeof(cache_variant_t)); + free_cbo_stats(); + return ERR_ALLOC_MEMORY; + } + + return CT_SUCCESS; +} + +int ha_tse::get_cbo_stats_4share() +{ + THD *thd = ha_thd(); + int ret = CT_SUCCESS; + time_t now = time(nullptr); + if (m_share && (m_share->need_fetch_cbo || now - m_share->get_cbo_time > 60)) { + if (m_tch.ctx_addr == INVALID_VALUE64) { + char user_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(table->s->normalized_path.str, user_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(user_name, user_name, SMALL_RECORD_SIZE); + update_member_tch(m_tch, tse_hton, thd); + ret = tse_open_table(&m_tch, table->s->table_name.str, user_name); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + if (ret != CT_SUCCESS) { + return ret; + } + } + update_member_tch(m_tch, tse_hton, thd); + ret = tse_get_cbo_stats(&m_tch, m_share->cbo_stats); + update_sess_ctx_by_tch(m_tch, tse_hton, thd); + if (ret == CT_SUCCESS && m_share->cbo_stats->is_updated) { + m_share->need_fetch_cbo = false; + } + m_share->get_cbo_time = now; + } + + return ret; +} + +void ha_tse::free_cbo_stats() +{ + if (!m_share || m_share->cbo_stats == nullptr) { + return; + } + + if (m_share->cbo_stats->tse_cbo_stats_table.num_distincts != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_share->cbo_stats->tse_cbo_stats_table.num_distincts); + m_share->cbo_stats->tse_cbo_stats_table.num_distincts = nullptr; + } + + if (m_share->cbo_stats->tse_cbo_stats_table.low_values != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_share->cbo_stats->tse_cbo_stats_table.low_values); + m_share->cbo_stats->tse_cbo_stats_table.low_values = nullptr; + } + + if (m_share->cbo_stats->tse_cbo_stats_table.high_values != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_share->cbo_stats->tse_cbo_stats_table.high_values); + m_share->cbo_stats->tse_cbo_stats_table.high_values = nullptr; + } + + tse_free_buf(&m_tch, (uchar *) m_share->cbo_stats); + m_share->cbo_stats = nullptr; + +} + +/** + Condition pushdown for update/delete + @param cond Condition to be pushed down. + @param other_tbls_ok Are other tables allowed to be referred + from the condition terms pushed down. + + @retval Return the 'remainder' condition, consisting of the AND'ed + sum of boolean terms which could not be pushed. A nullptr + is returned if entire condition was supported. +*/ + +const Item *ha_tse::cond_push(const Item *cond, bool other_tbls_ok MY_ATTRIBUTE((unused))) +{ + assert(pushed_cond == nullptr); + assert(cond != nullptr); + const Item *remainder; + remainder = cond; + return remainder; +} + +/** + Condition pushdown + Push a condition to ctc storage engine for evaluation + during table and index scans. The conditions will be cleared + by calling handler::extra(HA_EXTRA_RESET) or handler::reset(). + + The current implementation supports arbitrary AND/OR nested conditions + with comparisons between columns and constants (including constant + expressions and function calls) and the following comparison operators: + =, !=, >, >=, <, <=, "is null", and "is not null". + + If the condition consist of multiple AND/OR'ed 'boolean terms', + parts of it may be pushed, and other parts will be returned as a + 'remainder condition', which the server has to evaluate. + + handler::pushed_cond will be assigned the (part of) the condition + which we accepted to be pushed down. + + Note that this handler call has been partly deprecated by + ::engine_push() which does both join- and condition pushdown. + The only remaining intended usage for ::cond_push() is simple + update and delete queries, where the join part is not relevant. + * @param table_aqp The specific table in the join plan to examine. + * @return Possible error code, '0' if no errors. + */ +int ha_tse::engine_push(AQP::Table_access *table_aqp) +{ + DBUG_TRACE; + const Item *cond = table_aqp->get_condition(); + assert(m_cond == nullptr); + + THD *const thd = table->in_use; + if (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN)) { + return 0; + } + + if (thd->lex->all_query_blocks_list && thd->lex->all_query_blocks_list->is_recursive()) { + return 0; + } + + if (cond == nullptr) { + return 0; + } + // Filter Multi-Table Queries + const AQP::Join_plan *const plan = table_aqp->get_join_plan(); + if (plan->get_access_count() > 1) { + return 0; + } + + prep_cond_push(cond); + if (m_pushed_conds == nullptr) { + return 0; + } + + m_cond = (tse_conds *)tse_alloc_buf(&m_tch, sizeof(tse_conds)); + if (m_cond == nullptr) { + tse_log_warning("alloc shm mem failed, m_cond size(%lu), pushdown cond is null.", sizeof(tse_conds)); + return 0; + } + + bool no_backslash = false; + if (thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) { + no_backslash = true; + } + Field **field = table_aqp->get_table()->field; + if (tse_fill_conds(m_tch, m_pushed_conds, field, m_cond, no_backslash) != CT_SUCCESS) { + free_m_cond(m_tch, &m_cond); + m_pushed_conds = nullptr; + m_remainder_conds = nullptr; + return 0; + } + + pushed_cond = m_pushed_conds; + m_remainder_conds = const_cast(cond); + table_aqp->set_condition(const_cast(m_remainder_conds)); + return 0; +} diff --git a/storage/tianchi/ha_tse.h b/storage/tianchi/ha_tse.h new file mode 100644 index 0000000..fd9a7db --- /dev/null +++ b/storage/tianchi/ha_tse.h @@ -0,0 +1,980 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* class for the the tse handler */ + +#ifndef __HA_TSE_H__ +#define __HA_TSE_H__ + +#include +#include + +#include "my_inttypes.h" +#include "sql/handler.h" +#include "sql/table.h" +#include "sql/item.h" +#include "sql/record_buffer.h" +#include "my_sqlcommand.h" +#include "tse_srv.h" +#include "datatype_cnvrtr.h" +#include "tse_error.h" +#include "tse_cbo.h" +#include "sql/abstract_query_plan.h" +#include "sql/dd/types/schema.h" +#include "sql/dd/types/object_table_definition.h" + +#pragma GCC visibility push(default) + +using namespace std; + +#define _INT_TO_STR(s) #s +#define INT_TO_STR(s) _INT_TO_STR(s) + +#define CTC_CLIENT_VERSION_MAIN 3 +#define CTC_CLIENT_VERSION_MINOR 0 +#define CTC_CLIENT_VERSION_PATCH 0 +#define CTC_CLIENT_VERSION_BUGFIX 101 +#define CTC_VERSION_STR \ + INT_TO_STR(CTC_CLIENT_VERSION_MAIN) \ + "." INT_TO_STR(CTC_CLIENT_VERSION_MINOR) "." INT_TO_STR(CTC_CLIENT_VERSION_PATCH) \ + "." INT_TO_STR(CTC_CLIENT_VERSION_BUGFIX) + +// 版本号规则:十六进制后两位为小数点后数字,前面为小数点前数字,0x0310 --> 显示为3.16 +#define CTC_CLIENT_VERSION_NUMBER 0x0300u + + +#define CT_NULL_VALUE_LEN (uint16)0xFFFF +#define INVALID_MAX_UINT32 (uint32_t)0xFFFFFFFF +#define TSE_BUF_LEN (64 * 1024) // Set to max size of cursor defined by (sizeof(knl_cursor_t) + page_size * 2 + inst->attr.max_column_count * sizeof(uint16) * 2); +#define MAX_BATCH_FETCH_NUM 100 +#define DEFAULT_RANGE_DENSITY 0.5 +#define PREFER_RANGE_DENSITY 0.8 +#define CT_MAX_RECORD_LENGTH 64000 +#define BIG_RECORD_SIZE_DYNAMIC (BIG_RECORD_SIZE + 8) // ha_tse构造函数中若没有申请到读写buf共享内存,就在使用时从40968内存池子中动态申请和释放 + +/* update if restraints changed in Cantian */ +#define TSE_MAX_KEY_PART_LENGTH 4095 // CT_MAX_KEY_SIZE +#define TSE_MAX_KEY_PARTS 16 // CT_MAX_INDEX_COLUMNS +#define TSE_MAX_KEY_LENGTH 4095 // CT_MAX_KEY_SIZE +#define TSE_MAX_KEY_NUM 32 // CT_MAX_TABLE_INDEXES + +/* The 'MAIN TYPE' of a column */ +#define DATA_MISSING 0 /* missing column */ +#define DATA_VARCHAR 1 +#define DATA_CHAR 2 /* fixed length character of the latin1_swedish_ci charset-collation */ +#define DATA_FIXBINARY 3 /* binary string of fixed length */ +#define DATA_BINARY 4 /* binary string */ +#define DATA_BLOB 5 /* binary large object, or a TEXT type; \ + if prtype & DATA_BINARY_TYPE == 0, then this is \ + actually a TEXT column (or a BLOB created \ + with < 4.0.14; since column prefix indexes \ + came only in 4.0.14, the missing flag in BLOBs \ + created before that does not cause any harm) */ +#define DATA_INT 6 /* integer: can be any size 1 - 8 bytes */ +#define DATA_SYS_CHILD 7 /* address of the child page in node pointer */ +#define DATA_SYS 8 /* system column */ +/* Data types >= DATA_FLOAT must be compared using the whole field, not as binary strings */ +#define DATA_FLOAT 9 +#define DATA_DOUBLE 10 +#define DATA_DECIMAL 11 /* decimal number stored as an ASCII string */ +#define DATA_VARMYSQL 12 /* any charset varying length char */ +#define DATA_MYSQL 13 /* any charset fixed length char */ + /* NOTE that 4.1.1 used DATA_MYSQL and + DATA_VARMYSQL for all character sets, and the + charset-collation for tables created with it + can also be latin1_swedish_ci */ + +/* DATA_POINT&DATA_VAR_POINT are for standard geometry datatype 'point' and +DATA_GEOMETRY include all other standard geometry datatypes as described in +OGC standard(line_string, polygon, multi_point, multi_polygon, +multi_line_string, geometry_collection, geometry). +Currently, geometry data is stored in the standard Well-Known Binary(WKB) +format (http://www.opengeospatial.org/standards/sfa). +We use BLOB as underlying datatype for DATA_GEOMETRY and DATA_VAR_POINT +while CHAR for DATA_POINT */ +#define DATA_GEOMETRY 14 /* geometry datatype of variable length */ +/* The following two are disabled temporarily, we won't create them in +get_innobase_type_from_mysql_type(). +TODO: We will enable DATA_POINT/them when we come to the fixed-length POINT +again. */ +#define DATA_POINT 15 /* geometry datatype of fixed length POINT */ +#define DATA_VAR_POINT 16 /* geometry datatype of variable length \ + POINT, used when we want to store POINT \ + as BLOB internally */ +#define DATA_MTYPE_MAX 63 /* dtype_store_for_order_and_null_size() \ + requires the values are <= 63 */ + +#define MAX_CHAR_COLL_NUM 32767 /* We now support 15 bits (up to 32767) collation number */ + +#define CHAR_COLL_MASK MAX_CHAR_COLL_NUM /* Mask to get the Charset Collation number (0x7fff) */ + +#define DATA_NOT_NULL 256 /* this is ORed to the precise type when the column is declared as NOT NULL */ +#define DATA_UNSIGNED 512 /* this id ORed to the precise type when we have an unsigned integer type */ +#define DATA_BINARY_TYPE 1024 /* if the data type is a binary character string, this is ORed to the precise type: \ + this only holds for tables created with >= MySQL-4.0.14 */ + +#define TMP_DIR "tmp" +#define TSE_TMP_TABLE 1 +#define TSE_INTERNAL_TMP_TABLE 2 +#define TSE_TABLE_CONTAINS_VIRCOL 4 + + +/* cond pushdown */ +#define INVALID_MAX_COLUMN (uint16_t)0xFFFF + +#define RETURN_IF_OOM(result) \ + { \ + if (result == ERR_ALLOC_MEMORY) \ + return HA_ERR_SE_OUT_OF_MEMORY; \ + } + +#define IS_METADATA_NORMALIZATION() (tse_get_metadata_switch() == (int32_t)metadata_switchs::MATCH_META) + +static const uint ROW_ID_LENGTH = sizeof(uint64_t); +static const uint TSE_START_TIMEOUT = 120; // seconds +extern const char *tse_hton_name; +extern bool no_create_dir; +enum class lock_mode { + NO_LOCK = 0, + SHARED_LOCK, + EXCLUSIVE_LOCK +}; + +enum class metadata_switchs { + DEFAULT = -1, + NOT_MATCH, + MATCH_META, + MATCH_NO_META, + CLUSTER_NOT_READY +}; + +typedef int (*tse_prefetch_fn)(tianchi_handler_t *tch, uint8_t *records, uint16_t *record_lens, + uint32_t *recNum, uint64_t *rowids, int32 max_row_size); + +#define FILL_USER_INFO_WITH_THD(ctrl, _thd) \ + do { \ + const char *user_name = _thd->m_main_security_ctx.priv_user().str; \ + const char *user_ip = _thd->m_main_security_ctx.priv_host().str; \ + assert(strlen(user_name) + 1 <= sizeof(ctrl.user_name)); \ + memcpy(ctrl.user_name, user_name, strlen(user_name) + 1); \ + assert(strlen(user_ip) + 1 <= sizeof(ctrl.user_ip)); \ + memcpy(ctrl.user_ip, user_ip, strlen(user_ip) + 1); \ + } while (0) + +#define FILL_BROADCAST_BASE_REQ(broadcast_req, _sql_str, _user_name, _user_ip, _mysql_inst_id, _sql_command) \ + do { \ + (broadcast_req).mysql_inst_id = (_mysql_inst_id); \ + (broadcast_req).sql_command = (_sql_command); \ + strncpy((broadcast_req).sql_str, (_sql_str), MAX_DDL_SQL_LEN - 1); \ + strncpy((broadcast_req).user_name, (_user_name), SMALL_RECORD_SIZE - 1); \ + strncpy((broadcast_req).user_ip, (_user_ip), SMALL_RECORD_SIZE - 1); \ + } while (0) + +#define CHECK_HAS_MEMBER_IMPL(member) \ +template \ +struct check_has_##member { \ + template static auto check(_T)->typename std::decay::type; \ + static void check(...); \ + using type = decltype(check(std::declval())); \ + constexpr static bool value = !std::is_void::value; \ +}; + +#define CHECK_HAS_MEMBER_FUNC_IMPL(NAME) \ +template \ +struct check_has_member_func_##NAME { \ + template \ + constexpr static auto check(const void*)-> \ + decltype(std::declval().NAME(std::declval()...), std::true_type()); \ + \ + template \ + constexpr static std::false_type check(...); \ + \ + static constexpr bool value = decltype(check(nullptr))::value; \ +}; + +CHECK_HAS_MEMBER_IMPL(get_inst_id) +CHECK_HAS_MEMBER_IMPL(get_metadata_switch) +CHECK_HAS_MEMBER_IMPL(set_metadata_switch) +CHECK_HAS_MEMBER_IMPL(get_metadata_status) +CHECK_HAS_MEMBER_IMPL(op_before_load_meta) +CHECK_HAS_MEMBER_IMPL(op_after_load_meta) +CHECK_HAS_MEMBER_IMPL(drop_database_with_err) +CHECK_HAS_MEMBER_IMPL(binlog_log_query_with_err) + +CHECK_HAS_MEMBER_FUNC_IMPL(is_empty) +CHECK_HAS_MEMBER_FUNC_IMPL(invalidates) + +#define CHECK_HAS_MEMBER_FUNC(CLASS, MEMBER, ...) \ + check_has_member_func_##MEMBER::value + +#define CHECK_HAS_MEMBER(type, member) check_has_##member::value + +/** @brief + Tse_share is a class that will be shared among all open handlers. +*/ +class Tse_share : public Handler_share { + public: + tianchi_cbo_stats_t *cbo_stats = nullptr; + int used_count = 0; + bool need_fetch_cbo = false; + time_t get_cbo_time = 0; +}; + +/** @brief + Class definition for the storage engine +*/ + +class ha_tse : public handler { +public: + ha_tse(handlerton *hton, TABLE_SHARE *table); + ~ha_tse(); + + int initialize(); + + template + T *get_share() { + DBUG_TRACE; + T *tmp_share = nullptr; + + lock_shared_ha_data(); + if (!(tmp_share = static_cast(get_ha_share_ptr()))) { + tmp_share = new T; + if (!tmp_share) goto err; + set_ha_share_ptr(static_cast(tmp_share)); + } + tmp_share->used_count++; + err: + unlock_shared_ha_data(); + return tmp_share; + } + + template + void free_share() { + DBUG_TRACE; + T *tmp_share; + + lock_shared_ha_data(); + if ((tmp_share = static_cast(get_ha_share_ptr()))) { + if (!--tmp_share->used_count) { + free_cbo_stats(); + delete tmp_share; + set_ha_share_ptr(static_cast(nullptr)); + } + } + unlock_shared_ha_data(); + } + + bool check_unsupported_operation(THD *thd, HA_CREATE_INFO *create_info); + + void check_error_code_to_mysql(THD *thd, ct_errno_t *ret); + + /** @brief + The name that will be used for display purposes. + */ + const char *table_type() const override { + DBUG_TRACE; + return "CTC"; + } + + /** + Replace key algorithm with one supported by SE, return the default key + algorithm for SE if explicit key algorithm was not provided. + + @sa handler::adjust_index_algorithm(). + */ + virtual enum ha_key_alg get_default_index_algorithm() const override { + DBUG_TRACE; + return HA_KEY_ALG_BTREE; + } + + bool is_index_algorithm_supported(enum ha_key_alg key_alg) const override { + /* This method is never used for FULLTEXT or SPATIAL keys. + We rely on handler::ha_table_flags() to check if such keys + are supported. */ + assert(key_alg != HA_KEY_ALG_FULLTEXT && key_alg != HA_KEY_ALG_RTREE); + return key_alg == HA_KEY_ALG_BTREE; + } + /** + Rows also use a fixed-size format. + instead of create_info->table_options :: + share->db_options_in_use//db_create_options (see hanler.h, see row_format in + information_schema) + */ + enum row_type get_real_row_type(const HA_CREATE_INFO *) const override { + DBUG_TRACE; + return ROW_TYPE_FIXED; + } + + /** @brief + This is a list of flags that indicate what functionality the storage engine + implements. The current table flags are documented in handler.h + */ + ulonglong table_flags() const override { + DBUG_TRACE; + return (HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | HA_NULL_IN_KEY | HA_DESCENDING_INDEX | + HA_CAN_INDEX_VIRTUAL_GENERATED_COLUMN | HA_GENERATED_COLUMNS | HA_NO_READ_LOCAL_LOCK | + HA_SUPPORTS_DEFAULT_EXPRESSION | HA_CAN_INDEX_BLOBS | HA_CAN_EXPORT | HA_CAN_SQL_HANDLER | + HA_ATTACHABLE_TRX_COMPATIBLE); + } + + /** @brief + This is a bitmap of flags that indicates how the storage engine + implements indexes. The current index flags are documented in + handler.h. If you do not implement indexes, just return zero here. + + @details + part is the key part to check. First key part is 0. + If all_parts is set, MySQL wants to know the flags for the combined + index, up to and including 'part'. + */ + ulong index_flags(uint key, uint, bool) const override { + DBUG_TRACE; + + if (table_share->key_info[key].algorithm == HA_KEY_ALG_FULLTEXT) return 0; + + ulong flags = HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | HA_READ_ORDER | + HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN; + + // @todo: Check if spatial indexes really have all these properties + if (table_share->key_info[key].flags & HA_SPATIAL) + flags |= HA_KEY_SCAN_NOT_ROR; + + return flags; + } + + /** @brief + unireg.cc will call max_supported_record_length(), max_supported_keys(), + max_supported_key_parts(), uint max_supported_key_length() + to make sure that the storage engine can handle the data it is about to + send. Return *real* limits of your storage engine here; MySQL will do + min(your_limits, MySQL_limits) automatically. + */ + uint max_supported_record_length() const override { + DBUG_TRACE; + return CT_MAX_RECORD_LENGTH; + } + + /** @brief + unireg.cc will call this to make sure that the storage engine can handle + the data it is about to send. Return *real* limits of your storage engine + here; MySQL will do min(your_limits, MySQL_limits) automatically. + + @details + There is no need to implement ..._key_... methods if your engine doesn't + support indexes. + */ + /* uint max_supported_keys() const { + DBUG_TRACE; + return (MAX_KEY); + } */ + + /** @details + Set the maximum number of indexes per table + */ + uint max_supported_keys() const override; + + /** @brief + unireg.cc will call this to make sure that the storage engine can handle + the data it is about to send. Return *real* limits of your storage engine + here; MySQL will do min(your_limits, MySQL_limits) automatically. + + @details + There is no need to implement ..._key_... methods if your engine doesn't + support indexes. + */ + // uint max_supported_key_length() const { return (3500); } + + /** @details + Get the maximum possible key length + */ + uint max_supported_key_length() const override; + + /** @details + Set the maximum columns of a composite index +*/ + uint max_supported_key_parts() const override; + + /** @details + Get the maximum supported indexed columns length + */ + uint max_supported_key_part_length( + HA_CREATE_INFO *create_info) const override; + + /** @brief + Called in test_quick_select to determine if indexes should be used. + */ + virtual double scan_time() override { + DBUG_TRACE; + return (ulonglong)(stats.records + stats.deleted) / 100 + 2; + } + + /** @brief + This method will never be called if you do not implement indexes. + */ + virtual double read_time( + uint index, /*!< in: key number */ + uint ranges, /*!< in: how many ranges */ + ha_rows rows) /*!< in: estimated number of rows in the ranges */ override { + DBUG_TRACE; + + if (index != table->s->primary_key) { + /* Not clustered */ + return (handler::read_time(index, ranges, rows)); + } + + if (rows <= 2) { + return ((double)rows); + } + + /* Assume that the read time is proportional to the scan time for all + rows + at most one seek per range. */ + + double time_for_scan = scan_time(); + + if (stats.records < rows) { + return (time_for_scan); + } + + return (ranges + (double)rows / (double)stats.records * time_for_scan); + } + + bool inplace_alter_table( + TABLE *altered_table MY_ATTRIBUTE((unused)), + Alter_inplace_info *ha_alter_info MY_ATTRIBUTE((unused)), + const dd::Table *old_table_def MY_ATTRIBUTE((unused)), + dd::Table *new_table_def MY_ATTRIBUTE((unused))) override; + + int open(const char *name, int mode, uint test_if_locked, + const dd::Table *table_def) override; // required + + int close(void) override; // required + +#ifdef METADATA_NORMALIZED + int write_row(uchar *buf, bool write_through = false) override; +#endif + +#ifndef METADATA_NORMALIZED + int write_row(uchar *buf) override; +#endif + + int update_row(const uchar *old_data, uchar *new_data) override; + + int delete_row(const uchar *buf) override ; + + int index_init(uint index, bool sorted) override; + + int index_end() override; + + int index_read(uchar *buf, const uchar *key, uint key_len, + ha_rkey_function find_flag) override; + int index_read_last(uchar *buf, const uchar *key_ptr, uint key_len) override; + + int index_next_same(uchar *buf, const uchar *key, uint keylen) override; + + int index_fetch(uchar *buf); + + /** + @brief + Positions an index cursor to the index specified in the handle. Fetches the + row if available. If the key value is null, begin at the first key of the + index. It's not an obligatory method; + skip it and and MySQL will treat it as not implemented. + */ + // int index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map, + // enum ha_rkey_function find_flag); + + /** @brief + Used to read forward through the index. + It's not an obligatory method; + skip it and and MySQL will treat it as not implemented. + */ + int index_next(uchar *buf) override; + + /** @brief + Used to read backwards through the index. + It's not an obligatory method; + skip it and and MySQL will treat it as not implemented. + */ + int index_prev(uchar *buf) override; + + /** @brief + index_first() asks for the first key in the index. + It's not an obligatory method; + Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc. + skip it and and MySQL will treat it as not implemented. + */ + int index_first(uchar *buf) override; + + /** @brief + index_last() asks for the last key in the index. + It's not an obligatory method; + skip it and and MySQL will treat it as not implemented. + Called from opt_range.cc, opt_sum.cc, sql_handler.cc, and sql_select.cc. + */ + int index_last(uchar *buf) override; + + /** @brief + rnd_init() is called when the system wants the storage engine to do a table + scan. See the example in the introduction at the top of this file to see + when rnd_init() is called. + + Unlike index_init(), rnd_init() can be called two consecutive times + without rnd_end() in between (it only makes sense if scan=1). In this + case, the second call should prepare for the new table scan (e.g if + rnd_init() allocates the cursor, the second call should position the + cursor to the start of the table; no need to deallocate and allocate + it again. This is a required method. + + @details + Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, + sql_table.cc, and sql_update.cc. + + @see + filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and + sql_update.cc + */ + int rnd_init(bool scan) override; // required + + int rnd_end() override; + + /** + @brief + This is called for each row of the table scan. When you run out of records + you should return HA_ERR_END_OF_FILE. Fill buff up with the row information. + The Field structure for the table is the key to getting data into buf + in a manner that will allow the server to understand it. + + @details + Called from filesort.cc, records.cc, sql_handler.cc, sql_select.cc, + sql_table.cc, and sql_update.cc. + + @see + filesort.cc, records.cc, sql_handler.cc, sql_select.cc, sql_table.cc and + sql_update.cc + */ + int rnd_next(uchar *buf) override; ///< required + + /** + @brief + This is like rnd_next, but you are given a position to use + to determine the row. The position will be of the type that you stored in + ref. You can use ha_get_ptr(pos,ref_length) to retrieve whatever key + or position you saved when position() was called. + + @details + Called from filesort.cc, records.cc, sql_insert.cc, sql_select.cc, and + sql_update.cc. + + @see + filesort.cc, records.cc, sql_insert.cc, sql_select.cc and sql_update.cc + */ + int rnd_pos(uchar *buf, uchar *pos) override; ///< required + + int prefetch_and_fill_record_buffer(uchar *buf, tse_prefetch_fn); + void fill_record_to_rec_buffer(); + void reset_rec_buf(bool is_prefetch = false); + /** + @brief + position() is called after each call to rnd_next() if the data needs + to be ordered. You can do something like the following to store + the position: + @code + my_store_ptr(ref, ref_length, current_position); + @endcode + + @details + The server uses ref to store data. ref_length in the above case is + the size needed to store current_position. ref is just a byte array + that the server will maintain. If you are using offsets to mark rows, then + current_position should be the offset. If it is a primary key like in + BDB, then it needs to be a primary key. + + Called from filesort.cc, sql_select.cc, sql_delete.cc, and sql_update.cc. + + @see + filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc + */ + void position(const uchar *record) override; ///< required + + virtual void info_low(); + + int info(uint) override; ///< required + + /** + @brief + extra() is called whenever the server wishes to send a hint to + the storage engine. The myisam engine implements the most hints. + ha_innodb.cc has the most exhaustive list of these hints. + + @see + ha_innodb.cc + */ + int extra(enum ha_extra_function operation) override; + + /** + @brief + Used to delete all rows in a table, including cases of truncate and cases + where the optimizer realizes that all rows will be removed as a result of an + SQL statement. + + @details + Called from item_sum.cc by Item_func_group_concat::clear(), + Item_sum_count_distinct::clear(), and Item_func_group_concat::clear(). + Called from sql_delete.cc by mysql_delete(). + Called from sql_select.cc by JOIN::reinit(). + Called from sql_union.cc by st_select_lex_unit::exec(). + + @see + Item_func_group_concat::clear(), Item_sum_count_distinct::clear() and + Item_func_group_concat::clear() in item_sum.cc; + mysql_delete() in sql_delete.cc; + JOIN::reinit() in sql_select.cc and + st_select_lex_unit::exec() in sql_union.cc. + */ + int delete_all_rows(void) override; + + /** + Reset state of file to after 'open'. + This function is called after every statement for all tables used + by that statement. + */ + int reset() override; + + /** + @brief + Given a starting key and an ending key, estimate the number of rows that + will exist between the two keys. + + @details + end_key may be empty, in which case determine if start_key matches any rows. + + Called from opt_range.cc by check_quick_keys(). + + @see + check_quick_keys() in opt_range.cc + */ + ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) override; + + int records(ha_rows *num_rows) override; + int records_from_index(ha_rows *num_rows, uint inx) override; + + void set_tse_range_key(tse_range_key *tse_range_key, key_range *mysql_range_key, tse_cmp_type_t default_type); + + /** + @brief + Used to delete a table. By the time delete_table() has been called all + opened references to this table will have been closed (and your globally + shared references released). The variable name will just be the name of + the table. You will need to remove any files you have created at this point. + + @details + If you do not implement this, the default delete_table() is called from + handler.cc and it will delete all files with the file extensions from + handlerton::file_extensions. + + Called from handler.cc by delete_table and ha_create_table(). Only used + during create if the table_flag HA_DROP_BEFORE_CREATE was specified for + the storage engine. + + @see + delete_table and ha_create_table() in handler.cc + */ + int delete_table(const char *from, const dd::Table *table_def) override; + + // void drop_table(const char *name); + + /** + @brief + create() is called to create a database. The variable name will have the + name of the table. + create() is called to create a database. The variable name will have the + name of the table. + + @details + When create() is called you do not need to worry about + opening the table. Also, the .frm file will have already been + created so adjusting create_info is not necessary. You can overwrite + the .frm file at this point if you wish to change the table + definition, but there are no methods currently provided for doing + so. + + Called from handle.cc by ha_create_table(). + + @see + ha_create_table() in handle.cc + */ + int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info, + dd::Table *table_def) override; ///< required + + /** + @brief + Get number of lock objects returned in store_lock. + + @details + Returns the number of store locks needed in call to store lock. + We return number of partitions we will lock multiplied with number of + locks needed by each partition. Assists the above functions in allocating + sufficient space for lock structures. +*/ + uint lock_count(void) const override{ return 0; } + + THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, + enum thr_lock_type lock_type) override; ///< required + + /** + @brief + This will start/end a transaction for statement, reference to innodb engine, + for lock tables command will lock tables, but for now ignore this. + + @details + Called from lock.cc by lock_external() and unlock_external(). Also called + from sql_table.cc by copy_data_between_tables(). + + @see + lock.cc by lock_external() and unlock_external() in lock.cc; + the section "locking functions for mysql" in lock.cc; + copy_data_between_tables() in sql_table.cc. +*/ + int external_lock(THD *thd, int lock_type) override; + + /** + @brief + This will start/end a transaction for statement, reference to innodb engine, + for insert/update/delete command on temp table will lock tables, but for now + ignore this. + + @details + Called from sql_base.cc by check_lock_and_start_stmt(). + + @see + sql_base.cc by check_lock_and_start_stmt(). +*/ + int start_stmt(THD *thd, thr_lock_type lock_type) override; + + bool can_prefetch_records() const ; + uint32_t cur_pos_in_buf = INVALID_MAX_UINT32; // current position in prefetched record buf + /* Number of rows actually prefetched */ + uint32_t actual_fetched_nums = INVALID_MAX_UINT32; + + uint64_t cur_off_in_prefetch_buf = 0; + + uint32_t cur_fill_buf_index = 0; + + /** Find out if a Record_buffer is wanted by this handler, and what is + the maximum buffer size the handler wants. + + @param[out] max_rows gets set to the maximum number of records to + allocate space for in the buffer + @retval true if the handler wants a buffer + @retval false if the handler does not want a buffer */ + bool is_record_buffer_wanted(ha_rows *const max_rows) const override; + uint max_col_index; + + /** Find max column index needed by optimizer in read-only scan + in order to shrink bufsize when calling cantian_to_mysql func for filling + data into record_buffer **/ + void set_max_col_index_4_reading(); + + /* function pointer used for converting record into mysql format*/ + cnvrt_to_mysql_fn cnvrt_to_mysql_record; + void update_create_info( + HA_CREATE_INFO *create_info MY_ATTRIBUTE((unused))) override; + + /* function used for notifying SE to collect cbo stats */ + int analyze(THD *thd, HA_CHECK_OPT *check_opt) override; + + /* optimize is mapped to "ALTER TABLE tablename ENGINE=InnoDB" in innodb. it will return + HA_ADMIN_TRY_ALTER when optimize, and then recreate + analyze will be done in sql_admin.cc + in case HA_ADMIN_TRY_ALTER. + */ + int optimize(THD *thd, HA_CHECK_OPT *check_opt) override; + + /* functions used for notifying SE to start/terminate batch insertion */ + void start_bulk_insert(ha_rows rows) override; + int end_bulk_insert() override; + + /** Check if Tse supports a particular alter table in-place + @param altered_table TABLE object for new version of table. + @param ha_alter_info Structure describing changes to be done + by ALTER TABLE and holding data used during in-place alter. + @retval HA_ALTER_INPLACE_NOT_SUPPORTED Not supported + @retval HA_ALTER_INPLACE_NO_LOCK Supported + @retval HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE + Supported, but requires lock during main phase and + exclusive lock during prepare phase. + @retval HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE + Supported, prepare phase requires exclusive lock. */ + enum_alter_inplace_result check_if_supported_inplace_alter( + TABLE *altered_table, Alter_inplace_info *ha_alter_info) override; + + int rename_table(const char *from, const char *to, + const dd::Table *from_table_def, + dd::Table *to_table_def) override; + + int check(THD *thd, HA_CHECK_OPT *check_opt) override; + + bool get_error_message(int error, String *buf) override; + + void set_prefetch_buffer(); + + void update_blob_addrs(uchar *record); + + void free_blob_addrs(); + + int fill_and_cnvrt_key_info(index_key_info_t &key_info, ha_rkey_function find_flag, const uchar *key, uint key_len); + + virtual int initialize_cbo_stats(); + + virtual void free_cbo_stats(); + + virtual int get_cbo_stats_4share(); + + const Item *cond_push(const Item *cond, bool other_tbls_ok) override; + + int engine_push(AQP::Table_access *table) override; + + bool get_se_private_data(dd::Table *dd_table, bool reset) override; + + bool is_replay_ddl(MYSQL_THD thd); + + protected: + /* fooling percona-server's gap lock detection on rr which blocks some SQL */ + virtual bool has_gap_locks() const noexcept { return true; } + + protected: + + /* tianchi handler that can be used to determine who sends the request */ + tianchi_handler_t m_tch; + + /* cantian record buffer */ + uchar *m_tse_buf; + + /* select lock mode */ + lock_mode m_select_lock = lock_mode::NO_LOCK; + + bool m_is_covering_index = false; + + bool m_is_replace = false; + + bool m_is_insert_dup = false; + + bool m_ignore_dup = false; + + expected_cursor_action_t m_action; + + bool m_index_sorted; + + bool m_error_if_not_empty = false; + + /** + * Store tmp cantian format record when calling batch read intfs. + */ + uchar *m_prefetch_buf; + + /* cached record lens of prefetched row */ + uint16_t m_record_lens[MAX_BATCH_FETCH_NUM]; + + /* cached rowids in case position is called during prefetch*/ + uint64_t m_rowids[MAX_BATCH_FETCH_NUM]; + + /* estimated cantian record length*/ + int32 m_cantian_rec_len; + + /* max number of records that can be batch inserted at once */ + uint64_t m_max_batch_num; + + /* private record buffer */ + uchar *m_rec_buf_data; + + Record_buffer *m_rec_buf; + + Record_buffer *m_rec_buf_4_writing = nullptr; + + vector m_blob_addrs; + + /** Pointer to Tse_share on the TABLE_SHARE. */ + Tse_share *m_share; + + tse_select_mode_t get_select_mode(); + + /** Pointer to Cond pushdown */ + tse_conds *m_cond = nullptr; + Item *m_pushed_conds = nullptr; + Item *m_remainder_conds = nullptr; + +private: + int process_cantian_record(uchar *buf, record_info_t *record_info, ct_errno_t ct_ret, int rc_ret); + int bulk_insert(); + virtual int bulk_insert_low(dml_flag_t flag, uint *dup_offset); + int convert_mysql_record_and_write_to_cantian(uchar *buf, int *cantian_record_buf_size, + uint16_t *serial_column_offset, dml_flag_t flag); + void prep_cond_push(const Item *cond); + int handle_auto_increment(bool &has_explicit_autoinc); + bool pre_check_for_cascade(bool is_update); +}; + +struct dict_col { + uint mtype; + uint prtype; + uint len; +}; + +#pragma pack(4) +typedef struct { + uint64 sess_addr; + uint thd_id; + uint16 bind_core; + uint is_tse_trx_begin; + uint8_t sql_stat_start; /* TRUE when we start processing of an SQL statement */ + std::unordered_map *cursors_map; + std::vector *invalid_cursors; + void* msg_buf; +} thd_sess_ctx_s; +#pragma pack() + +int ha_tse_get_inst_id(); +void ha_tse_set_inst_id(uint32_t inst_id); + +bool is_ddl_sql_cmd(enum_sql_command sql_cmd); +bool is_dcl_sql_cmd(enum_sql_command sql_cmd); +thd_sess_ctx_s *get_or_init_sess_ctx(handlerton *hton, THD *thd); +handlerton *get_tse_hton(); +void update_sess_ctx_by_tch(tianchi_handler_t &tch, handlerton *hton, THD *thd); +void update_member_tch(tianchi_handler_t &tch, handlerton *hton, THD *thd, bool alloc_msg_buf = true); +int get_tch_in_handler_data(handlerton *hton, THD *thd, tianchi_handler_t &tch, bool alloc_msg_buf = true); +void tse_ddl_hook_cantian_error(const char *tag, THD *thd, ddl_ctrl_t *ddl_ctrl, + ct_errno_t *ret); +int tse_ddl_handle_fault(const char *tag, const THD *thd, + const ddl_ctrl_t *ddl_ctrl, ct_errno_t ret, const char *param = nullptr, int fix_ret = 0); +bool ddl_enabled_local(MYSQL_THD thd); +bool ddl_enabled_normal(MYSQL_THD thd); +bool engine_ddl_passthru(MYSQL_THD thd); +bool is_alter_table_copy(MYSQL_THD thd, const char *name = nullptr); +bool is_alter_table_scan(bool m_error_if_not_empty); + +int tse_fill_conds(const Item *pushed_cond, Field **field, tse_conds *m_cond, bool no_backslash); +void free_m_cond(tianchi_handler_t m_tch, tse_conds **conds); +void tse_set_metadata_switch(); +int32_t tse_get_metadata_switch(); +bool is_meta_version_initialize(); +bool is_initialize(); +bool is_starting(); + +bool tse_is_temporary(const dd::Table *table_def); + +#pragma GCC visibility pop +#endif diff --git a/storage/tianchi/ha_tse_ddl.cc b/storage/tianchi/ha_tse_ddl.cc new file mode 100644 index 0000000..bd37c55 --- /dev/null +++ b/storage/tianchi/ha_tse_ddl.cc @@ -0,0 +1,2706 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "storage/tianchi/ha_tse.h" +#include "storage/tianchi/ha_tse_ddl.h" +#include "storage/tianchi/ha_tsepart.h" +#include + +#include +#include +#include "my_sqlcommand.h" +#include "sql/create_field.h" +#include "sql/dd/collection.h" +#include "sql/dd/dd_table.h" +#include "sql/dd/types/table.h" +#include "sql/sql_tablespace.h" +#include "sql/dd/types/tablespace.h" +#include "sql/sql_class.h" +#include "sql/sql_lex.h" +#include "sql/strfunc.h" // find_type2 +#include "protobuf/tc_db.pb-c.h" +#include "scope_guard.h" // create_scope_guard +#include "sql/dd/types/foreign_key.h" // dd::Foreign_key +#include "sql/dd/types/foreign_key_element.h" // dd::Foreign_key_element +#include "sql/dd/types/index.h" // dd::Index +#include "sql/dd/types/index_element.h" // dd::Index_element +#include "sql/sql_initialize.h" // opt_initialize_insecure +#include "sql/dd/types/partition.h" +#include "sql/dd/types/partition_index.h" +#include "sql/dd/types/partition_value.h" +#include "sql/dd/types/partition_value.h" +#include "sql/partition_info.h" +#include "sql/partition_element.h" +#include "sql/dd/impl/utils.h" +#include "sql/sql_table.h" // primary_key_name +#include "sql/sql_partition.h" +#include "sql/item_func.h" +#include "my_time.h" +#include "decimal.h" + +#include "srv_mq_msg.h" +#include "decimal_convert.h" +#include "datatype_cnvrtr.h" +#include "tse_error.h" +#include "tse_log.h" +#include "tse_util.h" +#include "tse_ddl_util.h" +#include +#include + +using namespace std; + +#define TSE_MAX_COLUMN_LEN 65 + +#define CT_UNSPECIFIED_NUM_PREC 0 +#define CT_UNSPECIFIED_NUM_SCALE (-100) + +const uint32_t TSE_DDL_PROTOBUF_MEM_SIZE = 1024 * 1024 * 10; // 10M +mutex m_tse_ddl_protobuf_mem_mutex; +char tse_ddl_req_mem[TSE_DDL_PROTOBUF_MEM_SIZE]; +extern uint32_t tse_instance_id; +extern handlerton *tse_hton; + +size_t tse_ddl_stack_mem::tse_ddl_req_msg_mem_max_size = 0; +size_t tse_ddl_stack_mem::tse_ddl_req_msg_mem_use_heap_cnt = 0; + +int fill_delete_table_req(const char *full_path_name, const dd::Table *table_def, + THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + TcDb__TseDDLDropTableDef req; + + tc_db__tse_ddldrop_table_def__init(&req); + + // 填充req信息 + char db_name[SMALL_RECORD_SIZE] = {0}; + char user_name[SMALL_RECORD_SIZE] = {0}; + char table_name[SMALL_RECORD_SIZE] = {0}; + + bool is_tmp_table = tse_is_temporary(table_def); + tse_split_normalized_name(full_path_name, db_name, SMALL_RECORD_SIZE, table_name, SMALL_RECORD_SIZE, &is_tmp_table); + if (is_tmp_table) { + ddl_ctrl->table_flags |= TSE_TMP_TABLE; + req.name = table_name; + } else { + req.name = const_cast(table_def->name().c_str()); + } + tse_copy_name(user_name, db_name, SMALL_RECORD_SIZE); + + req.user = user_name; + req.db_name = TSE_GET_THD_DB_NAME(thd); + + // 拷贝算法语句在delete_table接口广播 + string drop_sql; + if (is_alter_table_copy(thd)) { + req.options |= TSE_DROP_FOR_MYSQL_COPY; + ddl_ctrl->is_alter_copy = true; + } + + if (is_tmp_table) { // 删除临时表不需要广播 + req.sql_str = nullptr; + } else { + drop_sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(drop_sql.c_str()); + } + + if (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) { + req.options |= TSE_DROP_NO_CHECK_FK; + } else if (table_def && !table_def->foreign_key_parents().empty()) { + // broadcasted mysql need set to ignore FKs and cantian also ignore FKs + req.options |= (TSE_DROP_NO_CHECK_FK_FOR_CANTIAN_AND_BROADCAST | TSE_DROP_NO_CHECK_FK); + } + + size_t msg_len = tc_db__tse_ddldrop_table_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddldrop_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len; + return 0; +} + +static int tse_init_create_tablespace_def(TcDb__TseDDLSpaceDef *req, char **mem_start, + char *mem_end) { + tc_db__tse_ddlspace_def__init(req); + req->n_datafiles_list = 1; + req->datafiles_list = (TcDb__TseDDLDataFileDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLDataFileDef*)); // mysql最多只有一个datafile,此处按1计算 + if (req->datafiles_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + req->datafiles_list[0] = (TcDb__TseDDLDataFileDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLDataFileDef)); + if (req->datafiles_list[0] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + + tc_db__tse_ddldata_file_def__init(req->datafiles_list[0]); + TcDb__TseDDLDataFileDef *datafile = req->datafiles_list[0]; + datafile->autoextend = (TcDb__TseDDLAutoExtendDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAutoExtendDef)); + if (datafile->autoextend == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlauto_extend_def__init(datafile->autoextend); + return 0; +} + +static void tse_ddl_fill_datafile_by_alter_info(TcDb__TseDDLDataFileDef *datafile, st_alter_tablespace *alter_info) { + datafile->name = const_cast(alter_info->data_file_name); + datafile->size = 1024 * 1024; // 8 * 1024 * 1024 + datafile->autoextend->enabled = true; + if(alter_info->autoextend_size.has_value()) { + datafile->autoextend->nextsize = (uint64_t)alter_info->autoextend_size.value(); + } else { + datafile->autoextend->nextsize = 0; + } + + // TODO:其他参数目前不确定如何填写 包含autoextend +} + +static int tse_create_tablespace_handler(handlerton *hton, THD *thd, + st_alter_tablespace *alter_info, + dd::Tablespace *dd_space MY_ATTRIBUTE((unused))) { + if (engine_ddl_passthru(thd)) { + return CT_SUCCESS; + } + ct_errno_t ret; + size_t msg_len = 0; + tse_ddl_stack_mem stack_mem(0); + void *tse_ddl_req_msg_mem = nullptr; + { + TcDb__TseDDLSpaceDef req; + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + ret = (ct_errno_t)tse_init_create_tablespace_def(&req, &req_mem_start, req_mem_end); + assert(req_mem_start <= req_mem_end); + if (ret != 0) { + return ret; + } + + // fill parameter for create tablespace + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(alter_info->tablespace_name)); + req.name = const_cast(alter_info->tablespace_name); + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + + // fill datafile parameter + TcDb__TseDDLDataFileDef *datafile = req.datafiles_list[0]; + if(check_data_file_name(alter_info->data_file_name)) { + return HA_ERR_WRONG_FILE_NAME; + } + + tse_ddl_fill_datafile_by_alter_info(datafile, alter_info); + + msg_len = tc_db__tse_ddlspace_def__get_packed_size(&req); + stack_mem.set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + tse_ddl_req_msg_mem = stack_mem.get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlspace_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + } + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ddl_ctrl.msg_len = msg_len; + ret = (ct_errno_t)tse_create_tablespace(tse_ddl_req_msg_mem, &ddl_ctrl); + memcpy(&tch, &ddl_ctrl.tch, sizeof(tianchi_handler_t)); + tse_ddl_hook_cantian_error("tse_create_tablespace_cantian_error", thd, &ddl_ctrl, &ret); + update_sess_ctx_by_tch(tch, hton, thd); + return tse_ddl_handle_fault("tse_create_tablespace", thd, &ddl_ctrl, ret, alter_info->tablespace_name); +} + +static int tse_alter_tablespace_handler(handlerton *hton, THD *thd, + st_alter_tablespace *alter_info, + const dd::Tablespace *old_dd_space, + dd::Tablespace *new_dd_space) { + // 只支持修改表空间名称 以及设置属性 + if (alter_info->ts_alter_tablespace_type != ALTER_TABLESPACE_RENAME && + alter_info->ts_alter_tablespace_type != ALTER_TABLESPACE_OPTIONS) { + return HA_ADMIN_NOT_IMPLEMENTED; + } + if (engine_ddl_passthru(thd)) { + return CT_SUCCESS; + } + // TODO 先检查旧表空间是否存在 + // TODO 检查是否是undo表空间 undo表空间需要指定 alter undo tablespace + // TODO 处理加密相关操作 + ct_errno_t ret; + const char *from = old_dd_space->name().c_str(); + const char *to = new_dd_space->name().c_str(); + size_t msg_len = 0; + tse_ddl_stack_mem stack_mem(0); + void *tse_ddl_req_msg_mem = nullptr; + { + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + // TODO 检测from表名 不能和系统表一致(即不能修改系统表) + if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_RENAME && + my_strcasecmp(system_charset_info, from, to) == 0) { + my_printf_error(ER_WRONG_TABLESPACE_NAME, + "tablespace name is same for rename", MYF(0)); + return HA_WRONG_CREATE_OPTION; + } + auto tse_alter_action = + g_tse_alter_tablespace_map.find(alter_info->ts_alter_tablespace_type); + if (tse_alter_action == g_tse_alter_tablespace_map.end()) { + return ER_ILLEGAL_HA; + } + + TcDb__TseDDLAlterSpaceDef req; + tc_db__tse_ddlalter_space_def__init(&req); + + req.action = tse_alter_action->second; + + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(from)); + req.name = const_cast(from); + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(to)); + req.new_name = const_cast(to); + + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + if (alter_info->autoextend_size != 0 && alter_info->autoextend_size.has_value()) { + req.auto_extend_size = (uint64_t)alter_info->autoextend_size.value(); + } + msg_len = tc_db__tse_ddlalter_space_def__get_packed_size(&req); + stack_mem.set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + tse_ddl_req_msg_mem = stack_mem.get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlalter_space_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + } + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ddl_ctrl.msg_len = msg_len; + ret = (ct_errno_t)tse_alter_tablespace(tse_ddl_req_msg_mem, &ddl_ctrl); + memcpy(&tch, &ddl_ctrl.tch, sizeof(tianchi_handler_t)); + tse_ddl_hook_cantian_error("tse_alter_tablespace_cantian_error", thd, &ddl_ctrl, &ret); + update_sess_ctx_by_tch(tch, hton, thd); + return tse_ddl_handle_fault("tse_alter_tablespace", thd, &ddl_ctrl, ret); +} + +static int tse_drop_tablespace_handler(handlerton *hton, THD *thd, + st_alter_tablespace *alter_info, + const dd::Tablespace *dd_space MY_ATTRIBUTE((unused))) { + if (engine_ddl_passthru(thd)) { + return CT_SUCCESS; + } + ct_errno_t ret; + size_t msg_len = 0; + tse_ddl_stack_mem stack_mem(0); + void *tse_ddl_req_msg_mem = nullptr; + { + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + TcDb__TseDDLDropSpaceDef req; + tc_db__tse_ddldrop_space_def__init(&req); + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(alter_info->tablespace_name)); + req.obj_name = const_cast(alter_info->tablespace_name); + + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + + + msg_len = tc_db__tse_ddldrop_space_def__get_packed_size(&req); + stack_mem.set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + tse_ddl_req_msg_mem = stack_mem.get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddldrop_space_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + } + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ddl_ctrl.msg_len = msg_len; + + ret = (ct_errno_t)tse_drop_tablespace(tse_ddl_req_msg_mem, &ddl_ctrl); + memcpy(&tch, &ddl_ctrl.tch, sizeof(tianchi_handler_t)); + tse_ddl_hook_cantian_error("tse_drop_tablespace_cantian_error", thd, &ddl_ctrl, &ret); + update_sess_ctx_by_tch(tch, hton, thd); + return tse_ddl_handle_fault("tse_drop_tablespace", thd, &ddl_ctrl, ret, alter_info->tablespace_name); +} + + +/** + alter tablespace. + @param: hton in, tse handlerton + @param: thd in, handle to the MySQL thread + @param: savepoint in, savepoint data + @return: 0 if succeeds +*/ +int tsebase_alter_tablespace(handlerton *hton, THD *thd, + st_alter_tablespace *alter_info, + const dd::Tablespace *old_ts_def, + dd::Tablespace *new_ts_def) { + DBUG_TRACE; + + // TODO:只读模式和强制恢复模式不能修改表空间 + switch (alter_info->ts_cmd_type) { + case CREATE_TABLESPACE: + return tse_create_tablespace_handler(hton, thd, alter_info, new_ts_def); + case ALTER_TABLESPACE: + return tse_alter_tablespace_handler(hton, thd, alter_info, old_ts_def, new_ts_def); + case DROP_TABLESPACE: + return tse_drop_tablespace_handler(hton, thd, alter_info, old_ts_def); + case CREATE_UNDO_TABLESPACE: + case ALTER_UNDO_TABLESPACE: + case DROP_UNDO_TABLESPACE: + return CT_SUCCESS; + case CREATE_LOGFILE_GROUP: + case DROP_LOGFILE_GROUP: + case ALTER_LOGFILE_GROUP: + my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "LOGFILE GROUP", "by CTC"); + break; + case ALTER_ACCESS_MODE_TABLESPACE: + my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "ACCESS MODE", "by CTC"); + break; + case CHANGE_FILE_TABLESPACE: + my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "CHANGE FILE", "by CTC"); + break; + case TS_CMD_NOT_DEFINED: + default: + my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "UNKNOWN", "by CTC"); + } + + return HA_ADMIN_NOT_IMPLEMENTED; +} + +static bool tse_fill_column_precision_and_scale(TcDb__TseDDLColumnDef *column, Field *field) { + switch (field->real_type()) { + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: { + if (field->decimals() == DECIMAL_NOT_SPECIFIED) { + column->datatype->scale = CT_UNSPECIFIED_NUM_SCALE; + column->datatype->precision = CT_UNSPECIFIED_NUM_PREC; + } else { + column->datatype->scale = field->decimals(); + column->datatype->precision = ((Field_real *)field)->max_display_length(); + } + break; + } + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: { + Field_new_decimal *f = (Field_new_decimal *)field; + column->datatype->precision = f->precision; + column->datatype->scale = f->decimals(); + if (f->precision > MAX_NUMERIC_BUFF) { + my_error(ER_TOO_BIG_PRECISION, MYF(0), static_cast(f->precision), + column->name, static_cast(MAX_NUMERIC_BUFF)); + return false; + } + break; + } + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP2: { + column->datatype->precision = field->decimals(); + break; + } + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: { + column->datatype->precision = ((Field_enum *)field)->typelib->count; + break; + } + case MYSQL_TYPE_BIT: + column->datatype->precision = field->max_display_length(); + break; + default: + break; + } + return true; +} + +static bool tse_ddl_fill_column_by_field_fill_type(TcDb__TseDDLColumnDef *column, Field *field) { + if (!tse_ddl_get_data_type_from_mysql_type(field, field->type(), &column->datatype->datatype)) { + char info[300]; // max column name length(64) * max_mb_size(4) + redundancy + sprintf(info, "column name: %s", field->field_name); + my_error(ER_FEATURE_UNSUPPORTED, MYF(0), "*DataType Conversion*", info); + return false; + } + + column->datatype->size = field->pack_length(); + column->datatype->mysql_ori_datatype = field->real_type(); + + if (field->type() == MYSQL_TYPE_VARCHAR) { + uint32_t varchar_length = field->row_pack_length(); + if (VARCHAR_AS_BLOB(varchar_length)) { + column->datatype->datatype = TSE_DDL_TYPE_CLOB; + } + column->datatype->size = varchar_length; + } + if ((is_numeric_type(field->type()) && field->is_unsigned()) || + field->real_type() == MYSQL_TYPE_ENUM || field->real_type() == MYSQL_TYPE_BIT) { + column->is_unsigned = 1; + } + + if (!tse_fill_column_precision_and_scale(column, field)) { + tse_log_error("fill column precision and scale failed"); + return false; + } + return true; +} + +static int tse_prepare_enum_field_impl(THD *thd, Create_field *sql_field, String *def) { + DBUG_TRACE; + assert(sql_field->sql_type == MYSQL_TYPE_ENUM); + if (!sql_field->charset) { + sql_field->charset = &my_charset_bin; + } + /* SQL "NULL" maps to NULL */ + if (def == nullptr) { + if ((sql_field->flags & NOT_NULL_FLAG) != 0) { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + return TSE_ENUM_DEFAULT_NULL; + } + } else { + def->length(sql_field->charset->cset->lengthsp(sql_field->charset, def->ptr(), def->length())); + TYPELIB *interval = sql_field->interval; + if (!interval) { + interval = create_typelib(thd->mem_root, sql_field); + } + uint enum_index = find_type2(interval, def->ptr(), def->length(), sql_field->charset); + if (enum_index == 0) { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + return TSE_ENUM_DEFAULT_INVALID; + } + return enum_index; + } + my_error(ER_INVALID_DEFAULT, MYF(0), "constant default is null"); + return TSE_ENUM_DEFAULT_INVALID; +} + +static bool tse_prepare_set_field_impl(THD *thd, Create_field *sql_field, ulonglong *set_bitmap, + String *def, TcDb__TseDDLColumnDef *column) { + DBUG_TRACE; + assert(sql_field->sql_type == MYSQL_TYPE_SET); + + if (!sql_field->charset) { + sql_field->charset = &my_charset_bin; + } + TYPELIB *interval = sql_field->interval; + if (!interval) { + /* + Create the typelib in runtime memory - we will free the + occupied memory at the same time when we free this + sql_field -- at the end of execution. + */ + interval = create_typelib(thd->mem_root, sql_field); + } + + // Comma is an invalid character for SET names + char comma_buf[4]; /* 4 bytes for utf32 */ + int comma_length = sql_field->charset->cset->wc_mb(sql_field->charset, ',', reinterpret_cast(comma_buf), + reinterpret_cast(comma_buf) + sizeof(comma_buf)); + assert(comma_length > 0); + + if (!set_column_datatype(interval->count, column)) { + tse_log_error("set column datatype failed, set num is %lu", interval->count); + return false; + } + + for (uint i = 0; i < interval->count; i++) { + uint is_default_values = sql_field->charset->coll->strstr(sql_field->charset, interval->type_names[i], + interval->type_lengths[i], comma_buf, comma_length, nullptr, 0); + if (is_default_values != 0) { + ErrConvString err(interval->type_names[i], interval->type_lengths[i], sql_field->charset); + my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr()); + return false; + } + } + + const char *not_used; + uint not_used2; + bool not_found = false; + // SQL "NULL" maps to NULL + if (def == nullptr) { + if ((sql_field->flags & NOT_NULL_FLAG) != 0) { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + return false; + } else { + // else, NULL is an allowed value + *set_bitmap = find_set(interval, nullptr, 0, sql_field->charset, ¬_used, ¬_used2, ¬_found); + } + } else { + // default not NULL */ + *set_bitmap = find_set(interval, def->ptr(), def->length(), sql_field->charset, ¬_used, ¬_used2, ¬_found); + } + + if (not_found) { + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + return false; + } + + return true; +} + +static bool tse_process_string_default_value(TcDb__TseDDLColumnDef *column, string &expr_str, + char **mem_start, char *mem_end, bool is_blob_type) { + if (!is_blob_type) { + boost::algorithm::replace_all(expr_str, "'", "''"); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, expr_str.length() + 1); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for bit default text failed, mem_start is null"); + return false; + } + strncpy(column->default_text, expr_str.c_str(), expr_str.length() + 1); + } else { + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, expr_str.length() * 2 + 1); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for bit default text failed, mem_start is null"); + return false; + } + int pos = 0; + for (char &ch : expr_str) { + sprintf(column->default_text + pos, "%02X", ch); + pos += 2; + } + column->default_text[pos] = '\0'; + } + return true; +} + +static bool tse_get_bit_default_value( + THD *thd, TcDb__TseDDLColumnDef *column, Field *field, const Create_field *fld, const dd::Column *col_obj, + char **mem_start, char *mem_end, bool is_expr_value) { + column->is_unsigned = 1; + longlong num = 0; + if (!is_expr_value) { + char* bit_value_buf = const_cast(col_obj->default_value().data()); + uint32_t bit_value_len = (uint32_t)(col_obj->default_value().length()); + Field_bit *bitfield = dynamic_cast(field); + Field_bit *new_field = bitfield->clone(thd->mem_root); + uchar bit_ptr[TSE_MAX_BIT_LEN]; + for (uint32_t i = 0; i < bit_value_len; i++) { + bit_ptr[i] = bit_value_buf[i]; + } + new_field->set_field_ptr(bit_ptr); + num = new_field->val_int(); + } else { + Item *expr_item; + if (fld == nullptr) { + expr_item = field->m_default_val_expr->expr_item; + } else { + expr_item = fld->m_default_val_expr->expr_item; + } + if (expr_item->type() != Item::STRING_ITEM) { + num = expr_item->val_int(); + } else { + StringBuffer tmp; + String *res = expr_item->val_str(&tmp); + if (res == nullptr) { + num = 0; + } else { + int err = 0; + num = my_strntoll(res->charset(), res->ptr(), res->length(), 10, nullptr, + &err); + if (err) { + string expr_str(res->c_ptr()); + return tse_process_string_default_value(column, expr_str, mem_start, mem_end, false); + } + } + } + } + + uint32_t num_len = to_string(num).length(); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, num_len + 1); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for bit default text failed, mem_start is null"); + return false; + } + sprintf(column->default_text, "%llu", num); + column->default_text[num_len] = '\0'; + + return true; +} + +static bool tse_get_datetime_default_value( + TcDb__TseDDLColumnDef *column, Field *field, const Create_field *fld, const dd::Column *col_obj, + char **mem_start, char *mem_end, tse_column_option_set_bit *option_set, bool is_expr_value) { + if (field->has_insert_default_datetime_value_expression()) { + // current_timestamp (or with ON UPDATE CURRENT_TIMESTAMP) + option_set->is_default_func = 1; + option_set->is_curr_timestamp = 1; + column->default_text = const_cast(col_obj->default_value_utf8().data()); + return true; + } + if (field->has_update_default_datetime_value_expression() && + (!col_obj->default_value_utf8().data() || + strlen(col_obj->default_value_utf8().data()) == 0)) { + // ON UPDATE CURRENT_TIMESTAMP without default_value + return true; + } + date_detail_t date_detail; + // decode mysql datetime from binary + MYSQL_TIME ltime; + memset(<ime, 0, sizeof(MYSQL_TIME)); + memset(&date_detail, 0, sizeof(date_detail_t)); + const field_cnvrt_aux_t* mysql_info = get_auxiliary_for_field_convert(field, field->type()); + assert(mysql_info != NULL); + string expr_str; + if (is_expr_value) { + String str; + if (fld) { + expr_str = (fld->m_default_val_expr->expr_item->val_str(&str))->c_ptr(); + } else { + expr_str = (field->m_default_val_expr->expr_item->val_str(&str))->c_ptr(); + } + MYSQL_TIME_STATUS status; + str_to_datetime(expr_str.c_str(), expr_str.length(), <ime, TIME_FRAC_TRUNCATE | TIME_FUZZY_DATE, + &status); + } else { + expr_str = const_cast(col_obj->default_value_utf8().data()); + const uchar *mysql_ptr = (const uchar *)(col_obj->default_value().data()); + decode_mysql_datetime(ltime, mysql_info, mysql_ptr, field); + } + + int ret = assign_mysql_date_detail(mysql_info->mysql_field_type, ltime, &date_detail); + if (ret != CT_SUCCESS) { + return false; + } + + if (check_zero_date(date_detail)) { + char *tmp_zero_date = const_cast("0000-00-00 00:00:00"); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, strlen(tmp_zero_date) + 1); + assert(column->default_text != NULL); + memset(column->default_text, 0, strlen(tmp_zero_date) + 1); + memcpy(column->default_text, tmp_zero_date, strlen(tmp_zero_date) + 1); + return true; + } + if (field->real_type() == MYSQL_TYPE_TIME2) { + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(char) * (expr_str.length() + sizeof("1900-01-01 ") + 1)); + assert(column->default_text != NULL); + sprintf(column->default_text, "1900-01-01 %s", expr_str.c_str()); + } else if (!is_expr_value && field->real_type() == MYSQL_TYPE_TIMESTAMP2) { + char tmp_timestamp[MAX_DATE_STRING_REP_LENGTH]; + int len = my_datetime_to_str(ltime, tmp_timestamp, field->decimals()); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, len + 1); + assert(column->default_text != NULL); + memset(column->default_text, 0, len + 1); + memcpy(column->default_text, tmp_timestamp, len); + column->default_text[len] = '\0'; + } else { + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, expr_str.length() + 1); + strncpy(column->default_text, expr_str.c_str(), expr_str.length() + 1); + } + return true; +} + +static int tse_prepare_enum_field(THD *thd, Field *field, const Create_field *fld, + const CHARSET_INFO *field_cs) { + int is_enum = 0; + String default_str; + String *def; + Create_field* sql_field; + // fld == nullptr 为create,此时field_charset 为空值需处理置位 + if (fld == nullptr) { + Create_field sql_field_local(field, field); + if (!field_cs) { + sql_field_local.charset = field_cs; + } + sql_field = sql_field_local.clone(thd->mem_root); + } else { + // fld != nullptr 为alter,此时field_charset 有值不用置位 + sql_field = const_cast(fld); + } + if (sql_field->constant_default != nullptr) { + def = sql_field->constant_default->val_str(&default_str); + } else { + def = sql_field->m_default_val_expr->expr_item->val_str(&default_str); + } + if (fld == nullptr) { + // 修改ENUM default带charset + // 或设置了全局charset找不到enum_index + // 判断当前charset与field charset是否一致 + if(field_cs == nullptr || strcmp(def->charset()->csname, field_cs->csname) != 0) { + sql_field->charset = def->charset(); + } + } + is_enum = tse_prepare_enum_field_impl(thd, sql_field, def); + return is_enum; +} + +static bool tse_get_enum_default_value( + THD *thd, TcDb__TseDDLColumnDef *column, const dd::Column *col_obj, Field *field, const Create_field *fld, + char **mem_start, char *mem_end, const CHARSET_INFO *field_cs) { + int is_enum; + column->is_unsigned = 1; + column->datatype->datatype = column->datatype->size == 1 ? TSE_DDL_TYPE_TINY : TSE_DDL_TYPE_SHORT; + + is_enum = tse_prepare_enum_field(thd, field, fld, field_cs); + + if (is_enum == TSE_ENUM_DEFAULT_INVALID) { + return false; + } + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, 10); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for enum default text failed, mem_start is null"); + return false; + } + if (is_enum != TSE_ENUM_DEFAULT_NULL) { + sprintf(column->default_text, "%d", is_enum); + } else { + column->default_text = const_cast(col_obj->default_value_utf8().data()); + } + return true; +} + +static bool tse_prepare_set_field(THD *thd, Field *field, const Create_field *fld, const CHARSET_INFO *field_cs, + ulonglong *set_bitmap, TcDb__TseDDLColumnDef *column) { + bool is_get_set_bitmap = 0; + String default_str; + String *def; + Create_field* sql_field; + // fld == nullptr 为create,此时field_charset 为空值需处理置位 + if (fld == nullptr) { + Create_field sql_field_local(field, field); + if (!field_cs) { + sql_field_local.charset = field_cs; + } + sql_field = sql_field_local.clone(thd->mem_root); + } else { + // fld != nullptr 为alter,此时field_charset 有值不用置位 + sql_field = const_cast(fld); + } + if (sql_field->constant_default != nullptr) { + def = sql_field->constant_default->val_str(&default_str); + } else { + def = sql_field->m_default_val_expr->expr_item->val_str(&default_str); + } + if (fld == nullptr) { + if(field_cs == nullptr || strcmp(def->charset()->csname, field_cs->csname) != 0) { + sql_field->charset = def->charset(); + } + } + + is_get_set_bitmap = tse_prepare_set_field_impl(thd, sql_field, set_bitmap, def, column); + return is_get_set_bitmap; +} + +static bool tse_get_set_default_value( + THD *thd, TcDb__TseDDLColumnDef *column, Field *field, const Create_field *fld, char **mem_start, + char *mem_end, const CHARSET_INFO *field_cs) { + ulonglong set_bitmap; + bool is_get_set_bitmap = false; + if (is_numeric_type(field->type()) && field->is_unsigned()) { + column->is_unsigned = 1; + } + // fld == nullptr 为create,此时field_charset 为空值需处理置位 + is_get_set_bitmap = tse_prepare_set_field(thd, field, fld, field_cs, &set_bitmap, column); + + if (!is_get_set_bitmap) { + return false; + } + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, 64); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for set default text failed, mem_start is null"); + return false; + } + sprintf(column->default_text, "%lld", set_bitmap); + + return true; +} + +static bool tse_verify_string_default_length(TcDb__TseDDLColumnDef *column, String* default_str, Field *field, + const Create_field *fld) { + if (column->datatype->datatype == TSE_DDL_TYPE_CLOB) { + return true; + } + const CHARSET_INFO* col_charset = fld ? fld->charset : field->charset(); + int max_char_count = column->datatype->size / col_charset->mbmaxlen; + int default_str_char_count = default_str->numchars(); + if (default_str_char_count > max_char_count) { + my_error(ER_INVALID_DEFAULT, MYF(0), column->name); + return false; + } + return true; +} + +static bool tse_get_string_default_value( + TcDb__TseDDLColumnDef *column, Field *field, const dd::Column *col_obj, const Create_field *fld, + char **mem_start, char *mem_end, bool is_blob_type) { + char *field_default_string = nullptr; + if (fld == nullptr) { + if (!field->m_default_val_expr) { + if (field->real_type() == MYSQL_TYPE_STRING) { + field_default_string = const_cast(col_obj->default_value().data()); + } else { + field_default_string = const_cast((col_obj->default_value().data() + 1)); + } + } else { + String tmp_string; + String* tmp_string_ptr; + assert(field->m_default_val_expr); + tmp_string_ptr = field->m_default_val_expr->expr_item->val_str(&tmp_string); + if (!is_blob_type && !tse_verify_string_default_length(column, tmp_string_ptr, field, fld)) { + return false; + } + field_default_string = tmp_string_ptr->c_ptr(); + } + } else { + // for alter table add column + String tmp_string; + String* tmp_string_ptr; + if (fld->constant_default != nullptr) { + tmp_string_ptr = fld->constant_default->val_str(&tmp_string); + } else { + tmp_string_ptr = fld->m_default_val_expr->expr_item->val_str(&tmp_string); + } + if (!tse_verify_string_default_length(column, tmp_string_ptr, field, fld)) { + return false; + } + field_default_string = tmp_string_ptr->c_ptr(); + } + string expr_str(field_default_string); + return tse_process_string_default_value(column, expr_str, mem_start, mem_end, is_blob_type); +} + +static bool tse_get_numeric_default_value( + TcDb__TseDDLColumnDef *column, Field *field, const dd::Column *col_obj, const Create_field *fld, + char **mem_start, char *mem_end, bool is_expr_value) +{ + char *field_default_string = nullptr; + if (is_expr_value) { + String tmp_string; + Item* expr_item; + expr_item = fld ? fld->m_default_val_expr->expr_item : field->m_default_val_expr->expr_item; + if (expr_item->type() == Item::VARBIN_ITEM) { + longlong num = expr_item->val_int(); + uint32_t num_len = to_string(num).length(); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, num_len + 1); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for set default text failed, mem_start is null"); + return false; + } + sprintf(column->default_text, "%llu", num); + column->default_text[num_len] = '\0'; + } else { + field_default_string = expr_item->val_str(&tmp_string)->c_ptr(); + column->default_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, strlen(field_default_string) + 1); + if (column->default_text == nullptr) { + tse_log_error("alloc mem for set default text failed, mem_start is null"); + return false; + } + strncpy(column->default_text, field_default_string, strlen(field_default_string) + 1); + } + } else { + column->default_text = const_cast(col_obj->default_value_utf8().data()); + } + return true; +} + +static bool tse_check_expression_default_value(TcDb__TseDDLColumnDef *column, Field *field, const Create_field *fld, + tse_column_option_set_bit *option_set, bool* is_expr_value) { + if ((field != nullptr && !field->m_default_val_expr) || + (fld != nullptr && !fld->m_default_val_expr)) { + //排除普通表达式 + option_set->is_default_func = 0; + return true; + } + Item *constant_default = fld == nullptr ? field->m_default_val_expr->expr_item : + fld->m_default_val_expr->expr_item; + //default expression + if (!constant_default->const_for_execution() && constant_default->type() != Item::FUNC_ITEM) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Current storage engine only support default expression without variable parameters"); + return false; + } else if (constant_default->type() == Item::FUNC_ITEM) { + // default function + Item_func *item_func = (Item_func *)constant_default; + column->default_func_name = const_cast(item_func->func_name()); + for (uint i = 0; i < item_func->arg_count; i++) { + if (item_func->get_arg(i)->type() == Item::FIELD_ITEM) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Current storage engine only support default function without variable parameters"); + return false; + } + } + } else { + option_set->is_default_func = 0; + *is_expr_value = true; + } + return true; +} + + +static bool tse_ddl_fill_column_default_value( + THD *thd, TcDb__TseDDLColumnDef *column, Field *field, const Create_field *fld, const dd::Column *col_obj, + tse_column_option_set_bit *option_set, char **mem_start, char *mem_end, const CHARSET_INFO *field_cs) { + option_set->is_default = true; + option_set->is_default_null = false; + + // function except DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP + // CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP is described in tse_get_datetime_default_value + option_set->is_default_func = field->has_insert_default_general_value_expression() && + !field->has_insert_default_datetime_value_expression() && + !field->has_update_default_datetime_value_expression(); + option_set->is_curr_timestamp = 0; + bool is_expr_value = false; + if (option_set->is_default_func) { + TSE_RETURN_IF_ERROR(tse_check_expression_default_value(column, field, fld, option_set, &is_expr_value), false); + if (!is_expr_value) { + return true; + } + } + + bool is_blob_type = false; + switch (field->real_type()) { + case MYSQL_TYPE_BIT: + TSE_RETURN_IF_ERROR(tse_get_bit_default_value(thd, column, field, fld, col_obj, mem_start, mem_end, is_expr_value), false); + break; + case MYSQL_TYPE_BLOB: + is_blob_type = (column->datatype->datatype != TSE_DDL_TYPE_CLOB); + case MYSQL_TYPE_JSON: + if (!is_expr_value) { + column->default_text = const_cast(col_obj->default_value_utf8().data()); + break; + } + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VARCHAR: + TSE_RETURN_IF_ERROR(tse_get_string_default_value(column, field, col_obj, fld, mem_start, mem_end, is_blob_type), false); + break; + case MYSQL_TYPE_ENUM: + TSE_RETURN_IF_ERROR(tse_get_enum_default_value(thd, column, col_obj, field, fld, mem_start, mem_end, field_cs), false); + break; + case MYSQL_TYPE_SET: + TSE_RETURN_IF_ERROR(tse_get_set_default_value(thd, column, field, fld, mem_start, mem_end, field_cs), false); + break; + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP2: + case MYSQL_TYPE_TIME2: + TSE_RETURN_IF_ERROR(tse_get_datetime_default_value(column, field, fld, col_obj, mem_start, mem_end, option_set, is_expr_value), false); + break; + default: + TSE_RETURN_IF_ERROR(tse_get_numeric_default_value(column, field, col_obj, fld, mem_start, mem_end, is_expr_value), false); + break; + } + return true; +} + +static void tse_fill_column_option_set(TcDb__TseDDLColumnDef *column, Field *field, + TABLE *form, tse_column_option_set_bit *option_set) { + column->is_option_set = 0; + option_set->is_option_set= 0; + option_set->primary = false; + option_set->is_default_null = false; + option_set->has_null = true; // 保证nullable的值是准确的 + option_set->nullable = (field->is_flag_set(NOT_NULL_FLAG)) ? 0 : 1; + + if (field->is_flag_set(PRI_KEY_FLAG)) { + option_set->primary = true; + option_set->has_null = true; + option_set->nullable = false; + } + option_set->unique = field->is_flag_set(UNIQUE_KEY_FLAG); + column->cons_name = option_set->primary ? const_cast("PRIMARY") : + (option_set->unique ? column->name : nullptr); + option_set->is_serial = field->is_flag_set(AUTO_INCREMENT_FLAG); + option_set->is_comment = field->comment.length > 0; + column->comment = option_set->is_comment ? const_cast(field->comment.str) : nullptr; + + /*处理自增列为unique key的情况*/ + if(option_set->is_serial) { + for (uint i = 0; i < form->s->keys; i++) { + if (strcmp(column->name, form->s->keynames.type_names[i]) == 0) { + option_set->unique = true; + option_set->primary = false; + column->cons_name = column->name; + } + } + } + const field_cnvrt_aux_t *mysql_info = get_auxiliary_for_field_convert(field, field->real_type()); + if (mysql_info->sql_data_type == STRING_DATA || mysql_info->sql_data_type == LOB_DATA) { + column->collate = tse_get_column_cs(field->charset()); + option_set->is_collate = 1; + } +} + +static bool tse_ddl_fill_column_by_field( + THD *thd, TcDb__TseDDLColumnDef *column, Field *field, + const dd::Table *table_def, TABLE *form, const Create_field *fld, + tse_alter_column_alter_mode alter_mode, char **mem_start, char *mem_end, const CHARSET_INFO *field_cs) { + const dd::Column *col_obj = NULL; + col_obj = table_def ? table_def->get_column(field->field_name) : nullptr; // create view中创临时表,table_def为空 + /* + We need this to get default values from the table + We have to restore the read_set if we are called from insert in case + of row based replication. + */ + my_bitmap_map *old_map = tmp_use_all_columns(form, form->read_set); + auto grd = create_scope_guard( + [&]() { tmp_restore_column_map(form->read_set, old_map); }); + if (fld != NULL && fld->change != NULL) { + column->name = const_cast(fld->change); + if (strcmp(fld->change, field->field_name) != 0) { + column->new_name = const_cast(field->field_name); + } + } else { + column->name = const_cast(field->field_name); + } + + TSE_RETURN_IF_ERROR(tse_ddl_fill_column_by_field_fill_type(column, field), false); + + tse_column_option_set_bit option_set; + tse_fill_column_option_set(column, field, form, &option_set); + + if (tse_is_with_default_value(field, col_obj)) { + TSE_RETURN_IF_ERROR(tse_ddl_fill_column_default_value(thd, column, field, fld, col_obj, + &option_set, mem_start, mem_end, field_cs), false); + } else { + option_set.is_default = 0; + option_set.is_default_func = 0; + option_set.is_curr_timestamp = 0; + option_set.is_default_null = 1; + } + // 这句代码要放在所有设置option_set的后面 + column->is_option_set = option_set.is_option_set; + column->alter_mode = alter_mode; // tse_alter_column_alter_mode + return true; +} + +static int tse_ddl_alter_table_fill_foreign_key_info(TcDb__TseDDLForeignKeyDef *fk_def, const Foreign_key_spec *fk, + char **mem_start, char *mem_end) +{ + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(fk->name.str)); + fk_def->name = const_cast(fk->name.str); + fk_def->delete_opt = tse_ddl_get_foreign_key_rule(fk->delete_opt); + fk_def->update_opt = tse_ddl_get_foreign_key_rule(fk->update_opt); + size_t buf_len = fk->ref_db.length + 1; + fk_def->referenced_table_schema_name = (char *)tse_ddl_alloc_mem(mem_start, mem_end, buf_len); + if (fk_def->referenced_table_schema_name == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + tse_copy_name(fk_def->referenced_table_schema_name, fk->ref_db.str, buf_len); + fk_def->referenced_table_name = + const_cast(fk->ref_table.str); + for (uint j = 0; j < fk_def->n_elements; j++) { + TcDb__TseDDLForeignKeyElementDef *fk_ele = fk_def->elements[j]; + fk_ele->src_column_name = + const_cast(fk->columns[j]->get_field_name()); + fk_ele->ref_column_name = + const_cast(fk->ref_columns[j]->get_field_name()); + } + return CT_SUCCESS; +} + +static int tse_ddl_create_table_fill_foreign_key_info(TcDb__TseDDLCreateTableDef *req, + const dd::Table *table_def, char **mem_start, char *mem_end) { + if (req->n_fk_list == 0) { + return CT_SUCCESS; + } + for (uint i = 0; i < req->n_fk_list; i++) { + TcDb__TseDDLForeignKeyDef *fk_def = req->fk_list[i]; + assert(table_def != nullptr); + const dd::Foreign_key *fk = table_def->foreign_keys().at(i); + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(fk->name().data())); + fk_def->name = const_cast(fk->name().data()); + + fk_def->delete_opt = tse_ddl_get_foreign_key_rule(fk->delete_rule()); + fk_def->update_opt = tse_ddl_get_foreign_key_rule(fk->update_rule()); + size_t buf_len = fk->referenced_table_schema_name().length() + 1; + fk_def->referenced_table_schema_name = (char *)tse_ddl_alloc_mem(mem_start, mem_end, buf_len); + if (fk_def->referenced_table_schema_name == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + tse_copy_name(fk_def->referenced_table_schema_name, fk->referenced_table_schema_name().data(), buf_len); + fk_def->referenced_table_name = + const_cast(fk->referenced_table_name().data()); + for (uint j = 0; j < fk_def->n_elements; j++) { + TcDb__TseDDLForeignKeyElementDef *fk_ele = fk_def->elements[j]; + const dd::Foreign_key_element *fk_col_obj = fk->elements().at(j); + fk_ele->src_column_name = + const_cast(fk_col_obj->column().name().data()); + fk_ele->ref_column_name = + const_cast(fk_col_obj->referenced_column_name().data()); + } + } + return CT_SUCCESS; +} + +static void tse_fill_prefix_func_key_part(TcDb__TseDDLTableKeyPart *req_key_part, + const Field *field, uint16 prefix_len) { + req_key_part->is_func = true; + if (field->real_type() == MYSQL_TYPE_BLOB && field->charset() == &my_charset_bin && + field->is_flag_set(BINARY_FLAG)) { + req_key_part->func_name = const_cast("substrb"); + snprintf(req_key_part->func_text, FUNC_TEXT_MAX_LEN - 1, "substrb(%s,1,%d)", + field->field_name, prefix_len); + } else { + req_key_part->func_name = const_cast("substr"); + snprintf(req_key_part->func_text, FUNC_TEXT_MAX_LEN - 1, "substr(%s,1,%d)", + field->field_name, prefix_len); + } + return; +} + +static uint32_t tse_fill_func_key_part(THD *thd, TcDb__TseDDLTableKeyPart *req_key_part, Value_generator *gcol_info) +{ + uint32_t arg_count = ((Item_func *)gcol_info->expr_item)->arg_count; + if (arg_count == 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "[TSE_CREATE_TABLE]: There is no functional index."); + return CT_ERROR; + } + + req_key_part->is_func = true; + req_key_part->func_name = const_cast(((Item_func *)gcol_info->expr_item)->func_name()); + Item **args = ((Item_func *)gcol_info->expr_item)->arguments(); + uint32_t col_item_count = 0; + for (uint32_t i = 0; i < arg_count; i++) { + if (args[i]->type() == Item::FIELD_ITEM) { + if (col_item_count >= 1) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Cantian does not support function indexes with multiple columns of arguments."); + return CT_ERROR; + } + req_key_part->name = const_cast(args[i]->item_name.ptr()); + col_item_count++; + } + } + + char buffer[FUNC_TEXT_MAX_LEN] = {0}; + String gc_expr(buffer, sizeof(buffer), &my_charset_bin); + gcol_info->print_expr(thd, &gc_expr); + string expr_str(buffer); + expr_str.erase(remove(expr_str.begin(), expr_str.end(), '`'), expr_str.end()); + // 处理json_value建索引,只允许returning char + // 不带returning默认char512 + if (strcmp(req_key_part->func_name, "json_value") == 0) { + std::regex reg_char("returning[ ]char[(]\\d+[)]"); + std::regex reg_charset("[_][a-z]+[0-9]*[a-z]*[0-9]*['$]"); + std::regex reg_charset2("[ ]character[ ]set[ ][a-z]+[0-9]*[a-z]*[0-9]"); + expr_str =std::regex_replace(expr_str, reg_char, "returning CLOB"); + expr_str =std::regex_replace(expr_str, reg_charset, "'"); + //处理char带charset设置 + expr_str =std::regex_replace(expr_str, reg_charset2, ""); + } + strncpy(req_key_part->func_text, expr_str.c_str(), FUNC_TEXT_MAX_LEN - 1); + return CT_SUCCESS; +} + +static bool tse_ddl_create_table_fill_add_key(TcDb__TseDDLCreateTableDef *req, THD *thd, + const dd::Table *table_def, TABLE *form, char *user) { + if (req->n_key_list == 0) { + return true; + } + + if (table_def == nullptr) { + for (uint i = 0; i < req->n_key_list; i++) { + TcDb__TseDDLTableKey *req_key_def = req->key_list[i]; + const KEY *key = form->key_info + i; + req_key_def->user = user; + req_key_def->table = req->name; + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(key->name)); + req_key_def->name = const_cast(key->name); + req_key_def->space = NULL; + TSE_RETURN_IF_ERROR(get_tse_key_type(key, &req_key_def->key_type), false); + TSE_RETURN_IF_ERROR(get_tse_key_algorithm(key->algorithm, &req_key_def->algorithm), false); + if (req_key_def->key_type == TSE_KEYTYPE_PRIMARY || req_key_def->key_type == TSE_KEYTYPE_UNIQUE) { + req_key_def->is_constraint = true; + } + for (uint j = 0; j < req_key_def->n_columns; j++) { + TcDb__TseDDLTableKeyPart *req_key_part = req_key_def->columns[j]; + KEY_PART_INFO *key_part = key->key_part + j; + if (key_part->key_part_flag & HA_REVERSE_SORT) { + req_key_def->is_dsc = true; + } + bool is_prefix_key = false; + assert(key_part != NULL); + Field *fld = form->field[key_part->field->field_index()]; + assert(fld != nullptr); + if (fld->is_field_for_functional_index()) { + req_key_def->is_func = true; + TSE_RETURN_IF_ERROR(tse_fill_func_key_part(thd, req_key_part, fld->gcol_info) == CT_SUCCESS, false); + } else { + if (fld->is_virtual_gcol()) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Cantian does not support index on virtual generated column."); + return false; + } + + uint prefix_len = get_prefix_index_len(fld, key_part->length); + if (prefix_len) { + tse_fill_prefix_func_key_part(req_key_part, fld, prefix_len); + is_prefix_key = true; + } else { + req_key_part->is_func = false; + req_key_part->func_text = nullptr; + } + req_key_part->name = const_cast(key_part->field->field_name); + } + req_key_part->length = key_part->length; + tse_ddl_get_data_type_from_mysql_type(fld, fld->type(), &req_key_part->datatype); + if (is_prefix_key && fld->is_flag_set(BLOB_FLAG)) { + req_key_part->datatype = TSE_DDL_TYPE_VARCHAR; + } + } + } + return true; + } + + for (uint i = 0; i < req->n_key_list; i++) { + TcDb__TseDDLTableKey *req_key_def = req->key_list[i]; + assert(table_def != nullptr); + const dd::Index *idx = table_def->indexes().at(i); + req_key_def->user = user; + req_key_def->table = req->name; + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(idx->name().data())); + req_key_def->name = const_cast(idx->name().data()); + req_key_def->space = NULL; + TSE_RETURN_IF_ERROR(tse_ddl_get_create_key_type(idx->type(), &req_key_def->key_type), false); + TSE_RETURN_IF_ERROR(tse_ddl_get_create_key_algorithm(idx->algorithm(), &req_key_def->algorithm), false); + + for (uint j = 0; j < req_key_def->n_columns; j++) { + TcDb__TseDDLTableKeyPart *req_key_part = req_key_def->columns[j]; + const dd::Index_element *key_part = idx->elements().at(j); + if (key_part->order() == dd::Index_element::ORDER_DESC) { + req_key_def->is_dsc = true; + } + bool is_prefix_key = false; + assert(key_part != NULL); + Field *fld = tse_get_field_by_name(form, key_part->column().name().data()); + assert(fld != nullptr); + + if (fld->is_field_for_functional_index()) { + req_key_def->is_func = true; + TSE_RETURN_IF_ERROR(tse_fill_func_key_part(thd, req_key_part, fld->gcol_info) == CT_SUCCESS, false); + } else { + if (fld->is_virtual_gcol()) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Cantian does not support index on virtual generated column."); + return false; + } + + uint prefix_len = get_prefix_index_len(fld, key_part->length()); + if (prefix_len) { + tse_fill_prefix_func_key_part(req_key_part, fld, prefix_len); + is_prefix_key = true; + } else { + req_key_part->is_func = false; + req_key_part->func_text = nullptr; + } + req_key_part->name = const_cast(key_part->column().name().data()); + } + req_key_part->length = key_part->length(); + tse_ddl_get_data_type_from_mysql_type(fld, fld->type(), &req_key_part->datatype); + if (is_prefix_key && fld->is_flag_set(BLOB_FLAG)) { + req_key_part->datatype = TSE_DDL_TYPE_VARCHAR; + } + } + } + return true; +} + +static int tse_ddl_fill_partition_table_info(const dd::Partition *pt, char **mem_start, char *mem_end, + TcDb__TseDDLPartitionDef *part_def, uint32_t part_id) +{ + TcDb__TseDDLPartitionTableDef *part_table = part_def->part_table_list[part_id]; + part_table->name = const_cast(pt->name().data()); + part_table->n_subpart_table_list = pt->subpartitions().size(); + if (part_table->n_subpart_table_list > 0) { + part_table->subpart_table_list = + (TcDb__TseDDLPartitionTableDef **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef *) * pt->subpartitions().size()); + if (part_table->subpart_table_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLPartitionTableDef **subpart_table_list = part_table->subpart_table_list; + uint32_t i = 0; + for (const dd::Partition *sub_part_obj : pt->subpartitions()) { + subpart_table_list[i] = (TcDb__TseDDLPartitionTableDef *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef)); + if (subpart_table_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlpartition_table_def__init(subpart_table_list[i]); + TcDb__TseDDLPartitionTableDef *sub_part_table = part_table->subpart_table_list[i]; + sub_part_table->name = const_cast(sub_part_obj->name().data()); + i++; + } + } + return 0; +} + +static int tse_ddl_prepare_create_partition_info(TcDb__TseDDLCreateTableDef *req, const dd::Table *table_def, + char **mem_start, char *mem_end) +{ + req->partition_def = (TcDb__TseDDLPartitionDef *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionDef)); + if (req->partition_def == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlpartition_def__init(req->partition_def); + int ret = convert_tse_part_type(table_def->partition_type(), &req->partition_def->part_type); + if (ret != 0) { + return ret; + } + + ret = convert_tse_subpart_type(table_def->subpartition_type(), &req->partition_def->subpart_type); + if (ret != 0) { + return ret; + } + + req->partition_def->n_part_table_list = table_def->partitions().size(); + + req->partition_def->part_table_list = + (TcDb__TseDDLPartitionTableDef **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef *) * req->partition_def->n_part_table_list); + if (req->partition_def->part_table_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLPartitionTableDef **part_table_list = req->partition_def->part_table_list; + uint32_t i = 0; + for (const dd::Partition *pt : table_def->partitions()) { + part_table_list[i] = (TcDb__TseDDLPartitionTableDef *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef)); + if (part_table_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + + tc_db__tse_ddlpartition_table_def__init(part_table_list[i]); + TSE_RETURN_IF_NOT_ZERO(tse_ddl_fill_partition_table_info(pt, mem_start, mem_end, req->partition_def, i)); + i++; + } + + return 0; +} + +static int tse_ddl_init_column_def(TcDb__TseDDLCreateTableDef *req, char **mem_start, char *mem_end) { + req->columns = (TcDb__TseDDLColumnDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDef*) * req->n_columns); + if (req->columns == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_columns; i++) { + req->columns[i] = (TcDb__TseDDLColumnDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDef)); + if (req->columns[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlcolumn_def__init(req->columns[i]); + TcDb__TseDDLColumnDef *column = req->columns[i]; + column->datatype = (TcDb__TseDDLColumnDataTypeDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDataTypeDef)); + if (column->datatype == NULL) { + return HA_ERR_OUT_OF_MEM; + } + + tc_db__tse_ddlcolumn_data_type_def__init(column->datatype); + } + + return 0; +} + +static int tse_ddl_init_foreign_key_def(TcDb__TseDDLCreateTableDef *req, const dd::Table *table_def, + char **mem_start, char *mem_end) { + req->fk_list = (TcDb__TseDDLForeignKeyDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyDef*) * req->n_fk_list); + if (req->fk_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_fk_list; i++) { + req->fk_list[i] = (TcDb__TseDDLForeignKeyDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyDef)); + if (req->fk_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlforeign_key_def__init(req->fk_list[i]); + TcDb__TseDDLForeignKeyDef *fk_def = req->fk_list[i]; + const dd::Foreign_key *fk = table_def->foreign_keys().at(i); + fk_def->n_elements = fk->elements().size(); + fk_def->elements = (TcDb__TseDDLForeignKeyElementDef **)tse_ddl_alloc_mem( + mem_start, mem_end, + sizeof(TcDb__TseDDLForeignKeyElementDef*) * fk_def->n_elements); + if (fk_def->elements == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint j = 0; j < fk_def->n_elements; j++) { + fk_def->elements[j] = (TcDb__TseDDLForeignKeyElementDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyElementDef)); + if (fk_def->elements[j] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlforeign_key_element_def__init(fk_def->elements[j]); + } + } + return 0; +} + +static int tse_ddl_init_index_def(TcDb__TseDDLCreateTableDef *req, const dd::Table *table_def, + char **mem_start, char *mem_end) { + req->key_list = (TcDb__TseDDLTableKey **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKey*) * req->n_key_list); + if (req->key_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_key_list; i++) { + req->key_list[i] = (TcDb__TseDDLTableKey *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKey)); + if (req->key_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLTableKey *req_key = req->key_list[i]; + tc_db__tse_ddltable_key__init(req_key); + const dd::Index *idx = table_def->indexes().at(i); + assert(idx != NULL); + req_key->n_columns = idx->elements().size(); + req_key->columns = (TcDb__TseDDLTableKeyPart **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKeyPart*) * req_key->n_columns); + if (req_key->columns == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint j = 0; j < req_key->n_columns; j++) { + req_key->columns[j] = (TcDb__TseDDLTableKeyPart *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKeyPart)); + if (req_key->columns[j] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddltable_key_part__init(req_key->columns[j]); + req_key->columns[j]->func_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, FUNC_TEXT_MAX_LEN); + assert(req_key->columns[j]->func_text != NULL); + memset(req_key->columns[j]->func_text, 0, FUNC_TEXT_MAX_LEN); + } + } + return 0; +} + +static int tse_ddl_init_index_form(TcDb__TseDDLCreateTableDef *req, TABLE *form, + char **mem_start, char *mem_end) { + + req->n_key_list = form->s->keys; + if (req->n_key_list > 0) { + req->key_list = (TcDb__TseDDLTableKey **)tse_ddl_alloc_mem( + mem_start, mem_end, + sizeof(TcDb__TseDDLTableKey*) * req->n_key_list); + if (req->key_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_key_list; i++) { + const KEY *key = form->key_info + i; + req->key_list[i] = (TcDb__TseDDLTableKey *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKey)); + if (req->key_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLTableKey *req_key = req->key_list[i]; + tc_db__tse_ddltable_key__init(req_key); + req_key->n_columns = key->user_defined_key_parts; + req_key->columns = (TcDb__TseDDLTableKeyPart **)tse_ddl_alloc_mem( + mem_start, mem_end, + sizeof(TcDb__TseDDLTableKeyPart*) * req_key->n_columns); + if (req_key->columns == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint j = 0; j < req_key->n_columns; j++) { + req_key->columns[j] = (TcDb__TseDDLTableKeyPart *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKeyPart)); + if (req_key->columns[j] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddltable_key_part__init(req_key->columns[j]); + req_key->columns[j]->func_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, FUNC_TEXT_MAX_LEN); + assert(req_key->columns[j]->func_text != NULL); + memset(req_key->columns[j]->func_text, 0, FUNC_TEXT_MAX_LEN); + } + } + } + return 0; +} + +static int tse_ddl_init_create_table_def(TcDb__TseDDLCreateTableDef *req, + TABLE *form, THD *thd, + const dd::Table *table_def, char **mem_start, + char *mem_end) { + uint fields = form->s->fields; + tc_db__tse_ddlcreate_table_def__init(req); + DBUG_EXECUTE_IF("tse_create_table_max_column", { fields = REC_MAX_N_USER_FIELDS + 1; }); + if (fields > REC_MAX_N_USER_FIELDS) { + tse_log_system("Max filed %d > %d, sql:%s", fields, REC_MAX_N_USER_FIELDS, + thd->query().str); + return HA_ERR_TOO_MANY_FIELDS; + } + req->n_columns = fields; + if (req->n_columns > 0) { + TSE_RETURN_IF_NOT_ZERO(tse_ddl_init_column_def(req, mem_start, mem_end)); + } + + if (table_def == nullptr) { + return tse_ddl_init_index_form(req, form, mem_start, mem_end); + } + + req->n_key_list = table_def->indexes().size(); + if (req->n_key_list > 0) { + TSE_RETURN_IF_NOT_ZERO(tse_ddl_init_index_def(req, table_def, mem_start, mem_end)); + } + + req->n_fk_list = table_def->foreign_keys().size(); + if (req->n_fk_list > 0) { + TSE_RETURN_IF_NOT_ZERO(tse_ddl_init_foreign_key_def(req, table_def, mem_start, mem_end)); + } + + if (table_def->partitions().size() > 0) { + uint subpart_num_per_part = table_def->leaf_partitions().size() / table_def->partitions().size(); + if (subpart_num_per_part > MAX_SUBPART_NUM) { + my_printf_error(ER_TOO_MANY_PARTITIONS_ERROR, + "The number of subpartitions of one parent partition exceeds the maximum %d.", MYF(0), MAX_SUBPART_NUM); + return -1; + } + int ret = tse_ddl_prepare_create_partition_info(req, table_def, mem_start, mem_end); + if (ret != 0) { + tse_log_system("tse_ddl_prepare_create_partition_info failed , ret = %d.", ret); + return ret; + } + } + return 0; +} + +int ha_tse_truncate_table(tianchi_handler_t *tch, THD *thd, const char *db_name, const char *table_name, bool is_tmp_table) { + assert(thd->lex->sql_command == SQLCOM_TRUNCATE); + + ct_errno_t ret = CT_SUCCESS; + size_t msg_len = 0; + tse_ddl_stack_mem stack_mem(0); + void *tse_ddl_req_msg_mem = nullptr; + { + TcDb__TseDDLTruncateTableDef req; + tc_db__tse_ddltruncate_table_def__init(&req); + char user_name[SMALL_RECORD_SIZE]; + tse_copy_name(user_name, db_name, SMALL_RECORD_SIZE); + req.schema = const_cast(user_name); + req.name = const_cast(table_name); + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql; + if (is_tmp_table) { // truncate临时表不需要广播 + req.sql_str = nullptr; + } else { + sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + } + if (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) { + req.no_check_fk = 1; + } + msg_len = tc_db__tse_ddltruncate_table_def__get_packed_size(&req); + stack_mem.set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddltruncate_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + } + update_member_tch(*tch, tse_hton, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, *tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ddl_ctrl.msg_len = msg_len; + ret = (ct_errno_t)tse_truncate_table(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_ddl_hook_cantian_error("tse_truncate_table_cantian_error", thd, &ddl_ctrl, &ret); + *tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(*tch, tse_hton, thd); + return tse_ddl_handle_fault("tse_truncate_table", thd, &ddl_ctrl, ret); +} + +static int fill_create_table_req_base_info(HA_CREATE_INFO *create_info, char *db_name, char *table_name, THD *thd, + TcDb__TseDDLCreateTableDef *req, bool is_alter_copy, char **mem_start, char *mem_end) { + req->schema = (char *)tse_ddl_alloc_mem(mem_start, mem_end, SMALL_RECORD_SIZE); + if (req->schema == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + req->alter_db_name = (char *)tse_ddl_alloc_mem(mem_start, mem_end, SMALL_RECORD_SIZE); + if (req->alter_db_name == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + tse_copy_name(req->schema, db_name, SMALL_RECORD_SIZE); + if (thd->lex->query_tables != nullptr) { + tse_copy_name(req->alter_db_name, thd->lex->query_tables->get_db_name(), SMALL_RECORD_SIZE); + } else { + tse_copy_name(req->alter_db_name, db_name, SMALL_RECORD_SIZE); + } + req->name = table_name; + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(create_info->tablespace)); + if (create_info->tablespace && strcmp(req->schema, create_info->tablespace) != 0) { + req->space = const_cast(create_info->tablespace); + } + + if (is_alter_copy) { + req->alter_table_name = const_cast(thd->lex->query_tables->table_name); + } else { + req->alter_table_name = table_name; + } + + req->auto_increment_value = create_info->auto_increment_value; + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) { + req->options |= TSE_CREATE_IF_NOT_EXISTS; + } + + if (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) { + req->options |= TSE_CREATE_TYPE_NO_CHECK_CONS; + } + + req->db_name = TSE_GET_THD_DB_NAME(thd); + req->is_create_as_select = !thd->lex->query_block->field_list_is_empty(); + return 0; +} + +static int fill_create_table_req_columns_info(HA_CREATE_INFO *create_info, dd::Table *table_def, TABLE *form, + THD *thd, ddl_ctrl_t *ddl_ctrl, TcDb__TseDDLCreateTableDef *req, char **mem_start, char *mem_end) { + uint32_t tse_col_idx = 0; + uint32_t mysql_col_idx = 0; + while (tse_col_idx < req->n_columns) { + Field *field = form->field[mysql_col_idx]; + if (field->is_gcol()) { + ddl_ctrl->table_flags |= TSE_TABLE_CONTAINS_VIRCOL; + if (field->is_virtual_gcol()) { + mysql_col_idx++; + req->n_columns--; + continue; + } + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Cantian does not support stored generated column."); + return HA_ERR_WRONG_COMMAND; + } + + TcDb__TseDDLColumnDef *column = req->columns[tse_col_idx]; + const Create_field *fld_charset = tse_get_create_field_by_column_name(thd, field->field_name); + const CHARSET_INFO *field_cs = fld_charset != nullptr ? get_sql_field_charset(fld_charset, create_info) : nullptr; + TSE_RETURN_IF_ERROR( + tse_ddl_fill_column_by_field(thd, column, field, table_def, form, NULL, TSE_ALTER_COLUMN_ALTER_ADD_COLUMN, + mem_start, mem_end, field_cs), HA_ERR_WRONG_COMMAND); + tse_col_idx++; + mysql_col_idx++; + } + + /*prevent only virtual columns*/ + if (req->n_columns == 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Cantian does not support all columns are generated."); + return HA_ERR_WRONG_COMMAND; + } + + return 0; +} + +int fill_create_table_req(HA_CREATE_INFO *create_info, dd::Table *table_def, char *db_name, char *table_name, + TABLE *form, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + TcDb__TseDDLCreateTableDef req; + int ret = tse_ddl_init_create_table_def(&req, form, thd, table_def, &req_mem_start, req_mem_end); + assert(req_mem_start <= req_mem_end); + if (ret != 0) { + return ret; + } + + string sql; + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { // 创建临时表不需要广播 + req.sql_str = nullptr; + } else { + sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + } + ret = fill_create_table_req_base_info(create_info, db_name, table_name, thd, &req, + ddl_ctrl->is_alter_copy, &req_mem_start, req_mem_end); + if (ret != 0) { + return ret; + } + + assert(form->s->row_type == create_info->row_type); + + ret = fill_create_table_req_columns_info(create_info, table_def, form, thd, ddl_ctrl, &req, &req_mem_start, req_mem_end); + if (ret != 0) { + return ret; + } + + TSE_RETURN_IF_NOT_ZERO(tse_ddl_create_table_fill_foreign_key_info(&req, table_def, &req_mem_start, req_mem_end)); + TSE_RETURN_IF_ERROR(tse_ddl_create_table_fill_add_key(&req, thd, table_def, form, req.schema), HA_ERR_WRONG_COMMAND); + + size_t msg_len = tc_db__tse_ddlcreate_table_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlcreate_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem + sizeof(ddl_ctrl_t)) != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len + sizeof(ddl_ctrl_t); + memcpy(tse_ddl_req_msg_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + return 0; +} + + +static int tse_ddl_fill_add_part_table_info(TcDb__TseDDLPartitionTableDef *add_part, partition_element &part, + char **mem_start, char *mem_end) +{ + add_part->name = (char *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(char) * (strlen(part.partition_name) + 1)); + assert(add_part->name != NULL); + memset(add_part->name, 0, (strlen(part.partition_name) + 1)); + strncpy(add_part->name, part.partition_name, strlen(part.partition_name)); + add_part->n_subpart_table_list = part.subpartitions.size(); + if (part.subpartitions.size() > 0) { + add_part->subpart_table_list = + (TcDb__TseDDLPartitionTableDef **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef *) * part.subpartitions.size()); + if (add_part->subpart_table_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLPartitionTableDef **subpart_table_list = add_part->subpart_table_list; + uint32_t i = 0; + for (partition_element sub_part_obj : part.subpartitions) { + subpart_table_list[i] = (TcDb__TseDDLPartitionTableDef *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(TcDb__TseDDLPartitionTableDef)); + if (subpart_table_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlpartition_table_def__init(subpart_table_list[i]); + subpart_table_list[i]->name = (char *)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(char) * (strlen(sub_part_obj.partition_name) + 1)); + assert(subpart_table_list[i]->name != NULL); + memset(subpart_table_list[i]->name, 0, (strlen(sub_part_obj.partition_name) + 1)); + strncpy(subpart_table_list[i]->name, sub_part_obj.partition_name, strlen(sub_part_obj.partition_name)); + i++; + } + } + return 0; +} + +static int tse_prepare_alter_partition_init_part_list(TcDb__TseDDLAlterTableDef *req, Alter_inplace_info *alter_info, + char **mem_start, char *mem_end) { + List part_list = alter_info->modified_part_info->partitions; + if (part_list.size() > PART_CURSOR_NUM) { + my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); + return -1; + } + req->drop_partition_names = (char **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(char *) * part_list.size()); + if (req->drop_partition_names == NULL) { + return HA_ERR_OUT_OF_MEM; + } + req->add_part_list = (TcDb__TseDDLPartitionTableDef **)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(TcDb__TseDDLPartitionTableDef *) * part_list.size()); + if (req->add_part_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + return 0; +} + +static int tse_ddl_prepare_alter_partition_info(TcDb__TseDDLAlterTableDef *req, + Alter_inplace_info *alter_info, char **mem_start, char *mem_end) +{ + req->n_drop_partition_names = 0; + req->n_add_part_list = 0; + req->hash_coalesce_count = 0; + if (alter_info->modified_part_info->partitions.size() <= 0) { + return 0; + } + TSE_RETURN_IF_NOT_ZERO(tse_prepare_alter_partition_init_part_list(req, alter_info, mem_start, mem_end)); + for (auto part : alter_info->modified_part_info->partitions) { + switch (part.part_state) { + case PART_TO_BE_DROPPED: { + req->drop_partition_names[req->n_drop_partition_names] = (char *)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(char) * (strlen(part.partition_name) + 1)); + assert(req->drop_partition_names[req->n_drop_partition_names] != NULL); + memset(req->drop_partition_names[req->n_drop_partition_names], 0, (strlen(part.partition_name) + 1)); + strcpy(req->drop_partition_names[req->n_drop_partition_names], part.partition_name); + req->n_drop_partition_names++; + break; + } + case PART_TO_BE_ADDED: { + req->add_part_list[req->n_add_part_list] = (TcDb__TseDDLPartitionTableDef *)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(TcDb__TseDDLPartitionTableDef)); + if (req->add_part_list[req->n_add_part_list] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLPartitionTableDef *add_part = req->add_part_list[req->n_add_part_list]; + tc_db__tse_ddlpartition_table_def__init(add_part); + TSE_RETURN_IF_NOT_ZERO(tse_ddl_fill_add_part_table_info(add_part, part, mem_start, mem_end)); + req->n_add_part_list++; + break; + } + case PART_REORGED_DROPPED: { + req->hash_coalesce_count++; + break; + } + case PART_CHANGED: + case PART_NORMAL: + break; + default: + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "The current operation on a partitioned table is not supported."); + return 1; + } + } + return 0; +} + +static int init_drop_list_4alter_table(TcDb__TseDDLAlterTableDef *req, char **mem_start, char *mem_end) { + req->drop_list = (TcDb__TseDDLAlterTableDrop **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableDrop*) * req->n_drop_list); + if (req->drop_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_drop_list; i++) { + req->drop_list[i] = (TcDb__TseDDLAlterTableDrop *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableDrop)); + if (req->drop_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_table_drop__init(req->drop_list[i]); + } + return 0; +} + +static int init_alter_list_4alter_table(TcDb__TseDDLAlterTableDef *req, char **mem_start, char *mem_end) { + req->alter_list = (TcDb__TseDDLAlterTableAlterColumn **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableAlterColumn*) * req->n_alter_list); + if (req->alter_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_alter_list; i++) { + req->alter_list[i] = (TcDb__TseDDLAlterTableAlterColumn *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableAlterColumn)); + if (req->alter_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_table_alter_column__init(req->alter_list[i]); + } + return 0; +} + +static int init_create_list_4alter_table(TcDb__TseDDLAlterTableDef *req, char **mem_start, char *mem_end) { + req->create_list = (TcDb__TseDDLColumnDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDef*) * req->n_create_list); + if (req->create_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_create_list; i++) { + req->create_list[i] = (TcDb__TseDDLColumnDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDef)); + if (req->create_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlcolumn_def__init(req->create_list[i]); + TcDb__TseDDLColumnDef *column = req->create_list[i]; + column->datatype = (TcDb__TseDDLColumnDataTypeDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLColumnDataTypeDef)); + if (column->datatype == NULL) { + return HA_ERR_OUT_OF_MEM; + } + + tc_db__tse_ddlcolumn_data_type_def__init(column->datatype); + } + return 0; +} + +static int init_add_key_list_4alter_table(TcDb__TseDDLAlterTableDef *req, Alter_inplace_info *ha_alter_info, + char **mem_start, char *mem_end) { + req->add_key_list = (TcDb__TseDDLTableKey **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKey*) * req->n_add_key_list); + if (req->add_key_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_add_key_list; i++) { + req->add_key_list[i] = (TcDb__TseDDLTableKey *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKey)); + if (req->add_key_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + TcDb__TseDDLTableKey *req_key = req->add_key_list[i]; + tc_db__tse_ddltable_key__init(req_key); + const KEY *key = &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; + assert(key != NULL); + req_key->n_columns = key->user_defined_key_parts; + req_key->columns = (TcDb__TseDDLTableKeyPart **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKeyPart*) * req_key->n_columns); + if (req_key->columns == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint j = 0; j < req_key->n_columns; j++) { + req_key->columns[j] = (TcDb__TseDDLTableKeyPart *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLTableKeyPart)); + if (req_key->columns[j] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddltable_key_part__init(req_key->columns[j]); + req_key->columns[j]->func_text = (char *)tse_ddl_alloc_mem(mem_start, mem_end, FUNC_TEXT_MAX_LEN); + if (req_key->columns[j]->func_text == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + memset(req_key->columns[j]->func_text, 0, FUNC_TEXT_MAX_LEN); + } + } + return 0; +} + +static int init_drop_key_list_4alter_table(TcDb__TseDDLAlterTableDef *req, char **mem_start, char *mem_end) { + req->drop_key_list = (TcDb__TseDDLAlterTableDropKey **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableDropKey*) * req->n_drop_key_list); + if (req->drop_key_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_drop_key_list; i++) { + req->drop_key_list[i] = (TcDb__TseDDLAlterTableDropKey *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTableDropKey)); + if (req->drop_key_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_table_drop_key__init(req->drop_key_list[i]); + } + return 0; +} + +static int init_foreign_key_list_4alter_table(TcDb__TseDDLAlterTableDef *req, Alter_inplace_info *ha_alter_info, + char **mem_start, char *mem_end) { + req->add_foreign_key_list = (TcDb__TseDDLForeignKeyDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyDef*) * ha_alter_info->alter_info->key_list.size()); + if (req->add_foreign_key_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + req->n_add_foreign_key_list = 0; + for (const Key_spec *key : ha_alter_info->alter_info->key_list) { + if (key->type != KEYTYPE_FOREIGN) { + continue; + } + req->add_foreign_key_list[req->n_add_foreign_key_list] = (TcDb__TseDDLForeignKeyDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyDef)); + if (req->add_foreign_key_list[req->n_add_foreign_key_list] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlforeign_key_def__init(req->add_foreign_key_list[req->n_add_foreign_key_list]); + TcDb__TseDDLForeignKeyDef *fk_def = req->add_foreign_key_list[req->n_add_foreign_key_list]; + const Foreign_key_spec *fk = down_cast(key); + fk_def->n_elements = fk->columns.size(); + fk_def->elements = (TcDb__TseDDLForeignKeyElementDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyElementDef*) * fk_def->n_elements); + if (fk_def->elements == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint j = 0; j < fk_def->n_elements; j++) { + fk_def->elements[j] = (TcDb__TseDDLForeignKeyElementDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLForeignKeyElementDef)); + if (fk_def->elements[j] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlforeign_key_element_def__init(fk_def->elements[j]); + } + TSE_RETURN_IF_NOT_ZERO(tse_ddl_alter_table_fill_foreign_key_info(fk_def, fk, mem_start, mem_end)); + req->n_add_foreign_key_list++; + } + return 0; +} + +static int init_alter_index_list_4alter_table(TcDb__TseDDLAlterTableDef *req, char **mem_start, char *mem_end) { + req->alter_index_list = (TcDb__TseDDLAlterIndexDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterIndexDef) * req->n_alter_index_list); + if (req->alter_index_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_alter_index_list; i++) { + req->alter_index_list[i] = (TcDb__TseDDLAlterIndexDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterIndexDef)); + if (req->alter_index_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_index_def__init(req->alter_index_list[i]); + } + return 0; +} + +static int init_tse_ddl_alter_table_def(TcDb__TseDDLAlterTableDef *req, Alter_inplace_info *ha_alter_info, + THD *thd, TABLE *altered_table, char **mem_start, char *mem_end, size_t *rename_cols) { + tc_db__tse_ddlalter_table_def__init(req); + uint32_t create_fields = (uint32_t)ha_alter_info->alter_info->create_list.size(); + DBUG_EXECUTE_IF("tse_alter_table_max_column", { create_fields = REC_MAX_N_USER_FIELDS + 1; }); + if (create_fields > REC_MAX_N_USER_FIELDS) { + tse_log_system("Max filed %d > %u, sql:%s", (uint32_t)create_fields, + REC_MAX_N_USER_FIELDS, thd->query().str); + my_error(ER_TOO_MANY_FIELDS, MYF(0)); + return HA_ERR_TOO_MANY_FIELDS; + } + req->n_drop_list = (uint32_t)ha_alter_info->alter_info->drop_list.size(); + for (size_t i = 0; i < ha_alter_info->alter_info->alter_list.size(); i++) { + const Alter_column *alter_column = ha_alter_info->alter_info->alter_list.at((size_t)i); + if (alter_column->change_type() == Alter_column::Type::RENAME_COLUMN) { + (*rename_cols)++; + } + } + req->n_alter_list = (uint32_t)ha_alter_info->alter_info->alter_list.size() + *rename_cols; + req->n_create_list = create_fields; + req->n_add_key_list = ha_alter_info->index_add_count; + req->n_drop_key_list = ha_alter_info->index_drop_count; + req->n_alter_index_list = ha_alter_info->index_rename_count; + + // 分区表 + if (ha_alter_info->modified_part_info != NULL) { + TSE_RETURN_IF_NOT_ZERO(tse_ddl_prepare_alter_partition_info(req, ha_alter_info, mem_start, mem_end)); + } + + if (req->n_drop_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_drop_list_4alter_table(req, mem_start, mem_end)); + } + + + if (req->n_alter_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_alter_list_4alter_table(req, mem_start, mem_end)); + } + + if (req->n_create_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_create_list_4alter_table(req, mem_start, mem_end)); + } + + req->table_def = (TcDb__TseDDLAlterTablePorp *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterTablePorp)); + if (req->table_def == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_table_porp__init(req->table_def); + + // 添加索引 + if ((ha_alter_info->handler_flags & Alter_inplace_info::ADD_STORED_BASE_COLUMN) && + thd->lex->sql_command == SQLCOM_ALTER_TABLE) { + req->n_add_key_list = 0; + } + if (req->n_add_key_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_add_key_list_4alter_table(req, ha_alter_info, mem_start, mem_end)); + } + + // 删除索引 + if (req->n_drop_key_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_drop_key_list_4alter_table(req, mem_start, mem_end)); + } + + // 增加外键 + if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_FOREIGN_KEY) { + TSE_RETURN_IF_NOT_ZERO(init_foreign_key_list_4alter_table(req, ha_alter_info, mem_start, mem_end)); + } + + // 自增 + if ((altered_table->found_next_number_field != nullptr) + && (ha_alter_info->handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) + && (ha_alter_info->create_info->used_fields & HA_CREATE_USED_AUTO)) { + req->new_auto_increment_value = ha_alter_info->create_info->auto_increment_value; + } + + // alter index + if (req->n_alter_index_list > 0) { + TSE_RETURN_IF_NOT_ZERO(init_alter_index_list_4alter_table(req, mem_start, mem_end)); + } + return 0; +} + +/** + Get Create_field object for newly created table by field index. + + @param alter_info Alter_info describing newly created table. + @param idx Field index. +*/ + +static const Create_field *get_field_by_index(Alter_info *alter_info, + uint idx) { + List_iterator_fast field_it(alter_info->create_list); + uint field_idx = 0; + const Create_field *field = NULL; + + while ((field = field_it++) && field_idx < idx) { + field_idx++; + } + + return field; +} + +static uint32_t tse_fill_key_part(THD *thd, + TcDb__TseDDLTableKeyPart *req_key_part, + TcDb__TseDDLTableKey *req_key_def, + const Create_field *create_field, + TABLE *form, + const KEY_PART_INFO *key_part) { + Field *field = tse_get_field_by_name(form, create_field->field_name); + assert(field != nullptr); + bool is_prefix_key = false; + + if (field->is_field_for_functional_index()) { + req_key_def->is_func = true; + TSE_RETURN_IF_ERROR(tse_fill_func_key_part(thd, req_key_part, create_field->gcol_info) == CT_SUCCESS, CT_ERROR); + } else { + if (field->is_virtual_gcol()) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Cantian does not support index on virtual generated column."); + return CT_ERROR; + } + + uint prefix_len = get_prefix_index_len(create_field->field, key_part->length); + if (prefix_len) { + tse_fill_prefix_func_key_part(req_key_part, create_field->field, prefix_len); + is_prefix_key = true; + } else { + req_key_part->is_func = false; + req_key_part->func_text = nullptr; + } + req_key_part->name = const_cast(create_field->field_name); + } + + tse_ddl_get_data_type_from_mysql_type(field, create_field->sql_type, &req_key_part->datatype); + if (is_prefix_key && field->is_flag_set(BLOB_FLAG)) { + req_key_part->datatype = TSE_DDL_TYPE_VARCHAR; + } + req_key_part->length = (uint32_t)create_field->key_length(); + + return CT_SUCCESS; +} + +bool tse_ddl_fill_add_key(THD *thd, TABLE *form, TcDb__TseDDLAlterTableDef *req, + Alter_inplace_info *ha_alter_info, char *user) +{ + for (uint i = 0; i < req->n_add_key_list; i++) { + TcDb__TseDDLTableKey *req_key_def = req->add_key_list[i]; + const KEY *key = &ha_alter_info->key_info_buffer[ha_alter_info->index_add_buffer[i]]; + assert(key != nullptr); + req_key_def->user = user; + req_key_def->table = const_cast(thd->lex->query_tables->table_name); + TSE_RETURN_IF_NOT_ZERO(check_tse_identifier_name(key->name)); + req_key_def->name = const_cast(key->name); + req_key_def->space = NULL; + TSE_RETURN_IF_ERROR(get_tse_key_type(key, &req_key_def->key_type), false); + if (req_key_def->key_type == TSE_KEYTYPE_PRIMARY || req_key_def->key_type == TSE_KEYTYPE_UNIQUE) { + req_key_def->is_constraint = true; + } + TSE_RETURN_IF_ERROR(get_tse_key_algorithm(key->algorithm, &req_key_def->algorithm), false); + for (uint j = 0; j < req_key_def->n_columns; j++) { + TcDb__TseDDLTableKeyPart *req_key_part = req_key_def->columns[j]; + const KEY_PART_INFO *key_part = key->key_part + j; + const Create_field *create_field = get_field_by_index(ha_alter_info->alter_info, key_part->fieldnr); + assert(create_field != NULL); + TSE_RETURN_IF_ERROR( + (tse_fill_key_part(thd, req_key_part, req_key_def, create_field, form, + key_part) == CT_SUCCESS), + false); + } + } + return true; +} + +static int tse_ddl_fill_drop_key(Alter_inplace_info *ha_alter_info, const dd::Table *old_table_def, + TcDb__TseDDLAlterTableDef *req) +{ + for (uint tse_drop_key_idx = 0; tse_drop_key_idx < req->n_drop_key_list; tse_drop_key_idx++) { + TcDb__TseDDLAlterTableDropKey *req_drop = req->drop_key_list[tse_drop_key_idx]; + const KEY *key = ha_alter_info->index_drop_buffer[tse_drop_key_idx]; + req_drop->name = const_cast(key->name); + req_drop->drop_type = TSE_ALTER_TABLE_DROP_KEY; + + const dd::Index *idx = tse_ddl_get_index_by_name(old_table_def, req_drop->name); + assert(idx != nullptr); + TSE_RETURN_IF_ERROR(tse_ddl_get_create_key_type(idx->type(), &req_drop->key_type), CT_ERROR); + } + + return CT_SUCCESS; +} + +static int fill_tse_alter_drop_list(Alter_inplace_info *ha_alter_info, const dd::Table *old_table_def, + TcDb__TseDDLAlterTableDef *req) +{ + uint32_t tse_drop_idx = 0; + uint32_t mysql_drop_idx = 0; + while (tse_drop_idx < req->n_drop_list) { + TcDb__TseDDLAlterTableDrop *req_drop = req->drop_list[tse_drop_idx]; + const Alter_drop *drop = ha_alter_info->alter_info->drop_list.at((size_t)mysql_drop_idx); + req_drop->name = const_cast(drop->name); + req_drop->drop_type = tse_ddl_get_drop_type_from_mysql_type(drop->type); + if (req_drop->drop_type == TSE_ALTER_TABLE_DROP_COLUMN) { + const dd::Column *col = tse_ddl_get_column_by_name(old_table_def, drop->name); + assert(col != nullptr); + if (col->is_virtual()) { + req->n_drop_list--; + mysql_drop_idx++; + continue; + } + } else if (req_drop->drop_type == TSE_ALTER_TABLE_DROP_FOREIGN_KEY) { + req_drop->key_type = TSE_KEYTYPE_FOREIGN; + } else if (req_drop->drop_type == TSE_ALTER_TABLE_DROP_KEY) { + // drop 索引通过index_drop_count实现 + req->n_drop_list--; + mysql_drop_idx++; + continue; + } + + tse_drop_idx++; + mysql_drop_idx++; + } + return CT_SUCCESS; +} + +static int fill_tse_alter_create_list(THD *thd, TABLE *altered_table, Alter_inplace_info *ha_alter_info, + dd::Table *new_table_def, TcDb__TseDDLAlterTableDef *req, ddl_ctrl_t *ddl_ctrl, char **mem_start, char *mem_end) +{ + uint32_t tse_col_idx = 0; + uint32_t mysql_col_idx = 0; + while (tse_col_idx < req->n_create_list) { + TcDb__TseDDLColumnDef *req_create_column = req->create_list[tse_col_idx]; + const Create_field *fld = ha_alter_info->alter_info->create_list[mysql_col_idx]; + + /* Generate Columns Not Processed */ + if (fld->is_gcol()) { + ddl_ctrl->table_flags |= TSE_TABLE_CONTAINS_VIRCOL; + if (fld->is_virtual_gcol()) { + req->n_create_list--; + mysql_col_idx++; + continue; + } else { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Cantian does not support stored generated column."); + return HA_ERR_WRONG_COMMAND; + } + } + + tse_alter_column_alter_mode alter_mode = TSE_ALTER_COLUMN_ALTER_MODE_NONE; + if (fld->field == NULL) { + alter_mode = TSE_ALTER_COLUMN_ALTER_ADD_COLUMN; + } + if (fld->change != NULL) { + alter_mode = TSE_ALTER_COLUMN_ALTER_MODIFY_COLUMN; + } + const CHARSET_INFO *field_cs = get_sql_field_charset(fld, ha_alter_info->create_info); + TSE_RETURN_IF_ERROR(tse_ddl_fill_column_by_field(thd, req_create_column, altered_table->s->field[mysql_col_idx], + ((const dd::Table *)new_table_def), altered_table, fld, alter_mode, mem_start, mem_end, field_cs), + CT_ERROR); + tse_col_idx++; + mysql_col_idx++; + } + + //prevent only virtual columns + if (req->n_create_list == 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Cantian does not support all columns are generated."); + return HA_ERR_WRONG_COMMAND; + } + + return CT_SUCCESS; +} + +static void fill_sys_cur_timestamp(THD *thd, TcDb__TseDDLAlterTableDef *req) { + date_detail_t date_detail; + MYSQL_TIME ltime; + timeval tm = thd->query_start_timeval_trunc(0); + my_tz_UTC->gmt_sec_to_TIME(<ime, tm); + assign_mysql_date_detail(MYSQL_TYPE_TIMESTAMP, ltime, &date_detail); + cm_encode_date(&date_detail, &req->systimestamp); + + MYSQL_TIME ltime2; + thd->time_zone()->gmt_sec_to_TIME(<ime2, tm); + longlong seconds_diff; + long microsec_diff; + bool negative = calc_time_diff(ltime2, ltime, 1, &seconds_diff, µsec_diff); + req->tz_offset_utc = negative ? -(seconds_diff / 60) : seconds_diff / 60; + return; +} + +static void fill_alter_list_4alter_table(dd::Table *new_table_def, Alter_inplace_info *ha_alter_info, + TcDb__TseDDLAlterTableDef *req, size_t rename_cols, uint32_t thd_id, char **req_mem_start, char *req_mem_end) { + TcDb__TseDDLAlterTableAlterColumn *req_alter = NULL; + uint32_t copy_rm_num = 0; + for (uint32_t i = 0; i < req->n_alter_list - rename_cols; i++) { + req_alter = req->alter_list[i]; + + const Alter_column *alter_column = ha_alter_info->alter_info->alter_list.at((size_t)i); + if (alter_column->change_type() == Alter_column::Type::SET_DEFAULT || + alter_column->change_type() == Alter_column::Type::DROP_DEFAULT || + alter_column->change_type() == Alter_column::Type::SET_COLUMN_VISIBLE || + alter_column->change_type() == Alter_column::Type::SET_COLUMN_INVISIBLE || + alter_column->change_type() == Alter_column::Type::RENAME_COLUMN) { + req_alter->name = const_cast(alter_column->name); + req_alter->new_name = const_cast(alter_column->m_new_name); + req_alter->type = tse_ddl_get_alter_column_type_from_mysql_type(alter_column->change_type()); + if (alter_column->change_type() == Alter_column::Type::RENAME_COLUMN) { + uint32_t copy_rm_index = req->n_alter_list - rename_cols + copy_rm_num; + req_alter->new_name = (char *)tse_ddl_alloc_mem(req_mem_start, req_mem_end, TSE_MAX_COLUMN_LEN); + sprintf(req_alter->new_name, "TMPCOLUMN4CANTIAN_%d_%d", copy_rm_index, thd_id); + // for rename swap columns: + // column a to b, b to c, c to x... or a to b, b to a + req->alter_list[copy_rm_index]->name = req_alter->new_name; + req->alter_list[copy_rm_index]->new_name = const_cast(alter_column->m_new_name); + req->alter_list[copy_rm_index]->type = req_alter->type; + copy_rm_num++; + continue; + } + const dd::Column *new_col = new_table_def->get_column(alter_column->name); + req_alter->has_no_default = new_col->has_no_default() ? true : false; + req_alter->is_default_null = new_col->is_default_value_null() ? true : false; + } + } +} + +int fill_alter_table_req(TABLE *altered_table, Alter_inplace_info *ha_alter_info, const dd::Table *old_table_def, + dd::Table *new_table_def, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + TcDb__TseDDLAlterTableDef req; + + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + + size_t rename_cols = 0; + TSE_RETURN_IF_NOT_ZERO(init_tse_ddl_alter_table_def(&req, ha_alter_info, thd, + altered_table, &req_mem_start, req_mem_end, &rename_cols)); + + assert(req_mem_start <= req_mem_end); + char user_name_str[SMALL_RECORD_SIZE]; + if (thd->lex->query_tables != nullptr) { + tse_copy_name(user_name_str, thd->lex->query_tables->get_db_name(), SMALL_RECORD_SIZE); + } else { + tse_copy_name(user_name_str, altered_table->s->db.str, SMALL_RECORD_SIZE); + } + req.user = user_name_str; + req.name = const_cast(thd->lex->query_tables->table_name); + fill_sys_cur_timestamp(thd, &req); + TSE_RETURN_IF_ERROR((fill_tse_alter_drop_list(ha_alter_info, old_table_def, &req) == CT_SUCCESS), CT_ERROR); + if (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) { + req.options |= TSE_CREATE_TYPE_NO_CHECK_CONS; + } + // 删除索引相关逻辑填充 + if (ha_alter_info->index_drop_count) { + assert(ha_alter_info->handler_flags & + (Alter_inplace_info::DROP_INDEX | + Alter_inplace_info::DROP_UNIQUE_INDEX | + Alter_inplace_info::DROP_PK_INDEX)); + + TSE_RETURN_IF_ERROR((tse_ddl_fill_drop_key(ha_alter_info, old_table_def, &req) == CT_SUCCESS), CT_ERROR); + } + + if (req.n_alter_list > 0) { + fill_alter_list_4alter_table(new_table_def, ha_alter_info, &req, + rename_cols, ddl_ctrl->tch.thd_id, &req_mem_start, req_mem_end); + } + + TSE_RETURN_IF_ERROR((fill_tse_alter_create_list(thd, altered_table, ha_alter_info, + new_table_def, &req, ddl_ctrl, &req_mem_start, req_mem_end) == CT_SUCCESS), CT_ERROR); + + // 创建索引相关逻辑填充 + TSE_RETURN_IF_ERROR(tse_ddl_fill_add_key(thd, altered_table, &req, ha_alter_info, req.user), true); + assert(req_mem_start <= req_mem_end); + + // rename索引 + for (uint32_t i = 0; i < req.n_alter_index_list; ++i) { + TcDb__TseDDLAlterIndexDef *req_alter_index_def = req.alter_index_list[i]; + + req_alter_index_def->user = user_name_str; + req_alter_index_def->table = const_cast(thd->lex->query_tables->table_name); + req_alter_index_def->name = const_cast(ha_alter_info->index_rename_buffer[i].old_key->name); + req_alter_index_def->new_name = const_cast(ha_alter_info->index_rename_buffer[i].new_key->name); + TSE_RETURN_IF_ERROR(get_tse_key_type(ha_alter_info->index_rename_buffer[i].old_key, &req_alter_index_def->key_type), true); + } + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + + size_t msg_len = tc_db__tse_ddlalter_table_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlalter_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem + sizeof(ddl_ctrl_t)) != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len + sizeof(ddl_ctrl_t); + memcpy(tse_ddl_req_msg_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + return 0; +} + +static void tse_fill_rename_constraints(TcDb__TseDDLRenameTableDef *req, const char *old_cons_name, + const char *new_cons_name, char **mem_start, char *mem_end) { + req->old_constraints_name[req->n_old_constraints_name] = (char *)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(char) * (strlen(old_cons_name) + 1)); + req->new_constraints_name[req->n_new_constraints_name] = (char *)tse_ddl_alloc_mem(mem_start, mem_end, + sizeof(char) * (strlen(new_cons_name) + 1)); + assert(req->old_constraints_name[req->n_old_constraints_name] != NULL); + assert(req->new_constraints_name[req->n_new_constraints_name] != NULL); + strcpy(req->old_constraints_name[req->n_old_constraints_name], old_cons_name); + strcpy(req->new_constraints_name[req->n_new_constraints_name], new_cons_name); +} + +static int init_tse_ddl_rename_constraints_def(THD *thd, TcDb__TseDDLRenameTableDef *req, + const dd::Table *from_table_def, dd::Table *to_table_def, char **mem_start, char *mem_end) { + size_t constraint_size = from_table_def->foreign_keys().size(); + handlerton *tse_handlerton = get_tse_hton(); + size_t generated_cons = 0; // The number of default constraints + bool is_alter_copy = is_alter_table_copy(thd); + + if (constraint_size <= 0) { + return 0; + } + + const char *from_tbl_name = is_alter_copy ? thd->lex->query_tables->table_name : + from_table_def->name().c_str(); + size_t tbl_name_length = is_alter_copy ? strlen(thd->lex->query_tables->table_name) : + from_table_def->name().length(); + bool is_rename_table = ((thd->lex->sql_command == SQLCOM_RENAME_TABLE) || // sql_command + (from_table_def->tablespace_id() != to_table_def->tablespace_id()) || // copy rename cross db + (strcmp(from_tbl_name, to_table_def->name().c_str()) != 0)); // alter copy(如指定) + for (const dd::Foreign_key *fk : from_table_def->foreign_keys()) { + bool is_generated_name = dd::is_generated_foreign_key_name(from_tbl_name, tbl_name_length, tse_handlerton, *fk); + if (is_generated_name && is_rename_table) { + generated_cons++; + } + } + + req->new_constraints_name = (char **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(char *) * generated_cons); + req->old_constraints_name = (char **)tse_ddl_alloc_mem(mem_start, mem_end, sizeof(char *) * generated_cons); + if (req->new_constraints_name == NULL || req->old_constraints_name == NULL) { + return HA_ERR_OUT_OF_MEM; + } + + for (const dd::Foreign_key *fk : from_table_def->foreign_keys()) { + bool is_generated_name = dd::is_generated_foreign_key_name(from_tbl_name, tbl_name_length, tse_handlerton, *fk); + if (is_generated_name && is_rename_table) { + char new_fk_name[TSE_MAX_CONS_NAME_LEN + 1]; + // Construct new name by copying suffix from the old one. + strxnmov(new_fk_name, sizeof(new_fk_name) - 1, to_table_def->name().c_str(), + fk->name().c_str() + tbl_name_length, NullS); + tse_fill_rename_constraints(req, fk->name().c_str(), new_fk_name, mem_start, mem_end); + req->n_old_constraints_name++; + req->n_new_constraints_name++; + } + } + + return 0; +} + +int fill_rename_table_req(const char *from, const char *to, const dd::Table *from_table_def, + dd::Table *to_table_def, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + char old_db[SMALL_RECORD_SIZE]; + char new_db[SMALL_RECORD_SIZE]; + char user_name[SMALL_RECORD_SIZE]; + char new_user_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(from, old_db, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_split_normalized_name(to, new_db, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(user_name, old_db, SMALL_RECORD_SIZE); + tse_copy_name(new_user_name, new_db, SMALL_RECORD_SIZE); + + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + TcDb__TseDDLRenameTableDef req; + tc_db__tse_ddlrename_table_def__init(&req); + + int ret = init_tse_ddl_rename_constraints_def(thd, &req, from_table_def, to_table_def, &req_mem_start, req_mem_end); + if (ret != 0) { + return ret; + } + + req.user = user_name; + req.new_user = new_user_name; + req.old_db_name = old_db; + req.old_table_name = const_cast(from_table_def->name().c_str()); + req.new_db_name = new_db; + req.new_table_name = const_cast(to_table_def->name().c_str()); + req.current_db_name = const_cast(TSE_GET_THD_DB_NAME(thd)); + + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + + size_t msg_len = tc_db__tse_ddlrename_table_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlrename_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem) != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len; + return 0; +} + +static int fill_partition_info_4truncate(TcDb__TseDDLTruncateTablePartitionDef *req, dd::Table *dd_table, + partition_info *part_info, char **mem_start, char *mem_end) { + uint32_t part_num = 0; + if (part_info->is_sub_partitioned()) { + req->n_subpartition_id = 0; + req->subpartition_id = (uint32_t *)tse_ddl_alloc_mem( + mem_start, mem_end, dd_table->leaf_partitions()->size() * sizeof(uint32_t)); + if (req->subpartition_id == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + req->n_subpartition_name = 0; + req->subpartition_name = (char **)tse_ddl_alloc_mem( + mem_start, mem_end, dd_table->leaf_partitions()->size() * sizeof(char *)); + if (req->subpartition_name == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + req->is_subpart = 1; + for (const auto dd_part : *dd_table->leaf_partitions()) { + if (!part_info->is_partition_used(part_num++)) { + continue; + } + int part_id = (part_num - 1) / part_info->num_subparts; + int subpart_id = (part_num - 1) % part_info->num_subparts; + req->partition_id[req->n_partition_id] = part_id; + req->n_partition_id++; + req->partition_name[req->n_partition_name] = const_cast(dd_part->name().c_str()); + req->n_partition_name++; + req->subpartition_id[req->n_subpartition_id] = subpart_id; + req->n_subpartition_id++; + req->subpartition_name[req->n_subpartition_name] = const_cast(dd_part->name().c_str()); + req->n_subpartition_name++; + } + } else { + for (const auto dd_part : *dd_table->leaf_partitions()) { + if (!part_info->is_partition_used(part_num++)) { + continue; + } + req->partition_id[req->n_partition_id] = part_num - 1; + req->n_partition_id++; + req->partition_name[req->n_partition_name] = const_cast(dd_part->name().c_str()); + req->n_partition_name++; + } + } + return 0; +} + +int fill_truncate_partition_req(const char *full_name, partition_info *part_info, + dd::Table *dd_table, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + char db_name[SMALL_RECORD_SIZE]; + char user_name[SMALL_RECORD_SIZE]; + const char *table_name_str = dd_table->name().c_str(); + tse_split_normalized_name(full_name, db_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(user_name, db_name, SMALL_RECORD_SIZE); + TcDb__TseDDLTruncateTablePartitionDef req; + tc_db__tse_ddltruncate_table_partition_def__init(&req); + req.user = user_name; + req.db_name = TSE_GET_THD_DB_NAME(thd); + req.table_name = const_cast(table_name_str); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + + req.n_partition_id = 0; + req.partition_id = (uint32_t *)tse_ddl_alloc_mem( + &req_mem_start, req_mem_end, dd_table->leaf_partitions()->size() * sizeof(uint32_t)); + if (req.partition_id == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + req.n_partition_name = 0; + req.partition_name = (char **)tse_ddl_alloc_mem( + &req_mem_start, req_mem_end, dd_table->leaf_partitions()->size() * sizeof(char *)); + if (req.partition_name == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + TSE_RETURN_IF_NOT_ZERO(fill_partition_info_4truncate(&req, dd_table, + part_info, &req_mem_start, req_mem_end)); + size_t msg_len = tc_db__tse_ddltruncate_table_partition_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddltruncate_table_partition_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem + sizeof(ddl_ctrl_t)) + != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len + sizeof(ddl_ctrl_t); + memcpy(tse_ddl_req_msg_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + return 0; +} + +int init_tse_optimize_table_def(TcDb__TseDDLAlterTableDef *req, TABLE *table, char **mem_start, char *mem_end) { + tc_db__tse_ddlalter_table_def__init(req); + req->n_alter_index_list = table->s->keys; + if (req->n_alter_index_list > 0) { + req->alter_index_list = (TcDb__TseDDLAlterIndexDef **)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterIndexDef) * req->n_alter_index_list); + if (req->alter_index_list == NULL) { + return HA_ERR_OUT_OF_MEM; + } + for (uint i = 0; i < req->n_alter_index_list; i++) { + req->alter_index_list[i] = (TcDb__TseDDLAlterIndexDef *)tse_ddl_alloc_mem( + mem_start, mem_end, sizeof(TcDb__TseDDLAlterIndexDef)); + if (req->alter_index_list[i] == NULL) { + return HA_ERR_OUT_OF_MEM; + } + tc_db__tse_ddlalter_index_def__init(req->alter_index_list[i]); + } + } + return 0; +} + +int fill_rebuild_index_req(TABLE *table, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem) { + int ret; + lock_guard lock(m_tse_ddl_protobuf_mem_mutex); + TcDb__TseDDLAlterTableDef req; + char *req_mem_start = tse_ddl_req_mem; + char *req_mem_end = req_mem_start + TSE_DDL_PROTOBUF_MEM_SIZE; + char db_name[SMALL_RECORD_SIZE]; + char table_name[SMALL_RECORD_SIZE]; + + tse_copy_name(db_name, thd->lex->query_tables->get_db_name(), SMALL_RECORD_SIZE); + tse_copy_name(table_name, thd->lex->query_tables->table_name, SMALL_RECORD_SIZE); + + ret = init_tse_optimize_table_def(&req, table, &req_mem_start, req_mem_end); + if (ret != 0) { + return ret; + } + req.user = db_name; + req.name = table_name; + fill_sys_cur_timestamp(thd, &req); + for (uint32_t i = 0; i < req.n_alter_index_list; ++i) { + TcDb__TseDDLAlterIndexDef *req_alter_index_def = req.alter_index_list[i]; + req_alter_index_def->user = db_name; + req_alter_index_def->table = table_name; + req_alter_index_def->name = const_cast (table->key_info[i].name); + } + req.db_name = TSE_GET_THD_DB_NAME(thd); + string sql = string(thd->query().str).substr(0, thd->query().length); + req.sql_str = const_cast(sql.c_str()); + size_t msg_len = tc_db__tse_ddlalter_table_def__get_packed_size(&req); + stack_mem->set_mem_size(msg_len + sizeof(ddl_ctrl_t)); + void *tse_ddl_req_msg_mem = stack_mem->get_buf(); + if(tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + + if (tc_db__tse_ddlalter_table_def__pack(&req, (uint8_t *)tse_ddl_req_msg_mem + sizeof(ddl_ctrl_t)) != msg_len) { + assert(false); + } + + ddl_ctrl->msg_len = msg_len + sizeof(ddl_ctrl_t); + memcpy(tse_ddl_req_msg_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + return 0; +} \ No newline at end of file diff --git a/storage/tianchi/ha_tse_ddl.h b/storage/tianchi/ha_tse_ddl.h new file mode 100644 index 0000000..04f6680 --- /dev/null +++ b/storage/tianchi/ha_tse_ddl.h @@ -0,0 +1,234 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __HA_TSE_DDL_H__ +#define __HA_TSE_DDL_H__ +#include "tse_srv.h" +#include +#include +#include +#include "storage/tianchi/ha_tsepart.h" +#define UN_SUPPORT_DDL "ddl statement" +/** Max table name length as defined in CT_MAX_NAME_LEN */ +#define TSE_MAX_TABLE_NAME_LEN 64 +#define TSE_MAX_CONS_NAME_LEN TSE_MAX_TABLE_NAME_LEN +#define TSE_MAX_DATABASE_NAME_LEN TSE_MAX_TABLE_NAME_LEN +#define TSE_MAX_BIT_LEN 64 +#define TSE_ENUM_DEFAULT_NULL -1 +#define TSE_ENUM_DEFAULT_INVALID -2 +#define TSE_MAX_FULL_NAME_LEN (TSE_MAX_TABLE_NAME_LEN + TSE_MAX_DATABASE_NAME_LEN + 14) +#define TSE_TYPE_TIME_SIZE 3 +#define TSE_TYPE_DATATIME_SIZE 5 +#define TSE_TYPE_TIMPSTAMP_SIZE 4 + +#define DATA_N_SYS_COLS 3 /* number of system columns defined above */ + +#define DATA_ITT_N_SYS_COLS 2 +/* Maximum values for various fields (for non-blob tuples) */ +#define REC_MAX_N_FIELDS (1024 - 1) +#define REC_MAX_HEAP_NO (2 * 8192 - 1) +#define REC_MAX_N_OWNED (16 - 1) + +/* Maximum number of user defined fields/columns. The reserved columns +are the ones InnoDB adds internally: DB_ROW_ID, DB_TRX_ID, DB_ROLL_PTR. +We need "* 2" because mlog_parse_index() creates a dummy table object +possibly, with some of the system columns in it, and then adds the 3 +system columns (again) using dict_table_add_system_columns(). The problem +is that mlog_parse_index() cannot recognize the system columns by +just having n_fields, n_uniq and the lengths of the columns. */ +#define REC_MAX_N_USER_FIELDS (REC_MAX_N_FIELDS - DATA_N_SYS_COLS * 2) + +#define TSE_DDL_PROTOBUF_MSG_STACK_SIZE (4 * 1024) // < 4kb用栈内存,大于4kb用堆内存 +#define TSE_DDL_PROTOBUF_MSG_SIZE (1024 * 1024 * 10) // 10M + +typedef enum { + TSE_CREATE_IF_NOT_EXISTS = 0x00000001, + TSE_CREATE_OR_REPLACE = 0x00000002, + TSE_CREATE_TYPE_NO_CHECK_CONS = 0x00000008, // for create child table but ref parent table not create +} tse_create_option_t; + +typedef enum { + TSE_DROP_IF_EXISTS = 0x00000001, + TSE_DROP_KEEP_FILES = 0x00000002, // for tablespace + TSE_DROP_CASCADE_CONS = 0x00000004, // for tablespace + TSE_DROP_NO_CHECK_FK = 0x00000010, // for support drop without checking foreign key + TSE_DROP_FOR_MYSQL_COPY = 0x00000020, // for support alter parent table using mysql copy + TSE_DROP_NO_CHECK_FK_FOR_CANTIAN_AND_BROADCAST = 0x01000000, // just for broadcast to set NO_CHECK_FK, not for cantian +} tse_drop_option_t; + +typedef enum { + TSE_ALTSPACE_ADD_DATAFILE = 0, + TSE_ALTSPACE_DROP_DATAFILE = 1, + TSE_ALTSPACE_RENAME_DATAFILE = 2, + TSE_ALTSPACE_RENAME_SPACE = 3, + TSE_ALTSPACE_SET_AUTOEXTEND = 4, + TSE_ALTSPACE_SET_AUTOPURGE = 5, + TSE_ALTSPACE_SET_RETENTION = 6, + TSE_ALTSPACE_OFFLINE_DATAFILE = 7, + TSE_ALTSPACE_SHRINK_SPACE = 8, + TSE_ALTSPACE_SET_AUTOOFFLINE = 9 +} tse_altspace_action_t; + +typedef enum { + TSE_DDL_FK_RULE_UNKNOW = -1, + TSE_DDL_FK_RULE_RESTRICT, + TSE_DDL_FK_RULE_CASCADE, + TSE_DDL_FK_RULE_SET_NULL +} tse_ddl_fk_rule; + +typedef enum { + /** + Used for cases when key algorithm which is supported by SE can't be + described by one of other classes from this enum (@sa Federated, + PerfSchema SE, @sa dd::Index::IA_SE_SPECIFIC). + + @note Assigned as default value for key algorithm by parser, replaced by + SEs default algorithm for keys in mysql_prepare_create_table(). + */ + TSE_HA_KEY_ALG_UNKNOW = -1, + TSE_HA_KEY_ALG_SE_SPECIFIC = 0, + TSE_HA_KEY_ALG_BTREE = 1, /* B-tree. */ + TSE_HA_KEY_ALG_RTREE = 2, /* R-tree, for spatial searches */ + TSE_HA_KEY_ALG_HASH = 3, /* HASH keys (HEAP, NDB). */ + TSE_HA_KEY_ALG_FULLTEXT = 4 /* FULLTEXT. */ +} tse_ha_key_alg; + +typedef enum { + COLLATE_DEFAULT = -1, + COLLATE_GBK_BIN = 3, + COLLATE_GBK_CHINESE_CI, + COLLATE_UTF8MB4_GENERAL_CI, + COLLATE_UTF8MB4_BIN, + COLLATE_BINARY, + COLLATE_UTF8MB4_0900_AI_CI, + COLLATE_UTF8MB4_0900_BIN, + COLLATE_LATIN1_GENERAL_CI, + COLLATE_LATIN1_GENERAL_CS, + COLLATE_LATIN1_BIN, + COLLATE_ASCII_GENERAL_CI, + COLLATE_ASCII_BIN, + COLLATE_UTF8MB3_GENERAL_CI, + COLLATE_UTF8MB3_BIN, + COLLATE_UTF8_TOLOWER_CI, + COLLATE_CP850_GENERAL_CI = 28, + COLLATE_LATIN1_DANISH_CI = 33, + COLLATE_LATIN1_GERMAN1_CI = 45, + COLLATE_HP_ENGLISH_CI = 46, + COLLATE_UJIS_JAPANESE_CI = 47, + COLLATE_SWE7_SWEDISH_CI = 48, + COLLATE_SJIS_JAPANESE_CI = 49, + COLLATE_KOI8R_GENERAL_CI = 63, + COLLATE_CP1251_BULGARIAN_CI = 65, + COLLATE_HEBREW_GENERAL_CI = 83, + COLLATE_DEC8_SWEDISH_CI = 87, + COLLATE_SWEDISH_CI = 255, + COLLATE_LATIN2_GENERAL_CI = 309 +} enum_tse_ddl_collate_type; + +// mysql字符序和daac的参数对接 +static map mysql_collate_num_to_tse_type = { + {3, COLLATE_DEC8_SWEDISH_CI}, + {4, COLLATE_CP850_GENERAL_CI}, + {5, COLLATE_LATIN1_GERMAN1_CI}, + {6, COLLATE_HP_ENGLISH_CI}, + {7, COLLATE_KOI8R_GENERAL_CI}, + {8, COLLATE_SWEDISH_CI}, + {9, COLLATE_LATIN2_GENERAL_CI}, + {10, COLLATE_SWE7_SWEDISH_CI}, + {13, COLLATE_SJIS_JAPANESE_CI}, + {12, COLLATE_UJIS_JAPANESE_CI}, + {14, COLLATE_CP1251_BULGARIAN_CI}, + {15, COLLATE_LATIN1_DANISH_CI}, + {16, COLLATE_HEBREW_GENERAL_CI}, + {45, COLLATE_UTF8MB4_GENERAL_CI}, + {46, COLLATE_UTF8MB4_BIN}, + {63, COLLATE_BINARY}, + {255, COLLATE_UTF8MB4_0900_AI_CI}, + {309, COLLATE_UTF8MB4_0900_BIN}, + {48, COLLATE_LATIN1_GENERAL_CI}, + {49, COLLATE_LATIN1_GENERAL_CS}, + {47, COLLATE_LATIN1_BIN}, + {11, COLLATE_ASCII_GENERAL_CI}, + {65, COLLATE_ASCII_BIN}, + {28, COLLATE_GBK_CHINESE_CI}, + {87, COLLATE_GBK_BIN}, + {33, COLLATE_UTF8MB3_GENERAL_CI}, + {83, COLLATE_UTF8MB3_BIN}, + {76, COLLATE_UTF8_TOLOWER_CI}, +}; + +static map g_tse_alter_tablespace_map = { + {ALTER_TABLESPACE_ADD_FILE, TSE_ALTSPACE_ADD_DATAFILE}, + {ALTER_TABLESPACE_DROP_FILE, TSE_ALTSPACE_DROP_DATAFILE}, + {ALTER_TABLESPACE_RENAME, TSE_ALTSPACE_RENAME_SPACE}, + {ALTER_TABLESPACE_OPTIONS, TSE_ALTSPACE_SET_AUTOEXTEND}, // option 只有auto extend适配 +}; + +class tse_ddl_stack_mem { + public: + tse_ddl_stack_mem(size_t mem_size):buf_obj(nullptr) { + set_mem_size(mem_size); + } + void set_mem_size(size_t mem_size) { + free_buf(); + assert(mem_size < TSE_DDL_PROTOBUF_MSG_SIZE); + if (mem_size <= TSE_DDL_PROTOBUF_MSG_STACK_SIZE) { + buf_obj = stack_obj; + } else { + buf_obj = my_malloc(PSI_NOT_INSTRUMENTED, mem_size, MYF(MY_WME)); + tse_ddl_req_msg_mem_use_heap_cnt++; + } + tse_ddl_req_msg_mem_max_size = + std::max(tse_ddl_req_msg_mem_max_size, mem_size); + } + ~tse_ddl_stack_mem() { free_buf(); } + void *get_buf() { return buf_obj; } +private: + void free_buf() { + if (buf_obj != nullptr && buf_obj != stack_obj) { + my_free(buf_obj); + buf_obj = nullptr; + } + } +public: + static size_t tse_ddl_req_msg_mem_max_size; // 统计ddl的req_msg_mem用的最多内存尺寸 + static size_t tse_ddl_req_msg_mem_use_heap_cnt; // 统计ddl的req_msg_mem用的堆内存的次数 + private: + char stack_obj[TSE_DDL_PROTOBUF_MSG_STACK_SIZE]; + void *buf_obj; +}; + +int fill_delete_table_req(const char *full_path_name, const dd::Table *table_def, + THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +int tsebase_alter_tablespace(handlerton *hton, THD *thd, + st_alter_tablespace *alter_info, + const dd::Tablespace *old_ts_def, + dd::Tablespace *new_ts_def); +int ha_tse_truncate_table(tianchi_handler_t *tch, THD *thd, const char *db_name, + const char *table_name, bool is_tmp_table); +int check_tse_identifier_name(const char *in_name); +int fill_create_table_req(HA_CREATE_INFO *create_info, dd::Table *table_def, char *db_name, char *table_name, + TABLE *form, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +int fill_alter_table_req(TABLE *altered_table, Alter_inplace_info *ha_alter_info, const dd::Table *old_table_def, + dd::Table *new_table_def, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +int fill_rename_table_req(const char *from, const char *to, const dd::Table *from_table_def, + dd::Table *to_table_def, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +int fill_truncate_partition_req(const char *full_name, partition_info *part_info, + dd::Table *dd_table, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +int fill_rebuild_index_req(TABLE *table, THD *thd, ddl_ctrl_t *ddl_ctrl, tse_ddl_stack_mem *stack_mem); +bool get_tse_key_type(const KEY *key_info, int32_t *ret_type); +bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm); +#endif diff --git a/storage/tianchi/ha_tsepart.cc b/storage/tianchi/ha_tsepart.cc new file mode 100644 index 0000000..94ccef6 --- /dev/null +++ b/storage/tianchi/ha_tsepart.cc @@ -0,0 +1,1115 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// @file storage/tianchi/ha_tsepart.cc +// description: TIANCHI handler implementation for MySQL storage engine API. +// this module should use tse_part_srv rather than knl_intf + +#include "ha_tsepart.h" +#include "ha_tse_ddl.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "field_types.h" +#include "my_base.h" +#include "my_dbug.h" +#include "my_macros.h" +#include "my_pointer_arithmetic.h" +#include "my_psi_config.h" +#include "mysql/plugin.h" +#include "sql/current_thd.h" +#include "sql/dd/types/table.h" +#include "sql/field.h" +#include "sql/sql_base.h" // enum_tdc_remove_table_type +#include "sql/sql_class.h" +#include "sql/sql_lex.h" +#include "sql/sql_plugin.h" +#include "sql/partition_info.h" +#include "tse_error.h" +#include "tse_log.h" +#include "srv_mq_msg.h" +#include +#include "typelib.h" +#include "tse_cbo.h" +#include "sql/sql_alter.h" + +#define INVALID_PART_ID (uint32)0xFFFFFFFF; + +extern handlerton *get_tse_hton(); + +constexpr uint64 INVALID_VALUE64 = 0xFFFFFFFFFFFFFFFFULL; +constexpr int max_prefetch_num = MAX_PREFETCH_REC_NUM; + +static uint32_t get_ct_sub_no(uint num_subparts, uint part_id) { + uint sub_no = part_id % num_subparts; + return (uint32_t)sub_no; +} + +static uint32_t get_ct_part_no(uint num_subparts, uint part_id) { + uint part_no = part_id / num_subparts; + return (uint32_t)part_no; +} + +static void get_used_partitions(partition_info *part_info, uint32_t **part_ids, uint32_t *used_parts) { + *used_parts = part_info->num_partitions_used(); + *part_ids = (uint32_t *)my_malloc(PSI_NOT_INSTRUMENTED, (*used_parts) * sizeof(uint32_t), MYF(MY_WME)); + + uint32_t part_id = part_info->get_first_used_partition(); + **part_ids = part_id; + for (uint32_t i = 1; i < *used_parts; i++) { + part_id = part_info->get_next_used_partition(part_id); + *(*part_ids + i) = part_id; + } +} + +ha_tsepart::ha_tsepart(handlerton *hton, TABLE_SHARE *table_arg) + : ha_tse(hton, table_arg), Partition_helper(this), + m_bulk_insert_parts(nullptr), m_part_share(nullptr) { + pruned_by_engine = false; + ref_length = ROW_ID_LENGTH + PARTITION_BYTES_IN_POS; +} + +/** + Open an TSE table. + @param[in] name table name + @param[in] mode access mode + @param[in] test_if_locked test if the file to be opened is locked + @param[in] table_def dd::Table describing table to be opened + @retval 1 if error + @retval 0 if success +*/ +int ha_tsepart::open(const char *name, int mode, uint test_if_locked, + const dd::Table *table_def) { + if (!(m_part_share = get_share())) return HA_ERR_OUT_OF_MEM; + + if (m_part_info == NULL) { + m_part_info = table->part_info; + } + + lock_shared_ha_data(); + if (m_part_share->populate_partition_name_hash(m_part_info)) { + unlock_shared_ha_data(); + free_share(); + return HA_ERR_INTERNAL_ERROR; + } + if (m_part_share->auto_inc_mutex == nullptr && + table->found_next_number_field != nullptr) { + if (m_part_share->init_auto_inc_mutex(table_share)) { + unlock_shared_ha_data(); + free_share(); + return HA_ERR_INTERNAL_ERROR; + } + } + unlock_shared_ha_data(); + + int ret = ha_tse::open(name, mode, test_if_locked, table_def); + m_max_batch_num = m_max_batch_num > MAX_BULK_INSERT_PART_ROWS ? MAX_BULK_INSERT_PART_ROWS : m_max_batch_num; + + if (ret != CT_SUCCESS) { + free_share(); + return ret; + } + if (open_partitioning(m_part_share)) { + return close(); + } + + return ret; +} + +int ha_tsepart::close() { + assert(m_part_share); + close_partitioning(); + free_share(); + if (m_bulk_insert_parts != nullptr) { + my_free(m_bulk_insert_parts); + m_bulk_insert_parts = nullptr; + } + return ha_tse::close(); +} + +void ha_tsepart::set_partition(uint part_id) { + if (m_is_sub_partitioned) { + m_tch.part_id = get_ct_part_no(m_part_info->num_subparts, part_id); + m_tch.subpart_id = get_ct_sub_no(m_part_info->num_subparts, part_id); + } else { + m_tch.part_id = part_id; + m_tch.subpart_id = INVALID_PART_ID; + } +} + +void ha_tsepart::reset_partition(uint part_id) { + m_tch.part_id = INVALID_PART_ID; + m_tch.subpart_id = INVALID_PART_ID; + m_last_part = part_id; +} + +void ha_tsepart::get_auto_increment(ulonglong, ulonglong, ulonglong, + ulonglong *first_value, + ulonglong*) { + uint64 inc_value; + update_member_tch(m_tch, get_tse_hton(), ha_thd()); + THD* thd = ha_thd(); + dml_flag_t flag; + flag.auto_inc_offset = thd->variables.auto_increment_increment; + flag.auto_inc_step = thd->variables.auto_increment_offset; + flag.auto_increase = true; + int ret = tse_get_serial_value(&m_tch, &inc_value, flag); + update_sess_ctx_by_tch(m_tch, get_tse_hton(), ha_thd()); + if (ret != 0) { + *first_value = (~(ulonglong)0); + return; + } + *first_value = inc_value; +} + +void ha_tsepart::print_error(int error, myf errflag) { + if (print_partition_error(error)) { + handler::print_error(error, errflag); + } +} + +void ha_tsepart::part_autoinc_has_expl_non_null_value_update_row(uchar *new_data) { + if (table->found_next_number_field && new_data == table->record[0] && + !table->s->next_number_keypart && + bitmap_is_set(table->write_set, + table->found_next_number_field->field_index())) { + autoinc_has_expl_non_null_value_update_row = true; + } +} + +/** + Write a row in specific partition. + Stores a row in an TSE database, to the table specified in this + handle. + @param[in] part_id Partition to write to. + @param[in] record A row in MySQL format. + @return error code. +*/ +int ha_tsepart::write_row_in_part(uint part_id, uchar *record) { + bool saved_autoinc_has_expl_non_null = table->autoinc_field_has_explicit_non_null_value; + Field *saved_next_number_field = table->next_number_field; + THD *thd = ha_thd(); + if (!autoinc_has_expl_non_null_value_update_row && + table->next_number_field && !autoinc_has_expl_non_null_value) { + table->autoinc_field_has_explicit_non_null_value = false; + table->next_number_field->store(0, true); + } + if (table->found_next_number_field && autoinc_has_expl_non_null_value_update_row) { + table->autoinc_field_has_explicit_non_null_value = true; + table->next_number_field = table->found_next_number_field; + if (table->next_number_field->val_int() == 0) { + thd->force_one_auto_inc_interval(0); + } + autoinc_has_expl_non_null_value_update_row = false; + } + + set_partition(part_id); + int ret = ha_tse::write_row(record); + + if (ret == 0 && m_rec_buf_4_writing != nullptr) { + assert(m_bulk_insert_parts != nullptr); + assert(m_rec_buf_4_writing->records() > 0); + // write_row has already put the record in buffer, so pos is size - 1 + ha_rows pos = m_rec_buf_4_writing->records() - 1; + m_bulk_insert_parts[pos] = {m_tch.part_id, m_tch.subpart_id}; + } + reset_partition(part_id); + + table->autoinc_field_has_explicit_non_null_value = saved_autoinc_has_expl_non_null; + table->next_number_field = saved_next_number_field; + return ret; +} + +void ha_tsepart::start_bulk_insert(ha_rows rows) { + assert(m_rec_buf_4_writing == nullptr); + ha_tse::start_bulk_insert(rows); + if (m_rec_buf_4_writing != nullptr) { + if (m_bulk_insert_parts == nullptr) { + // m_max_batch_num is fixed after open table, if table structrue is changed, it should be closed and reopened + m_bulk_insert_parts = (ctc_part_t *)my_malloc(PSI_NOT_INSTRUMENTED, + m_max_batch_num * sizeof(ctc_part_t), MYF(MY_WME)); + } + } +} + +int ha_tsepart::bulk_insert_low(dml_flag_t flag, uint *dup_offset) { + record_info_t record_info = {m_rec_buf_data, (uint16_t)m_cantian_rec_len}; + return (ct_errno_t)tse_bulk_write(&m_tch, &record_info, m_rec_buf_4_writing->records(), + dup_offset, flag, m_bulk_insert_parts); +} + +/** + Update a row in partition. + Updates a row given as a parameter to a new value. + @param[in] part_id Partition to update row in. + @param[in] old_row Old row in MySQL format. + @param[in] new_row New row in MySQL format. + @return error number or 0. +*/ +int ha_tsepart::update_row_in_part(uint part_id, const uchar *old_row, uchar *new_row) { + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + int ret; + ret = ha_tse::update_row(old_row, new_row); + reset_partition(part_id); + return ret; +} + +/** + Write row to new partition. + @param[in] new_part_id New partition to write to. + @return 0 for success else error code. +*/ +int ha_tsepart::write_row_in_new_part(uint new_part_id) { + UNUSED_PARAM(new_part_id); + return 0; +} + +/** + Deletes a row in partition. + @param[in] part_id Partition to delete from. + @param[in] record Row to delete in MySQL format. + @return error number or 0. +*/ +int ha_tsepart::delete_row_in_part(uint part_id, const uchar *record) { + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + int ret; + ret = ha_tse::delete_row(record); + reset_partition(part_id); + return ret; +} + +/** + Initialize random read/scan of a specific partition. + @param[in] part_id Partition to initialize. + @param[in] scan True for scan else random access. + @return error number or 0. +*/ +int ha_tsepart::rnd_init_in_part(uint part_id, bool scan) { + set_partition(part_id); + int ret = ha_tse::rnd_init(scan); + reset_partition(part_id); + return ret; +} + +/** + Get next row during scan of a specific partition. + @param[in] part_id Partition to read from. + @param[out] buf Next row. + @return error number or 0. +*/ +int ha_tsepart::rnd_next_in_part(uint part_id, uchar *buf) { + set_partition(part_id); + int ret = ha_tse::rnd_next(buf); + reset_partition(part_id); + return ret; +} + +/** + End random read/scan of a specific partition. + @param[in] part_id Partition to end random read/scan. + @param[in] scan True for scan else random access. + @return error number or 0. +*/ +int ha_tsepart::rnd_end_in_part(uint part_id, bool scan) { + UNUSED_PARAM(scan); + if (m_tch.cursor_addr == INVALID_VALUE64) { + return 0; + } + set_partition(part_id); + int ret = ha_tse::rnd_end(); + reset_partition(part_id); + return ret; +} + +/** + Get a reference to the current cursor position in the last used partition. + @param[out] ref_arg Reference (PK if exists else row_id). + @param[in] record Record to position. +*/ +void ha_tsepart::position_in_last_part(uchar *ref_arg, const uchar *record) { + UNUSED_PARAM(record); + m_tch.thd_id = ha_thd()->thread_id(); + uint part_id = m_last_part; + set_partition(part_id); + int ret = 0; + if (cur_pos_in_buf == INVALID_MAX_UINT32) { + ret = tse_position(&m_tch, ref_arg, ref_length - PARTITION_BYTES_IN_POS); + } else { + assert(cur_pos_in_buf < max_prefetch_num); + memcpy(ref_arg, &m_rowids[cur_pos_in_buf], ref_length - PARTITION_BYTES_IN_POS); + } + + if (ret != 0) { + tse_log_error("find position failed."); + assert(0); + } + reset_partition(part_id); +} + +/** + Get a row from a position. + Fetches a row from the table based on a row reference. + @param[out] buf Returns the row in this buffer, in MySQL format. + @param[in] pos Position, given as primary key value or DB_ROW_ID + @return 0, HA_ERR_KEY_NOT_FOUND or error code. +*/ +int ha_tsepart::rnd_pos(uchar *buf, uchar *pos) { + DBUG_TRACE; + ha_statistic_increment(&System_status_var::ha_read_rnd_count); + m_tch.thd_id = ha_thd()->thread_id(); + uint part_id = uint2korr(pos); + set_partition(part_id); + int ret = ha_tse::rnd_pos(buf, pos + PARTITION_BYTES_IN_POS); + reset_partition(part_id); + return ret; +} + +/** + Initializes a handle to use an index. + @param[in] index Key (index) number. + @param[in] sorted True if result MUST be sorted according to index. + @return 0 or error number. +*/ +int ha_tsepart::index_init(uint index, bool sorted) { + int ret; + ret = ph_index_init_setup(index, sorted); + if (ret != 0) { + return ret; + } + + if (sorted) { + ret = init_record_priority_queue(); + if (ret != 0) { + /* Needs cleanup in case it returns error. */ + destroy_record_priority_queue(); + return ret; + } + } + + uint part_id = m_part_info->get_first_used_partition(); + + set_partition(part_id); + ret = ha_tse::index_init(index, sorted); + reset_partition(part_id); + + pruned_by_engine = false; + if (sorted && m_rec_buf && m_part_info->num_partitions_used() > 1) { + delete m_rec_buf; + m_rec_buf = nullptr; + } + + return ret; +} + +/** + End index cursor. + @return 0 or error code. +*/ +int ha_tsepart::index_end() { + pruned_by_engine = false; + if (m_ordered) { + destroy_record_priority_queue(); + for (uint i = m_part_info->get_first_used_partition(); i < MY_BIT_NONE; i = m_part_info->get_next_used_partition(i)) { + if (cursor_is_set(cursor_set, i)){ + m_tch.cursor_addr = cursors[i]; + ha_tse::index_end(); + cursor_clear_bit(cursor_set, i); + } + } + m_tch.part_id = INVALID_PART_ID; + m_tch.subpart_id = INVALID_PART_ID; + return 0; + } + + ha_tse::index_end(); + m_tch.part_id = INVALID_PART_ID; + m_tch.subpart_id = INVALID_PART_ID; + m_tch.cursor_ref = 0; + m_tch.cursor_valid = false; + return 0; +} + +int ha_tsepart::index_read(uchar *buf, const uchar *key, uint key_len, + ha_rkey_function find_flag) { + return ha_tse::index_read(buf, key, key_len, find_flag); +} + +/** + Return first record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record First record in index in the partition. + @return error number or 0. +*/ +int ha_tsepart::index_first_in_part(uint part_id, uchar *record) { + if (part_id != m_last_part) { + ha_tse::reset_rec_buf(); + } + set_partition(part_id); + int ret = ha_tse::index_first(record); + reset_partition(part_id); + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + cursors[part_id] = m_tch.cursor_addr; + } + return ret; +} + +/** + Return last record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. +*/ +int ha_tsepart::index_last_in_part(uint part_id, uchar *record) { + if (part_id != m_last_part) { + ha_tse::reset_rec_buf(); + } + set_partition(part_id); + int ret = ha_tse::index_last(record); + reset_partition(part_id); + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + cursors[part_id] = m_tch.cursor_addr; + } + return ret; +} + +/** + Return previous record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. +*/ +int ha_tsepart::index_prev_in_part(uint part_id, uchar *record) { + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + set_partition(part_id); + int ret = ha_tse::index_prev(record); + reset_partition(part_id); + return ret; +} + +/** + Return next record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. +*/ +int ha_tsepart::index_next_in_part(uint part_id, uchar *record) { + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + set_partition(part_id); + int ret = ha_tse::index_next(record); + reset_partition(part_id); + return ret; +} + +/** + Return next same record in index from a partition. + This routine is used to read the next record, but only if the key is + the same as supplied in the call. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @param[in] key Key to match. + @param[in] length Length of key. + @return error number or 0. +*/ +int ha_tsepart::index_next_same_in_part(uint part_id, uchar *record, const uchar *key, uint length) { + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + set_partition(part_id); + int ret = ha_tse::index_next_same(record, key, length); + reset_partition(part_id); + return ret; +} + +/** + Start index scan and return first record from a partition. + This routine starts an index scan using a start key. The calling + function will check the end key on its own. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @param[in] find_flag Key condition/direction to use. + @return error number or 0. +*/ +int ha_tsepart::index_read_map_in_part(uint part_id, uchar *record, const uchar *key, + key_part_map keypart_map, enum ha_rkey_function find_flag) { + if (part_id != m_last_part) { + ha_tse::reset_rec_buf(); + } + set_partition(part_id); + int ret = ha_tse::index_read_map(record, key, keypart_map, find_flag); + reset_partition(part_id); + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + cursors[part_id] = m_tch.cursor_addr; + } + return ret; +} + +/** + Return last matching record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last matching record in index in the partition. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @return error number or 0. +*/ +int ha_tsepart::index_read_last_map_in_part(uint part_id, uchar *record, const uchar *key, + key_part_map keypart_map) { + if (part_id != m_last_part) { + ha_tse::reset_rec_buf(); + } + set_partition(part_id); + int ret = ha_tse::index_read_last_map(record, key, keypart_map); + reset_partition(part_id); + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + cursors[part_id] = m_tch.cursor_addr; + } + return ret; +} + +/** + Start index scan and return first record from a partition. + This routine starts an index scan using a start key. The calling + function will check the end key on its own. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + @param[in] index Index to read from. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @param[in] find_flag Key condition/direction to use. + @return error number or 0. +*/ +int ha_tsepart::index_read_idx_map_in_part(uint part_id, uchar *record, uint index, + const uchar *key, key_part_map keypart_map, + enum ha_rkey_function find_flag) { + set_partition(part_id); + int ret = ha_tse::index_read_idx_map(record, index, key, keypart_map, find_flag); + reset_partition(part_id); + return ret; +} + +bool ha_tsepart::need_prune_partitions_by_engine(const key_range *start_key, const key_range *end_key) { + if (start_key == nullptr || end_key == nullptr) { + return false; + } + + if (m_part_info->num_partitions_used() != m_part_info->get_tot_partitions()) { + // pruned by optimizer + return false; + } + + if (start_key->flag == HA_READ_KEY_EXACT) { + return false; + } + + for (uint i = 0; i < m_part_info->num_columns; i++) { + if (!m_part_info->part_field_array[i]->part_of_key.is_set(active_index)) { + // partition field is not used in current index + return false; + } + } + + return true; +} + +bool ha_tsepart::equal_range_on_part_field(const key_range *start_key, const key_range *end_key) { + vector part_field_ids; + for (uint i = 0; i num_columns; i++) { + part_field_ids.push_back(m_part_info->part_field_array[i]->field_index()); + } + + KEY cur_index = table->key_info[active_index]; + uint offset = 0; + + for (uint i = 0; i < cur_index.actual_key_parts; i++) { + if (offset >= start_key->length) { + return false; + } + KEY_PART_INFO cur_index_part = cur_index.key_part[i]; + auto iter = find(part_field_ids.begin(), part_field_ids.end(), cur_index_part.field->field_index()); + if (iter == part_field_ids.end()) { + // current key part is not in parted columns + continue; + } + if (memcmp(start_key->key + offset, end_key->key + offset, cur_index_part.length) != 0) { + return false; + } + if (start_key->keypart_map & (1 << i)) { + offset += cur_index_part.length; + } + } + return true; +} + +/** + Start index scan and return first record from a partition. + This routine starts an index scan using a start and end key. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + if NULL use table->record[0] as return buffer. + @param[in] start_key Start key to match. + @param[in] end_key End key to match. + @param[in] sorted Return rows in sorted order. + @return error number or 0. +*/ +int ha_tsepart::read_range_first_in_part(uint part_id, uchar *record, + const key_range *start_key, + const key_range *end_key, bool sorted) { + UNUSED_PARAM(sorted); + + uchar *read_record = record; + if (read_record == nullptr) { + read_record = table->record[0]; + } + + if (pruned_by_engine && part_id != part_spec.start_part) { + return HA_ERR_END_OF_FILE; + } + + // prune partitions that doesn't match with condition and take an early return + if (need_prune_partitions_by_engine(start_key, end_key) && equal_range_on_part_field(start_key, end_key)) { + pruned_by_engine = true; + key_range tmp_key; + memcpy(&tmp_key, start_key, sizeof(key_range)); + tmp_key.flag = HA_READ_KEY_EXACT; + get_partition_set(table, read_record, active_index, &tmp_key, &part_spec); + assert(part_spec.start_part == part_spec.end_part); + + if (part_id != part_spec.start_part) { + return HA_ERR_END_OF_FILE; + } + } + + int ret; + if (part_id != m_last_part) { + ha_tse::reset_rec_buf(); + } + + set_partition(part_id); + if (m_start_key.key != nullptr) { + ret = index_read(read_record, m_start_key.key, + m_start_key.length, m_start_key.flag); + } else { + ret = ha_tse::index_first(read_record); + } + if (ret == HA_ERR_KEY_NOT_FOUND) { + ret = HA_ERR_END_OF_FILE; + } else if (ret == 0 && !in_range_check_pushed_down) { + /* compare_key uses table->record[0], so we + need to copy the data if not already there. */ + + if (record != nullptr) { + memcpy(table->record[0], read_record, m_rec_length); + } + if (compare_key(end_range) > 0) { + ret = HA_ERR_END_OF_FILE; + } + } + reset_partition(part_id); + + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + cursors[part_id] = m_tch.cursor_addr; + } + return ret; +} + +/** + Return next record in index range scan from a partition. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + if NULL use table->record[0] as return buffer. + @return error number or 0. +*/ +int ha_tsepart::read_range_next_in_part(uint part_id, uchar *record) { + uchar *read_record = record; + if (read_record == nullptr) { + read_record = table->record[0]; + } + if (m_index_sorted) { + cursor_set_bit(cursor_set, part_id); + m_tch.cursor_addr = cursors[part_id]; + } + set_partition(part_id); + int ret = ha_tse::index_next(read_record); + reset_partition(part_id); + return ret; +} + +/** + Get partition row type + @param[in] partition_table Partition table + @param[in] part_id Id of partition for which row type to be retrieved + @return Partition row type. +*/ +enum row_type ha_tsepart::get_partition_row_type(const dd::Table *partition_table, uint part_id) { + UNUSED_PARAM(partition_table); + UNUSED_PARAM(part_id); + return ROW_TYPE_NOT_USED; +} + +void ha_tsepart::info_low() { + stats.records = 0; + if (m_part_share->cbo_stats != nullptr) { + uint part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : + table->part_info->num_parts; + for (uint part_id = m_part_info->get_first_used_partition(); part_id < part_num; + part_id = m_part_info->get_next_used_partition(part_id)) { + stats.records += m_part_share->cbo_stats->estimate_part_rows_and_blocks[part_id]; + } + } +} + +ha_rows ha_tsepart::records_in_range(uint inx, key_range *min_key, key_range *max_key) { + tse_range_key tse_min_key; + tse_range_key tse_max_key; + set_tse_range_key(&tse_min_key, min_key, CMP_TYPE_GREAT); + set_tse_range_key(&tse_max_key, max_key, CMP_TYPE_LESS); + + uint32_t used_parts; + uint32_t *part_ids = NULL; + get_used_partitions(m_part_info, &part_ids, &used_parts); + uint64_t n_rows_num = 0; + uint32_t part_num = table->part_info->num_parts; + uint32_t subpart_num = table->part_info->num_subparts; + + for (uint i = 0; i < used_parts; i++) { + uint32_t part_id = m_is_sub_partitioned ? part_ids[i] / m_part_info->num_subparts : + part_ids[i]; + uint32_t subpart_id = m_is_sub_partitioned ? part_ids[i] % m_part_info->num_subparts : + INVALID_PART_ID; + part_info_t part_info = {part_id, subpart_id, part_num, subpart_num}; + double density = calc_density_one_table(inx, &tse_min_key, &tse_max_key, part_info, m_part_share->cbo_stats, *table); + n_rows_num += m_part_share->cbo_stats->estimate_part_rows_and_blocks[part_id] * density; + } + + /* + * The MySQL optimizer seems to believe an estimate of 0 rows is + * always accurate and may return the result 'Empty set' based on that + */ + if (n_rows_num == 0) { + n_rows_num = 1; + } + my_free(part_ids); + return (ha_rows)n_rows_num; +} + +int ha_tsepart::records(ha_rows *num_rows) /*!< out: number of rows */ +{ + *num_rows = 0; + int ret; + for (uint part_id = m_part_info->get_first_used_partition(); part_id < m_tot_parts; + part_id = m_part_info->get_next_used_partition(part_id)) { + set_partition(part_id); + ha_rows n_rows{}; + ret = ha_tse::records(&n_rows); + reset_partition(part_id); + if (ret != 0) { + *num_rows = HA_POS_ERROR; + return ret; + } + *num_rows += n_rows; + } + return 0; +} + +extern uint32_t tse_instance_id; +/* alter table truncate partition */ +int ha_tsepart::truncate_partition_low(dd::Table *dd_table) { + THD *thd = ha_thd(); + if (engine_ddl_passthru(thd)) { + return 0; + } + + tse_ddl_stack_mem stack_mem(0); + update_member_tch(m_tch, ht, thd); + ddl_ctrl_t ddl_ctrl = {{0}, {0}, {0}, 0, 0, m_tch, tse_instance_id, false, 0}; + FILL_USER_INFO_WITH_THD(ddl_ctrl, thd); + ct_errno_t ret = (ct_errno_t)fill_truncate_partition_req( + table->s->normalized_path.str, m_part_info, dd_table, thd, &ddl_ctrl, + &stack_mem); + if (ret != 0) { + return convert_tse_error_code_to_mysql(ret); + } + void *tse_ddl_req_msg_mem = stack_mem.get_buf(); + if (tse_ddl_req_msg_mem == nullptr) { + return HA_ERR_OUT_OF_MEM; + } + ret = (ct_errno_t)tse_truncate_partition(tse_ddl_req_msg_mem, &ddl_ctrl); + tse_ddl_hook_cantian_error("tse_truncate_partition_cantian_error", thd, &ddl_ctrl, &ret); + m_tch = ddl_ctrl.tch; + update_sess_ctx_by_tch(m_tch, ht, thd); + return tse_ddl_handle_fault("tse_truncate_partition", thd, &ddl_ctrl, ret); +} + +int ha_tsepart::analyze(THD *thd, HA_CHECK_OPT *opt) { + if (engine_ddl_passthru(thd)) { + m_part_share->need_fetch_cbo = true; + return 0; + } + Alter_info *const alter_info = get_thd()->lex->alter_info; + if ((alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION) == 0 || + (alter_info->flags & Alter_info::ALTER_ALL_PARTITION)) { + m_tch.part_id = INVALID_PART_ID; + m_part_share->need_fetch_cbo = true; + return ha_tse::analyze(thd, opt); + } + int ret; + uint32_t used_parts; + uint32_t *part_ids = NULL; + if (!m_part_info->set_read_partitions(&alter_info->partition_names)) { + get_used_partitions(m_part_info, &part_ids, &used_parts); + } else { + tse_log_error("no partition alter !"); + return HA_ERR_GENERIC; + } + if (m_part_info->num_parts == used_parts) { + m_tch.part_id = INVALID_PART_ID; + my_free(part_ids); + m_part_share->need_fetch_cbo = true; + return ha_tse::analyze(thd, opt); + } + for (uint i = 0; i < used_parts; i++) { + uint32_t part_id = part_ids[i]; + m_tch.part_id = part_id; + m_part_share->need_fetch_cbo = true; + ret = ha_tse::analyze(thd, opt); + if (ret != 0) { + tse_log_error("analyze partition error!"); + my_free(part_ids); + return ret; + } + } + my_free(part_ids); + return ret; +} + +int ha_tsepart::optimize(THD *thd, HA_CHECK_OPT *opt) { + int ret; + m_tch.part_id = INVALID_PART_ID; + ret = ha_tse::analyze(thd, opt); + if (ret != 0) { + tse_log_error("analyze partition error!"); + return ret; + } + m_part_share->need_fetch_cbo = true; + ret = ha_tse::optimize(thd, opt); + if (ret != 0) { + tse_log_error("optimize partition error!"); + return ret; + } + return (HA_ADMIN_TRY_ALTER); +} + +int ha_tsepart::initialize_cbo_stats() { + if (m_part_share->cbo_stats != nullptr) { + return CT_SUCCESS; + } + uint32_t part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : + table->part_info->num_parts; + uint32_t part_field = table->s->fields; + + /* estimate_part_rows_and_blocks数组包括part_rows和part_blocks,数组长度为2 * part_num */ + uint32_t rows_and_blocks_num = 2 * part_num; + + if (part_num * part_field * sizeof(cache_variant_t) > MAX_MESSAGE_SIZE) { + /* 申请共享内存超限时申请一片连续空间,包括tianchi_cbo_stats_t结构体、part_rows及part_blocks数组 + * 以及num_distincts、low_values、high_values三块数据区域 + */ + uint32_t data_size = sizeof(tianchi_cbo_stats_t) + rows_and_blocks_num * sizeof(uint32_t) + + part_num * part_field * (sizeof(uint32_t) + sizeof(cache_variant_t) + sizeof(cache_variant_t)); + m_part_share->cbo_stats = (tianchi_cbo_stats_t *)malloc(data_size); + if (m_part_share->cbo_stats == nullptr) { + tse_log_error("alloc mem failed, m_part_share->cbo_stats size(%lu)", sizeof(data_size)); + return ERR_ALLOC_MEMORY; + } + *m_part_share->cbo_stats = {0, 0, 0, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, 0, 0, 0, 0, {}}; + + uint8_t *offset = (uint8_t *)m_part_share->cbo_stats + sizeof(tianchi_cbo_stats_t) + rows_and_blocks_num * sizeof(uint32_t); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts = (uint32_t *)offset; + offset += part_num * part_field * sizeof(uint32_t); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values = (cache_variant_t *)offset; + offset += part_num * part_field * sizeof(cache_variant_t); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values = (cache_variant_t *)offset; + } else { + m_part_share->cbo_stats = (tianchi_cbo_stats_t*)tse_alloc_buf(&m_tch, sizeof(tianchi_cbo_stats_t) + + rows_and_blocks_num * sizeof(uint32_t)); + if (m_part_share->cbo_stats == nullptr) { + tse_log_error("alloc shm mem failed, m_part_share->cbo_stats size(%lu)", sizeof(tianchi_cbo_stats_t)); + return ERR_ALLOC_MEMORY; + } + *m_part_share->cbo_stats = {0, 0, 0, 0, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr, 0, 0, 0, 0, {}}; + + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts = + (uint32_t *)tse_alloc_buf(&m_tch, part_num * part_field * sizeof(uint32_t)); + + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values = + (cache_variant_t *)tse_alloc_buf(&m_tch, part_num * part_field * sizeof(cache_variant_t)); + + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values = + (cache_variant_t *)tse_alloc_buf(&m_tch, part_num * part_field * sizeof(cache_variant_t)); + + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts == nullptr || + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values == nullptr || + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values == nullptr) { + tse_log_error("alloc mem failed, size(%lu)", part_num * part_field * sizeof(uint32_t) + + 2 * part_num * part_field * sizeof(cache_variant_t)); + free_cbo_stats(); + return ERR_ALLOC_MEMORY; + } + } + m_part_share->cbo_stats->part_table_info.rows_and_blocks_size = rows_and_blocks_num * sizeof(uint32_t); + m_part_share->cbo_stats->part_table_info.num_distinct_size = part_num * part_field * sizeof(uint32_t); + m_part_share->cbo_stats->part_table_info.low_value_size = part_num * part_field * sizeof(cache_variant_t); + m_part_share->cbo_stats->part_table_info.high_value_size = part_num * part_field * sizeof(cache_variant_t); + + return CT_SUCCESS; +} + + +int ha_tsepart::get_cbo_stats_4share() +{ + THD *thd = ha_thd(); + int ret = CT_SUCCESS; + time_t now = time(nullptr); + if (m_part_share->need_fetch_cbo || now - m_part_share->get_cbo_time > 60) { + if (m_tch.ctx_addr == INVALID_VALUE64) { + char user_name[SMALL_RECORD_SIZE]; + tse_split_normalized_name(table->s->normalized_path.str, user_name, SMALL_RECORD_SIZE, nullptr, 0, nullptr); + tse_copy_name(user_name, user_name, SMALL_RECORD_SIZE); + update_member_tch(m_tch, get_tse_hton(), thd); + ret = tse_open_table(&m_tch, table->s->table_name.str, user_name); + update_sess_ctx_by_tch(m_tch, get_tse_hton(), thd); + if (ret != CT_SUCCESS) { + return ret; + } + } + update_member_tch(m_tch, get_tse_hton(), thd); + ret = tse_get_cbo_stats(&m_tch, m_part_share->cbo_stats); + update_sess_ctx_by_tch(m_tch, get_tse_hton(), thd); + if (ret == CT_SUCCESS && m_part_share->cbo_stats->is_updated) { + m_part_share->need_fetch_cbo = false; + } + m_part_share->get_cbo_time = now; + } + + return ret; +} + +void ha_tsepart::free_cbo_stats() { + if (m_part_share->cbo_stats == nullptr) { + return; + } + + if (m_part_share->cbo_stats->part_table_info.low_value_size <= MAX_MESSAGE_SIZE) { + // 释放m_part_share->cbo_stats指向的共享内存 + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts = nullptr; + } + + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values = nullptr; + } + + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values != nullptr) { + tse_free_buf(&m_tch, (uchar *) m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values); + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values = nullptr; + } + + tse_free_buf(&m_tch, (uchar *) m_part_share->cbo_stats); + } else { + // 释放m_part_share->cbo_stats指向的普通内存 + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts != nullptr) { + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_num_distincts = nullptr; + } + + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values != nullptr) { + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_low_values = nullptr; + } + + if (m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values != nullptr) { + m_part_share->cbo_stats->tse_cbo_stats_table.part_table_high_values = nullptr; + } + + free(m_part_share->cbo_stats); + } + m_part_share->cbo_stats = nullptr; +} + +int ha_tsepart::check(THD *, HA_CHECK_OPT *) +{ + return HA_ADMIN_OK; +} + +int ha_tsepart::repair(THD *thd, HA_CHECK_OPT *) +{ + if (engine_ddl_passthru(thd)) { + return HA_ADMIN_OK; + } + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(get_tse_hton(), thd, tch)); + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + string sql = string(thd->query().str).substr(0, thd->query().length); + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, tse_instance_id, thd->lex->sql_command); + if (thd->db().str != NULL && thd->db().length > 0) { + strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + } + broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; + + if (IS_METADATA_NORMALIZATION()) { + ct_errno_t ret = (ct_errno_t)ctc_record_sql_for_cantian(&tch, &broadcast_req, false); + assert (ret == CT_SUCCESS); + } else { + ct_errno_t ret = (ct_errno_t)tse_execute_mysql_ddl_sql(&tch, &broadcast_req, false); + assert (ret == CT_SUCCESS); + } + + return HA_ADMIN_OK; +} + +uint32 ha_tsepart::calculate_key_hash_value(Field **field_array) +{ + return (Partition_helper::ph_calculate_key_hash_value(field_array)); +} + diff --git a/storage/tianchi/ha_tsepart.h b/storage/tianchi/ha_tsepart.h new file mode 100644 index 0000000..0cb0759 --- /dev/null +++ b/storage/tianchi/ha_tsepart.h @@ -0,0 +1,438 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* class for the the tse part table handler */ + +#ifndef __HA_TSEPART_H__ +#define __HA_TSEPART_H__ + +#include "ha_tse.h" +#include "tse_srv.h" +#include "tse_util.h" +#include "sql/partitioning/partition_handler.h" + +class Tsepart_share : public Partition_share { + public: + //std::vector table_records; + tianchi_cbo_stats_t *cbo_stats = nullptr; + int used_count = 0; + bool need_fetch_cbo = false; + time_t get_cbo_time = 0; +}; + + +/** @brief + Class definition for the storage engine +*/ +class ha_tsepart : public ha_tse, + public Partition_helper, + public Partition_handler { + public: + ha_tsepart(handlerton *hton, TABLE_SHARE *table_arg); + + handler *get_handler() override { return (static_cast(this)); } + + /** Set active partition. + @param[in] part_id Partition to set as active. */ + void set_partition(uint part_id); + + /** Reset active partition and last partition. + @param[in] part_id Partition to reset after use. */ + void reset_partition(uint part_id); + + /** + Truncate partition. + + Low-level primitive for handler, implementing + Partition_handler::truncate_partition(). + + @sa Partition_handler::truncate_partition(). + */ + int truncate_partition_low(dd::Table *dd_table) override; + + /** Write a row in specific partition. + Stores a row in an TSE database, to the table specified in this + handle. + @param[in] part_id Partition to write to. + @param[in] record A row in MySQL format. + @return error code. */ + int write_row_in_part(uint part_id, uchar *record) override; + + /* functions used for notifying SE to start/terminate batch insertion */ + void start_bulk_insert(ha_rows rows) override; + + /** write row to new partition. + @param[in] new_part New partition to write to. + @return 0 for success else error code. */ + int write_row_in_new_part(uint new_part) override; + + /** Update a row in partition. + Updates a row given as a parameter to a new value. + @param[in] part_id Partition to update row in. + @param[in] old_row Old row in MySQL format. + @param[in] new_row New row in MySQL format. + @return error number or 0. */ + int update_row_in_part(uint part_id, const uchar *old_row, + uchar *new_row) override; + + /** Deletes a row in partition. + @param[in] part_id Partition to delete from. + @param[in] record Row to delete in MySQL format. + @return error number or 0. */ + int delete_row_in_part(uint part_id, const uchar *record) override; + + /** Return first record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record First record in index in the partition. + @return error number or 0. */ + int index_first_in_part(uint part_id, uchar *record) override; + + /** Return last record in index from a partition. + @param[in] part_idart Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. */ + int index_last_in_part(uint part_id, uchar *record) override; + + /** Return previous record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. */ + int index_prev_in_part(uint part_id, uchar *record) override; + + /** Return next record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @return error number or 0. */ + int index_next_in_part(uint part_id, uchar *record) override; + + /** Initialize random read/scan of a specific partition. + @param[in] part_id Partition to initialize. + @param[in] scan True for scan else random access. + @return error number or 0. */ + int rnd_init_in_part(uint part_id, bool scan) override; + + /** Get next row during scan of a specific partition. + @param[in] part_id Partition to read from. + @param[out] buf Next row. + @return error number or 0. */ + int rnd_next_in_part(uint part_id, uchar *buf) override; + + /** End random read/scan of a specific partition. + @param[in] part_id Partition to end random read/scan. + @param[in] scan True for scan else random access. + @return error number or 0. */ + int rnd_end_in_part(uint part_id, bool scan) override; + + /** Get a reference to the current cursor position in the last used + partition. + @param[out] ref_arg Reference (PK if exists else row_id). + @param[in] record Record to position. */ + void position_in_last_part(uchar *ref_arg, const uchar *record) override; + + /** Return next same record in index from a partition. + This routine is used to read the next record, but only if the key is + the same as supplied in the call. + @param[in] part_id Partition to read from. + @param[out] record Last record in index in the partition. + @param[in] key Key to match. + @param[in] length Length of key. + @return error number or 0. */ + int index_next_same_in_part(uint part_id, uchar *record, const uchar *key, + uint length) override; + + /** Start index scan and return first record from a partition. + This routine starts an index scan using a start key. The calling + function will check the end key on its own. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @param[in] find_flag Key condition/direction to use. + @return error number or 0. */ + int index_read_map_in_part(uint part_id, uchar *record, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) override; + + /** Return last matching record in index from a partition. + @param[in] part_id Partition to read from. + @param[out] record Last matching record in index in the partition. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @return error number or 0. */ + int index_read_last_map_in_part(uint papart_id, uchar *record, const uchar *key, + key_part_map keypart_map) override; + + /** Start index scan and return first record from a partition. + This routine starts an index scan using a start and end key. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + if NULL use table->record[0] as return buffer. + @param[in] start_key Start key to match. + @param[in] end_key End key to match. + @param[in] sorted Return rows in sorted order. + @return error number or 0. */ + int read_range_first_in_part(uint part_id, uchar *record, + const key_range *start_key, + const key_range *end_key, bool sorted) override; + + /** Return next record in index range scan from a partition. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + if NULL use table->record[0] as return buffer. + @return error number or 0. */ + int read_range_next_in_part(uint part_id, uchar *record) override; + + /** Start index scan and return first record from a partition. + This routine starts an index scan using a start key. The calling + function will check the end key on its own. + @param[in] part_id Partition to read from. + @param[out] record First matching record in index in the partition. + @param[in] index Index to read from. + @param[in] key Key to match. + @param[in] keypart_map Which part of the key to use. + @param[in] find_flag Key condition/direction to use. + @return error number or 0. */ + int index_read_idx_map_in_part(uint part_id, uchar *record, uint index, + const uchar *key, key_part_map keypart_map, + enum ha_rkey_function find_flag) override; + + /** Open an TSE table. + @param[in] name table name + @param[in] mode access mode + @param[in] test_if_locked test if the file to be opened is locked + @param[in] table_def dd::Table describing table to be opened + @retval 1 if error + @retval 0 if success */ + int open(const char *name, int mode, uint test_if_locked, + const dd::Table *table_def) override; + + int close() override; + + int check(THD *thd, HA_CHECK_OPT *check_opt) override; + + int repair(THD *thd, HA_CHECK_OPT *check_opt) override; + + int rnd_init(bool scan) override { + return (Partition_helper::ph_rnd_init(scan)); + } + + int rnd_next(uchar *record) override { + return (Partition_helper::ph_rnd_next(record)); + } + + int rnd_end() override { + return (Partition_helper::ph_rnd_end()); + } + + void position(const uchar *record) override { + Partition_helper::ph_position(record); + } + + int rnd_pos(uchar *record, uchar *pos) override; + + void part_autoinc_has_expl_non_null_value_update_row(uchar *new_data); +#ifdef METADATA_NORMALIZED + int write_row(uchar *record, bool write_through MY_ATTRIBUTE((unused)) = false) override { +#endif +#ifndef METADATA_NORMALIZED + int write_row(uchar *record) override { +#endif + if (table->next_number_field) { + autoinc_has_expl_non_null_value = true; + } + return Partition_helper::ph_write_row(record); + } + + int update_row(const uchar *old_record, uchar *new_record) override { + part_autoinc_has_expl_non_null_value_update_row(new_record); + return (Partition_helper::ph_update_row(old_record, new_record)); + } + + int delete_row(const uchar *record) override { + return (Partition_helper::ph_delete_row(record)); + } + + int delete_all_rows() override { return (handler::delete_all_rows()); } + + int index_init(uint index, bool sorted) override; + + int index_end() override; + + int index_read(uchar *buf, const uchar *key, uint key_len, + ha_rkey_function find_flag) override; + + int index_next(uchar *record) override { + return (Partition_helper::ph_index_next(record)); + } + + int index_next_same(uchar *record, const uchar *, uint keylen) override { + return (Partition_helper::ph_index_next_same(record, keylen)); + } + + int index_prev(uchar *record) override { + return (Partition_helper::ph_index_prev(record)); + } + + int index_first(uchar *record) override { + return (Partition_helper::ph_index_first(record)); + } + + int index_last(uchar *record) override { + return (Partition_helper::ph_index_last(record)); + } + + int index_read_last_map(uchar *record, const uchar *key, + key_part_map keypart_map) override { + return (Partition_helper::ph_index_read_last_map(record, key, keypart_map)); + } + + int index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map, + enum ha_rkey_function find_flag) override { + return (Partition_helper::ph_index_read_map(buf, key, keypart_map, find_flag)); + } + + int index_read_idx_map(uchar *buf, uint index, const uchar *key, + key_part_map keypart_map, + enum ha_rkey_function find_flag) override { + return (Partition_helper::ph_index_read_idx_map(buf, index, key, keypart_map, find_flag)); + } + + /** @brief + Read first row between two ranges. + @retval + 0 Found row + @retval + HA_ERR_END_OF_FILE No rows in range + */ + int read_range_first(const key_range *start_key, const key_range *end_key, + bool eq_range_arg, bool sorted) override { + int result = Partition_helper::ph_read_range_first(start_key, end_key, eq_range_arg, sorted); + return (result == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_END_OF_FILE : result; + } + + int read_range_next() override { + return (Partition_helper::ph_read_range_next()); + } + + ulonglong table_flags() const override { + return (ha_tse::table_flags() | HA_CAN_REPAIR); + } + + THD *get_thd() const override { return ha_thd(); } + + TABLE *get_table() const override { return table; } + + bool get_eq_range() const override { return eq_range; } + + void set_eq_range(bool eq_range_arg) override { eq_range = eq_range_arg; } + + void set_range_key_part(KEY_PART_INFO *key_part) override { + range_key_part = key_part; + } + + int initialize_auto_increment(bool no_lock MY_ATTRIBUTE((unused))) override { return 0; } + + void get_dynamic_partition_info(ha_statistics *stat_info, + ha_checksum *check_sum, + uint part_id) override { + Partition_helper::get_dynamic_partition_info_low(stat_info, check_sum, + part_id); + } + + void set_part_info(partition_info *part_info, bool early) override { + Partition_helper::set_part_info_low(part_info, early); + } + + void get_auto_increment(ulonglong offset, ulonglong increment, + ulonglong nb_desired_values, ulonglong *first_value, + ulonglong *nb_reserved_values) override; + + void print_error(int error, myf errflag) override; + + /* function used for notifying SE to collect cbo stats */ + int analyze(THD *thd, HA_CHECK_OPT *check_opt) override; + + int optimize(THD *thd, HA_CHECK_OPT *check_opt) override; + + /* Get partition row type + @param[in] partition_table partition table + @param[in] part_id Id of partition for which row type to be retrieved + @return Partition row type. */ + enum row_type get_partition_row_type(const dd::Table *partition_table, + uint part_id) override; + + Partition_handler *get_partition_handler() override { + return (static_cast(this)); + } + + uint alter_flags(uint flags MY_ATTRIBUTE((unused))) const override { + return (HA_PARTITION_FUNCTION_SUPPORTED | HA_INPLACE_CHANGE_PARTITION); + } + + bool need_prune_partitions_by_engine(const key_range *start_key, const key_range *end_key); + + bool equal_range_on_part_field(const key_range *start_key, const key_range *end_key); + + void info_low() override; + + ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) override; + + int records(ha_rows *num_rows) override; + + int initialize_cbo_stats() override; + + void free_cbo_stats() override; + + int get_cbo_stats_4share() override; + + uint32 calculate_key_hash_value(Field **field_array) override; + + protected: + bool pruned_by_engine; + + part_id_range part_spec; + + uint64 cursors[PART_CURSOR_NUM]; + + //BITMAP cursor_set; + int cursor_set[PART_CURSOR_NUM / 8] = {0}; + + // store partitions for bulk insert + ctc_part_t *m_bulk_insert_parts; + + /** Pointer to Tsepart_share on the TABLE_SHARE. */ + Tsepart_share *m_part_share; + bool autoinc_has_expl_non_null_value = false; + bool autoinc_has_expl_non_null_value_update_row = false; + + private: + int bulk_insert_low(dml_flag_t flag, uint *dup_offset) override; +}; + +static inline void cursor_set_bit(int *cursor_set, uint bit) { + (cursor_set)[bit / 8] |= (1 << (bit & 7)); +} + +static inline bool cursor_is_set(int *cursor_set, uint bit) { + return (cursor_set)[bit / 8] & (1 << (bit & 7)); +} + +static inline void cursor_clear_bit(int *cursor_set, uint bit) { + (cursor_set)[bit / 8] &= ~(1 << (bit & 7)); +} + +#endif /* ha_tsepart_h */ diff --git a/storage/tianchi/message_queue/dsw_list.h b/storage/tianchi/message_queue/dsw_list.h new file mode 100644 index 0000000..1f3f7dc --- /dev/null +++ b/storage/tianchi/message_queue/dsw_list.h @@ -0,0 +1,484 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __dsw_list_pub_h__ +#define __dsw_list_pub_h__ + +#include +#include "dsw_typedef.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +#ifdef _PCLINT_ +typedef struct list_head list_head_t; +#else +typedef struct list_head { + struct list_head *prev; + struct list_head *next; +} list_head_t; +#endif + +static inline void list_init_head(list_head_t *head) +{ + head->next = head; + head->prev = head; +} + +static inline void __list_add(list_head_t *new_node, list_head_t *prev_node, list_head_t *next_node) +{ + new_node->prev = prev_node; + new_node->next = next_node; + prev_node->next = new_node; + next_node->prev = new_node; +} + +static inline void __list_del(list_head_t *prev, list_head_t *next) +{ + prev->next = next; + next->prev = prev; +} + +static inline void list_add_tail(list_head_t *new_node, list_head_t *head) +{ + __list_add(new_node, head->prev, head); +} + +static inline void list_add_first(list_head_t *new_node, list_head_t *head) +{ + __list_add(new_node, head, head->next); +} + +static inline void list_insert_node(list_head_t *new_node, list_head_t *prev_node, list_head_t *next_node) +{ + __list_add(new_node, prev_node, next_node); +} + +static inline void list_del_node(list_head_t *node) +{ + __list_del(node->prev, node->next); + list_init_head(node); +} + +/* + * @return the first node, which has been deleted; + * @if return is NULL, the queue is empty + */ +static inline list_head_t *list_del_first_node(list_head_t *head) +{ + list_head_t *ret; + + ret = head->next; + if (ret == head) { + /* the list is free */ + return NULL; + } else { + list_del_node(ret); + } + + return ret; +} + +static inline list_head_t *list_get_first_node(list_head_t *head) +{ + list_head_t *ret; + + ret = head->next; + if (ret == head) { + /* the list is free */ + return NULL; + } + + return head->next; +} + +static inline list_head_t *list_get_tail_node(list_head_t *head) +{ + list_head_t *ret; + + ret = head->prev; + if (ret == head) { + /* the list is free */ + return NULL; + } + + return head->prev; +} + +/* + * @return the last node, which has been deleted; + * @if return is NULL, the queue is empty + */ +static inline list_head_t *list_del_tail_node(list_head_t *head) +{ + list_head_t *ret; + + ret = head->prev; + if (ret == head) { + /* the list is free */ + return NULL; + } else { + list_del_node(ret); + } + + return ret; +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(list_head_t *old_node, list_head_t *new_node) +{ + new_node->next = old_node->next; + new_node->next->prev = new_node; + new_node->prev = old_node->prev; + new_node->prev->next = new_node; + list_init_head(old_node); +} + +/* + * Description: to check whether the node is in queue. + * return: @1 ture; @ 2 false. + */ +static inline dsw_int list_check_in_queue(list_head_t *node) +{ + if ((node->next == node) && (node->prev == node)) { + return 0; + } + + return 1; +} + +static inline dsw_int list_check_null(list_head_t *node) +{ + if ((node->next != NULL) && (node->prev != NULL)) { + return 0; + } + + return 1; +} + +/* + * Description: to check whether the queue is empty. + * return: @1 ture; @ 2 false. + */ +static inline dsw_int list_is_empty(list_head_t *head) +{ + if ((head->next == head) && (head->prev == head)) { + return 1; + } + + return 0; +} + +/* + * Description: Add second_list to the tail of first_list, and empty the second list + * return: @1 ture; @ 2 false. + */ +static inline void list_merge(list_head_t *first_list, list_head_t *second_list) +{ + if (list_is_empty(second_list)) { + return; + } + + if (list_is_empty(first_list)) { + list_replace(second_list, first_list); + return; + } + + list_head_t *first_list_end = first_list->prev; + list_head_t *second_list_begin = second_list->next; + list_head_t *second_list_end = second_list->prev; + + first_list_end->next = second_list_begin; + second_list_begin->prev = first_list_end; + second_list_end->next = first_list; + first_list->prev = second_list_end; + + list_init_head(second_list); +} + +/* + * Description: to check whether this node is the tail of queue. + * return: @1 ture; @ 2 false. + */ +static inline dsw_int list_node_is_tail(list_head_t *node, list_head_t *head) +{ + if (node == head->prev) { + return 1; + } + + return 0; +} + +/* + * Description: to check whether this node is the first of queue. + * return: @1 ture; @ 2 false. + */ +static inline dsw_int list_node_is_first(list_head_t *node, list_head_t *head) +{ + if (node == head->next) { + return 1; + } + + return 0; +} + +/** + * __list_for_each iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + * + */ +#define list_for_each(node, head) for (node = (head)->next; node != (head); node = node->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next) + +#ifndef container_of + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr:the pointer to the member. + * @type:the type of the container struct this is embedded in. + * @member:the name of the member within the struct. + * + */ + +/*lint --emacro((160), container_of) --emacro((42), container_of) --emacro((413), container_of) --emacro((545), container_of)*/ +#define container_of(ptr, type, member) \ + ({ \ + const DSW_TYPEOF(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - ((unsigned long)&((type *)0)->member)); \ + }) + +#endif + +/** + * list_entry - get the struct for this entry + * @ptr:the &struct list_head pointer. + * @type:the type of the struct this is embedded in. + * @member:the name of the list_struct within the struct. + */ + +#define list_entry(ptr, type, member) container_of(ptr, type, member) + + +#define list_get_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) + + +static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + first->prev = prev; + prev->next = first; + last->next = next; + next->prev = last; +} + + +static inline void list_del_set_null(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = entry->prev = NULL; +} + +static inline void list_splice_tail_init(struct list_head *list, struct list_head *head) +{ + if (!list_is_empty(list)) { + __list_splice(list, head->prev, head); + list_init_head(list); + } +} + + +/* + * Description: get list size. + * return: @1 ture; @ 2 false. + */ +static inline dsw_int list_size(list_head_t *head) +{ + int size = 0; + list_head_t *node = NULL; + + list_for_each(node, head) + { + size++; + } + + return size; +} + +static inline void list_splice_head_init(struct list_head *list, struct list_head *head) +{ + if (!list_is_empty(list)) { + __list_splice(list, head, head->next); + list_init_head(list); + } +} + +/* ************ List BEGIN ************ */ +typedef struct dsw_list_s { + list_head_t list_head; + dsw_int node_num; +} dsw_list_t; + +typedef struct dsw_lock_list_s { + list_head_t list_head; + dsw_int node_num; + pthread_mutex_t mutex; +} dsw_lock_list_t; + +static inline void dsw_list_init(dsw_list_t *list) +{ + list_init_head(&(list->list_head)); + list->node_num = 0; +} + +static inline void dsw_lock_list_init(dsw_lock_list_t *lock_list) +{ + DSW_THREAD_MUTEX_INIT(&(lock_list->mutex), NULL); + list_init_head(&(lock_list->list_head)); + lock_list->node_num = 0; +} + +static inline void dsw_list_add_tail(list_head_t *node, dsw_list_t *list) +{ + list_add_tail(node, &(list->list_head)); + list->node_num += 1; +} + +static inline void dsw_list_add_first(list_head_t *node, dsw_list_t *list) +{ + list_add_first(node, &(list->list_head)); + list->node_num += 1; +} + +static inline void dsw_lock_list_add_first(list_head_t *node, dsw_lock_list_t *lock_list) +{ + DSW_THREAD_MUTEX_LOCK(&(lock_list->mutex)); + list_add_first(node, &(lock_list->list_head)); + lock_list->node_num += 1; + DSW_THREAD_MUTEX_UNLOCK(&(lock_list->mutex)); +} + +static inline void dsw_lock_list_add_tail(list_head_t *node, dsw_lock_list_t *lock_list) +{ + DSW_THREAD_MUTEX_LOCK(&(lock_list->mutex)); + list_add_tail(node, &(lock_list->list_head)); + lock_list->node_num += 1; + DSW_THREAD_MUTEX_UNLOCK(&(lock_list->mutex)); +} + +static inline void dsw_list_del_node(list_head_t *node, dsw_list_t *list) +{ + DSW_ASSERT_INNER(list->node_num > 0); + list_del_node(node); + list->node_num -= 1; +} + +static inline void dsw_lock_list_del_node(list_head_t *node, dsw_lock_list_t *lock_list) +{ + DSW_THREAD_MUTEX_LOCK(&(lock_list->mutex)); + DSW_ASSERT_INNER(lock_list->node_num > 0); + list_del_node(node); + lock_list->node_num -= 1; + DSW_THREAD_MUTEX_UNLOCK(&(lock_list->mutex)); +} + +static inline list_head_t *dsw_list_del_first_node(dsw_list_t *list) +{ + list_head_t *node = list_del_first_node(&(list->list_head)); + if (NULL != node) { + DSW_ASSERT(list->node_num > 0); + list->node_num -= 1; + return node; + } else { + DSW_ASSERT(0 == list->node_num); + return NULL; + } +} + +static inline list_head_t *dsw_list_get_first_node(dsw_list_t *list) +{ + list_head_t *node = list_get_first_node(&(list->list_head)); + if (NULL != node) { + return node; + } else { + DSW_ASSERT(0 == list->node_num); + return NULL; + } +} + +static inline list_head_t *dsw_list_del_tail_node(dsw_list_t *list) +{ + list_head_t *node = list_del_tail_node(&(list->list_head)); + if (NULL != node) { + DSW_ASSERT(list->node_num > 0); + list->node_num -= 1; + return node; + } else { + DSW_ASSERT(0 == list->node_num); + return NULL; + } +} + +static inline list_head_t *dsw_lock_list_del_first_node(dsw_lock_list_t *lock_list) +{ + DSW_THREAD_MUTEX_LOCK(&(lock_list->mutex)); + list_head_t *node = list_del_first_node(&(lock_list->list_head)); + if (NULL != node) { + DSW_ASSERT(lock_list->node_num > 0); + lock_list->node_num -= 1; + } + + DSW_THREAD_MUTEX_UNLOCK(&(lock_list->mutex)); + return node; +} + +static inline void dsw_list_merge(dsw_list_t *old_list, dsw_list_t *new_list) +{ + list_head_t *iter_node = dsw_list_del_first_node(old_list); + while (iter_node) { + dsw_list_add_tail(iter_node, new_list); + iter_node = dsw_list_del_first_node(old_list); + } +} + +// жnodeǷ +static inline dsw_bool is_node_isolated(list_head_t *node) +{ + return ((node->next == node->prev) && (node->next == node)); +} + +/* ************ List End ************ */ + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ +#endif // __dsw_list_pub_h__ + \ No newline at end of file diff --git a/storage/tianchi/message_queue/dsw_message.h b/storage/tianchi/message_queue/dsw_message.h new file mode 100644 index 0000000..636ea1f --- /dev/null +++ b/storage/tianchi/message_queue/dsw_message.h @@ -0,0 +1,131 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __dsw_message_pub_h__ +#define __dsw_message_pub_h__ + +#include +#include "dsw_typedef.h" +#include "dsw_list.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +#pragma pack(1) + + +#define SERVER_PROC_ID 0 +#define SERVER_REGISTER_PROC_ID 1 +#define CLIENT_PROC_ID 1 + + +typedef struct { + dsw_u32 type; /* Data type */ + dsw_u32 length; +} dsw_message_segment_desc_t; + +#define DSW_MESSAGE_SEGMENT_NUM_MAX (512) // TODO: too long, rename + + +typedef struct token_latency_timestamp_s { + dsw_u16 start_time; + dsw_u16 latency; +} token_latency_timestamp_t; + +/* reserved for updating + * 1. detect msg use 6 bytes for apm lids + * 2. unhealthy used the first 5 bytes, and negotiation used 6th byte + * 3. ǰ#pragma pack(1)֤ڴһֽڶ + */ +typedef union message_head_reserved_s { + dsw_u8 reserved[12]; + + /* clientģ: + * update map when IOView is changed. + * delete_all_osd_in_pool 1:ɾosd0:ɾָosd + */ + struct update_map_in_del_pool_s { + dsw_u32 osd_id; + dsw_u8 delete_all_osd_in_pool; + } update_map_in_del_pool; + + dsw_u16 pool_id; // client ģ + dsw_u8 io_type; // vbp/kvs-clientжǷ˫IO + + struct token_latency_s { + dsw_u8 padding[6]; // padding for unhealthy_and_negoation + token_latency_timestamp_t token_latency_timestamp; // rsmʹ + } token_latency; +} message_head_reserved_t; + +/** + * @ingroup Message + * messageʱ׶ε㣺н׶ε㡣 + */ +typedef struct { + sem_t sem; + dsw_u32 magic; + dsw_u32 version; + dsw_u64 request_id; /* Request ID */ + dsw_u32 src_nid; /* Source node ID */ + dsw_u32 dst_nid; /* Destination node ID */ + dsw_u8 net_point; /* Type of net point */ + dsw_u8 src_mid; + dsw_u8 dst_mid; + dsw_u32 cmd_type; /* Command type */ + dsw_u16 slice_id; /* Message slice ID */ + dsw_u16 priority; /* Message priority */ + dsw_u16 handle_id; /* IO trace handle ID */ + dsw_u16 seg_num; + dsw_message_segment_desc_t seg_desc[DSW_MESSAGE_SEGMENT_NUM_MAX]; + dsw_u32 crc; /* crc of the msg */ + dsw_u64 try_id; /* try id */ + + /* reserved for updating + * 1. detect msg use 6 bytes for apm lids + * 2. unhealthy used the first 5 bytes, and negotiation used 6th byte + */ + message_head_reserved_t reserved_u; + dsw_u32 head_crc; /* crc of msg head */ +} dsw_message_head_t; + +/* + * Definition of message block + * + * A whole message block mainly cotains a message head and at most four message data. Meanwhile, the node which creates + * the message block should record time stamp for the node (Notice: the time stamp is a 64 bits value generated by local + * tick generator, and is only valid locally) The Time stamp will been initialized to be DSW_MESSAGE_TS_NORMAL as + * default. If DSW_MESSAGE_TS_DROPED, the message will been discarded directly by net module. + */ +typedef struct { + dsw_message_head_t head; + void *seg_buf[DSW_MESSAGE_SEGMENT_NUM_MAX]; + dsw_u64 ts; /* Time stamp */ + dsw_u32 seg_buf_crc; + list_head_t msg_node; +} dsw_message_block_t; + +#ifdef __arm__ +#pragma pack(0) +#else +#pragma pack() +#endif + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ +#endif // __dsw_message_pub_h__ diff --git a/storage/tianchi/message_queue/dsw_shm.h b/storage/tianchi/message_queue/dsw_shm.h new file mode 100644 index 0000000..33ea257 --- /dev/null +++ b/storage/tianchi/message_queue/dsw_shm.h @@ -0,0 +1,289 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __dsw_shm_pub_h__ +#define __dsw_shm_pub_h__ + +#include +#include +#include +#include +#include + +#include "dsw_message.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +#define SHM_KEY_NULL 0 +#define SHM_KEY_SYSV 1 +#define SHM_KEY_MMAP 2 +#define SHM_KEY_UNSOCK 3 /* unix socket */ +#define SHM_KEY_VSOCK 4 +#define SHM_KEY_IV 5 +#define SHM_KEY_MAX 3 + +#define MQ_SHM_MMAP_NAME_PREFIX "cantian" +#define MQ_SHM_MMAP_DIR "/dev/shm" + +typedef enum shm_message_priority_e { + SHM_PRIORITY_NORMAL = 0, + SHM_PRIORITY_HIGH +} shm_message_priority_t; + +typedef enum shm_log_level_e { + SHM_LOG_LEVEL_INFO, + SHM_LOG_LEVEL_ERROR +} shm_log_level_t; + +typedef struct shm_key_s { + int type; + union { + struct { + key_t sysv_key; + }; + struct { + char shm_name[NAME_MAX]; + char mmap_name[NAME_MAX]; + int seg_id; + }; + struct { + char unix_name[NAME_MAX]; + }; + struct { + char vsock_port; + char vsock_cid; + }; + struct { + char dev_name[NAME_MAX]; + char sock_path[NAME_MAX]; + }; + }; +} shm_key_t; + +#define MAX_SHM_PROC 20 /* The maximum number of business processes in an instance */ +#define MYSQL_PROC_START 2 +#define MAX_MEM_CLASS 32 /* the capacity of mem_class [] */ +#define SHM_MAX_LEN (4096L * 1024L * 1024L) /* The maximum size of a shared memory */ +#define SHM_ADDR 0x300000000000UL /* Shared memory area starting address */ +#define MAX_SHM_SEG_NUM 128 /* The number of instances of shared memory support */ +#define SHM_MAX_LOG_LENTH 1024 /* The maximum length of the shared memory log string */ + + +/* **************************************************************************** + variable name : shm_mem_class. + Functional description : The entry of memory object configration + + Precautions �� The structure is only initialized in the master, and the + message size of all communication units must strictly + respect the format of the message structure. +**************************************************************************** */ +typedef struct shm_mem_class { + int size; /* The size of a message */ + int num; /* The number of corresponding size data in the storage unit */ +} shm_mem_class_t; + +/* **************************************************************************** + variable name : shm_seg_s + Functional description : Shared memory instance tag, used to mark an instance + of multiple instances need to initialize the structure + of the variable + Precautions �� The structure variable can not access its members at + the use level and must be freed after its use. +**************************************************************************** */ +struct shm_seg_s; + +/* **************************************************************************** + function name : shm_init + Functional description : Initialize the shared memory area corresponding to + the instance and obtain the right to initialize the + memory segment + Input paraments : shm_key_t shm_key: Shared memory application label (one + segment corresponds to a label). + Output paraments : Null + Return value : struct shm_seg_s *seg : Shared memory segment label; + Precautions : The initialization process must be executed after the + master initialization process, otherwise it fails. +**************************************************************************** */ +struct shm_seg_s *shm_init(shm_key_t *shm_key, int is_server); + +/* **************************************************************************** + function name : shm_get_all_keys + Functional description : get all segments + Input paraments : + pos -- the first key which return in the list, when + the returned the 'pos' will be updated to the new + next position + + key_list -- an array use to contain the keys which + returned + + nr_key_list -- number of rooms of the key_list + + Output paraments : the 'pos' will be updated to the new value + + Return value : + >0 -- the number of valid keys that returned + ==0 -- there is not more keys can be returned from + the position 'pos' + <0 -- there must be an error happend +**************************************************************************** */ +int shm_get_all_keys(int *pos, struct shm_key_s key_list[], int nr_key_list); + +/* **************************************************************************** + function name : is_shm + Functional description : To determine whether a piece of memory is shared memory area + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + void *addr : Shared memory measured address. + Output paraments : Null + Return value : int: Returns 1 in shared memory; otherwise returns 0. +*************************************************************************** */ +int is_shm(struct shm_seg_s *seg, void *addr); + +/* **************************************************************************** + function name : shm_alloc + Functional description : Apply for a piece of memory in the shared memory area + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + size_t size : The requested memory block size. + Return value : void *: Return the pointer of the requested memory block. + +**************************************************************************** */ +void *shm_alloc(struct shm_seg_s *seg, size_t size); + +/* **************************************************************************** + function name : shm_free + Functional description : Release shared memory + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + void *ptr : Release shared memory + Return value : Null + Precautions : If the specified shared memory reference count is greater + than 1, using this function will only subtract 1 from the + reference count of that memory block, and will not actually + free this memory. +**************************************************************************** */ +void shm_free(struct shm_seg_s *seg, void *ptr); + +/* **************************************************************************** + function name : shm_proc_start + Functional description : Initialize and start listening thread (start listening) + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + int proc_id : Business module process id. + int thread_num : Receive queue thread number. + int (*recv_msg)(struct shm_seg_s *, dsw_message_block_t *) : Receive callback function. + Output paraments : Null + Return value : int : Return 0 success; otherwise fail. +**************************************************************************** */ +int shm_proc_start(struct shm_seg_s *seg, int proc_id, int thread_num, cpu_set_t *mask, int is_dynamic, + int (*recv_msg)(struct shm_seg_s *, dsw_message_block_t *)); + +/* **************************************************************************** + function name : shm_proc_alive + Functional description : Check the corresponding proc_id process is still working. + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + int proc_id : Business module process id. + Return value : Null +**************************************************************************** */ +int shm_proc_alive(struct shm_seg_s *seg, int proc_id); + +/* **************************************************************************** + function name : shm_send_msg + Functional description : send massages + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + int proc_id :Business module process id. + dsw_message_block_t *msg : Message structure compatible + with the dsware framework. + Return value : int : Return 0 success; otherwise fail. +**************************************************************************** */ +int shm_send_msg(struct shm_seg_s *seg, int proc_id, dsw_message_block_t *msg); + +/* **************************************************************************** + function name : shm_seg_stop + Functional description : stop job thread on this segment. + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + Return value : Null +**************************************************************************** */ +void shm_seg_stop(struct shm_seg_s *seg); + +/* **************************************************************************** + function name : shm_seg_exit + Functional description : Structure memory to release segment tags. + Input paraments : struct shm_seg_s *seg : Shared memory segment label; + Return value : Null +**************************************************************************** */ +void shm_seg_exit(struct shm_seg_s *seg); + +/* **************************************************************************** + function name : shm_master_init + Functional description : Initialize the master process. + Input paraments : shm_key_t shm_key: Shared memory application label + (one instance corresponds to a label). + shm_mem_class_t mem_class[]: Memory application form. + int nr_mem_class: Memory application form size. + Return value : struct shm_seg_s *seg : Shared memory segment label; + Precautions : The process of initialization must define the message + format of shared memory, and run in the context or process + of non-IO process. +**************************************************************************** */ +struct shm_seg_s *shm_master_init(shm_key_t *shm_key, shm_mem_class_t mem_class[], int nr_mem_class); + +/* **************************************************************************** + function name : shm_master_exit + Functional description : remove a segment from master + Input paraments : seg -- pointer of the segment + Return value : 0 -- success, -1 -- failed + Precautions : must call shm_seg_exit before call this function +**************************************************************************** */ +int shm_master_exit(struct shm_seg_s *seg); + +/* **************************************************************************** + function name : shm_set_info_log_writer/shm_set_error_log_writer + Functional description : Register the callback function that outputs log information + Input paraments : void (*writer)(char *, int)) : Callback function to output log information + (Callback function parameters include information content string and string length) + Return value : Null +**************************************************************************** */ +void shm_set_info_log_writer(void (*writer)(char *, int)); +void shm_set_error_log_writer(void (*writer)(char *, int)); + +/* **************************************************************************** + function name : shm_write_log_info/shm_write_log_error + Functional description : log print function + Input paraments : char *log_text The contents of the string log. + int length : String length + Return value : Null + Precautions : This function is for JNI only. +**************************************************************************** */ +void shm_write_log_info(char *log_text, int length); +void shm_write_log_error(char *log_text, int length); + +void shm_assign_proc_id(struct shm_seg_s *seg, int proc_id); + +void shm_set_thread_cool_time(uint32_t time_us); + +void shm_set_proc_connected_callback(int (*func)(int)); + +int shm_client_connect(shm_key_t *shm_key, int *client_id); +void shm_client_disconnect(); + +int shm_tpool_init(int thd_num); +void shm_tpool_destroy(); + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ +#endif // __dsw_shm_pub_h__ diff --git a/storage/tianchi/message_queue/dsw_typedef.h b/storage/tianchi/message_queue/dsw_typedef.h new file mode 100644 index 0000000..61a924d --- /dev/null +++ b/storage/tianchi/message_queue/dsw_typedef.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __dsw_typedef_pub_h__ +#define __dsw_typedef_pub_h__ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +typedef int dsw_int; +typedef int dsw_bool; +typedef long dsw_long; + +typedef int8_t dsw_s8; +typedef uint8_t dsw_u8; +typedef int16_t dsw_s16; +typedef uint16_t dsw_u16; +typedef int32_t dsw_s32; +typedef uint32_t dsw_u32; +typedef int64_t dsw_s64; +typedef uint64_t dsw_u64; + + +#define PACKFLAG __attribute__((__packed__)) + + +#define DSW_TYPEOF(x) typeof((x)) + + +extern void __dsw_assert(dsw_u64 exp); +extern void __dsw_assert_inner(dsw_u64 exp); +/*lint --emacro(506, DSW_ASSERT) --emacro(571, DSW_ASSERT)*/ +#define DSW_ASSERT(x) \ + { \ + __dsw_assert((dsw_u64)(x)); \ + } +/*lint --emacro(506, DSW_ASSERT_INNER) --emacro(571, DSW_ASSERT_INNER)*/ +#define DSW_ASSERT_INNER(x) \ + { \ + __dsw_assert_inner((dsw_u64)(x)); \ + } + + +#define DSW_THREAD_MUTEX_INIT(mutex, attr) \ + do { \ + int inner_retval = pthread_mutex_init((mutex), (attr)); \ + if ((0 != inner_retval) && (EBUSY != inner_retval)) { \ + DSW_ASSERT_INNER(0); \ + } \ + } while (0) + +#define DSW_THREAD_MUTEX_LOCK(mutex) \ + do { \ + int inner_retval = pthread_mutex_lock((mutex)); \ + if ((0 != inner_retval) && (EDEADLK != inner_retval)) { \ + DSW_ASSERT_INNER(0); \ + } \ + } while (0) + +#define DSW_THREAD_MUTEX_UNLOCK(mutex) \ + do { \ + int inner_retval = pthread_mutex_unlock((mutex)); \ + if ((0 != inner_retval) && (EPERM != inner_retval)) { \ + DSW_ASSERT_INNER(0); \ + } \ + } while (0) + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ + +#endif // __dsw_typedef_pub_h__ diff --git a/storage/tianchi/mysql_daac_plugin.cc b/storage/tianchi/mysql_daac_plugin.cc new file mode 100644 index 0000000..91c6b10 --- /dev/null +++ b/storage/tianchi/mysql_daac_plugin.cc @@ -0,0 +1,152 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "m_string.h" // strlen +#include "my_dbug.h" +#include "my_dir.h" +#include "my_inttypes.h" +#include "my_io.h" +#include "my_psi_config.h" +#include "my_sys.h" // my_write, my_malloc +#include "my_thread.h" +#include "mysql/psi/mysql_memory.h" +#include "sql/sql_plugin.h" // st_plugin_int +#include "sql/sql_initialize.h" // opt_initialize_insecure +#include "tse_log.h" + +struct mysql_daac_context { + my_thread_handle daac_startup_thread; +}; + +extern "C" { +const char *cantiand_get_dbversion() +{ + return "NONE"; +} +} + +extern "C" int cantiand_lib_main(int argc, char *argv[]); +extern "C" void ct_singlep_shutdown(); + +static std::string get_cantiand_mode() { + std::string mode = "nomount"; + char *tmp_mode = getenv("CANTIAND_MODE"); + if (tmp_mode != NULL && strlen(tmp_mode) > 0) { + mode = tmp_mode; + } + return mode; +} + +static std::string get_cantiand_home_dir() { + std::string home_dir = "/home/regress/data"; + char *tmp_home_dir = getenv("CANTIAND_HOME_DIR"); + if (tmp_home_dir != NULL && strlen(tmp_home_dir) > 0) { + home_dir = tmp_home_dir; + } + return home_dir; +} + +static void *mysql_daac_startup_thread(void *p) { + DBUG_TRACE; + struct mysql_daac_context *con = (struct mysql_daac_context *)p; + if(con->daac_startup_thread.thread == 0) { + tse_log_error("please create the nomont thread first!"); + return nullptr; + } + + std::string mode = get_cantiand_mode(); + std::string home_dir = get_cantiand_home_dir(); + int ret; + if (mode != "open") { + char const *argv[] = {"/home/regress/install/bin/cantiand", mode.c_str(), + "-D", home_dir.c_str()}; + ret = cantiand_lib_main(4, const_cast(argv)); + } else { + char const *argv[] = {"/home/regress/install/bin/cantiand", "-D", + home_dir.c_str()}; + ret = cantiand_lib_main(3, const_cast(argv)); + } + tse_log_system("init daac mode:%s,home_dir:%s, ret:%d", mode.c_str(), + home_dir.c_str(), ret); + return nullptr; +} + +struct mysql_daac_context *daac_context = NULL; +int daemon_daac_plugin_init() { + DBUG_TRACE; + if (opt_initialize_insecure) { + tse_log_debug("initialize-insecure mode no need start the daac startup thread."); + return 0; + } + + const char *se_name = "ctc_ddl_rewriter"; + const LEX_CSTRING name = {se_name, strlen(se_name)}; + if (!plugin_is_ready(name, MYSQL_AUDIT_PLUGIN)) { + tse_log_error("tse_ddl_rewriter plugin install failed."); + return -1; + } + + if (daac_context != NULL) { + tse_log_error("daemon_daac_plugin_init daac_context:%p not NULL", daac_context); + return 0; + } + + daac_context = (struct mysql_daac_context *)my_malloc( + PSI_NOT_INSTRUMENTED, + sizeof(struct mysql_daac_context), MYF(0)); + + my_thread_attr_t startup_attr; /* Thread attributes */ + my_thread_attr_init(&startup_attr); + my_thread_attr_setdetachstate(&startup_attr, MY_THREAD_CREATE_JOINABLE); + /* now create the startup thread */ + if (my_thread_create(&daac_context->daac_startup_thread, &startup_attr, mysql_daac_startup_thread, + (void *)daac_context) != 0) { + tse_log_error("Could not create daac startup thread!"); + return -1; + } + return 0; +} + +int daemon_daac_plugin_deinit() { + DBUG_TRACE; + void *dummy_retval; + + if (daac_context == nullptr || daac_context->daac_startup_thread.thread == 0) { + tse_log_system("startup thread not started"); + return 0; + } + + ct_singlep_shutdown(); + my_thread_join(&daac_context->daac_startup_thread, &dummy_retval); + my_free(daac_context); + daac_context = NULL; + return 0; +} + +int (*tse_init)() = daemon_daac_plugin_init; +int (*tse_deinit)() = daemon_daac_plugin_deinit; diff --git a/storage/tianchi/protobuf/tc_db.pb-c.c b/storage/tianchi/protobuf/tc_db.pb-c.c new file mode 100644 index 0000000..a900d25 --- /dev/null +++ b/storage/tianchi/protobuf/tc_db.pb-c.c @@ -0,0 +1,3998 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: tc_db.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "tc_db.pb-c.h" +void tc_db__tse_ddlcolumn_data_type_def__init + (TcDb__TseDDLColumnDataTypeDef *message) +{ + static const TcDb__TseDDLColumnDataTypeDef init_value = TC_DB__TSE_DDLCOLUMN_DATA_TYPE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlcolumn_data_type_def__get_packed_size + (const TcDb__TseDDLColumnDataTypeDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_data_type_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlcolumn_data_type_def__pack + (const TcDb__TseDDLColumnDataTypeDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_data_type_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlcolumn_data_type_def__pack_to_buffer + (const TcDb__TseDDLColumnDataTypeDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_data_type_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLColumnDataTypeDef * + tc_db__tse_ddlcolumn_data_type_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLColumnDataTypeDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlcolumn_data_type_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlcolumn_data_type_def__free_unpacked + (TcDb__TseDDLColumnDataTypeDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_data_type_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlcolumn_def__init + (TcDb__TseDDLColumnDef *message) +{ + static const TcDb__TseDDLColumnDef init_value = TC_DB__TSE_DDLCOLUMN_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlcolumn_def__get_packed_size + (const TcDb__TseDDLColumnDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlcolumn_def__pack + (const TcDb__TseDDLColumnDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlcolumn_def__pack_to_buffer + (const TcDb__TseDDLColumnDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLColumnDef * + tc_db__tse_ddlcolumn_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLColumnDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlcolumn_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlcolumn_def__free_unpacked + (TcDb__TseDDLColumnDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlcolumn_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlforeign_key_element_def__init + (TcDb__TseDDLForeignKeyElementDef *message) +{ + static const TcDb__TseDDLForeignKeyElementDef init_value = TC_DB__TSE_DDLFOREIGN_KEY_ELEMENT_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlforeign_key_element_def__get_packed_size + (const TcDb__TseDDLForeignKeyElementDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_element_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlforeign_key_element_def__pack + (const TcDb__TseDDLForeignKeyElementDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_element_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlforeign_key_element_def__pack_to_buffer + (const TcDb__TseDDLForeignKeyElementDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_element_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLForeignKeyElementDef * + tc_db__tse_ddlforeign_key_element_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLForeignKeyElementDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlforeign_key_element_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlforeign_key_element_def__free_unpacked + (TcDb__TseDDLForeignKeyElementDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_element_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlforeign_key_def__init + (TcDb__TseDDLForeignKeyDef *message) +{ + static const TcDb__TseDDLForeignKeyDef init_value = TC_DB__TSE_DDLFOREIGN_KEY_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlforeign_key_def__get_packed_size + (const TcDb__TseDDLForeignKeyDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlforeign_key_def__pack + (const TcDb__TseDDLForeignKeyDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlforeign_key_def__pack_to_buffer + (const TcDb__TseDDLForeignKeyDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLForeignKeyDef * + tc_db__tse_ddlforeign_key_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLForeignKeyDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlforeign_key_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlforeign_key_def__free_unpacked + (TcDb__TseDDLForeignKeyDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlforeign_key_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddltable_key_part__init + (TcDb__TseDDLTableKeyPart *message) +{ + static const TcDb__TseDDLTableKeyPart init_value = TC_DB__TSE_DDLTABLE_KEY_PART__INIT; + *message = init_value; +} +size_t tc_db__tse_ddltable_key_part__get_packed_size + (const TcDb__TseDDLTableKeyPart *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key_part__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddltable_key_part__pack + (const TcDb__TseDDLTableKeyPart *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key_part__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddltable_key_part__pack_to_buffer + (const TcDb__TseDDLTableKeyPart *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key_part__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLTableKeyPart * + tc_db__tse_ddltable_key_part__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLTableKeyPart *) + protobuf_c_message_unpack (&tc_db__tse_ddltable_key_part__descriptor, + allocator, len, data); +} +void tc_db__tse_ddltable_key_part__free_unpacked + (TcDb__TseDDLTableKeyPart *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddltable_key_part__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddltable_key__init + (TcDb__TseDDLTableKey *message) +{ + static const TcDb__TseDDLTableKey init_value = TC_DB__TSE_DDLTABLE_KEY__INIT; + *message = init_value; +} +size_t tc_db__tse_ddltable_key__get_packed_size + (const TcDb__TseDDLTableKey *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddltable_key__pack + (const TcDb__TseDDLTableKey *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddltable_key__pack_to_buffer + (const TcDb__TseDDLTableKey *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddltable_key__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLTableKey * + tc_db__tse_ddltable_key__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLTableKey *) + protobuf_c_message_unpack (&tc_db__tse_ddltable_key__descriptor, + allocator, len, data); +} +void tc_db__tse_ddltable_key__free_unpacked + (TcDb__TseDDLTableKey *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddltable_key__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_msg_comm_def__init + (TcDb__TseMsgCommDef *message) +{ + static const TcDb__TseMsgCommDef init_value = TC_DB__TSE_MSG_COMM_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_msg_comm_def__get_packed_size + (const TcDb__TseMsgCommDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_msg_comm_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_msg_comm_def__pack + (const TcDb__TseMsgCommDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_msg_comm_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_msg_comm_def__pack_to_buffer + (const TcDb__TseMsgCommDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_msg_comm_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseMsgCommDef * + tc_db__tse_msg_comm_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseMsgCommDef *) + protobuf_c_message_unpack (&tc_db__tse_msg_comm_def__descriptor, + allocator, len, data); +} +void tc_db__tse_msg_comm_def__free_unpacked + (TcDb__TseMsgCommDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_msg_comm_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlpartition_table_def__init + (TcDb__TseDDLPartitionTableDef *message) +{ + static const TcDb__TseDDLPartitionTableDef init_value = TC_DB__TSE_DDLPARTITION_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlpartition_table_def__get_packed_size + (const TcDb__TseDDLPartitionTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlpartition_table_def__pack + (const TcDb__TseDDLPartitionTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlpartition_table_def__pack_to_buffer + (const TcDb__TseDDLPartitionTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLPartitionTableDef * + tc_db__tse_ddlpartition_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLPartitionTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlpartition_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlpartition_table_def__free_unpacked + (TcDb__TseDDLPartitionTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlpartition_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlpartition_def__init + (TcDb__TseDDLPartitionDef *message) +{ + static const TcDb__TseDDLPartitionDef init_value = TC_DB__TSE_DDLPARTITION_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlpartition_def__get_packed_size + (const TcDb__TseDDLPartitionDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlpartition_def__pack + (const TcDb__TseDDLPartitionDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlpartition_def__pack_to_buffer + (const TcDb__TseDDLPartitionDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlpartition_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLPartitionDef * + tc_db__tse_ddlpartition_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLPartitionDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlpartition_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlpartition_def__free_unpacked + (TcDb__TseDDLPartitionDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlpartition_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlcreate_table_def__init + (TcDb__TseDDLCreateTableDef *message) +{ + static const TcDb__TseDDLCreateTableDef init_value = TC_DB__TSE_DDLCREATE_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlcreate_table_def__get_packed_size + (const TcDb__TseDDLCreateTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcreate_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlcreate_table_def__pack + (const TcDb__TseDDLCreateTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcreate_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlcreate_table_def__pack_to_buffer + (const TcDb__TseDDLCreateTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlcreate_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLCreateTableDef * + tc_db__tse_ddlcreate_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLCreateTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlcreate_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlcreate_table_def__free_unpacked + (TcDb__TseDDLCreateTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlcreate_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_table_porp__init + (TcDb__TseDDLAlterTablePorp *message) +{ + static const TcDb__TseDDLAlterTablePorp init_value = TC_DB__TSE_DDLALTER_TABLE_PORP__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_table_porp__get_packed_size + (const TcDb__TseDDLAlterTablePorp *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_porp__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_table_porp__pack + (const TcDb__TseDDLAlterTablePorp *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_porp__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_table_porp__pack_to_buffer + (const TcDb__TseDDLAlterTablePorp *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_porp__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterTablePorp * + tc_db__tse_ddlalter_table_porp__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterTablePorp *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_table_porp__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_table_porp__free_unpacked + (TcDb__TseDDLAlterTablePorp *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_porp__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_table_drop__init + (TcDb__TseDDLAlterTableDrop *message) +{ + static const TcDb__TseDDLAlterTableDrop init_value = TC_DB__TSE_DDLALTER_TABLE_DROP__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_table_drop__get_packed_size + (const TcDb__TseDDLAlterTableDrop *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_table_drop__pack + (const TcDb__TseDDLAlterTableDrop *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_table_drop__pack_to_buffer + (const TcDb__TseDDLAlterTableDrop *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterTableDrop * + tc_db__tse_ddlalter_table_drop__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterTableDrop *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_table_drop__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_table_drop__free_unpacked + (TcDb__TseDDLAlterTableDrop *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_table_drop_key__init + (TcDb__TseDDLAlterTableDropKey *message) +{ + static const TcDb__TseDDLAlterTableDropKey init_value = TC_DB__TSE_DDLALTER_TABLE_DROP_KEY__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_table_drop_key__get_packed_size + (const TcDb__TseDDLAlterTableDropKey *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop_key__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_table_drop_key__pack + (const TcDb__TseDDLAlterTableDropKey *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop_key__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_table_drop_key__pack_to_buffer + (const TcDb__TseDDLAlterTableDropKey *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop_key__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterTableDropKey * + tc_db__tse_ddlalter_table_drop_key__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterTableDropKey *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_table_drop_key__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_table_drop_key__free_unpacked + (TcDb__TseDDLAlterTableDropKey *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_drop_key__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_table_alter_column__init + (TcDb__TseDDLAlterTableAlterColumn *message) +{ + static const TcDb__TseDDLAlterTableAlterColumn init_value = TC_DB__TSE_DDLALTER_TABLE_ALTER_COLUMN__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_table_alter_column__get_packed_size + (const TcDb__TseDDLAlterTableAlterColumn *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_alter_column__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_table_alter_column__pack + (const TcDb__TseDDLAlterTableAlterColumn *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_alter_column__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_table_alter_column__pack_to_buffer + (const TcDb__TseDDLAlterTableAlterColumn *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_alter_column__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterTableAlterColumn * + tc_db__tse_ddlalter_table_alter_column__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterTableAlterColumn *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_table_alter_column__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_table_alter_column__free_unpacked + (TcDb__TseDDLAlterTableAlterColumn *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_alter_column__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_table_def__init + (TcDb__TseDDLAlterTableDef *message) +{ + static const TcDb__TseDDLAlterTableDef init_value = TC_DB__TSE_DDLALTER_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_table_def__get_packed_size + (const TcDb__TseDDLAlterTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_table_def__pack + (const TcDb__TseDDLAlterTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_table_def__pack_to_buffer + (const TcDb__TseDDLAlterTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterTableDef * + tc_db__tse_ddlalter_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_table_def__free_unpacked + (TcDb__TseDDLAlterTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddltruncate_table_def__init + (TcDb__TseDDLTruncateTableDef *message) +{ + static const TcDb__TseDDLTruncateTableDef init_value = TC_DB__TSE_DDLTRUNCATE_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddltruncate_table_def__get_packed_size + (const TcDb__TseDDLTruncateTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddltruncate_table_def__pack + (const TcDb__TseDDLTruncateTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddltruncate_table_def__pack_to_buffer + (const TcDb__TseDDLTruncateTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLTruncateTableDef * + tc_db__tse_ddltruncate_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLTruncateTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddltruncate_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddltruncate_table_def__free_unpacked + (TcDb__TseDDLTruncateTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddltruncate_table_partition_def__init + (TcDb__TseDDLTruncateTablePartitionDef *message) +{ + static const TcDb__TseDDLTruncateTablePartitionDef init_value = TC_DB__TSE_DDLTRUNCATE_TABLE_PARTITION_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddltruncate_table_partition_def__get_packed_size + (const TcDb__TseDDLTruncateTablePartitionDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_partition_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddltruncate_table_partition_def__pack + (const TcDb__TseDDLTruncateTablePartitionDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_partition_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddltruncate_table_partition_def__pack_to_buffer + (const TcDb__TseDDLTruncateTablePartitionDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_partition_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLTruncateTablePartitionDef * + tc_db__tse_ddltruncate_table_partition_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLTruncateTablePartitionDef *) + protobuf_c_message_unpack (&tc_db__tse_ddltruncate_table_partition_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddltruncate_table_partition_def__free_unpacked + (TcDb__TseDDLTruncateTablePartitionDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddltruncate_table_partition_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlrename_table_def__init + (TcDb__TseDDLRenameTableDef *message) +{ + static const TcDb__TseDDLRenameTableDef init_value = TC_DB__TSE_DDLRENAME_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlrename_table_def__get_packed_size + (const TcDb__TseDDLRenameTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlrename_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlrename_table_def__pack + (const TcDb__TseDDLRenameTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlrename_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlrename_table_def__pack_to_buffer + (const TcDb__TseDDLRenameTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlrename_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLRenameTableDef * + tc_db__tse_ddlrename_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLRenameTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlrename_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlrename_table_def__free_unpacked + (TcDb__TseDDLRenameTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlrename_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddldrop_table_def__init + (TcDb__TseDDLDropTableDef *message) +{ + static const TcDb__TseDDLDropTableDef init_value = TC_DB__TSE_DDLDROP_TABLE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddldrop_table_def__get_packed_size + (const TcDb__TseDDLDropTableDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_table_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddldrop_table_def__pack + (const TcDb__TseDDLDropTableDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_table_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddldrop_table_def__pack_to_buffer + (const TcDb__TseDDLDropTableDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_table_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLDropTableDef * + tc_db__tse_ddldrop_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLDropTableDef *) + protobuf_c_message_unpack (&tc_db__tse_ddldrop_table_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddldrop_table_def__free_unpacked + (TcDb__TseDDLDropTableDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddldrop_table_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_index_def__init + (TcDb__TseDDLAlterIndexDef *message) +{ + static const TcDb__TseDDLAlterIndexDef init_value = TC_DB__TSE_DDLALTER_INDEX_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_index_def__get_packed_size + (const TcDb__TseDDLAlterIndexDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_index_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_index_def__pack + (const TcDb__TseDDLAlterIndexDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_index_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_index_def__pack_to_buffer + (const TcDb__TseDDLAlterIndexDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_index_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterIndexDef * + tc_db__tse_ddlalter_index_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterIndexDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_index_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_index_def__free_unpacked + (TcDb__TseDDLAlterIndexDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_index_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlauto_extend_def__init + (TcDb__TseDDLAutoExtendDef *message) +{ + static const TcDb__TseDDLAutoExtendDef init_value = TC_DB__TSE_DDLAUTO_EXTEND_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlauto_extend_def__get_packed_size + (const TcDb__TseDDLAutoExtendDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlauto_extend_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlauto_extend_def__pack + (const TcDb__TseDDLAutoExtendDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlauto_extend_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlauto_extend_def__pack_to_buffer + (const TcDb__TseDDLAutoExtendDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlauto_extend_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAutoExtendDef * + tc_db__tse_ddlauto_extend_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAutoExtendDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlauto_extend_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlauto_extend_def__free_unpacked + (TcDb__TseDDLAutoExtendDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlauto_extend_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddldata_file_def__init + (TcDb__TseDDLDataFileDef *message) +{ + static const TcDb__TseDDLDataFileDef init_value = TC_DB__TSE_DDLDATA_FILE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddldata_file_def__get_packed_size + (const TcDb__TseDDLDataFileDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddldata_file_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddldata_file_def__pack + (const TcDb__TseDDLDataFileDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddldata_file_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddldata_file_def__pack_to_buffer + (const TcDb__TseDDLDataFileDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddldata_file_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLDataFileDef * + tc_db__tse_ddldata_file_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLDataFileDef *) + protobuf_c_message_unpack (&tc_db__tse_ddldata_file_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddldata_file_def__free_unpacked + (TcDb__TseDDLDataFileDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddldata_file_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlspace_def__init + (TcDb__TseDDLSpaceDef *message) +{ + static const TcDb__TseDDLSpaceDef init_value = TC_DB__TSE_DDLSPACE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlspace_def__get_packed_size + (const TcDb__TseDDLSpaceDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlspace_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlspace_def__pack + (const TcDb__TseDDLSpaceDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlspace_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlspace_def__pack_to_buffer + (const TcDb__TseDDLSpaceDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlspace_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLSpaceDef * + tc_db__tse_ddlspace_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLSpaceDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlspace_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlspace_def__free_unpacked + (TcDb__TseDDLSpaceDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlspace_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddldrop_space_def__init + (TcDb__TseDDLDropSpaceDef *message) +{ + static const TcDb__TseDDLDropSpaceDef init_value = TC_DB__TSE_DDLDROP_SPACE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddldrop_space_def__get_packed_size + (const TcDb__TseDDLDropSpaceDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_space_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddldrop_space_def__pack + (const TcDb__TseDDLDropSpaceDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_space_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddldrop_space_def__pack_to_buffer + (const TcDb__TseDDLDropSpaceDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddldrop_space_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLDropSpaceDef * + tc_db__tse_ddldrop_space_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLDropSpaceDef *) + protobuf_c_message_unpack (&tc_db__tse_ddldrop_space_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddldrop_space_def__free_unpacked + (TcDb__TseDDLDropSpaceDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddldrop_space_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void tc_db__tse_ddlalter_space_def__init + (TcDb__TseDDLAlterSpaceDef *message) +{ + static const TcDb__TseDDLAlterSpaceDef init_value = TC_DB__TSE_DDLALTER_SPACE_DEF__INIT; + *message = init_value; +} +size_t tc_db__tse_ddlalter_space_def__get_packed_size + (const TcDb__TseDDLAlterSpaceDef *message) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_space_def__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t tc_db__tse_ddlalter_space_def__pack + (const TcDb__TseDDLAlterSpaceDef *message, + uint8_t *out) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_space_def__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t tc_db__tse_ddlalter_space_def__pack_to_buffer + (const TcDb__TseDDLAlterSpaceDef *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &tc_db__tse_ddlalter_space_def__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +TcDb__TseDDLAlterSpaceDef * + tc_db__tse_ddlalter_space_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (TcDb__TseDDLAlterSpaceDef *) + protobuf_c_message_unpack (&tc_db__tse_ddlalter_space_def__descriptor, + allocator, len, data); +} +void tc_db__tse_ddlalter_space_def__free_unpacked + (TcDb__TseDDLAlterSpaceDef *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &tc_db__tse_ddlalter_space_def__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor tc_db__tse_ddlcolumn_data_type_def__field_descriptors[5] = +{ + { + "datatype", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDataTypeDef, datatype), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "size", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDataTypeDef, size), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "precision", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDataTypeDef, precision), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "scale", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDataTypeDef, scale), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "mysql_ori_datatype", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDataTypeDef, mysql_ori_datatype), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlcolumn_data_type_def__field_indices_by_name[] = { + 0, /* field[0] = datatype */ + 4, /* field[4] = mysql_ori_datatype */ + 2, /* field[2] = precision */ + 3, /* field[3] = scale */ + 1, /* field[1] = size */ +}; +static const ProtobufCIntRange tc_db__tse_ddlcolumn_data_type_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlcolumn_data_type_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLColumnDataTypeDef", + "TseDDLColumnDataTypeDef", + "TcDb__TseDDLColumnDataTypeDef", + "tc_db", + sizeof(TcDb__TseDDLColumnDataTypeDef), + 5, + tc_db__tse_ddlcolumn_data_type_def__field_descriptors, + tc_db__tse_ddlcolumn_data_type_def__field_indices_by_name, + 1, tc_db__tse_ddlcolumn_data_type_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlcolumn_data_type_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlcolumn_def__field_descriptors[14] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "datatype", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, datatype), + &tc_db__tse_ddlcolumn_data_type_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_option_set", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, is_option_set), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "col_id", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, col_id), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cons_name", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, cons_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "ref_user", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, ref_user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "ref_table", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, ref_table), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "default_text", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, default_text), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "comment", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, comment), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "alter_mode", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, alter_mode), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "collate", + 15, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, collate), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_name", + 16, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, new_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_unsigned", + 17, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, is_unsigned), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "default_func_name", + 18, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLColumnDef, default_func_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlcolumn_def__field_indices_by_name[] = { + 9, /* field[9] = alter_mode */ + 3, /* field[3] = col_id */ + 10, /* field[10] = collate */ + 8, /* field[8] = comment */ + 4, /* field[4] = cons_name */ + 1, /* field[1] = datatype */ + 13, /* field[13] = default_func_name */ + 7, /* field[7] = default_text */ + 2, /* field[2] = is_option_set */ + 12, /* field[12] = is_unsigned */ + 0, /* field[0] = name */ + 11, /* field[11] = new_name */ + 6, /* field[6] = ref_table */ + 5, /* field[5] = ref_user */ +}; +static const ProtobufCIntRange tc_db__tse_ddlcolumn_def__number_ranges[3 + 1] = +{ + { 1, 0 }, + { 4, 2 }, + { 10, 5 }, + { 0, 14 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlcolumn_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLColumnDef", + "TseDDLColumnDef", + "TcDb__TseDDLColumnDef", + "tc_db", + sizeof(TcDb__TseDDLColumnDef), + 14, + tc_db__tse_ddlcolumn_def__field_descriptors, + tc_db__tse_ddlcolumn_def__field_indices_by_name, + 3, tc_db__tse_ddlcolumn_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlcolumn_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlforeign_key_element_def__field_descriptors[2] = +{ + { + "src_column_name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyElementDef, src_column_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "ref_column_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyElementDef, ref_column_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlforeign_key_element_def__field_indices_by_name[] = { + 1, /* field[1] = ref_column_name */ + 0, /* field[0] = src_column_name */ +}; +static const ProtobufCIntRange tc_db__tse_ddlforeign_key_element_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlforeign_key_element_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLForeignKeyElementDef", + "TseDDLForeignKeyElementDef", + "TcDb__TseDDLForeignKeyElementDef", + "tc_db", + sizeof(TcDb__TseDDLForeignKeyElementDef), + 2, + tc_db__tse_ddlforeign_key_element_def__field_descriptors, + tc_db__tse_ddlforeign_key_element_def__field_indices_by_name, + 1, tc_db__tse_ddlforeign_key_element_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlforeign_key_element_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlforeign_key_def__field_descriptors[8] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "unique_index_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, unique_index_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "match_opt", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, match_opt), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "update_opt", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, update_opt), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "delete_opt", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, delete_opt), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "referenced_table_schema_name", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, referenced_table_schema_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "referenced_table_name", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLForeignKeyDef, referenced_table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "elements", + 8, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLForeignKeyDef, n_elements), + offsetof(TcDb__TseDDLForeignKeyDef, elements), + &tc_db__tse_ddlforeign_key_element_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlforeign_key_def__field_indices_by_name[] = { + 4, /* field[4] = delete_opt */ + 7, /* field[7] = elements */ + 2, /* field[2] = match_opt */ + 0, /* field[0] = name */ + 6, /* field[6] = referenced_table_name */ + 5, /* field[5] = referenced_table_schema_name */ + 1, /* field[1] = unique_index_name */ + 3, /* field[3] = update_opt */ +}; +static const ProtobufCIntRange tc_db__tse_ddlforeign_key_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 8 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlforeign_key_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLForeignKeyDef", + "TseDDLForeignKeyDef", + "TcDb__TseDDLForeignKeyDef", + "tc_db", + sizeof(TcDb__TseDDLForeignKeyDef), + 8, + tc_db__tse_ddlforeign_key_def__field_descriptors, + tc_db__tse_ddlforeign_key_def__field_indices_by_name, + 1, tc_db__tse_ddlforeign_key_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlforeign_key_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddltable_key_part__field_descriptors[6] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "length", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, length), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "datatype", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, datatype), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_func", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, is_func), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "func_text", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, func_text), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "func_name", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKeyPart, func_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddltable_key_part__field_indices_by_name[] = { + 2, /* field[2] = datatype */ + 5, /* field[5] = func_name */ + 4, /* field[4] = func_text */ + 3, /* field[3] = is_func */ + 1, /* field[1] = length */ + 0, /* field[0] = name */ +}; +static const ProtobufCIntRange tc_db__tse_ddltable_key_part__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddltable_key_part__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLTableKeyPart", + "TseDDLTableKeyPart", + "TcDb__TseDDLTableKeyPart", + "tc_db", + sizeof(TcDb__TseDDLTableKeyPart), + 6, + tc_db__tse_ddltable_key_part__field_descriptors, + tc_db__tse_ddltable_key_part__field_indices_by_name, + 1, tc_db__tse_ddltable_key_part__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddltable_key_part__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddltable_key__field_descriptors[10] = +{ + { + "user", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, table), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "space", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, space), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "key_type", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, key_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "algorithm", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, algorithm), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_func", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, is_func), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "columns", + 8, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLTableKey, n_columns), + offsetof(TcDb__TseDDLTableKey, columns), + &tc_db__tse_ddltable_key_part__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_constraint", + 9, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, is_constraint), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_dsc", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTableKey, is_dsc), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddltable_key__field_indices_by_name[] = { + 5, /* field[5] = algorithm */ + 7, /* field[7] = columns */ + 8, /* field[8] = is_constraint */ + 9, /* field[9] = is_dsc */ + 6, /* field[6] = is_func */ + 4, /* field[4] = key_type */ + 2, /* field[2] = name */ + 3, /* field[3] = space */ + 1, /* field[1] = table */ + 0, /* field[0] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddltable_key__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 10 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddltable_key__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLTableKey", + "TseDDLTableKey", + "TcDb__TseDDLTableKey", + "tc_db", + sizeof(TcDb__TseDDLTableKey), + 10, + tc_db__tse_ddltable_key__field_descriptors, + tc_db__tse_ddltable_key__field_indices_by_name, + 1, tc_db__tse_ddltable_key__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddltable_key__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_msg_comm_def__field_descriptors[4] = +{ + { + "inst_id", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseMsgCommDef, inst_id), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "thd_id", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseMsgCommDef, thd_id), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "handler_id", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseMsgCommDef, handler_id), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sess_addr", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseMsgCommDef, sess_addr), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_msg_comm_def__field_indices_by_name[] = { + 2, /* field[2] = handler_id */ + 0, /* field[0] = inst_id */ + 3, /* field[3] = sess_addr */ + 1, /* field[1] = thd_id */ +}; +static const ProtobufCIntRange tc_db__tse_msg_comm_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor tc_db__tse_msg_comm_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseMsgCommDef", + "TseMsgCommDef", + "TcDb__TseMsgCommDef", + "tc_db", + sizeof(TcDb__TseMsgCommDef), + 4, + tc_db__tse_msg_comm_def__field_descriptors, + tc_db__tse_msg_comm_def__field_indices_by_name, + 1, tc_db__tse_msg_comm_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_msg_comm_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlpartition_table_def__field_descriptors[2] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLPartitionTableDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "subpart_table_list", + 2, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLPartitionTableDef, n_subpart_table_list), + offsetof(TcDb__TseDDLPartitionTableDef, subpart_table_list), + &tc_db__tse_ddlpartition_table_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlpartition_table_def__field_indices_by_name[] = { + 0, /* field[0] = name */ + 1, /* field[1] = subpart_table_list */ +}; +static const ProtobufCIntRange tc_db__tse_ddlpartition_table_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlpartition_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLPartitionTableDef", + "TseDDLPartitionTableDef", + "TcDb__TseDDLPartitionTableDef", + "tc_db", + sizeof(TcDb__TseDDLPartitionTableDef), + 2, + tc_db__tse_ddlpartition_table_def__field_descriptors, + tc_db__tse_ddlpartition_table_def__field_indices_by_name, + 1, tc_db__tse_ddlpartition_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlpartition_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlpartition_def__field_descriptors[3] = +{ + { + "part_type", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLPartitionDef, part_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "subpart_type", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLPartitionDef, subpart_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "part_table_list", + 3, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLPartitionDef, n_part_table_list), + offsetof(TcDb__TseDDLPartitionDef, part_table_list), + &tc_db__tse_ddlpartition_table_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlpartition_def__field_indices_by_name[] = { + 2, /* field[2] = part_table_list */ + 0, /* field[0] = part_type */ + 1, /* field[1] = subpart_type */ +}; +static const ProtobufCIntRange tc_db__tse_ddlpartition_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlpartition_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLPartitionDef", + "TseDDLPartitionDef", + "TcDb__TseDDLPartitionDef", + "tc_db", + sizeof(TcDb__TseDDLPartitionDef), + 3, + tc_db__tse_ddlpartition_def__field_descriptors, + tc_db__tse_ddlpartition_def__field_indices_by_name, + 1, tc_db__tse_ddlpartition_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlpartition_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlcreate_table_def__field_descriptors[14] = +{ + { + "schema", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, schema), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "space", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, space), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "columns", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLCreateTableDef, n_columns), + offsetof(TcDb__TseDDLCreateTableDef, columns), + &tc_db__tse_ddlcolumn_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "fk_list", + 5, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLCreateTableDef, n_fk_list), + offsetof(TcDb__TseDDLCreateTableDef, fk_list), + &tc_db__tse_ddlforeign_key_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "key_list", + 6, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLCreateTableDef, n_key_list), + offsetof(TcDb__TseDDLCreateTableDef, key_list), + &tc_db__tse_ddltable_key__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "auto_increment_value", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, auto_increment_value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "options", + 8, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, options), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 9, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "alter_table_name", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, alter_table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "alter_db_name", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, alter_db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_create_as_select", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, is_create_as_select), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "partition_def", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLCreateTableDef, partition_def), + &tc_db__tse_ddlpartition_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlcreate_table_def__field_indices_by_name[] = { + 11, /* field[11] = alter_db_name */ + 10, /* field[10] = alter_table_name */ + 6, /* field[6] = auto_increment_value */ + 3, /* field[3] = columns */ + 8, /* field[8] = db_name */ + 4, /* field[4] = fk_list */ + 12, /* field[12] = is_create_as_select */ + 5, /* field[5] = key_list */ + 1, /* field[1] = name */ + 7, /* field[7] = options */ + 13, /* field[13] = partition_def */ + 0, /* field[0] = schema */ + 2, /* field[2] = space */ + 9, /* field[9] = sql_str */ +}; +static const ProtobufCIntRange tc_db__tse_ddlcreate_table_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 14 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlcreate_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLCreateTableDef", + "TseDDLCreateTableDef", + "TcDb__TseDDLCreateTableDef", + "tc_db", + sizeof(TcDb__TseDDLCreateTableDef), + 14, + tc_db__tse_ddlcreate_table_def__field_descriptors, + tc_db__tse_ddlcreate_table_def__field_indices_by_name, + 1, tc_db__tse_ddlcreate_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlcreate_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_table_porp__field_descriptors[6] = +{ + { + "new_name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, new_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "pctfree", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, pctfree), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "appendonly", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, appendonly), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "enable_row_move", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, enable_row_move), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "shrink_opt", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, shrink_opt), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "serial_start", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTablePorp, serial_start), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_table_porp__field_indices_by_name[] = { + 2, /* field[2] = appendonly */ + 3, /* field[3] = enable_row_move */ + 0, /* field[0] = new_name */ + 1, /* field[1] = pctfree */ + 5, /* field[5] = serial_start */ + 4, /* field[4] = shrink_opt */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_table_porp__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_porp__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterTablePorp", + "TseDDLAlterTablePorp", + "TcDb__TseDDLAlterTablePorp", + "tc_db", + sizeof(TcDb__TseDDLAlterTablePorp), + 6, + tc_db__tse_ddlalter_table_porp__field_descriptors, + tc_db__tse_ddlalter_table_porp__field_indices_by_name, + 1, tc_db__tse_ddlalter_table_porp__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_table_porp__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_table_drop__field_descriptors[3] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDrop, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "drop_type", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDrop, drop_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "key_type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDrop, key_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_table_drop__field_indices_by_name[] = { + 1, /* field[1] = drop_type */ + 2, /* field[2] = key_type */ + 0, /* field[0] = name */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_table_drop__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_drop__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterTableDrop", + "TseDDLAlterTableDrop", + "TcDb__TseDDLAlterTableDrop", + "tc_db", + sizeof(TcDb__TseDDLAlterTableDrop), + 3, + tc_db__tse_ddlalter_table_drop__field_descriptors, + tc_db__tse_ddlalter_table_drop__field_indices_by_name, + 1, tc_db__tse_ddlalter_table_drop__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_table_drop__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_table_drop_key__field_descriptors[3] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDropKey, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "drop_type", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDropKey, drop_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "key_type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDropKey, key_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_table_drop_key__field_indices_by_name[] = { + 1, /* field[1] = drop_type */ + 2, /* field[2] = key_type */ + 0, /* field[0] = name */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_table_drop_key__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_drop_key__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterTableDropKey", + "TseDDLAlterTableDropKey", + "TcDb__TseDDLAlterTableDropKey", + "tc_db", + sizeof(TcDb__TseDDLAlterTableDropKey), + 3, + tc_db__tse_ddlalter_table_drop_key__field_descriptors, + tc_db__tse_ddlalter_table_drop_key__field_indices_by_name, + 1, tc_db__tse_ddlalter_table_drop_key__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_table_drop_key__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_table_alter_column__field_descriptors[7] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, new_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "has_no_default", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, has_no_default), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "has_default", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, has_default), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_default_null", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, is_default_null), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "default_text", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableAlterColumn, default_text), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_table_alter_column__field_indices_by_name[] = { + 6, /* field[6] = default_text */ + 4, /* field[4] = has_default */ + 3, /* field[3] = has_no_default */ + 5, /* field[5] = is_default_null */ + 0, /* field[0] = name */ + 1, /* field[1] = new_name */ + 2, /* field[2] = type */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_table_alter_column__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 7 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_alter_column__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterTableAlterColumn", + "TseDDLAlterTableAlterColumn", + "TcDb__TseDDLAlterTableAlterColumn", + "tc_db", + sizeof(TcDb__TseDDLAlterTableAlterColumn), + 7, + tc_db__tse_ddlalter_table_alter_column__field_descriptors, + tc_db__tse_ddlalter_table_alter_column__field_indices_by_name, + 1, tc_db__tse_ddlalter_table_alter_column__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_table_alter_column__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_table_def__field_descriptors[20] = +{ + { + "action", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, action), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "options", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, options), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "user", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "drop_list", + 5, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_drop_list), + offsetof(TcDb__TseDDLAlterTableDef, drop_list), + &tc_db__tse_ddlalter_table_drop__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "alter_list", + 6, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_alter_list), + offsetof(TcDb__TseDDLAlterTableDef, alter_list), + &tc_db__tse_ddlalter_table_alter_column__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "create_list", + 7, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_create_list), + offsetof(TcDb__TseDDLAlterTableDef, create_list), + &tc_db__tse_ddlcolumn_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table_def", + 8, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, table_def), + &tc_db__tse_ddlalter_table_porp__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "add_key_list", + 9, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_add_key_list), + offsetof(TcDb__TseDDLAlterTableDef, add_key_list), + &tc_db__tse_ddltable_key__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "drop_key_list", + 10, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_drop_key_list), + offsetof(TcDb__TseDDLAlterTableDef, drop_key_list), + &tc_db__tse_ddlalter_table_drop_key__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "add_foreign_key_list", + 11, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_add_foreign_key_list), + offsetof(TcDb__TseDDLAlterTableDef, add_foreign_key_list), + &tc_db__tse_ddlforeign_key_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_auto_increment_value", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, new_auto_increment_value), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "alter_index_list", + 15, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_alter_index_list), + offsetof(TcDb__TseDDLAlterTableDef, alter_index_list), + &tc_db__tse_ddlalter_index_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "drop_partition_names", + 16, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(TcDb__TseDDLAlterTableDef, n_drop_partition_names), + offsetof(TcDb__TseDDLAlterTableDef, drop_partition_names), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "add_part_list", + 17, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLAlterTableDef, n_add_part_list), + offsetof(TcDb__TseDDLAlterTableDef, add_part_list), + &tc_db__tse_ddlpartition_table_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "hash_coalesce_count", + 18, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, hash_coalesce_count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "systimestamp", + 19, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, systimestamp), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "tz_offset_UTC", + 20, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterTableDef, tz_offset_utc), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_table_def__field_indices_by_name[] = { + 0, /* field[0] = action */ + 10, /* field[10] = add_foreign_key_list */ + 8, /* field[8] = add_key_list */ + 16, /* field[16] = add_part_list */ + 14, /* field[14] = alter_index_list */ + 5, /* field[5] = alter_list */ + 6, /* field[6] = create_list */ + 12, /* field[12] = db_name */ + 9, /* field[9] = drop_key_list */ + 4, /* field[4] = drop_list */ + 15, /* field[15] = drop_partition_names */ + 17, /* field[17] = hash_coalesce_count */ + 3, /* field[3] = name */ + 11, /* field[11] = new_auto_increment_value */ + 1, /* field[1] = options */ + 13, /* field[13] = sql_str */ + 18, /* field[18] = systimestamp */ + 7, /* field[7] = table_def */ + 19, /* field[19] = tz_offset_UTC */ + 2, /* field[2] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_table_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 20 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterTableDef", + "TseDDLAlterTableDef", + "TcDb__TseDDLAlterTableDef", + "tc_db", + sizeof(TcDb__TseDDLAlterTableDef), + 20, + tc_db__tse_ddlalter_table_def__field_descriptors, + tc_db__tse_ddlalter_table_def__field_indices_by_name, + 1, tc_db__tse_ddlalter_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddltruncate_table_def__field_descriptors[5] = +{ + { + "schema", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTableDef, schema), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTableDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTableDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTableDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "no_check_fk", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTableDef, no_check_fk), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddltruncate_table_def__field_indices_by_name[] = { + 2, /* field[2] = db_name */ + 1, /* field[1] = name */ + 4, /* field[4] = no_check_fk */ + 0, /* field[0] = schema */ + 3, /* field[3] = sql_str */ +}; +static const ProtobufCIntRange tc_db__tse_ddltruncate_table_def__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 4, 2 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddltruncate_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLTruncateTableDef", + "TseDDLTruncateTableDef", + "TcDb__TseDDLTruncateTableDef", + "tc_db", + sizeof(TcDb__TseDDLTruncateTableDef), + 5, + tc_db__tse_ddltruncate_table_def__field_descriptors, + tc_db__tse_ddltruncate_table_def__field_indices_by_name, + 2, tc_db__tse_ddltruncate_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddltruncate_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddltruncate_table_partition_def__field_descriptors[9] = +{ + { + "user", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTablePartitionDef, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTablePartitionDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table_name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTablePartitionDef, table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "partition_name", + 4, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(TcDb__TseDDLTruncateTablePartitionDef, n_partition_name), + offsetof(TcDb__TseDDLTruncateTablePartitionDef, partition_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "partition_id", + 5, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(TcDb__TseDDLTruncateTablePartitionDef, n_partition_id), + offsetof(TcDb__TseDDLTruncateTablePartitionDef, partition_id), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTablePartitionDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "is_subpart", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLTruncateTablePartitionDef, is_subpart), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "subpartition_name", + 8, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(TcDb__TseDDLTruncateTablePartitionDef, n_subpartition_name), + offsetof(TcDb__TseDDLTruncateTablePartitionDef, subpartition_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "subpartition_id", + 9, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_UINT32, + offsetof(TcDb__TseDDLTruncateTablePartitionDef, n_subpartition_id), + offsetof(TcDb__TseDDLTruncateTablePartitionDef, subpartition_id), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_PACKED, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddltruncate_table_partition_def__field_indices_by_name[] = { + 1, /* field[1] = db_name */ + 6, /* field[6] = is_subpart */ + 4, /* field[4] = partition_id */ + 3, /* field[3] = partition_name */ + 5, /* field[5] = sql_str */ + 8, /* field[8] = subpartition_id */ + 7, /* field[7] = subpartition_name */ + 2, /* field[2] = table_name */ + 0, /* field[0] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddltruncate_table_partition_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 9 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddltruncate_table_partition_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLTruncateTablePartitionDef", + "TseDDLTruncateTablePartitionDef", + "TcDb__TseDDLTruncateTablePartitionDef", + "tc_db", + sizeof(TcDb__TseDDLTruncateTablePartitionDef), + 9, + tc_db__tse_ddltruncate_table_partition_def__field_descriptors, + tc_db__tse_ddltruncate_table_partition_def__field_indices_by_name, + 1, tc_db__tse_ddltruncate_table_partition_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddltruncate_table_partition_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlrename_table_def__field_descriptors[12] = +{ + { + "action", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, action), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "options", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, options), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "user", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_user", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, new_user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_table_name", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, new_table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_db_name", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, new_db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "old_table_name", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, old_table_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "old_db_name", + 8, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, old_db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "current_db_name", + 9, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, current_db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLRenameTableDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "old_constraints_name", + 11, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(TcDb__TseDDLRenameTableDef, n_old_constraints_name), + offsetof(TcDb__TseDDLRenameTableDef, old_constraints_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_constraints_name", + 12, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_STRING, + offsetof(TcDb__TseDDLRenameTableDef, n_new_constraints_name), + offsetof(TcDb__TseDDLRenameTableDef, new_constraints_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlrename_table_def__field_indices_by_name[] = { + 0, /* field[0] = action */ + 8, /* field[8] = current_db_name */ + 11, /* field[11] = new_constraints_name */ + 5, /* field[5] = new_db_name */ + 4, /* field[4] = new_table_name */ + 3, /* field[3] = new_user */ + 10, /* field[10] = old_constraints_name */ + 7, /* field[7] = old_db_name */ + 6, /* field[6] = old_table_name */ + 1, /* field[1] = options */ + 9, /* field[9] = sql_str */ + 2, /* field[2] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddlrename_table_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 12 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlrename_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLRenameTableDef", + "TseDDLRenameTableDef", + "TcDb__TseDDLRenameTableDef", + "tc_db", + sizeof(TcDb__TseDDLRenameTableDef), + 12, + tc_db__tse_ddlrename_table_def__field_descriptors, + tc_db__tse_ddlrename_table_def__field_indices_by_name, + 1, tc_db__tse_ddlrename_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlrename_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddldrop_table_def__field_descriptors[6] = +{ + { + "options", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, options), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "user", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "dbname_und", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, dbname_und), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropTableDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddldrop_table_def__field_indices_by_name[] = { + 4, /* field[4] = db_name */ + 3, /* field[3] = dbname_und */ + 2, /* field[2] = name */ + 0, /* field[0] = options */ + 5, /* field[5] = sql_str */ + 1, /* field[1] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddldrop_table_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddldrop_table_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLDropTableDef", + "TseDDLDropTableDef", + "TcDb__TseDDLDropTableDef", + "tc_db", + sizeof(TcDb__TseDDLDropTableDef), + 6, + tc_db__tse_ddldrop_table_def__field_descriptors, + tc_db__tse_ddldrop_table_def__field_indices_by_name, + 1, tc_db__tse_ddldrop_table_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddldrop_table_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_index_def__field_descriptors[6] = +{ + { + "user", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, user), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "table", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, table), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_name", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, new_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "key_type", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterIndexDef, key_type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_index_def__field_indices_by_name[] = { + 5, /* field[5] = key_type */ + 1, /* field[1] = name */ + 4, /* field[4] = new_name */ + 3, /* field[3] = table */ + 2, /* field[2] = type */ + 0, /* field[0] = user */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_index_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_index_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterIndexDef", + "TseDDLAlterIndexDef", + "TcDb__TseDDLAlterIndexDef", + "tc_db", + sizeof(TcDb__TseDDLAlterIndexDef), + 6, + tc_db__tse_ddlalter_index_def__field_descriptors, + tc_db__tse_ddlalter_index_def__field_indices_by_name, + 1, tc_db__tse_ddlalter_index_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_index_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlauto_extend_def__field_descriptors[3] = +{ + { + "enabled", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAutoExtendDef, enabled), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "nextsize", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAutoExtendDef, nextsize), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "maxsize", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAutoExtendDef, maxsize), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlauto_extend_def__field_indices_by_name[] = { + 0, /* field[0] = enabled */ + 2, /* field[2] = maxsize */ + 1, /* field[1] = nextsize */ +}; +static const ProtobufCIntRange tc_db__tse_ddlauto_extend_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 3 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlauto_extend_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAutoExtendDef", + "TseDDLAutoExtendDef", + "TcDb__TseDDLAutoExtendDef", + "tc_db", + sizeof(TcDb__TseDDLAutoExtendDef), + 3, + tc_db__tse_ddlauto_extend_def__field_descriptors, + tc_db__tse_ddlauto_extend_def__field_indices_by_name, + 1, tc_db__tse_ddlauto_extend_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlauto_extend_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddldata_file_def__field_descriptors[5] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDataFileDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "size", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDataFileDef, size), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "block_size", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDataFileDef, block_size), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "autoextend", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDataFileDef, autoextend), + &tc_db__tse_ddlauto_extend_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "node_id", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDataFileDef, node_id), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddldata_file_def__field_indices_by_name[] = { + 3, /* field[3] = autoextend */ + 2, /* field[2] = block_size */ + 0, /* field[0] = name */ + 4, /* field[4] = node_id */ + 1, /* field[1] = size */ +}; +static const ProtobufCIntRange tc_db__tse_ddldata_file_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddldata_file_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLDataFileDef", + "TseDDLDataFileDef", + "TcDb__TseDDLDataFileDef", + "tc_db", + sizeof(TcDb__TseDDLDataFileDef), + 5, + tc_db__tse_ddldata_file_def__field_descriptors, + tc_db__tse_ddldata_file_def__field_indices_by_name, + 1, tc_db__tse_ddldata_file_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddldata_file_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlspace_def__field_descriptors[9] = +{ + { + "name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "type", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, type), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "in_memory", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, in_memory), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "autooffline", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, autooffline), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "extent_size", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, extent_size), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "datafiles_list", + 6, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(TcDb__TseDDLSpaceDef, n_datafiles_list), + offsetof(TcDb__TseDDLSpaceDef, datafiles_list), + &tc_db__tse_ddldata_file_def__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "flags", + 7, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, flags), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 8, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 9, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLSpaceDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlspace_def__field_indices_by_name[] = { + 3, /* field[3] = autooffline */ + 5, /* field[5] = datafiles_list */ + 7, /* field[7] = db_name */ + 4, /* field[4] = extent_size */ + 6, /* field[6] = flags */ + 2, /* field[2] = in_memory */ + 0, /* field[0] = name */ + 8, /* field[8] = sql_str */ + 1, /* field[1] = type */ +}; +static const ProtobufCIntRange tc_db__tse_ddlspace_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 9 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlspace_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLSpaceDef", + "TseDDLSpaceDef", + "TcDb__TseDDLSpaceDef", + "tc_db", + sizeof(TcDb__TseDDLSpaceDef), + 9, + tc_db__tse_ddlspace_def__field_descriptors, + tc_db__tse_ddlspace_def__field_indices_by_name, + 1, tc_db__tse_ddlspace_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlspace_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddldrop_space_def__field_descriptors[4] = +{ + { + "obj_name", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropSpaceDef, obj_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "option", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropSpaceDef, option), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropSpaceDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLDropSpaceDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddldrop_space_def__field_indices_by_name[] = { + 2, /* field[2] = db_name */ + 0, /* field[0] = obj_name */ + 1, /* field[1] = option */ + 3, /* field[3] = sql_str */ +}; +static const ProtobufCIntRange tc_db__tse_ddldrop_space_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddldrop_space_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLDropSpaceDef", + "TseDDLDropSpaceDef", + "TcDb__TseDDLDropSpaceDef", + "tc_db", + sizeof(TcDb__TseDDLDropSpaceDef), + 4, + tc_db__tse_ddldrop_space_def__field_descriptors, + tc_db__tse_ddldrop_space_def__field_indices_by_name, + 1, tc_db__tse_ddldrop_space_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddldrop_space_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor tc_db__tse_ddlalter_space_def__field_descriptors[6] = +{ + { + "action", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, action), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "name", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "new_name", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, new_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "auto_extend_size", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT64, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, auto_extend_size), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "db_name", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, db_name), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "sql_str", + 6, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_STRING, + 0, /* quantifier_offset */ + offsetof(TcDb__TseDDLAlterSpaceDef, sql_str), + NULL, + &protobuf_c_empty_string, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned tc_db__tse_ddlalter_space_def__field_indices_by_name[] = { + 0, /* field[0] = action */ + 3, /* field[3] = auto_extend_size */ + 4, /* field[4] = db_name */ + 1, /* field[1] = name */ + 2, /* field[2] = new_name */ + 5, /* field[5] = sql_str */ +}; +static const ProtobufCIntRange tc_db__tse_ddlalter_space_def__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 6 } +}; +const ProtobufCMessageDescriptor tc_db__tse_ddlalter_space_def__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "tc_db.TseDDLAlterSpaceDef", + "TseDDLAlterSpaceDef", + "TcDb__TseDDLAlterSpaceDef", + "tc_db", + sizeof(TcDb__TseDDLAlterSpaceDef), + 6, + tc_db__tse_ddlalter_space_def__field_descriptors, + tc_db__tse_ddlalter_space_def__field_indices_by_name, + 1, tc_db__tse_ddlalter_space_def__number_ranges, + (ProtobufCMessageInit) tc_db__tse_ddlalter_space_def__init, + NULL,NULL,NULL /* reserved[123] */ +}; diff --git a/storage/tianchi/protobuf/tc_db.pb-c.h b/storage/tianchi/protobuf/tc_db.pb-c.h new file mode 100644 index 0000000..b72cc52 --- /dev/null +++ b/storage/tianchi/protobuf/tc_db.pb-c.h @@ -0,0 +1,1152 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: tc_db.proto */ + +#ifndef PROTOBUF_C_tc_5fdb_2eproto__INCLUDED +#define PROTOBUF_C_tc_5fdb_2eproto__INCLUDED + +#include + +PROTOBUF_C__BEGIN_DECLS + +#if PROTOBUF_C_VERSION_NUMBER < 1003000 +# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. +#elif 1004001 < PROTOBUF_C_MIN_COMPILER_VERSION +# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. +#endif + + +typedef struct TcDb__TseDDLColumnDataTypeDef TcDb__TseDDLColumnDataTypeDef; +typedef struct TcDb__TseDDLColumnDef TcDb__TseDDLColumnDef; +typedef struct TcDb__TseDDLForeignKeyElementDef TcDb__TseDDLForeignKeyElementDef; +typedef struct TcDb__TseDDLForeignKeyDef TcDb__TseDDLForeignKeyDef; +typedef struct TcDb__TseDDLTableKeyPart TcDb__TseDDLTableKeyPart; +typedef struct TcDb__TseDDLTableKey TcDb__TseDDLTableKey; +typedef struct TcDb__TseMsgCommDef TcDb__TseMsgCommDef; +typedef struct TcDb__TseDDLPartitionTableDef TcDb__TseDDLPartitionTableDef; +typedef struct TcDb__TseDDLPartitionDef TcDb__TseDDLPartitionDef; +typedef struct TcDb__TseDDLCreateTableDef TcDb__TseDDLCreateTableDef; +typedef struct TcDb__TseDDLAlterTablePorp TcDb__TseDDLAlterTablePorp; +typedef struct TcDb__TseDDLAlterTableDrop TcDb__TseDDLAlterTableDrop; +typedef struct TcDb__TseDDLAlterTableDropKey TcDb__TseDDLAlterTableDropKey; +typedef struct TcDb__TseDDLAlterTableAlterColumn TcDb__TseDDLAlterTableAlterColumn; +typedef struct TcDb__TseDDLAlterTableDef TcDb__TseDDLAlterTableDef; +typedef struct TcDb__TseDDLTruncateTableDef TcDb__TseDDLTruncateTableDef; +typedef struct TcDb__TseDDLTruncateTablePartitionDef TcDb__TseDDLTruncateTablePartitionDef; +typedef struct TcDb__TseDDLRenameTableDef TcDb__TseDDLRenameTableDef; +typedef struct TcDb__TseDDLDropTableDef TcDb__TseDDLDropTableDef; +typedef struct TcDb__TseDDLAlterIndexDef TcDb__TseDDLAlterIndexDef; +typedef struct TcDb__TseDDLAutoExtendDef TcDb__TseDDLAutoExtendDef; +typedef struct TcDb__TseDDLDataFileDef TcDb__TseDDLDataFileDef; +typedef struct TcDb__TseDDLSpaceDef TcDb__TseDDLSpaceDef; +typedef struct TcDb__TseDDLDropSpaceDef TcDb__TseDDLDropSpaceDef; +typedef struct TcDb__TseDDLAlterSpaceDef TcDb__TseDDLAlterSpaceDef; + + +/* --- enums --- */ + + +/* --- messages --- */ + +struct TcDb__TseDDLColumnDataTypeDef +{ + ProtobufCMessage base; + /* + * These definitions is same as the `typmode_t`; thus they should + * be replaced by typmode_t for unifying the definition of columns + */ + /* + * ct_type_t + */ + int32_t datatype; + uint32_t size; + uint32_t precision; + int32_t scale; + int32_t mysql_ori_datatype; +}; +#define TC_DB__TSE_DDLCOLUMN_DATA_TYPE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlcolumn_data_type_def__descriptor) \ + , 0, 0, 0, 0, 0 } + + +struct TcDb__TseDDLColumnDef +{ + ProtobufCMessage base; + char *name; + TcDb__TseDDLColumnDataTypeDef *datatype; + uint32_t is_option_set; + uint32_t col_id; + char *cons_name; + char *ref_user; + char *ref_table; + char *default_text; + char *comment; + /* + * tse_alter_column_alter_mode + */ + uint32_t alter_mode; + uint64_t collate; + char *new_name; + uint32_t is_unsigned; + char *default_func_name; +}; +#define TC_DB__TSE_DDLCOLUMN_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlcolumn_def__descriptor) \ + , (char *)protobuf_c_empty_string, NULL, 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, 0, (char *)protobuf_c_empty_string, 0, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLForeignKeyElementDef +{ + ProtobufCMessage base; + char *src_column_name; + char *ref_column_name; +}; +#define TC_DB__TSE_DDLFOREIGN_KEY_ELEMENT_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlforeign_key_element_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLForeignKeyDef +{ + ProtobufCMessage base; + /* + * fill_dd_foreign_keys_from_create_fields + */ + char *name; + char *unique_index_name; + uint32_t match_opt; + uint32_t update_opt; + uint32_t delete_opt; + char *referenced_table_schema_name; + char *referenced_table_name; + size_t n_elements; + TcDb__TseDDLForeignKeyElementDef **elements; +}; +#define TC_DB__TSE_DDLFOREIGN_KEY_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlforeign_key_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL } + + +struct TcDb__TseDDLTableKeyPart +{ + ProtobufCMessage base; + /* + * KEY_PART_INFO + */ + char *name; + /* + * Length of key part in bytes, excluding NULL flag and length bytes + */ + uint32_t length; + int32_t datatype; + protobuf_c_boolean is_func; + char *func_text; + char *func_name; +}; +#define TC_DB__TSE_DDLTABLE_KEY_PART__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddltable_key_part__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLTableKey +{ + ProtobufCMessage base; + /* + * Key + */ + char *user; + char *table; + char *name; + char *space; + /* + * tse_key_type + */ + int32_t key_type; + /* + * tse_ha_key_alg + */ + int32_t algorithm; + protobuf_c_boolean is_func; + size_t n_columns; + TcDb__TseDDLTableKeyPart **columns; + protobuf_c_boolean is_constraint; + protobuf_c_boolean is_dsc; +}; +#define TC_DB__TSE_DDLTABLE_KEY__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddltable_key__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, 0, 0, 0,NULL, 0, 0 } + + +struct TcDb__TseMsgCommDef +{ + ProtobufCMessage base; + uint32_t inst_id; + uint32_t thd_id; + uint32_t handler_id; + uint64_t sess_addr; +}; +#define TC_DB__TSE_MSG_COMM_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_msg_comm_def__descriptor) \ + , 0, 0, 0, 0 } + + +struct TcDb__TseDDLPartitionTableDef +{ + ProtobufCMessage base; + char *name; + size_t n_subpart_table_list; + TcDb__TseDDLPartitionTableDef **subpart_table_list; +}; +#define TC_DB__TSE_DDLPARTITION_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlpartition_table_def__descriptor) \ + , (char *)protobuf_c_empty_string, 0,NULL } + + +struct TcDb__TseDDLPartitionDef +{ + ProtobufCMessage base; + uint32_t part_type; + uint32_t subpart_type; + size_t n_part_table_list; + TcDb__TseDDLPartitionTableDef **part_table_list; +}; +#define TC_DB__TSE_DDLPARTITION_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlpartition_def__descriptor) \ + , 0, 0, 0,NULL } + + +struct TcDb__TseDDLCreateTableDef +{ + ProtobufCMessage base; + char *schema; + char *name; + char *space; + size_t n_columns; + TcDb__TseDDLColumnDef **columns; + size_t n_fk_list; + TcDb__TseDDLForeignKeyDef **fk_list; + size_t n_key_list; + TcDb__TseDDLTableKey **key_list; + /* + *init auto incremnet value + */ + uint64_t auto_increment_value; + /* + * if not exists + */ + uint32_t options; + char *db_name; + char *sql_str; + char *alter_table_name; + char *alter_db_name; + protobuf_c_boolean is_create_as_select; + TcDb__TseDDLPartitionDef *partition_def; +}; +#define TC_DB__TSE_DDLCREATE_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlcreate_table_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0,NULL, 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, NULL } + + +struct TcDb__TseDDLAlterTablePorp +{ + ProtobufCMessage base; + /* + * knl_alt_table_prop_t + */ + char *new_name; + uint32_t pctfree; + uint32_t appendonly; + uint32_t enable_row_move; + uint32_t shrink_opt; + int64_t serial_start; +}; +#define TC_DB__TSE_DDLALTER_TABLE_PORP__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_table_porp__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0, 0, 0, 0 } + + +struct TcDb__TseDDLAlterTableDrop +{ + ProtobufCMessage base; + char *name; + /* + * tse_alter_table_drop_type + */ + int32_t drop_type; + /* + * tse_key_type + */ + int32_t key_type; +}; +#define TC_DB__TSE_DDLALTER_TABLE_DROP__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_table_drop__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0 } + + +struct TcDb__TseDDLAlterTableDropKey +{ + ProtobufCMessage base; + char *name; + /* + * tse_alter_table_drop_type + */ + int32_t drop_type; + /* + * tse_key_type + */ + int32_t key_type; +}; +#define TC_DB__TSE_DDLALTER_TABLE_DROP_KEY__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_table_drop_key__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0 } + + +struct TcDb__TseDDLAlterTableAlterColumn +{ + ProtobufCMessage base; + char *name; + char *new_name; + /* + * SET_DEFAULT, DROP_DEFAULT, RENAME_COLUMN + */ + uint32_t type; + protobuf_c_boolean has_no_default; + protobuf_c_boolean has_default; + protobuf_c_boolean is_default_null; + /* + * string default_data = 8; + */ + char *default_text; +}; +#define TC_DB__TSE_DDLALTER_TABLE_ALTER_COLUMN__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_table_alter_column__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, 0, 0, 0, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLAlterTableDef +{ + ProtobufCMessage base; + /* + * altable_action_t + */ + uint32_t action; + uint32_t options; + char *user; + char *name; + /* + ** + *Columns, keys and constraints to be dropped. + */ + size_t n_drop_list; + TcDb__TseDDLAlterTableDrop **drop_list; + /* + * Columns for ALTER_COLUMN_CHANGE_DEFAULT. + */ + size_t n_alter_list; + TcDb__TseDDLAlterTableAlterColumn **alter_list; + /* + * List of columns, used by both CREATE and ALTER TABLE. + */ + size_t n_create_list; + TcDb__TseDDLColumnDef **create_list; + TcDb__TseDDLAlterTablePorp *table_def; + size_t n_add_key_list; + TcDb__TseDDLTableKey **add_key_list; + size_t n_drop_key_list; + TcDb__TseDDLAlterTableDropKey **drop_key_list; + size_t n_add_foreign_key_list; + TcDb__TseDDLForeignKeyDef **add_foreign_key_list; + uint64_t new_auto_increment_value; + char *db_name; + char *sql_str; + size_t n_alter_index_list; + TcDb__TseDDLAlterIndexDef **alter_index_list; + size_t n_drop_partition_names; + char **drop_partition_names; + size_t n_add_part_list; + TcDb__TseDDLPartitionTableDef **add_part_list; + uint32_t hash_coalesce_count; + int64_t systimestamp; + int32_t tz_offset_utc; +}; +#define TC_DB__TSE_DDLALTER_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_table_def__descriptor) \ + , 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0,NULL, NULL, 0,NULL, 0,NULL, 0,NULL, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, 0,NULL, 0, 0, 0 } + + +struct TcDb__TseDDLTruncateTableDef +{ + ProtobufCMessage base; + char *schema; + char *name; + char *db_name; + char *sql_str; + uint32_t no_check_fk; +}; +#define TC_DB__TSE_DDLTRUNCATE_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddltruncate_table_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0 } + + +struct TcDb__TseDDLTruncateTablePartitionDef +{ + ProtobufCMessage base; + char *user; + char *db_name; + char *table_name; + size_t n_partition_name; + char **partition_name; + size_t n_partition_id; + uint32_t *partition_id; + char *sql_str; + protobuf_c_boolean is_subpart; + size_t n_subpartition_name; + char **subpartition_name; + size_t n_subpartition_id; + uint32_t *subpartition_id; +}; +#define TC_DB__TSE_DDLTRUNCATE_TABLE_PARTITION_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddltruncate_table_partition_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL, (char *)protobuf_c_empty_string, 0, 0,NULL, 0,NULL } + + +struct TcDb__TseDDLRenameTableDef +{ + ProtobufCMessage base; + /* + * altable_action_t + */ + uint32_t action; + uint32_t options; + char *user; + char *new_user; + char *new_table_name; + char *new_db_name; + char *old_table_name; + char *old_db_name; + char *current_db_name; + char *sql_str; + size_t n_old_constraints_name; + char **old_constraints_name; + size_t n_new_constraints_name; + char **new_constraints_name; +}; +#define TC_DB__TSE_DDLRENAME_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlrename_table_def__descriptor) \ + , 0, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0,NULL, 0,NULL } + + +struct TcDb__TseDDLDropTableDef +{ + ProtobufCMessage base; + uint32_t options; + char *user; + char *name; + char *dbname_und; + char *db_name; + char *sql_str; +}; +#define TC_DB__TSE_DDLDROP_TABLE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddldrop_table_def__descriptor) \ + , 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLAlterIndexDef +{ + ProtobufCMessage base; + char *user; + char *name; + /* + * def type + */ + uint32_t type; + char *table; + char *new_name; + /* + * tse_key_type + */ + int32_t key_type; +}; +#define TC_DB__TSE_DDLALTER_INDEX_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_index_def__descriptor) \ + , (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0 } + + +struct TcDb__TseDDLAutoExtendDef +{ + ProtobufCMessage base; + protobuf_c_boolean enabled; + uint64_t nextsize; + int64_t maxsize; +}; +#define TC_DB__TSE_DDLAUTO_EXTEND_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlauto_extend_def__descriptor) \ + , 0, 0, 0 } + + +struct TcDb__TseDDLDataFileDef +{ + ProtobufCMessage base; + char *name; + /* + *device size + */ + int64_t size; + int32_t block_size; + /* + * the data of the autoextend property of the device + */ + TcDb__TseDDLAutoExtendDef *autoextend; + uint32_t node_id; +}; +#define TC_DB__TSE_DDLDATA_FILE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddldata_file_def__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0, NULL, 0 } + + +struct TcDb__TseDDLSpaceDef +{ + ProtobufCMessage base; + /* + * name of the space + */ + char *name; + /* + * type of the space + */ + uint32_t type; + protobuf_c_boolean in_memory; + protobuf_c_boolean autooffline; + uint32_t extent_size; + size_t n_datafiles_list; + TcDb__TseDDLDataFileDef **datafiles_list; + uint32_t flags; + char *db_name; + char *sql_str; +}; +#define TC_DB__TSE_DDLSPACE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlspace_def__descriptor) \ + , (char *)protobuf_c_empty_string, 0, 0, 0, 0, 0,NULL, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLDropSpaceDef +{ + ProtobufCMessage base; + char *obj_name; + uint32_t option; + char *db_name; + char *sql_str; +}; +#define TC_DB__TSE_DDLDROP_SPACE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddldrop_space_def__descriptor) \ + , (char *)protobuf_c_empty_string, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +struct TcDb__TseDDLAlterSpaceDef +{ + ProtobufCMessage base; + uint32_t action; + /* + * name of the space + */ + char *name; + /* + * name of the new space + */ + char *new_name; + uint64_t auto_extend_size; + char *db_name; + char *sql_str; +}; +#define TC_DB__TSE_DDLALTER_SPACE_DEF__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&tc_db__tse_ddlalter_space_def__descriptor) \ + , 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string, 0, (char *)protobuf_c_empty_string, (char *)protobuf_c_empty_string } + + +/* TcDb__TseDDLColumnDataTypeDef methods */ +void tc_db__tse_ddlcolumn_data_type_def__init + (TcDb__TseDDLColumnDataTypeDef *message); +size_t tc_db__tse_ddlcolumn_data_type_def__get_packed_size + (const TcDb__TseDDLColumnDataTypeDef *message); +size_t tc_db__tse_ddlcolumn_data_type_def__pack + (const TcDb__TseDDLColumnDataTypeDef *message, + uint8_t *out); +size_t tc_db__tse_ddlcolumn_data_type_def__pack_to_buffer + (const TcDb__TseDDLColumnDataTypeDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLColumnDataTypeDef * + tc_db__tse_ddlcolumn_data_type_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlcolumn_data_type_def__free_unpacked + (TcDb__TseDDLColumnDataTypeDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLColumnDef methods */ +void tc_db__tse_ddlcolumn_def__init + (TcDb__TseDDLColumnDef *message); +size_t tc_db__tse_ddlcolumn_def__get_packed_size + (const TcDb__TseDDLColumnDef *message); +size_t tc_db__tse_ddlcolumn_def__pack + (const TcDb__TseDDLColumnDef *message, + uint8_t *out); +size_t tc_db__tse_ddlcolumn_def__pack_to_buffer + (const TcDb__TseDDLColumnDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLColumnDef * + tc_db__tse_ddlcolumn_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlcolumn_def__free_unpacked + (TcDb__TseDDLColumnDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLForeignKeyElementDef methods */ +void tc_db__tse_ddlforeign_key_element_def__init + (TcDb__TseDDLForeignKeyElementDef *message); +size_t tc_db__tse_ddlforeign_key_element_def__get_packed_size + (const TcDb__TseDDLForeignKeyElementDef *message); +size_t tc_db__tse_ddlforeign_key_element_def__pack + (const TcDb__TseDDLForeignKeyElementDef *message, + uint8_t *out); +size_t tc_db__tse_ddlforeign_key_element_def__pack_to_buffer + (const TcDb__TseDDLForeignKeyElementDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLForeignKeyElementDef * + tc_db__tse_ddlforeign_key_element_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlforeign_key_element_def__free_unpacked + (TcDb__TseDDLForeignKeyElementDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLForeignKeyDef methods */ +void tc_db__tse_ddlforeign_key_def__init + (TcDb__TseDDLForeignKeyDef *message); +size_t tc_db__tse_ddlforeign_key_def__get_packed_size + (const TcDb__TseDDLForeignKeyDef *message); +size_t tc_db__tse_ddlforeign_key_def__pack + (const TcDb__TseDDLForeignKeyDef *message, + uint8_t *out); +size_t tc_db__tse_ddlforeign_key_def__pack_to_buffer + (const TcDb__TseDDLForeignKeyDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLForeignKeyDef * + tc_db__tse_ddlforeign_key_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlforeign_key_def__free_unpacked + (TcDb__TseDDLForeignKeyDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLTableKeyPart methods */ +void tc_db__tse_ddltable_key_part__init + (TcDb__TseDDLTableKeyPart *message); +size_t tc_db__tse_ddltable_key_part__get_packed_size + (const TcDb__TseDDLTableKeyPart *message); +size_t tc_db__tse_ddltable_key_part__pack + (const TcDb__TseDDLTableKeyPart *message, + uint8_t *out); +size_t tc_db__tse_ddltable_key_part__pack_to_buffer + (const TcDb__TseDDLTableKeyPart *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLTableKeyPart * + tc_db__tse_ddltable_key_part__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddltable_key_part__free_unpacked + (TcDb__TseDDLTableKeyPart *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLTableKey methods */ +void tc_db__tse_ddltable_key__init + (TcDb__TseDDLTableKey *message); +size_t tc_db__tse_ddltable_key__get_packed_size + (const TcDb__TseDDLTableKey *message); +size_t tc_db__tse_ddltable_key__pack + (const TcDb__TseDDLTableKey *message, + uint8_t *out); +size_t tc_db__tse_ddltable_key__pack_to_buffer + (const TcDb__TseDDLTableKey *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLTableKey * + tc_db__tse_ddltable_key__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddltable_key__free_unpacked + (TcDb__TseDDLTableKey *message, + ProtobufCAllocator *allocator); +/* TcDb__TseMsgCommDef methods */ +void tc_db__tse_msg_comm_def__init + (TcDb__TseMsgCommDef *message); +size_t tc_db__tse_msg_comm_def__get_packed_size + (const TcDb__TseMsgCommDef *message); +size_t tc_db__tse_msg_comm_def__pack + (const TcDb__TseMsgCommDef *message, + uint8_t *out); +size_t tc_db__tse_msg_comm_def__pack_to_buffer + (const TcDb__TseMsgCommDef *message, + ProtobufCBuffer *buffer); +TcDb__TseMsgCommDef * + tc_db__tse_msg_comm_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_msg_comm_def__free_unpacked + (TcDb__TseMsgCommDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLPartitionTableDef methods */ +void tc_db__tse_ddlpartition_table_def__init + (TcDb__TseDDLPartitionTableDef *message); +size_t tc_db__tse_ddlpartition_table_def__get_packed_size + (const TcDb__TseDDLPartitionTableDef *message); +size_t tc_db__tse_ddlpartition_table_def__pack + (const TcDb__TseDDLPartitionTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddlpartition_table_def__pack_to_buffer + (const TcDb__TseDDLPartitionTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLPartitionTableDef * + tc_db__tse_ddlpartition_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlpartition_table_def__free_unpacked + (TcDb__TseDDLPartitionTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLPartitionDef methods */ +void tc_db__tse_ddlpartition_def__init + (TcDb__TseDDLPartitionDef *message); +size_t tc_db__tse_ddlpartition_def__get_packed_size + (const TcDb__TseDDLPartitionDef *message); +size_t tc_db__tse_ddlpartition_def__pack + (const TcDb__TseDDLPartitionDef *message, + uint8_t *out); +size_t tc_db__tse_ddlpartition_def__pack_to_buffer + (const TcDb__TseDDLPartitionDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLPartitionDef * + tc_db__tse_ddlpartition_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlpartition_def__free_unpacked + (TcDb__TseDDLPartitionDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLCreateTableDef methods */ +void tc_db__tse_ddlcreate_table_def__init + (TcDb__TseDDLCreateTableDef *message); +size_t tc_db__tse_ddlcreate_table_def__get_packed_size + (const TcDb__TseDDLCreateTableDef *message); +size_t tc_db__tse_ddlcreate_table_def__pack + (const TcDb__TseDDLCreateTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddlcreate_table_def__pack_to_buffer + (const TcDb__TseDDLCreateTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLCreateTableDef * + tc_db__tse_ddlcreate_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlcreate_table_def__free_unpacked + (TcDb__TseDDLCreateTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterTablePorp methods */ +void tc_db__tse_ddlalter_table_porp__init + (TcDb__TseDDLAlterTablePorp *message); +size_t tc_db__tse_ddlalter_table_porp__get_packed_size + (const TcDb__TseDDLAlterTablePorp *message); +size_t tc_db__tse_ddlalter_table_porp__pack + (const TcDb__TseDDLAlterTablePorp *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_table_porp__pack_to_buffer + (const TcDb__TseDDLAlterTablePorp *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterTablePorp * + tc_db__tse_ddlalter_table_porp__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_table_porp__free_unpacked + (TcDb__TseDDLAlterTablePorp *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterTableDrop methods */ +void tc_db__tse_ddlalter_table_drop__init + (TcDb__TseDDLAlterTableDrop *message); +size_t tc_db__tse_ddlalter_table_drop__get_packed_size + (const TcDb__TseDDLAlterTableDrop *message); +size_t tc_db__tse_ddlalter_table_drop__pack + (const TcDb__TseDDLAlterTableDrop *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_table_drop__pack_to_buffer + (const TcDb__TseDDLAlterTableDrop *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterTableDrop * + tc_db__tse_ddlalter_table_drop__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_table_drop__free_unpacked + (TcDb__TseDDLAlterTableDrop *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterTableDropKey methods */ +void tc_db__tse_ddlalter_table_drop_key__init + (TcDb__TseDDLAlterTableDropKey *message); +size_t tc_db__tse_ddlalter_table_drop_key__get_packed_size + (const TcDb__TseDDLAlterTableDropKey *message); +size_t tc_db__tse_ddlalter_table_drop_key__pack + (const TcDb__TseDDLAlterTableDropKey *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_table_drop_key__pack_to_buffer + (const TcDb__TseDDLAlterTableDropKey *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterTableDropKey * + tc_db__tse_ddlalter_table_drop_key__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_table_drop_key__free_unpacked + (TcDb__TseDDLAlterTableDropKey *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterTableAlterColumn methods */ +void tc_db__tse_ddlalter_table_alter_column__init + (TcDb__TseDDLAlterTableAlterColumn *message); +size_t tc_db__tse_ddlalter_table_alter_column__get_packed_size + (const TcDb__TseDDLAlterTableAlterColumn *message); +size_t tc_db__tse_ddlalter_table_alter_column__pack + (const TcDb__TseDDLAlterTableAlterColumn *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_table_alter_column__pack_to_buffer + (const TcDb__TseDDLAlterTableAlterColumn *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterTableAlterColumn * + tc_db__tse_ddlalter_table_alter_column__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_table_alter_column__free_unpacked + (TcDb__TseDDLAlterTableAlterColumn *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterTableDef methods */ +void tc_db__tse_ddlalter_table_def__init + (TcDb__TseDDLAlterTableDef *message); +size_t tc_db__tse_ddlalter_table_def__get_packed_size + (const TcDb__TseDDLAlterTableDef *message); +size_t tc_db__tse_ddlalter_table_def__pack + (const TcDb__TseDDLAlterTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_table_def__pack_to_buffer + (const TcDb__TseDDLAlterTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterTableDef * + tc_db__tse_ddlalter_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_table_def__free_unpacked + (TcDb__TseDDLAlterTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLTruncateTableDef methods */ +void tc_db__tse_ddltruncate_table_def__init + (TcDb__TseDDLTruncateTableDef *message); +size_t tc_db__tse_ddltruncate_table_def__get_packed_size + (const TcDb__TseDDLTruncateTableDef *message); +size_t tc_db__tse_ddltruncate_table_def__pack + (const TcDb__TseDDLTruncateTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddltruncate_table_def__pack_to_buffer + (const TcDb__TseDDLTruncateTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLTruncateTableDef * + tc_db__tse_ddltruncate_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddltruncate_table_def__free_unpacked + (TcDb__TseDDLTruncateTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLTruncateTablePartitionDef methods */ +void tc_db__tse_ddltruncate_table_partition_def__init + (TcDb__TseDDLTruncateTablePartitionDef *message); +size_t tc_db__tse_ddltruncate_table_partition_def__get_packed_size + (const TcDb__TseDDLTruncateTablePartitionDef *message); +size_t tc_db__tse_ddltruncate_table_partition_def__pack + (const TcDb__TseDDLTruncateTablePartitionDef *message, + uint8_t *out); +size_t tc_db__tse_ddltruncate_table_partition_def__pack_to_buffer + (const TcDb__TseDDLTruncateTablePartitionDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLTruncateTablePartitionDef * + tc_db__tse_ddltruncate_table_partition_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddltruncate_table_partition_def__free_unpacked + (TcDb__TseDDLTruncateTablePartitionDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLRenameTableDef methods */ +void tc_db__tse_ddlrename_table_def__init + (TcDb__TseDDLRenameTableDef *message); +size_t tc_db__tse_ddlrename_table_def__get_packed_size + (const TcDb__TseDDLRenameTableDef *message); +size_t tc_db__tse_ddlrename_table_def__pack + (const TcDb__TseDDLRenameTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddlrename_table_def__pack_to_buffer + (const TcDb__TseDDLRenameTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLRenameTableDef * + tc_db__tse_ddlrename_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlrename_table_def__free_unpacked + (TcDb__TseDDLRenameTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLDropTableDef methods */ +void tc_db__tse_ddldrop_table_def__init + (TcDb__TseDDLDropTableDef *message); +size_t tc_db__tse_ddldrop_table_def__get_packed_size + (const TcDb__TseDDLDropTableDef *message); +size_t tc_db__tse_ddldrop_table_def__pack + (const TcDb__TseDDLDropTableDef *message, + uint8_t *out); +size_t tc_db__tse_ddldrop_table_def__pack_to_buffer + (const TcDb__TseDDLDropTableDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLDropTableDef * + tc_db__tse_ddldrop_table_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddldrop_table_def__free_unpacked + (TcDb__TseDDLDropTableDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterIndexDef methods */ +void tc_db__tse_ddlalter_index_def__init + (TcDb__TseDDLAlterIndexDef *message); +size_t tc_db__tse_ddlalter_index_def__get_packed_size + (const TcDb__TseDDLAlterIndexDef *message); +size_t tc_db__tse_ddlalter_index_def__pack + (const TcDb__TseDDLAlterIndexDef *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_index_def__pack_to_buffer + (const TcDb__TseDDLAlterIndexDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterIndexDef * + tc_db__tse_ddlalter_index_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_index_def__free_unpacked + (TcDb__TseDDLAlterIndexDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAutoExtendDef methods */ +void tc_db__tse_ddlauto_extend_def__init + (TcDb__TseDDLAutoExtendDef *message); +size_t tc_db__tse_ddlauto_extend_def__get_packed_size + (const TcDb__TseDDLAutoExtendDef *message); +size_t tc_db__tse_ddlauto_extend_def__pack + (const TcDb__TseDDLAutoExtendDef *message, + uint8_t *out); +size_t tc_db__tse_ddlauto_extend_def__pack_to_buffer + (const TcDb__TseDDLAutoExtendDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAutoExtendDef * + tc_db__tse_ddlauto_extend_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlauto_extend_def__free_unpacked + (TcDb__TseDDLAutoExtendDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLDataFileDef methods */ +void tc_db__tse_ddldata_file_def__init + (TcDb__TseDDLDataFileDef *message); +size_t tc_db__tse_ddldata_file_def__get_packed_size + (const TcDb__TseDDLDataFileDef *message); +size_t tc_db__tse_ddldata_file_def__pack + (const TcDb__TseDDLDataFileDef *message, + uint8_t *out); +size_t tc_db__tse_ddldata_file_def__pack_to_buffer + (const TcDb__TseDDLDataFileDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLDataFileDef * + tc_db__tse_ddldata_file_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddldata_file_def__free_unpacked + (TcDb__TseDDLDataFileDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLSpaceDef methods */ +void tc_db__tse_ddlspace_def__init + (TcDb__TseDDLSpaceDef *message); +size_t tc_db__tse_ddlspace_def__get_packed_size + (const TcDb__TseDDLSpaceDef *message); +size_t tc_db__tse_ddlspace_def__pack + (const TcDb__TseDDLSpaceDef *message, + uint8_t *out); +size_t tc_db__tse_ddlspace_def__pack_to_buffer + (const TcDb__TseDDLSpaceDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLSpaceDef * + tc_db__tse_ddlspace_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlspace_def__free_unpacked + (TcDb__TseDDLSpaceDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLDropSpaceDef methods */ +void tc_db__tse_ddldrop_space_def__init + (TcDb__TseDDLDropSpaceDef *message); +size_t tc_db__tse_ddldrop_space_def__get_packed_size + (const TcDb__TseDDLDropSpaceDef *message); +size_t tc_db__tse_ddldrop_space_def__pack + (const TcDb__TseDDLDropSpaceDef *message, + uint8_t *out); +size_t tc_db__tse_ddldrop_space_def__pack_to_buffer + (const TcDb__TseDDLDropSpaceDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLDropSpaceDef * + tc_db__tse_ddldrop_space_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddldrop_space_def__free_unpacked + (TcDb__TseDDLDropSpaceDef *message, + ProtobufCAllocator *allocator); +/* TcDb__TseDDLAlterSpaceDef methods */ +void tc_db__tse_ddlalter_space_def__init + (TcDb__TseDDLAlterSpaceDef *message); +size_t tc_db__tse_ddlalter_space_def__get_packed_size + (const TcDb__TseDDLAlterSpaceDef *message); +size_t tc_db__tse_ddlalter_space_def__pack + (const TcDb__TseDDLAlterSpaceDef *message, + uint8_t *out); +size_t tc_db__tse_ddlalter_space_def__pack_to_buffer + (const TcDb__TseDDLAlterSpaceDef *message, + ProtobufCBuffer *buffer); +TcDb__TseDDLAlterSpaceDef * + tc_db__tse_ddlalter_space_def__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void tc_db__tse_ddlalter_space_def__free_unpacked + (TcDb__TseDDLAlterSpaceDef *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*TcDb__TseDDLColumnDataTypeDef_Closure) + (const TcDb__TseDDLColumnDataTypeDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLColumnDef_Closure) + (const TcDb__TseDDLColumnDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLForeignKeyElementDef_Closure) + (const TcDb__TseDDLForeignKeyElementDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLForeignKeyDef_Closure) + (const TcDb__TseDDLForeignKeyDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLTableKeyPart_Closure) + (const TcDb__TseDDLTableKeyPart *message, + void *closure_data); +typedef void (*TcDb__TseDDLTableKey_Closure) + (const TcDb__TseDDLTableKey *message, + void *closure_data); +typedef void (*TcDb__TseMsgCommDef_Closure) + (const TcDb__TseMsgCommDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLPartitionTableDef_Closure) + (const TcDb__TseDDLPartitionTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLPartitionDef_Closure) + (const TcDb__TseDDLPartitionDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLCreateTableDef_Closure) + (const TcDb__TseDDLCreateTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterTablePorp_Closure) + (const TcDb__TseDDLAlterTablePorp *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterTableDrop_Closure) + (const TcDb__TseDDLAlterTableDrop *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterTableDropKey_Closure) + (const TcDb__TseDDLAlterTableDropKey *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterTableAlterColumn_Closure) + (const TcDb__TseDDLAlterTableAlterColumn *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterTableDef_Closure) + (const TcDb__TseDDLAlterTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLTruncateTableDef_Closure) + (const TcDb__TseDDLTruncateTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLTruncateTablePartitionDef_Closure) + (const TcDb__TseDDLTruncateTablePartitionDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLRenameTableDef_Closure) + (const TcDb__TseDDLRenameTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLDropTableDef_Closure) + (const TcDb__TseDDLDropTableDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterIndexDef_Closure) + (const TcDb__TseDDLAlterIndexDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLAutoExtendDef_Closure) + (const TcDb__TseDDLAutoExtendDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLDataFileDef_Closure) + (const TcDb__TseDDLDataFileDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLSpaceDef_Closure) + (const TcDb__TseDDLSpaceDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLDropSpaceDef_Closure) + (const TcDb__TseDDLDropSpaceDef *message, + void *closure_data); +typedef void (*TcDb__TseDDLAlterSpaceDef_Closure) + (const TcDb__TseDDLAlterSpaceDef *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCMessageDescriptor tc_db__tse_ddlcolumn_data_type_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlcolumn_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlforeign_key_element_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlforeign_key_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddltable_key_part__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddltable_key__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_msg_comm_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlpartition_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlpartition_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlcreate_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_porp__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_drop__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_drop_key__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_alter_column__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddltruncate_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddltruncate_table_partition_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlrename_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddldrop_table_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_index_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlauto_extend_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddldata_file_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlspace_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddldrop_space_def__descriptor; +extern const ProtobufCMessageDescriptor tc_db__tse_ddlalter_space_def__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_tc_5fdb_2eproto__INCLUDED */ diff --git a/storage/tianchi/protobuf/tc_db.proto b/storage/tianchi/protobuf/tc_db.proto new file mode 100644 index 0000000..375d0c7 --- /dev/null +++ b/storage/tianchi/protobuf/tc_db.proto @@ -0,0 +1,259 @@ +syntax = "proto3"; + +package tc_db; + +message TseDDLColumnDataTypeDef { + /* + * These definitions is same as the `typmode_t`; thus they should + * be replaced by typmode_t for unifying the definition of columns + */ + int32 datatype = 1; // ct_type_t + uint32 size = 2; + uint32 precision = 3; + int32 scale = 4; + int32 mysql_ori_datatype = 5; +} +message TseDDLColumnDef { + string name = 1; + TseDDLColumnDataTypeDef datatype = 2; + uint32 is_option_set = 4; + uint32 col_id = 5; + string cons_name = 6; + string ref_user = 10; + string ref_table = 11; + string default_text = 12; + string comment = 13; + uint32 alter_mode = 14; // tse_alter_column_alter_mode + uint64 collate = 15; + string new_name = 16; + uint32 is_unsigned = 17; + string default_func_name = 18; +} +message TseDDLForeignKeyElementDef { + string src_column_name = 1; + string ref_column_name = 2; +} +message TseDDLForeignKeyDef { + // fill_dd_foreign_keys_from_create_fields + string name = 1; + string unique_index_name = 2; + uint32 match_opt = 3; + uint32 update_opt = 4; + uint32 delete_opt = 5; + string referenced_table_schema_name = 6; + string referenced_table_name = 7; + repeated TseDDLForeignKeyElementDef elements = 8; +} +message TseDDLTableKeyPart { + // KEY_PART_INFO + string name = 1; + /* Length of key part in bytes, excluding NULL flag and length bytes */ + uint32 length = 2; + int32 datatype = 3; + bool is_func = 4; + string func_text = 5; + string func_name = 6; +} +message TseDDLTableKey { + // Key + string user = 1; + string table = 2; + string name = 3; + string space = 4; + int32 key_type = 5; // tse_key_type + int32 algorithm = 6; // tse_ha_key_alg + bool is_func = 7; + repeated TseDDLTableKeyPart columns = 8; + bool is_constraint = 9; + bool is_dsc = 10; +} +message TseMsgCommDef { + uint32 inst_id = 1; + uint32 thd_id = 2; + uint32 handler_id = 3; + uint64 sess_addr = 4; +} + +message TseDDLPartitionTableDef { + string name = 1; + repeated TseDDLPartitionTableDef subpart_table_list = 2; +} + +message TseDDLPartitionDef { + uint32 part_type = 1; + uint32 subpart_type = 2; + repeated TseDDLPartitionTableDef part_table_list = 3; +} + +message TseDDLCreateTableDef { + string schema = 1; + string name = 2; + string space = 3; + repeated TseDDLColumnDef columns = 4; + repeated TseDDLForeignKeyDef fk_list = 5; + repeated TseDDLTableKey key_list = 6; + uint64 auto_increment_value = 7; //init auto incremnet value + uint32 options = 8; // if not exists + string db_name = 9; + string sql_str = 10; + string alter_table_name = 11; + string alter_db_name = 12; + bool is_create_as_select = 13; + TseDDLPartitionDef partition_def = 14; +} + +message TseDDLAlterTablePorp { + // knl_alt_table_prop_t + string new_name = 1; + uint32 pctfree = 2; + uint32 appendonly = 3; + uint32 enable_row_move = 4; + uint32 shrink_opt = 5; + int64 serial_start = 6; +} + +message TseDDLAlterTableDrop { + string name = 1; + int32 drop_type = 2; // tse_alter_table_drop_type + int32 key_type = 3; // tse_key_type +} + +message TseDDLAlterTableDropKey { + string name = 1; + int32 drop_type = 2; // tse_alter_table_drop_type + int32 key_type = 3; // tse_key_type +} + +message TseDDLAlterTableAlterColumn { + string name = 1; + string new_name = 2; + uint32 type = 3; // SET_DEFAULT, DROP_DEFAULT, RENAME_COLUMN + bool has_no_default = 4; + bool has_default = 5; + bool is_default_null = 6; + string default_text = 7; +// string default_data = 8; +} + +message TseDDLAlterTableDef { + uint32 action = 1; // altable_action_t + uint32 options = 2; + string user = 3; + string name = 4; + /** + Columns, keys and constraints to be dropped. + */ + repeated TseDDLAlterTableDrop drop_list = 5; + // Columns for ALTER_COLUMN_CHANGE_DEFAULT. + repeated TseDDLAlterTableAlterColumn alter_list = 6; + // List of columns, used by both CREATE and ALTER TABLE. + repeated TseDDLColumnDef create_list = 7; + TseDDLAlterTablePorp table_def = 8; + repeated TseDDLTableKey add_key_list = 9; + repeated TseDDLAlterTableDropKey drop_key_list = 10; + repeated TseDDLForeignKeyDef add_foreign_key_list = 11; + uint64 new_auto_increment_value = 12; + string db_name = 13; + string sql_str = 14; + repeated TseDDLAlterIndexDef alter_index_list = 15; + repeated string drop_partition_names = 16; + repeated TseDDLPartitionTableDef add_part_list = 17; + uint32 hash_coalesce_count = 18; + int64 systimestamp = 19; + int32 tz_offset_UTC = 20; +} + +message TseDDLTruncateTableDef { + string schema = 1; + string name = 2; + string db_name = 4; + string sql_str = 5; + uint32 no_check_fk = 6; +} + +message TseDDLTruncateTablePartitionDef { + string user = 1; + string db_name = 2; + string table_name = 3; + repeated string partition_name = 4; + repeated uint32 partition_id = 5; + string sql_str = 6; + bool is_subpart = 7; + repeated string subpartition_name = 8; + repeated uint32 subpartition_id = 9; +} + +message TseDDLRenameTableDef { + uint32 action = 1; // altable_action_t + uint32 options = 2; + string user = 3; + string new_user = 4; + string new_table_name = 5; + string new_db_name = 6; + string old_table_name = 7; + string old_db_name = 8; + string current_db_name = 9; + string sql_str = 10; + repeated string old_constraints_name = 11; + repeated string new_constraints_name = 12; +} + +message TseDDLDropTableDef { + uint32 options = 1; + string user = 2; + string name = 3; + string dbname_und = 4; + string db_name = 5; + string sql_str = 6; +} + +message TseDDLAlterIndexDef { + string user = 1; + string name = 2; + uint32 type = 3; // def type + string table = 4; + string new_name = 5; + int32 key_type = 6; // tse_key_type +} + +message TseDDLAutoExtendDef { + bool enabled = 1; + uint64 nextsize = 2; + int64 maxsize = 3; +} + +message TseDDLDataFileDef { + string name = 1; + int64 size = 2; //device size + int32 block_size = 3; + TseDDLAutoExtendDef autoextend = 4; // the data of the autoextend property of the device + uint32 node_id = 5; +} + +message TseDDLSpaceDef { + string name = 1; // name of the space + uint32 type = 2; // type of the space + bool in_memory = 3; + bool autooffline = 4; + uint32 extent_size = 5; + repeated TseDDLDataFileDef datafiles_list = 6; + uint32 flags = 7; + string db_name = 8; + string sql_str = 9; +} + +message TseDDLDropSpaceDef { + string obj_name = 1; + uint32 option = 2; + string db_name = 3; + string sql_str = 4; +} + +message TseDDLAlterSpaceDef { + uint32 action = 1; + string name = 2; // name of the space + string new_name = 3; // name of the new space + uint64 auto_extend_size = 4; + string db_name = 5; + string sql_str = 6; +} diff --git a/storage/tianchi/srv_mq_msg.h b/storage/tianchi/srv_mq_msg.h new file mode 100644 index 0000000..e4e1297 --- /dev/null +++ b/storage/tianchi/srv_mq_msg.h @@ -0,0 +1,427 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SRV_MQ_MSG__ +#define SRV_MQ_MSG__ + +#include "tse_srv.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +#define SHM_SEG_MAX_NUM 64 +#define TSE_MAX_COLUMNS 4096 // CT_MAX_COLUMNS +#define INDEX_KEY_SIZE 4096 // 索引查询条件的大小mysql限制为3072,取4096 +#define MAX_PREFETCH_REC_NUM 100 +#define REQUEST_SIZE (MAX_RECORD_SIZE + (2 * MAX_PREFETCH_REC_NUM) + 24) // 根据rnd_prefetch_request计算, 取8字节对齐 +#define TSE_MQ_MESSAGE_SLICE_LEN 102400 + +#define MAX_LOB_LOCATOR_SIZE 4000 // 存储引擎存储blob对象结构体最大长度 +#define MAX_MESSAGE_SIZE 491520 // 共享内存最大可申请空间大小 + +#define REG_MISMATCH_CTC_VERSION 501 +#define REG_ALLOC_INST_ID_FAILED 502 + +struct register_instance_request { + uint32_t ctc_version; // ctc支持多版本的接口,格式为1.1.3=1001003,00作为点标记 + int group_num; + int cpu_info[SHM_SEG_MAX_NUM][SMALL_RECORD_SIZE]; + int result; +}; + +struct close_session_request { + tianchi_handler_t tch; + int result; +}; + +struct open_table_request { + char table_name[SMALL_RECORD_SIZE]; + char user_name[SMALL_RECORD_SIZE]; + tianchi_handler_t tch; + int result; +}; + +struct close_table_request { + tianchi_handler_t tch; + int result; +}; + +struct write_row_request { + uint16_t record_len; + uint8_t *record; + int result; + tianchi_handler_t tch; + uint16_t serial_column_offset; + uint64_t last_insert_id; + dml_flag_t flag; +}; + +struct bulk_write_request { + int result; + tianchi_handler_t tch; + uint16_t record_len; + uint64_t record_num; + uint32_t err_pos; + uint8_t record[MAX_RECORD_SIZE]; + dml_flag_t flag; + ctc_part_t part_ids[MAX_BULK_INSERT_PART_ROWS]; +}; + +struct update_row_request { + tianchi_handler_t tch; + uint16_t new_record_len; + uint8_t *new_record; + uint16_t upd_cols[TSE_MAX_COLUMNS]; + uint16_t col_num; + int result; + dml_flag_t flag; +}; + +struct delete_row_request { + tianchi_handler_t tch; + uint16_t record_len; + int result; + dml_flag_t flag; +}; + +struct rnd_init_request { + tianchi_handler_t tch; + int result; + expected_cursor_action_t action; + tse_select_mode_t mode; + tse_conds *cond; +}; + +struct rnd_end_request { + tianchi_handler_t tch; + int result; +}; + +struct scan_records_request { + tianchi_handler_t tch; + uint64_t num_rows; + char index_name[TSE_MAX_KEY_NAME_LENGTH]; // 索引名 + int result; +}; + +struct rnd_next_request { + tianchi_handler_t tch; + uint16_t record_len; + uint8_t *record; + int result; +}; + +struct rnd_prefetch_request { + tianchi_handler_t tch; + int result; + int max_row_size; + uint8_t records[MAX_RECORD_SIZE]; + uint16_t record_lens[MAX_PREFETCH_REC_NUM]; + uint32_t recNum[1]; + uint64_t rowids[MAX_PREFETCH_REC_NUM]; +}; + +struct trx_begin_request { + tianchi_handler_t tch; + int result; + tianchi_trx_context_t trx_context; + bool is_mysql_local; +}; + +struct trx_commit_request { + tianchi_handler_t tch; + int result; + bool is_ddl_commit; + int32_t csize; + uint64_t *cursors; +}; + +struct trx_rollback_request { + tianchi_handler_t tch; + int result; + int32_t csize; + uint64_t *cursors; +}; + +struct lock_table_request { + char db_name[SMALL_RECORD_SIZE]; + tse_lock_table_info lock_info; + tianchi_handler_t tch; + int result; + uint32_t mysql_inst_id; + int error_code; + char error_message[ERROR_MESSAGE_LEN]; +}; + + +struct pre_create_db_request { + tianchi_handler_t tch; + char sql_str[MAX_DDL_SQL_LEN]; + char db_name[SMALL_RECORD_SIZE]; + uint32_t tse_db_datafile_size; + bool tse_db_datafile_autoextend; + uint32_t tse_db_datafile_extend_size; + int error_code; + char error_message[SMALL_RECORD_SIZE]; + int result; +}; + +struct drop_tablespace_and_user_request { + tianchi_handler_t tch; + char db_name[SMALL_RECORD_SIZE]; + char sql_str[MAX_DDL_SQL_LEN]; + char user_name[SMALL_RECORD_SIZE]; + char user_ip[SMALL_RECORD_SIZE]; + int error_code; + char error_message[SMALL_RECORD_SIZE]; + int result; +}; + +struct drop_db_pre_check_request { + tianchi_handler_t tch; + char db_name[SMALL_RECORD_SIZE]; + int result; + int error_code; + char error_message[ERROR_MESSAGE_LEN]; +}; + +struct srv_set_savepoint_request { + char name[SMALL_RECORD_SIZE]; + tianchi_handler_t tch; + int result; +}; + +struct srv_rollback_savepoint_request { + char name[SMALL_RECORD_SIZE]; + tianchi_handler_t tch; + int result; + int32_t csize; + uint64_t *cursors; +}; + +struct srv_release_savepoint_request { + char name[SMALL_RECORD_SIZE]; + tianchi_handler_t tch; + int result; +}; + +struct index_key_info { + uint32_t key_lens[MAX_KEY_COLUMNS]; + uint32_t key_offsets[MAX_KEY_COLUMNS]; +}; + +struct index_read_request { + bool sorted; + bool need_init; + uint8_t *record; + uint16_t record_len; + uint16_t find_flag; + char index_name[TSE_MAX_KEY_NAME_LENGTH + 1]; + uint16_t key_num; + int action; + int result; + bool is_key_null[MAX_KEY_COLUMNS]; + uint8_t left_key_record[INDEX_KEY_SIZE]; + uint8_t right_key_record[INDEX_KEY_SIZE]; + struct index_key_info left_key_info; + struct index_key_info right_key_info; + tianchi_handler_t tch; + tse_select_mode_t mode; + tse_conds *cond; + bool is_replace; +}; + +struct index_end_request { + tianchi_handler_t tch; + int result; +}; + +struct general_fetch_request { + tianchi_handler_t tch; + uint16_t record_len; + uint8_t *record; + int result; +}; + +struct general_prefetch_request { + tianchi_handler_t tch; + int result; + int max_row_size; + uint8_t records[MAX_RECORD_SIZE]; + uint16_t record_lens[MAX_PREFETCH_REC_NUM]; + uint32_t recNum[1]; + uint64_t rowids[MAX_PREFETCH_REC_NUM]; +}; + +struct free_session_cursors_request { + tianchi_handler_t tch; + int result; + int32_t csize; + uint64_t *cursors; +}; + +struct get_index_slot_request { + tianchi_handler_t tch; + int result; + char index_name[TSE_MAX_KEY_NAME_LENGTH + 1]; +}; + +struct rnd_pos_request { + tianchi_handler_t tch; + uint16_t record_len; + uint8_t *record; + uint16_t pos_length; + uint8_t position[SMALL_RECORD_SIZE]; + int result; +}; + +struct position_request { + tianchi_handler_t tch; + uint16_t pos_length; + uint8_t position[SMALL_RECORD_SIZE]; + int result; +}; + +struct delete_all_rows_request { + tianchi_handler_t tch; + int result; + dml_flag_t flag; +}; + +struct knl_write_lob_request { + tianchi_handler_t tch; + char locator[MAX_LOB_LOCATOR_SIZE]; + int column_id; + uint32_t data_len; + bool force_outline; + int result; + char data[0]; +}; + +struct knl_read_lob_request { + tianchi_handler_t tch; + char locator[MAX_LOB_LOCATOR_SIZE]; + uint32_t offset; + uint32_t size; + uint32_t read_size; + int result; + char buf[0]; +}; + +struct get_max_session_request { + uint32_t max_sessions; +}; + +struct analyze_table_request { + tianchi_handler_t tch; + char table_name[SMALL_RECORD_SIZE]; + char user_name[SMALL_RECORD_SIZE]; + double ratio; + int result; +}; + +struct get_cbo_stats_request { + int result; + tianchi_handler_t tch; + tianchi_cbo_stats_t *stats; +}; + +struct get_serial_val_request { + tianchi_handler_t tch; + uint64_t value; + int result; + dml_flag_t flag; +}; + +struct close_mysql_connection_request { + uint32_t thd_id; + uint32_t inst_id; + int result; +}; + +struct tse_lock_tables_request { + tianchi_handler_t tch; + char db_name[SMALL_RECORD_SIZE]; + tse_lock_table_info lock_info; + int err_code; + int result; +}; + +struct tse_unlock_tables_request { + tianchi_handler_t tch; + int result; + uint32_t mysql_inst_id; + tse_lock_table_info lock_info; +}; + +struct check_table_exists_request { + char db[SMALL_RECORD_SIZE]; + char name[SMALL_RECORD_SIZE]; + bool is_exists; + int result; +}; + +struct search_metadata_status_request { + bool metadata_switch; + bool cluster_ready; + int result; +}; + +struct execute_ddl_mysql_sql_request { + tse_ddl_broadcast_request broadcast_req; + uint32_t thd_id; + int result; + bool allow_fail; +}; + +struct execute_mysql_ddl_sql_request { + tse_ddl_broadcast_request broadcast_req; + tianchi_handler_t tch; + int result; + bool allow_fail; +}; + +struct lock_instance_request { + bool is_mysqld_starting; + tse_lock_table_mode_t lock_type; + tianchi_handler_t tch; + int result; +}; + +struct unlock_instance_request { + bool is_mysqld_starting; + tianchi_handler_t tch; + int result; +}; + +struct invalidate_mysql_dd_request { + tse_invalidate_broadcast_request broadcast_req; + tianchi_handler_t tch; + int err_code; + int result; +}; + +void* alloc_share_mem(void* shm_inst, uint32_t mem_size); + +void free_share_mem(void* shm_inst, void* shm_mem); + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ + +#endif diff --git a/storage/tianchi/tse_cbo.cc b/storage/tianchi/tse_cbo.cc new file mode 100644 index 0000000..95bf3fe --- /dev/null +++ b/storage/tianchi/tse_cbo.cc @@ -0,0 +1,231 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "tse_cbo.h" +#include "ha_tse.h" +#include "tse_log.h" +#include "sql/field.h" +#include "tse_srv_mq_module.h" + +void r_key2variant(tse_range_key *rKey, KEY_PART_INFO *cur_index_part, cache_variant_t *ret_val) { + enum_field_types field_type = cur_index_part->field->real_type(); + + uint16_t offset = 0; + if (cur_index_part->field->is_nullable()) { + offset = 1; + } + + ret_val->is_null = 0; + ret_val->type = field_type; + + switch(field_type) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + ret_val->v_int = *(int32_t *)const_cast(rKey->key + offset); + break; + case MYSQL_TYPE_FLOAT: + ret_val->v_real = *(float *)const_cast(rKey->key + offset); + break; + case MYSQL_TYPE_DOUBLE: + ret_val->v_real = *(double *)const_cast(rKey->key + offset); + break; + case MYSQL_TYPE_LONGLONG: + ret_val->v_bigint = *(int64_t *)const_cast(rKey->key + offset); + break; + default: + ret_val->is_null = 1; + break; + } +} + +double eval_density_result(cache_variant_t *result) +{ + /* + * key range is beyond the actual index range, + * don't have any records in this range + */ + if (result->v_real < 0) { + return 0; + } + /* + * key range is larger than the actual index range, + * any key with this range shoule be deemed as not selective + */ + if (result->v_real > 1) { + return 1; + } + return result->v_real; +} + +int calc_density_low(KEY_PART_INFO *cur_index_part, cache_variant_t *high_val, cache_variant_t *low_val, + cache_variant_t *left_val, cache_variant_t *right_val, cache_variant_t *result) +{ + double density = DEFAULT_RANGE_DENSITY; + if (low_val->is_null == 1 || right_val->is_null == 1) { + return ERR_SQL_SYNTAX_ERROR; + } + + enum_field_types field_type = cur_index_part->field->real_type(); + + double numerator, denominator; + switch(field_type) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + numerator = (int64_t)left_val->v_int - (int64_t)right_val->v_int; + denominator = (int64_t)high_val->v_int - (int64_t)low_val->v_int; + density = (double)numerator/(double)denominator; + break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + numerator = left_val->v_real - right_val->v_real; + denominator = high_val->v_real - low_val->v_real; + density = (double)numerator/(double)denominator; + break; + case MYSQL_TYPE_LONGLONG: + numerator = (int64_t)left_val->v_bigint - (int64_t)right_val->v_bigint; + denominator = (int64_t)high_val->v_bigint - (int64_t)low_val->v_bigint; + density = (double)numerator/(double)denominator; + break; + default: + break; + } + + result->v_real = density; + + return CT_SUCCESS; +} + +double calc_density_by_cond(tianchi_cbo_stats_t *cbo_stats, KEY *cur_index, + tse_range_key *tse_min_key, tse_range_key *tse_max_key, part_info_t part_info) { + double default_density = DEFAULT_RANGE_DENSITY; + KEY_PART_INFO cur_index_part = cur_index->key_part[0]; + uint32 col_id = cur_index_part.field->field_index(); + uint32_t part_id = part_info.part_id; + uint32_t subpart_id = part_info.subpart_id; + uint32_t total_part_count = IS_TSE_PART(subpart_id) ? part_info.part_num * part_info.subpart_num : part_info.part_num; + + if (!IS_TSE_PART(part_id) && cbo_stats->tse_cbo_stats_table.num_distincts[col_id] == 0) { + return DEFAULT_RANGE_DENSITY; + } + + uint32 index_no = (IS_TSE_PART(part_id) & IS_TSE_PART(subpart_id)) ? + (total_part_count * col_id) + (part_id * part_info.subpart_num + subpart_id) : + total_part_count * col_id + part_id; + + if (IS_TSE_PART(part_id) && cbo_stats->tse_cbo_stats_table.part_table_num_distincts[index_no] == 0) { + return DEFAULT_RANGE_DENSITY; + } + + cache_variant_t *low_val, *high_val; + cache_variant_t result; + + if (IS_TSE_PART(part_id)) { + low_val = &(cbo_stats->tse_cbo_stats_table.part_table_low_values[index_no]); + high_val = &(cbo_stats->tse_cbo_stats_table.part_table_high_values[index_no]); + } else { + low_val = cbo_stats->tse_cbo_stats_table.low_values + col_id; + high_val = cbo_stats->tse_cbo_stats_table.high_values + col_id; + } + + if (tse_min_key->cmp_type == CMP_TYPE_GREAT && tse_max_key->cmp_type == CMP_TYPE_LESS) { + cache_variant_t min_key_val, max_key_val; + r_key2variant(tse_min_key, &cur_index_part, &min_key_val); + r_key2variant(tse_max_key, &cur_index_part, &max_key_val); + + if (calc_density_low(&cur_index_part, high_val, low_val, &max_key_val, &min_key_val, &result) != CT_SUCCESS) { + return default_density; + } + return eval_density_result(&result); + } + + if (tse_min_key->cmp_type == CMP_TYPE_GREAT) { + cache_variant_t min_key_val; + r_key2variant(tse_min_key, &cur_index_part, &min_key_val); + + if (calc_density_low(&cur_index_part, high_val, low_val, high_val, &min_key_val, &result) != CT_SUCCESS) { + return default_density; + } + return eval_density_result(&result); + } + + if (tse_max_key->cmp_type == CMP_TYPE_LESS) { + cache_variant_t max_key_val; + r_key2variant(tse_max_key, &cur_index_part, &max_key_val); + + if (calc_density_low(&cur_index_part, high_val, low_val, &max_key_val, low_val, &result) != CT_SUCCESS) { + return default_density; + } + return eval_density_result(&result); + } + + return default_density; +} + +double calc_density_one_table(uint16_t idx_id, tse_range_key *min_key, tse_range_key *max_key, + part_info_t part_info, tianchi_cbo_stats_t *cbo_stats, const TABLE &table) +{ + double density = DEFAULT_RANGE_DENSITY; + if (!cbo_stats->is_updated) { + tse_log_debug("table %s has not been analyzed", table.alias); + return density; + } + uint32_t part_id = part_info.part_id; + uint32_t subpart_id = part_info.subpart_id; + uint32_t total_part_count = IS_TSE_PART(subpart_id) ? part_info.part_num * part_info.subpart_num : part_info.part_num; + + uint32 col_id; + if (min_key->cmp_type == CMP_TYPE_EQUAL) { + double col_product = 1.0; + uint64_t col_map = min_key->col_map; + KEY cur_index = table.key_info[idx_id]; + /* + * For all columns in used index, + * density = 1.0 / (column[0]->num_distinct * ... * column[n]->num_distinct) + */ + for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts; idx_col_num++) { + if (col_map & ((uint64_t)1 << idx_col_num)) { + KEY_PART_INFO cur_index_part = cur_index.key_part[idx_col_num]; + col_id = cur_index_part.field->field_index(); + if (!IS_TSE_PART(part_id) && cbo_stats->tse_cbo_stats_table.num_distincts[col_id] != 0) { + col_product = col_product * cbo_stats->tse_cbo_stats_table.num_distincts[col_id]; + } + + uint32 index_no = (IS_TSE_PART(part_id) & IS_TSE_PART(subpart_id)) ? + (total_part_count * col_id) + (part_id * part_info.subpart_num + subpart_id) : + total_part_count * col_id + part_id; + + if (IS_TSE_PART(part_id) && cbo_stats->tse_cbo_stats_table.part_table_num_distincts[index_no] != 0) { + col_product = col_product * cbo_stats->tse_cbo_stats_table.part_table_num_distincts[index_no]; + } + } + } + density = 1.0 / col_product; + } else { + KEY cur_index = table.key_info[idx_id]; + density = calc_density_by_cond(cbo_stats, &cur_index, min_key, max_key, part_info); + } + /* + * This is a safe-guard logic since we don't handle tse call error in this method, + * we need this to make sure that our optimizer continue to work even when we + * miscalculated the density, and it's still prefer index read + */ + if (density < 0.0 || density > 1.0) { + density = PREFER_RANGE_DENSITY; + } + return density; +} \ No newline at end of file diff --git a/storage/tianchi/tse_cbo.h b/storage/tianchi/tse_cbo.h new file mode 100644 index 0000000..4fee771 --- /dev/null +++ b/storage/tianchi/tse_cbo.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __TSE_CBO_H__ +#define __TSE_CBO_H__ + +#include "tse_srv.h" +#include "sql/table.h" +#include "sql/dd/types/table.h" +#include "srv_mq_msg.h" + + +typedef enum en_tse_cmp_type { + CMP_TYPE_UNKNOWN = 0, + CMP_TYPE_EQUAL, + CMP_TYPE_GREAT, + CMP_TYPE_LESS +} tse_cmp_type_t; + +/* range key type */ +typedef struct { + const char *key; + uint len; + tse_cmp_type_t cmp_type; + uint64_t col_map; +} tse_range_key; + +typedef struct { + uint32_t part_id; + uint32_t subpart_id; + uint32_t part_num; + uint32_t subpart_num; +} part_info_t; + +double calc_density_one_table(uint16_t idx_id, tse_range_key *min_key, tse_range_key *max_key, + part_info_t part_info, tianchi_cbo_stats_t *cbo_stats, const TABLE &table); + +#endif diff --git a/storage/tianchi/tse_ddl_rewriter_plugin.cc b/storage/tianchi/tse_ddl_rewriter_plugin.cc new file mode 100644 index 0000000..5470b10 --- /dev/null +++ b/storage/tianchi/tse_ddl_rewriter_plugin.cc @@ -0,0 +1,1324 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "my_inttypes.h" +#include "my_psi_config.h" +#include "my_thread.h" // my_thread_handle needed by mysql_memory.h +#include "sql/sql_class.h" +#include "sql/sql_lex.h" +#include "sql/sql_error.h" +#include "tse_log.h" +#include "tse_srv.h" +#include "tse_util.h" +#include "tse_proxy_util.h" +#include "tse_error.h" +#include "ha_tse.h" +#include "ha_tse_ddl.h" +#include "sql/sql_initialize.h" // opt_initialize_insecure +#include "sql/sql_list.h" +#include "sql/set_var.h" +#include "sql/dd/types/schema.h" +#include "sql/dd/cache/dictionary_client.h" +#include "sql/lock.h" +#include "sql/auth/auth_common.h" +#include +#include +#include "sql/sql_tablespace.h" +#include "sql/sql_lex.h" +#include "sql/sql_db.h" // check_schema_readonly +#include "sql/sql_backup_lock.h" +#include "mysql/plugin_auth.h" +#include "sql/auth/sql_auth_cache.h" +#include "sql/auth/auth_internal.h" +#include "sql/sql_parse.h" + +using namespace std; + +static SYS_VAR *tse_rewriter_system_variables[] = { + nullptr +}; + +extern uint32_t tse_instance_id; + +static bool is_current_system_var(set_var *setvar) { + Item_func_get_system_var *itemFunc = dynamic_cast(setvar->value); + if (setvar->value == nullptr || itemFunc) { + return true; + } + return false; +} + +typedef int (*check_variable_fn)(set_var *setvar, bool &need_forward, string user_val_str); + +int check_default_engine(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unused)), string user_val_str) { + if (is_current_system_var(setvar)) { + return 0; + } + + if (setvar->value->item_name.ptr() == nullptr) { + if (user_val_str == "") { + return 0; + } + + transform(user_val_str.begin(), user_val_str.end(), user_val_str.begin(), ::tolower); + if (user_val_str == "ctc" || user_val_str == "default") { + return 0; + } + + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Once the CTC is loaded, it must be set as the default engine. To modify the setting, uninstall the CTC first."); + return -1; + } + + if (strcasecmp(setvar->value->item_name.ptr(), tse_hton_name) != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Once the CTC is loaded, it must be set as the default engine. To modify the setting, uninstall the CTC first."); + return -1; + } + return 0; +} + +int check_session_pool_volume(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unused)), string user_val_str) { + if (is_current_system_var(setvar)) { + return 0; + } + + uint max_sessions; + if (tse_get_max_sessions_per_node(&max_sessions)) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Get max connections in Cantian failed"); + return -1; + } + + if (setvar->value->item_name.ptr() == nullptr) { + if (user_val_str == "") { + return 0; + } + + if (!isdigit(*user_val_str.c_str())) { + my_printf_error(ER_DISALLOWED_OPERATION, "[CTC]:Please make sure value is digits.", MYF(0)); + return -1; + } + + int tmp_max_connection = atoi(user_val_str.c_str()); + if (tmp_max_connection > (int)max_sessions) { + my_printf_error(ER_DISALLOWED_OPERATION, "Current SE can only provide %d connections for one mysql-server", MYF(0), max_sessions); + return -1; + } else if (tmp_max_connection < 1) { + my_printf_error(ER_DISALLOWED_OPERATION, "Current SE cannot provide less than one connection.", MYF(0)); + return -1; + } + return 0; + } + + int num_max_conns = atoi(setvar->value->item_name.ptr()); + if (num_max_conns > (int)max_sessions) { + my_printf_error(ER_DISALLOWED_OPERATION, "Current SE can only provide %d connections for one mysql-server", MYF(0), max_sessions); + return -1; + } else if (num_max_conns < 1) { + my_printf_error(ER_DISALLOWED_OPERATION, "Current SE cannot provide less than one connection.", MYF(0)); + return -1; + } + return 0; +} + +int not_allow_modify(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unused)), + string user_val_str MY_ATTRIBUTE((unused))) { + if (is_current_system_var(setvar)) { + return 0; + } + + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "CTC doesn't support modifying the variable"); + return -1; +} + +/* + 参考 Sys_var_transaction_isolation::session_update 和 Sys_var_typelib::do_check(). + transaction_isolation 只支持设置为READ_COMMITTED +*/ +int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unused)), string user_val_str) { + if (is_current_system_var(setvar)) { + return 0; + } + + if (setvar->value->result_type() == STRING_RESULT) { + // 对应 SET @@global.transaction_isolation = @global_start_value;的写法 + if (setvar->value->item_name.ptr() == nullptr) { + transform(user_val_str.begin(), user_val_str.end(), user_val_str.begin(), ::tolower); + if (user_val_str == "read-committed" || user_val_str == "1") { + return 0; + } else if (user_val_str == "repeatable-read" || user_val_str == "2") { + push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); + return 0; + } + + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "CTC STORAGE ENGINE ONLY SUPPORT READ_COMMITTED TRANSACTION ISOLATION LEVEL."); + return -1; + } + + // 对应set transaction_isolation='read-committed' 写法 + if (strcasecmp(setvar->value->item_name.ptr(), "read-committed") == 0) { + return 0; + } else if (strcasecmp(setvar->value->item_name.ptr(), "repeatable-read") == 0) { + push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); + return 0; + } + } else { + // 对应SET TRANSACTION ISOLATION LEVEL READ COMMITTED 写法 + enum_tx_isolation tx_isol = (enum_tx_isolation)setvar->value->val_int(); + if (tx_isol == ISO_READ_COMMITTED) { + return 0; + } else if (tx_isol == ISO_REPEATABLE_READ) { + push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); + return 0; + } + } + + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "CTC STORAGE ENGINE ONLY SUPPORT READ_COMMITTED TRANSACTION ISOLATION LEVEL."); + return -1; +} + +int tse_check_opt_forward(set_var *setvar MY_ATTRIBUTE((unused)), bool &need_forward, + string user_val_str MY_ATTRIBUTE((unused))) { + need_forward = false; + push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + "CTC: This parameter will not be broadcast to other nodes."); + return 0; +} + +static std::unordered_map set_variable_rules_map = { + {"default_storage_engine", check_default_engine}, + {"max_connections", check_session_pool_volume}, + {"transaction_isolation", unsupport_tx_isolation_level}, + {"read_only", tse_check_opt_forward}, + {"super_read_only", tse_check_opt_forward}, + {"offline_mode", tse_check_opt_forward}, + {"gtid_next", tse_check_opt_forward} +}; + +static int tse_get_user_var_string(MYSQL_THD thd, Item_func_get_user_var *itemFunc, string &user_val_str) { + mysql_mutex_lock(&thd->LOCK_thd_data); + + String str; + user_var_entry *var_entry; + var_entry = find_or_nullptr(thd->user_vars, itemFunc->name.ptr()); + if (var_entry == nullptr) { + tse_log_system("user var:%s have no value. no need to broadcast.", itemFunc->name.ptr()); + my_printf_error(ER_DISALLOWED_OPERATION, "[CTC]:Please make sure %s has value in it.", MYF(0), itemFunc->name.ptr()); + mysql_mutex_unlock(&thd->LOCK_thd_data); + return -1; + } + + bool is_var_null; + String *var_value = var_entry->val_str(&is_var_null, &str, DECIMAL_NOT_SPECIFIED); + + mysql_mutex_unlock(&thd->LOCK_thd_data); + + if (!is_var_null) { + user_val_str = string(var_value->c_ptr_safe()); + } + + return 0; +} + +static int allow_sqlcmd(MYSQL_THD thd, string session_var_name) { + String str; + user_var_entry *var_entry = find_or_nullptr(thd->user_vars, session_var_name); + if(var_entry == nullptr || var_entry->ptr() == nullptr) { + return 0; + } + bool is_var_null; + longlong var_value = var_entry->val_int(&is_var_null); + String *var_value_str = var_entry->val_str(&is_var_null, &str, DECIMAL_NOT_SPECIFIED); + string var_str = var_value_str->c_ptr_safe(); + transform(var_str.begin(), var_str.end(), var_str.begin(), ::tolower); + if (!is_var_null && (var_value == 1L || (var_str == "true"))) { + return -1; + } + return 0; +} + +static int tse_check_dcl(string &, MYSQL_THD thd, bool &need_forward) { + if (check_readonly(thd, true) || + (thd->lex->query_tables != nullptr && + check_schema_readonly(thd, thd->lex->query_tables->table_name))) { + need_forward = false; + } + if (allow_sqlcmd(thd, "ctc_dcl_disabled") != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "DCL query is not allowed (ctc_dcl_disabled = true)"); + return -1; + } + return 0; +} + +// reference for 'validate_password_require_current' function +int tse_verify_password4existed_user(MYSQL_THD thd, const LEX_USER *existed_user, bool &res) { + ACL_USER *acl_user = nullptr; + plugin_ref plugin = nullptr; + int is_error = 0; + Acl_cache_lock_guard acl_cache_lock(thd, Acl_cache_lock_mode::WRITE_MODE); + if (!acl_cache_lock.lock()) { + tse_log_error("tse_verify_password failed, lock acl cache failed"); + return -1; + } + acl_user = find_acl_user(existed_user->host.str, existed_user->user.str, true); + if (!acl_user) { + tse_log_error("tse_verify_password failed, find acl user failed"); + return -1; + } + plugin = my_plugin_lock_by_name(nullptr, acl_user->plugin, MYSQL_AUTHENTICATION_PLUGIN); + if (!plugin) { + tse_log_error("tse_verify_password failed, lock plugin %s failed", acl_user->plugin.str ? acl_user->plugin.str : ""); + return -1; + } + st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; + + if (acl_user->credentials[PRIMARY_CRED].m_auth_string.length == 0 && existed_user->current_auth.length > 0) { + res = false; + } else if ((auth->authentication_flags & AUTH_FLAG_USES_INTERNAL_STORAGE) && auth->compare_password_with_hash && + auth->compare_password_with_hash(acl_user->credentials[PRIMARY_CRED].m_auth_string.str, + (unsigned long)acl_user->credentials[PRIMARY_CRED].m_auth_string.length, existed_user->current_auth.str, + (unsigned long)existed_user->current_auth.length, &is_error) && !is_error) { + res = false; + } + res = true; + plugin_unlock(nullptr, plugin); + return 0; +} + +void tse_remove_replace_clause4sql(string &sql_str) { + // match: replace "xxx" | replace 'xxx' + regex replace_pattern(" \\s*replace \\s*(\".*\"|'.*')", std::regex_constants::icase); + sql_str = regex_replace(sql_str, replace_pattern, " "); +} + +/* + to adapt TSE broadcast: + 1. alter user current_user() -> alter user 'user'@'host' + 2. alter user current user && replace 'old password', we need check the old password to remove the 'replace clause' +*/ +static int tse_rewrite_alter_user4update_passwd(MYSQL_THD thd, string &sql_str) { + List_iterator user_list(thd->lex->users_list); + LEX_USER *tmp_user; + LEX_USER *user; + bool existed_other_user_with_replace = false; + string rw_query_sql = sql_str; + Security_context *sctx = thd->security_context(); + while ((tmp_user = user_list++)) { + /* If it is an empty lex_user update it with current user */ + if (!tmp_user->host.str && !tmp_user->user.str) { + assert(sctx->priv_host().str); + tmp_user->host.str = sctx->priv_host().str; + tmp_user->host.length = strlen(sctx->priv_host().str); + assert(sctx->user().str); + tmp_user->user.str = sctx->user().str; + tmp_user->user.length = strlen(sctx->user().str); + } + user = get_current_user(thd, tmp_user); + bool is_self = !strcmp(sctx->user().length ? sctx->user().str : "", user->user.str) && + !my_strcasecmp(&my_charset_latin1, user->host.str, sctx->priv_host().str); + if (user->uses_replace_clause) { + if (is_self) { + bool is_password_matched = false; + if (tse_verify_password4existed_user(thd, user, is_password_matched)) { + return -1; + } + if (!is_password_matched) { + my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); + return -1; + } + } else { + existed_other_user_with_replace = true; + } + } + } + if (!existed_other_user_with_replace) { + tse_remove_replace_clause4sql(rw_query_sql); + } + regex current_user_pattern(" \\s*current_user[(][)] ", regex_constants::icase); + string current_user_name(sctx->user().str); + current_user_name = tse_deserilize_username_with_single_quotation(current_user_name); + string user2host(""); + user2host = " '" + current_user_name + "'@'" + string(sctx->priv_host().str) + "'"; + rw_query_sql = regex_replace(rw_query_sql, current_user_pattern, user2host.c_str()); + sql_str = rw_query_sql; + return 0; +} + +static int tse_check_alter_user(string &sql_str, MYSQL_THD thd, bool &need_forward) { + if (tse_check_dcl(sql_str, thd, need_forward) != 0) { + return -1; + } + + return tse_rewrite_alter_user4update_passwd(thd, sql_str); +} + +static int tse_rewrite_setpasswd(MYSQL_THD thd, string &sql_str) { + // match: set password = | set password to | set password for current_user(),but 'to' and '=' dont match for replacing + regex add_or_rewrite_for_pattern("^set \\s*password\\s*((?=to|=)|for \\s*current_user[(][)])", regex_constants::icase); + string rw_query_sql = sql_str; + string user2host(""); + + List *lex_var_list = &thd->lex->var_list; + assert(lex_var_list->elements == 1); + List_iterator_fast it(*lex_var_list); + set_var_base *var; + while ((var = it++)) { + set_var_password *set_passwd = static_cast(var); + const LEX_USER *user_for_setpasswd = set_passwd->get_user(); + string username(user_for_setpasswd->user.str); + username = tse_deserilize_username_with_single_quotation(username); + user2host = "SET PASSWORD FOR '" + username + "'@'" + string(user_for_setpasswd->host.str) + "' "; + rw_query_sql = regex_replace(rw_query_sql, add_or_rewrite_for_pattern, user2host.c_str()); + + // 为当前用户设置密码,为不报错不加replace + if (user_for_setpasswd->uses_replace_clause && + !strcmp(thd->m_main_security_ctx.priv_user().str, user_for_setpasswd->user.str)) { + // check replacing old password is correct or not + bool is_password_matched = false; + if (tse_verify_password4existed_user(thd, user_for_setpasswd, is_password_matched)) { + return -1; + } + if (is_password_matched) { + tse_remove_replace_clause4sql(rw_query_sql); + } else { + my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); + return -1; + } + } + } + sql_str = rw_query_sql; + return 0; +} + +static int tse_check_set_password(SENSI_INFO string &sql_str, MYSQL_THD thd, bool &need_forward) { + if (tse_check_dcl(sql_str, thd, need_forward) != 0) { + return -1; + } + + return tse_rewrite_setpasswd(thd, sql_str); +} + +static int tse_check_flush(string &, MYSQL_THD thd, bool &need_forward) { + need_forward = thd->lex->type & (REFRESH_FOR_EXPORT | REFRESH_READ_LOCK | REFRESH_GRANT); + return 0; +} + +static unordered_set set_variable_not_broadcast{"ctc_ddl_local_enabled", "ctc_ddl_enabled"}; +static bool tse_check_ddl_local_enable(string sql_str, bool &need_forwar) { + transform(sql_str.begin(), sql_str.end(), sql_str.begin(), ::tolower); + + for (auto it : set_variable_not_broadcast) { + if (sql_str.find(it) != sql_str.npos) { + need_forwar = false; + return true; + } + } + + return false; +} + +static uint32_t tse_set_var_option(bool is_null_value, bool is_set_default_value, + set_var *setvar) { + uint32_t options = 0; + if (is_null_value) { + options |= TSE_SET_VARIABLE_TO_NULL; + } + if (is_set_default_value) { + options |= TSE_SET_VARIABLE_TO_DEFAULT; + } + if (setvar->type == OPT_PERSIST_ONLY) { + options |= TSE_SET_VARIABLE_PERSIST_ONLY; + } + if (setvar->type == OPT_PERSIST) { + options |= TSE_SET_VARIABLE_PERSIST; + } + return options; +} + +static int tse_set_var_meta(MYSQL_THD thd, uint32_t options, const char* base_name, + string var_name, string var_value) { + tianchi_handler_t tch; + tch.inst_id = tse_instance_id; + handlerton* hton = get_tse_hton(); + + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; + broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + string sql = string(thd->query().str).substr(0, thd->query().length); + + // user_name存变量名,user_ip存变量值 + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), var_name.c_str(), + var_value.c_str(), tse_instance_id, SQLCOM_SET_OPTION); + if(base_name != nullptr) { + strncpy(broadcast_req.db_name, base_name, strlen(base_name)); + } + broadcast_req.options |= options; + int ret = tse_execute_mysql_ddl_sql(&tch, &broadcast_req, false); + update_sess_ctx_by_tch(tch, hton, thd); + + return ret; +} + +static int tse_get_variables_value_string(MYSQL_THD thd, string &sql_str, set_var* setvar, string& val_str, + bool& is_null_value, bool &need_forward) { + Item_func_get_user_var *itemFunc = dynamic_cast(setvar->value); + Item_func_get_system_var *itemFuncSys = dynamic_cast(setvar->value); + + if (setvar->value->fix_fields(thd, &(setvar->value))) { + thd->clear_error(); + need_forward = false; + return 0; // ctc返回,交由MySQL判断报错 + } + + if (itemFunc) { + // 从临时变量取值 + tse_log_system("[TSE_DDL_REWRITE]:get user var value. %s", sql_str.c_str()); + int ret = tse_get_user_var_string(thd, itemFunc, val_str); + if (ret != 0) { + need_forward = false; + return -1; + } + } else if (itemFuncSys) { + // 从系统变量取值 + String* new_str; + String str; + tse_log_system("[TSE_DDL_REWRITE]:get system var value. %s", sql_str.c_str()); + if (itemFuncSys->bind(thd)) { + need_forward = false; + return -1; + } + itemFuncSys->fixed = true; + if (!(new_str = itemFuncSys->val_str(&str))) { + is_null_value = true; + val_str = "null"; + } else { + val_str = new_str->c_ptr(); + } + } else { + // 其他变量类型 + String* new_str; + String str; + if (!(new_str = setvar->value->val_str(&str))) { + is_null_value = true; + val_str = "null"; + } else { + val_str = new_str->c_ptr(); + } + } + return 0; +} + +static int tse_check_set_opt_rule(set_var *setvar, string& name_str, string& user_val_str, bool& need_forward) { + int ret = 0; + transform(name_str.begin(), name_str.end(), name_str.begin(), ::tolower); + auto it = set_variable_rules_map.find(name_str); + if (it != set_variable_rules_map.end()) { + int rule_res = it->second(setvar, need_forward, user_val_str); + if (rule_res == -1) { + need_forward = false; + } + ret |= rule_res; + } + return ret; +} + +/* 参考set_var.cc: sql_set_variables */ +static int tse_check_set_opt(string &sql_str, MYSQL_THD thd, bool &need_forward) { + if (tse_check_ddl_local_enable(sql_str, need_forward)) { + return 0; + } + + List_iterator_fast var_it(thd->lex->var_list); + + set_var_base *var = nullptr; + int ret = 0; + string name_str; + string val_str; + + // broadcast SET_OPTION query with subselect item + bool contain_subselect = false; + if (thd->lex->query_tables) { + contain_subselect = true; + } + var_it.rewind(); + while ((var = var_it++)) { + set_var *setvar = dynamic_cast(var); + bool is_set_default_value = false; + bool is_null_value = false; + if (setvar && setvar->var) { + need_forward = !setvar->var->is_readonly() && setvar->is_global_persist(); + name_str = setvar->var->name.str; + if (!contain_subselect) { + /* get user value (@xxxxx) as string */ + if (!setvar->value) { + is_set_default_value = true; + val_str = ""; + } else { + ret = tse_get_variables_value_string(thd, sql_str, setvar, val_str, is_null_value, need_forward); + } + + ret |= tse_check_set_opt_rule(setvar, name_str, val_str, need_forward); + } + } + + if (need_forward && allow_sqlcmd(thd, "ctc_setopt_disabled") != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Set global variable query is not allowed (ctc_setopt_disabled = true)"); + return -1; + } + + if(IS_METADATA_NORMALIZATION() && !contain_subselect && need_forward && setvar) { + if (setvar->check(thd) == 0) { + uint32_t options = tse_set_var_option(is_null_value, is_set_default_value, setvar); + ret = tse_set_var_meta(thd, options, setvar->base.str, name_str, val_str); + } else { + thd->clear_error(); + need_forward = false; // 值校验失败, ctc不进行广播并返回成功, 后续报错由MySQL完成 + } + } + + tse_log_system("set option %s, need_forward: %d", sql_str.c_str(), need_forward); + } + if (IS_METADATA_NORMALIZATION() && !contain_subselect) { + need_forward = false; + } + return ret; +} + +static int is_system_db(const char *ddl_db) { + if (mysql_system_db.find(ddl_db) != mysql_system_db.end()) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Once the CTC is loaded, it must be used as the default engine. To specify other engine for table, uninstall the CTC first."); + return -1; + } + + return 0; +} + +static int tse_check_ddl_engine(string &, MYSQL_THD thd, bool &need_forward) { + need_forward = false; // broadcast by storage engine + LEX_CSTRING tse_name; + tse_name.str = tse_hton_name; + tse_name.length = strlen(tse_hton_name); + handlerton *tse_handlerton = nullptr; + // 获取TSE引擎handlerton指针,如果thd->lex->create_info->db_type和TSE引擎指针不相等,那么必然不是TSE引擎 + plugin_ref plugin = ha_resolve_by_name(thd, &tse_name, false); + if (plugin) { + tse_handlerton = plugin_data(plugin); + } + + // 检查ddl语句是否显示指定非CTC + if (thd->lex->create_info != nullptr && + thd->lex->create_info->db_type != nullptr && + thd->lex->create_info->db_type != tse_handlerton && + !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Once the CTC is loaded, it must be used as the default engine. To specify other engine for table, uninstall the CTC first."); + return -1; + } + + if (!IS_METADATA_NORMALIZATION()) { + // create like table 检查是否是系统库 + if (thd->lex->query_tables != nullptr && + thd->lex->query_tables->next_global != nullptr && + thd->lex->create_info != nullptr && + thd->lex->create_info->options & HA_LEX_CREATE_TABLE_LIKE && + !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) && + !thd->lex->drop_temporary) { + const char *ddl_db = thd->lex->query_tables->next_global->db; + return is_system_db(ddl_db); + } + } + +// create tablespace 检查是否为engine=Innodb情况 + if (thd->lex->sql_command == SQLCOM_ALTER_TABLESPACE) { + const Sql_cmd_tablespace *sct = dynamic_cast(thd->lex->m_sql_cmd); + if (sct != nullptr && + sct->get_options().engine_name.str != nullptr && + strcmp(sct->get_options().engine_name.str, tse_name.str) != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Once the CTC is loaded, it must be used as the default engine. To specify other engine for table, uninstall the CTC first."); + return -1; + } + } + + if (!IS_METADATA_NORMALIZATION()) { + // create表 && drop表/库 (检查是否是系统库上ddl) + if (thd->lex->query_tables != nullptr && + (thd->lex->create_info != nullptr && !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) && + !thd->lex->drop_temporary) { + const char *ddl_db = thd->lex->query_tables->db; + return is_system_db(ddl_db); + } + } + + return 0; +} + +static int tse_check_ddl(string &, MYSQL_THD, bool &need_forward) { + need_forward = false; // broadcast by storage engine + return 0; +} + +static int tse_check_unspport_ddl(string &, MYSQL_THD, bool &) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Cantian doesn't support current operation"); + return -1; +} + +static int tse_read_only_ddl(string &, MYSQL_THD thd, bool &need_forward) { + if (check_readonly(thd, true) || + (thd->lex->query_tables != nullptr && + check_schema_readonly(thd, thd->lex->query_tables->table_name))) { + need_forward = false; + } + return 0; +} + +typedef struct ddl_broadcast_cmd_s +{ + bool need_select_db; // 需要指定数据库 + int (*pre_func)(string &sql_str, MYSQL_THD thd, bool &need_forward); //转发之前的预处理函数,为空则不调用 +} ddl_broadcast_cmd; + +static unordered_map + ddl_cmds = { + // DCL,broadcast on !tse_dcl_disabled + {SQLCOM_GRANT, {true, tse_check_dcl}}, + {SQLCOM_REVOKE, {false, tse_check_dcl}}, + {SQLCOM_CREATE_USER, {false, tse_check_dcl}}, + {SQLCOM_DROP_USER, {false, tse_check_dcl}}, + {SQLCOM_RENAME_USER, {false, tse_check_dcl}}, + {SQLCOM_REVOKE_ALL, {false, tse_check_dcl}}, + {SQLCOM_ALTER_USER, {false, tse_check_alter_user}}, + {SQLCOM_ALTER_USER_DEFAULT_ROLE, {false, tse_check_dcl}}, + {SQLCOM_CREATE_ROLE, {false, tse_check_dcl}}, + {SQLCOM_DROP_ROLE, {false, tse_check_dcl}}, + {SQLCOM_SET_ROLE, {false, tse_check_dcl}}, + {SQLCOM_GRANT_ROLE, {false, tse_check_dcl}}, + {SQLCOM_REVOKE_ROLE, {false, tse_check_dcl}}, + {SQLCOM_SET_PASSWORD, {false, tse_check_set_password}}, + + // prepare statement + {SQLCOM_PREPARE, {false, tse_check_ddl}}, + {SQLCOM_EXECUTE, {false, tse_check_ddl}}, + + // 存储过程,broadcast + {SQLCOM_CREATE_PROCEDURE, {true, tse_read_only_ddl}}, + {SQLCOM_DROP_PROCEDURE, {true, tse_read_only_ddl}}, + {SQLCOM_ALTER_PROCEDURE, {true, tse_read_only_ddl}}, + {SQLCOM_ALTER_FUNCTION, {true, tse_read_only_ddl}}, + {SQLCOM_CREATE_SPFUNCTION, {true, tse_read_only_ddl}}, + {SQLCOM_DROP_FUNCTION, {true, tse_read_only_ddl}}, + + // 触发器 & 视图,broadcast + {SQLCOM_CREATE_VIEW, {true, tse_read_only_ddl}}, + {SQLCOM_DROP_VIEW, {true, tse_read_only_ddl}}, + {SQLCOM_CREATE_TRIGGER, {true, tse_read_only_ddl}}, + {SQLCOM_DROP_TRIGGER, {true, tse_read_only_ddl}}, + + // set Variable, check var map + // SET_OPTION query with subselect item needs specific db + {SQLCOM_SET_OPTION, {true, tse_check_set_opt}}, + + // Locking, broadcast + {SQLCOM_LOCK_TABLES, {true, NULL}}, + {SQLCOM_UNLOCK_TABLES, {true, NULL}}, + {SQLCOM_LOCK_INSTANCE, {false, NULL}}, + {SQLCOM_UNLOCK_INSTANCE, {false, NULL}}, + + // analyze broardcast for share cbo + {SQLCOM_ANALYZE, {true, NULL}}, + + // Flush, only broadcast for REFRESH_READ_LOCK + {SQLCOM_FLUSH, {false, tse_check_flush}}, + + // table & tablespace operations, do not broadcast in rewriter + {SQLCOM_CREATE_TABLE, {false, tse_check_ddl_engine}}, + {SQLCOM_ALTER_TABLE, {false, tse_check_ddl_engine}}, + {SQLCOM_CREATE_INDEX, {false, tse_check_ddl}}, + {SQLCOM_DROP_INDEX, {false, tse_check_ddl}}, + {SQLCOM_REPAIR, {false, tse_check_ddl}}, + {SQLCOM_OPTIMIZE, {false, tse_check_ddl}}, + {SQLCOM_CHECK, {false, tse_check_ddl}}, + {SQLCOM_RENAME_TABLE, {false, tse_check_ddl}}, + {SQLCOM_ALTER_TABLESPACE, {false, tse_check_ddl_engine}}, + + // drop table operations, do not broadcast in rewriter + {SQLCOM_DROP_TABLE, {false, tse_check_ddl_engine}}, + + // database operations, do not broadcast in rewriter + + {SQLCOM_CHANGE_DB, {false, tse_check_ddl}}, + {SQLCOM_CREATE_DB, {false, tse_check_ddl}}, + {SQLCOM_DROP_DB, {false, tse_check_ddl_engine}}, + + // alter database broadcast for recording logical logs + {SQLCOM_ALTER_DB, {false, NULL}}, + + + // 不支持创建,修改,删除EVENT + {SQLCOM_CREATE_EVENT, {false, tse_check_unspport_ddl}}, + {SQLCOM_ALTER_EVENT, {false, tse_check_unspport_ddl}}, + {SQLCOM_DROP_EVENT, {false, tse_check_unspport_ddl}}, + + // Replication operations - unsupported + {SQLCOM_CREATE_SERVER, {false, tse_check_unspport_ddl}}, + {SQLCOM_DROP_SERVER, {false, tse_check_unspport_ddl}}, + {SQLCOM_ALTER_SERVER, {false, tse_check_unspport_ddl}}, + + // 不支持alter instance + {SQLCOM_ALTER_INSTANCE, {false, tse_check_unspport_ddl}}, + + // 不支持import table + {SQLCOM_IMPORT, {false, tse_check_unspport_ddl}}, + + // 不支持创建,删除SRS + {SQLCOM_CREATE_SRS, {false, tse_check_unspport_ddl}}, + {SQLCOM_DROP_SRS, {false, tse_check_unspport_ddl}}, + + // 不支持创建,修改,删除,设置资源组 + {SQLCOM_CREATE_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + {SQLCOM_ALTER_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + {SQLCOM_DROP_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + {SQLCOM_SET_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + + // XA operations - unsupported + {SQLCOM_XA_START, {false, tse_check_unspport_ddl}}, + {SQLCOM_XA_END, {false, tse_check_unspport_ddl}}, + {SQLCOM_XA_PREPARE, {false, tse_check_unspport_ddl}}, + {SQLCOM_XA_COMMIT, {false, tse_check_unspport_ddl}}, + {SQLCOM_XA_ROLLBACK, {false, tse_check_unspport_ddl}}, + {SQLCOM_XA_RECOVER, {false, tse_check_unspport_ddl}}, + + // handler operations - supported + {SQLCOM_HA_OPEN, {false, tse_check_ddl}}, + {SQLCOM_HA_CLOSE, {false, tse_check_ddl}}, + {SQLCOM_HA_READ, {false, tse_check_ddl}}, + +}; + +bool is_ddl_sql_cmd(enum_sql_command sql_cmd) { + if (ddl_cmds.find(sql_cmd) != ddl_cmds.end()) { + return true; + } + return false; +} + +bool is_dcl_sql_cmd(enum_sql_command sql_cmd) { + + if (sql_cmd == SQLCOM_GRANT || sql_cmd == SQLCOM_REVOKE || + sql_cmd == SQLCOM_CREATE_USER || sql_cmd == SQLCOM_DROP_USER || + sql_cmd == SQLCOM_RENAME_USER || sql_cmd == SQLCOM_REVOKE_ALL || + sql_cmd == SQLCOM_ALTER_USER || sql_cmd == SQLCOM_ALTER_USER_DEFAULT_ROLE || + sql_cmd == SQLCOM_CREATE_ROLE || sql_cmd == SQLCOM_DROP_ROLE || + sql_cmd == SQLCOM_SET_ROLE || sql_cmd ==SQLCOM_GRANT_ROLE || + sql_cmd == SQLCOM_REVOKE_ROLE) { + return true; + } + + return false; +} + +#ifdef HAVE_PSI_INTERFACE +static PSI_memory_key key_memory_tse_ddl_rewriter; + +static PSI_memory_info all_rewrite_memory[] = { + {&key_memory_tse_ddl_rewriter, "ctc_ddl_rewriter", 0, 0, PSI_DOCUMENT_ME}}; + +static int plugin_init(MYSQL_PLUGIN) { + const char *category = "rewriter"; + int count = static_cast(array_elements(all_rewrite_memory)); + mysql_memory_register(category, all_rewrite_memory, count); + tse_log_system("plugin_init called"); + return 0; /* success */ +} +#else +#define plugin_init nullptr +#define key_memory_tse_ddl_rewriter PSI_NOT_INSTRUMENTED +#endif /* HAVE_PSI_INTERFACE */ + +static inline bool is_temporary_table_being_opened(const TABLE_LIST *table) { + return table->open_type == OT_TEMPORARY_ONLY || + (table->open_type == OT_TEMPORARY_OR_BASE && + is_temporary_table(table)); +} + +int tse_lock_table_pre(THD* thd, vector& ticket_list) { + TABLE_LIST *tables_start = thd->lex->query_tables; + TABLE_LIST *tables_end = thd->lex->first_not_own_table(); + TABLE_LIST *table; + for (table = tables_start; table && table != tables_end; + table = table->next_global) { + if (is_temporary_table_being_opened(table)) { + continue; + } + MDL_request req; + MDL_REQUEST_INIT(&req, MDL_key::TABLE, table->db, table->table_name, + MDL_SHARED_NO_READ_WRITE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&req, 1)) { + return 1; + } + ticket_list.push_back(req.ticket); + } + return 0; +} + +void tse_lock_table_post(THD* thd, vector& ticket_list) { + for (auto it = ticket_list.begin(); it != ticket_list.end(); ++it) { + thd->mdl_context.release_lock(*it); + } + ticket_list.clear(); +} + +static void tse_ddl_rewrite_handle_error(MYSQL_THD thd, int ret, tse_ddl_broadcast_request &broadcast_req, uint8_t sql_cmd) { + if (ret == TSE_DDL_VERSION_NOT_MATCH) { + broadcast_req.err_code = ER_DISALLOWED_OPERATION; + my_printf_error(ER_DISALLOWED_OPERATION, "Version not match. Please make sure cluster on the same version.", MYF(0)); + tse_log_system("[TSE_DDL_REWRITE]: Version not match, sql=%s", sql_without_plaintext_password(&broadcast_req).c_str()); + return; + } + + my_printf_error(broadcast_req.err_code, "Got error(err_code:%d, err_msg:%s) on remote mysql.", MYF(0), + broadcast_req.err_code, broadcast_req.err_msg); + + tse_log_error("[TSE_DDL_REWRITE]:Got error on remote mysql, query:%s, user_name:%s, err_code:%d, err_msg:%s", + sql_without_plaintext_password(&broadcast_req).c_str(), broadcast_req.user_name, broadcast_req.err_code, broadcast_req.err_msg); + + // unlock when lock instance failed + if (sql_cmd == SQLCOM_LOCK_INSTANCE) { + tse_check_unlock_instance(thd); + } + + return; +} + +int ddl_broadcast_and_wait(MYSQL_THD thd, string &query_str, + uint8_t sql_cmd, ddl_broadcast_cmd &broadcast_cmd) { + tianchi_handler_t tch; + memset(&tch, 0, sizeof(tch)); + tch.inst_id = tse_instance_id; + handlerton *hton = get_tse_hton(); + update_member_tch(tch, hton, thd); + + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + + if (thd->db().str != NULL && strlen(thd->db().str) > 0 && + broadcast_cmd.need_select_db) { + strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + } + + if (sql_cmd == SQLCOM_SET_OPTION) { + // Use it to mark SET_OPTION query with subselect item + broadcast_req.options |= TSE_SET_VARIABLE_WITH_SUBSELECT; + } + broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; + broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + FILL_BROADCAST_BASE_REQ(broadcast_req, query_str.c_str(), thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, tse_instance_id, sql_cmd); + + vector ticket_list; + if (sql_cmd == SQLCOM_LOCK_TABLES) { + int pre_lock_ret = tse_lock_table_pre(thd, ticket_list); + if (pre_lock_ret != 0) { + tse_lock_table_post(thd, ticket_list); + my_printf_error(ER_LOCK_WAIT_TIMEOUT, "[TSE_DDL_REWRITE]: LOCK TABLE FAILED", MYF(0)); + return ER_LOCK_WAIT_TIMEOUT; + } + } + + // 全局创建连接成功后执行sql语句 + int ret = tse_broadcast_rewrite_sql(&tch, &broadcast_req, true); + + if (sql_cmd == SQLCOM_LOCK_TABLES) { + tse_lock_table_post(thd, ticket_list); + } + + DBUG_EXECUTE_IF("tse_ddl_rewrite_broadcast_fail", { ret = TSE_DDL_VERSION_NOT_MATCH;broadcast_req.err_code = ER_DISALLOWED_OPERATION; }); + if (ret != 0 && broadcast_req.err_code != 0) { + tse_ddl_rewrite_handle_error(thd, ret, broadcast_req, sql_cmd); + return broadcast_req.err_code; + } + + tse_log_system("[TSE_DDL_REWRITE]:ret:%d, query:%s, user_name:%s, err_code:%d, broadcast_inst_id:%u, " + "conn_id:%u, tse_inst_id:%u", ret, sql_without_plaintext_password(&broadcast_req).c_str(), broadcast_req.user_name, + broadcast_req.err_code, broadcast_req.mysql_inst_id, tch.thd_id, tch.inst_id); + + update_sess_ctx_by_tch(tch, hton, thd); + return convert_tse_error_code_to_mysql((ct_errno_t)ret); +} + +bool plugin_ddl_passthru(MYSQL_THD thd, + unordered_map::iterator &it) { + if (it == ddl_cmds.end()) { + return true; + } + + if (engine_ddl_passthru(thd)) { + return true; + } + +#ifdef NDEBUG + const char *engine_str = thd->variables.table_plugin->name.str; +#else + const char *engine_str = (*thd->variables.table_plugin)->name.str; +#endif + if (strcasecmp(engine_str, tse_hton_name) != 0) { + return true; + } + + return false; +} + +bool check_agent_connection(MYSQL_THD thd) { + // Only user from localhost/127.0.0.1 or % can be proxied remotely + if (strcmp(thd->m_main_security_ctx.priv_host().str, my_localhost) != 0 && + strcmp(thd->m_main_security_ctx.priv_host().str, "127.0.0.1") != 0 && + strcmp(thd->m_main_security_ctx.priv_host().str, "%") != 0 && + strcmp(thd->m_main_security_ctx.priv_host().str, "skip-grants host") != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, + "%s@%s is not allowed for DDL remote execution!", MYF(0), + thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str); + return true; + } + + MYSQL *agent_conn = NULL; + // 连接mysql server失败,不允许执行ddl操作 + if (tse_init_agent_client(agent_conn) != 0) { + my_printf_error(ER_DISALLOWED_OPERATION, + "Failed to establish connection for DDL remote execution!", MYF(0)); + tse_close_mysql_conn(&agent_conn); + return true; + } + + tse_close_mysql_conn(&agent_conn); + return false; +} + +int ctc_record_sql(MYSQL_THD thd, bool need_select_db) { + tianchi_handler_t tch; + tch.inst_id = tse_instance_id; + handlerton* hton = get_tse_hton(); + + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); + + tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; + + if (thd->db().str != NULL && strlen(thd->db().str) > 0 && need_select_db) { + strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + } + + broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; + broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + string sql = string(thd->query().str).substr(0, thd->query().length); + + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->m_main_security_ctx.priv_user().str, + thd->m_main_security_ctx.priv_host().str, tse_instance_id, (uint8_t)thd->lex->sql_command); + + int ret = ctc_record_sql_for_cantian(&tch, &broadcast_req, false); + update_sess_ctx_by_tch(tch, hton, thd); + + tse_log_system("[TSE_REWRITE_META]:ret:%d, query:%s", ret, sql_without_plaintext_password(&broadcast_req).c_str()); + + return ret; +} + + +bool plugin_ddl_block(MYSQL_THD thd, + unordered_map::iterator &it, + string &query_str, + bool &need_forward) { + ddl_broadcast_cmd broadcast_cmd = it->second; + if (broadcast_cmd.pre_func != NULL) { + int ret = broadcast_cmd.pre_func(query_str, thd, need_forward); + if (ret != 0) { + tse_log_system("pre_func execute failed,ret:%d,cmd:%d, sql:%s", + ret, it->first, query_str.c_str()); + return true; + } + } + + if (tse_check_ddl_sql_length(query_str)) { + return true; + } + + if (!need_forward) { + return false; + } + + if (IS_METADATA_NORMALIZATION() && !is_dcl_sql_cmd(thd->lex->sql_command)) { + if (ctc_record_sql(thd, broadcast_cmd.need_select_db)) { + tse_log_error("[CTC_META_SQL]:record sql str failed. sql:%s", query_str.c_str()); + return true; + } + } + + if (!IS_METADATA_NORMALIZATION()) { + // disallow ddl query if ctc_concurrent_ddl=OFF and tse_enable_ddl not set + if (!ddl_enabled_normal(thd)) { + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "DDL not allowed in this mode, Please check the value of @@ctc_concurrent_ddl."); + return true; + } + + return check_agent_connection(thd); + } + + return false; +} + +// due to MDL_key::BACKUP_LOCK`s MDL_INTENTION_EXCLUSIVE comflicts with MDL_key::BACKUP_LOCK`s MDL_SHARED (user execute STMT `lock instance for backup`) +static bool tse_is_instance_locked_by_backup(MYSQL_THD thd) { + MDL_request mdl_request; + MDL_key key(MDL_key::BACKUP_LOCK, "", ""); + // check this conn whether has backup S lock + if (thd->mdl_context.owns_equal_or_stronger_lock(&key, MDL_SHARED)) { + return true; + } + // check other conn whether has backup S lock + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP_LOCK, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); + if (thd->mdl_context.acquire_lock(&mdl_request, 0)) { + thd->clear_error(); // clear lock failed error + return true; + } else { + thd->mdl_context.release_lock(mdl_request.ticket); // MDL_EXPLICIT need us to release when locked succeed + return false; + } +} + +static bool tse_is_have_global_read_lock(MYSQL_THD thd) { + // check if current connetion hold global read lock, let it go + if (thd->global_read_lock.is_acquired()) { + return false; + } + + // block other connections + if (Global_read_lock::global_read_lock_active()) { + return true; + } + + return false; +} + +static inline bool tse_is_broadcast_by_storage_engine(ddl_broadcast_cmd broadcast_cmd) { + return broadcast_cmd.pre_func == tse_check_ddl || broadcast_cmd.pre_func == tse_check_ddl_engine; +} + +static bool tse_is_set_session_var(MYSQL_THD thd, string &query_str) { + if (thd->lex->sql_command != SQLCOM_SET_OPTION) { + return false; + } + + set_var_base *var = nullptr; + List_iterator_fast var_it(thd->lex->var_list); + + while ((var = var_it++)) { + // identify SET statement other than GLOBAL scop + set_var *setvar = dynamic_cast(var); + if (setvar && setvar->type != OPT_GLOBAL) { + tse_log_system("[TSE_DDL_REWRITE]:let non global scop sql pass. sql_str:%s", query_str.c_str()); + return true; + } + + // identify "set names utf8" sql str + set_var_collation_client *set_var_collation = dynamic_cast(var); + if (set_var_collation) { + tse_log_system("[TSE_DDL_REWRITE]:let set names xxx pass. sql_str:%s", query_str.c_str()); + return true; + } + } + + return false; +} + +static int tse_check_metadata_switch() { + metadata_switchs metadata_switch = (metadata_switchs)tse_get_metadata_switch(); + switch (metadata_switch) { + case metadata_switchs::MATCH_META: { + return 0; + } + case metadata_switchs::MATCH_NO_META: + return 1; + case metadata_switchs::CLUSTER_NOT_READY: + tse_log_error("[CTC_META]: Cantian cluster not ready"); + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "CANTIAN cluster not read."); + return -1; + case metadata_switchs::NOT_MATCH: + tse_log_error("[CTC_META]: The metadata switch of CTC and CANTIAN not match"); + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "metadata switch not match."); + return -1; + default: + tse_log_error("[CTC_META]: ctc_get_metadata_switch fail"); + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "CTC get metadata switch status fail."); + return -1; + } +} + +static int tse_ddl_rewrite(MYSQL_THD thd, mysql_event_class_t event_class, + const void *event) { + if(is_meta_version_initialize()) { + return 0; + } + + /* We can exit early if this is not a pre-parse event. */ + const struct mysql_event_parse *event_parse = + static_cast(event); + assert(event_class == MYSQL_AUDIT_PARSE_CLASS && + event_parse->event_subclass == MYSQL_AUDIT_PARSE_POSTPARSE); + + enum enum_sql_command sql_cmd = thd->lex->sql_command; + auto it = ddl_cmds.find(sql_cmd); + + bool need_forward = true; + string query_str = string(event_parse->query.str).substr(0, event_parse->query.length); + + if (plugin_ddl_passthru(thd, it)) { + return 0; + } + + if (plugin_ddl_block(thd, it, query_str, need_forward)) { + return -1; + } + + int check_metadata_switch_result = tse_check_metadata_switch(); + // for non-metadata-normalization's gate test + DBUG_EXECUTE_IF("non_metadata_normalization", { check_metadata_switch_result = 1; }); + // broadcast SET_OPTION query with subselect item + if (check_metadata_switch_result != 1 && !(need_forward && sql_cmd == SQLCOM_SET_OPTION)) { + return check_metadata_switch_result; + } + + if (sql_cmd == SQLCOM_LOCK_INSTANCE) { + if (tse_check_lock_instance(thd, need_forward)) { + return -1; + } + } else if (sql_cmd == SQLCOM_UNLOCK_INSTANCE) { + tse_check_unlock_instance(thd); + } else if (!IS_METADATA_NORMALIZATION() && (need_forward || tse_is_broadcast_by_storage_engine(it->second))) { + // block ddl when instance has exclusive backup lock (LOCK INSTANCE FOR BACKUP), ref sql_backup_lock.cc + if (tse_is_instance_locked_by_backup(thd)) { + + // don't block SET session variable after "lock instance for backup" + if (tse_is_set_session_var(thd, query_str)) { + return 0; + } + + my_printf_error(ER_DISALLOWED_OPERATION, "Instance has been locked, disallow this operation", MYF(0)); + tse_log_system("[TSE_DDL_REWRITE]: Instance has been locked, disallow sql=%s", query_str.c_str()); + return -1; + } + + if (tse_is_have_global_read_lock(thd)) { + my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0)); + tse_log_error("[TSE_DDL_REWRITE]: Instance have global read lock, disallow sql=%s", query_str.c_str()); + return -1; + } + } + + ddl_broadcast_cmd broadcast_cmd = it->second; + return need_forward && ddl_broadcast_and_wait(thd, query_str, (uint8_t)sql_cmd, broadcast_cmd); // 0: success other: fail +} + +/* Audit plugin descriptor. */ +static struct st_mysql_audit tse_ddl_rewriter_descriptor = { + MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ + nullptr, /* release_thd() */ + tse_ddl_rewrite, /* event_notify() */ + { + 0, + 0, + (unsigned long)MYSQL_AUDIT_PARSE_POSTPARSE, + } /* class mask */ +}; + +#if !defined __STRICT_ANSI__ && defined __GNUC__ && !defined __clang__ +#define STRUCT_FLD(name, value) \ + name: \ + value +#else +#define STRUCT_FLD(name, value) value +#endif +struct st_mysql_plugin g_tse_ddl_rewriter_plugin = { + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_AUDIT_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &tse_ddl_rewriter_descriptor), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "ctc_ddl_rewriter"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, "HUAWEI-CTC"), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "Rewrite of DDL statements."), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, plugin_init), + + /* the function to invoke when plugin is un installed */ + /* int (*)(void*); */ + nullptr, + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, nullptr), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, CTC_CLIENT_VERSION_NUMBER), + + /* SHOW_VAR* */ + STRUCT_FLD(status_vars, nullptr), + + /* SYS_VAR** */ + STRUCT_FLD(system_vars, tse_rewriter_system_variables), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, nullptr), + + /* Plugin flags */ + /* unsigned long */ + STRUCT_FLD(flags, PLUGIN_OPT_ALLOW_EARLY), +}; diff --git a/storage/tianchi/tse_ddl_util.cc b/storage/tianchi/tse_ddl_util.cc new file mode 100644 index 0000000..e2b5921 --- /dev/null +++ b/storage/tianchi/tse_ddl_util.cc @@ -0,0 +1,495 @@ +/* + Copyright (C) 2022. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under version 2 of the GNU General Public License (GPLv2) as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#include "tse_ddl_util.h" +#include "tse_log.h" +#include "sql/sql_class.h" +#include "sql/create_field.h" +#include "sql/sql_lex.h" +#include "sql/sql_table.h" + +using namespace std; + +const char *ibd_suffix = ".ibd"; + +void *tse_ddl_alloc_mem(char **mem_start, char *mem_end, + size_t malloc_size) { + assert(mem_start != NULL && *mem_start != NULL && mem_end != NULL); + if (*mem_start + malloc_size >= mem_end) { + tse_log_error("alloc ddl mem failed,size:%u", (uint32_t)malloc_size); + return NULL; + } + void *ptr = *mem_start; + *mem_start += malloc_size; + return ptr; +} + +int check_tse_identifier_name(const char *in_name) { + if (in_name == nullptr) { + return 0; + } + if (strlen(in_name) > TSE_IDENTIFIER_MAX_LEN) { + my_error(ER_TOO_LONG_IDENT, MYF(0), in_name); + return -1; + } + return 0; +} + +bool check_file_name_has_suffix(const char *file_name, const char *suffix) { + size_t suffix_len = strlen(suffix); + size_t file_name_len = strlen(file_name); + if (file_name_len <= suffix_len || (strcmp(file_name + file_name_len - suffix_len, suffix) != 0)) { + return true; + } + return false; +} + +bool check_file_name_prefix(const char *file_name) { + if (file_name[0] == ' ' || file_name[0] == '/') { + return true; + } + return false; +} + +bool check_data_file_name(const char *data_file_name) { + if (data_file_name == nullptr || data_file_name[0] == '\0') { + my_printf_error(ER_WRONG_FILE_NAME, "The ADD DATAFILE filepath does not have a proper filename", MYF(0)); + return true; + } + + // The datafile name can not start with '/' or ' ' + if (check_file_name_prefix(data_file_name)) { + my_printf_error(ER_WRONG_FILE_NAME, "The DATAFILE location must be in a known directory.", MYF(0)); + return true; + } + + // The datafile name must be suffixed with '.ibd' + if (check_file_name_has_suffix(data_file_name, ibd_suffix)) { + my_printf_error(ER_WRONG_FILE_NAME, "The ADD DATAFILE filepath must end with '%s'.", MYF(0), ibd_suffix); + return true; + } + + return false; +} + +Field *tse_get_field_by_name(TABLE *form, const char *name) { + for (uint32_t i = 0; i < form->s->fields; i++) { + if (strcasecmp(form->field[i]->field_name, name) == 0) { + return form->field[i]; + } + } + return nullptr; +} + +const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* field_name) { + // 处理普通建表 + Alter_info *alter_info = thd->lex->alter_info; + const Create_field *field = NULL; + if (alter_info != nullptr) { + List_iterator_fast field_it(alter_info->create_list); + while ((field = field_it++)) { + if(strcmp(field->field_name, field_name) == 0) { + return field; + } + } + + // 处理create table as select * from table 的特殊情况 + // 此时alter_info->create_list为空,需生成Create_field + TABLE tmp_table MY_ATTRIBUTE((unused)); + // lex execution is not started, item->field cannot be got. + if(!thd->lex->is_exec_started()) { + return nullptr; + } + mem_root_deque *items = thd->lex->unit->get_unit_column_types(); + for (Item *item : VisibleFields(*items)) { + if(strcmp(item->item_name.ptr(), field_name) == 0) { + Create_field *cr_field = generate_create_field(thd, item, &tmp_table); + if (cr_field == nullptr) { + break; + } + return cr_field; + } + } + } + + // 处理create table like 情况 + // 此时alter_info为空,需通过prepare_alter_table生成alter_info + if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) { + return nullptr; + } + Alter_info local_alter_info(thd->mem_root); + const dd::Table *src_table = nullptr; + Alter_table_ctx local_alter_ctx MY_ATTRIBUTE((unused)); + TABLE_LIST *table_list = thd->lex->query_tables->next_global; + if (table_list != nullptr && table_list->table != nullptr) { + /* Fill HA_CREATE_INFO and Alter_info with description of source table. */ + HA_CREATE_INFO create_info; + create_info.db_type = table_list->table->s->db_type(); + // This should be ok even if engine substitution has taken place since + // row_type denontes the desired row_type, and a different row_type may be + // assigned to real_row_type later. + create_info.row_type = table_list->table->s->row_type; + create_info.init_create_options_from_share(table_list->table->s, create_info.used_fields); + + // Prepare Create_field and Key_spec objects for ALTER and upgrade. + prepare_fields_and_keys(thd, src_table, table_list->table, &create_info, &local_alter_info, + &local_alter_ctx, create_info.used_fields); + List_iterator_fast field_like_it(local_alter_info.create_list); + while ((field = field_like_it++)) { + if(strcmp(field->field_name, field_name) == 0) { + return field; + } + } + } + + return nullptr; +} + +tse_alter_table_drop_type tse_ddl_get_drop_type_from_mysql_type( + Alter_drop::drop_type drop_type) { + switch (drop_type) { + case Alter_drop::drop_type::KEY: + return TSE_ALTER_TABLE_DROP_KEY; + case Alter_drop::drop_type::COLUMN: + return TSE_ALTER_TABLE_DROP_COLUMN; + case Alter_drop::drop_type::FOREIGN_KEY: + return TSE_ALTER_TABLE_DROP_FOREIGN_KEY; + case Alter_drop::drop_type::CHECK_CONSTRAINT: + return TSE_ALTER_TABLE_DROP_CHECK_CONSTRAINT; + case Alter_drop::drop_type::ANY_CONSTRAINT: + return TSE_ALTER_TABLE_DROP_ANY_CONSTRAINT; + default: + return TSE_ALTER_TABLE_DROP_UNKNOW; + } +} + +tse_alter_column_type tse_ddl_get_alter_column_type_from_mysql_type( + Alter_column::Type alter_column_type) { + switch (alter_column_type) {// SET_DEFAULT, DROP_DEFAULT, RENAME_COLUMN + case Alter_column::Type::SET_DEFAULT: + return TSE_ALTER_COLUMN_SET_DEFAULT; + case Alter_column::Type::DROP_DEFAULT: + return TSE_ALTER_COLUMN_DROP_DEFAULT; + case Alter_column::Type::RENAME_COLUMN: + return TSE_ALTER_COLUMN_RENAME_COLUMN; + case Alter_column::Type::SET_COLUMN_VISIBLE: + return TSE_ALTER_COLUMN_SET_COLUMN_VISIBLE; + case Alter_column::Type::SET_COLUMN_INVISIBLE: + return TSE_ALTER_COLUMN_SET_COLUMN_INVISIBLE; + default: + return TSE_ALTER_COLUMN_UNKNOW; + } +} + +bool get_tse_key_type(const KEY *key_info, int32_t *ret_type) { + *ret_type = TSE_KEYTYPE_UNKNOW; + if (key_info->flags & HA_SPATIAL) { + *ret_type = TSE_KEYTYPE_SPATIAL; + } else if (key_info->flags & HA_NOSAME) { + if (!my_strcasecmp(system_charset_info, key_info->name, primary_key_name)) { + *ret_type = TSE_KEYTYPE_PRIMARY; + } else { + *ret_type = TSE_KEYTYPE_UNIQUE; + } + } else if (key_info->flags & HA_FULLTEXT) { + *ret_type = TSE_KEYTYPE_FULLTEXT; + } else if (key_info->flags & HA_GENERATED_KEY) { + *ret_type = TSE_KEYTYPE_FOREIGN; + } else { + *ret_type = TSE_KEYTYPE_MULTIPLE; + } + switch (*ret_type) { + case TSE_KEYTYPE_SPATIAL: + *ret_type = TSE_KEYTYPE_UNKNOW; + TSE_ENGINE_ERROR("unsupport index type:TSE_KEYTYPE_SPATIAL"); + return false; + case TSE_KEYTYPE_FULLTEXT: + *ret_type = TSE_KEYTYPE_UNKNOW; + TSE_ENGINE_ERROR("unsupport index type:TSE_KEYTYPE_FULLTEXT"); + return false; + default: + break; + } + return true; +} + +bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm) { + *ret_algorithm = (int32_t)TSE_HA_KEY_ALG_BTREE; + switch (algorithm) { + case HA_KEY_ALG_RTREE: + tse_log_error("unsupport index hash_type:HA_KEY_ALG_RTREE"); + return true; + case HA_KEY_ALG_SE_SPECIFIC: + TSE_ENGINE_ERROR("unsupport index hash_type:HA_KEY_ALG_SE_SPECIFIC"); + return false; + case HA_KEY_ALG_FULLTEXT: + TSE_ENGINE_ERROR("unsupport index hash_type:HA_KEY_ALG_FULLTEXT"); + return false; + case TSE_HA_KEY_ALG_HASH: + // tse_log_error("unsupport index hash_type:TSE_HA_KEY_ALG_HASH"); + return true; + default: + break; + } + // mysql字符序和daac的参数对接 + static map + g_tse_key_algorithm_map = { + {HA_KEY_ALG_SE_SPECIFIC, TSE_HA_KEY_ALG_SE_SPECIFIC}, + {HA_KEY_ALG_BTREE, TSE_HA_KEY_ALG_BTREE}, + {HA_KEY_ALG_RTREE, TSE_HA_KEY_ALG_RTREE}, + {HA_KEY_ALG_HASH, TSE_HA_KEY_ALG_HASH}, + {HA_KEY_ALG_FULLTEXT, TSE_HA_KEY_ALG_FULLTEXT}}; + auto it = g_tse_key_algorithm_map.find(algorithm); + if (it != g_tse_key_algorithm_map.end()) { + *ret_algorithm = (int32_t)it->second; + return true; + } + return false; +} + +bool tse_ddl_get_data_type_from_mysql_type(Field *field, + const enum_field_types &mysql_type, int32_t *ret_type) { + if (field != nullptr) { + const field_cnvrt_aux_t *mysql_info = get_auxiliary_for_field_convert(field, mysql_type); + if (mysql_info != nullptr) { + *ret_type = mysql_info->ddl_field_type; + return true; + } + } + + tse_log_error("unsupport mysql datatype:%d", (int32_t)mysql_type); + *ret_type = TSE_DDL_TYPE_UNKNOW; + return false; +} + +// SET类型最多只能包含64个成员, 1~8成员的集合占1个字节 ,9~16成员的集合占2个字节 +// 17~24成员的集合占3个字节, 25~32成员的集合占4个字节, 33~64成员的集合占8个字节 +bool set_column_datatype(size_t set_num, TcDb__TseDDLColumnDef *column) { + if (set_num < 9) { + column->datatype->datatype = TSE_DDL_TYPE_TINY; + return true; + } else if (set_num > 8 && set_num < 17) { + column->datatype->datatype = TSE_DDL_TYPE_SHORT; + return true; + } else if (set_num > 16 && set_num < 33) { + column->datatype->datatype = TSE_DDL_TYPE_INT24; + return true; + } else if (set_num > 32 && set_num < 65) { + column->datatype->datatype = TSE_DDL_TYPE_LONGLONG; + return true; + } + + return false; +} + +bool tse_is_with_default_value(Field *field, const dd::Column *col_obj) { + bool has_default_value = false; + if (col_obj != nullptr) { + const bool has_default = ((!field->is_flag_set(NO_DEFAULT_VALUE_FLAG) && + !(field->auto_flags & Field::NEXT_NUMBER)) && + !col_obj->is_default_value_null()) || + field->m_default_val_expr; + has_default_value = has_default && (col_obj->default_value_utf8().data()) != NULL; + } + const bool has_default_timestamp = field->has_insert_default_datetime_value_expression(); + if (has_default_value || has_default_timestamp) { + return true; + } + return false; +} + +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(fk_option rule) { + switch (rule) { + case FK_OPTION_UNDEF: + case FK_OPTION_NO_ACTION: + case FK_OPTION_RESTRICT: + case FK_OPTION_DEFAULT: + return TSE_DDL_FK_RULE_RESTRICT; + case FK_OPTION_CASCADE: + return TSE_DDL_FK_RULE_CASCADE; + case FK_OPTION_SET_NULL: + return TSE_DDL_FK_RULE_SET_NULL; + default: + break; + } + tse_log_error("unknown foreign key option %d", (int)rule); + assert(0); + return TSE_DDL_FK_RULE_UNKNOW; +} + +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(dd::Foreign_key::enum_rule rule) { + switch (rule) { + case dd::Foreign_key::enum_rule::RULE_NO_ACTION: + case dd::Foreign_key::enum_rule::RULE_RESTRICT: + case dd::Foreign_key::enum_rule::RULE_SET_DEFAULT: + return TSE_DDL_FK_RULE_RESTRICT; + case dd::Foreign_key::enum_rule::RULE_CASCADE: + return TSE_DDL_FK_RULE_CASCADE; + case dd::Foreign_key::enum_rule::RULE_SET_NULL: + return TSE_DDL_FK_RULE_SET_NULL; + default: + break; + } + tse_log_error("unknown foreign key option %d", (int)rule); + assert(0); + return TSE_DDL_FK_RULE_UNKNOW; +} + +const dd::Index *tse_ddl_get_index_by_name(const dd::Table *tab_obj, + const char *index_name) { + for (const dd::Index *index : tab_obj->indexes()) { + if (strcmp(index->name().data(), index_name) == 0) { + return index; + } + } + return nullptr; +} + +const dd::Column *tse_ddl_get_column_by_name(const dd::Table *table_def, + const char *col_name) { + for (auto iter : table_def->columns()) { + if (my_strcasecmp(system_charset_info, iter->name().data(), col_name) == 0) { + return iter; + } + } + return nullptr; +} + +bool tse_ddl_get_create_key_type(dd::Index::enum_index_type type, int32_t *ret_type) { + *ret_type = TSE_KEYTYPE_UNKNOW; + switch (type) { + case dd::Index::enum_index_type::IT_PRIMARY: + *ret_type = TSE_KEYTYPE_PRIMARY; + return true; + case dd::Index::enum_index_type::IT_UNIQUE: + *ret_type = TSE_KEYTYPE_UNIQUE; + return true; + case dd::Index::enum_index_type::IT_MULTIPLE: + *ret_type = TSE_KEYTYPE_MULTIPLE; + return true; + case dd::Index::enum_index_type::IT_FULLTEXT: + TSE_ENGINE_ERROR("unsupport index type:IT_FULLTEXT"); + return false; + case dd::Index::enum_index_type::IT_SPATIAL: + TSE_ENGINE_ERROR("unsupport index type:IT_SPATIAL"); + return false; + default: + break; + } + return true; +} + +bool tse_ddl_get_create_key_algorithm(dd::Index::enum_index_algorithm algorithm, + int32_t *ret_algorithm) { + *ret_algorithm = (int32_t)TSE_HA_KEY_ALG_BTREE; + switch (algorithm) { + case dd::Index::enum_index_algorithm::IA_RTREE: + // tse_log_error("unsupport index hash_type:IA_RTREE,use TSE_HA_KEY_ALG_BTREE"); + return true; + case dd::Index::enum_index_algorithm::IA_SE_SPECIFIC: + TSE_ENGINE_ERROR("unsupport index hash_type:IA_SE_SPECIFIC"); + return false; + case dd::Index::enum_index_algorithm::IA_FULLTEXT: + TSE_ENGINE_ERROR("unsupport index hash_type:IA_FULLTEXT"); + return false; + case dd::Index::enum_index_algorithm::IA_HASH: + // tse_log_error("unsupport index hash_type:IA_HASH USE TSE_HA_KEY_ALG_BTREE"); + return true; + default: + break; + } + + static map + g_tse_create_key_algorithm_map = { + {dd::Index::enum_index_algorithm::IA_SE_SPECIFIC, TSE_HA_KEY_ALG_SE_SPECIFIC}, + {dd::Index::enum_index_algorithm::IA_BTREE, TSE_HA_KEY_ALG_BTREE}, + {dd::Index::enum_index_algorithm::IA_RTREE, TSE_HA_KEY_ALG_RTREE}, + {dd::Index::enum_index_algorithm::IA_HASH, TSE_HA_KEY_ALG_HASH}, + {dd::Index::enum_index_algorithm::IA_FULLTEXT, TSE_HA_KEY_ALG_FULLTEXT}}; + auto it = g_tse_create_key_algorithm_map.find(algorithm); + if (it != g_tse_create_key_algorithm_map.end()) { + *ret_algorithm = (int32_t)it->second; + return true; + } + my_printf_error(ER_DISALLOWED_OPERATION, + "get index algorithm failed, unsuported index algorithm", MYF(0)); + return false; +} + +uint16 get_prefix_index_len(const Field *field, const uint16 key_length) { + uint16 prefix_len = 0; + + /* No prefix index on multi-value field */ + if (!field->is_array() && + (field->is_flag_set(BLOB_FLAG)|| + (key_length < field->pack_length() && + field->type() == MYSQL_TYPE_STRING) || + (field->type() == MYSQL_TYPE_VARCHAR && + key_length < field->pack_length() - field->get_length_bytes()))) { + prefix_len = key_length; + prefix_len /= field->charset()->mbmaxlen; + assert(!field->gcol_info); + } + return prefix_len; +} + +int convert_tse_part_type(dd::Table::enum_partition_type mysql_part_type, uint32_t *tse_part_type) { + *tse_part_type = TSE_PART_TYPE_INVALID; + switch (mysql_part_type) { + case dd::Table::PT_RANGE: + case dd::Table::PT_RANGE_COLUMNS: + *tse_part_type = TSE_PART_TYPE_RANGE; + break; + case dd::Table::PT_LIST: + case dd::Table::PT_LIST_COLUMNS: + *tse_part_type = TSE_PART_TYPE_LIST; + break; + case dd::Table::PT_HASH: + case dd::Table::PT_LINEAR_HASH: + case dd::Table::PT_KEY_51: + case dd::Table::PT_KEY_55: + case dd::Table::PT_LINEAR_KEY_51: + case dd::Table::PT_LINEAR_KEY_55: + *tse_part_type = TSE_PART_TYPE_HASH; + break; + default : + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "Partition tables support only hash partitions, range partitions, list partitions, and columns partitions."); + tse_log_system("unsupported partition type : %d.", mysql_part_type); + return 1; + } + return 0; +} + +int convert_tse_subpart_type(dd::Table::enum_subpartition_type mysql_subpart_type, uint32_t *tse_part_type) { + *tse_part_type = TSE_PART_TYPE_INVALID; + switch (mysql_subpart_type) { + case dd::Table::ST_NONE: + *tse_part_type = TSE_PART_TYPE_INVALID; + break; + case dd::Table::ST_HASH: + case dd::Table::ST_LINEAR_HASH: + case dd::Table::ST_KEY_51: + case dd::Table::ST_KEY_55: + case dd::Table::ST_LINEAR_KEY_51: + case dd::Table::ST_LINEAR_KEY_55: + *tse_part_type = TSE_PART_TYPE_HASH; + break; + default : + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), + "SubPartition tables support only hash partitions"); + tse_log_system("unsupported partition type : %d.", mysql_subpart_type); + return 1; + } + return 0; +} \ No newline at end of file diff --git a/storage/tianchi/tse_ddl_util.h b/storage/tianchi/tse_ddl_util.h new file mode 100644 index 0000000..0565539 --- /dev/null +++ b/storage/tianchi/tse_ddl_util.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2022. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under version 2 of the GNU General Public License (GPLv2) as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#ifndef __TSE_DDL_UTIL_H__ +#define __TSE_DDL_UTIL_H__ + +#include "sql/table.h" +#include "sql/sql_alter.h" +#include "tse_srv.h" +#include "protobuf/tc_db.pb-c.h" +#include "ha_tse_ddl.h" + +void *tse_ddl_alloc_mem(char **mem_start, char *mem_end, size_t malloc_size); +int check_tse_identifier_name(const char *in_name); +bool check_file_name_has_suffix(const char *file_name, const char *suffix); +bool check_file_name_prefix(const char *file_name); +bool check_data_file_name(const char *data_file_name); +Field *tse_get_field_by_name(TABLE *form, const char *name); +const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* field_name); +tse_alter_table_drop_type tse_ddl_get_drop_type_from_mysql_type(Alter_drop::drop_type drop_type); +tse_alter_column_type tse_ddl_get_alter_column_type_from_mysql_type( + Alter_column::Type alter_column_type); +bool get_tse_key_type(const KEY *key_info, int32_t *ret_type); +bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm); +bool tse_ddl_get_data_type_from_mysql_type(Field *field, + const enum_field_types &mysql_type, int32_t *ret_type); +bool set_column_datatype(size_t set_num, TcDb__TseDDLColumnDef *column); +bool tse_is_with_default_value(Field *field, const dd::Column *col_obj); +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(fk_option rule); +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(dd::Foreign_key::enum_rule rule); +const dd::Index *tse_ddl_get_index_by_name(const dd::Table *tab_obj, const char *index_name); +const dd::Column *tse_ddl_get_column_by_name(const dd::Table *table_def, const char *col_name); +bool tse_ddl_get_create_key_type(dd::Index::enum_index_type type, int32_t *ret_type); +bool tse_ddl_get_create_key_algorithm(dd::Index::enum_index_algorithm algorithm, int32_t *ret_algorithm); +uint16 get_prefix_index_len(const Field *field, const uint16 key_length); +int convert_tse_part_type(dd::Table::enum_partition_type mysql_part_type, uint32_t *tse_part_type); +int convert_tse_subpart_type(dd::Table::enum_subpartition_type mysql_subpart_type, uint32_t *tse_part_type); +#endif // __TSE_DDL_UTIL_H__ \ No newline at end of file diff --git a/storage/tianchi/tse_error.cc b/storage/tianchi/tse_error.cc new file mode 100644 index 0000000..55c4462 --- /dev/null +++ b/storage/tianchi/tse_error.cc @@ -0,0 +1,159 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "tse_error.h" +#include "my_base.h" +#include "tse_log.h" + +static std::unordered_map err_code_lookup_map = { + {ERR_OAMAP_DUP_KEY_ERROR, HA_ERR_GENERIC}, + {ERR_OAMAP_INSERTION_FAILED, HA_ERR_GENERIC}, + {ERR_OAMAP_FETCH_FAILED, HA_ERR_GENERIC}, + {ERR_GENERIC_INTERNAL_ERROR, HA_ERR_GENERIC}, + {ERR_NOT_SUPPORT, HA_ERR_WRONG_COMMAND}, + {ERR_OPERATIONS_NOT_SUPPORT, HA_ERR_WRONG_COMMAND}, + /* Since we rolled back the whole transaction, we must + tell it also to MySQL so that MySQL knows to empty the + cached binlog for this transaction */ + {ERR_DEAD_LOCK, HA_ERR_LOCK_DEADLOCK}, + /* The DAAC serialization isolation level is stricter than the MySQL + repeatable read isolation level. If two transactions conflict: + - The daac is locked, including lock timeout and transaction area conflict. + - MySQL will be locked, including lock timeout and success. + Therefore, the daac transaction conflict error code is temporarily + classified as lock timeout. */ + {ERR_SERIALIZE_ACCESS, HA_ERR_RECORD_CHANGED}, + /* Starting from 5.0.13, we let MySQL just roll back the + latest SQL statement in a lock wait timeout. Previously, we + rolled back the whole transaction. */ + {ERR_LOCK_TIMEOUT, HA_ERR_LOCK_WAIT_TIMEOUT}, + /* If prefix is true then a 768-byte prefix is stored + locally for BLOB fields. Refer to dict_table_get_format(). + We limit max record size to 16k for 64k page size. */ + {ERR_RECORD_SIZE_OVERFLOW, HA_ERR_TOO_BIG_ROW}, + /* Be cautious with returning this error, since + mysql could re-enter the storage layer to get + duplicated key info, the operation requires a + valid table handle and/or transaction information, + which might not always be available in the error + handling stage. */ + {ERR_DUPLICATE_KEY, HA_ERR_FOUND_DUPP_KEY}, + {ERR_CONSTRAINT_VIOLATED_NO_FOUND, HA_ERR_NO_REFERENCED_ROW}, + {ERR_ROW_IS_REFERENCED, HA_ERR_ROW_IS_REFERENCED}, + {ERR_DEF_CHANGED, HA_ERR_TABLE_DEF_CHANGED}, + {ERR_SAVEPOINT_NOT_EXIST, HA_ERR_NO_SAVEPOINT}, + {ERR_NO_MORE_LOCKS, HA_ERR_LOCK_TABLE_FULL}, + {ERR_FILE_NOT_EXIST, HA_ERR_WRONG_FILE_NAME}, + {ERR_SPACE_NOT_EXIST, HA_ERR_TABLESPACE_MISSING}, + {ERR_SPACE_ALREADY_EXIST, HA_ERR_TABLESPACE_EXISTS}, + {ERR_BTREE_LEVEL_EXCEEDED, HA_ERR_INTERNAL_ERROR}, + {ERR_TABLE_OR_VIEW_NOT_EXIST, HA_ERR_NO_SUCH_TABLE}, + {ERR_DC_INVALIDATED, HA_ERR_NO_SUCH_TABLE}, + {ERR_INDEX_INVALID, HA_ERR_WRONG_INDEX}, + {ERR_CONNECTION_FAILED, HA_ERR_NO_CONNECTION}, + {ERR_ALLOC_MEMORY, HA_ERR_SE_OUT_OF_MEMORY}, + {ERR_ROW_LOCKED_NOWAIT, HA_ERR_NO_WAIT_LOCK}, + {ERR_OPERATION_CANCELED, HA_ERR_QUERY_INTERRUPTED}, + {ERR_SEM_FAULT, HA_ERR_INTERNAL_ERROR}, + {ERR_BATCH_DATA_HANDLE_FAILED, HA_ERR_INTERNAL_ERROR}, + {ERR_SHM_SEND_MSG_FAILED, HA_ERR_NO_CONNECTION}, + {ERR_INSTANCE_REG_FAILED, HA_ERR_INTERNAL_ERROR}, + {ERR_AUTOINC_READ_FAILED, HA_ERR_AUTOINC_READ_FAILED}, + {ERR_OBJECT_ALREADY_DROPPED, HA_ERR_TABLE_CORRUPT}, + {ERR_PAGE_CORRUPTED, HA_ERR_TABLE_CORRUPT}, +}; + +bool convert_cantian_err_to_mysql(ct_errno_t error) { + switch (error) { + case ERR_CAPABILITY_NOT_SUPPORT: + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Cantian capability not support."); + break; + case ERR_COLUMNS_MISMATCH: + my_error(ER_WRONG_VALUE_COUNT, MYF(0)); + break; + case ERR_ROW_LOCKED_NOWAIT: + my_error(ER_LOCK_NOWAIT, MYF(0)); + break; + case ERR_ROW_SELF_UPDATED: + my_printf_error(ER_MULTI_UPDATE_KEY_CONFLICT, + "Primary key/partition key update is not allowed since the table is updated both.", MYF(0)); + break; + case ERR_COLUMN_HAS_NULL: + my_error(ER_INVALID_USE_OF_NULL, MYF(0)); + break; + case ERR_TOO_MANY_CONNECTIONS: + my_error(ER_CON_COUNT_ERROR, MYF(0)); + break; + case ERR_NAME_TOO_LONG: + my_printf_error(ER_TOO_LONG_IDENT, "Identifier name is too long", MYF(0)); + break; + case ERR_CHILD_DUPLICATE_KEY: + my_printf_error(ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO, + "Foreign key constraint would lead to a duplicate entry in child table", MYF(0)); + break; + case ERR_FK_NO_INDEX_PAREN_4MYSQL: + my_error(ER_CANNOT_ADD_FOREIGN, MYF(0)); + break; + case ERR_EXCEED_MAX_CASCADE_DEPTH: + my_printf_error(ER_FK_DEPTH_EXCEEDED, "Foreign key cascade delete/update exceeds max depth of 15", MYF(0)); + break; + case ERR_SNAPSHOT_TOO_OLD: + my_printf_error(HA_ERR_TOO_MANY_CONCURRENT_TRXS, + "snapshot too old, it is advised to modify the parameters _undo_active_segments in Cantian", MYF(0)); + break; + case ERR_CHILD_ROW_CANNOT_ADD_OR_UPDATE: + my_printf_error(ER_NO_REFERENCED_ROW_2, + "Cannot add or update a child row: a foreign key constraint fails", MYF(0)); + break; + default: + return false; + } + return true; +} + +void tse_alter_table_handle_fault(ct_errno_t error) { + switch (error) { + case ERR_CONSTRAINT_VIOLATED_NO_FOUND: + my_printf_error(ER_NO_REFERENCED_ROW_2, + "Cannot add or update a child row: a foreign key constraint fails.", MYF(0)); + break; + default: + my_error(ER_GET_ERRNO, MYF(0), error, "Cantian error"); + break; + } +} + + +int convert_tse_error_code_to_mysql_impl(ct_errno_t error, const char* funcName, const int line) { + if (error == CT_SUCCESS) { + return 0; + } + + if (convert_cantian_err_to_mysql(error)) { + return HA_ERR_WRONG_COMMAND; + } + + int ret = HA_ERR_GENERIC; + auto iter = err_code_lookup_map.find(error); + if (iter != err_code_lookup_map.end()) { + ret = iter->second; + } else { + tse_log_system("func %s(line%d) returned with unknown err, cantian ret %d", funcName, line, (int)error); + } + tse_log_note("func %s(line%d) returned with errCode %d, cantian ret %d", funcName, line, ret, (int)error); + return ret; +} diff --git a/storage/tianchi/tse_error.h b/storage/tianchi/tse_error.h new file mode 100644 index 0000000..0067146 --- /dev/null +++ b/storage/tianchi/tse_error.h @@ -0,0 +1,218 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __TSE_ERROR_H__ +#define __TSE_ERROR_H__ + + +typedef enum en_errno { + CT_SUCCESS = 0, + ERR_ALLOC_MEMORY = 1, + ERR_CAPABILITY_NOT_SUPPORT = 101, + ERR_OPERATIONS_NOT_SUPPORT = 130, + ERR_GENERIC_INTERNAL_ERROR = 299, + ERR_TOO_MANY_CONNECTIONS = 403, + ERR_NOT_SUPPORT = 404, + ERR_ROW_LOCKED_NOWAIT = 408, + ERR_USER_DDL_LOCKED = 411, + ERR_CLT_PARALLEL_LOCK = 517, + ERR_SQL_SYNTAX_ERROR = 601, + ERR_COLUMNS_MISMATCH = 619, + ERR_INVALID_SESSION_ID = 683, + ERR_MAX_ROLE_COUNT = 686, + ERR_TOO_MANY_OBJECTS = 706, + ERR_COLUMN_HAS_NULL = 709, + ERR_SNAPSHOT_TOO_OLD = 715, + ERR_DEAD_LOCK = 716, + ERR_LOCK_TIMEOUT = 717, + ERR_OPERATION_CANCELED = 718, + ERR_DC_INVALIDATED = 722, + ERR_RECORD_SIZE_OVERFLOW = 727, + ERR_DUPLICATE_KEY = 729, + ERR_DEF_CHANGED = 732, + ERR_SERIALIZE_ACCESS = 735, + ERR_SAVEPOINT_NOT_EXIST = 736, + ERR_TOO_MANY_SAVEPOINTS = 737, + ERR_NO_MORE_LOCKS = 740, + ERR_NAME_TOO_LONG = 748, + ERR_OBJECT_EXISTS = 753, + ERR_INDEX_INVALID = 759, + ERR_FILE_NOT_EXIST = 771, + ERR_SPACE_NOT_EXIST = 780, + ERR_USER_NOT_EXIST = 781, + ERR_SPACE_ALREADY_EXIST = 788, + ERR_ROW_SELF_UPDATED = 814, + ERR_COL_TYPE_MISMATCH = 817, + ERR_BTREE_LEVEL_EXCEEDED = 820, + ERR_TABLE_OR_VIEW_NOT_EXIST = 843, + ERR_COLUMN_NOT_EXIST = 844, + ERR_FUNCTION_NOT_EXIST = 845, + ERR_TABLE_ID_NOT_EXIST = 846, + ERR_DROP_CONS = 847, + ERR_SEQ_NOT_EXIST = 848, + ERR_OBJECT_ALREADY_DROPPED = 849, + ERR_XA_EXTEND_BUFFER_EXCEEDED = 850, + ERR_ALLOC_TEMP_EXTENT = 851, + ERR_RECYCLE_PARTITION_NOT_EXIST = 852, + ERR_PERMANENTOBJ_IN_TEMPSPACE = 853, + ERR_BACKUP_RESTORE = 855, + ERR_CANNOT_MODIFY_COLUMN = 856, + ERR_LOG_ARCH_DEST_IN_USE = 857, + ERR_CANNOT_CLOSE_ARCHIVE = 858, + ERR_OPEN_RESETLOGS = 859, + ERR_LOGFILE_OPERATION_CANCELED = 860, + ERR_SPACE_OPEARTION_CANCELED = 861, + ERR_READMODE_OPEARTION_CANCELED = 862, + ERR_RENAME_FUNC_INDEX = 863, + ERR_ENFORCE_INDEX = 864, + ERR_EXCEED_MAX_BACKUP_PATH_LEN = 865, + ERR_NO_AUTO_INCREMENT_COLUMN = 866, + ERR_DATABASE_IS_ROLLING_BACK = 867, + ERR_TOO_MANY_TABLES = 868, + ERR_CHECKSUM_FAILED = 869, + ERR_NOLOGGING_SPACE = 870, + ERR_MISUSE_UNDO_SPACE = 871, + ERR_PART_LIST_COUNT = 872, + ERR_USER_ID_NOT_EXIST = 873, + ERR_EXCEED_MAX_INCR_BACKUP = 874, + ERR_ALTER_DB_TIMEZONE_FAILED = 875, + ERR_SHRINK_SPACE_SIZE = 876, + ERR_CANNOT_OPEN_DATABASE = 877, + ERR_SEND_RECORD_REQ_FAILED = 878, + ERR_RECORD_BACKUP_FAILED = 879, + ERR_PAGE_CORRUPTED = 880, + ERR_DATAFILE_RESIZE_TOO_SMALL = 881, + ERR_EXCLUDE_SPACES = 882, + ERR_INDEX_ALREADY_DROPPED = 883, + ERR_DATAFILE_RESIZE_EXCEED = 884, + ERR_XA_IN_AUTON_TRANS = 885, + ERR_SHRINK_EXTEND = 886, + ERR_SPACE_NO_DATAFILE = 887, + ERR_DUPLICATE_ENTRY = 970, + + ERR_ROW_IS_REFERENCED = 1123, + ERR_CONSTRAINT_VIOLATED_NO_FOUND = 1128, + ERR_EXCEED_MAX_CASCADE_DEPTH = 1133, + ERR_CHILD_ROW_CANNOT_ADD_OR_UPDATE = 1134, + + /* additional: sql engine */ + ERR_DUPLICATE_AUTO_COLUMN = 1300, + ERR_DUPLICATE_TABLE = 1301, + ERR_UNKNOWN_LOB_TYPE = 1302, + ERR_CONVERT_TYPE = 1303, + ERR_UNSUPPORT_DATATYPE = 1304, + ERR_UNKNOWN_PLAN_TYPE = 1305, + ERR_INVALID_DATAFILE_NUMBER = 1306, + ERR_STORED_PROCEDURE = 1307, + ERR_FEW_FILLED = 1308, + ERR_DISTRI_COLUMN_DATA_TYPE = 1309, + ERR_COMMENT_OBJECT_TYPE = 1310, + ERR_MUST_BE_FIX_DATATYPE = 1311, + ERR_KEY_EXPECTED = 1312, + ERR_INVALID_ATTR_NAME = 1313, + ERR_ONLY_SUPPORT_STR = 1314, + ERR_COMPARE_TYPE = 1315, + ERR_UNEXPECTED_KEY = 1316, + ERR_UNEXPECTED_ARRG = 1317, + ERR_UNKNOWN_DATATYPE = 1318, + ERR_NUM_OVERFLOW = 1319, + ERR_UNDEFINED_OPER = 1320, + ERR_UNKNOWN_ARRG_OPER = 1321, + ERR_CALC_EXPRESSION = 1322, + ERR_UNSUPPORT_FUNC = 1323, + ERR_INVOKE_FUNC_FAIL = 1324, + ERR_COLUMN_DATA_TYPE = 1325, + ERR_CAST_TO_COLUMN = 1326, + ERR_UNSUPPORT_OPER_TYPE = 1327, + ERR_TOO_MANY_ARRG = 1328, + ERR_INVALID_FUNC = 1329, + ERR_PARAM_VALUE_OUT_RANGE = 1330, + ERR_INVALID_PACKAGE = 1331, + ERR_FORBID_CREATE_SYS_USER = 1332, + ERR_NO_OPTION_SPECIFIED = 1333, + ERR_XA_TRANS_EXEC = 1334, + ERR_READ_LOB_NULL = 1335, + ERR_DATANODE_EXIST = 1336, + ERR_DATANODE_NOT_EXIST = 1337, + ERR_COORDNODE_FORBIDDEN = 1338, + ERR_DISTRI_COLUMN_FORBIDDEN = 1339, + ERR_INVALID_SEL4UPDATE = 1340, + ERR_NO_SORT_ITEM_REMOTE = 1341, + ERR_COLUM_LIST_EXCEED = 1342, + ERR_INVALID_PROTOCOL_INVOKE = 1343, + ERR_INVALID_STATEMENT_ID = 1344, + ERR_DML_INSIDE_QUERY = 1345, + ERR_EXCEED_MAX_FIELD_LEN = 1346, + ERR_FUNCTION_NOT_INDEXABLE = 1347, + ERR_RESERV_SQL_CURSORS_DECREASE = 1348, + ERR_SELECT_ROWID = 1349, + ERR_INVALID_NUMBER_FORAMT = 1350, + ERR_INVALID_SESSION_TYPE = 1351, + ERR_SQL_MAP_ONLY_SUPPORT_DML = 1352, + ERR_SQL_MAP_NOT_EXIST = 1353, + ERR_TF_ONLY_ONE_TABLE = 1354, + ERR_TF_TABLE_NAME_NULL = 1355, + ERR_EXCEED_MAX_STMTS = 1356, + ERR_DEFAULT_LEN_TOO_LARGE = 1357, + ERR_EXPECT_COLUMN_HERE = 1358, + ERR_FOR_UPDATE_FROM_VIEW = 1359, + ERR_CALC_COLUMN_NOT_ALLOWED = 1360, + ERR_FOR_UPDATE_NOT_ALLOWED = 1361, + ERR_INVALID_ARRAY_FORMAT = 1362, + ERR_WRONG_ELEMENT_COUNT = 1363, + ERR_INDEX_ON_ARRAY_FIELD = 1364, + ERR_DATATYPE_NOT_SUPPORT_ARRAY = 1365, + ERR_INVALID_ARG_TYPE = 1366, + ERR_CONVERT_CODE_FAILED = 1367, + ERR_REF_ON_ARRAY_COLUMN = 1368, + ERR_SET_DEF_ARRAY_VAL = 1369, + ERR_INVALID_SUBSCRIPT = 1370, + ERR_USE_WRONG_SUBSCRIPT = 1371, + ERR_ARRAY_NOT_SUPPORT = 1372, + ERR_MODIFY_ARRAY_COLUMN = 1373, + ERR_MODIFY_ARRAY_DATATYPE = 1374, + ERR_WRONG_TABLE_TYPE = 1375, + ERR_TF_DDL_ID_NULL = 1376, + ERR_TF_DDL_INFO_NULL = 1377, + ERR_TF_DDL_ID_OVER_LEN = 1378, + ERR_TF_DDL_INFO_OVER_LEN = 1379, + ERR_ARRAY_TO_STR_FAILED = 1380, + ERR_AUTOINC_READ_FAILED = 1467, + + ERR_OAMAP_DUP_KEY_ERROR = 2008, + ERR_OAMAP_INSERTION_FAILED = 2009, + ERR_OAMAP_FETCH_FAILED = 2010, + + ERR_GSS_FILE_IS_OPEN = 2042, + + // SHM and TSE + ERR_SEM_FAULT = 4000, + ERR_BATCH_DATA_HANDLE_FAILED = 4001, + ERR_SHM_SEND_MSG_FAILED = 4002, + ERR_INSTANCE_REG_FAILED = 4003, + ERR_CONNECTION_FAILED = 4004, + + ERR_USER_NOT_EMPTY_4MYSQL = 4005, + ERR_FK_NO_INDEX_PAREN_4MYSQL = 4006, + ERR_CHILD_DUPLICATE_KEY = 4007, + TSE_DDL_VERSION_NOT_MATCH = 9999, +} ct_errno_t; + +#define convert_tse_error_code_to_mysql(error) convert_tse_error_code_to_mysql_impl(error, __func__, __LINE__) +int convert_tse_error_code_to_mysql_impl(ct_errno_t error, const char* funcName, const int line); + +void tse_alter_table_handle_fault(ct_errno_t error); +#endif \ No newline at end of file diff --git a/storage/tianchi/tse_log.h b/storage/tianchi/tse_log.h new file mode 100644 index 0000000..81b4507 --- /dev/null +++ b/storage/tianchi/tse_log.h @@ -0,0 +1,152 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include // vfprintf, stderr +#include +#include +#include "sql/log.h" +#include "sql/mysqld.h" +#include +#include "my_dbug.h" +#include "mysqld_error.h" + +#ifndef __TSE_LOG_H__ +#define __TSE_LOG_H__ + +#define TSE_LOG_SIZE 1024 +#define UNUSED_PARAM(_p) (void(_p)) // supress warning declared but not used +#define __FILENAME__ (strrchr("/" __FILE__, '/') + 1) + +typedef enum en_regex_type_e +{ + REGEX_LINE, + REGEX_SECURITY, + REGEX_TOKEN, + REGEX_PASSWORD +}regex_type_e; + +typedef struct regex_conf +{ + regex_type_e regex_type; + const char regex[256]; +}regex_conf_t; + +static regex_conf_t g_regex_conf[] = +{ + {REGEX_SECURITY, "security:\\S*"}, // 加密密钥 + {REGEX_TOKEN, "[Tt][Oo][Kk][Ee][Nn]((\\S*)|(\\s*:\\s*)|(\\s*=\\s*)|(\\s*-\\s*)|(\\s*\\(\\s*)|(\\s*\\[\\s*)|(\\s*\\{\\s*))\\S*"}, // token + {REGEX_PASSWORD, "[Pp][Aa][Ss][Ss]([Ww]|[Ww][Dd]|[Ww][Oo][Rr][Dd])((\\S*)|(\\s*:\\s*)|(\\s*=\\s*)|(\\s*-\\s*)|(\\s*\\(\\s*)|(\\s*\\[\\s*)|(\\s*\\{\\s*))\\S*"} // password +}; + +static void replace_all(char *filter_str, const char *regex) { + std::regex pattern(regex); + std::string s(filter_str); + s = std::regex_replace(s, pattern, "*****"); + if (s.length() >= TSE_LOG_SIZE) { + s = s.substr(0, TSE_LOG_SIZE - 1); + } + strcpy(filter_str, s.c_str()); + filter_str[s.length()] = '\0'; + return; +} + +static void do_security_filter(char *filter_str) { + for (uint index = 0; index < sizeof(g_regex_conf) / sizeof(g_regex_conf[0]); index++) { + replace_all(filter_str, g_regex_conf[index].regex); + } +} + +/* + Print message to MySQL Server's error log(s) + + @param loglevel Selects the loglevel used when + printing the message to log. + @param[in] fmt printf-like format string + @param[in] ap Arguments + +*/ + +inline void tse_log_print(enum loglevel loglevel, const char *fmt, ...) MY_ATTRIBUTE((format(printf, 2, 3))); + +void tse_log_print(enum loglevel loglevel, const char *fmt, ...) { + if (log_error_verbosity < loglevel) return; + assert(fmt); + va_list args; + char msg_buf[TSE_LOG_SIZE]; + + va_start(args, fmt); + int res = vsnprintf(msg_buf, sizeof(msg_buf), fmt, args); + va_end(args); + + assert(res); + if (res >= TSE_LOG_SIZE) { + msg_buf[TSE_LOG_SIZE - 2] = '.'; + msg_buf[TSE_LOG_SIZE - 3] = '.'; + msg_buf[TSE_LOG_SIZE - 4] = '.'; + } + + if (!opt_general_log_raw) { //配置文件中的log-raw + do_security_filter(msg_buf); + } + + LogErr(loglevel, ER_IB_MSG_1381, msg_buf); +} + +/* System Level log */ +#define tse_log_system(fmt, args...) tse_log_print(SYSTEM_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) + +/* Error Level log */ +#define tse_log_error(fmt, args...) tse_log_print(ERROR_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) + +/* Warning Level log */ +#define tse_log_warning(fmt, args...) tse_log_print(WARNING_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) + +/* note Level log */ +#define tse_log_note(fmt, args...) tse_log_print(INFORMATION_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) +#define tse_log_verbose tse_log_note +#define tse_log_info tse_log_note +#define tse_log_trivia tse_log_note + +/* debug only Level log */ +#define tse_log_debug(fmt, args...) DBUG_PRINT("tse", (fmt, ##args)) +#define tse_log_debug_only tse_log_debug + +#define TSE_ENGINE_ERROR(message) \ + do { \ + tse_log_error(message); \ + my_error(ER_IB_MSG_1381, MYF(0), message); \ + } while (0) + +#define TSE_RETURN_IF_ERROR(_expVal, retVal) \ + do { \ + bool _status_ = (_expVal); \ + if (!_status_) { \ + tse_log_system("TSE_RETURN_IF_ERROR return"); \ + return retVal; \ + } \ + } while (0) + +#define TSE_RETURN_IF_NOT_ZERO(retVal) \ + do { \ + int ret = retVal; \ + if (ret != 0) { \ + tse_log_system("TSE_RETURN_IF_NOT_ZERO return"); \ + return ret; \ + } \ + } while (0) + +#endif // __TSE_LOG_H__ diff --git a/storage/tianchi/tse_mysql_proxy.cc b/storage/tianchi/tse_mysql_proxy.cc new file mode 100644 index 0000000..f2ac71d --- /dev/null +++ b/storage/tianchi/tse_mysql_proxy.cc @@ -0,0 +1,690 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#include +#include +#include +#include +#include +#include "my_md5.h" +#include "my_md5_size.h" +#include "mysql.h" +#include "sql/mysqld.h" // mysql_port, my_localhost +#include "tse_log.h" +#include "tse_srv.h" +#include "tse_util.h" +#include "ctc_meta_data.h" +#include "tse_proxy_util.h" +#include "sql/sql_table.h" +#include "my_dir.h" +#include "sql/sql_handler.h" +#include "sql/sql_base.h" +#include "sql/sql_class.h" +#include "sql/dd/cache/dictionary_client.h" +#include "sql/mysqld_thd_manager.h" +#include "sql/dd/types/procedure.h" +#include "sql/dd/types/function.h" +#include "sql/dd/types/routine.h" +#include "sql/mdl.h" +#include "sql/dd/types/event.h" +#include "sql/dd/types/resource_group.h" +#include "sql/dd/types/trigger.h" +#include "sql/auth/auth_common.h" +#include "sql/sys_vars_shared.h" // intern_find_sys_var +#include "sql/sql_lex.h" // lex_start/lex_end +#include "sql/handler.h" // ha_tse_commit + +using namespace std; + +struct ctc_mysql_conn { + MYSQL* conn; + set> table_lock_info; // 连接上已存在的表锁 (db, table) + bool has_explicit_table_lock; // 连接上是否存在显式的表锁 + uint32_t name_locks; // 连接上持有的命名锁数量 +}; + +static map g_mysql_conn_map; +static mutex m_tse_mysql_proxy_mutex; + +static ctc_mysql_conn* init_ctc_mysql_conn(MYSQL* curr_conn) { + ctc_mysql_conn *ctc_conn_info = new ctc_mysql_conn(); + ctc_conn_info->conn = curr_conn; + ctc_conn_info->table_lock_info = set>(); + ctc_conn_info->has_explicit_table_lock = false; + ctc_conn_info->name_locks = 0; + return ctc_conn_info; +} + +static void set_explicit_table_lock(uint64_t conn_map_key, uint8_t sql_command) { + lock_guard lock(m_tse_mysql_proxy_mutex); + if (sql_command == SQLCOM_LOCK_TABLES) { + g_mysql_conn_map[conn_map_key]->has_explicit_table_lock = true; + } else if (sql_command == SQLCOM_UNLOCK_TABLES) { + g_mysql_conn_map[conn_map_key]->has_explicit_table_lock = false; + } + return; +} + +int tse_select_db(MYSQL *curr_conn, const char *db) { + if (CM_IS_EMPTY_STR(db)) { + return 0; + } + + int ret = mysql_ping(curr_conn); + if (ret != 0) { + tse_log_error("tse_select_db: mysql server has gone. db:%s error_code:%d, reconnecting.", db, ret); + } + + ret = mysql_select_db(curr_conn, db); + if (ret != 0) { + tse_log_error("select db:%s failed,ret:%d, error_code:%d,desc:%s", db, ret, + mysql_errno(curr_conn), mysql_error(curr_conn)); + return mysql_errno(curr_conn); + } + return 0; +} + +static void tse_drop_proxy_user(MYSQL *agent_conn, const string &proxy_user_name) +{ + string drop_user_sql = "drop user if exists '" + proxy_user_name + "';"; + + if (tse_mysql_query(agent_conn, drop_user_sql.c_str())) { + tse_log_error("tse_drop_proxy_user failed, drop user=%s, sql=%s, err_code=%d, err_msg=%s", + proxy_user_name.c_str(), drop_user_sql.c_str(), mysql_errno(agent_conn), mysql_error(agent_conn)); + assert(0); + } +} + +static int tse_create_proxy_user(MYSQL *agent_conn, const char*user_name, const char*user_ip, + string &proxy_user_name, string &proxy_user_password) +{ + string create_user_sql = "CREATE USER '" + proxy_user_name + \ + "' IDENTIFIED WITH 'mysql_native_password' BY RANDOM PASSWORD;"; + int ret = tse_mysql_query(agent_conn, create_user_sql.c_str()); // ret: success: 0, fail: 1 + + int err_code = mysql_errno(agent_conn); + char err_msg[ERROR_MESSAGE_LEN] = {0}; + strncpy(err_msg, mysql_error(agent_conn), ERROR_MESSAGE_LEN - 1); + if (ret != 0 || err_code != 0) { + tse_log_error("tse_create_proxy_user failed to create user %s, " + "sql=%s, ret=%d, err_code=%d, err_msg=%s", + proxy_user_name.c_str(), create_user_sql.c_str(), ret, err_code, err_msg); + return err_code; + } + + MYSQL_RES *result = mysql_store_result(agent_conn); + if (result == nullptr) { + tse_log_error("tse_create_proxy_user store result failed, user name:%s", user_name); + tse_drop_proxy_user(agent_conn, proxy_user_name); + return -1; + } + + MYSQL_ROW row = mysql_fetch_row(result); + if (row == nullptr) { + tse_log_error("tse_create_proxy_user mysql_fetch_row failed, user name:%s", user_name); + tse_drop_proxy_user(agent_conn, proxy_user_name); + return -1; + } + + proxy_user_password = row[2]; + mysql_free_result(result); + + string username(user_name); + username = tse_escape_single_quotation_str(username); + + string grant_user_sql = "grant proxy on '" + username + + "'@'" + string(user_ip) + "' to '" + proxy_user_name + "';"; + ret = tse_mysql_query(agent_conn, grant_user_sql.c_str()); + + err_code = mysql_errno(agent_conn); + strncpy(err_msg, mysql_error(agent_conn), ERROR_MESSAGE_LEN - 1); + if (ret != 0 || err_code != 0) { + tse_log_error("tse_create_proxy_user failed to grant %s to %s, " + "sql=%s, ret=%d, err_code=%d, err_msg=%s", + user_name, proxy_user_name.c_str(), grant_user_sql.c_str(), ret, err_code, err_msg); + tse_drop_proxy_user(agent_conn, proxy_user_name); + return err_code; + } + return 0; +} + +static int tse_init_proxy_client(MYSQL *&curr_conn, uint64_t conn_map_key, + const char *user_name, const char *user_ip) +{ + MYSQL *agent_conn = NULL; + int ret = tse_init_agent_client(agent_conn); + if (ret != 0) { + return ret; + } + + SENSI_INFO string proxy_user_password; + string proxy_user_name = "proxy_" + std::to_string(conn_map_key); + + ret = tse_create_proxy_user(agent_conn, user_name, user_ip, proxy_user_name, proxy_user_password); + if (ret != 0) { + tse_log_error("tse_init_proxy_client tse_create_proxy_user failed, ret=%d", ret); + tse_close_mysql_conn(&agent_conn); + return ret; + } + + const char *con_host = my_localhost; + if (strcmp(user_ip, "%") != 0) { + con_host = user_ip; + } + ret = tse_mysql_conn(curr_conn, con_host, proxy_user_name.c_str(), proxy_user_password.c_str()); + proxy_user_password.clear(); + if (ret) { + tse_log_error("tse_init_proxy_client tse_mysql_conn failed, user=%s, err_code=%d, err_msg=%s.", + proxy_user_name.c_str(), mysql_errno(curr_conn), mysql_error(curr_conn)); + tse_close_mysql_conn(&curr_conn); + } + + tse_drop_proxy_user(agent_conn, proxy_user_name); + tse_close_mysql_conn(&agent_conn); + return ret; +} + +static void get_ctc_mysql_conn(uint64_t conn_map_key, MYSQL *&curr_conn) { + lock_guard lock(m_tse_mysql_proxy_mutex); + auto iter = g_mysql_conn_map.find(conn_map_key); + if (iter != g_mysql_conn_map.end()) { + curr_conn = iter->second->conn; + } +} + +int tse_init_mysql_client(uint64_t conn_map_key, const char *db, MYSQL *&curr_conn, + const char *user_name, const char *user_ip, bool use_proxy) { + + if (opt_noacl && strcmp(user_name, "skip-grants user") == 0) { + use_proxy = false; + } + + get_ctc_mysql_conn(conn_map_key, curr_conn); + + int ret = 0; + if (curr_conn != NULL) { + ret = tse_select_db(curr_conn, db); + if (ret == 0) { + return 0; + } + + tse_log_error("tse_init_mysql_client select db failed, err_code=%d, err_msg=%s.", + mysql_errno(curr_conn), mysql_error(curr_conn)); + lock_guard lock(m_tse_mysql_proxy_mutex); + delete g_mysql_conn_map[conn_map_key]; + g_mysql_conn_map.erase(conn_map_key); + tse_close_mysql_conn(&curr_conn); + } + + assert(curr_conn == nullptr); + while(!mysqld_server_started) { + tse_log_system("[TSE_INIT]:tse_init_mysql_client wait mysql server start!!!!"); + sleep(1); + } + + if (use_proxy) { + ret = tse_init_proxy_client(curr_conn, conn_map_key, user_name, user_ip); + } else { + ret = tse_init_agent_client(curr_conn); + } + + if (ret) { + tse_log_error("init mysql client failed ret=%d", ret); + return ret; + } + + ret = tse_mysql_query(curr_conn, "set lock_wait_timeout = 1;"); + if (ret != 0 || mysql_errno(curr_conn) != 0) { + tse_log_error("set lock_wait_timeout = 1 failed. err_code:%u, err_msg:%s", + mysql_errno(curr_conn), mysql_error(curr_conn)); + } + + ret = tse_select_db(curr_conn, db); + if (ret != 0) { + tse_log_error("tse_init_mysql_client select db failed, err_code=%d, err_msg=%s.", + mysql_errno(curr_conn), mysql_error(curr_conn)); + tse_close_mysql_conn(&curr_conn); + return ret; + } + + { + lock_guard lock(m_tse_mysql_proxy_mutex); + g_mysql_conn_map[conn_map_key] = init_ctc_mysql_conn(curr_conn); + } + return 0; +} + +static void close_mysql_conn_by_key(uint64_t conn_map_key) { + /* 存在并发场景 map操作加锁 */ + lock_guard lock(m_tse_mysql_proxy_mutex); + auto iter = g_mysql_conn_map.find(conn_map_key); + + if (iter == g_mysql_conn_map.end()) { + tse_log_system("[TSE_CLOSE_CONN]: Connection has already been closed or not exists (key=%lu)", conn_map_key); + return; + } + + MYSQL *mysql_conn = iter->second->conn; + tse_close_mysql_conn(&mysql_conn); + + uint32_t name_locks = sub_g_name_locks(iter->second->name_locks); + tse_log_system("[TSE_CLOSE_CONN]: Close connect by key=%lu, current global name locks=%u", conn_map_key, name_locks); + + delete g_mysql_conn_map[conn_map_key]; + g_mysql_conn_map.erase(conn_map_key); +} + +static MYSQL* get_mysql_conn_by_key(uint64_t conn_map_key) { + /* 存在并发场景 map操作加锁 */ + lock_guard lock(m_tse_mysql_proxy_mutex); + auto iter = g_mysql_conn_map.find(conn_map_key); + + if (iter == g_mysql_conn_map.end()) { + tse_log_system("get mysql Connection has already been closed or not exists (key=%lu)", conn_map_key); + return NULL; + } + return iter->second->conn; +} + +static void close_mysql_conn_by_inst_id(uint32_t inst_id, bool by_mysql_inst) { + lock_guard lock(m_tse_mysql_proxy_mutex); + for (auto iter = g_mysql_conn_map.begin(); iter != g_mysql_conn_map.end(); ) { + uint32_t find_id = by_mysql_inst ? tse_get_inst_id_from_conn_key(iter->first) : + tse_get_cantian_id_from_conn_key(iter->first); + if (find_id == inst_id) { + MYSQL *mysql_conn = iter->second->conn; + tse_close_mysql_conn(&mysql_conn); + uint32_t name_locks = sub_g_name_locks(iter->second->name_locks); + tse_log_system("[TSE_CLOSE_CONN]: Close connects by mysql_id/cantian_id = %d, instance_id=%u, key=%lu," + "current global name locks=%u", by_mysql_inst, inst_id, iter->first, name_locks); + + delete g_mysql_conn_map[iter->first]; + iter = g_mysql_conn_map.erase(iter); + } else { + ++iter; + } + } +} + +static inline bool is_backup_lock_op(uint8_t sql_command) { + return sql_command == SQLCOM_LOCK_INSTANCE || + sql_command == SQLCOM_UNLOCK_INSTANCE; +} + +extern uint32_t tse_instance_id; +__attribute__((visibility("default"))) int tse_execute_rewrite_open_conn(uint32_t thd_id, tse_ddl_broadcast_request *broadcast_req) { + // 相同节点不用执行 + if (broadcast_req->mysql_inst_id == tse_instance_id) { + return 0; + } + + bool use_proxy = !is_backup_lock_op(broadcast_req->sql_command); + uint64_t conn_map_key = tse_get_conn_key(broadcast_req->mysql_inst_id, thd_id, use_proxy); + + MYSQL *curr_conn = NULL; + int ret = tse_init_mysql_client(conn_map_key, broadcast_req->db_name, curr_conn, + broadcast_req->user_name, broadcast_req->user_ip, use_proxy); + if (ret != 0) { + broadcast_req->err_code = ret; + tse_log_error("[TSE_REWRITE_CONN]:init_mysql_client failed, ret:%d, conn_map_key:%lu, sql:%s", ret, conn_map_key, + sql_without_plaintext_password(broadcast_req).c_str()); + return ret; + } + + tse_log_system("[TSE_REWRITE_CONN]: remote open conn for sql=%s, user_name:%s, success, mysql_inst_id=%u," + "conn_map_key:%lu", sql_without_plaintext_password(broadcast_req).c_str(), broadcast_req->user_name, + broadcast_req->mysql_inst_id, conn_map_key); + + mysql_free_result(mysql_store_result(curr_conn)); + return 0; +} + +__attribute__((visibility("default"))) int tse_ddl_execute_update(uint32_t thd_id, tse_ddl_broadcast_request *broadcast_req, bool *allow_fail) { + // 相同节点不用执行 + if(broadcast_req->mysql_inst_id == tse_instance_id) { + tse_log_note("tse_ddl_execute_update curnode not need execute,mysql_inst_id:%u", broadcast_req->mysql_inst_id); + return 0; + } + + bool is_meta_normalization = IS_METADATA_NORMALIZATION(); + if (is_meta_normalization && broadcast_req->sql_command != SQLCOM_SET_OPTION) { + return 0; + } else if (is_meta_normalization && broadcast_req->sql_command == SQLCOM_SET_OPTION + && (broadcast_req->options & TSE_SET_VARIABLE_WITH_SUBSELECT) == 0){ + ctc_set_sys_var(broadcast_req); + return 0; + } + + bool use_proxy = !is_backup_lock_op(broadcast_req->sql_command); + uint64_t conn_map_key = tse_get_conn_key(broadcast_req->mysql_inst_id, thd_id, use_proxy); + + MYSQL *curr_conn = NULL; + int ret = tse_init_mysql_client(conn_map_key, broadcast_req->db_name, curr_conn, + broadcast_req->user_name, broadcast_req->user_ip, use_proxy); + if (ret != 0) { + broadcast_req->err_code = ret; + tse_log_error("[TSE_DDL]:init_mysql_client failed, ret:%d, conn_id:%u, sql_str:%s", ret, thd_id, + sql_without_plaintext_password(broadcast_req).c_str()); + + return ret; + } + + // 设置随机密码seed + if (broadcast_req->sql_command == SQLCOM_CREATE_USER || broadcast_req->sql_command == SQLCOM_ALTER_USER || broadcast_req->sql_command == SQLCOM_SET_PASSWORD) { + ret = tse_mysql_query(curr_conn, ("set @random_password_seed = " + std::to_string(thd_id) + ";").c_str()); + if (ret != 0) { + tse_log_error("tse_init_proxy_client set @random_password_seed failed, error_code:%d", mysql_errno(curr_conn)); + return ret; + } + } + + if (broadcast_req->options & TSE_OPEN_NO_CHECK_FK_FOR_CURRENT_SQL) { + if (tse_mysql_query(curr_conn, "SET SESSION foreign_key_checks = 0;")) { + tse_log_error("tse_init_proxy_client SET SESSION foreign_key_checks = 0; failed, error_code:%d,error:%s", mysql_errno(curr_conn), mysql_error(curr_conn)); + broadcast_req->err_code = mysql_errno(curr_conn); + tse_close_mysql_conn(&curr_conn); + return broadcast_req->err_code; + } + } + ret = tse_mysql_query(curr_conn, broadcast_req->sql_str); // ret: success: 0, fail: 1 + int error_code = mysql_errno(curr_conn); + if (ret != 0 || error_code != 0) { + broadcast_req->err_code = error_code; + strncpy(broadcast_req->err_msg, mysql_error(curr_conn), ERROR_MESSAGE_LEN - 1); + tse_log_error("[TSE_DDL]:mysql query exectue failed. err_code:%d, err_msg:%s, sql_str:%s, user_name:%s," + " conn_id:%u, allow_fail:%d",error_code, broadcast_req->err_msg, + sql_without_plaintext_password(broadcast_req).c_str(), broadcast_req->user_name, thd_id, *allow_fail); + return broadcast_req->err_code; + } + + if (broadcast_req->options & TSE_OPEN_NO_CHECK_FK_FOR_CURRENT_SQL) { + if (tse_mysql_query(curr_conn, "SET SESSION foreign_key_checks = 1;")) { + tse_log_error("tse_init_proxy_client SET SESSION foreign_key_checks = 1; failed, error_code:%d,error:%s", mysql_errno(curr_conn), mysql_error(curr_conn)); + broadcast_req->err_code = mysql_errno(curr_conn); + tse_close_mysql_conn(&curr_conn); + return broadcast_req->err_code; + } + } + + tse_log_system("[TSE_DDL]: remote execute sql=%s, user_name:%s, success, mysql_inst_id=%u, conn_map_key:%lu", + sql_without_plaintext_password(broadcast_req).c_str(), broadcast_req->user_name, broadcast_req->mysql_inst_id, conn_map_key); + + set_explicit_table_lock(conn_map_key, broadcast_req->sql_command); + + // 存在执行成功的节点,后续流程不再允许失败 + *allow_fail = false; + mysql_free_result(mysql_store_result(curr_conn)); + return 0; +} + +static int tse_ddl_get_lock(MYSQL *curr_conn, const uint64_t &conn_map_key, const char *lock_name, int *err_code) { + uchar digest[MD5_HASH_SIZE]; + compute_md5_hash(pointer_cast(digest), lock_name, strlen(lock_name)); + + // + 1 for the null terminator + char output[(MD5_HASH_SIZE * 2) + 1]; + array_to_hex(output, digest, MD5_HASH_SIZE); + output[(MD5_HASH_SIZE * 2)] = '\0'; + + string lock_function_str = string("SELECT GET_LOCK('") + output + string("', 0);"); + int ret = tse_mysql_query(curr_conn, lock_function_str.c_str()); + *err_code = mysql_errno(curr_conn); + if (ret != 0 || *err_code != 0) { + tse_log_error("[TSE_LOCK_TABLE]:execute GET_LOCK() failed, " + "return_err: %d, err_code:%d, err_msg:%s, lock_function_str:%s", + ret, *err_code, mysql_error(curr_conn), lock_function_str.c_str()); + return *err_code; + } + + MYSQL_RES *query_res = mysql_store_result(curr_conn); + if (query_res == nullptr) { + tse_log_error("[TSE_LOCK_TABLE]:execute GET_LOCK() failed to store result, lock_name:%s, err_msg:%s", + lock_name, mysql_error(curr_conn)); + return 1; + } + + MYSQL_ROW row_res = mysql_fetch_row(query_res); + /* If the return value of get_lock() is 0, obtaining the lock times out. */ + if (atoi(*row_res) == 0) { + *err_code = ER_DISALLOWED_OPERATION; + mysql_free_result(query_res); + return -1; + } + mysql_free_result(query_res); + + { + lock_guard lock(m_tse_mysql_proxy_mutex); + auto iter = g_mysql_conn_map.find(conn_map_key); + if (iter != g_mysql_conn_map.end()) { + iter->second->name_locks++; + uint32_t name_locks = add_g_name_locks(1); + tse_log_note("[TSE_LOCK_TABLE]: conn key=%lu, its name locks=%u, current global name locks=%u", + conn_map_key, iter->second->name_locks, name_locks); + } + } + return 0; +} + +int32_t tse_check_table_exist(MYSQL *curr_conn_proxy, const char *db_name, const char *table_name, int *err_code) { + string sql_str = "SELECT EXISTS (SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA LIKE '" + + string(db_name) + "' AND TABLE_NAME = '" + string(table_name) + "');"; + + MYSQL_RES *query_res = nullptr; + if (tse_mysql_query(curr_conn_proxy, sql_str.c_str()) || !(query_res = mysql_store_result(curr_conn_proxy))) { + *err_code = mysql_errno(curr_conn_proxy); + tse_log_error("[TSE_LOCK_TABLE]:err_msg:%s, db:%s, table:%s", mysql_error(curr_conn_proxy), db_name, table_name); + return -1; + } + + MYSQL_ROW row_res = mysql_fetch_row(query_res); + int32_t res = atoi(*row_res); + + mysql_free_result(query_res); + return res; +} + +__attribute__((visibility("default"))) int tse_ddl_execute_lock_tables(tianchi_handler_t *tch, char *db_name, tse_lock_table_info *lock_info, int *err_code) { + + if (IS_METADATA_NORMALIZATION()) { + if (tse_mdl_lock_thd(tch, lock_info, err_code)) { + return *err_code; + } + return 0; + } + + bool is_same_node = (tch->inst_id == tse_instance_id); + uint64_t conn_map_key = tse_get_conn_key(tch->inst_id, tch->thd_id, !is_same_node); + + MYSQL *curr_conn = NULL; + int ret = tse_init_mysql_client(conn_map_key, db_name, curr_conn, lock_info->user_name, lock_info->user_ip, !is_same_node); + if (ret != 0) { + *err_code = ret; + tse_log_error("[TSE_LOCK_TABLE]:tse_init_mysql_client failed, ret:%d, conn_id:%u, tse_instance_id:%u", + ret, tch->thd_id, tch->inst_id); + return ret; + } + + /* Operations on the Database, only need to lock the database. */ + if (strlen(lock_info->table_name) == 0) { + return tse_ddl_get_lock(curr_conn, conn_map_key, lock_info->db_name, err_code); + } + + string lock_name_str; + lock_name_str.append(lock_info->db_name); + lock_name_str.append("."); + lock_name_str.append(lock_info->table_name); + ret = tse_ddl_get_lock(curr_conn, conn_map_key, lock_name_str.c_str(), err_code); + if (ret != 0) { + return ret; + } + + /* Do not run lock_table on the same node. */ + if(is_same_node) { + tse_log_note("[TSE_LOCK_TABLE]:curnode not need execute, mysql_inst_id:%u", tch->inst_id); + return 0; + } + + if (lock_info->sql_type == SQLCOM_CREATE_TABLE || + lock_info->sql_type == SQLCOM_DROP_VIEW || + lock_info->sql_type == SQLCOM_CREATE_VIEW) { + tse_log_note("[TSE_LOCK_TABLE]:Skip lock_table. sql_cmd:%d", lock_info->sql_type); + return 0; + } + + if (g_mysql_conn_map[conn_map_key]->has_explicit_table_lock) { + tse_log_system("[TSE_LOCK_TABLE]: curnode doesn't need execute, conn_map_key=%lu, mysql_thd_id=%u, mysql_inst_id=%u", + conn_map_key, tch->thd_id, tch->inst_id); + return ret; + } + + int32_t row_res = tse_check_table_exist(curr_conn, lock_info->db_name, lock_info->table_name, err_code); + if (row_res > 0) { + lock_guard lock(m_tse_mysql_proxy_mutex); + g_mysql_conn_map[conn_map_key]->table_lock_info.insert(make_pair(lock_info->db_name, lock_info->table_name)); + } + + string lock_str = "lock tables "; + { + lock_guard lock(m_tse_mysql_proxy_mutex); + for (auto iter : g_mysql_conn_map[conn_map_key]->table_lock_info) { + row_res = tse_check_table_exist(curr_conn, iter.first.c_str(), iter.second.c_str(), err_code); + if (row_res <= 0) { + tse_log_warning("[TSE_LOCK_TABLE]:Table not exist. row_res:%d, db:%s, table:%s", row_res, iter.first.c_str(), iter.second.c_str()); + return 0; + } + + string db = cnvrt_name_for_sql(iter.first); + string table = cnvrt_name_for_sql(iter.second); + lock_str += "`" + db + "`.`" + table + "` write, "; + } + } + lock_str.erase(lock_str.end() - 2); /* 2 is comma and space len in string end */ + lock_str += ";"; + + if (g_mysql_conn_map[conn_map_key]->table_lock_info.size() > 0) { + ret = tse_mysql_query(curr_conn, lock_str.c_str()); + if (ret != 0 || mysql_errno(curr_conn) != 0) { + *err_code = mysql_errno(curr_conn); + tse_log_error("[TSE_LOCK_TABLE]:return_err:%d, err_code:%d, err_msg:%s, lock_sql_str:%s, conn_id:%u, tse_instance_id:%u", + ret, *err_code, mysql_error(curr_conn), lock_str.c_str(), tch->thd_id, tch->inst_id); + } + } + + return ret; +} + +__attribute__((visibility("default"))) int tse_ddl_execute_unlock_tables(tianchi_handler_t *tch, uint32_t mysql_inst_id, tse_lock_table_info *lock_info) + { + if (IS_METADATA_NORMALIZATION()) { + UNUSED_PARAM(mysql_inst_id); + tse_mdl_unlock_thd(tch, lock_info); + return 0; + } + + bool is_same_node = (tch->inst_id == tse_instance_id); + uint64_t conn_map_key = tse_get_conn_key(tch->inst_id, tch->thd_id, !is_same_node); + MYSQL *curr_conn = get_mysql_conn_by_key(conn_map_key); + if (curr_conn == NULL) { + tse_log_system("[TSE_UNLOCK_TABLE]: curr_conn is NULL, conn_map_key=%lu, conn_id=%u, tse_instance_id=%u", + conn_map_key, tch->thd_id, tch->inst_id); + return 0; + } + + /* Releases all named locks held by the current session */ + if (tse_mysql_query(curr_conn, "SELECT RELEASE_ALL_LOCKS();")) { + tse_log_error("[TSE_UNLOCK_TABLE]: RELEASE_ALL_LOCKS failed, close conn, conn_id=%u, err_code=%d, err_msg=%s", + tch->thd_id, mysql_errno(curr_conn), mysql_error(curr_conn)); + close_mysql_conn_by_key(conn_map_key); + return 0; + } + + mysql_free_result(mysql_store_result(curr_conn)); + + { + // 清空加锁信息 + lock_guard lock(m_tse_mysql_proxy_mutex); + auto iter = g_mysql_conn_map.find(conn_map_key); + if (iter != g_mysql_conn_map.end()) { + iter->second->table_lock_info.clear(); + if (iter->second->name_locks > 0) { + iter->second->name_locks--; + uint32_t name_locks = sub_g_name_locks(1); + tse_log_note("[TSE_LOCK_TABLE]: conn key=%lu, its name locks=%u, current global name locks=%u", + conn_map_key, iter->second->name_locks, name_locks); + } + } + } + + /* Do not run unlock_table on the same node. */ + if(is_same_node) { + close_mysql_conn_by_key(conn_map_key); + tse_log_note("[TSE_UNLOCK_TABLE]: curnode doesn't need execute, conn_map_key=%lu, mysql_inst_id=%u", conn_map_key, tch->inst_id); + return 0; + } + + if (g_mysql_conn_map[conn_map_key]->has_explicit_table_lock) { + tse_log_system("[TSE_UNLOCK_TABLE]: curnode doesn't need execute, conn_map_key=%lu, mysql_thd_id=%u, mysql_inst_id=%u", conn_map_key, tch->thd_id, tch->inst_id); + return 0; + } + + if (tse_mysql_query(curr_conn, "UNLOCK TABLES;")) { + tse_log_error("[TSE_UNLOCK_TABLE]: UNLOCK TABLES failed, close conn, conn_id=%u, err_code=%d, err_msg=%s", + tch->thd_id, mysql_errno(curr_conn), mysql_error(curr_conn)); + close_mysql_conn_by_key(conn_map_key); + return 0; + } + mysql_free_result(mysql_store_result(curr_conn)); + return 0; +} + +/* thd_id为0时,关闭实例id为mysql_inst_id的所有连接 +* mysql_inst_id: 高16位 ---> 参天实例id +* 低16位 ---> mysqld实例id, 由当前节点参天分配,取值范围(2-19) +* 低16位全为1代表整个参天节点故障,清理与参天实例id相关的资源 +*/ +__attribute__((visibility("default"))) int close_mysql_connection(uint32_t thd_id, uint32_t mysql_inst_id) { + if (IS_METADATA_NORMALIZATION()) { + close_tse_mdl_thd(thd_id, mysql_inst_id); + return 0; + } + + if (thd_id == 0) { + if ((uint16_t)mysql_inst_id == (uint16_t)CANTIAN_DOWN_MASK) { + /* 清理整个参天节点相关的连接 */ + tse_log_system("[TSE_CLOSE_SESSION]:Close All connects on bad node by cantian_instance_id:%u", + (mysql_inst_id >> 16)); + close_mysql_conn_by_inst_id((mysql_inst_id >> 16), false); + } else { + /* 清理整个mysqld节点相关的连接 */ + tse_log_system("[TSE_CLOSE_SESSION]:Close All connects by tse_instance_id:%u", mysql_inst_id); + close_mysql_conn_by_inst_id(mysql_inst_id, true); + } + } else { + /* 通过把mysql_inst_id左移32位 与 thd_id拼接在一起 用来唯一标识一个连接 */ + uint64_t proxy_conn_map_key = tse_get_conn_key(mysql_inst_id, thd_id, true); + tse_log_note("[TSE_CLOSE_SESSION]: Close connect by conn_id=%u, tse_instance_id=%u, proxy_conn_map_key=%lu", + thd_id, mysql_inst_id, proxy_conn_map_key); + close_mysql_conn_by_key(proxy_conn_map_key); + + uint64_t agent_conn_map_key = tse_get_conn_key(mysql_inst_id, thd_id, false); + tse_log_note("[TSE_CLOSE_SESSION]: Close connect by conn_id=%u, tse_instance_id=%u, agent_conn_map_key=%lu", + thd_id, mysql_inst_id, agent_conn_map_key); + close_mysql_conn_by_key(agent_conn_map_key); + } + return 0; +} diff --git a/storage/tianchi/tse_proxy_util.cc b/storage/tianchi/tse_proxy_util.cc new file mode 100644 index 0000000..e3b3214 --- /dev/null +++ b/storage/tianchi/tse_proxy_util.cc @@ -0,0 +1,224 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "tse_proxy_util.h" +#include +#include "tse_log.h" +#include "sql/sql_connect.h" +#include "sql/conn_handler/connection_handler_manager.h" // Connection_handler_manager +#include "compression.h" + +#define TSE_CONN_MAX_RETRY_TIMES 10 +#define TSE_PASSWORD_BUFFER_SIZE (uint32)512 + +#ifndef SENSI_INFO +#define SENSI_INFO +#endif + +static atomic g_name_locks(0); // 实例持有的命名锁总数,用于标记当前是否有 DDL 正在执行 + +uint32_t get_g_name_locks(void) { + return g_name_locks.load(); +} + +uint32_t add_g_name_locks(uint32_t num) { + uint32_t name_locks = g_name_locks.fetch_add(num); + return name_locks + num; +} + +uint32_t sub_g_name_locks(uint32_t num) { + uint32_t name_locks = g_name_locks.fetch_sub(num); + return name_locks - num; +} + +static bool is_dangerous_pwd(const char *password) { + + bool danger_pwd_flag = false; + + for(int i = 0; password[i] != '\0'; i++) { + if (!isalnum(password[i]) && password[i] != '+' && password[i] != '/' && password[i] != '=' && + !(password[i] == '\n' && password[i+1] == '\0')) { + danger_pwd_flag = true; + break; + } + } + return danger_pwd_flag; +} + +static int tse_get_agent_info(char *password, uint password_size) { + char *user_password = getenv("MYSQL_AGENT_PASSWORD"); + if (user_password == NULL) { + return -1; + } + if (is_dangerous_pwd(user_password)) { + tse_log_error("checking pwd failed"); + return -1; + } + + string cmd = "encrypt -d "; + cmd += user_password; + + FILE *fp = popen(cmd.c_str(), "r"); + if (fp == NULL) { + tse_log_error("encrypting cmd failed"); + return -1; + } + + if (fgets(password, password_size, fp) == NULL) { + tse_log_error("get password failed"); + pclose (fp); + return -1; + } + + size_t passwd_len = strlen(password); + passwd_len = passwd_len >= password_size ? password_size - 1 : passwd_len; + if (passwd_len > 0) { + password[passwd_len] = '\0'; + } + + // remove \n from the passwd + if(passwd_len > 0 && password[passwd_len -1] == '\n' ) { + password[passwd_len -1] = '\0'; + } + + pclose (fp); + return 0; +} + +static void tse_inc_conn_count(int &dec_conn_count) +{ + Connection_handler_manager *conn_manager = Connection_handler_manager::get_instance(); + conn_manager->check_and_incr_conn_count(true); + Connection_handler_manager::reset_max_used_connections(); + dec_conn_count--; + tse_log_warning("[TSE_CONN_INC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", + Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); +} + +static void tse_dec_conn_count(int &dec_conn_count) +{ + Connection_handler_manager::dec_connection_count(); + dec_conn_count++; + tse_log_warning("[TSE_CONN_DEC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", + Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); +} + +int tse_mysql_conn(MYSQL *&con, const char *host, const char *user, const char *passwd) { + con = mysql_init(NULL); + if (con == nullptr) { + tse_log_error("tse_mysql_conn mysql_init failed, error_code:%d,error:%s", mysql_errno(con), mysql_error(con)); + my_thread_end(); + if (!mysql_errno(con)) { + return CR_OUT_OF_MEMORY; + } + return mysql_errno(con); + } + + const bool opt_reconnect = true; + (void)mysql_options(con, MYSQL_OPT_RECONNECT, &opt_reconnect); + (void)mysql_options(con, MYSQL_DEFAULT_AUTH, "mysql_native_password"); + + // do init sql commands for new con. + // for ddl do not go to ctc SE. this command should be first executed. it should be placed firstly at mysql_options MYSQL_INIT_COMMAND. + (void)mysql_options(con, MYSQL_INIT_COMMAND, "set @ctc_ddl_local_enabled = true;"); + /* proxy的连接强制解除只读属性 + proxy的连接应该永远都是没有只读状态才对的,因为如果发起端连接只读,ddl不会转到远端, + 但是如果发起端没有只读属性,远端proxy建立的连接有只读属性,远端执行ddl就会报错,节点被踢掉 + */ + (void)mysql_options(con, MYSQL_INIT_COMMAND, "SET SESSION TRANSACTION_READ_ONLY = 0;"); + + // 设为 1 年 365 * 86400 = 31536000,保证连接闲时等待不返回超时 + const uint32_t opt_timeout = 31536000; + (void)mysql_options(con, MYSQL_OPT_CONNECT_TIMEOUT, &opt_timeout); + (void)mysql_options(con, MYSQL_OPT_READ_TIMEOUT, &opt_timeout); + (void)mysql_options(con, MYSQL_OPT_WRITE_TIMEOUT, &opt_timeout); + + int retry_time = TSE_CONN_MAX_RETRY_TIMES; + int dec_conn_count = 0; + while (!mysql_real_connect(con, host, user, passwd, NULL, mysqld_port, mysqld_unix_port, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS | CLIENT_REMEMBER_OPTIONS | CLIENT_INTERACTIVE) && retry_time > 0) { + int err = mysql_errno(con); + if (err == ER_CON_COUNT_ERROR) { + tse_dec_conn_count(dec_conn_count); + } + // 3922 errcode, server has open compress conn, client need to open. + if (err == ER_WRONG_COMPRESSION_ALGORITHM_CLIENT) { + if ((con->server_capabilities & CLIENT_COMPRESS)) { // server open zlib conn + mysql_options(con, MYSQL_OPT_COMPRESSION_ALGORITHMS, COMPRESSION_ALGORITHM_ZLIB); + } else if((con->server_capabilities & CLIENT_ZSTD_COMPRESSION_ALGORITHM)) { // server open zstd conn + mysql_options(con, MYSQL_OPT_COMPRESSION_ALGORITHMS, COMPRESSION_ALGORITHM_ZSTD); + } + retry_time--; + continue; + } + tse_log_error("tse_mysql_conn create internal connection failed, retry_time=%d, user=%s, err_code=%d, err_msg=%s.", + retry_time, user, err, mysql_error(con)); + retry_time--; + } + + while (dec_conn_count != 0) { + tse_inc_conn_count(dec_conn_count); + } + my_thread_end(); + return con == nullptr; +} + +int tse_init_agent_client(MYSQL *&curr_conn) { + SENSI_INFO char agent_password[TSE_PASSWORD_BUFFER_SIZE] = {0}; + string agent_user = "root"; + if (!tse_get_agent_info(agent_password, TSE_PASSWORD_BUFFER_SIZE)) { + agent_user = "RDS_agent"; + } + const char *password = (agent_user == "root") ? NULL : agent_password; + int ret = tse_mysql_conn(curr_conn, my_localhost, agent_user.c_str(), password); + memset(agent_password, 0, TSE_PASSWORD_BUFFER_SIZE); + if (ret) { + tse_log_error("tse_init_agent_client tse_mysql_conn failed, err_code=%d, err_msg=%s.", + mysql_errno(curr_conn), mysql_error(curr_conn)); + tse_close_mysql_conn(&curr_conn); + return ret; + } + + return 0; +} + +int tse_mysql_query(MYSQL *mysql, const char *query) { + reset_mqh(nullptr, nullptr, 0); + + int ret = mysql_ping(mysql); + if (ret != 0) { + tse_log_error("tse_mysql_query: mysql server has gone. error_code:%d, reconnecting.", ret); + } + + /* + SUCCESS: 0 + CR_COMMANDS_OUT_OF_SYNC: 2014 + CR_SERVER_GONE_ERROR: 2006 + CR_SERVER_LOST: 2013 + CR_UNKNOWN_ERROR: 2000 + */ + ret = mysql_query(mysql, query); + if (ret != 0) { + tse_log_error("[TSE_MYSQL_QUERY]:ret:%d, err_code=%d, err_msg=%s.", ret, mysql_errno(mysql), mysql_error(mysql)); + } + + return ret; // success: 0, fail: other +} + +void tse_close_mysql_conn(MYSQL **curr_conn) { + mysql_close(*curr_conn); + *curr_conn = NULL; +} \ No newline at end of file diff --git a/storage/tianchi/tse_proxy_util.h b/storage/tianchi/tse_proxy_util.h new file mode 100644 index 0000000..e8a04d2 --- /dev/null +++ b/storage/tianchi/tse_proxy_util.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __TSE_PROXY_UTIL_H__ +#define __TSE_PROXY_UTIL_H__ + +#include + +#pragma GCC visibility push(default) + +using namespace std; + +#define AGENT_CONN_KEY_MASK (0x8000000000000000ULL) + +// this api can called by both CTC storage level(ha_ctc.so) and ctc_proxy.so, mysql_close C API used mysqlclient +void tse_close_mysql_conn(MYSQL **curr_conn); + +/* + conn_key format: + + |-----------------|---------------|-------------| + |16bits cantian_id|16bits mysql_id| | + |-----------------|---------------|32bits thd_id| + | 32bits mysql_inst_id | | + |---------------------------------|-------------| + | 64 bits conn_key (first bit is proxy mask) | + |-----------------------------------------------| + + because cantiand_id ranges from [0, 1] + use the first bit of conn_key to represent if this conn is proxy or agent (0: proxy, 1: agent) +*/ +inline uint64_t tse_get_conn_key(uint32_t inst_id, uint32_t thd_id, bool use_proxy) { + uint64_t conn_key = (((uint64_t)(inst_id)) << 32) + thd_id; + if (!use_proxy) { + conn_key |= AGENT_CONN_KEY_MASK; + } + return conn_key; +} + +inline uint32_t tse_get_inst_id_from_conn_key(uint64_t conn_key) { + return (conn_key & (AGENT_CONN_KEY_MASK - 1)) >> 32; +} + +inline uint16_t tse_get_cantian_id_from_conn_key(uint64_t conn_key) { + return (conn_key & (AGENT_CONN_KEY_MASK - 1)) >> 48; +} + +int tse_init_agent_client(MYSQL *&curr_conn); +int tse_mysql_conn(MYSQL *&con, const char *host, const char *user, const char *passwd); + +uint32_t get_g_name_locks(void); +uint32_t add_g_name_locks(uint32_t num); +uint32_t sub_g_name_locks(uint32_t num); +int tse_mysql_query(MYSQL *mysql, const char *query); + +#pragma GCC visibility pop + +#endif // __TSE_PROXY_UTIL_H__ diff --git a/storage/tianchi/tse_srv.h b/storage/tianchi/tse_srv.h new file mode 100644 index 0000000..6b7bd0a --- /dev/null +++ b/storage/tianchi/tse_srv.h @@ -0,0 +1,604 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __TSE_SRV_H__ +#define __TSE_SRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef EXTER_ATTACK +#define EXTER_ATTACK +#endif + +#ifndef SENSI_INFO +#define SENSI_INFO +#endif + +#define SMALL_RECORD_SIZE 128 // 表名、库名等长度不会特别大,取128 +#define ERROR_MESSAGE_LEN 512 +#define MAX_DDL_SQL_LEN_CONTEXT (129024) // 126kb, 预留2kb +#define MAX_DDL_SQL_LEN (MAX_DDL_SQL_LEN_CONTEXT + 30) // ddl sql语句的长度 不能超过128kb, 超过了会报错 +#define DD_BROADCAST_RECORD_LENGTH (3072) +#define LOCK_TABLE_SQL_FMT_LEN 20 +#define MAX_LOCK_TABLE_NAME (MAX_DDL_SQL_LEN - LOCK_TABLE_SQL_FMT_LEN) +#define MAX_KEY_COLUMNS (uint32_t)16 // cantian限制复合索引最大支持字段不超过16 +#define FUNC_TEXT_MAX_LEN 128 +#define TSE_IDENTIFIER_MAX_LEN 64 +#define CANTIAN_DOWN_MASK 0xFFFF // 参天节点故障 +#define MAX_DDL_ERROR_MSG_LEN 1024 +#define PART_CURSOR_NUM 8192 +#define MAX_SUBPART_NUM 4096 // 参天限制每个一级分区下子分区不超过4096 +#define TSE_BUF_LEN (64 * 1024) +#define BIG_RECORD_SIZE TSE_BUF_LEN // 采用最大长度 +#define MAX_RECORD_SIZE (3 * TSE_BUF_LEN) // 查询时按照3条数据合并返回预估最大长度, 取8字节对齐 +#define TSE_MAX_KEY_NAME_LENGTH 64 +#define TSE_SQL_START_INTERNAL_SAVEPOINT "TSE4CANTIAN_SYS_SV" +#define IS_TSE_PART(part_id) ((part_id) < (PART_CURSOR_NUM)) +#define MAX_BULK_INSERT_PART_ROWS 128 +#define SESSION_CURSOR_NUM (8192 * 2) + +// for broadcast_req.options +#define TSE_SET_VARIABLE_PERSIST (0x1 << 8) +#define TSE_SET_VARIABLE_PERSIST_ONLY (0x1 << 7) +#define TSE_OPEN_NO_CHECK_FK_FOR_CURRENT_SQL (0x1 << 6) +#define TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD (0x1 << 5) +#define TSE_NOT_NEED_CANTIAN_EXECUTE (0x1 << 4) +#define TSE_SET_VARIABLE_TO_DEFAULT (0x1 << 3) +#define TSE_SET_VARIABLE_TO_NULL (0x1 << 2) +#define TSE_SET_VARIABLE_WITH_SUBSELECT (0x1 << 0) + +#define CTC_AUTOINC_OLD_STYLE_LOCKING 0 +#define CTC_AUTOINC_NEW_STYLE_LOCKING 1 +#define CTC_AUTOINC_NO_LOCKING 2 + +typedef struct { + uint32_t inst_id; // instance id, thd_id alone is not sufficient to uniquely identify a tse session + uint32_t thd_id; + uint32_t part_id; + uint32_t subpart_id; + uint64_t sess_addr; + uint64_t ctx_addr; + uint64_t cursor_addr; + int32_t cursor_ref; + bool cursor_valid; + uint16_t bind_core; + uint8_t sql_command; + int64_t query_id; + uint8_t sql_stat_start; // TRUE when we start processing of an SQL statement + uint8_t change_data_capture; // TRUE when start logicrep in cantian + bool is_broadcast; + uint64_t pre_sess_addr; + void* msg_buf; +} tianchi_handler_t; + +typedef struct { + char db_name[SMALL_RECORD_SIZE]; + char table_name[SMALL_RECORD_SIZE]; + char user_name[SMALL_RECORD_SIZE]; + char user_ip[SMALL_RECORD_SIZE]; + int32_t sql_type; + int32_t mdl_namespace; +} tse_lock_table_info; + +#pragma pack(4) +typedef struct cache_st_variant { + union { + int v_int; + unsigned int v_uint32; + unsigned int v_bool; + long long v_bigint; + unsigned long long v_ubigint; + double v_real; + }; + + union { + struct { + short type; + unsigned char is_null; + unsigned char is_hex; + }; + + unsigned int ctrl; + }; +} cache_variant_t; + +/** + * cache info that can expand this struct + * if need more cbo stats cache + */ +typedef struct { + uint32_t max_col_id; + uint32_t *num_distincts; + cache_variant_t *low_values; + cache_variant_t *high_values; + uint32_t max_part_no; // the part no of max rows num part + uint32_t *part_table_num_distincts; + cache_variant_t *part_table_low_values; + cache_variant_t *part_table_high_values; +} tse_cbo_stats_table_t; + +typedef struct { + uint32_t rows_and_blocks_size; + uint32_t num_distinct_size; + uint32_t low_value_size; + uint32_t high_value_size; +} tianchi_part_table_cbo_info_t; + +/* + * statistics information that mysql optimizer need + * expand this struct if need more cbo stats + */ +typedef struct { + uint32_t estimate_rows; + uint32_t estimate_blocks; + bool is_updated; + tse_cbo_stats_table_t tse_cbo_stats_table; + tianchi_part_table_cbo_info_t part_table_info; + uint32_t estimate_part_rows_and_blocks[0]; +} tianchi_cbo_stats_t; +#pragma pack() + +typedef struct { + char error_msg[MAX_DDL_ERROR_MSG_LEN]; + char user_name[SMALL_RECORD_SIZE]; + char user_ip[SMALL_RECORD_SIZE]; + int32_t error_code; + uint32_t msg_len; + tianchi_handler_t tch; + uint32_t mysql_inst_id; + bool is_alter_copy; + uint32_t table_flags; +} ddl_ctrl_t; + +typedef struct { + int isolation_level; + uint32_t autocommit; + uint32_t lock_wait_timeout; + bool use_exclusive_lock; +} tianchi_trx_context_t; + +typedef struct { + char db_name[SMALL_RECORD_SIZE]; + char sql_str[MAX_DDL_SQL_LEN]; + char user_name[SMALL_RECORD_SIZE]; + char user_ip[SMALL_RECORD_SIZE]; + uint32_t mysql_inst_id; + int err_code; + uint8_t sql_command; + uint32_t options; + char err_msg[ERROR_MESSAGE_LEN]; +} tse_ddl_broadcast_request; + +typedef struct { + uint8_t type; + char first[SMALL_RECORD_SIZE]; + char second[SMALL_RECORD_SIZE]; +} invalidate_obj_entry_t; + +typedef struct { + char buff[DD_BROADCAST_RECORD_LENGTH]; + uint32_t buff_len; + uint32_t mysql_inst_id; + bool is_dcl; + int err_code; +} tse_invalidate_broadcast_request; + +typedef struct { + bool is_key_null; // 该列数据是否为null + uint8_t *left_key; // 指向索引查询条件的左值 + uint8_t *right_key; // 指向索引查询条件的右值 + uint32_t left_key_len; // 左值的数据长度 + uint32_t right_key_len; // 右值的数据长度 +} key_info_t; + +typedef struct { + uint8_t *record; + uint16_t record_len; +} record_info_t; + +typedef union { + struct { + uint32_t nullable : 1; // 是否允许为空(1允许为空 0不允许) + uint32_t primary : 1; // if it is a primary key (主键) + uint32_t unique : 1; // 是否唯一 + uint32_t is_serial : 1; // 自增 + uint32_t is_check : 1; // 检查列(取值范围)约束 http://c.biancheng.net/view/2446.html + uint32_t is_ref : 1; // 指定外键 参考sql_parse_column_ref + uint32_t is_default : 1; // 是否有默认值 通过is_default_null default_text来设置默认值 + uint32_t is_update_default : 1; // sql_parse_column_default + uint32_t is_comment : 1; // 是否有注释 sql_parse_column_comment 通过 column->comment 存储注释 + uint32_t is_collate : 1; // sql_parse_collate 字符串排序用的 跟字符集有关系 https://www.cnblogs.com/jpfss/p/11548826.html + uint32_t has_null : 1; // not null sql_parse_column_not_null + uint32_t has_quote : 1; // if column name wrapped with double quotation 如果列名用双引号括起来 + uint32_t is_dummy : 1; // if it is a dummy column for index 目前在daac代码中暂未使用 + uint32_t is_default_null : 1; // empty string treat as null or '' + uint32_t isKey : 1; // key关键字 + uint32_t is_default_func : 1; // if default value is generated by mysql functions + uint32_t is_curr_timestamp : 1; // if default value is current_timestamp + uint32_t unused_ops : 15; + }; + uint32_t is_option_set; +} tse_column_option_set_bit; + +typedef enum { + EXP_CURSOR_ACTION_SELECT = 0, + EXP_CURSOR_ACTION_UPDATE = 1, + EXP_CURSOR_ACTION_DELETE = 2, + EXP_CURSOR_ACTION_INDEX_ONLY = 3, // covering index scan +} expected_cursor_action_t; + +typedef struct { + bool sorted; + bool need_init; + expected_cursor_action_t action; + uint16_t find_flag; + uint16_t active_index; + char index_name[TSE_MAX_KEY_NAME_LENGTH + 1]; // 索引名 + uint16_t key_num; // 查询条件覆盖多少列 + key_info_t key_info[MAX_KEY_COLUMNS]; // 索引查询条件数组 +} index_key_info_t; + +enum TSE_FUNC_TYPE { + TSE_FUNC_TYPE_OPEN_TABLE = 0, + TSE_FUNC_TYPE_CLOSE_TABLE, + TSE_FUNC_TYPE_CLOSE_SESSION, + TSE_FUNC_TYPE_WRITE_ROW, + TSE_FUNC_TYPE_WRITE_THROUGH_ROW, + TSE_FUNC_TYPE_UPDATE_ROW, + TSE_FUNC_TYPE_DELETE_ROW, + TSE_FUNC_TYPE_RND_INIT, + TSE_FUNC_TYPE_RND_END, + TSE_FUNC_TYPE_RND_NEXT, + TSE_FUNC_TYPE_RND_PREFETCH, + TSE_FUNC_TYPE_SCAN_RECORDS, + TSE_FUNC_TYPE_TRX_COMMIT, + TSE_FUNC_TYPE_TRX_ROLLBACK, + TSE_FUNC_TYPE_TRX_BEGIN, + TSE_FUNC_TYPE_LOCK_TABLE, + TSE_FUNC_TYPE_UNLOCK_TABLE, + TSE_FUNC_TYPE_INDEX_END, + TSE_FUNC_TYPE_SRV_SET_SAVEPOINT, + TSE_FUNC_TYPE_SRV_ROLLBACK_SAVEPOINT, + TSE_FUNC_TYPE_SRV_RELEASE_SAVEPOINT, + TSE_FUNC_TYPE_GENERAL_FETCH, + TSE_FUNC_TYPE_GENERAL_PREFETCH, + TSE_FUNC_TYPE_FREE_CURSORS, + TSE_FUNC_TYPE_GET_INDEX_NAME, + TSE_FUNC_TYPE_INDEX_READ, + TSE_FUNC_TYPE_RND_POS, + TSE_FUNC_TYPE_POSITION, + TSE_FUNC_TYPE_DELETE_ALL_ROWS, + TSE_FUNC_TYPE_GET_CBO_STATS, + TSE_FUNC_TYPE_GET_HUGE_PART_TABLE_CBO_STATS, + TSE_FUNC_TYPE_WRITE_LOB, + TSE_FUNC_TYPE_READ_LOB, + TSE_FUNC_TYPE_CREATE_TABLE, + TSE_FUNC_TYPE_TRUNCATE_TABLE, + TSE_FUNC_TYPE_TRUNCATE_PARTITION, + TSE_FUNC_TYPE_RENAME_TABLE, + TSE_FUNC_TYPE_ALTER_TABLE, + TSE_FUNC_TYPE_GET_SERIAL_VALUE, + TSE_FUNC_TYPE_DROP_TABLE, + TSE_FUNC_TYPE_EXCUTE_MYSQL_DDL_SQL, + TSE_FUNC_TYPE_BROADCAST_REWRITE_SQL, + TSE_FUNC_TYPE_CREATE_TABLESPACE, + TSE_FUNC_TYPE_ALTER_TABLESPACE, + TSE_FUNC_TYPE_DROP_TABLESPACE, + TSE_FUNC_TYPE_BULK_INSERT, + TSE_FUNC_TYPE_ANALYZE, + TSE_FUNC_TYPE_GET_MAX_SESSIONS, + TSE_FUNC_LOCK_INSTANCE, + TSE_FUNC_UNLOCK_INSTANCE, + TSE_FUNC_CHECK_TABLE_EXIST, + TSE_FUNC_SEARCH_METADATA_SWITCH, + TSE_FUNC_PRE_CREATE_DB, + TSE_FUNC_TYPE_DROP_TABLESPACE_AND_USER, + TSE_FUNC_DROP_DB_PRE_CHECK, + TSE_FUNC_KILL_CONNECTION, + TSE_FUNC_TYPE_INVALIDATE_OBJECT, + TSE_FUNC_TYPE_RECORD_SQL, + /* for instance registration, should be the last but before duplex */ + TSE_FUNC_TYPE_REGISTER_INSTANCE, + TSE_FUNC_TYPE_WAIT_CONNETOR_STARTUPED, + /* for duplex channel */ + TSE_FUNC_TYPE_MYSQL_EXECUTE_UPDATE, + TSE_FUNC_TYPE_CLOSE_MYSQL_CONNECTION, + TSE_FUNC_TYPE_LOCK_TABLES, + TSE_FUNC_TYPE_UNLOCK_TABLES, + TSE_FUNC_TYPE_EXECUTE_REWRITE_OPEN_CONN, + TSE_FUNC_TYPE_INVALIDATE_OBJECTS, + TSE_FUNC_TYPE_NUMBER, +}; + +typedef enum en_select_mode { + SELECT_ORDINARY, /* default behaviour */ + SELECT_SKIP_LOCKED, /* skip the row if row is locked */ + SELECT_NOWAIT /* return immediately if row is locked */ +} tse_select_mode_t; + +typedef enum { + TSE_DDL_TYPE_UNKNOW = -1, + TSE_DDL_TYPE_DECIMAL, + TSE_DDL_TYPE_TINY, + TSE_DDL_TYPE_SHORT, + TSE_DDL_TYPE_LONG, + TSE_DDL_TYPE_FLOAT, + TSE_DDL_TYPE_DOUBLE, + TSE_DDL_TYPE_NULL, + TSE_DDL_TYPE_TIMESTAMP, + TSE_DDL_TYPE_LONGLONG, + TSE_DDL_TYPE_INT24, + TSE_DDL_TYPE_DATE, + TSE_DDL_TYPE_TIME, + TSE_DDL_TYPE_DATETIME, + TSE_DDL_TYPE_YEAR, + TSE_DDL_TYPE_NEWDATE, /**< Internal to TSE_DDL. Not used in protocol */ + TSE_DDL_TYPE_VARCHAR, + TSE_DDL_TYPE_BIT, + TSE_DDL_TYPE_TIMESTAMP2, + TSE_DDL_TYPE_DATETIME2, /**< Internal to TSE_DDL. Not used in protocol */ + TSE_DDL_TYPE_TIME2, /**< Internal to TSE_DDL. Not used in protocol */ + TSE_DDL_TYPE_TYPED_ARRAY, /**< Used for replication only */ + TSE_DDL_TYPE_JSON = 245, + TSE_DDL_TYPE_NEWDECIMAL = 246, + TSE_DDL_TYPE_CLOB = 247, + TSE_DDL_TYPE_TINY_BLOB = 249, + TSE_DDL_TYPE_MEDIUM_BLOB = 250, + TSE_DDL_TYPE_LONG_BLOB = 251, + TSE_DDL_TYPE_BLOB = 252, + TSE_DDL_TYPE_VAR_STRING = 253, + TSE_DDL_TYPE_STRING = 254, +} enum_tse_ddl_field_types; + +typedef enum { + TSE_ALTER_TABLE_DROP_UNKNOW = -1, + TSE_ALTER_TABLE_DROP_KEY, + TSE_ALTER_TABLE_DROP_COLUMN, + TSE_ALTER_TABLE_DROP_FOREIGN_KEY, + TSE_ALTER_TABLE_DROP_CHECK_CONSTRAINT, + TSE_ALTER_TABLE_DROP_ANY_CONSTRAINT +} tse_alter_table_drop_type; + +typedef enum { + TSE_ALTER_COLUMN_UNKNOW = -1, + TSE_ALTER_COLUMN_SET_DEFAULT, + TSE_ALTER_COLUMN_DROP_DEFAULT, + TSE_ALTER_COLUMN_RENAME_COLUMN, + TSE_ALTER_COLUMN_SET_COLUMN_VISIBLE, + TSE_ALTER_COLUMN_SET_COLUMN_INVISIBLE +} tse_alter_column_type; + +typedef enum { + TSE_ALTER_COLUMN_ALTER_MODE_NONE = -1, + TSE_ALTER_COLUMN_ALTER_ADD_COLUMN = 1, // 添加列 + TSE_ALTER_COLUMN_ALTER_MODIFY_COLUMN = 2, // 修改列 +} tse_alter_column_alter_mode; + +typedef enum { + TSE_KEYTYPE_UNKNOW = -1, + TSE_KEYTYPE_PRIMARY, + TSE_KEYTYPE_UNIQUE, + TSE_KEYTYPE_MULTIPLE, + TSE_KEYTYPE_FULLTEXT, + TSE_KEYTYPE_SPATIAL, + TSE_KEYTYPE_FOREIGN +} tse_key_type; + +typedef enum { + TSE_PART_TYPE_INVALID = 0, + TSE_PART_TYPE_RANGE = 1, + TSE_PART_TYPE_LIST = 2, + TSE_PART_TYPE_HASH = 3, +} tse_part_type; + +typedef enum en_tse_lock_table_mode { + TSE_LOCK_MODE_SHARE = 0, /* SHARE */ + TSE_LOCK_MODE_EXCLUSIVE /* EXCLUSIVE */ +} tse_lock_table_mode_t; + +typedef struct tse_db_infos { + char *name; + uint32_t datafile_size; + bool datafile_autoextend; + uint32_t datafile_extend_size; +} tse_db_infos_t; + +typedef enum en_tse_func_type_t { + TSE_UNKNOWN_FUNC, + TSE_EQ_FUNC, + TSE_EQUAL_FUNC, + TSE_NE_FUNC, + TSE_LT_FUNC, + TSE_LE_FUNC, + TSE_GE_FUNC, + TSE_GT_FUNC, + TSE_LIKE_FUNC, + TSE_ISNULL_FUNC, + TSE_ISNOTNULL_FUNC, + TSE_NOT_FUNC, + TSE_COND_AND_FUNC, + TSE_COND_OR_FUNC, + TSE_XOR_FUNC +} tse_func_type_t; + +typedef struct en_tse_cond_field_t { + uint16_t field_no; + enum_tse_ddl_field_types field_type; + uint16_t field_size; + void *field_value; + bool null_value; + uint32_t collate_id; + bool col_updated; + bool no_backslash; +} tse_cond_field; + +struct en_tse_cond_list_t; +typedef struct en_tse_cond_t { + tse_func_type_t func_type; + tse_cond_field field_info; + struct en_tse_cond_list_t *cond_list; + struct en_tse_cond_t *next; +} tse_conds; + +typedef struct en_tse_cond_list_t { + tse_conds *first; + tse_conds *last; + uint16_t elements; +} tse_cond_list; + +typedef struct { + uint64_t ignore : 1; + uint64_t no_foreign_key_check : 1; + uint64_t no_cascade_check : 1; + uint64_t dd_update : 1; + uint64_t is_replace : 1; + uint64_t dup_update : 1; + uint64_t no_logging : 1; + uint64_t auto_inc_used : 1; + uint64_t has_explicit_autoinc : 1; + uint64_t auto_increase : 1; + uint64_t autoinc_lock_mode : 2; + uint64_t auto_inc_step : 16; + uint64_t auto_inc_offset : 16; + uint64_t write_through : 1; + uint64_t is_create_select : 1; + uint64_t unused_ops : 18; +} dml_flag_t; + +typedef struct { + uint32_t part_id; + uint32_t subpart_id; +} ctc_part_t; + +/* General Control Interface */ +int srv_wait_instance_startuped(void); +int tse_alloc_inst_id(uint32_t *inst_id); +int tse_release_inst_id(uint32_t inst_id); + +int tse_open_table(tianchi_handler_t *tch, const char *table_name, const char *user_name); +int tse_close_table(tianchi_handler_t *tch); + +int tse_close_session(tianchi_handler_t *tch); +void tse_kill_session(tianchi_handler_t *tch); + +uint8_t *tse_alloc_buf(tianchi_handler_t *tch, uint32_t buf_size); +void tse_free_buf(tianchi_handler_t *tch, uint8_t *buf); + +/* Data Manipulation Language(DML) Related Interface */ +int tse_write_row(tianchi_handler_t *tch, const record_info_t *record_info, + uint16_t serial_column_offset, uint64_t *last_insert_id, dml_flag_t flag); +/* corresponds to cantian. */ +int tse_write_through_row(tianchi_handler_t *tch, const record_info_t *record_info, + uint16_t serial_column_offset, uint64_t *last_insert_id, dml_flag_t flag); +int tse_bulk_write(tianchi_handler_t *tch, const record_info_t *record_info, uint64_t rec_num, + uint32_t *err_pos, dml_flag_t flag, ctc_part_t *part_ids); +int tse_update_row(tianchi_handler_t *tch, uint16_t new_record_len, const uint8_t *new_record, + const uint16_t *upd_cols, uint16_t col_num, dml_flag_t flag); +int tse_delete_row(tianchi_handler_t *tch, uint16_t record_len, dml_flag_t flag); +int tse_rnd_init(tianchi_handler_t *tch, expected_cursor_action_t action, + tse_select_mode_t mode, tse_conds *cond); +int tse_rnd_end(tianchi_handler_t *tch); +int tse_rnd_next(tianchi_handler_t *tch, record_info_t *record_info); +int tse_rnd_prefetch(tianchi_handler_t *tch, uint8_t *records, uint16_t *record_lens, + uint32_t *recNum, uint64_t *rowids, int32_t max_row_size); +int tse_position(tianchi_handler_t *tch, uint8_t *position, uint16_t pos_length); +int tse_rnd_pos(tianchi_handler_t *tch, uint16_t pos_length, uint8_t *position, record_info_t *record_info); +int tse_delete_all_rows(tianchi_handler_t *tch, dml_flag_t flag); +int tse_scan_records(tianchi_handler_t *tch, uint64_t *num_rows, char *index_name); +/* Index Related Interface */ +int tse_index_end(tianchi_handler_t *tch); +int tse_index_read(tianchi_handler_t *tch, record_info_t *record_info, index_key_info_t *index_info, + tse_select_mode_t mode, tse_conds *cond, const bool is_replace); +int tse_general_fetch(tianchi_handler_t *tch, record_info_t *record_info); +int tse_general_prefetch(tianchi_handler_t *tch, uint8_t *records, uint16_t *record_lens, + uint32_t *recNum, uint64_t *rowids, int32_t max_row_size); +int tse_free_session_cursors(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize); + +/* Transaction Related Interface */ +int tse_trx_begin(tianchi_handler_t *tch, tianchi_trx_context_t trx_context, bool is_mysql_local); +int tse_trx_commit(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit); +int tse_trx_rollback(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize); + +int tse_srv_set_savepoint(tianchi_handler_t *tch, const char *name); +int tse_srv_rollback_savepoint(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize, const char *name); +int tse_srv_release_savepoint(tianchi_handler_t *tch, const char *name); + +/* Optimizer Related Interface */ +int tse_analyze_table(tianchi_handler_t *tch, const char *db_name, const char *table_name, double sampling_ratio); +int tse_get_cbo_stats(tianchi_handler_t *tch, tianchi_cbo_stats_t *stats); +int tse_get_index_name(tianchi_handler_t *tch, char *index_name); + +/* Datatype Related Interface */ +int tse_knl_write_lob(tianchi_handler_t *tch, char *locator, uint32_t locator_size, + int column_id, void *data, uint32_t data_len, bool force_outline); +int tse_knl_read_lob(tianchi_handler_t *tch, char* loc, uint32_t offset, + void *buf, uint32_t size, uint32_t *read_size); + +/* Data Definition Language(DDL) Related Interface */ +int tse_lock_table(tianchi_handler_t *tch, const char *db_name, tse_lock_table_info *lock_info, int *error_code); +int tse_unlock_table(tianchi_handler_t *tch, uint32_t mysql_inst_id, tse_lock_table_info *lock_info); + +int tse_lock_instance(bool *is_mysqld_starting, tse_lock_table_mode_t lock_type, tianchi_handler_t *tch); +int tse_unlock_instance(bool *is_mysqld_starting, tianchi_handler_t *tch); + +int tse_drop_tablespace_and_user(tianchi_handler_t *tch, const char *db_name, + const char *sql_str, const char *user_name, const char *user_ip, + int *error_code, char *error_message); +int tse_drop_db_pre_check(tianchi_handler_t *tch, const char *db_name, int *error_code, char *error_message); +int tse_pre_create_db(tianchi_handler_t *tch, const char *sql_str, tse_db_infos_t *db_infos, + int *error_code, char *error_message); + +int tse_create_tablespace(void *space_def, ddl_ctrl_t *ddl_ctrl); +int tse_alter_tablespace(void *space_alter_def, ddl_ctrl_t *ddl_ctrl); +int tse_drop_tablespace(void *space_drop_def, ddl_ctrl_t *ddl_ctrl); + +int tse_create_table(void *table_def, ddl_ctrl_t *ddl_ctrl); +int tse_alter_table(void *alter_def, ddl_ctrl_t *ddl_ctrl); +int tse_truncate_table(void *table_def, ddl_ctrl_t *ddl_ctrl); +int tse_truncate_partition(void *table_def, ddl_ctrl_t *ddl_ctrl); +int tse_rename_table(void *alter_def, ddl_ctrl_t *ddl_ctrl); +int tse_drop_table(void *drop_def, ddl_ctrl_t *ddl_ctrl); + +int tse_get_max_sessions_per_node(uint32_t *max_sessions); +int tse_get_serial_value(tianchi_handler_t *tch, uint64_t *value, dml_flag_t flag); + +int close_mysql_connection(uint32_t thd_id, uint32_t mysql_inst_id); +int tse_ddl_execute_lock_tables(tianchi_handler_t *tch, char *db_name, tse_lock_table_info *lock_info, int *err_code); +int tse_ddl_execute_unlock_tables(tianchi_handler_t *tch, uint32_t mysql_inst_id, tse_lock_table_info *lock_info); +EXTER_ATTACK int tse_ddl_execute_update(uint32_t thd_id, tse_ddl_broadcast_request *broadcast_req, bool *allow_fail); +EXTER_ATTACK int tse_execute_mysql_ddl_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail); +int tse_execute_rewrite_open_conn(uint32_t thd_id, tse_ddl_broadcast_request *broadcast_req); +int tse_broadcast_rewrite_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail); + +/* Metadata Related Interface */ +int tse_check_db_table_exists(const char *db, const char *name, bool *is_exists); +int tse_search_metadata_status(bool *cantian_metadata_switch, bool *cantian_cluster_ready); + +int tse_invalidate_mysql_dd_cache(tianchi_handler_t *tch, tse_invalidate_broadcast_request *broadcast_req, int *err_code); +int tse_broadcast_mysql_dd_invalidate(tianchi_handler_t *tch, tse_invalidate_broadcast_request *broadcast_req); + +int ctc_record_sql_for_cantian(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/storage/tianchi/tse_srv_mq_module.cc b/storage/tianchi/tse_srv_mq_module.cc new file mode 100644 index 0000000..c66299a --- /dev/null +++ b/storage/tianchi/tse_srv_mq_module.cc @@ -0,0 +1,548 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "srv_mq_msg.h" +#include "tse_srv_mq_module.h" +#include +#include +#include +#include +#include "assert.h" +#include "tse_error.h" +#include "tse_log.h" +#include "message_queue/dsw_shm.h" +#include "tse_stats.h" +#include "ha_tse.h" + +#define MQ_THD_NUM 1 +#define SHM_SEG_NUM 8 +#define MAX_DDL_THD_NUM 1024 + +using namespace std; +#define CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, tag) \ + do { \ + if ((req)->result != 0 && get_server_state() == SERVER_SHUTTING_DOWN) { \ + tse_log_error("%s failed,server will shutdown:result:%d", (tag), \ + (req)->result); \ + (req)->result = 0; \ + } \ + } while (0) + +#define CTC_GET_CLIENT_ID(inst_id) ((int) ((inst_id) & 0xFFFF)) + +// the last shm seg g_shm_segs[SHM_SEG_NUM] is for upstream, served by mysqld +shm_seg_s *g_shm_segs[SHM_SEG_NUM + 1] = {nullptr}; +shm_seg_s *g_upstream_shm_seg = nullptr; +atomic_int g_ddl_thd_num(0); +int g_shm_client_id(-1); + +static void* mq_msg_handler(void *arg) { + pthread_detach(pthread_self()); + dsw_message_block_t *message_block = (dsw_message_block_t *)arg; + tse_log_note("recv msg ! cmd:%d", message_block->head.cmd_type); + switch (message_block->head.cmd_type) { + case TSE_FUNC_TYPE_EXECUTE_REWRITE_OPEN_CONN: { + execute_ddl_mysql_sql_request *req = (execute_ddl_mysql_sql_request *)message_block->seg_buf[0]; + req->result = tse_execute_rewrite_open_conn(req->thd_id, &req->broadcast_req); + tse_log_note("execute_rewrite_open_conn : sql_txt:%s,result:%d", req->broadcast_req.sql_str, req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "tse_ddl_execute_update"); + break; + } + case TSE_FUNC_TYPE_MYSQL_EXECUTE_UPDATE: { + execute_ddl_mysql_sql_request *req = + (execute_ddl_mysql_sql_request *)message_block->seg_buf[0]; + req->result = tse_ddl_execute_update(req->thd_id, &req->broadcast_req, &req->allow_fail); + tse_log_note("execute_ddl_mysql_sql : db:%s, sql_txt:%s,result:%d", req->broadcast_req.db_name, + req->broadcast_req.sql_str, req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "tse_ddl_execute_update"); + break; + } + case TSE_FUNC_TYPE_CLOSE_MYSQL_CONNECTION: { + struct close_mysql_connection_request *req = (struct close_mysql_connection_request *)message_block->seg_buf[0]; + req->result = close_mysql_connection(req->thd_id, req->inst_id); + tse_log_note("close_connection : thd_id : %d, inst_id : %d, ret : %d.", req->thd_id, req->inst_id, req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "close_mysql_connection"); + break; + } + case TSE_FUNC_TYPE_LOCK_TABLES: { + struct tse_lock_tables_request *req = (struct tse_lock_tables_request *)message_block->seg_buf[0]; + req->result = tse_ddl_execute_lock_tables(&(req->tch), req->db_name, &(req->lock_info), &(req->err_code)); + tse_log_note("lock tables : thd_id : %d, inst_id : %d, ret : %d.", req->tch.thd_id, req->tch.inst_id, + req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "tse_ddl_execute_lock_tables"); + break; + } + case TSE_FUNC_TYPE_UNLOCK_TABLES: { + struct tse_unlock_tables_request *req = (struct tse_unlock_tables_request *)message_block->seg_buf[0]; + req->result = tse_ddl_execute_unlock_tables(&(req->tch), req->mysql_inst_id, &(req->lock_info)); + tse_log_note("unlock tables : thd_id : %d, inst_id : %d, ret : %d.", req->tch.thd_id, req->tch.inst_id, + req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "tse_ddl_execute_unlock_tables"); + break; + } + case TSE_FUNC_TYPE_INVALIDATE_OBJECTS: { + struct invalidate_mysql_dd_request *req = (struct invalidate_mysql_dd_request *)message_block->seg_buf[0]; + req->result = tse_invalidate_mysql_dd_cache(&(req->tch), &req->broadcast_req, &(req->err_code)); + tse_log_note("invalidate dd cache: thd_id : %d, inst_id : %d, ret : %d.", req->tch.thd_id, req->tch.inst_id, + req->result); + CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, "tse_invalidate_mysql_dd_cache"); + break; + } + default: { + tse_log_error("cmd type invalid, cmd_type:%d.", message_block->head.cmd_type); + break; + } + } + + int result = sem_post(&message_block->head.sem); + if (result != CT_SUCCESS) { + tse_log_error("sem post failed, result:%d.", result); + } + g_ddl_thd_num--; + pthread_exit(0); + return NULL; +} + +int mq_recv_msg(struct shm_seg_s *shm_seg, dsw_message_block_t *message_block) +{ + (void)shm_seg; + int result; + pthread_t thd; + if (g_ddl_thd_num > MAX_DDL_THD_NUM) { + tse_log_error("ddl thd has reach max limit: %d", MAX_DDL_THD_NUM); + assert(0); + } + result = pthread_create(&thd, NULL, mq_msg_handler, (void*)message_block); + if (result != 0) { + tse_log_error("pthread_create failed, result:%d.", result); + } + g_ddl_thd_num++; + return result; +} + +void shm_log_err(char *log_text, int length) +{ + UNUSED_PARAM(length); + tse_log_error("%s", log_text); +} + +void shm_log_info(char *log_text, int length) +{ + UNUSED_PARAM(length); + tse_log_system("%s", log_text); +} + +int mq_srv_start(int proc_id) +{ + g_upstream_shm_seg = g_shm_segs[SHM_SEG_NUM]; + shm_set_thread_cool_time(0); + return shm_proc_start(g_upstream_shm_seg, proc_id, MQ_THD_NUM, NULL, 0, mq_recv_msg); +} + +int init_tse_mq_moudle() +{ + shm_set_info_log_writer(shm_log_info); + shm_set_error_log_writer(shm_log_err); + + if (shm_tpool_init(MQ_THD_NUM) != 0) { + tse_log_error("shm tpool init failed"); + return -1; + } + + int inst_id = -1; + for (int i = 0; i < SHM_SEG_NUM + 1; ++i) { + if (g_shm_segs[i] != nullptr) { + continue; + } + + shm_key_t shm_key; + shm_key.type = SHM_KEY_MMAP; + std::string shm_name = MQ_SHM_MMAP_NAME_PREFIX; + std::string map_name = MQ_SHM_MMAP_NAME_PREFIX + std::string(".") + std::to_string(i); + strcpy(shm_key.mmap_name, map_name.c_str()); + strcpy(shm_key.shm_name, shm_name.c_str()); + shm_key.seg_id = i; + + if (i == 0) { + if (shm_client_connect(&shm_key, &inst_id) < 0) { + tse_log_error("shm client connect failed, shm_name(%s)", shm_key.shm_name); + return -1; + } + ha_tse_set_inst_id((uint32_t) inst_id); + g_shm_client_id = CTC_GET_CLIENT_ID(inst_id); + } + + g_shm_segs[i] = shm_init(&shm_key, false); + if (g_shm_segs[i] == nullptr) { + tse_log_error("shm init failed, shm_seg is null i:%d.", i); + return -1; + } + + shm_assign_proc_id(g_shm_segs[i], g_shm_client_id); + } + + return 0; +} + +int deinit_tse_mq_moudle() +{ + for (int i = 0; i < SHM_SEG_NUM + 1; ++i) { + if (g_shm_segs[i] == nullptr) { + continue; + } + shm_seg_stop(g_shm_segs[i]); + } + shm_tpool_destroy(); + for (int i = 0; i < SHM_SEG_NUM + 1; ++i) { + if (g_shm_segs[i] == nullptr) { + continue; + } + shm_seg_exit(g_shm_segs[i]); + } + shm_client_disconnect(); + return 0; +} + +int (*tse_init)() = init_tse_mq_moudle; +int (*tse_deinit)() = deinit_tse_mq_moudle; + +static int g_group_num = 0; +cpu_set_t g_masks[SHM_SEG_NUM]; +static int g_cpu_info[SHM_SEG_MAX_NUM][SMALL_RECORD_SIZE]; +void *get_one_shm_inst(tianchi_handler_t *tch) +{ + uint32_t hashSeed = tch == nullptr ? 0 : tch->thd_id; + if (g_group_num != 0 && tch != nullptr && tch->bind_core != 1) { + cpu_set_t mask = g_masks[(hashSeed % SHM_SEG_NUM) % g_group_num]; + pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask); + tch->bind_core = 1; + } + return (void *)g_shm_segs[hashSeed % SHM_SEG_NUM]; +} + +void *alloc_share_mem(void *seg, uint32_t mem_size) +{ + return shm_alloc((shm_seg_s *)seg, mem_size); +} + +void free_share_mem(void *seg, void *shm_mem) +{ + UNUSED_PARAM(seg); + shm_free(nullptr, shm_mem); +} + +void batch_free_shm_buf(void *seg, dsw_message_block_t* msg) +{ + UNUSED_PARAM(seg); + for (uint16_t i = 0; i < msg->head.seg_num; ++i) { + if (msg->seg_buf[i]) { + shm_free(nullptr, msg->seg_buf[i]); + } else { + tse_log_error("seg buf is null, i:%u, seg_num:%u.", i, msg->head.seg_num); + } + } +} + +static void set_cpu_info(register_instance_request *req) +{ + g_group_num = req->group_num; + for (int i = 0; i < g_group_num; i++) { + for (int j = 0; j < SMALL_RECORD_SIZE; j++) { + g_cpu_info[i][j] = req->cpu_info[i][j]; + if (g_cpu_info[i][j] < 0) { + break; + } + } + } +} + +static void set_cpu_mask() +{ + for (int i = 0; i < g_group_num; i++) { + cpu_set_t mask; + CPU_ZERO(&mask); + for (int j = 0; j < SHM_SEG_MAX_NUM; j++) { + if (g_cpu_info[i][j] < 0) { + break; + } + CPU_SET(g_cpu_info[i][j], &mask); + } + g_masks[i] = mask; + } +} + +static void tse_log_reg_error_by_code(int error_code) +{ + switch(error_code) { + case ERR_CONNECTION_FAILED: + tse_log_error("shm connection failed"); + break; + case REG_MISMATCH_CTC_VERSION: + tse_log_error("CTC client version mismatch server!"); + break; + default: + tse_log_error("recv unknown register instance error code %d", error_code); + break; + } +} + +EXTER_ATTACK int tse_mq_deal_func(void *shm_inst, TSE_FUNC_TYPE func_type, + void *request, void* msg_buf, uint32_t server_id, uint32_t wait_sec) +{ + uint64_t start_time = 0; + if (ctc_stats::get_instance().get_stats_enabled()) { + start_time = my_getsystime() / 10; + } + + shm_seg_s *seg = (shm_seg_s *)shm_inst; + dsw_message_block_t *msg; + bool is_alloc = false; + if (msg_buf != nullptr) { + msg = (dsw_message_block_t *)msg_buf; + } else { + msg = (dsw_message_block_t *)shm_alloc(seg, sizeof(dsw_message_block_t)); + is_alloc = true; + } + + if (msg == nullptr) { + tse_log_error("alloc shm failed, len:%lu.", sizeof(dsw_message_block_t)); + return ERR_ALLOC_MEMORY; + } + int ret = CT_SUCCESS; + if (is_alloc) { + ret = sem_init(&msg->head.sem, 1, 0); + } + + if (ret != CT_SUCCESS) { + if (is_alloc) { + shm_free(nullptr, msg); + } + tse_log_error("sem init failed, ret:%d, func_type:%d.", ret, func_type); + return ERR_SEM_FAULT; + } + + msg->head.src_nid = g_shm_client_id; + msg->head.dst_nid = server_id; + msg->head.seg_num = 1; + msg->head.seg_desc[0].type = 0; + msg->head.seg_desc[0].length = REQUEST_SIZE; + msg->head.cmd_type = (uint32_t)func_type; + msg->seg_buf[0] = request; + + ct_errno_t result = CT_SUCCESS; + do { + ret = shm_send_msg(seg, server_id, msg); + if (ret != CT_SUCCESS) { + result = ERR_SHM_SEND_MSG_FAILED; + tse_log_error("send msg failed, ret:%d, func_type:%d.", ret, func_type); + break; + } + + // register funcs won't relinquish the processor + if (func_type < TSE_FUNC_TYPE_REGISTER_INSTANCE) { + sched_yield(); + } + + if (wait_sec > 0) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += wait_sec; + ret = sem_timedwait(&msg->head.sem, &ts); + } else { + ret = sem_wait(&msg->head.sem); + } + + if (ret != CT_SUCCESS) { + result = ERR_SEM_FAULT; + tse_log_error("send msg sem wait failed, ret:%d, func_type:%d.", ret, func_type); + break; + } + } while (0); + + if (is_alloc) { + ret = sem_destroy(&msg->head.sem); + if (ret != CT_SUCCESS) { + tse_log_error("sem destory failed, ret:%d, func_type:%d.", ret, func_type); + } + shm_free(nullptr, msg); + } + + + if (ctc_stats::get_instance().get_stats_enabled()) { + ctc_stats::get_instance().gather_stats(func_type, my_getsystime() / 10 - start_time); + } + + return result; +} + +int tse_mq_register_func(void) +{ + mq_srv_start(g_shm_client_id); + + shm_seg_s *shm_inst = (shm_seg_s *)get_one_shm_inst(nullptr); + register_instance_request *req = (register_instance_request *)alloc_share_mem(shm_inst, sizeof(register_instance_request)); + if (req == NULL) { + tse_log_error("[TSE_INIT]: alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(register_instance_request)); + return ERR_ALLOC_MEMORY; + } + req->ctc_version = (uint32_t)CTC_CLIENT_VERSION_NUMBER; + + int result = ERR_CONNECTION_FAILED; + if (tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_REGISTER_INSTANCE, req, nullptr, SERVER_REGISTER_PROC_ID) == CT_SUCCESS) { + result = req->result; + } + + if (result == CT_SUCCESS) { + set_cpu_info(req); + set_cpu_mask(); + } else { + tse_log_reg_error_by_code(result); + } + + shm_free(nullptr, req); + return result; +} + +int tse_mq_get_batch_data(dsw_message_block_t *message_block, uint8_t *buf_data, uint32_t buf_len) +{ + uint32_t use_buf_len = 0; + for (uint16_t i = 0; i < message_block->head.seg_num; ++i) { + if (message_block->head.seg_desc[i].length > TSE_MQ_MESSAGE_SLICE_LEN) { + tse_log_error("seg_data length error, seg_len:%u.", message_block->head.seg_desc[i].length); + return ERR_GENERIC_INTERNAL_ERROR; + } + + if (use_buf_len + message_block->head.seg_desc[i].length > buf_len) { + tse_log_error("buf len error, buf_len:%u, use_buf_len:%u.", buf_len, use_buf_len); + return ERR_GENERIC_INTERNAL_ERROR; + } + + if (message_block->seg_buf[i] == nullptr) { + tse_log_error("buf_data error, seg_buf[%u] is null.", i); + return ERR_GENERIC_INTERNAL_ERROR; + } + + memcpy(buf_data + use_buf_len, message_block->seg_buf[i], message_block->head.seg_desc[i].length); + use_buf_len += message_block->head.seg_desc[i].length; + } + return CT_SUCCESS; +} + +static int tse_mq_fill_batch_data(shm_seg_s *seg, dsw_message_block_t* msg, uint8_t* data_buf, + uint32_t data_len, uint32_t buf_size) +{ + assert(data_len <= buf_size); + + uint8_t* buf_tmp = data_buf; + msg->head.seg_num = 0; + uint16_t i; + uint32_t tmp_len = buf_size; + uint32_t copy_len; + while (tmp_len > 0) { + i = msg->head.seg_num; + if (tmp_len > TSE_MQ_MESSAGE_SLICE_LEN) { + msg->head.seg_desc[i].length = TSE_MQ_MESSAGE_SLICE_LEN; + } else { + msg->head.seg_desc[i].length = tmp_len; + } + tmp_len -= msg->head.seg_desc[i].length; + + msg->head.seg_desc[i].type = 0; + msg->seg_buf[i] = shm_alloc(seg, msg->head.seg_desc[i].length); + if (msg->seg_buf[i] == nullptr) { + tse_log_error("Alloc seg_buf failed, seg_num:%u, buf_len:%u.", i, msg->head.seg_desc[i].length); + batch_free_shm_buf(seg, msg); + return ERR_ALLOC_MEMORY; + } + + if (data_len > 0) { + copy_len = data_len > TSE_MQ_MESSAGE_SLICE_LEN ? TSE_MQ_MESSAGE_SLICE_LEN : data_len; + data_len -= copy_len; + + memcpy(msg->seg_buf[i], buf_tmp, copy_len); + buf_tmp += copy_len; + } + ++msg->head.seg_num; + } + return CT_SUCCESS; +} + +EXTER_ATTACK int tse_mq_batch_send_message(void *shm_inst, TSE_FUNC_TYPE func_type, uint8_t* data_buf, + uint32_t send_data_len, uint32_t buf_size) +{ + if (buf_size > TSE_MQ_MESSAGE_SLICE_LEN * DSW_MESSAGE_SEGMENT_NUM_MAX) { + tse_log_error("batch send message failed, data_len:%u.", buf_size); + return ERR_GENERIC_INTERNAL_ERROR; + } + + shm_seg_s *seg = (shm_seg_s *)shm_inst; + dsw_message_block_t* msg = (dsw_message_block_t*)shm_alloc(seg, sizeof(dsw_message_block_t)); + if (msg == nullptr) { + tse_log_error("alloc shm failed, len:%lu.", sizeof(dsw_message_block_t)); + return ERR_ALLOC_MEMORY; + } + + ct_errno_t result = CT_SUCCESS; + int ret = sem_init(&msg->head.sem, 1, 0); + if (ret != 0) { + shm_free(nullptr, msg); + result = ERR_SEM_FAULT; + tse_log_error("sem init failed, ret(%d).", ret); + return result; + } + + do { + ret = tse_mq_fill_batch_data(seg, msg, data_buf, send_data_len, buf_size); + if (ret != CT_SUCCESS) { + result = ERR_BATCH_DATA_HANDLE_FAILED; + break; + } + + msg->head.src_nid = g_shm_client_id; + msg->head.dst_nid = SERVER_PROC_ID; + msg->head.cmd_type = (uint32_t)func_type; + ret = shm_send_msg(seg, SERVER_PROC_ID, msg); + if (ret != CT_SUCCESS) { + result = ERR_SHM_SEND_MSG_FAILED; + tse_log_error("batch send msg failed, ret:%d, func_type:%d.", ret, func_type); + break; + } + + sched_yield(); + ret = sem_wait(&msg->head.sem); + if (ret != CT_SUCCESS) { + result = ERR_SEM_FAULT; + tse_log_error("batch send msg sem wait failed, ret:%d, func_type:%d.", ret, func_type); + break; + } + + ret = tse_mq_get_batch_data(msg, data_buf, buf_size); + if (ret != 0) { + result = ERR_BATCH_DATA_HANDLE_FAILED; + tse_log_error("get batch data error, data_buf:%p, data_len:%u.", data_buf, buf_size); + break; + } + } while (0); + + ret = sem_destroy(&msg->head.sem); + if (ret != CT_SUCCESS) { + tse_log_error("sem destory failed, ret:%d, func_type:%d.", ret, func_type); + } + batch_free_shm_buf(seg, msg); + shm_free(nullptr, msg); + return result; +} diff --git a/storage/tianchi/tse_srv_mq_module.h b/storage/tianchi/tse_srv_mq_module.h new file mode 100644 index 0000000..f542c8f --- /dev/null +++ b/storage/tianchi/tse_srv_mq_module.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __TSE_SRV_MQ_MODULE__ +#define __TSE_SRV_MQ_MODULE__ + +#include "tse_srv.h" +#include "message_queue/dsw_shm.h" +#include "message_queue/dsw_message.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cpluscplus */ + +void *get_one_shm_inst(tianchi_handler_t *tch); +int tse_mq_register_func(void); +int tse_mq_batch_send_message(void *shm_inst, TSE_FUNC_TYPE func_type, uint8_t* data_buf, + uint32_t send_data_len, uint32_t buf_size); + +int tse_mq_deal_func(void* shm_inst, enum TSE_FUNC_TYPE func_type, void* request,void* msg_buf, + uint32_t server_id = SERVER_PROC_ID, uint32_t wait_sec = 0); + +#ifdef __cplusplus +} +#endif /* __cpluscplus */ + +#endif diff --git a/storage/tianchi/tse_srv_mq_stub.cc b/storage/tianchi/tse_srv_mq_stub.cc new file mode 100644 index 0000000..31c723c --- /dev/null +++ b/storage/tianchi/tse_srv_mq_stub.cc @@ -0,0 +1,1458 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "srv_mq_msg.h" +#include "tse_srv_mq_module.h" +#include "message_queue/dsw_shm.h" +#include "tse_error.h" +#include "tse_log.h" +#include "tse_srv.h" +#include "tse_util.h" +#include "ha_tse.h" +#include "protobuf/tc_db.pb-c.h" +#include + +#define OUTLINE_LOB_LOCATOR_SIZE 44 // 行外LOB数据结构体长度 + +#define TSE_RESET_SHM_REQ_ERROR_CODE(_req) \ + do { \ + _req->error_code = 0; \ + _req->error_message[0] = 0; \ + } while (0) + +// 双进程模式在 tse_init 中已经提前获取 inst_id +int tse_alloc_inst_id(uint32_t *inst_id) { + *inst_id = ha_tse_get_inst_id(); + return tse_mq_register_func(); +} + +// 双进程模式在 clean_up_for_bad_mysql_proc 中释放 inst_id +int tse_release_inst_id(uint32_t ) { + return CT_SUCCESS; +} + +int tse_open_table(tianchi_handler_t *tch, const char *table_name, const char *user_name) { + assert(strlen(table_name) + 1 < SMALL_RECORD_SIZE); + assert(strlen(user_name) + 1 < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + open_table_request *req = (open_table_request*)alloc_share_mem(shm_inst, sizeof(open_table_request)); + DBUG_EXECUTE_IF("open_table_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(open_table_request)); + return ERR_ALLOC_MEMORY; + } + + memcpy(req->table_name, table_name, strlen(table_name) + 1); + memcpy(req->user_name, user_name, strlen(user_name) + 1); + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_OPEN_TABLE, req, tch->msg_buf); + *tch = req->tch; // 此处不管参天处理成功与否,都需要拷贝一次,避免session泄漏 + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_close_session(tianchi_handler_t *tch) { + tse_log_note("close session"); + void *shm_inst = get_one_shm_inst(tch); + close_session_request *req = (close_session_request*)alloc_share_mem(shm_inst, sizeof(close_session_request)); + if (req == NULL) { + tse_log_error("[TSE_CLOSE_SESSION]:alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(close_session_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_CLOSE_SESSION, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +void tse_kill_session(tianchi_handler_t *tch) { + tse_log_note("kill session"); + void *shm_inst = get_one_shm_inst(tch); + close_session_request *req = (close_session_request*)alloc_share_mem(shm_inst, sizeof(close_session_request)); + if (req == NULL) { + tse_log_error("[TSE_KILL_SESSION]:alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(close_session_request)); + return; + } + req->tch = *tch; + + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_KILL_CONNECTION, req, tch->msg_buf); + if (ret != CT_SUCCESS) { + tse_log_error("[TSE_KILL_SESSION]:Connection failed when sending kill stmt message to Cantian"); + } + free_share_mem(shm_inst, req); +} + +int tse_close_table(tianchi_handler_t *tch) { + void *shm_inst = get_one_shm_inst(tch); + close_table_request *req = (close_table_request*)alloc_share_mem(shm_inst, sizeof(close_table_request)); + DBUG_EXECUTE_IF("close_table_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(close_table_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_CLOSE_TABLE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_write_row(tianchi_handler_t *tch, const record_info_t *record_info, + uint16_t serial_column_offset, uint64_t *last_insert_id, dml_flag_t flag) { + void *shm_inst = get_one_shm_inst(tch); + write_row_request *req = (write_row_request*)alloc_share_mem(shm_inst, sizeof(write_row_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(write_row_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record_len = record_info->record_len; + req->record = record_info->record; + req->serial_column_offset = serial_column_offset; + req->flag = flag; + int result = ERR_CONNECTION_FAILED; + int ret = CT_SUCCESS; + if (req->flag.write_through) { + ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_WRITE_THROUGH_ROW, req, tch->msg_buf); + } else { + ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_WRITE_ROW, req, tch->msg_buf); + } + tch->sql_stat_start = req->tch.sql_stat_start; + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + *last_insert_id = req->last_insert_id; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_bulk_write(tianchi_handler_t *tch, const record_info_t *record_info, uint64_t rec_num, + uint32_t *err_pos, dml_flag_t flag, ctc_part_t *part_ids) { + void *shm_inst = get_one_shm_inst(tch); + assert(record_info->record_len * rec_num <= MAX_RECORD_SIZE); + bulk_write_request *req = (bulk_write_request*)alloc_share_mem(shm_inst, sizeof(bulk_write_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(bulk_write_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record_len = record_info->record_len; + req->record_num = rec_num; + req->flag = flag; + memcpy(req->record, record_info->record, record_info->record_len * rec_num); + if (part_ids != nullptr) { + memcpy(req->part_ids, part_ids, rec_num * sizeof(ctc_part_t)); + } + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_BULK_INSERT, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + if (result == ERR_DUPLICATE_KEY) { + *err_pos = req->err_pos; + } + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_update_row(tianchi_handler_t *tch, uint16_t new_record_len, const uint8_t *new_record, + const uint16_t *upd_cols, uint16_t col_num, dml_flag_t flag) { + assert(new_record_len < BIG_RECORD_SIZE); + assert(col_num <= TSE_MAX_COLUMNS); + void *shm_inst = get_one_shm_inst(tch); + update_row_request *req = (update_row_request*)alloc_share_mem(shm_inst, sizeof(update_row_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(update_row_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->new_record_len = new_record_len; + req->col_num = col_num; + req->new_record = const_cast(new_record); + req->flag = flag; + memcpy(req->upd_cols, upd_cols, sizeof(uint16_t) * col_num); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_UPDATE_ROW, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_delete_row(tianchi_handler_t *tch, uint16_t record_len, dml_flag_t flag) { + assert(record_len < BIG_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + delete_row_request *req = (delete_row_request*)alloc_share_mem(shm_inst, sizeof(delete_row_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(delete_row_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record_len = record_len; + req->flag = flag; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DELETE_ROW, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_scan_records(tianchi_handler_t *tch, uint64_t *num_rows, char *index_name) { + void *shm_inst = get_one_shm_inst(tch); + scan_records_request *req = (scan_records_request*)alloc_share_mem(shm_inst, sizeof(scan_records_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(scan_records_request)); + return ERR_ALLOC_MEMORY; + } + memset(req, 0, sizeof(scan_records_request)); + if (index_name != nullptr) { + memcpy(req->index_name, index_name, strlen(index_name) + 1); + } + req->tch = *tch; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_SCAN_RECORDS, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + if (req->result == CT_SUCCESS) { + *num_rows = req->num_rows; + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_rnd_next(tianchi_handler_t *tch, record_info_t *record_info) { + void *shm_inst = get_one_shm_inst(tch); + rnd_next_request *req = (rnd_next_request*)alloc_share_mem(shm_inst, sizeof(rnd_next_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(rnd_next_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record = record_info->record; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RND_NEXT, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + if(req->result == CT_SUCCESS) { + record_info->record_len = req->record_len; + assert(record_info->record_len < BIG_RECORD_SIZE); + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_rnd_prefetch(tianchi_handler_t *tch, uint8_t *records, uint16_t *record_lens, + uint32_t *recNum, uint64_t *rowids, int32_t max_row_size) +{ + void *shm_inst = get_one_shm_inst(tch); + rnd_prefetch_request *req = (rnd_prefetch_request*)alloc_share_mem(shm_inst, sizeof(rnd_prefetch_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(rnd_prefetch_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->max_row_size = max_row_size; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RND_PREFETCH, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + if (req->result == CT_SUCCESS) { + *recNum = *(req->recNum); + if (*recNum != 0) { + uint32_t record_len = 0; + for(uint8_t i = 0; i < *recNum; i ++){ + record_len += req->record_lens[i]; + } + memcpy(records, req->records, record_len); + memcpy(record_lens, req->record_lens, *recNum * sizeof(uint16_t)); + memcpy(rowids, req->rowids, *recNum * sizeof(uint64_t)); + } + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_rnd_init(tianchi_handler_t *tch, expected_cursor_action_t action, tse_select_mode_t mode, tse_conds *cond) { + void *shm_inst = get_one_shm_inst(tch); + rnd_init_request *req = (rnd_init_request*)alloc_share_mem(shm_inst, sizeof(rnd_init_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(rnd_init_request)); + return ERR_ALLOC_MEMORY; + } + + req->tch = *tch; + req->action = action; + req->mode = mode; + req->cond = cond; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RND_INIT, req, tch->msg_buf); + *tch = req->tch; + tch->sql_stat_start = req->tch.sql_stat_start; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_rnd_end(tianchi_handler_t *tch) { + void *shm_inst = get_one_shm_inst(tch); + rnd_end_request *req = (rnd_end_request*)alloc_share_mem(shm_inst, sizeof(rnd_end_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(rnd_end_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RND_END, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_position(tianchi_handler_t *tch, uint8_t *position, uint16_t pos_length) { + assert(pos_length < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + position_request *req = (position_request*)alloc_share_mem(shm_inst, sizeof(position_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(position_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->pos_length = pos_length; + memcpy(req->position, position, pos_length); + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_POSITION, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + memcpy(position, req->position, pos_length); + } + result = req->result; + free_share_mem(shm_inst, req); + return result; +} + +int tse_rnd_pos(tianchi_handler_t *tch, uint16_t pos_length, uint8_t *position, record_info_t *record_info) { + assert(pos_length < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + rnd_pos_request *req = (rnd_pos_request*)alloc_share_mem(shm_inst, sizeof(rnd_pos_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(rnd_pos_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record = record_info->record; + req->pos_length = pos_length; + memcpy(req->position, position, pos_length); + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RND_POS, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + if(req->result == CT_SUCCESS) { + record_info->record_len = req->record_len; + assert(record_info->record_len < BIG_RECORD_SIZE); + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_delete_all_rows(tianchi_handler_t *tch, dml_flag_t flag) { + void *shm_inst = get_one_shm_inst(tch); + delete_all_rows_request *req = (delete_all_rows_request*)alloc_share_mem(shm_inst, sizeof(delete_all_rows_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(delete_all_rows_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->flag = flag; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DELETE_ALL_ROWS, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_index_end(tianchi_handler_t *tch) { + void *shm_inst = get_one_shm_inst(tch); + index_end_request *req = (index_end_request*)alloc_share_mem(shm_inst, sizeof(index_end_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(index_end_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_INDEX_END, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +static void copy_index_info_to_req(const index_key_info_t *index_info, index_read_request *req) { + uint32_t left_offset = 0; + uint32_t right_offset = 0; + uint8_t *pLeft = req->left_key_record; + uint8_t *pRight = req->right_key_record; + for (uint i = 0; i < MAX_KEY_COLUMNS; ++i) { + req->is_key_null[i] = true; + } + + for (int i = 0; i < index_info->key_num; ++i) { + req->is_key_null[i] = index_info->key_info[i].is_key_null; + if (index_info->key_info[i].left_key != nullptr) { + assert(left_offset + index_info->key_info[i].left_key_len <= INDEX_KEY_SIZE); + memcpy(pLeft, index_info->key_info[i].left_key, index_info->key_info[i].left_key_len); + pLeft += index_info->key_info[i].left_key_len; + req->left_key_info.key_offsets[i] = left_offset; + req->left_key_info.key_lens[i] = index_info->key_info[i].left_key_len; + left_offset += req->left_key_info.key_lens[i]; + } else { + req->left_key_info.key_lens[i] = 0; + req->left_key_info.key_offsets[i] = 0; + } + + if (index_info->key_info[i].right_key != nullptr) { + assert(right_offset + index_info->key_info[i].right_key_len <= INDEX_KEY_SIZE); + memcpy(pRight, index_info->key_info[i].right_key, index_info->key_info[i].right_key_len); + pRight += index_info->key_info[i].right_key_len; + req->right_key_info.key_offsets[i] = right_offset; + req->right_key_info.key_lens[i] = index_info->key_info[i].right_key_len; + right_offset += req->right_key_info.key_lens[i]; + } else { + req->right_key_info.key_lens[i] = 0; + req->right_key_info.key_offsets[i] = 0; + } + } + + req->need_init = index_info->need_init; + req->find_flag = index_info->find_flag; + req->action = index_info->action; + req->sorted = index_info->sorted; + req->key_num = index_info->key_num; + memcpy(req->index_name, index_info->index_name, strlen(index_info->index_name) + 1); + + return; +} + +int tse_index_read(tianchi_handler_t *tch, record_info_t *record_info, index_key_info_t *index_info, + tse_select_mode_t mode, tse_conds *cond, const bool is_replace) { + if (index_info == NULL) { + return ERR_GENERIC_INTERNAL_ERROR; + } + + void *shm_inst = get_one_shm_inst(tch); + index_read_request *req = (index_read_request*)alloc_share_mem(shm_inst, sizeof(index_read_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(index_read_request)); + return ERR_ALLOC_MEMORY; + } + + copy_index_info_to_req(index_info, req); + + req->tch = *tch; + req->record = record_info->record; + req->record_len = 0; + req->mode = mode; + req->cond = cond; + req->is_replace = is_replace; + req->result = 0; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_INDEX_READ, req, tch->msg_buf); + *tch = req->tch; + tch->sql_stat_start = req->tch.sql_stat_start; + if (ret == CT_SUCCESS) { + if(req->result == CT_SUCCESS) { + record_info->record_len = req->record_len; + assert(record_info->record_len < BIG_RECORD_SIZE); + } + result = req->result; + index_info->need_init = req->need_init; + } + + free_share_mem(shm_inst, req); + + return result; +} + +int tse_trx_begin(tianchi_handler_t *tch, tianchi_trx_context_t trx_context, bool is_mysql_local) { + void *shm_inst = get_one_shm_inst(tch); + trx_begin_request *req = (trx_begin_request*)alloc_share_mem(shm_inst, sizeof(trx_begin_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(trx_begin_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->trx_context = trx_context; + req->is_mysql_local = is_mysql_local; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_TRX_BEGIN, req, tch->msg_buf); + *tch = req->tch; // 此处不管参天处理成功与否,都需要拷贝一次,避免session泄漏 + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_trx_commit(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit) { + void *shm_inst = get_one_shm_inst(tch); + trx_commit_request *req = (trx_commit_request*)alloc_share_mem(shm_inst, sizeof(trx_commit_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(trx_commit_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->csize = csize; + req->cursors = cursors; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_TRX_COMMIT, req, tch->msg_buf); + *is_ddl_commit = req->is_ddl_commit; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_trx_rollback(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize) { + void *shm_inst = get_one_shm_inst(tch); + trx_rollback_request *req = (trx_rollback_request*)alloc_share_mem(shm_inst, sizeof(trx_rollback_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(trx_rollback_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->csize = csize; + req->cursors = cursors; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_TRX_ROLLBACK, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_srv_set_savepoint(tianchi_handler_t *tch, const char *name) { + assert(strlen(name) + 1 < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + srv_set_savepoint_request *req = (srv_set_savepoint_request*)alloc_share_mem(shm_inst, sizeof(srv_set_savepoint_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(srv_set_savepoint_request)); + return ERR_ALLOC_MEMORY; + } + memcpy(req->name, name, strlen(name) + 1); + req->tch = *tch; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_SRV_SET_SAVEPOINT, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_srv_rollback_savepoint(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize, const char *name) { + assert(strlen(name) + 1 < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + srv_rollback_savepoint_request *req = (srv_rollback_savepoint_request*)alloc_share_mem(shm_inst, sizeof(srv_rollback_savepoint_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(srv_rollback_savepoint_request)); + return ERR_ALLOC_MEMORY; + } + memcpy(req->name, name, strlen(name) + 1); + req->tch = *tch; + req->csize = csize; + req->cursors = cursors; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_SRV_ROLLBACK_SAVEPOINT, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_srv_release_savepoint(tianchi_handler_t *tch, const char *name) { + assert(strlen(name) + 1 < SMALL_RECORD_SIZE); + void *shm_inst = get_one_shm_inst(tch); + srv_release_savepoint_request *req = (srv_release_savepoint_request*)alloc_share_mem(shm_inst, sizeof(srv_release_savepoint_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(srv_release_savepoint_request)); + return ERR_ALLOC_MEMORY; + } + memcpy(req->name, name, strlen(name) + 1); + req->tch = *tch; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_SRV_RELEASE_SAVEPOINT, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_general_fetch(tianchi_handler_t *tch, record_info_t *record_info) { + void *shm_inst = get_one_shm_inst(tch); + general_fetch_request *req = (general_fetch_request*)alloc_share_mem(shm_inst, sizeof(general_fetch_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(general_fetch_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->record = record_info->record; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GENERAL_FETCH, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + if (req->result == CT_SUCCESS) { + record_info->record_len = req->record_len; + assert(record_info->record_len < BIG_RECORD_SIZE); + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_free_session_cursors(tianchi_handler_t *tch, uint64_t *cursors, int32_t csize) { + void *shm_inst = get_one_shm_inst(tch); + free_session_cursors_request *req = (free_session_cursors_request*)alloc_share_mem(shm_inst, sizeof(free_session_cursors_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(free_session_cursors_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->csize = csize; + req->cursors = cursors; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_FREE_CURSORS, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_get_max_sessions_per_node(uint32_t *max_sessions) { + void *shm_inst = get_one_shm_inst(NULL); + get_max_session_request *req = (get_max_session_request*)alloc_share_mem(shm_inst, sizeof(get_max_session_request)); + DBUG_EXECUTE_IF("tse_get_max_sessions_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(get_max_session_request)); + return ERR_ALLOC_MEMORY; + } + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GET_MAX_SESSIONS, req, nullptr); + if (ret == CT_SUCCESS) { + *max_sessions = req->max_sessions; + } + return ret; +} + +int tse_analyze_table(tianchi_handler_t *tch, const char *db_name, const char *table_name, double sampling_ratio) { + assert(strlen(db_name) + 1 <= SMALL_RECORD_SIZE); + assert(strlen(table_name) + 1 <= SMALL_RECORD_SIZE); + + void *shm_inst = get_one_shm_inst(tch); + analyze_table_request *req = (analyze_table_request*)alloc_share_mem(shm_inst, sizeof(analyze_table_request)); + DBUG_EXECUTE_IF("tse_analyze_table_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(analyze_table_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->ratio = sampling_ratio; + memcpy(req->table_name, table_name, strlen(table_name) + 1); + memcpy(req->user_name, db_name, strlen(db_name) + 1); + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_ANALYZE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_get_huge_part_table_cbo_stats(tianchi_handler_t *tch, tianchi_cbo_stats_t *stats) { + void *shm_inst = get_one_shm_inst(tch); + uint32_t request_size = sizeof(get_cbo_stats_request) + sizeof(tianchi_cbo_stats_t) + + stats->part_table_info.rows_and_blocks_size; + uint32_t req_size = request_size + stats->part_table_info.high_value_size + + stats->part_table_info.num_distinct_size + + stats->part_table_info.low_value_size; + uint8_t *req_buf = new uint8_t[req_size]; + get_cbo_stats_request *req = (get_cbo_stats_request *)req_buf; + req->tch = *tch; + memcpy(req_buf + sizeof(get_cbo_stats_request), stats, + sizeof(tianchi_cbo_stats_t) + stats->part_table_info.rows_and_blocks_size); + uint8_t *stats_offset = req_buf + sizeof(get_cbo_stats_request); + req->stats = (tianchi_cbo_stats_t *)stats_offset; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_GET_HUGE_PART_TABLE_CBO_STATS, req_buf, + request_size, req_size); + if (ret != CT_SUCCESS) { + result = ret; + tse_log_error("tse_mq_batch_send_message failed in get_huge_part_table_cbo_stats: %d", ret); + } else if (req->result == CT_SUCCESS) { + // 此时req指向的参天区域,需要将其指向mysql数据区 + req->stats = (tianchi_cbo_stats_t *)stats_offset; + req->stats->tse_cbo_stats_table.part_table_num_distincts = stats->tse_cbo_stats_table.part_table_num_distincts; + req->stats->tse_cbo_stats_table.part_table_low_values = stats->tse_cbo_stats_table.part_table_low_values; + req->stats->tse_cbo_stats_table.part_table_high_values = stats->tse_cbo_stats_table.part_table_high_values; + + *tch = req->tch; + memcpy(stats, req_buf + sizeof(get_cbo_stats_request), req_size - sizeof(get_cbo_stats_request)); + result = req->result; + } + delete[] req_buf; + return result; +} + +int tse_get_cbo_stats(tianchi_handler_t *tch, tianchi_cbo_stats_t *stats) { + if (stats->part_table_info.low_value_size > MAX_MESSAGE_SIZE) { + return tse_get_huge_part_table_cbo_stats(tch, stats); + } + void *shm_inst = get_one_shm_inst(tch); + get_cbo_stats_request *req = (get_cbo_stats_request*)alloc_share_mem(shm_inst, sizeof(get_cbo_stats_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(get_cbo_stats_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->stats = stats; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GET_CBO_STATS, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + if (req->result == CT_SUCCESS) { + *tch = req->tch; + stats = req->stats; + } + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_get_index_name(tianchi_handler_t *tch, char *index_name) { + void *shm_inst = get_one_shm_inst(tch); + get_index_slot_request *req = (get_index_slot_request*)alloc_share_mem(shm_inst, sizeof(get_index_slot_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%d)", shm_inst, REQUEST_SIZE); + return ERR_ALLOC_MEMORY; + } + memset(req, 0, sizeof(get_index_slot_request)); + req->tch = *tch; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GET_INDEX_NAME, req, tch->msg_buf); + + if (ret == CT_SUCCESS) { + memcpy(index_name, req->index_name, strlen(req->index_name) + 1); + result = req->result; + } else { + result = ret; + tse_log_error("tse_get_index_name failed: %d", ret); + } + + free_share_mem(shm_inst, req); + return result; +} + +uint8_t* tse_alloc_buf(tianchi_handler_t *tch, uint32_t buf_size) { + if (buf_size == 0) { + return nullptr; + } + void *shm_inst = get_one_shm_inst(tch); + return (uint8_t*)alloc_share_mem(shm_inst, buf_size); +} + +void tse_free_buf(tianchi_handler_t *tch, uint8_t *buf) { + if (buf == nullptr) { + return; + } + void *shm_inst = get_one_shm_inst(tch); + free_share_mem(shm_inst, buf); +} + +int tse_general_prefetch(tianchi_handler_t *tch, uint8_t *records, uint16_t *record_lens, + uint32_t *recNum, uint64_t *rowids, int32_t max_row_size) { + void *shm_inst = get_one_shm_inst(tch); + general_prefetch_request *req = (general_prefetch_request*)alloc_share_mem(shm_inst, sizeof(general_prefetch_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(general_prefetch_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->max_row_size = max_row_size; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GENERAL_PREFETCH, req, tch->msg_buf); + *tch = req->tch; + + if (ret == CT_SUCCESS) { + *recNum = *(req->recNum); + if (*recNum != 0) { + uint32_t record_len = 0; + for(uint8_t i = 0; i < *recNum; i ++){ + record_len += req->record_lens[i]; + } + memcpy(records, req->records, record_len); + memcpy(record_lens, req->record_lens, *recNum * sizeof(uint16_t)); + memcpy(rowids, req->rowids, *recNum * sizeof(uint64_t)); + } + result = req->result; + } else { + result = ret; + tse_log_error("cantiand deal the message failed: %d", ret); + } + + free_share_mem(shm_inst, req); + return result; +} + +int tse_drop_tablespace_and_user(tianchi_handler_t *tch, + const char *db_name, + const char *sql_str, + const char *user_name, + const char *user_ip, + int *error_code, + char *error_message) +{ + void *shm_inst = get_one_shm_inst(tch); + drop_tablespace_and_user_request *req = (drop_tablespace_and_user_request*)alloc_share_mem(shm_inst, sizeof(drop_tablespace_and_user_request)); + DBUG_EXECUTE_IF("drop_tablespace_and_user_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(drop_tablespace_and_user_request)); + return ERR_ALLOC_MEMORY; + } + assert(strlen(db_name) + 1 <= sizeof(req->db_name)); + memcpy(req->db_name, db_name, strlen(db_name) + 1); + assert(strlen(sql_str) + 1 <= sizeof(req->sql_str)); + memcpy(req->sql_str, sql_str, strlen(sql_str) + 1); + + assert(strlen(user_name) + 1 <= sizeof(req->user_name)); + memcpy(req->user_name, user_name, strlen(user_name) + 1); + assert(strlen(user_ip) + 1 <= sizeof(req->user_ip)); + memcpy(req->user_ip, user_ip, strlen(user_ip) + 1); + TSE_RESET_SHM_REQ_ERROR_CODE(req); + req->tch = *tch; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DROP_TABLESPACE_AND_USER, req, tch->msg_buf); + *tch = req->tch; + if(req->error_message != NULL && strlen(req->error_message) > 0) { + *error_code = req->error_code; + memcpy(error_message, req->error_message, ERROR_MESSAGE_LEN); + } + free_share_mem(shm_inst, req); + int result = ERR_CONNECTION_FAILED; + if (ret == CT_SUCCESS) { + result = req->result; + } + return result; +} + +int tse_drop_db_pre_check(tianchi_handler_t *tch, const char *db_name, int *error_code, char *error_message) { + void *shm_inst = get_one_shm_inst(tch); + drop_db_pre_check_request *req = (drop_db_pre_check_request*)alloc_share_mem(shm_inst, sizeof(drop_db_pre_check_request)); + req->tch = *tch; + assert(strlen(db_name) + 1 <= sizeof(req->db_name)); + memcpy(req->db_name, db_name, strlen(db_name) + 1); + TSE_RESET_SHM_REQ_ERROR_CODE(req); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_DROP_DB_PRE_CHECK, req, tch->msg_buf); + *tch = req->tch; + *error_code = req->error_code; + strncpy(error_message, req->error_message, ERROR_MESSAGE_LEN - 1); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_lock_table(tianchi_handler_t *tch, const char *db_name, tse_lock_table_info *lock_info, + int *error_code) { + void *shm_inst = get_one_shm_inst(tch); + lock_table_request *req = (lock_table_request*)alloc_share_mem(shm_inst, sizeof(lock_table_request)); + DBUG_EXECUTE_IF("lock_table_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(lock_table_request)); + return ERR_ALLOC_MEMORY; + } + + req->db_name[0] = '\0'; + if (db_name != nullptr) { + strncpy(req->db_name, db_name, strlen(db_name) + 1); + } + + req->tch = *tch; + req->lock_info = *lock_info; + req->mysql_inst_id = tch->inst_id; + TSE_RESET_SHM_REQ_ERROR_CODE(req); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_LOCK_TABLE, req, tch->msg_buf); + *tch = req->tch; + *error_code = req->error_code; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_pre_create_db(tianchi_handler_t *tch, const char *sql_str, tse_db_infos_t *db_infos, + int *error_code, char *error_message) +{ + void *shm_inst = get_one_shm_inst(tch); + pre_create_db_request *req = (pre_create_db_request*)alloc_share_mem(shm_inst, sizeof(pre_create_db_request)); + DBUG_EXECUTE_IF("create_tablespace_and_user_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(pre_create_db_request)); + return ERR_ALLOC_MEMORY; + } + assert(strlen(sql_str) + 1 <= sizeof(req->sql_str)); + memcpy(req->sql_str, sql_str, strlen(sql_str) + 1); + assert(strlen(db_infos->name) + 1 <= sizeof(req->db_name)); + memcpy(req->db_name, db_infos->name, strlen(db_infos->name) + 1); + + req->tse_db_datafile_size = db_infos->datafile_size; + req->tse_db_datafile_autoextend = db_infos->datafile_autoextend; + req->tse_db_datafile_extend_size = db_infos->datafile_extend_size; + req->tch = *tch; + TSE_RESET_SHM_REQ_ERROR_CODE(req); + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_PRE_CREATE_DB, req, tch->msg_buf); + *tch = req->tch; + if(req->error_message != NULL && strlen(req->error_message) > 0) { + *error_code = req->error_code; + memcpy(error_message, req->error_message, ERROR_MESSAGE_LEN); + } + free_share_mem(shm_inst, req); + int result = ERR_CONNECTION_FAILED; + if (ret == CT_SUCCESS) { + result = req->result; + } + return result; +} + +int tse_unlock_table(tianchi_handler_t *tch, uint32_t mysql_insert_id, tse_lock_table_info *lock_info) { + void *shm_inst = get_one_shm_inst(tch); + tse_unlock_tables_request *req = (tse_unlock_tables_request*)alloc_share_mem(shm_inst, sizeof(tse_unlock_tables_request)); + DBUG_EXECUTE_IF("unlock_table_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(tse_unlock_tables_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->mysql_inst_id = mysql_insert_id; + req->lock_info = *lock_info; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_UNLOCK_TABLE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_knl_write_lob(tianchi_handler_t *tch, char* locator, uint32_t locator_size, int column_id, + void* data, uint32_t data_len, bool force_outline) +{ + void *shm_inst = get_one_shm_inst(tch); + int reqSize = sizeof(knl_write_lob_request) + data_len; + uchar* reqBuf = new uchar[reqSize]; + knl_write_lob_request *req = (knl_write_lob_request *)reqBuf; + if (req == NULL) { + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + memcpy(req->locator, locator, locator_size); + memcpy(req->data, data, data_len); + req->data_len = data_len; + req->column_id = column_id; + req->force_outline = force_outline; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_WRITE_LOB, reqBuf, reqSize, reqSize); + *tch = req->tch; + if (ret != CT_SUCCESS) { + tse_log_error("tse_mq_batch_send_message failed in write lob: %d", ret); + } else { + if (req->result == CT_SUCCESS) { + memcpy(locator, req->locator, locator_size); + } + result = req->result; + } + delete[] reqBuf; + return result; +} + +int tse_knl_read_lob(tianchi_handler_t *tch, char* locator, uint32_t offset, void *buf, uint32_t size, uint32_t *read_size) +{ + void *shm_inst = get_one_shm_inst(tch); + int reqSize = sizeof(knl_read_lob_request) + size; + uchar* reqBuf = new uchar[reqSize]; + knl_read_lob_request *req = (knl_read_lob_request *)reqBuf; + if (req == NULL) { + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + memcpy(req->locator, locator, OUTLINE_LOB_LOCATOR_SIZE); + req->offset = offset; + req->size = size; + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_READ_LOB, reqBuf, reqSize, reqSize); + if (ret != CT_SUCCESS) { + tse_log_error("tse_mq_batch_send_message failed in read lob: %d", ret); + } else { + if(req->result == CT_SUCCESS) { + *read_size = (uint32_t)(req->read_size); + assert(*read_size <= size); + memcpy(buf, req->buf, *read_size); + } + result = req->result; + } + delete[] reqBuf; + return result; +} + +int srv_wait_instance_startuped(void) +{ + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, 0); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%d)", shm_inst, 0); + return ERR_ALLOC_MEMORY; + } + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_WAIT_CONNETOR_STARTUPED, req_mem, nullptr, SERVER_REGISTER_PROC_ID, 5); + free_share_mem(shm_inst, req_mem); + return ret; +} + +int tse_create_table(void *table_def, ddl_ctrl_t *ddl_ctrl) { + void *shm_inst = get_one_shm_inst(&ddl_ctrl->tch); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_CREATE_TABLE, (uint8_t*)table_def, ddl_ctrl->msg_len, + ddl_ctrl->msg_len); + memcpy(ddl_ctrl, table_def, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + return result; +} + +int tse_truncate_table(void *table_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("truncate_table_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), table_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_TRUNCATE_TABLE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_truncate_partition(void *table_def, ddl_ctrl_t *ddl_ctrl) { + void *shm_inst = get_one_shm_inst(&ddl_ctrl->tch); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_TRUNCATE_PARTITION, (uint8_t*)table_def, ddl_ctrl->msg_len, + ddl_ctrl->msg_len); + memcpy(ddl_ctrl, table_def, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + return result; +} + +int tse_alter_table(void *alter_def, ddl_ctrl_t *ddl_ctrl) { + void *shm_inst = get_one_shm_inst(&ddl_ctrl->tch); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_batch_send_message(shm_inst, TSE_FUNC_TYPE_ALTER_TABLE, (uint8_t*)alter_def, ddl_ctrl->msg_len, + ddl_ctrl->msg_len); + memcpy(ddl_ctrl, alter_def, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + return result; +} + +int tse_rename_table(void *alter_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("rename_table_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), alter_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RENAME_TABLE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_execute_mysql_ddl_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail) { + void *shm_inst = get_one_shm_inst(tch); + execute_mysql_ddl_sql_request *req = (execute_mysql_ddl_sql_request*)alloc_share_mem(shm_inst, sizeof(execute_mysql_ddl_sql_request)); + DBUG_EXECUTE_IF("xcute_general_ddl_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(execute_mysql_ddl_sql_request)); + return ERR_ALLOC_MEMORY; + } + memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_ddl_broadcast_request)); + req->tch = *tch; + req->allow_fail = allow_fail; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_EXCUTE_MYSQL_DDL_SQL, req, tch->msg_buf); + *tch = req->tch; + broadcast_req->err_code = req->broadcast_req.err_code; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_broadcast_mysql_dd_invalidate(tianchi_handler_t *tch, tse_invalidate_broadcast_request *broadcast_req) { + void *shm_inst = get_one_shm_inst(tch); + invalidate_mysql_dd_request *req = (invalidate_mysql_dd_request *)alloc_share_mem(shm_inst, sizeof(invalidate_mysql_dd_request)); + DBUG_EXECUTE_IF("xcute_general_ddl_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(invalidate_mysql_dd_request)); + return ERR_ALLOC_MEMORY; + } + memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_invalidate_broadcast_request)); + req->tch = *tch; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_INVALIDATE_OBJECT, req, tch->msg_buf); + *tch = req->tch; + broadcast_req->err_code = req->broadcast_req.err_code; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_broadcast_rewrite_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail) { + void *shm_inst = get_one_shm_inst(tch); + execute_mysql_ddl_sql_request *req = (execute_mysql_ddl_sql_request*)alloc_share_mem(shm_inst, sizeof(execute_mysql_ddl_sql_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(execute_mysql_ddl_sql_request)); + return ERR_ALLOC_MEMORY; + } + + memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_ddl_broadcast_request)); + req->tch = *tch; + req->allow_fail = allow_fail; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_BROADCAST_REWRITE_SQL, req, tch->msg_buf); + *tch = req->tch; + broadcast_req->err_code = req->broadcast_req.err_code; + memcpy(broadcast_req->err_msg, req->broadcast_req.err_msg, ERROR_MESSAGE_LEN); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_get_serial_value(tianchi_handler_t *tch, uint64_t *value, dml_flag_t flag) { + void *shm_inst = get_one_shm_inst(tch); + get_serial_val_request *req = (get_serial_val_request*)alloc_share_mem(shm_inst, sizeof(get_serial_val_request)); + DBUG_EXECUTE_IF("get_serial_val_ddl_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(get_serial_val_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->flag.auto_inc_step = flag.auto_inc_step; + req->flag.auto_inc_offset = flag.auto_inc_offset; + req->flag.auto_increase = flag.auto_increase; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GET_SERIAL_VALUE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + *value = req->value; + result = req->result; + } + + free_share_mem(shm_inst, req); + return result; +} + +int tse_drop_table(void *drop_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("drop_table_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), drop_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DROP_TABLE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_create_tablespace(void *space_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("create_tablespace_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), space_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_CREATE_TABLESPACE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_alter_tablespace(void *space_alter_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("alter_tablespace_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), space_alter_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_ALTER_TABLESPACE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_drop_tablespace(void *space_drop_def, ddl_ctrl_t *ddl_ctrl) { + assert(ddl_ctrl->msg_len + sizeof(ddl_ctrl_t) < REQUEST_SIZE); + void *shm_inst = get_one_shm_inst(NULL); + void *req_mem = alloc_share_mem(shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + DBUG_EXECUTE_IF("drop_tablespace_shm_oom", { req_mem = NULL; }); + if (req_mem == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, ddl_ctrl->msg_len + sizeof(ddl_ctrl_t)); + return ERR_ALLOC_MEMORY; + } + memcpy((char *)req_mem, ddl_ctrl, sizeof(ddl_ctrl_t)); + memcpy((char *)req_mem + sizeof(ddl_ctrl_t), space_drop_def, ddl_ctrl->msg_len); + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DROP_TABLESPACE, req_mem, nullptr); + memcpy(ddl_ctrl, req_mem, sizeof(ddl_ctrl_t)); + if (ret == CT_SUCCESS) { + result = ddl_ctrl->error_code; + } + free_share_mem(shm_inst, req_mem); + return result; +} + +int tse_lock_instance(bool *is_mysqld_starting, tse_lock_table_mode_t lock_type, tianchi_handler_t *tch) { + void *shm_inst = get_one_shm_inst(tch); + lock_instance_request *req = (lock_instance_request*)alloc_share_mem(shm_inst, sizeof(lock_instance_request)); + DBUG_EXECUTE_IF("lock_instance_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(lock_instance_request)); + return ERR_ALLOC_MEMORY; + } + + req->tch = *tch; + req->lock_type = lock_type; + req->is_mysqld_starting = *is_mysqld_starting; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_LOCK_INSTANCE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_unlock_instance(bool *is_mysqld_starting, tianchi_handler_t *tch) { + void *shm_inst = get_one_shm_inst(tch); + unlock_instance_request *req = (unlock_instance_request*)alloc_share_mem(shm_inst, sizeof(unlock_instance_request)); + DBUG_EXECUTE_IF("unlock_instance_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(unlock_instance_request)); + return ERR_ALLOC_MEMORY; + } + + req->tch = *tch; + req->is_mysqld_starting = *is_mysqld_starting; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_UNLOCK_INSTANCE, req, tch->msg_buf); + *tch = req->tch; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + +int tse_search_metadata_status(bool *cantian_metadata_switch, bool *cantian_cluster_ready) { + void *shm_inst = get_one_shm_inst(NULL); + search_metadata_status_request *req = (search_metadata_status_request*)alloc_share_mem(shm_inst, sizeof(search_metadata_status_request)); + DBUG_EXECUTE_IF("check_init_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(search_metadata_status_request)); + return ERR_ALLOC_MEMORY; + } + + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_SEARCH_METADATA_SWITCH, req, nullptr); + if (ret == CT_SUCCESS) { + result = req->result; + *cantian_metadata_switch = req->metadata_switch; + *cantian_cluster_ready = req->cluster_ready; + } + free_share_mem(shm_inst, req); + + return result; +} + +int tse_check_db_table_exists(const char *db, const char *name, bool *is_exists) { + void *shm_inst = get_one_shm_inst(NULL); + check_table_exists_request *req = (check_table_exists_request*)alloc_share_mem(shm_inst, sizeof(check_table_exists_request)); + DBUG_EXECUTE_IF("check_init_shm_oom", { req = NULL; }); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(check_table_exists_request)); + return ERR_ALLOC_MEMORY; + } + int result = ERR_CONNECTION_FAILED; + memcpy(req->db, db, strlen(db) + 1); + memcpy(req->name, name, strlen(name) + 1); + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_CHECK_TABLE_EXIST, req, nullptr); + if (ret == CT_SUCCESS) { + result = req->result; + *is_exists = (bool)req->is_exists; + } + free_share_mem(shm_inst, req); + + return result; +} + +int ctc_record_sql_for_cantian(tianchi_handler_t *tch, tse_ddl_broadcast_request *broadcast_req, bool allow_fail) { + void *shm_inst = get_one_shm_inst(tch); + execute_mysql_ddl_sql_request *req = (execute_mysql_ddl_sql_request*)alloc_share_mem(shm_inst, sizeof(execute_mysql_ddl_sql_request)); + if (req == NULL) { + tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(execute_mysql_ddl_sql_request)); + return ERR_ALLOC_MEMORY; + } + + memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_ddl_broadcast_request)); + req->tch = *tch; + req->allow_fail = allow_fail; + int result = ERR_CONNECTION_FAILED; + int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_RECORD_SQL, req, tch->msg_buf); + *tch = req->tch; + broadcast_req->err_code = req->broadcast_req.err_code; + memcpy(broadcast_req->err_msg, req->broadcast_req.err_msg, ERROR_MESSAGE_LEN); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} diff --git a/storage/tianchi/tse_stats.cc b/storage/tianchi/tse_stats.cc new file mode 100644 index 0000000..6ba8508 --- /dev/null +++ b/storage/tianchi/tse_stats.cc @@ -0,0 +1,146 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "tse_stats.h" +#include "tse_log.h" +#include + +const char *ctc_interface_strs[] = { + "TSE_FUNC_TYPE_OPEN_TABLE", + "TSE_FUNC_TYPE_CLOSE_TABLE", + "TSE_FUNC_TYPE_CLOSE_SESSION", + "TSE_FUNC_TYPE_WRITE_ROW", + "TSE_FUNC_TYPE_WRITE_THROUGH_ROW", + "TSE_FUNC_TYPE_UPDATE_ROW", + "TSE_FUNC_TYPE_DELETE_ROW", + "TSE_FUNC_TYPE_RND_INIT", + "TSE_FUNC_TYPE_RND_END", + "TSE_FUNC_TYPE_RND_NEXT", + "TSE_FUNC_TYPE_RND_PREFETCH", + "TSE_FUNC_TYPE_SCAN_RECORDS", + "TSE_FUNC_TYPE_TRX_COMMIT", + "TSE_FUNC_TYPE_TRX_ROLLBACK", + "TSE_FUNC_TYPE_TRX_BEGIN", + "TSE_FUNC_TYPE_LOCK_TABLE", + "TSE_FUNC_TYPE_UNLOCK_TABLE", + "TSE_FUNC_TYPE_INDEX_END", + "TSE_FUNC_TYPE_SRV_SET_SAVEPOINT", + "TSE_FUNC_TYPE_SRV_ROLLBACK_SAVEPOINT", + "TSE_FUNC_TYPE_SRV_RELEASE_SAVEPOINT", + "TSE_FUNC_TYPE_GENERAL_FETCH", + "TSE_FUNC_TYPE_GENERAL_PREFETCH", + "TSE_FUNC_TYPE_FREE_CURSORS", + "TSE_FUNC_TYPE_GET_INDEX_NAME", + "TSE_FUNC_TYPE_INDEX_READ", + "TSE_FUNC_TYPE_RND_POS", + "TSE_FUNC_TYPE_POSITION", + "TSE_FUNC_TYPE_DELETE_ALL_ROWS", + "TSE_FUNC_TYPE_GET_CBO_STATS", + "TSE_FUNC_TYPE_GET_HUGE_PART_TABLE_CBO_STATS", + "TSE_FUNC_TYPE_WRITE_LOB", + "TSE_FUNC_TYPE_READ_LOB", + "TSE_FUNC_TYPE_CREATE_TABLE", + "TSE_FUNC_TYPE_TRUNCATE_TABLE", + "TSE_FUNC_TYPE_TRUNCATE_PARTITION", + "TSE_FUNC_TYPE_RENAME_TABLE", + "TSE_FUNC_TYPE_ALTER_TABLE", + "TSE_FUNC_TYPE_GET_SERIAL_VALUE", + "TSE_FUNC_TYPE_DROP_TABLE", + "TSE_FUNC_TYPE_EXCUTE_MYSQL_DDL_SQL", + "TSE_FUNC_TYPE_BROADCAST_REWRITE_SQL", + "TSE_FUNC_TYPE_CREATE_TABLESPACE", + "TSE_FUNC_TYPE_ALTER_TABLESPACE", + "TSE_FUNC_TYPE_DROP_TABLESPACE", + "TSE_FUNC_TYPE_BULK_INSERT", + "TSE_FUNC_TYPE_ANALYZE", + "TSE_FUNC_TYPE_GET_MAX_SESSIONS", + "TSE_FUNC_LOCK_INSTANCE", + "TSE_FUNC_UNLOCK_INSTANCE", + "TSE_FUNC_CHECK_TABLE_EXIST", + "TSE_FUNC_SEARCH_METADATA_SWITCH", + "TSE_FUNC_PRE_CREATE_DB", + "TSE_FUNC_TYPE_DROP_TABLESPACE_AND_USER", + "TSE_FUNC_DROP_DB_PRE_CHECK", + "TSE_FUNC_KILL_CONNECTION", + "TSE_FUNC_TYPE_INVALIDATE_OBJECT", + "TSE_FUNC_TYPE_RECORD_SQL", + "TSE_FUNC_TYPE_REGISTER_INSTANCE", + "TSE_FUNC_TYPE_WAIT_CONNETOR_STARTUPED", + "TSE_FUNC_TYPE_MYSQL_EXECUTE_UPDATE", + "TSE_FUNC_TYPE_CLOSE_MYSQL_CONNECTION", + "TSE_FUNC_TYPE_LOCK_TABLES", + "TSE_FUNC_TYPE_UNLOCK_TABLES", + "TSE_FUNC_TYPE_EXECUTE_REWRITE_OPEN_CONN", + "TSE_FUNC_TYPE_INVALIDATE_OBJECTS", +}; + +ctc_stats& ctc_stats::get_instance() noexcept { + static ctc_stats m_ctc_stats; + return m_ctc_stats; +} + +bool ctc_stats::get_stats_enabled() { + return m_stats_enabled; +} + +void ctc_stats::set_stats_enabled(const bool val) { + if (val && !m_stats_enabled) { + for (int i = 0; i < TSE_FUNC_TYPE_NUMBER; i++) { + m_calls[i] = 0; + m_use_time[i] = 0; + } + } + + m_stats_enabled = val; +} + +void ctc_stats::gather_stats(const enum TSE_FUNC_TYPE& type, const uint64_t use_time) { + m_calls[type]++; + m_use_time[type] += use_time; +} + +void ctc_stats::print_stats(THD *thd, stat_print_fn *stat_print) { + char *ctc_srv_monitor; + std::string ctc_srv_monitor_str; + if ((sizeof(ctc_interface_strs) / sizeof(ctc_interface_strs[0])) != TSE_FUNC_TYPE_NUMBER) { + ctc_srv_monitor_str = "[CTC_STATS]: ctc_interface_strs number must be same as total ctc interfaces."; + ctc_srv_monitor = &ctc_srv_monitor_str[0]; + stat_print(thd, "ctc", + static_cast(strlen("ctc")), + STRING_WITH_LEN(""), ctc_srv_monitor, (uint)ctc_srv_monitor_str.length()); + return; + } + + ctc_srv_monitor_str = "\n======================================CTC_STATS=====================================\n"; + ctc_srv_monitor_str += "Interface: Call counter Used Time Average Time\n"; + for (int i = 0; i < TSE_FUNC_TYPE_NUMBER; i++) { + uint64_t calls = m_calls[i]; + uint64_t use_time = m_use_time[i]; + if (calls == 0) { + continue; + } + + double average_time = (double) use_time / calls; + ctc_srv_monitor_str += ctc_interface_strs[i]; + ctc_srv_monitor_str += ": " + std::to_string(calls) + " " + std::to_string(use_time) + " "+ std::to_string(average_time)+"\n"; + } + + ctc_srv_monitor_str += "\n======================================CTC_STATS=====================================\n"; + ctc_srv_monitor = &ctc_srv_monitor_str[0]; + stat_print(thd, "ctc", + static_cast(strlen("ctc")), + STRING_WITH_LEN(""), ctc_srv_monitor, (uint)ctc_srv_monitor_str.length()); +} diff --git a/storage/tianchi/tse_stats.h b/storage/tianchi/tse_stats.h new file mode 100644 index 0000000..1566c42 --- /dev/null +++ b/storage/tianchi/tse_stats.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __CTC_STATS_H__ +#define __CTC_STATS_H__ + +#include +#include +#include "../../sql/handler.h" +#include "../../sql/sql_class.h" +#include "../../sql/sql_profile.h" +#include "my_config.h" +#include "tse_srv.h" + +class ctc_stats { + private: + ctc_stats(void) = default; + ~ctc_stats() = default; + + ctc_stats(const ctc_stats&) = delete; + ctc_stats& operator=(const ctc_stats&) = delete; + + public: + static ctc_stats& get_instance(void) noexcept; + bool get_stats_enabled(void); + void set_stats_enabled(const bool val); + void gather_stats(const enum TSE_FUNC_TYPE& type, const uint64_t use_time); + void print_stats(THD *thd, stat_print_fn *stat_print); + + private: + bool m_stats_enabled = false; + + std::atomic_uint64_t m_calls[TSE_FUNC_TYPE_NUMBER]; + std::atomic_uint64_t m_use_time[TSE_FUNC_TYPE_NUMBER]; +}; + +#endif diff --git a/storage/tianchi/tse_util.cc b/storage/tianchi/tse_util.cc new file mode 100644 index 0000000..2c1eb38 --- /dev/null +++ b/storage/tianchi/tse_util.cc @@ -0,0 +1,710 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "tse_srv.h" +#include "tse_util.h" +#include "tse_log.h" +#include "tse_proxy_util.h" + +#include "sql/sql_class.h" +#include "sql/tztime.h" +#include "m_ctype.h" +#include "my_sys.h" +#include "sql/mysqld.h" +#include "sql/strfunc.h" +#include "ha_tse.h" +#include "tse_error.h" +#include "decimal_convert.h" +#include "sql_string.h" +#include "ha_tse_ddl.h" + +using namespace std; +extern bool tse_enable_x_lock_instance; + +string cnvrt_name_for_sql(string name) { + string res = ""; + for (size_t i = 0; i < name.length(); i++) { + switch (name[i]) { + case '`': + res += '`'; + default: + res += name[i]; + } +} + return res; +} + +void tse_print_cantian_err_msg(const ddl_ctrl_t *ddl_ctrl, ct_errno_t ret) +{ + switch (ret) { + case ERR_DUPLICATE_ENTRY: + my_printf_error(ER_DUP_ENTRY, "%s", MYF(0), ddl_ctrl->error_msg); + break; + case ERR_COL_TYPE_MISMATCH: + my_printf_error(ER_FK_INCOMPATIBLE_COLUMNS, "%s", MYF(0), ddl_ctrl->error_msg); + break; + default: + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), ddl_ctrl->error_msg); + break; + } +} + +static uint32_t tse_convert_identifier_to_sysname(char *to, const char *from, size_t to_len) { + uint32_t errors_ignored; + CHARSET_INFO *cs_from = &my_charset_filename; + CHARSET_INFO *cs_to = system_charset_info; + + return (static_cast( + strconvert(cs_from, from, cs_to, to, to_len, &errors_ignored))); +} + +void tse_split_normalized_name(const char *file_name, char db[], size_t db_buf_len, + char name[], size_t name_buf_len, bool *is_tmp_table) { + size_t dir_length, prefix_length; + string path(file_name); + const char *buf = path.c_str(); + + dir_length = dirname_length(buf); + + if (name != nullptr && is_tmp_table != nullptr && (*is_tmp_table)) { + /* Get table */ + string table_name = path.substr(dir_length); + if (table_name.find("#sql") == table_name.npos) { + *is_tmp_table = false; + } else { + assert(table_name.length() <= name_buf_len); + table_name.copy(name, table_name.length()); + name[table_name.length() + 1] = '\0'; + name[name_buf_len - 1] = '\0'; + } + } + + assert(db != nullptr); + if (is_tmp_table != nullptr && (*is_tmp_table)) { + (void)strncpy(db, TMP_DIR, db_buf_len); + db[db_buf_len - 1] = '\0'; + } else if (dir_length > 1) { + /* Get database */ + path.replace(path.begin() + dir_length - 1, path.begin() + dir_length, 1, 0); // Remove end '/' + prefix_length = dirname_length(buf); + (void)tse_convert_identifier_to_sysname(db, buf + prefix_length, db_buf_len - 1); + db[db_buf_len - 1] = '\0'; + } +} + + +void tse_copy_name(char to_name[], const char from_name[], size_t to_buf_len) { + if (to_name != from_name) { + (void)strncpy(to_name, from_name, to_buf_len - 1); + to_name[to_buf_len - 1] = '\0'; + } +} + +bool tse_check_ddl_sql_length(const string &query_str) { + if (query_str.length() > MAX_DDL_SQL_LEN_CONTEXT) { + string err_msg = + "`" + query_str.substr(0, 100) + "...` Is Large Than " + to_string(MAX_DDL_SQL_LEN_CONTEXT); + my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), err_msg.c_str()); + return true; + } + return false; +} + +string sql_without_plaintext_password(tse_ddl_broadcast_request* broadcast_req) { + if (broadcast_req->options & TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD) { + return "(contains plaintext password), sql_command = " + to_string(broadcast_req->sql_command); + } + return (string)broadcast_req->sql_str; +} + +int16_t tse_get_column_by_field(Field **field, const char *col_name) { + int16_t col_id; + for (col_id = 0; *field != nullptr; field++, col_id++) { + if (my_strcasecmp(system_charset_info, (*field)->field_name, col_name) == 0) { + return col_id; + } + } + return INVALID_MAX_COLUMN; +} + +int tse_set_cond_field_size(const field_cnvrt_aux_t *mysql_info, tse_conds *cond) { + switch (mysql_info->cantian_map_type) { + case CANTIAN_COL_BITS_4: + cond->field_info.field_size = 4; + break; + case CANTIAN_COL_BITS_8: + cond->field_info.field_size = 8; + break; + case CANTIAN_COL_BITS_VAR:{ + if (mysql_info->sql_data_type == STRING_DATA || mysql_info->sql_data_type == NUMERIC_DATA) { + return CT_SUCCESS; + } + break; + } + default: + tse_log_error("tse_set_cond_field_size: unknow col bits: %d", mysql_info->cantian_map_type); + return CT_ERROR; + } + return CT_SUCCESS; +} + +int tse_fill_cond_field_data_num(tianchi_handler_t m_tch, Item *items, Field *mysql_field, + const field_cnvrt_aux_t *mysql_info, tse_conds *cond) { + int ret = CT_SUCCESS; + void *data = nullptr; + bool is_alloc_data = CT_FALSE; + switch (mysql_info->ddl_field_type) { + case TSE_DDL_TYPE_LONG: + case TSE_DDL_TYPE_LONGLONG: { + if ((((Item_func *)items)->arguments()[1])->type() == Item::CACHE_ITEM) { + longlong val = ((Item_cache_int *)(((Item_func *)items)->arguments()[1]))->val_int(); + data = (uchar *)malloc(sizeof(longlong)); + is_alloc_data = CT_TRUE; + memcpy(data, &val, sizeof(longlong)); + } else { + data = &((Item_int *)(((Item_func_eq *)items)->arguments()[1]))->value; + } + break; + } + case TSE_DDL_TYPE_DOUBLE: + data = &((Item_float *)(((Item_func_eq *)items)->arguments()[1]))->value; + break; + case TSE_DDL_TYPE_NEWDECIMAL: { + const int scale = mysql_field->decimals(); + const int prec = ((Field_new_decimal *)mysql_field)->precision; + int binary_size = my_decimal_get_binary_size(prec, scale); + uchar *buff = new uchar[binary_size]; + my_decimal *d = ((Item_decimal *)(((Item_func_eq *)items)->arguments()[1]))->val_decimal(nullptr); + my_decimal2binary(E_DEC_FATAL_ERROR, d, buff, prec, scale); + data = (uchar *)malloc(binary_size); + is_alloc_data = CT_TRUE; + memcpy(data, buff, binary_size); + delete[] buff; + break; + } + default: + tse_log_error("[tse_copy_cond_field_data]unsupport sql_data_type %d", mysql_info->sql_data_type); + assert(0); + return CT_ERROR; + } + uchar cantian_ptr[DECIMAL_MAX_STR_LENGTH + 1]; + ret = convert_numeric_to_cantian(mysql_info, (const uchar *)data, cantian_ptr, mysql_field, + (uint32_t *)(&cond->field_info.field_size)); + cond->field_info.field_value = tse_alloc_buf(&m_tch, cond->field_info.field_size); + if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { + tse_log_error("tse_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); + return CT_ERROR; + } + + memcpy(cond->field_info.field_value, cantian_ptr, cond->field_info.field_size); + if (is_alloc_data) { + free(data); + is_alloc_data = CT_FALSE; + } + return ret; +} + +int tse_fill_cond_field_data_date(tianchi_handler_t m_tch, const field_cnvrt_aux_t *mysql_info, + MYSQL_TIME ltime, date_detail_t *date_detail, tse_conds *cond) { + int ret = CT_SUCCESS; + + cond->field_info.field_value = tse_alloc_buf(&m_tch, cond->field_info.field_size); + if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { + tse_log_error("tse_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); + return CT_ERROR; + } + + uchar my_ptr[8] = {0}; + longlong ll; + switch (mysql_info->mysql_field_type) { + case MYSQL_TYPE_TIME: + ll = TIME_to_longlong_time_packed(ltime); + my_time_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); + memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); + return ret; + + case MYSQL_TYPE_DATETIME: + ll = TIME_to_longlong_datetime_packed(ltime); + my_datetime_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); + memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); + return ret; + + case MYSQL_TYPE_DATE: + my_date_to_binary(<ime, my_ptr); + memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); + return ret; + + case MYSQL_TYPE_TIMESTAMP: { + if (!check_zero_time_ltime(ltime)) { + struct timeval tm = {0, 0}; + THD *thd = current_thd; + int warnings = 0; + tse_datetime_with_no_zero_in_date_to_timeval(<ime, *thd->time_zone(), &tm, &warnings); + assert((warnings == EOK) || (warnings == MYSQL_TIME_WARN_TRUNCATED)); + my_tz_UTC->gmt_sec_to_TIME(<ime, tm); + } + /* fall through */ + } + + default: + ret = assign_mysql_date_detail(mysql_info->mysql_field_type, ltime, date_detail); + if (ret != CT_SUCCESS) { + return ret; + } + cm_encode_date(date_detail, (date_t *)cond->field_info.field_value); + return ret; + } + +} + +void update_value_by_charset(char *data, uint16 *size, uint16 bytes) { + if (bytes == 0) { + return; + } + uint16 cur = 0; + for (int i = 0; i < *size; i++) { + if (data[i] == '_' || data[i] == '%') { + cur -= bytes; + } + data[cur++] = data[i]; + } + *size = cur; +} + +int tse_get_column_cs(const CHARSET_INFO *cs) { + auto it = mysql_collate_num_to_tse_type.find(cs->number); + if (it != mysql_collate_num_to_tse_type.end()) { + return (int32_t)it->second; + } + return cs->number; +} + +int tse_fill_cond_field_data_string(tianchi_handler_t m_tch, Item_func *item_func, + tse_conds *cond, bool no_backslash) { + if ((item_func->arguments()[1])->type() == Item::NULL_ITEM) { + cond->field_info.null_value = true; + return CT_SUCCESS; + } + Item_field *item_field = (Item_field *)((item_func)->arguments()[0]); + uint cslen = item_field->collation.collation->mbminlen; + cond->field_info.collate_id = tse_get_column_cs(item_field->collation.collation); + if (no_backslash) { + cond->field_info.no_backslash = true; + } + String *item_string = ((Item_string *)(item_func->arguments()[1]))->val_str(nullptr); + cond->field_info.field_size = item_string->length(); + void *data = item_string->ptr(); + cond->field_info.field_value = tse_alloc_buf(&m_tch, cond->field_info.field_size); + if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { + tse_log_error("tse_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); + return CT_ERROR; + } + memset(cond->field_info.field_value, 0, cond->field_info.field_size); + memcpy(cond->field_info.field_value, data, cond->field_info.field_size); + if(cond->func_type == TSE_LIKE_FUNC) { + update_value_by_charset((char *)cond->field_info.field_value, &cond->field_info.field_size, cslen - 1); + } + return CT_SUCCESS; +} + +int tse_fill_cond_field_data(tianchi_handler_t m_tch, Item *items, Field *mysql_field, + const field_cnvrt_aux_t *mysql_info, tse_conds *cond) { + int ret = CT_SUCCESS; + Item_func *item_func = (Item_func *)items; + if ((item_func->arguments()[1])->type() == Item::CACHE_ITEM) { + cond->field_info.null_value = !((Item_cache *)((item_func)->arguments()[1]))->has_value(); + } else { + cond->field_info.null_value = ((Item_func_eq *)items)->arguments()[1]->null_value; + } + if (cond->field_info.null_value) { + return CT_SUCCESS; + } + + switch (mysql_info->sql_data_type) { + case NUMERIC_DATA: + ret = tse_fill_cond_field_data_num(m_tch, items, mysql_field, mysql_info, cond); + break; + case DATETIME_DATA:{ + MYSQL_TIME ltime; + date_detail_t date_detail; + memset(&date_detail, 0, sizeof(date_detail_t)); + if (mysql_info->mysql_field_type == MYSQL_TYPE_YEAR) { + ltime.year = ((Item_int *)(((Item_func_eq *)items)->arguments()[1]))->value; + ltime.month = 1; + ltime.day = 1; + ltime.hour = 0; + ltime.minute = 0; + ltime.second = 0; + ltime.second_part = 0; + ltime.neg = false; + } else if (((Item_date_literal *)(((Item_func_eq *)items)->arguments()[1]))->get_date(<ime, TIME_FUZZY_DATE)) { + return CT_ERROR; + } + ret = tse_fill_cond_field_data_date(m_tch, mysql_info, ltime, &date_detail, cond); + break; + } + case STRING_DATA:{ + ret = tse_fill_cond_field_data_string(m_tch, item_func, cond, false); + break; + } + case LOB_DATA: + case UNKNOW_DATA: + default: + tse_log_error("[mysql2cantian]unsupport sql_data_type %d", mysql_info->sql_data_type); + return CT_ERROR; + } + return ret; +} + +int tse_fill_cond_field(tianchi_handler_t m_tch, Item *items, Field **field, tse_conds *cond, bool no_backslash) { + Item_func *item_func = (Item_func *)items; + const char *field_name = item_func->arguments()[0]->item_name.ptr(); + cond->field_info.field_no = tse_get_column_by_field(field, field_name); + if (cond->field_info.field_no == INVALID_MAX_COLUMN) { + return CT_ERROR; + } + Field *mysql_field = *(field + cond->field_info.field_no); + enum_field_types type = mysql_field->type(); + type = (type == MYSQL_TYPE_FLOAT) ? MYSQL_TYPE_DOUBLE : type; + const field_cnvrt_aux_t *mysql_info = get_auxiliary_for_field_convert(mysql_field, type); + cond->field_info.field_type = mysql_info->ddl_field_type; + // update field_no if there are gcol in tables + uint16_t gcol_cnt = 0; + for (uint16_t col_id = 0; col_id < cond->field_info.field_no; col_id++) { + Field *pre_field = *(field + col_id); + if (pre_field->is_gcol()) { + gcol_cnt++; + } + } + cond->field_info.field_no -= gcol_cnt; + if (cond->func_type == TSE_ISNULL_FUNC || cond->func_type == TSE_ISNOTNULL_FUNC) { + return CT_SUCCESS; + } else if(cond->func_type == TSE_LIKE_FUNC) { + return tse_fill_cond_field_data_string(m_tch, item_func, cond, no_backslash); + } + + if (tse_set_cond_field_size(mysql_info, cond) != CT_SUCCESS) { + return CT_ERROR; + } + + return tse_fill_cond_field_data(m_tch, items, mysql_field, mysql_info, cond); +} + +int tse_push_cond_list(tianchi_handler_t m_tch, Item *items, Field **field, + tse_cond_list *list, bool no_backslash) { + Item_cond *item_cond = (Item_cond *)items; + List *argument_list = item_cond->argument_list(); + uint16_t size = argument_list->size(); + list_node *node = argument_list->first_node(); + + for (uint16_t i = 0; i < size; i++) { + tse_conds *cond = (tse_conds *)tse_alloc_buf(&m_tch, sizeof(tse_conds)); + if (cond == nullptr) { + tse_log_error("tse_push_cond_list: alloc tse_conds error, size(%lu).", sizeof(tse_conds)); + return CT_ERROR; + } + memset(cond, 0, sizeof(tse_conds)); + if (dfs_fill_conds(m_tch, (Item *)(node->info), field, cond, no_backslash) != CT_SUCCESS) { + return CT_ERROR; + } + if (list->elements == 0) { + list->first = cond; + } else { + list->last->next = cond; + } + list->last = cond; + (list->elements)++; + node = node->next; + } + + return CT_SUCCESS; +} + +int tse_push_cond_args(tianchi_handler_t m_tch, Item *items, Field **field, + tse_cond_list *list, bool no_backslash) { + Item_func *item_func = (Item_func *)items; + Item **args = item_func->arguments(); + uint16_t size = item_func->argument_count(); + + for (uint16_t i = 0; i < size; i++) { + tse_conds *cond = (tse_conds *)tse_alloc_buf(&m_tch, sizeof(tse_conds)); + if (cond == nullptr) { + tse_log_error("tse_push_cond_args: alloc tse_conds error, size(%lu).", sizeof(tse_conds)); + return CT_ERROR; + } + memset(cond, 0, sizeof(tse_conds)); + dfs_fill_conds(m_tch, args[i], field, cond, no_backslash); + if (list->elements == 0) { + list->first = cond; + } else { + list->last->next = cond; + } + list->last = cond; + (list->elements)++; + } + + return CT_SUCCESS; +} + +tse_func_type_t item_func_to_tse_func(Item_func::Functype fc) { + switch (fc) { + case (Item_func::Functype::EQUAL_FUNC): + return TSE_EQUAL_FUNC; + case (Item_func::Functype::EQ_FUNC): + return TSE_EQ_FUNC; + case (Item_func::Functype::NE_FUNC): + return TSE_NE_FUNC; + case (Item_func::Functype::LT_FUNC): + return TSE_LT_FUNC; + case (Item_func::Functype::LE_FUNC): + return TSE_LE_FUNC; + case (Item_func::Functype::GT_FUNC): + return TSE_GT_FUNC; + case (Item_func::Functype::GE_FUNC): + return TSE_GE_FUNC; + case (Item_func::Functype::ISNULL_FUNC): + return TSE_ISNULL_FUNC; + case (Item_func::Functype::ISNOTNULL_FUNC): + return TSE_ISNOTNULL_FUNC; + case (Item_func::Functype::LIKE_FUNC): + return TSE_LIKE_FUNC; + case (Item_func::Functype::NOT_FUNC): + return TSE_NOT_FUNC; + case (Item_func::Functype::COND_AND_FUNC): + return TSE_COND_AND_FUNC; + case (Item_func::Functype::COND_OR_FUNC): + return TSE_COND_OR_FUNC; + case (Item_func::Functype::XOR_FUNC): + return TSE_XOR_FUNC; + default: + return TSE_UNKNOWN_FUNC; + } +} + +int dfs_fill_conds(tianchi_handler_t m_tch, Item *items, Field **field, tse_conds *conds, bool no_backslash) { + Item_func *item_func = (Item_func *)items; + Item_func::Functype fc = item_func->functype(); + conds->func_type = item_func_to_tse_func(fc); + int ret = CT_SUCCESS; + tse_cond_list *list; + + switch (conds->func_type) { + case TSE_COND_AND_FUNC: + case TSE_COND_OR_FUNC: + list = (tse_cond_list *)tse_alloc_buf(&m_tch, sizeof(tse_cond_list)); + if (list == nullptr) { + tse_log_error("tse_fill_conds: alloc tse_cond_list error, size(%lu).", sizeof(tse_cond_list)); + return CT_ERROR; + } + memset(list, 0, sizeof(tse_cond_list)); + ret = tse_push_cond_list(m_tch, items, field, list, no_backslash); + if (ret == CT_SUCCESS) { + conds->cond_list = list; + } + break; + case TSE_NOT_FUNC: + case TSE_XOR_FUNC: + list = (tse_cond_list *)tse_alloc_buf(&m_tch, sizeof(tse_cond_list)); + if (list == nullptr) { + tse_log_error("tse_fill_conds: alloc tse_cond_list error, size(%lu).", sizeof(tse_cond_list)); + return CT_ERROR; + } + memset(list, 0, sizeof(tse_cond_list)); + ret = tse_push_cond_args(m_tch, items, field, list, no_backslash); + if (ret == CT_SUCCESS) { + conds->cond_list = list; + } + break; + case TSE_EQ_FUNC: + case TSE_EQUAL_FUNC: + case TSE_NE_FUNC: + case TSE_LT_FUNC: + case TSE_LE_FUNC: + case TSE_GE_FUNC: + case TSE_GT_FUNC: + case TSE_ISNULL_FUNC: + case TSE_ISNOTNULL_FUNC: + case TSE_LIKE_FUNC: + ret = tse_fill_cond_field(m_tch, item_func, field, conds, no_backslash); + break; + case TSE_UNKNOWN_FUNC: + default: + return CT_ERROR; + } + return ret; +} + +void cm_assert(bool condition) +{ + if (!condition) { + *((uint32 *)NULL) = 1; + } +} + +/* + reference mysql function 'get_text' to implement deserilize get_text +@note: + 1.遇到反斜杠 + 后一个字符是_,%,该字符与'\\'一起保持原样 => '\\' + '_' | '\\' + '%' + 后一个字符是其他字符,转义反斜杠本身 => '\\' + '\\' + 2.遇到Mysql认为的特殊字符 + 拆成两个字符, '\\' + x + 3.普通字符 + 追加即可 +*/ +string tse_deserilize_get_text(string &name) { + THD *thd = current_thd; + string res(""); + int len = name.size(); + if (!(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)) { + res = name; + return res; + } + for (int i = 0; i < len; i++) { + if (name[i] == '\\' && i < len - 1) { + switch (name[++i]) { + case '_': + case '%': + res += '\\'; + res += name[i]; + break; + default: + res += '\\'; + res += '\\'; + --i; + break; + } + } else { + // 识别单个特殊字符(转移字符) => 两个字符:\\ + 本身 + switch (name[i]) { + case '\n': + res += '\\'; + res += 'n'; + break; + case '\t': + res += '\\'; + res += 't'; + break; + case '\r': + res += '\\'; + res += 'r'; + break; + case '\b': + res += '\\'; + res += 'b'; + break; + case '\032': + res += '\\'; + res += 'Z'; + break; + default: + res += name[i]; + break; + } + } + } + return res; +} + +string tse_escape_single_quotation_str(string &src) { + string res = ""; + for (size_t i = 0; i < src.length(); i++) { + switch (src[i]) { + case '\'': + res += '\\'; + default: + res += src[i]; + } + } + return res; +} + +string tse_deserilize_username_with_single_quotation(string &src) { + string deserilize = tse_deserilize_get_text(src); + return tse_escape_single_quotation_str(deserilize); +} + +/** + Check for global name lock counts to determine if ddl is processing. + @return + - true: there is ddl in progress + - false: no ddl is in progress +*/ +static bool tse_is_ddl_processing() { + uint32_t name_locks = get_g_name_locks(); + if (name_locks > 0) { + tse_log_system("[TSE_LOCK_INSTANCE]: contains %u global name locks, there is DDL in progress.", name_locks); + return true; + } + return false; +} + +int tse_check_lock_instance(MYSQL_THD thd, bool &need_forward) { + if (thd->mdl_context.has_locks(MDL_key::BACKUP_LOCK)) { + need_forward = false; + return 0; + } + + if (tse_is_ddl_processing()) { + my_printf_error(ER_DISALLOWED_OPERATION, "Please try lock instance for backup later, DDL is in processing.", MYF(0)); + return -1; + } + + if (acquire_exclusive_backup_lock(thd, 0, false)) { + my_printf_error(ER_DISALLOWED_OPERATION, "Please try lock instance for backup later, DDL is in processing.", MYF(0)); + tse_log_error("[TSE_LOCK_INSTANCE]: Not allowed to lock instance, DDL is in processing"); + return -1; + } + + tse_lock_table_mode_t lock_mode; + bool is_mysqld_starting = is_starting(); + if (tse_enable_x_lock_instance || is_mysqld_starting) { + lock_mode = TSE_LOCK_MODE_EXCLUSIVE; + } else { + lock_mode = TSE_LOCK_MODE_SHARE; + } + + tianchi_handler_t tch; + handlerton *tse_hton = get_tse_hton(); + if (get_tch_in_handler_data(tse_hton, thd, tch)) { + tse_log_error("[TSE_LOCK_INSTANCE]: failed to get tch"); + release_backup_lock(thd); + return -1; + } + + int ret = tse_lock_instance(&is_mysqld_starting, lock_mode, &tch); + update_sess_ctx_by_tch(tch, tse_hton, thd); + assert(ret == 0); + + tse_log_system("[TSE_LOCK_INSTANCE]: SUCCESS. tse_inst:%u, conn_id:%u, lock_mode:%s", + tch.inst_id, tch.thd_id, lock_mode == TSE_LOCK_MODE_EXCLUSIVE ? "X_LATCH" : "S_LATCH"); + return ret; +} + +int tse_check_unlock_instance(MYSQL_THD thd) { + if (!thd->mdl_context.has_locks(MDL_key::BACKUP_LOCK)) { + return 0; + } + + tianchi_handler_t tch; + TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(get_tse_hton(), thd, tch)); + + bool is_mysqld_starting = is_starting(); + tse_unlock_instance(&is_mysqld_starting, &tch); + tse_log_system("[TSE_UNLOCK_INSTANCE]: SUCCESS. tse_inst:%u, conn_id:%u", tch.inst_id, tch.thd_id); + return 0; +} \ No newline at end of file diff --git a/storage/tianchi/tse_util.h b/storage/tianchi/tse_util.h new file mode 100644 index 0000000..3cad7f2 --- /dev/null +++ b/storage/tianchi/tse_util.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __TSE_UTIL_H__ +#define __TSE_UTIL_H__ + +#include +#include +#include +#include +#include "sql/table.h" +#include "datatype_cnvrtr.h" +#include "sql/item_timefunc.h" +#include "sql/my_decimal.h" +#include "sql/sql_backup_lock.h" + +using namespace std; + +static unordered_set mysql_system_db{"information_schema", "mysql", "performance_schema", "sys"}; + +#define CM_IS_EMPTY_STR(str) (((str) == NULL) || ((str)[0] == 0)) + +#define TSE_GET_THD_DB_NAME(thd) (thd->db().str == NULL) ? nullptr : const_cast(thd->db().str) + +void tse_split_normalized_name(const char *file_name, char db[], size_t db_buf_len, + char name[], size_t name_buf_len, bool *is_tmp_table); +void tse_copy_name(char to_name[], const char from_name[], size_t to_buf_len); +bool tse_check_ddl_sql_length(const string &query_str); + +string format_remote_errmsg(const char *err_msg); +// utils for cond pushdown +int dfs_fill_conds(tianchi_handler_t m_tch, Item *items, Field **field, tse_conds *conds, bool no_backslash); +int tse_push_cond_list(tianchi_handler_t m_tch, Item *items, Field **field, tse_cond_list *list, bool no_backslash); +int tse_push_cond_args(tianchi_handler_t m_tch, Item *items, Field **field, tse_cond_list *list, bool no_backslash); +int tse_fill_cond_field(Item *items, Field **field, tse_conds *cond, bool no_backslash); +int tse_set_cond_field_size(const field_cnvrt_aux_t *mysql_info, tse_conds *cond); +int tse_fill_cond_field_data(tianchi_handler_t m_tch, Item *items, Field *mysql_field, + const field_cnvrt_aux_t *mysql_info, tse_conds *cond); +int tse_fill_cond_field_data_num(tianchi_handler_t m_tch, Item *items, Field *mysql_field, + const field_cnvrt_aux_t *mysql_info, tse_conds *cond); +int tse_fill_cond_field_data_date(tianchi_handler_t m_tch, const field_cnvrt_aux_t *mysql_info, + MYSQL_TIME ltime, date_detail_t *date_detail, tse_conds *cond); +int tse_fill_cond_field_data_string(tianchi_handler_t m_tch, Item_func *item_func, tse_conds *cond, bool no_backslash); +void update_value_by_charset(char *data, uint16 *size, uint16 bytes); +tse_func_type_t item_func_to_tse_func(Item_func::Functype fc); +int16_t tse_get_column_by_field(Field **field, const char *col_name); +int tse_get_column_cs(const CHARSET_INFO *cs); + +void cm_assert(bool condition); +string tse_deserilize_username_with_single_quotation(string &src); +void tse_print_cantian_err_msg(const ddl_ctrl_t *ddl_ctrl, ct_errno_t ret); +int tse_check_lock_instance(MYSQL_THD thd, bool &need_forward); +int tse_check_unlock_instance(MYSQL_THD thd); +int ctc_record_sql(MYSQL_THD thd, bool need_select_db); + +#pragma GCC visibility push(default) + +/* exposing API for tse_proxy */ +string sql_without_plaintext_password(tse_ddl_broadcast_request* broadcast_req); +string tse_escape_single_quotation_str(string &src); +string cnvrt_name_for_sql(string name); + +#pragma GCC visibility pop + +#endif // __TSE_UTIL_H__ -- Gitee From 1b8942cf0faa1f9d77ae4fcfcdcc7914f272bdad Mon Sep 17 00:00:00 2001 From: solid-yang Date: Thu, 25 Jan 2024 16:25:33 +0800 Subject: [PATCH 2/2] fix kill session --- storage/tianchi/ha_tse.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/storage/tianchi/ha_tse.cc b/storage/tianchi/ha_tse.cc index c0b5332..52b1cab 100644 --- a/storage/tianchi/ha_tse.cc +++ b/storage/tianchi/ha_tse.cc @@ -1715,7 +1715,14 @@ static int tse_close_connect(handlerton *hton, THD *thd) { tch.is_broadcast = true; } - int ret = tse_close_session(&tch); + tianchi_handler_t local_tch; + memset(&local_tch, 0, sizeof(local_tch)); + local_tch.inst_id = tch.inst_id; + local_tch.sess_addr = tch.sess_addr; + local_tch.thd_id = tch.thd_id; + local_tch.is_broadcast = tch.is_broadcast; + + int ret = tse_close_session(&local_tch); release_sess_ctx(sess_ctx, hton, thd); return convert_tse_error_code_to_mysql((ct_errno_t)ret); } @@ -1734,7 +1741,13 @@ static void tse_kill_connection(handlerton *hton, THD *thd) { return; } - tse_kill_session(&tch); + tianchi_handler_t local_tch; + memset(&local_tch, 0, sizeof(local_tch)); + local_tch.inst_id = tch.inst_id; + local_tch.sess_addr = tch.sess_addr; + local_tch.thd_id = tch.thd_id; + + tse_kill_session(&local_tch); tse_log_system("[TSE_KILL_SESSION]:conn_id:%u, tse_instance_id:%u", tch.thd_id, tch.inst_id); } -- Gitee