2025-03-05 14:31:08

This commit is contained in:
Ho Sy Tan 2025-03-05 14:31:37 +07:00
commit 4a107fd10e
47719 changed files with 16557060 additions and 0 deletions

376
.clang-format Normal file
View file

@ -0,0 +1,376 @@
# Copyright (c) 2016, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# We currently use clang-format version 15.
#
# This is the output of
#
# $ clang-format-10 --style=google --dump-config
#
# for C++ files except for changes mentioned below.
#
# For JavaScript files the output is generated by:
#
# $ clang-format-10 --assume-filename=format.js \
# --style=google --dump-config
#
# We lock the style so that any newer version of clang-format will give
# the same result; as time goes, we may update this list, requiring
# newer versions of clang-format.
---
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
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^<ext/.*\.h>'
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
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
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
Standard: Latest
# 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
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^<ext/.*\.h>'
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
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
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never

75
.clang-tidy Normal file
View file

@ -0,0 +1,75 @@
# Copyright (c) 2022, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
Checks:
-*,
bugprone-*,
-bugprone-easily-swappable-parameters,
-bugprone-narrowing-conversions,
clang-analyzer-*,
-clang-diagnostic-unused-function,
cppcoreguidelines-*,
-cppcoreguidelines-avoid-c-arrays,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-pro-bounds-constant-array-index,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-non-private-member-variables-in-classes,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-narrowing-conversions,
google-*,
-google-readability-todo,
-google-readability-braces-around-statements,
-google-runtime-int,
-google-build-using-namespace,
misc-*,
-misc-const-correctness,
-misc-non-private-member-variables-in-classes,
modernize-use-nullptr,
llvm-*,
-llvm-header-guard,
-llvm-include-order,
performance-*,
readability-*,
-readability-braces-around-statements,
-readability-named-parameter,
-readability-redundant-member-init,
-readability-magic-numbers,
-clang-diagnostic-error,
CheckOptions:
- key: readability-magic-numbers.IgnoredIntegerValues
value: "1;2;3;4;8;9;10;15;32;127;128;240;255"
# Allow things like CHARSET_INFO cs;
- key: readability-identifier-length.MinimumParameterNameLength
value: 2
- key: readability-identifier-length.MinimumVariableNameLength
value: 2
- key: readability-function-cognitive-complexity.Threshold
value: 50
FormatStyle: "file"

33
.gitconfig Normal file
View file

@ -0,0 +1,33 @@
# Copyright (c) 2018, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# 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

2776
CMakeLists.txt Normal file

File diff suppressed because it is too large Load diff

18
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,18 @@
We welcome your code contributions. Before submitting code via a GitHub pull
request, or by filing a bug in https://bugs.mysql.com you will need to have
signed the Oracle Contributor Agreement, see https://oca.opensource.oracle.com
Only pull requests from committers that can be verified as having signed the OCA
can be accepted.
Submitting a contribution
-------------------------
1. Make sure you have a user account at https://bugs.mysql.com. You'll need to reference
this user account when you submit your OCA (Oracle Contributor Agreement).
2. Sign the Oracle OCA. You can find instructions for doing that at the OCA Page,
at https://oca.opensource.oracle.com
3. Validate your contribution by including tests that sufficiently cover the functionality.
4. Verify that the entire test suite passes with your code applied.
5. Submit your pull request via GitHub or uploading it using the contribution tab to a bug
record in https://bugs.mysql.com (using the 'contribution' tab).

104
Docs/README.build Normal file
View file

@ -0,0 +1,104 @@
Copyright (c) 2003, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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
Build Instructions for MySQL Server
===================================
The recommended way to build MySQL for developers:
cd <some build directory>
cmake <path to source directory>
make
This will give you a release (actually RelWithDebInfo) build,
with compiler options taken from
../cmake/build_configurations/compiler_options.cmake
Adding -DWITH_DEBUG=1 to the cmake command line gives you a debug build.
Building on Windows is slightly different:
cd <some build directory>
cmake <path to source directory> -G <generator>
We only support Visual Studio as generator and only 64 bit ("Win64").
cmake --build . --config Debug
or
cmake --build . --config RelWithDebInfo
You can pass options to msbuild, see
https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019
To speed up compilation, building multiple projects in parallel:
cmake --build . --config Debug -- -m
To have a completely silent build:
cmake --build . --config Debug -- -v:q
Or combined:
cmake --build . --config Debug -- -m -v:q
If you have special needs, you can disable the defaults by setting
this cmake variable off: WITH_DEFAULT_COMPILER_OPTIONS
Building MySQL from source requires SSL headers and libraries to be
available. The default value for the cmake variable WITH_SSL is "system".
This means that on UNIX systems, you should install the appropriate
OpenSSL developer package.
For Windows users, please see
https://wiki.openssl.org/index.php/Binaries
For Mac users, please see
http://brewformulas.org/Openssl
You may also build OpenSSL yourself, and do
cmake -DWITH_SSL=</path/to/custom/openssl>
in order to build MySQL.
===
It is possible to compile with Clang on Windows, which compiles faster
and also yields faster binaries, but this is experimental and not officially
supported. To compile, install the most recent version from
https://github.com/llvm/llvm-project/releases
(Clang/C2, which is Microsoft's own version of Clang, is not supported)
Ensure that you have ninja and cmake in your path.
Source the appropriate vcvarsall.bat file which comes with Visual Studio,
so that Visual Studio executables are in your PATH.
cmake -G Ninja -DFORCE_UNSUPPORTED_COMPILER=1
-DCMAKE_C_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe"
-DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe"
-DCMAKE_LINKER="C:/Program Files/LLVM/bin/lld-link.exe"
..
ninja
This configuration also supports ASAN (-DWITH_ASAN=1)
Note that leak sanitizer is *not* supported.
For running tests with --parallel, you may need to add --build-thread= (500 is
a reasonable value to try).

1121
Docs/sp-imp-spec.txt Normal file

File diff suppressed because it is too large Load diff

129
Doxyfile-ignored Normal file
View file

@ -0,0 +1,129 @@
# Copyright (c) 2015, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
#===========================================================================
# All non-empty non-comment lines are regex patterns using CMake regex
# syntax. Matching lines will be removed from the error log when writing
# tofix-all.log. See run_doxygen.cmake for details.
#===========================================================================
# MAINTAINER:
#
# For bugs in the MySQL source code
#
# File a bug for each doxygen failure seen during the build:
# - PRODUCT = MySQL Server (8478)
# - COMPONENT = SRDOXYGEN
# - make sure the title contains DOXYGEN
# and update this file with exceptions using the templates below
#
# For bugs in the doxygen tool
#
# Indicate which doxygen version is broken,
# Indicate which doxygen version is fixed, if any,
# Indicate the doxygen issue number, if known
#
#===========================================================================
#===========================================================================
# << template to remove an entire directory >>
# BUG#XXXXXXXX - TITLE
# DATE / BUG REPORT AUTHOR
# storage/innobase/*
#===========================================================================
#===========================================================================
# << template to remove some files >>
# BUG#XXXXXXXX - TITLE
# DATE / BUG REPORT AUTHOR
# include/m_ctype.h:[0-9]+: warning:
#===========================================================================
# BUG#31354781 - FIX DOXYGEN WARNINGS IN RPL CODE
# 07-DEC-2020 Erlend Dahl
sql/rpl_rli_pdb.h:[0-9]+: warning:
sql/rpl_trx_tracking.h:[0-9]+: warning:
sql/rpl_utility.h:[0-9]+: warning:
mysql/binlog/event/binlog_event.h:[0-9]+: warning:
mysql/binlog/event/codecs/binary.h:[0-9]+: warning:
mysql/binlog/event/trx_boundary_parser.h:[0-9]+: warning:
plugin/group_replication/src/applier.cc:[0-9]+: warning:
sql/log_event.h:[0-9]+: warning:
sql/rpl_replica.cc:[0-9]+: warning:
sql/rpl_trx_tracking.h:[0-9]+: warning:
sql/rpl_utility.h:[0-9]+: warning:
#
# BUG#32245629 - FIX DOXYGEN WARNINGS IN THE OPTIMIZER CODE
# 07-DEC-2020 Erlend Dahl
sql/join_optimizer/join_optimizer.cc:[0-9]+: warning:
sql/range_optimizer/range_optimizer.cc:[0-9]+: warning:
sql/protocol_callback.h:[0-9]+: warning:
sql/sql_lex.h:[0-9]+: warning:
sql/sql_optimizer.cc:[0-9]+: warning:
sql/sql_optimizer_internal.h:[0-9]+: warning:
sql/sql_prepare.cc:[0-9]+: warning:
sql/sql_table.cc:[0-9]+: warning:
sql-common/json_dom.h:[0-9]+: warning:
sql/handler.cc:[0-9]+: warning:
sql/handler.h:[0-9]+: warning:
sql/item_func.h:[0-9]+: warning:
sql/range_optimizer/index_range_scan_plan.cc:[0-9]+: warning:
sql/range_optimizer/index_skip_scan_plan.cc:[0-9]+: warning:
sql/range_optimizer/index_skip_scan_plan.h:[0-9]+: warning:
sql/range_optimizer/path_helpers.h:[0-9]+: warning:
sql/range_optimizer/range_analysis.cc:[0-9]+: warning:
#===========================================================================
# 08-DEC-2020 Marc Alff
# Doxygen bug in 1.8.18
# Doxygen is confused by anonymous namespaces,
# which creates a lot of "warning: no matching class member found for"
# and "warning: no uniquely matching class member found for"
#
# https://github.com/doxygen/doxygen/issues/8413
#
sql/join_optimizer/join_optimizer.cc:.*no matching class member found for
sql/rpl_info_dummy.cc:.*no uniquely matching class member found for
sql/rpl_info_table.cc:.*no uniquely matching class member found for
sql/rwlock_scoped_lock.cc:.*no uniquely matching class member found for
sql/sql_prepare.cc:.*no uniquely matching class member found for
sql/log_event.cc:.*no uniquely matching class member found for
sql/log_event.cc:.*no matching class member found for
#===========================================================================
#===========================================================================
# 09-DEC-2020 Marc Alff
# Doxygen multiline error messages.
#
# Doxygen can print errors in multiple lines:
# the first line contains the file path, line number, and error message
# subsequent lines contains additional information.
#
# Ignore rules are based on the first line only (with a path),
# so that subsequent lines are silenced here from tofix-regressions.log.
#
# To read a full error message, read tofix-all.log.
#
Possible candidates:
^[ ]+
#===========================================================================

2788
Doxyfile.in Normal file

File diff suppressed because it is too large Load diff

11
INSTALL Normal file
View file

@ -0,0 +1,11 @@
Pre-built binaries in different package formats can be found on
http://www.mysql.com/downloads
You can find information about how to install from a source distribution at
http://dev.mysql.com/doc/refman/8.0/en/source-installation.html
The MySQL 8.0 Reference Manual is available on
http://dev.mysql.com/doc/refman/8.0/en/

5331
LICENSE Normal file

File diff suppressed because it is too large Load diff

5
MYSQL_VERSION Normal file
View file

@ -0,0 +1,5 @@
MYSQL_VERSION_MAJOR=8
MYSQL_VERSION_MINOR=4
MYSQL_VERSION_PATCH=4
MYSQL_VERSION_EXTRA=
MYSQL_VERSION_MATURITY="LTS"

20
README Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
This is a release of MySQL, an SQL database server.
License information can be found in the LICENSE file.
In test packages where this file is renamed README-test, the license
file is renamed LICENSE-test.
This distribution may include materials developed by third parties.
For license and attribution notices for these materials,
please refer to the LICENSE file.
For further information on MySQL or additional documentation, visit
http://dev.mysql.com/doc/
For additional downloads and the source of MySQL, visit
http://dev.mysql.com/downloads/
MySQL is brought to you by the MySQL team at Oracle.

32
SECURITY.md Normal file
View file

@ -0,0 +1,32 @@
Reporting security vulnerabilities
==================================
Oracle values the independent security research community and believes that
responsible disclosure of security vulnerabilities helps us ensure the security
and privacy of all our users.
Please do NOT raise a GitHub Issue to report a security vulnerability. If you
believe you have found a security vulnerability, please submit a report to
secalert_us@oracle.com preferably with a proof of concept. Please review
some additional information on how to report security vulnerabilities to Oracle,
see https://www.oracle.com/corporate/security-practices/assurance/vulnerability/reporting.html
We encourage people who contact Oracle Security to use email encryption using
our encryption key, see https://www.oracle.com/security-alerts/encryptionkey.html
We ask that you do not use other channels or contact the project maintainers
directly.
Security updates, alerts and bulletins
--------------------------------------
Security updates will be released on a regular cadence. Many of our projects
will typically release security fixes in conjunction with the Oracle Critical Patch
Update program. Additional information, including past advisories, is available on our
security alerts page at https://www.oracle.com/security-alerts/
Security-related information
----------------------------
We will provide security related information such as a threat model, considerations
for secure use, or any known security issues in our documentation. Please note
that labs and sample code are intended to demonstrate a concept and may not be
sufficiently hardened for production use.

315
client/CMakeLists.txt Normal file
View file

@ -0,0 +1,315 @@
# Copyright (c) 2006, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
ADD_WSHADOW_WARNING()
# We are not interesting in profiling clients.
DISABLE_MISSING_PROFILE_WARNING()
## Subdirectory for mysql_migrate_keyring code.
ADD_SUBDIRECTORY(migrate_keyring)
MYSQL_ADD_EXECUTABLE(mysql
${CMAKE_SOURCE_DIR}/sql-common/net_ns.cc
completion_hash.cc
mysql.cc
pattern_matcher.cc
readline.cc
client_query_attributes.cc
multi_factor_passwordopt-vars.cc
multi_option.cc
${CMAKE_CURRENT_SOURCE_DIR}/common/user_registration.cc
${CMAKE_SOURCE_DIR}/sql-common/sql_string.cc
LINK_LIBRARIES mysqlclient ${EDITLINE_LIBRARY}
)
MYSQL_ADD_EXECUTABLE(mysqltest
mysqltest.cc
mysqltest/error_names.cc
mysqltest/expected_errors.cc
mysqltest/expected_warnings.cc
mysqltest/logfile.cc
mysqltest/regular_expressions.cc
mysqltest/secondary_engine.cc
mysqltest/utils.cc
client_query_attributes.cc
COMPONENT Test
DEPENDENCIES GenError GenClientError
ENABLE_EXPORTS
LINK_LIBRARIES mysqlclient
)
IF(MY_COMPILER_IS_GNU AND (WITH_LTO OR CMAKE_COMPILER_FLAG_WITH_LTO))
TARGET_LINK_OPTIONS(mysqltest PRIVATE -Wno-error=stringop-overflow)
ENDIF()
MYSQL_ADD_EXECUTABLE(mysqlcheck
check/mysqlcheck.cc
check/mysqlcheck_core.cc
multi_factor_passwordopt-vars.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysqldump
mysqldump.cc
multi_factor_passwordopt-vars.cc
multi_option.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysqlimport
mysqlimport.cc
multi_factor_passwordopt-vars.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysqlshow
mysqlshow.cc
multi_factor_passwordopt-vars.cc
LINK_LIBRARIES mysqlclient
)
OPTION(WITH_JSON_BINLOG_LIBRARY
"Build and install standalone json_binlog library" OFF)
IF(WITH_JSON_BINLOG_LIBRARY)
UNSET(INSTALL_JSON_BINLOG_LIBRARY)
INSTALL(FILES
../sql-common/json_binary.h
../sql-common/json_error_handler.h
DESTINATION ${INSTALL_INCLUDEDIR}/sql-common
COMPONENT Development
)
ELSE()
SET(INSTALL_JSON_BINLOG_LIBRARY SKIP_INSTALL)
ENDIF()
# Set library version to match server version.
IF(WIN32)
# Windows wants only major.minor, but our MINOR_VERSION is zero anyways:
SET(json_binlog_VERSION "${MAJOR_VERSION}.${PATCH_VERSION}")
ELSE()
SET(json_binlog_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")
ENDIF()
# This is a standalone library to de-serialize json data.
# The public interface is in ../sql/json_binary.h which provides functions
# for parsing binary data, and converting it to Value objects.
# There are also utility functions to convert Value objects to JSON strings.
# We add enough source files to make it a complete standalone library,
# which can be tested by our ordinary mtr tests for the 'mysqlbinlog' client.
# Some detailed interface tests are found as unit tests.
#
# Always build it, but do not *use* it for mysqlbinlog unless
# WITH_JSON_BINLOG_LIBRARY=ON
ADD_SHARED_LIBRARY(json_binlog
${CMAKE_SOURCE_DIR}/sql-common/json_binary.cc
${CMAKE_SOURCE_DIR}/sql-common/json_dom.cc
${CMAKE_SOURCE_DIR}/sql-common/json_path.cc
${CMAKE_SOURCE_DIR}/sql-common/json_syntax_check.cc
${CMAKE_SOURCE_DIR}/sql-common/sql_string.cc
COMPILE_DEFINITIONS DISABLE_PSI_MUTEX EXPORT_JSON_FUNCTIONS
DEPENDENCIES GenError
${INSTALL_JSON_BINLOG_LIBRARY}
LINK_LIBRARIES mysys extra::rapidjson ext::zlib decimal
LINUX_VERSION_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/json_binlog.ver"
VERSION "${json_binlog_VERSION}"
NO_UNDEFINED
)
ADD_CONVENIENCE_LIBRARY(json_client_library
${CMAKE_SOURCE_DIR}/sql-common/json_binary.cc
${CMAKE_SOURCE_DIR}/sql-common/json_dom.cc
${CMAKE_SOURCE_DIR}/sql-common/json_path.cc
${CMAKE_SOURCE_DIR}/sql-common/json_syntax_check.cc
${CMAKE_SOURCE_DIR}/sql-common/sql_string.cc
LINK_LIBRARIES ext::zlib
COMPILE_DEFINITIONS
DISABLE_PSI_MUTEX
$<TARGET_PROPERTY:extra::rapidjson,INTERFACE_COMPILE_DEFINITIONS>
SYSTEM_INCLUDE_DIRECTORIES
$<TARGET_PROPERTY:extra::rapidjson,INTERFACE_INCLUDE_DIRECTORIES>
DEPENDENCIES GenError
)
ADD_CONVENIENCE_LIBRARY(decimal
${CMAKE_SOURCE_DIR}/sql-common/my_decimal.cc
)
SET(JSON_BINLOG_LIBS_TO_MERGE
json_client_library
mysys
mytime
strings
decimal
)
MERGE_CONVENIENCE_LIBRARIES(json_binlog_static
${JSON_BINLOG_LIBS_TO_MERGE}
COMPONENT Development
${INSTALL_JSON_BINLOG_LIBRARY}
)
# This is a test executable which verifies that Json_wrapper::seek,
# Json_dom::seek and Json_dom::parse functions are visible and can be called.
MYSQL_ADD_EXECUTABLE(json_client_library_main
json_client_library_main.cc
INCLUDE_DIRECTORIES ../sql
LINK_LIBRARIES json_client_library strings mysys decimal
SKIP_INSTALL
)
# A test executable which does nothing, except verify that symbols are visible.
# To test standalone build:
# cmake -DINSTALL_MYSQLTESTDIR=0 -DWITH_JSON_BINLOG_LIBRARY=1
# make install DESTDIR=/tmp/foo
# g++ -I/tmp/foo/usr/local/mysql/include json_binlog_main.cc
# -L/tmp/foo/usr/local/mysql/lib -Wl,-R,/tmp/foo/usr/local/mysql/lib
# -ljson_binlog
MYSQL_ADD_EXECUTABLE(json_binlog_main
json_binlog_main.cc
INCLUDE_DIRECTORIES ../sql ../sql-common
LINK_LIBRARIES json_binlog
SKIP_INSTALL
)
# Same test executable, linked statically.
# To test standalone build:
# g++ -I/tmp/foo/usr/local/mysql/include json_binlog_main.cc
# -L/tmp/foo/usr/local/mysql/lib
# -ljson_binlog_static -lpthread
MYSQL_ADD_EXECUTABLE(json_binlog_main_static
json_binlog_main.cc
INCLUDE_DIRECTORIES ../sql ../sql-common
LINK_LIBRARIES json_binlog_static
SKIP_INSTALL
)
MY_CHECK_CXX_COMPILER_WARNING("-Wunused-but-set-variable" HAS_WARN_FLAG)
IF(HAS_WARN_FLAG)
TARGET_COMPILE_OPTIONS(json_binlog_main PRIVATE "${HAS_WARN_FLAG}")
TARGET_COMPILE_OPTIONS(json_binlog_main_static PRIVATE "${HAS_WARN_FLAG}")
ENDIF()
MY_CHECK_CXX_COMPILER_WARNING("-Wunused-variable" HAS_WARN_FLAG)
IF(HAS_WARN_FLAG)
TARGET_COMPILE_OPTIONS(json_binlog_main PRIVATE "${HAS_WARN_FLAG}")
TARGET_COMPILE_OPTIONS(json_binlog_main_static PRIVATE "${HAS_WARN_FLAG}")
ENDIF()
SET(MYSQLBINLOG_SOURCES
mysqlbinlog.cc
${CMAKE_SOURCE_DIR}/sql/log_event.cc
${CMAKE_SOURCE_DIR}/sql/rpl_utility.cc
${CMAKE_SOURCE_DIR}/sql/rpl_gtid_tsid_map.cc
${CMAKE_SOURCE_DIR}/sql/rpl_gtid_misc.cc
${CMAKE_SOURCE_DIR}/sql/rpl_gtid_set.cc
${CMAKE_SOURCE_DIR}/sql/rpl_gtid_specification.cc
${CMAKE_SOURCE_DIR}/sql/rpl_tblmap.cc
${CMAKE_SOURCE_DIR}/sql/basic_istream.cc
${CMAKE_SOURCE_DIR}/sql/binlog_istream.cc
${CMAKE_SOURCE_DIR}/sql/binlog_reader.cc
${CMAKE_SOURCE_DIR}/sql/stream_cipher.cc
${CMAKE_SOURCE_DIR}/sql/rpl_log_encryption.cc
)
# The client version of log_event.cc has false positives.
# Downgrade from error to warning:
IF(MY_COMPILER_IS_GNU AND CMAKE_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO")
ADD_COMPILE_FLAGS(${CMAKE_SOURCE_DIR}/sql/log_event.cc
COMPILE_FLAGS
" -Wno-error=uninitialized"
" -Wno-error=maybe-uninitialized"
)
ENDIF()
# duplicate explicit instantiation of 'net_field_length_checked'
# ignored as a Microsoft extension
IF(WIN32_CLANG)
ADD_COMPILE_FLAGS(${CMAKE_SOURCE_DIR}/sql/log_event.cc
COMPILE_FLAGS " -Wno-microsoft-template")
ENDIF()
SET(MYSQLBINLOG_LIBRARIES
mysql_binlog_event
mysqlclient
)
IF(WITH_JSON_BINLOG_LIBRARY)
LIST(APPEND MYSQLBINLOG_LIBRARIES json_binlog)
ELSE()
LIST(APPEND MYSQLBINLOG_LIBRARIES json_binlog_static)
ENDIF()
MYSQL_ADD_EXECUTABLE(mysqlbinlog
${MYSQLBINLOG_SOURCES}
DEPENDENCIES GenError
LINK_LIBRARIES ${MYSQLBINLOG_LIBRARIES}
)
# __builtin_strncpy specified bound depends on the length of the source argument
# mysqlbinlog.cc:2169:22: note: length computed here
IF((WITH_LTO OR CMAKE_COMPILER_FLAG_WITH_LTO) AND
MY_COMPILER_IS_GNU AND
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 11)
MY_TARGET_LINK_OPTIONS(mysqlbinlog "-Wno-stringop-truncation")
ENDIF()
IF(WITH_JSON_BINLOG_LIBRARY)
IF(APPLE)
ADD_CUSTOM_COMMAND(TARGET mysqlbinlog POST_BUILD
COMMAND install_name_tool -change
"@rpath/$<TARGET_FILE_NAME:json_binlog>"
"@loader_path/../lib/$<TARGET_FILE_NAME:json_binlog>"
"$<TARGET_FILE:mysqlbinlog>"
)
ELSEIF(UNIX)
ADD_INSTALL_RPATH(mysqlbinlog "\$ORIGIN/../${INSTALL_LIBDIR}")
ENDIF()
ENDIF()
TARGET_COMPILE_DEFINITIONS(mysqlbinlog PRIVATE DISABLE_PSI_MUTEX)
TARGET_INCLUDE_DIRECTORIES(mysqlbinlog PRIVATE ${CMAKE_SOURCE_DIR}/sql)
MYSQL_ADD_EXECUTABLE(mysqladmin
mysqladmin.cc
multi_factor_passwordopt-vars.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysqlslap
mysqlslap.cc
multi_factor_passwordopt-vars.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysql_config_editor
mysql_config_editor.cc
LINK_LIBRARIES mysqlclient
)
MYSQL_ADD_EXECUTABLE(mysql_secure_installation
mysql_secure_installation.cc
LINK_LIBRARIES mysqlclient
)
# "WIN32" also covers 64 bit. "echo" is used in some files below "mysql-test/".
IF(WIN32)
MYSQL_ADD_EXECUTABLE(echo echo.cc)
ENDIF(WIN32)

553
client/check/mysqlcheck.cc Normal file
View file

@ -0,0 +1,553 @@
/*
Copyright (c) 2001, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "client/check/mysqlcheck.h"
#include <mysql_version.h>
#include <mysqld_error.h>
#include <stdlib.h>
#include "client/include/caching_sha2_passwordopt-vars.h"
#include "client/include/client_priv.h"
#include "client/include/sslopt-vars.h"
#include "compression.h"
#include "my_alloc.h"
#include "my_dbug.h"
#include "my_default.h"
#include "my_inttypes.h"
#include "my_macros.h"
#include "mysql/service_mysql_alloc.h"
#include "mysql/strings/m_ctype.h"
#include "nulls.h"
#include "print_version.h"
#include "typelib.h"
#include "welcome_copyright_notice.h" /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
using namespace Mysql::Tools::Check;
using std::string;
using std::vector;
/* Exit codes */
#define EX_USAGE 1
#define EX_MYSQLERR 2
static MYSQL mysql_connection, *sock = nullptr;
static bool opt_alldbs = false, opt_check_only_changed = false,
opt_extended = false, opt_compress = false, opt_databases = false,
opt_fast = false, opt_medium_check = false, opt_quick = false,
opt_all_in_1 = false, opt_silent = false, opt_auto_repair = false,
ignore_errors = false, opt_frm = false, debug_info_flag = false,
debug_check_flag = false, opt_fix_table_names = false,
opt_fix_db_names = false, opt_upgrade = false,
opt_write_binlog = true;
static uint verbose = 0, opt_mysql_port = 0;
static uint opt_enable_cleartext_plugin = 0;
static bool using_opt_enable_cleartext_plugin = false;
static int my_end_arg;
static char *opt_mysql_unix_port = nullptr;
static char *current_user = nullptr, *current_host = nullptr;
static const char *default_charset = nullptr;
static char *opt_plugin_dir = nullptr, *opt_default_auth = nullptr;
static int first_error = 0;
static const char *opt_skip_database = "";
static uint opt_zstd_compress_level = default_zstd_compression_level;
static char *opt_compress_algorithm = nullptr;
#if defined(_WIN32)
static char *shared_memory_base_name = nullptr;
#endif
static uint opt_protocol = 0;
static char *opt_bind_addr = nullptr;
#include "client/include/multi_factor_passwordopt-vars.h"
static struct my_option my_long_options[] = {
{"all-databases", 'A',
"Check all the databases. This is the same as --databases with all "
"databases selected.",
&opt_alldbs, &opt_alldbs, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"analyze", 'a', "Analyze given tables.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"all-in-1", '1',
"Instead of issuing one query for each table, use one query per database, "
"naming all tables in the database in a comma-separated list.",
&opt_all_in_1, &opt_all_in_1, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"auto-repair", OPT_AUTO_REPAIR,
"If a checked table is corrupted, automatically fix it. Repairing will be "
"done after all tables have been checked, if corrupted ones were found.",
&opt_auto_repair, &opt_auto_repair, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"bind-address", 0, "IP address to bind to.", (uchar **)&opt_bind_addr,
(uchar **)&opt_bind_addr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"character-sets-dir", OPT_CHARSETS_DIR,
"Directory for character set files.", &charsets_dir, &charsets_dir,
nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"check", 'c', "Check table for errors.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"check-only-changed", 'C',
"Check only tables that have changed since last check or haven't been "
"closed properly.",
nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"check-upgrade", 'g',
"Check tables for version-dependent changes. May be used with "
"--auto-repair to correct tables requiring version-dependent updates.",
nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"compress", OPT_COMPRESS, "Use compression in server/client protocol.",
&opt_compress, &opt_compress, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"databases", 'B',
"Check several databases. Note the difference in usage; in this case no "
"tables are given. All name arguments are regarded as database names.",
&opt_databases, &opt_databases, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#ifdef NDEBUG
{"debug", '#', "This is a non-debug version. Catch this and exit.", nullptr,
nullptr, nullptr, GET_DISABLED, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-check", OPT_DEBUG_CHECK,
"This is a non-debug version. Catch this and exit.", nullptr, nullptr,
nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-info", OPT_DEBUG_INFO,
"This is a non-debug version. Catch this and exit.", nullptr, nullptr,
nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#else
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", nullptr,
nullptr, nullptr, GET_STR, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-check", OPT_DEBUG_CHECK,
"Check memory and open file usage at exit.", &debug_check_flag,
&debug_check_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
&debug_info_flag, &debug_info_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"default-character-set", OPT_DEFAULT_CHARSET,
"Set the default character set.", &default_charset, &default_charset,
nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"default_auth", OPT_DEFAULT_AUTH,
"Default authentication client-side plugin to use.", &opt_default_auth,
&opt_default_auth, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
"Enable/disable the clear text authentication plugin.",
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, nullptr,
GET_BOOL, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"fast", 'F', "Check only tables that haven't been closed properly.",
&opt_fast, &opt_fast, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"force", 'f', "Continue even if we get an SQL error.", &ignore_errors,
&ignore_errors, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"extended", 'e',
"If you are using this option with CHECK TABLE, it will ensure that the "
"table is 100 percent consistent, but will take a long time. If you are "
"using this option with REPAIR TABLE, it will force using old slow repair "
"with keycache method, instead of much faster repair by sorting.",
&opt_extended, &opt_extended, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"help", '?', "Display this help message and exit.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"host", 'h', "Connect to host.", &current_host, &current_host, nullptr,
GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"medium-check", 'm',
"Faster than extended-check, but only finds 99.99 percent of all errors. "
"Should be good enough for most cases.",
nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"write-binlog", OPT_WRITE_BINLOG,
"Write ANALYZE, OPTIMIZE and REPAIR TABLE commands to the binary log. "
"Use --skip-write-binlog to omit this.",
&opt_write_binlog, &opt_write_binlog, nullptr, GET_BOOL, NO_ARG, 1, 0, 0,
nullptr, 0, nullptr},
{"optimize", 'o', "Optimize table.", nullptr, nullptr, nullptr, GET_NO_ARG,
NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#include "client/include/multi_factor_passwordopt-longopts.h"
#ifdef _WIN32
{"pipe", 'W', "Use named pipes to connect to server.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#endif
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
&opt_plugin_dir, &opt_plugin_dir, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"port", 'P',
"Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&opt_mysql_port, &opt_mysql_port, nullptr, GET_UINT, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol to use for connection (tcp, socket, pipe, memory).", nullptr,
nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"quick", 'q',
"If you are using this option with CHECK TABLE, it prevents the check "
"from scanning the rows to check for wrong links. This is the fastest "
"check. If you are using this option with REPAIR TABLE, it will try to "
"repair only the index tree. This is the fastest repair method for a "
"table.",
&opt_quick, &opt_quick, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"repair", 'r',
"Can fix almost anything except unique keys that aren't unique.", nullptr,
nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#if defined(_WIN32)
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
"Base name of shared memory.", &shared_memory_base_name,
&shared_memory_base_name, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"silent", 's', "Print only error messages.", &opt_silent, &opt_silent,
nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"skip_database", 0, "Don't process the database specified as argument",
&opt_skip_database, &opt_skip_database, nullptr, GET_STR, REQUIRED_ARG, 0,
0, 0, nullptr, 0, nullptr},
{"socket", 'S', "The socket file to use for connection.",
&opt_mysql_unix_port, &opt_mysql_unix_port, nullptr, GET_STR, REQUIRED_ARG,
0, 0, 0, nullptr, 0, nullptr},
#include "client/include/caching_sha2_passwordopt-longopts.h"
#include "client/include/sslopt-longopts.h"
{"tables", OPT_TABLES, "Overrides option --databases (-B).", nullptr,
nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"use-frm", OPT_FRM,
"When used with REPAIR, get table structure from .frm file, so the table "
"can be repaired even if .MYI header is corrupted.",
&opt_frm, &opt_frm, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"user", 'u', "User for login if not current user.", &current_user,
&current_user, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"verbose", 'v', "Print info about the various stages.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"version", 'V', "Output version information and exit.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"compression-algorithms", 0,
"Use compression algorithm in server/client protocol. Valid values "
"are any combination of 'zstd','zlib','uncompressed'.",
&opt_compress_algorithm, &opt_compress_algorithm, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"zstd-compression-level", 0,
"Use this compression level in the client/server protocol, in case "
"--compression-algorithms=zstd. Valid range is between 1 and 22, "
"inclusive. Default is 3.",
&opt_zstd_compress_level, &opt_zstd_compress_level, nullptr, GET_UINT,
REQUIRED_ARG, 3, 1, 22, nullptr, 0, nullptr},
{nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
0, nullptr, 0, nullptr}};
static const char *load_default_groups[] = {"mysqlcheck", "client", nullptr};
static void usage(void);
static int get_options(int *argc, char ***argv, MEM_ROOT *alloc);
static int dbConnect(char *host, char *user);
static void dbDisconnect(char *host);
static void DBerror(MYSQL *mysql, const string &when);
static void safe_exit(int error);
static int what_to_do = 0;
static void usage(void) {
print_version();
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
puts(
"This program can be used to CHECK (-c, -m, -C), REPAIR (-r), ANALYZE "
"(-a),");
puts("or OPTIMIZE (-o) tables. Some of the options (like -e or -q) can be");
puts(
"used at the same time. Not all options are supported by all storage "
"engines.");
puts("Please consult the MySQL manual for latest information about the");
puts(
"above. The options -c, -r, -a, and -o are exclusive to each other, "
"which");
puts("means that the last option will be used, if several was specified.\n");
puts("The option -c will be used by default, if none was specified. You");
puts("can change the default behavior by making a symbolic link, or");
puts("copying this file somewhere with another name, the alternatives are:");
puts("mysqlrepair: The default option will be -r");
puts("mysqlanalyze: The default option will be -a");
puts("mysqloptimize: The default option will be -o\n");
printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
printf("OR %s [OPTIONS] --databases DB1 [DB2 DB3...]\n", my_progname);
printf("OR %s [OPTIONS] --all-databases\n", my_progname);
print_defaults("my", load_default_groups);
my_print_help(my_long_options);
my_print_variables(my_long_options);
} /* usage */
extern "C" {
static bool get_one_option(int optid, const struct my_option *opt,
char *argument) {
const int orig_what_to_do = what_to_do;
switch (optid) {
case 'a':
what_to_do = DO_ANALYZE;
break;
case 'c':
what_to_do = DO_CHECK;
break;
case 'C':
what_to_do = DO_CHECK;
opt_check_only_changed = true;
break;
case 'I':
[[fallthrough]];
case '?':
usage();
exit(0);
case 'm':
what_to_do = DO_CHECK;
opt_medium_check = true;
break;
case 'o':
what_to_do = DO_OPTIMIZE;
break;
PARSE_COMMAND_LINE_PASSWORD_OPTION;
case 'r':
what_to_do = DO_REPAIR;
break;
case 'g':
what_to_do = DO_CHECK;
opt_upgrade = true;
break;
case 'W':
#ifdef _WIN32
opt_protocol = MYSQL_PROTOCOL_PIPE;
#endif
break;
case '#':
DBUG_PUSH(argument ? argument : "d:t:o");
debug_check_flag = true;
break;
#include "client/include/sslopt-case.h"
case OPT_TABLES:
opt_databases = false;
break;
case 'v':
verbose++;
break;
case 'V':
print_version();
exit(0);
case OPT_ENABLE_CLEARTEXT_PLUGIN:
using_opt_enable_cleartext_plugin = true;
break;
case OPT_MYSQL_PROTOCOL:
opt_protocol =
find_type_or_exit(argument, &sql_protocol_typelib, opt->name);
break;
case OPT_COMPRESS:
CLIENT_WARN_DEPRECATED("--compress", "--compression-algorithms");
break;
}
if (orig_what_to_do && (what_to_do != orig_what_to_do)) {
fprintf(stderr,
"Error: %s doesn't support multiple contradicting commands.\n",
my_progname);
return true;
}
return false;
}
}
static int get_options(int *argc, char ***argv, MEM_ROOT *alloc) {
int ho_error;
if (*argc == 1) {
usage();
exit(0);
}
my_getopt_use_args_separator = true;
if ((ho_error =
load_defaults("my", load_default_groups, argc, argv, alloc)) ||
(ho_error = handle_options(argc, argv, my_long_options, get_one_option)))
exit(ho_error);
my_getopt_use_args_separator = false;
if (!what_to_do) {
const size_t pnlen = strlen(my_progname);
if (pnlen < 6) /* name too short */
what_to_do = DO_CHECK;
else if (!strcmp("repair", my_progname + pnlen - 6))
what_to_do = DO_REPAIR;
else if (!strcmp("analyze", my_progname + pnlen - 7))
what_to_do = DO_ANALYZE;
else if (!strcmp("optimize", my_progname + pnlen - 8))
what_to_do = DO_OPTIMIZE;
else
what_to_do = DO_CHECK;
}
/*
If there's no --default-character-set option given with
--fix-table-name or --fix-db-name set the default character set to
"utf8mb4".
*/
if (!default_charset) {
if (opt_fix_db_names || opt_fix_table_names)
default_charset = "utf8mb4";
else
default_charset = MYSQL_AUTODETECT_CHARSET_NAME;
}
if (strcmp(default_charset, MYSQL_AUTODETECT_CHARSET_NAME) &&
!get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME))) {
printf("Unsupported character set: %s\n", default_charset);
return 1;
}
if (*argc > 0 && opt_alldbs) {
printf("You should give only options, no arguments at all, with option\n");
printf("--all-databases. Please see %s --help for more information.\n",
my_progname);
return 1;
}
if (*argc < 1 && !opt_alldbs) {
printf("You forgot to give the arguments! Please see %s --help\n",
my_progname);
printf("for more information.\n");
return 1;
}
if (debug_info_flag) my_end_arg = MY_CHECK_ERROR | MY_GIVE_INFO;
if (debug_check_flag) my_end_arg = MY_CHECK_ERROR;
return (0);
} /* get_options */
static int dbConnect(char *host, char *user) {
DBUG_TRACE;
if (verbose) {
fprintf(stderr, "# Connecting to %s...\n", host ? host : "localhost");
}
mysql_init(&mysql_connection);
if (opt_compress) mysql_options(&mysql_connection, MYSQL_OPT_COMPRESS, NullS);
if (opt_compress_algorithm)
mysql_options(&mysql_connection, MYSQL_OPT_COMPRESSION_ALGORITHMS,
opt_compress_algorithm);
mysql_options(&mysql_connection, MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
&opt_zstd_compress_level);
if (SSL_SET_OPTIONS(&mysql_connection)) {
fprintf(stderr, "%s", SSL_SET_OPTIONS_ERROR);
return 1;
}
if (opt_protocol)
mysql_options(&mysql_connection, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
if (opt_bind_addr)
mysql_options(&mysql_connection, MYSQL_OPT_BIND, opt_bind_addr);
#if defined(_WIN32)
if (shared_memory_base_name)
mysql_options(&mysql_connection, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
if (opt_plugin_dir && *opt_plugin_dir)
mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir);
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
if (using_opt_enable_cleartext_plugin)
mysql_options(&mysql_connection, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
(char *)&opt_enable_cleartext_plugin);
mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr);
mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name",
"mysqlcheck");
set_server_public_key(&mysql_connection);
set_get_server_public_key_option(&mysql_connection);
set_password_options(&mysql_connection);
if (!(sock =
mysql_real_connect(&mysql_connection, host, user, nullptr, nullptr,
opt_mysql_port, opt_mysql_unix_port, 0))) {
DBerror(&mysql_connection, "when trying to connect");
return 1;
}
return 0;
} /* dbConnect */
static void dbDisconnect(char *host) {
if (verbose)
fprintf(stderr, "# Disconnecting from %s...\n", host ? host : "localhost");
mysql_close(sock);
} /* dbDisconnect */
static void DBerror(MYSQL *mysql, const string &when) {
DBUG_TRACE;
my_printf_error(0, "Got error: %d: %s %s", MYF(0), mysql_errno(mysql),
mysql_error(mysql), when.c_str());
safe_exit(EX_MYSQLERR);
} /* DBerror */
static void safe_exit(int error) {
if (!first_error) first_error = error;
if (ignore_errors) return;
if (sock) mysql_close(sock);
exit(error);
}
int main(int argc, char **argv) {
MY_INIT(argv[0]);
/*
** Check out the args
*/
MEM_ROOT alloc(PSI_NOT_INSTRUMENTED, 512);
if (get_options(&argc, &argv, &alloc)) {
my_end(my_end_arg);
exit(EX_USAGE);
}
if (dbConnect(current_host, current_user)) exit(EX_MYSQLERR);
// Sun Studio does not work with range constructor from char** to string.
vector<string> conv;
conv.reserve(argc);
for (int i = 0; i < argc; i++) conv.push_back(argv[i]);
mysql_check(sock, what_to_do, opt_alldbs, opt_check_only_changed,
opt_extended, opt_databases, opt_fast, opt_medium_check,
opt_quick, opt_all_in_1, opt_silent, opt_auto_repair,
ignore_errors, opt_frm, opt_fix_table_names, opt_fix_db_names,
opt_upgrade, opt_write_binlog, verbose, opt_skip_database, conv,
DBerror);
dbDisconnect(current_host);
free_passwords();
#if defined(_WIN32)
my_free(shared_memory_base_name);
#endif
alloc.Clear();
my_end(my_end_arg);
return (first_error != 0);
} /* main */

147
client/check/mysqlcheck.h Normal file
View file

@ -0,0 +1,147 @@
/*
Copyright (c) 2014, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 MYSQLCHECK_INCLUDED
#define MYSQLCHECK_INCLUDED
#include <sys/types.h>
#include <string>
#include <vector>
#include "mysql.h"
namespace Mysql {
namespace Tools {
namespace Check {
enum operations {
DO_CHECK = 1,
DO_REPAIR,
DO_ANALYZE,
DO_OPTIMIZE,
DO_UPGRADE
};
extern void mysql_check(MYSQL *connection, int what_to_do, bool opt_alldbs,
bool opt_check_only_changed, bool opt_extended,
bool opt_databases, bool opt_fast,
bool opt_medium_check, bool opt_quick,
bool opt_all_in_1, bool opt_silent,
bool opt_auto_repair, bool ignore_errors, bool opt_frm,
bool opt_fix_table_names, bool opt_fix_db_names,
bool opt_upgrade, bool opt_write_binlog,
unsigned int verbose, std::string opt_skip_database,
std::vector<std::string> arguments,
void (*dberror)(MYSQL *mysql, const std::string &when));
/**
This class is object wrapper to mysql_check function. It looks like
it is implementing Abstract_program, but it is not explicitly implementing
it now. This is to make future implementation of Abstract_program easier.
*/
class Program {
public:
/**
Default constructor.
*/
Program();
/**
Checks specified databases on MySQL server.
*/
int check_databases(MYSQL *connection,
const std::vector<std::string> &databases);
/**
Checks all databases on MySQL server.
*/
int check_all_databases(MYSQL *connection);
/**
Automatically try to fix table when upgrade is needed.
*/
Program *enable_auto_repair(bool enable);
/**
Check and upgrade tables.
*/
Program *enable_upgrade(bool enable);
/**
Turns on verbose messages.
*/
Program *enable_verbosity(bool enable);
/**
Enables logging repairing queries to binlog.
*/
Program *enable_writing_binlog(bool enable);
/**
Enables table name fixing for all encountered tables.
*/
Program *enable_fixing_table_names(bool enable);
/**
Enables database name fixing for all encountered databases.
*/
Program *enable_fixing_db_names(bool enable);
/**
Ignores all errors and don't print error messages.
*/
Program *set_ignore_errors(bool ignore);
/**
Sets a name of database to ignore during process.
*/
Program *set_skip_database(std::string database);
/**
Sets error callback to be called when error is encountered.
*/
Program *set_error_callback(void (*error_callback)(MYSQL *mysql,
const std::string &when));
private:
/**
Sets mysqlcheck program operation type to perform.
*/
Program *set_what_to_do(int functionality);
/**
Starts mysqlcheck process.
*/
int execute(const std::vector<std::string> &positional_options);
int m_what_to_do;
bool m_auto_repair;
bool m_upgrade;
bool m_verbose;
bool m_ignore_errors;
bool m_write_binlog;
bool m_process_all_dbs;
bool m_fix_table_names;
bool m_fix_db_names;
MYSQL *m_connection;
std::string m_database_to_skip;
void (*m_error_callback)(MYSQL *mysql, const std::string &when);
};
} // namespace Check
} // namespace Tools
} // namespace Mysql
#endif

View file

@ -0,0 +1,530 @@
/*
Copyright (c) 2001, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <mysql_version.h>
#include <mysqld_error.h>
#include <sys/types.h>
#include <string>
#include <vector>
#include "client/check/mysqlcheck.h"
#include "client/include/client_priv.h"
#include "m_string.h"
#include "my_default.h"
#include "my_inttypes.h"
#include "mysql/strings/m_ctype.h"
using namespace Mysql::Tools::Check;
using std::string;
using std::vector;
/* ALTER instead of repair. */
#define MAX_ALTER_STR_SIZE 128 * 1024
#define KEY_PARTITIONING_CHANGED_STR "KEY () partitioning changed"
static MYSQL *sock = nullptr;
static bool opt_alldbs = false, opt_check_only_changed = false,
opt_extended = false, opt_databases = false, opt_fast = false,
opt_medium_check = false, opt_quick = false, opt_all_in_1 = false,
opt_silent = false, opt_auto_repair = false, ignore_errors = false,
opt_frm = false, opt_fix_table_names = false,
opt_fix_db_names = false, opt_upgrade = false,
opt_write_binlog = true;
static uint verbose = 0;
static string opt_skip_database;
int what_to_do = 0;
void (*DBError)(MYSQL *mysql, const string &when);
static int first_error = 0;
vector<string> tables4repair, tables4rebuild, alter_table_cmds;
static int process_all_databases();
static int process_databases(const vector<string> &db_names);
static int process_selected_tables(const string &db,
const vector<string> &table_names);
static int process_all_tables_in_db(const string &database);
static int process_one_db(const string &database);
static int use_db(const string &database);
static int handle_request_for_tables(const string &tables);
static void print_result();
static string escape_table_name(const string &src);
static int process_all_databases() {
MYSQL_ROW row;
MYSQL_RES *tableres;
int result = 0;
if (mysql_query(sock, "SHOW DATABASES") ||
!(tableres = mysql_store_result(sock))) {
my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s", MYF(0),
mysql_error(sock));
return 1;
}
while ((row = mysql_fetch_row(tableres))) {
if (process_one_db(row[0])) result = 1;
}
mysql_free_result(tableres);
return result;
}
/* process_all_databases */
static int process_databases(const vector<string> &db_names) {
int result = 0;
for (const string &db_name : db_names) {
if (process_one_db(db_name)) result = 1;
}
return result;
} /* process_databases */
static int process_selected_tables(const string &db,
const vector<string> &table_names) {
if (use_db(db)) return 1;
/*
TODO (a bug): properly handle all-in-1 option:
we should create and pass a table list to handle_request_for_tables().
*/
for (const string &table_name : table_names) {
handle_request_for_tables(escape_table_name(table_name));
}
return 0;
} /* process_selected_tables */
static inline void escape_str(const string &src, size_t start, size_t end,
string &res) {
res += '`';
for (size_t i = start; i < end; i++) {
switch (src[i]) {
case '`': /* Escape backtick character. */
res += '`';
[[fallthrough]];
default:
res += src[i];
}
}
res += '`';
}
static string escape_table_name(const string &src) {
string res = "";
escape_str(src, 0, src.length(), res);
return res;
}
static string escape_db_table_name(const string &src, size_t dot_pos) {
string res = "";
/* Escape database name. */
escape_str(src, 0, dot_pos - 1, res);
/* Add a dot. */
res += '.';
/* Escape table name. */
escape_str(src, dot_pos, src.length(), res);
return res;
}
static int process_all_tables_in_db(const string &database) {
MYSQL_RES *res = nullptr;
MYSQL_ROW row;
uint num_columns;
if (use_db(database)) return 1;
if ((mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") &&
mysql_query(sock, "SHOW TABLES")) ||
!(res = mysql_store_result(sock))) {
my_printf_error(0, "Error: Couldn't get table list for database %s: %s",
MYF(0), database.c_str(), mysql_error(sock));
return 1;
}
num_columns = mysql_num_fields(res);
vector<string> table_names;
while ((row = mysql_fetch_row(res))) {
/* Skip views if we don't perform renaming. */
if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) continue;
table_names.push_back(row[0]);
}
mysql_free_result(res);
process_selected_tables(database, table_names);
return 0;
} /* process_all_tables_in_db */
static int run_query(const string &query) {
if (mysql_query(sock, query.c_str())) {
fprintf(stderr, "Failed to run query \"%s\"\n", query.c_str());
fprintf(stderr, "Error: %s\n", mysql_error(sock));
return 1;
}
return 0;
}
static int rebuild_table(const string &name) {
int rc = 0;
string query = "ALTER TABLE " + name + " FORCE";
if (mysql_real_query(sock, query.c_str(), (ulong)query.length())) {
fprintf(stderr, "Failed to %s\n", query.c_str());
fprintf(stderr, "Error: %s\n", mysql_error(sock));
rc = 1;
} else
printf("%s\nRunning : %s\nstatus : OK\n", name.c_str(), query.c_str());
return rc;
}
static int process_one_db(const string &database) {
if (opt_skip_database.length() > 0 && opt_alldbs &&
database == opt_skip_database)
return 0;
return process_all_tables_in_db(database);
}
static int use_db(const string &database) {
if (mysql_get_server_version(sock) >= FIRST_INFORMATION_SCHEMA_VERSION &&
!my_strcasecmp(&my_charset_latin1, database.c_str(),
INFORMATION_SCHEMA_DB_NAME))
return 1;
if (mysql_get_server_version(sock) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
!my_strcasecmp(&my_charset_latin1, database.c_str(),
PERFORMANCE_SCHEMA_DB_NAME))
return 1;
if (mysql_select_db(sock, database.c_str())) {
DBError(sock, "when selecting the database");
return 1;
}
return 0;
} /* use_db */
static int disable_binlog() { return run_query("SET SQL_LOG_BIN=0"); }
static int handle_request_for_tables(const string &tables) {
string operation, options;
switch (what_to_do) {
case DO_CHECK:
operation = "CHECK";
if (opt_quick) options += " QUICK";
if (opt_fast) options += " FAST";
if (opt_medium_check) options += " MEDIUM"; /* Default */
if (opt_extended) options += " EXTENDED";
if (opt_check_only_changed) options += " CHANGED";
if (opt_upgrade) options += " FOR UPGRADE";
break;
case DO_REPAIR:
operation = (opt_write_binlog) ? "REPAIR" : "REPAIR NO_WRITE_TO_BINLOG";
if (opt_quick) options += " QUICK";
if (opt_extended) options += " EXTENDED";
if (opt_frm) options += " USE_FRM";
break;
case DO_ANALYZE:
operation = (opt_write_binlog) ? "ANALYZE" : "ANALYZE NO_WRITE_TO_BINLOG";
break;
case DO_OPTIMIZE:
operation =
(opt_write_binlog) ? "OPTIMIZE" : "OPTIMIZE NO_WRITE_TO_BINLOG";
break;
}
string query = operation + " TABLE " + tables + " " + options;
if (mysql_real_query(sock, query.c_str(), (ulong)query.length())) {
DBError(sock,
"when executing '" + operation + " TABLE ... " + options + "'");
return 1;
}
print_result();
return 0;
}
static void print_result() {
MYSQL_RES *res;
MYSQL_ROW row;
char prev[NAME_LEN * 3 + 2];
char prev_alter[MAX_ALTER_STR_SIZE];
size_t dot_pos;
bool found_error = false, table_rebuild = false;
res = mysql_use_result(sock);
dot_pos = strlen(sock->db) + 1;
prev[0] = '\0';
prev_alter[0] = 0;
while ((row = mysql_fetch_row(res))) {
const int changed = strcmp(prev, row[0]);
const bool status = !strcmp(row[2], "status");
if (status) {
/*
if there was an error with the table, we have --auto-repair set,
and this isn't a repair op, then add the table to the tables4repair
list
*/
if (found_error && opt_auto_repair && what_to_do != DO_REPAIR &&
strcmp(row[3], "OK")) {
if (table_rebuild) {
if (prev_alter[0])
alter_table_cmds.push_back(prev_alter);
else
tables4rebuild.push_back(escape_db_table_name(prev, dot_pos));
} else {
tables4repair.push_back(escape_db_table_name(prev, dot_pos));
}
}
found_error = false;
table_rebuild = false;
prev_alter[0] = 0;
if (opt_silent) continue;
}
if (status && changed)
printf("%-50s %s", row[0], row[3]);
else if (!status && changed) {
if (opt_auto_repair && what_to_do != DO_REPAIR) {
printf("%-50s To be repaired, cause follows:\nServer issued %-9s: %s",
row[0], row[2], row[3]);
} else {
printf("%s\n%-9s: %s", row[0], row[2], row[3]);
}
if (opt_auto_repair && strcmp(row[2], "note")) {
const char *alter_txt = strstr(row[3], "ALTER TABLE");
found_error = true;
if (alter_txt) {
table_rebuild = true;
if (!strncmp(row[3], KEY_PARTITIONING_CHANGED_STR,
strlen(KEY_PARTITIONING_CHANGED_STR)) &&
strstr(alter_txt, "PARTITION BY")) {
if (strlen(alter_txt) >= MAX_ALTER_STR_SIZE) {
printf(
"Error: Alter command too long (>= %d),"
" please do \"%s\" or dump/reload to fix it!\n",
MAX_ALTER_STR_SIZE, alter_txt);
table_rebuild = false;
prev_alter[0] = 0;
} else {
strncpy(prev_alter, alter_txt, MAX_ALTER_STR_SIZE - 1);
prev_alter[MAX_ALTER_STR_SIZE - 1] = 0;
}
}
}
}
} else
printf("%-9s: %s", row[2], row[3]);
my_stpcpy(prev, row[0]);
putchar('\n');
}
/* add the last table to be repaired to the list */
if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) {
if (table_rebuild) {
if (prev_alter[0])
alter_table_cmds.push_back(prev_alter);
else
tables4rebuild.push_back(escape_db_table_name(prev, dot_pos));
} else {
tables4repair.push_back(escape_db_table_name(prev, dot_pos));
}
}
mysql_free_result(res);
}
namespace Mysql::Tools::Check {
void mysql_check(MYSQL *connection, int what_to_do, bool opt_alldbs,
bool opt_check_only_changed, bool opt_extended,
bool opt_databases, bool opt_fast, bool opt_medium_check,
bool opt_quick, bool opt_all_in_1, bool opt_silent,
bool opt_auto_repair, bool ignore_errors, bool opt_frm,
bool opt_fix_table_names, bool opt_fix_db_names,
bool opt_upgrade, bool opt_write_binlog, uint verbose,
std::string opt_skip_database,
std::vector<std::string> arguments,
void (*dberror)(MYSQL *mysql, const std::string &when)) {
::sock = connection;
::what_to_do = what_to_do;
::opt_alldbs = opt_alldbs;
::opt_check_only_changed = opt_check_only_changed;
::opt_extended = opt_extended;
::opt_databases = opt_databases;
::opt_fast = opt_fast;
::opt_medium_check = opt_medium_check;
::opt_quick = opt_quick;
::opt_all_in_1 = opt_all_in_1;
::opt_silent = opt_silent;
::opt_auto_repair = opt_auto_repair;
::ignore_errors = ignore_errors;
::opt_frm = opt_frm;
::opt_fix_table_names = opt_fix_table_names;
::opt_fix_db_names = opt_fix_db_names;
::opt_upgrade = opt_upgrade;
::opt_write_binlog = opt_write_binlog;
::verbose = verbose;
::opt_skip_database = opt_skip_database;
::DBError = dberror;
if (!::opt_write_binlog) {
if (disable_binlog()) {
first_error = 1;
return;
}
}
if (::opt_alldbs) process_all_databases();
/* Only one database and selected table(s) */
else if (arguments.size() > 1 && !::opt_databases) {
string db_name = arguments[0];
arguments.erase(arguments.begin());
process_selected_tables(db_name, arguments);
}
/* One or more databases, all tables */
else
process_databases(arguments);
if (::opt_auto_repair) {
if (!::opt_silent && !(tables4repair.empty() && tables4rebuild.empty()))
puts("\nRepairing tables");
::what_to_do = DO_REPAIR;
for (const string &table4repair : tables4repair) {
handle_request_for_tables(table4repair);
}
for (const string &table4rebuild : tables4rebuild) {
rebuild_table(table4rebuild);
}
for (const string &alter_table_cmd : alter_table_cmds) {
run_query(alter_table_cmd);
}
}
}
} // namespace Mysql::Tools::Check
Program::Program()
: m_what_to_do(0),
m_auto_repair(false),
m_upgrade(false),
m_verbose(false),
m_ignore_errors(false),
m_write_binlog(false),
m_process_all_dbs(false),
m_fix_table_names(false),
m_fix_db_names(false),
m_connection(nullptr),
m_error_callback(nullptr) {}
int Program::check_databases(MYSQL *connection,
const vector<string> &databases) {
this->m_connection = connection;
this->m_process_all_dbs = false;
return this->set_what_to_do(DO_CHECK)->execute(databases);
}
int Program::check_all_databases(MYSQL *connection) {
this->m_connection = connection;
this->m_process_all_dbs = true;
return this->set_what_to_do(DO_CHECK)->execute(vector<string>());
}
Program *Program::enable_auto_repair(bool enable) {
this->m_auto_repair = enable;
return this;
}
Program *Program::enable_upgrade(bool enable) {
this->m_upgrade = enable;
return this;
}
Program *Program::enable_verbosity(bool enable) {
this->m_verbose = enable;
return this;
}
Program *Program::enable_writing_binlog(bool enable) {
this->m_write_binlog = enable;
return this;
}
Program *Program::enable_fixing_table_names(bool enable) {
this->m_fix_table_names = enable;
return this;
}
Program *Program::enable_fixing_db_names(bool enable) {
this->m_fix_db_names = enable;
return this;
}
Program *Program::set_ignore_errors(bool ignore) {
this->m_ignore_errors = ignore;
return this;
}
Program *Program::set_skip_database(string database) {
this->m_database_to_skip = std::move(database);
return this;
}
Program *Program::set_error_callback(
void (*error_callback)(MYSQL *mysql, const string &when)) {
this->m_error_callback = error_callback;
return this;
}
Program *Program::set_what_to_do(int functionality) {
this->m_what_to_do = functionality;
return this;
}
/// @relates Mysql::Tools::Check::Program
int Program::execute(const vector<string> &positional_options) {
Mysql::Tools::Check::mysql_check(
this->m_connection, // connection
this->m_what_to_do, // what_to_do
this->m_process_all_dbs, // opt_alldbs
false, // opt_check_only_changed
false, // opt_extended
!this->m_process_all_dbs, // opt_databases
false, // opt_fast
false, // opt_medium_check
false, // opt_quick
false, // opt_all_in_1
false, // opt_silent
this->m_auto_repair, // opt_auto_repair
this->m_ignore_errors, // ignore_errors
false, // opt_frm
this->m_fix_table_names, // opt_fix_table_names
this->m_fix_db_names, // opt_fix_db_names
this->m_upgrade, // opt_upgrade
this->m_write_binlog, // opt_write_binlog
this->m_verbose, // verbose
this->m_database_to_skip, positional_options, this->m_error_callback);
return 0;
}

View file

@ -0,0 +1,93 @@
/*
Copyright (c) 2020, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "client/include/client_priv.h"
#include "my_config.h"
#include "mysql/service_mysql_alloc.h" // my_malloc, my_strdup
#include "client/client_query_attributes.h"
client_query_attributes *global_attrs = nullptr;
bool client_query_attributes::push_param(const char *name, const char *value) {
return push_param(name, strlen(name), value, strlen(value));
}
bool client_query_attributes::push_param(const char *name, size_t name_length,
const char *value,
size_t value_length) {
if (count >= max_count) return true;
/* Copy name */
char *name_copy =
(char *)my_malloc(PSI_NOT_INSTRUMENTED, name_length + 1, MYF(0));
if (name_length) {
memcpy(name_copy, name, name_length);
}
name_copy[name_length] = 0;
names[count] = name_copy;
/* Copy value */
char *value_copy =
(char *)my_malloc(PSI_NOT_INSTRUMENTED, value_length + 1, MYF(0));
if (value_length) {
memcpy(value_copy, value, value_length);
}
value_copy[value_length] = 0;
memset(&values[count], 0, sizeof(MYSQL_BIND));
values[count].buffer = value_copy;
values[count].buffer_length = value_length;
values[count].buffer_type = MYSQL_TYPE_STRING;
count++;
return false;
}
int client_query_attributes::set_params(MYSQL *mysql) {
if (count == 0) return 0;
const int rc = mysql_bind_param(mysql, count, values, names);
return rc;
}
int client_query_attributes::set_params_stmt(MYSQL_STMT *stmt) {
if (count == 0) return 0;
const int rc = mysql_stmt_bind_named_param(stmt, values, count, names);
return rc;
}
void client_query_attributes::clear(MYSQL *mysql) {
if (mysql != nullptr) mysql_bind_param(mysql, 0, nullptr, nullptr);
while (count) {
count--;
my_free(const_cast<char *>(names[count]));
my_free(values[count].buffer);
}
memset(&names, 0, sizeof(names));
memset(&values, 0, sizeof(values));
}

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2020, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 CLIENT_QUERY_ATTRIBUTES_H
#define CLIENT_QUERY_ATTRIBUTES_H
#include "mysql.h"
class client_query_attributes {
public:
client_query_attributes() = default;
~client_query_attributes() { clear(); }
/* Assumes that name and value are 0 terminated. */
bool push_param(const char *name, const char *value);
/* Does not assumes that name and value are 0 terminated. */
bool push_param(const char *name, size_t name_length, const char *value,
size_t value_length);
int set_params(MYSQL *mysql);
int set_params_stmt(MYSQL_STMT *stmt);
void clear(MYSQL *mysql = nullptr);
private:
/* 32 should be enough for everybody */
static constexpr int max_count = 32;
const char *names[max_count];
MYSQL_BIND values[max_count];
unsigned count{0};
};
extern client_query_attributes *global_attrs;
#endif

View file

@ -0,0 +1,253 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <scope_guard.h>
#include <sstream>
#include <vector>
#include "client/include/user_registration.h"
#include "my_hostname.h"
#include "my_inttypes.h"
#include "my_sys.h"
#include "mysql/service_mysql_alloc.h" // my_malloc
#include "mysqld_error.h"
#define QUERY_LENGTH 2048
#define MAX_QUERY_LENGTH 4096
#define ENCODING_LENGTH 4
#define CAPABILITY_BIT_LENGTH 1
/**
This helper method parses --register-factor
option values, and inserts the parsed values in list.
@param [in] what_factor Comma separated list of values, which specifies
which factor requires registration.
Valid values are "2", "3", "2,3" or "3,2"
@param [out] factors container holding individual factors
@return true failed
@return false success
*/
bool parse_register_option(const char *what_factor,
std::vector<unsigned int> &factors) {
std::string token;
std::stringstream str(what_factor);
while (getline(str, token, ',')) {
unsigned int nth_factor = 0;
try {
nth_factor = std::stoul(token);
} catch (std::invalid_argument &) {
return true;
} catch (std::out_of_range &) {
return true;
}
/* nth_factor can be either 2 or 3 */
if (nth_factor < 2 || nth_factor > 3) return true;
factors.push_back(nth_factor);
}
return false;
}
/**
This helper method is used to perform device registration against a user
account.
Please refer @ref sect_webauthn_info for more information.
@param [in] mysql_handle mysql connection handle
@param [in] register_option Comma separated list of values, which
specifies which factor requires registration. Valid values are "2", "3", "2,3"
or "3,2"
@param [out] errmsg Buffer to hold error message in case of error.
@return true failed
@return false success
*/
bool user_device_registration(MYSQL *mysql_handle, char *register_option,
char *errmsg) {
char query[QUERY_LENGTH] = {0};
char *query_ptr = nullptr;
MYSQL_RES *result;
MYSQL_ROW row;
ulong *lengths;
uchar *server_challenge = nullptr;
uchar *server_challenge_response = nullptr;
std::string client_plugin_name;
struct st_mysql_client_plugin *plugin_handler = nullptr;
std::stringstream err{};
auto print_error = [&errmsg, &mysql_handle, &err](bool print_mysql_error) {
if (print_mysql_error) {
sprintf(errmsg, "%s: %d (%s): %s\n", err.str().c_str(),
mysql_errno(mysql_handle), mysql_sqlstate(mysql_handle),
mysql_error(mysql_handle));
} else {
sprintf(errmsg, "%s\n", err.str().c_str());
}
};
std::vector<unsigned int> factors;
if (parse_register_option(register_option, factors)) {
err << "Incorrect value specified for "
"--register-factor option. "
"Correct values can be '2', '3', '2,3' or '3,2'.";
print_error(false);
return true;
}
for (auto f : factors) {
sprintf(query, "ALTER USER USER() %d FACTOR INITIATE REGISTRATION", f);
if (mysql_real_query(mysql_handle, query, (ulong)strlen(query))) {
err << "Initiate registration for " << f << " factor: ALTER USER failed";
print_error(true);
return true;
}
if (!(result = mysql_store_result(mysql_handle))) {
err << "Initiate registration for " << f
<< " factor: Cannot process result";
print_error(true);
return true;
}
if (mysql_num_rows(result) > 1) {
err << "Initiate registration for " << f << " factor: Unexpected result";
print_error(true);
mysql_free_result(result);
return true;
}
row = mysql_fetch_row(result);
lengths = mysql_fetch_lengths(result);
/*
max length of challenge can be 32 (random challenge) +
255 (relying party ID) + 255 (host name) + 32 (user name) + 4 byte for
length encodings + 1 byte capability
*/
if (lengths[0] >
(CHALLENGE_LENGTH + RELYING_PARTY_ID_LENGTH + HOSTNAME_LENGTH +
USERNAME_LENGTH + ENCODING_LENGTH + CAPABILITY_BIT_LENGTH)) {
err << "Initiate registration for " << f
<< " factor: Received server challenge is corrupt. "
"Please retry.";
print_error(false);
mysql_free_result(result);
return true;
}
server_challenge = static_cast<uchar *>(my_malloc(
PSI_NOT_INSTRUMENTED, lengths[0] + 1, MYF(MY_WME | MY_ZEROFILL)));
memcpy(server_challenge, row[0], lengths[0]);
auto cleanup_guard = create_scope_guard([&] {
if (server_challenge_response) {
delete[] server_challenge_response;
server_challenge_response = nullptr;
}
if (query_ptr && query_ptr != query) {
my_free(query_ptr);
query_ptr = nullptr;
}
if (server_challenge) {
my_free(server_challenge);
server_challenge = nullptr;
}
});
if (mysql_num_fields(result) >= 2) {
if (!lengths[1] || !row[1]) {
err << "Initiate registration for " << f
<< " factor: No client plugin name received. Please retry.";
print_error(false);
mysql_free_result(result);
return true;
}
client_plugin_name.assign(row[1], lengths[1]);
}
mysql_free_result(result);
plugin_handler =
mysql_client_find_plugin(mysql_handle, client_plugin_name.c_str(),
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
/* check if client plugin is loaded */
if (!plugin_handler) {
err << "Initiate registration for " << f
<< " factor: Loading client plugin '" << client_plugin_name
<< "'failed with error";
print_error(true);
return true;
}
/* set server challenge in plugin */
if (mysql_plugin_options(plugin_handler, "registration_challenge",
server_challenge)) {
err << "Finish registration for " << f
<< " factor: Failed to set plugin options \"registration_challenge\" "
"for plugin '"
<< client_plugin_name << "'.";
print_error(false);
return true;
}
/* get challenge response from plugin, and release the memory */
if (mysql_plugin_get_option(plugin_handler, "registration_response",
&server_challenge_response)) {
err << "Finish registration for " << f
<< " factor: Failed to get plugin options \"registration_response\". "
"for pugin '"
<< client_plugin_name << "'.";
print_error(false);
return true;
}
/* execute FINISH REGISTRATION sql */
int n = snprintf(query, sizeof(query),
"ALTER USER USER() %d FACTOR FINISH REGISTRATION SET "
"CHALLENGE_RESPONSE AS ",
f);
size_t tot_query_len =
n + strlen(reinterpret_cast<char *>(server_challenge_response));
if (tot_query_len >= MAX_QUERY_LENGTH) {
err << "Finish registration for " << f
<< " factor: registration_response length exceeds max "
"supported length of "
<< MAX_QUERY_LENGTH << "\n";
print_error(false);
return true;
}
if (tot_query_len >= QUERY_LENGTH) {
/* allocate required buffer to construct query */
query_ptr = static_cast<char *>(my_malloc(
PSI_NOT_INSTRUMENTED, tot_query_len + 1, MYF(MY_WME | MY_ZEROFILL)));
}
if (query_ptr == nullptr) query_ptr = query;
sprintf(query_ptr,
"ALTER USER USER() %d FACTOR FINISH REGISTRATION SET "
"CHALLENGE_RESPONSE AS '%s'",
f, server_challenge_response);
if (mysql_real_query(mysql_handle, query, (ulong)strlen(query))) {
err << "Finish registration for " << f << " factor failed";
print_error(true);
return true;
}
}
return false;
}

209
client/completion_hash.cc Normal file
View file

@ -0,0 +1,209 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
// Hash implementation used for tab completion.
// TODO: Use a trie or similar instead.
#include "client/completion_hash.h"
#include "m_string.h"
#include "my_alloc.h"
#include "my_inttypes.h"
#include "my_sys.h"
#include "mysql/service_mysql_alloc.h"
static uint hashpjw(const char *arKey, uint nKeyLength) {
uint h = 0, g, i;
for (i = 0; i < nKeyLength; i++) {
h = (h << 4) + arKey[i];
if ((g = (h & 0xF0000000))) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h;
}
int completion_hash_init(HashTable *ht, uint nSize) {
ht->arBuckets =
(Bucket **)my_malloc(PSI_NOT_INSTRUMENTED, nSize * sizeof(Bucket *),
MYF(MY_ZEROFILL | MY_WME));
if (!ht->arBuckets) {
ht->initialized = 0;
return FAILURE;
}
::new ((void *)&ht->mem_root) MEM_ROOT(PSI_NOT_INSTRUMENTED, 8192);
ht->pHashFunction = hashpjw;
ht->nTableSize = nSize;
ht->initialized = 1;
return SUCCESS;
}
int completion_hash_update(HashTable *ht, const char *arKey, uint nKeyLength,
const char *str) {
uint h, nIndex;
Bucket *p;
h = ht->pHashFunction(arKey, nKeyLength);
nIndex = h % ht->nTableSize;
if (nKeyLength <= 0) {
return FAILURE;
}
p = ht->arBuckets[nIndex];
while (p) {
if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
if (!memcmp(p->arKey, arKey, nKeyLength)) {
entry *n;
if (!(n = (entry *)ht->mem_root.Alloc(sizeof(entry)))) return FAILURE;
n->pNext = p->pData;
n->str = str;
p->pData = n;
p->count++;
return SUCCESS;
}
}
p = p->pNext;
}
if (!(p = (Bucket *)ht->mem_root.Alloc(sizeof(Bucket)))) return FAILURE;
p->arKey = arKey;
p->nKeyLength = nKeyLength;
p->h = h;
if (!(p->pData = (entry *)ht->mem_root.Alloc(sizeof(entry)))) return FAILURE;
p->pData->str = str;
p->pData->pNext = nullptr;
p->count = 1;
p->pNext = ht->arBuckets[nIndex];
ht->arBuckets[nIndex] = p;
return SUCCESS;
}
static Bucket *completion_hash_find(HashTable *ht, const char *arKey,
uint nKeyLength) {
uint h, nIndex;
Bucket *p;
h = ht->pHashFunction(arKey, nKeyLength);
nIndex = h % ht->nTableSize;
p = ht->arBuckets[nIndex];
while (p) {
if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
if (!memcmp(p->arKey, arKey, nKeyLength)) {
return p;
}
}
p = p->pNext;
}
return (Bucket *)nullptr;
}
int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength) {
uint h, nIndex;
Bucket *p;
h = ht->pHashFunction(arKey, nKeyLength);
nIndex = h % ht->nTableSize;
p = ht->arBuckets[nIndex];
while (p) {
if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
if (!strcmp(p->arKey, arKey)) {
return 1;
}
}
p = p->pNext;
}
return 0;
}
Bucket *find_all_matches(HashTable *ht, const char *str, uint length,
uint *res_length) {
Bucket *b;
b = completion_hash_find(ht, str, length);
if (!b) {
*res_length = 0;
return (Bucket *)nullptr;
} else {
*res_length = length;
return b;
}
}
Bucket *find_longest_match(HashTable *ht, char *str, uint length,
uint *res_length) {
Bucket *b, *return_b;
const char *s;
uint count;
uint lm;
b = completion_hash_find(ht, str, length);
if (!b) {
*res_length = 0;
return (Bucket *)nullptr;
}
count = b->count;
lm = length;
s = b->pData->str;
return_b = b;
while (s[lm] != 0 && (b = completion_hash_find(ht, s, lm + 1))) {
if (b->count < count) {
*res_length = lm;
return return_b;
}
return_b = b;
lm++;
}
*res_length = lm;
return return_b;
}
void completion_hash_clean(HashTable *ht) {
ht->mem_root.Clear();
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
}
void completion_hash_free(HashTable *ht) {
completion_hash_clean(ht);
my_free(ht->arBuckets);
}
void add_word(HashTable *ht, const char *str) {
int i;
const char *pos = str;
for (i = 1; *pos; i++, pos++) completion_hash_update(ht, str, i, str);
}

70
client/completion_hash.h Normal file
View file

@ -0,0 +1,70 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 _HASH_
#define _HASH_
#define SUCCESS 0
#define FAILURE 1
#include <sys/types.h>
#include "my_alloc.h"
#include "my_sys.h"
typedef struct _entry {
const char *str;
struct _entry *pNext;
} entry;
typedef struct bucket {
uint h; /* Used for numeric indexing */
const char *arKey;
uint nKeyLength;
uint count;
entry *pData;
struct bucket *pNext;
} Bucket;
typedef struct hashtable {
uint nTableSize;
uint initialized;
MEM_ROOT mem_root;
uint (*pHashFunction)(const char *arKey, uint nKeyLength);
Bucket **arBuckets;
} HashTable;
extern int completion_hash_init(HashTable *ht, uint nSize);
extern int completion_hash_update(HashTable *ht, const char *arKey,
uint nKeyLength, const char *str);
extern int hash_exists(HashTable *ht, char *arKey);
extern Bucket *find_all_matches(HashTable *ht, const char *str, uint length,
uint *res_length);
extern Bucket *find_longest_match(HashTable *ht, char *str, uint length,
uint *res_length);
extern void add_word(HashTable *ht, const char *str);
extern void completion_hash_clean(HashTable *ht);
extern int completion_hash_exists(HashTable *ht, char *arKey, uint nKeyLength);
extern void completion_hash_free(HashTable *ht);
#endif /* _HASH_ */

49
client/echo.cc Normal file
View file

@ -0,0 +1,49 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
/*
echo is a replacement for the "echo" command builtin to cmd.exe
on Windows, to get a Unix eqvivalent behaviour when running commands
like:
$> echo "hello" | mysql
The windows "echo" would have sent "hello" to mysql while
Unix echo will send hello without the enclosing hyphens
This is a very advanced high tech program so take care when
you change it and remember to valgrind it before production
use.
*/
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++) {
fprintf(stdout, "%s", argv[i]);
if (i < argc - 1) fprintf(stdout, " ");
}
fprintf(stdout, "\n");
return 0;
}

View file

@ -0,0 +1,29 @@
/* Copyright (c) 2022, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
#if defined(_WIN32)
case OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE:
opt_authentication_kerberos_client_mode =
find_type_or_exit(argument, &client_mode_typelib, opt->name) - 1;
break;
#endif

View file

@ -0,0 +1,40 @@
/* Copyright (c) 2022, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
#if defined(_WIN32)
{"plugin_authentication_kerberos_client_mode",
OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE,
"Kerberos authentication mode. Valid values: SSPI, GSSAPI. If not specified, "
"default is SSPI",
nullptr,
nullptr,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
#endif /* _WIN32 */

View file

@ -0,0 +1,71 @@
/* Copyright (c) 2022, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 AUTHETICATION_KERBEROS_CLIENTOPT_VARS_H
#define AUTHETICATION_KERBEROS_CLIENTOPT_VARS_H
#if defined(_WIN32)
#include "m_string.h"
#include "mysql.h"
#include "template_utils.h"
#include "typelib.h"
#include <cstdio>
using std::snprintf;
const char *client_mode_names_lib[] = {"SSPI", "GSSAPI", NullS};
TYPELIB client_mode_typelib = {array_elements(client_mode_names_lib) - 1, "",
client_mode_names_lib, nullptr};
static int opt_authentication_kerberos_client_mode = 0;
static int set_authentication_kerberos_client_mode(MYSQL *mysql, char *error,
size_t error_size) {
if (opt_authentication_kerberos_client_mode == 1) {
struct st_mysql_client_plugin *kerberos_client_plugin =
mysql_client_find_plugin(mysql, "authentication_kerberos_client",
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
if (!kerberos_client_plugin) {
snprintf(error, error_size,
"Failed to load plugin authentication_kerberos_client.");
return 1;
}
if (mysql_plugin_options(
kerberos_client_plugin,
"plugin_authentication_kerberos_client_mode",
client_mode_names_lib[opt_authentication_kerberos_client_mode])) {
snprintf(error, error_size,
"Failed to set value '%s' for "
"--plugin-authentication-kerberos-client-mode",
client_mode_names_lib[opt_authentication_kerberos_client_mode]);
return 1;
}
}
return 0;
}
#endif /* _WIN32 */
#endif // !AUTHETICATION_KERBEROS_CLIENTOPT_VARS_H

View file

@ -0,0 +1,32 @@
/* Copyright (c) 2023, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 AUTHENTICATION_WEBAUTHN_CLIENTOPT_CASE_H
#define AUTHENTICATION_WEBAUTHN_CLIENTOPT_CASE_H
case OPT_AUTHENTICATION_WEBAUTHN_CLIENT_PRESERVE_PRIVACY:
opt_authentication_webauthn_client_preserve_privacy =
(argument != disabled_my_option);
break;
#endif /* AUTHENTICATION_WEBAUTHN_CLIENTOPT_CASE_H */

View file

@ -0,0 +1,44 @@
/* Copyright (c) 2023, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 AUTHENTICATION_WEBAUTHN_CLIENTOPT_LONGOPTS_H
#define AUTHENTICATION_WEBAUTHN_CLIENTOPT_LONGOPTS_H
{"plugin_authentication_webauthn_client_preserve_privacy",
OPT_AUTHENTICATION_WEBAUTHN_CLIENT_PRESERVE_PRIVACY,
"Allows selection of discoverable credential to be used for signing "
"challenge. "
"default is false - implies challenge is signed by all credentials for "
"given relying party.",
&opt_authentication_webauthn_client_preserve_privacy,
&opt_authentication_webauthn_client_preserve_privacy,
nullptr,
GET_BOOL,
NO_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
#endif /* AUTHENTICATION_WEBAUTHN_CLIENTOPT_LONGOPTS_H */

View file

@ -0,0 +1,57 @@
/* Copyright (c) 2023, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 AUTHENTICATION_WEBAUTH_CLIENTOPT_VARS_H
#define AUTHENTICATION_WEBAUTH_CLIENTOPT_VARS_H
#include <cstdio>
#include "mysql.h"
using std::snprintf;
bool opt_authentication_webauthn_client_preserve_privacy = false;
static int set_authentication_webauthn_options(MYSQL *mysql, char *error,
size_t error_size) {
if (opt_authentication_webauthn_client_preserve_privacy) {
struct st_mysql_client_plugin *webauthn_client_plugin =
mysql_client_find_plugin(mysql, "authentication_webauthn_client",
MYSQL_CLIENT_AUTHENTICATION_PLUGIN);
if (!webauthn_client_plugin) {
snprintf(error, error_size,
"Failed to load authentication_webauthn_client.");
return 1;
}
if (mysql_plugin_options(
webauthn_client_plugin,
"authentication_webauthn_client_preserve_privacy",
&opt_authentication_webauthn_client_preserve_privacy)) {
snprintf(error, error_size,
"Failed to set value 'TRUE' for "
"--plugin-authentication-webauthn-client-preserve-privacy");
return 1;
}
}
return 0;
}
#endif /* AUTHENTICATION_WEBAUTH_CLIENTOPT_VARS_H */

View file

@ -0,0 +1,55 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 include/caching_sha2_passwordopt-longopts.h
*/
{"server-public-key-path",
OPT_SERVER_PUBLIC_KEY,
"File path to the server public RSA key in PEM format.",
&opt_server_public_key,
&opt_server_public_key,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"get-server-public-key",
0,
"Get server public key",
&opt_get_server_public_key,
&opt_get_server_public_key,
nullptr,
GET_BOOL,
NO_ARG,
0,
0,
0,
nullptr,
0,
nullptr},

View file

@ -0,0 +1,46 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 include/caching_sha2_passwordopt-vars.h
*/
#include "mysql.h"
static char *opt_server_public_key = nullptr;
static bool opt_get_server_public_key = false;
static void set_server_public_key(MYSQL *mysql,
const char *server_public_key = nullptr) {
if (server_public_key && *server_public_key)
mysql_options(mysql, MYSQL_SERVER_PUBLIC_KEY, server_public_key);
else if (opt_server_public_key && *opt_server_public_key)
mysql_options(mysql, MYSQL_SERVER_PUBLIC_KEY, opt_server_public_key);
}
static void set_get_server_public_key_option(
MYSQL *mysql, const bool *get_server_public_key = nullptr) {
mysql_options(mysql, MYSQL_OPT_GET_SERVER_PUBLIC_KEY,
get_server_public_key ? get_server_public_key
: &opt_get_server_public_key);
}

View file

@ -0,0 +1,240 @@
/*
Copyright (c) 2001, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 CLIENT_PRIV_INCLUDED
#define CLIENT_PRIV_INCLUDED
/* Common defines for all clients */
#include <mysql.h>
#include "errmsg.h"
#include "my_getopt.h"
#include "my_sys.h"
#ifndef WEXITSTATUS
#ifdef _WIN32
#define WEXITSTATUS(stat_val) (stat_val)
#else
#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#endif
enum options_client {
OPT_CHARSETS_DIR = 256,
OPT_DEFAULT_CHARSET,
OPT_PAGER,
OPT_TEE,
OPT_LOW_PRIORITY,
OPT_AUTO_REPAIR,
OPT_COMPRESS,
OPT_DROP,
OPT_LOCKS,
OPT_KEYWORDS,
OPT_OPTIMIZE,
OPT_FTB,
OPT_LTB,
OPT_ENC,
OPT_O_ENC,
OPT_ESC,
OPT_TABLES,
OPT_SOURCE_DATA,
OPT_AUTOCOMMIT,
OPT_AUTO_REHASH,
OPT_LINE_NUMBERS,
OPT_COLUMN_NAMES,
OPT_CONNECT_TIMEOUT,
OPT_MAX_ALLOWED_PACKET,
OPT_NET_BUFFER_LENGTH,
OPT_SELECT_LIMIT,
OPT_MAX_JOIN_SIZE,
OPT_SSL_SSL,
OPT_SSL_KEY,
OPT_SSL_CERT,
OPT_SSL_CA,
OPT_SSL_CAPATH,
OPT_SSL_CIPHER,
OPT_SHUTDOWN_TIMEOUT,
OPT_LOCAL_INFILE,
OPT_DELETE_SOURCE_LOGS,
OPT_COMPACT,
OPT_PROMPT,
OPT_IGN_LINES,
OPT_TRANSACTION,
OPT_MYSQL_PROTOCOL,
OPT_SHARED_MEMORY_BASE_NAME,
OPT_FRM,
OPT_SKIP_OPTIMIZATION,
OPT_COMPATIBLE,
OPT_RECONNECT,
OPT_DELIMITER,
OPT_OPEN_FILES_LIMIT,
OPT_SET_CHARSET,
OPT_SET_GTID_PURGED,
OPT_STOP_POSITION,
OPT_START_DATETIME,
OPT_STOP_DATETIME,
OPT_SIGINT_IGNORE,
OPT_HEXBLOB,
OPT_ORDER_BY_PRIMARY,
OPT_COUNT,
OPT_TRIGGERS,
OPT_MYSQL_ONLY_PRINT,
OPT_MYSQL_LOCK_DIRECTORY,
OPT_USE_THREADS,
OPT_IMPORT_USE_THREADS,
OPT_MYSQL_NUMBER_OF_QUERY,
OPT_IGNORE_TABLE,
OPT_INSERT_IGNORE,
OPT_SHOW_WARNINGS,
OPT_DROP_DATABASE,
OPT_TZ_UTC,
OPT_CREATE_SLAP_SCHEMA,
OPT_MYSQLDUMP_REPLICA_APPLY,
OPT_MYSQLDUMP_REPLICA_DATA,
OPT_MYSQLDUMP_INCLUDE_SOURCE_HOST_PORT,
OPT_MYSQLDUMP_IGNORE_ERROR,
OPT_SLAP_CSV,
OPT_SLAP_CREATE_STRING,
OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
OPT_SLAP_PRE_QUERY,
OPT_SLAP_POST_QUERY,
OPT_SLAP_PRE_SYSTEM,
OPT_SLAP_POST_SYSTEM,
OPT_SLAP_COMMIT,
OPT_SLAP_DETACH,
OPT_SLAP_NO_DROP,
OPT_MYSQL_REPLACE_INTO,
OPT_BASE64_OUTPUT_MODE,
OPT_SERVER_ID,
OPT_FIX_TABLE_NAMES,
OPT_FIX_DB_NAMES,
OPT_SSL_VERIFY_SERVER_CERT,
OPT_AUTO_VERTICAL_OUTPUT,
OPT_DEBUG_INFO,
OPT_DEBUG_CHECK,
OPT_COLUMN_TYPES,
OPT_ERROR_LOG_FILE,
OPT_WRITE_BINLOG,
OPT_DUMP_DATE,
OPT_INIT_COMMAND,
OPT_PLUGIN_DIR,
OPT_DEFAULT_AUTH,
OPT_DEFAULT_PLUGIN,
OPT_RAW_OUTPUT,
OPT_WAIT_SERVER_ID,
OPT_STOP_NEVER,
OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
OPT_HISTIGNORE,
OPT_BINARY_MODE,
OPT_SSL_CRL,
OPT_SSL_CRLPATH,
OPT_MYSQLBINLOG_SKIP_GTIDS,
OPT_MYSQLBINLOG_INCLUDE_GTIDS,
OPT_MYSQLBINLOG_EXCLUDE_GTIDS,
OPT_REMOTE_PROTO,
OPT_CONFIG_ALL,
OPT_REWRITE_DB,
OPT_SERVER_PUBLIC_KEY,
OPT_ENABLE_CLEARTEXT_PLUGIN,
OPT_CONNECTION_SERVER_ID,
OPT_TLS_VERSION,
OPT_SSL_MODE,
OPT_PRINT_TABLE_METADATA,
OPT_SSL_FIPS_MODE,
OPT_TLS_CIPHERSUITES,
OPT_MYSQL_BINARY_AS_HEX,
OPT_LOAD_DATA_LOCAL_DIR,
OPT_READ_FROM_REMOTE_MASTER_DEPRECATED,
OPT_MASTER_DATA_DEPRECATED,
OPT_MYSQLDUMP_SLAVE_APPLY_DEPRECATED,
OPT_DELETE_MASTER_LOGS_DEPRECATED,
OPT_MYSQLDUMP_SLAVE_DATA_DEPRECATED,
OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT_DEPRECATED,
OPT_SSL_SESSION_DATA,
OPT_SSL_SESSION_DATA_CONTINUE_ON_FAILED_REUSE,
OPT_LONG_QUERY_TIME,
OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE,
OPT_TLS_SNI_SERVERNAME,
OPT_INIT_COMMAND_ADD,
OPT_OUTPUT_AS_VERSION,
OPT_AUTHENTICATION_WEBAUTHN_CLIENT_PRESERVE_PRIVACY,
/* Add new option above this */
OPT_MAX_CLIENT_OPTION
};
/**
First mysql version supporting the information schema.
*/
#define FIRST_INFORMATION_SCHEMA_VERSION 50003
/**
Name of the information schema database.
*/
#define INFORMATION_SCHEMA_DB_NAME "information_schema"
/**
First mysql version supporting the performance schema.
*/
#define FIRST_PERFORMANCE_SCHEMA_VERSION 50503
/**
Name of the performance schema database.
*/
#define PERFORMANCE_SCHEMA_DB_NAME "performance_schema"
/**
First mysql version supporting the sys schema.
*/
#define FIRST_SYS_SCHEMA_VERSION 50707
/**
Name of the sys schema database.
*/
#define SYS_SCHEMA_DB_NAME "sys"
/**
Client deprecation warnings
*/
#define CLIENT_WARN_DEPRECATED_NO_REPLACEMENT_MSG(opt) \
opt " is deprecated and will be removed in a future version\n"
#define CLIENT_WARN_DEPRECATED_MSG(opt, new_opt) \
opt " is deprecated and will be removed in a future version. " \
"Use " new_opt " instead.\n"
#define CLIENT_WARN_DEPRECATED_NO_REPLACEMENT(opt) \
fprintf(stderr, "WARNING: " CLIENT_WARN_DEPRECATED_NO_REPLACEMENT_MSG(opt))
#define CLIENT_WARN_DEPRECATED(opt, new_opt) \
fprintf(stderr, "WARNING: " CLIENT_WARN_DEPRECATED_MSG(opt, new_opt))
#endif

View file

@ -0,0 +1,93 @@
/* Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 include/multi_factor_passwordopt-longopts.h
This file contains password options to be specified as part of command-line
options for first,second,third authentication plugin factors for a given user.
*/
/* preserve existing option for backward compatibility */
{"password",
'p',
"Password to use when connecting to server. If password is not given it's "
"asked from the tty.",
nullptr,
nullptr,
nullptr,
GET_PASSWORD,
OPT_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
/*
--password1, --password2 --password3 are new options to handle password for
first, second and third factor authentication plugin defined for a given
user account
*/
{"password1",
MYSQL_OPT_USER_PASSWORD,
"Password for first factor authentication plugin.",
nullptr,
nullptr,
nullptr,
GET_PASSWORD,
OPT_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"password2",
MYSQL_OPT_USER_PASSWORD,
"Password for second factor authentication plugin.",
nullptr,
nullptr,
nullptr,
GET_PASSWORD,
OPT_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"password3",
MYSQL_OPT_USER_PASSWORD,
"Password for third factor authentication plugin.",
nullptr,
nullptr,
nullptr,
GET_PASSWORD,
OPT_ARG,
0,
0,
0,
nullptr,
0,
nullptr},

View file

@ -0,0 +1,48 @@
/* Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 MULTI_FACTOR_PASSWORDOPT_VARS_H
#define MULTI_FACTOR_PASSWORDOPT_VARS_H
#include "mysql.h"
extern char *opt_password[MAX_AUTH_FACTORS];
extern bool tty_password[MAX_AUTH_FACTORS];
/** parse passwords for --password or --password<N> option where N = 1,2,3 */
void parse_command_line_password_option(const struct my_option *opt,
char *argument);
/** Set password in mysql->options */
void set_password_options(MYSQL *mysql);
/** Release memory for opt_password */
void free_passwords();
#define PARSE_COMMAND_LINE_PASSWORD_OPTION \
case 'p': \
parse_command_line_password_option(opt, argument); \
break; \
case MYSQL_OPT_USER_PASSWORD: \
parse_command_line_password_option(opt, argument); \
break;
#endif // MULTI_FACTOR_PASSWORDOPT_VARS_H

View file

@ -0,0 +1,49 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
#ifdef MYSQL_SERVER
#error This header is supposed to be used only in the client
#endif
case OPT_SSL_MODE:
opt_ssl_mode = find_type_or_exit(argument, &ssl_mode_typelib, opt->name);
ssl_mode_set_explicitly = true;
break;
case OPT_SSL_FIPS_MODE:
opt_ssl_fips_mode =
find_type_or_exit(argument, &ssl_fips_mode_typelib, opt->name) - 1;
break;
case OPT_SSL_CA:
case OPT_SSL_CAPATH:
/* Don't change ssl-mode if set explicitly. */
if (!ssl_mode_set_explicitly) opt_ssl_mode = SSL_MODE_VERIFY_CA;
break;
case OPT_SSL_KEY:
case OPT_SSL_CERT:
case OPT_SSL_CIPHER:
case OPT_SSL_CRL:
case OPT_SSL_CRLPATH:
case OPT_TLS_VERSION:
case OPT_SSL_SESSION_DATA:
case OPT_TLS_SNI_SERVERNAME:
break;

View file

@ -0,0 +1,230 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 include/sslopt-longopts.h
*/
{"ssl-mode",
OPT_SSL_MODE,
"SSL connection mode.",
nullptr,
nullptr,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-ca",
OPT_SSL_CA,
"CA file in PEM format.",
&opt_ssl_ca,
&opt_ssl_ca,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-capath",
OPT_SSL_CAPATH,
"CA directory.",
&opt_ssl_capath,
&opt_ssl_capath,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-cert",
OPT_SSL_CERT,
"X509 cert in PEM format.",
&opt_ssl_cert,
&opt_ssl_cert,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-cipher",
OPT_SSL_CIPHER,
"SSL cipher to use.",
&opt_ssl_cipher,
&opt_ssl_cipher,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-key",
OPT_SSL_KEY,
"X509 key in PEM format.",
&opt_ssl_key,
&opt_ssl_key,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-crl",
OPT_SSL_CRL,
"Certificate revocation list.",
&opt_ssl_crl,
&opt_ssl_crl,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-crlpath",
OPT_SSL_CRLPATH,
"Certificate revocation list path.",
&opt_ssl_crlpath,
&opt_ssl_crlpath,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"tls-version",
OPT_TLS_VERSION,
"TLS version to use, "
#ifdef HAVE_TLSv13
"permitted values are: TLSv1.2, TLSv1.3",
#else
"permitted values are: TLSv1.2",
#endif
&opt_tls_version,
&opt_tls_version,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-fips-mode",
OPT_SSL_FIPS_MODE,
"SSL FIPS mode (applies only for OpenSSL); "
"permitted values are: OFF, ON, STRICT",
nullptr,
nullptr,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"tls-ciphersuites",
OPT_TLS_CIPHERSUITES,
"TLS v1.3 cipher to use.",
&opt_tls_ciphersuites,
&opt_tls_ciphersuites,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-session-data",
OPT_SSL_SESSION_DATA,
"Session data file to use to enable ssl session reuse",
&opt_ssl_session_data,
&opt_ssl_session_data,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"ssl-session-data-continue-on-failed-reuse",
OPT_SSL_SESSION_DATA_CONTINUE_ON_FAILED_REUSE,
"If set to ON, this option will allow connection to succeed even if "
"session data cannot be reused.",
&opt_ssl_session_data_continue_on_failed_reuse,
&opt_ssl_session_data_continue_on_failed_reuse,
nullptr,
GET_BOOL,
OPT_ARG,
0,
0,
0,
nullptr,
0,
nullptr},
{"tls-sni-servername",
OPT_TLS_SNI_SERVERNAME,
"The SNI server name to pass to server",
&opt_tls_sni_servername,
&opt_tls_sni_servername,
nullptr,
GET_STR,
REQUIRED_ARG,
0,
0,
0,
nullptr,
0,
nullptr},

View file

@ -0,0 +1,162 @@
/* Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 SSLOPT_VARS_INCLUDED
#define SSLOPT_VARS_INCLUDED
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <functional>
#ifdef MYSQL_SERVER
#error This header is supposed to be used only in the client
#endif
#include "my_inttypes.h"
#include "my_macros.h"
#include "mysql.h"
#include "nulls.h"
#include "template_utils.h"
#include "typelib.h"
const char *ssl_mode_names_lib[] = {"DISABLED", "PREFERRED", "REQUIRED",
"VERIFY_CA", "VERIFY_IDENTITY", NullS};
TYPELIB ssl_mode_typelib = {array_elements(ssl_mode_names_lib) - 1, "",
ssl_mode_names_lib, nullptr};
const char *ssl_fips_mode_names_lib[] = {"OFF", "ON", "STRICT", NullS};
TYPELIB ssl_fips_mode_typelib = {array_elements(ssl_fips_mode_names_lib) - 1,
"", ssl_fips_mode_names_lib, nullptr};
static uint opt_ssl_mode = SSL_MODE_PREFERRED;
static char *opt_ssl_ca = nullptr;
static char *opt_ssl_capath = nullptr;
static char *opt_ssl_cert = nullptr;
static char *opt_ssl_cipher = nullptr;
static char *opt_tls_ciphersuites = nullptr;
static char *opt_ssl_key = nullptr;
static char *opt_ssl_crl = nullptr;
static char *opt_ssl_crlpath = nullptr;
static char *opt_tls_version = nullptr;
static ulong opt_ssl_fips_mode = SSL_FIPS_MODE_OFF;
static bool ssl_mode_set_explicitly = false;
static char *opt_ssl_session_data = nullptr;
static bool opt_ssl_session_data_continue_on_failed_reuse = false;
static char *opt_tls_sni_servername = nullptr;
static inline int set_client_ssl_options(MYSQL *mysql) {
/*
Print a warning if explicitly defined combination of --ssl-mode other than
VERIFY_CA or VERIFY_IDENTITY with explicit --ssl-ca or --ssl-capath values.
*/
if (ssl_mode_set_explicitly && opt_ssl_mode < SSL_MODE_VERIFY_CA &&
(opt_ssl_ca || opt_ssl_capath)) {
fprintf(stderr,
"WARNING: no verification of server certificate will be done. "
"Use --ssl-mode=VERIFY_CA or VERIFY_IDENTITY.\n");
}
/* Set SSL parameters: key, cert, ca, capath, cipher, clr, clrpath. */
mysql_options(mysql, MYSQL_OPT_SSL_KEY, opt_ssl_key);
mysql_options(mysql, MYSQL_OPT_SSL_CERT, opt_ssl_cert);
mysql_options(mysql, MYSQL_OPT_SSL_CIPHER, opt_ssl_cipher);
if (opt_ssl_mode >= SSL_MODE_VERIFY_CA) {
mysql_options(mysql, MYSQL_OPT_SSL_CA, opt_ssl_ca);
mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, opt_ssl_capath);
} else {
mysql_options(mysql, MYSQL_OPT_SSL_CA, nullptr);
mysql_options(mysql, MYSQL_OPT_SSL_CAPATH, nullptr);
}
mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
mysql_options(mysql, MYSQL_OPT_TLS_VERSION, opt_tls_version);
mysql_options(mysql, MYSQL_OPT_SSL_MODE, &opt_ssl_mode);
if (opt_ssl_fips_mode > 0) {
mysql_options(mysql, MYSQL_OPT_SSL_FIPS_MODE, &opt_ssl_fips_mode);
if (mysql_errno(mysql) == CR_SSL_FIPS_MODE_ERR) return 1;
}
mysql_options(mysql, MYSQL_OPT_TLS_CIPHERSUITES, opt_tls_ciphersuites);
mysql_options(mysql, MYSQL_OPT_TLS_SNI_SERVERNAME, opt_tls_sni_servername);
if (opt_ssl_session_data) {
FILE *fi = fopen(opt_ssl_session_data, "rb");
char buff[4096], *bufptr = &buff[0];
size_t read = 0;
if (!fi) {
fprintf(stderr, "Error: Can't open the ssl session data file.\n");
return 1;
}
long file_length = sizeof(buff) - 1;
if (0 == fseek(fi, 0, SEEK_END)) {
file_length = ftell(fi);
if (file_length > 0)
file_length = std::min(file_length, 65536L);
else
file_length = sizeof(buff) - 1;
fseek(fi, 0, SEEK_SET);
}
if (file_length > (long)(sizeof(buff) - 1)) {
bufptr = (char *)malloc(file_length + 1);
if (bufptr)
bufptr[file_length] = 0;
else {
bufptr = &buff[0];
file_length = sizeof(buff) - 1;
}
}
read = fread(bufptr, 1, file_length, fi);
if (!read) {
fprintf(stderr, "Error: Can't read the ssl session data file.\n");
fclose(fi);
if (bufptr != &buff[0]) free(bufptr);
return 1;
}
assert(read <= (size_t)file_length);
bufptr[read] = 0;
fclose(fi);
int ret = 0;
if (read) ret = mysql_options(mysql, MYSQL_OPT_SSL_SESSION_DATA, buff);
if (bufptr != &buff[0]) free(bufptr);
return ret;
}
return 0;
}
inline static bool ssl_client_check_post_connect_ssl_setup(
MYSQL *mysql, std::function<void(const char *)> report_error) {
if (opt_ssl_session_data && !opt_ssl_session_data_continue_on_failed_reuse &&
!mysql_get_ssl_session_reused(mysql)) {
report_error(
"--ssl-session-data specified but the session was not reused.");
return true;
}
return false;
}
#define SSL_SET_OPTIONS(mysql) set_client_ssl_options(mysql)
const char *SSL_SET_OPTIONS_ERROR = "Failed to set ssl related options.\n";
#endif /* SSLOPT_VARS_INCLUDED */

View file

@ -0,0 +1,34 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 USER_REGISTRATION_H_
#define USER_REGISTRATION_H_
#include <mysql.h>
bool user_device_registration(MYSQL *mysql_handle, char *register_option,
char *errmsg);
#endif // USER_REGISTRATION_H_

58
client/infix_ostream_it.h Normal file
View file

@ -0,0 +1,58 @@
/*
Copyright (c) 2012, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 INFIX_OSTREAM_IT_INCLUDED
#define INFIX_OSTREAM_IT_INCLUDED
#include <iterator>
#include <ostream>
#include <string>
template <class T>
class infix_ostream_iterator
: public std::iterator<std::output_iterator_tag, T> {
public:
explicit infix_ostream_iterator(std::ostream &s) : m_os(&s) {}
infix_ostream_iterator(std::ostream &s, const char *d)
: m_os(&s), m_delimiter(d) {}
infix_ostream_iterator<T> &operator=(T const &item) {
*m_os << m_curr_delimiter << item;
m_curr_delimiter = m_delimiter;
return *this;
}
infix_ostream_iterator<T> &operator*() { return *this; }
infix_ostream_iterator<T> &operator++() { return *this; }
infix_ostream_iterator<T> &operator++(int) { return *this; }
private:
std::ostream *m_os;
std::string m_curr_delimiter;
std::string m_delimiter;
};
#endif

42
client/json_binlog.ver Normal file
View file

@ -0,0 +1,42 @@
/* Copyright (c) 2020, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
/*
These are the functions used by mysqlbinlog:
Json_wrapper::to_string(String*, bool, char const*) const
Json_wrapper::type() const
Json_wrapper::Json_wrapper(json_binary::Value const&)
Json_wrapper::~Json_wrapper()
json_binary::parse_binary(char const*, unsigned long)
*/
{
global:
extern "C++" {
*Json_wrapper*;
json_binary::*;
};
local:
*;
};

View file

@ -0,0 +1,65 @@
/* Copyright (c) 2020, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
/*
This is a test executable which does nothing, except verify that symbols are
visible. See the accompanying cmake rules.
Instantiated Value objects are bad, running this executable will fail.
*/
#include <stdlib.h>
#include <string>
#include "sql-common/json_binary.h"
int main() {
json_binary::Value value = json_binary::parse_binary(nullptr, 0);
const bool is_valid = value.is_valid();
const json_binary::Value::enum_type enum_type = value.type();
value = json_binary::Value(json_binary::Value::OBJECT, nullptr, 0, 1, false);
const json_binary::Value elt1 = value.element(1);
const json_binary::Value key1 = value.key(1);
const size_t sz1 = value.lookup_index("foo", 3);
const size_t sz2 = value.lookup_index(std::string("foo"));
const bool has_space = value.has_space(0, 0, nullptr);
const json_binary::Value null_value =
json_binary::Value(json_binary::Value::LITERAL_NULL);
const json_binary::Value int_value =
json_binary::Value(json_binary::Value::INT, 42);
const json_binary::Value double_value = json_binary::Value(0.0);
const json_binary::Value string_value = json_binary::Value("foo", 3);
std::string string_buf;
string_value.to_std_string(&string_buf, [] { assert(false); });
string_value.to_pretty_std_string(&string_buf, [] { assert(false); });
return 0;
}

View file

@ -0,0 +1,322 @@
/* Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 */
/*
This is a test executable which verifies that Json_wrapper::seek,
Json_dom::seek, Json_dom::parse, json_binary::parse_binary,
json_binary::serialize functions are visible and can be called.
*/
#include <cassert>
#include <cstring>
#include <iostream>
#include <memory>
#include <new>
#include <string>
#include <string_view>
#include <utility>
#include "field_types.h"
#include "mysql/components/services/bits/psi_bits.h"
#include "mysql_time.h"
#include "sql-common/json_binary.h"
#include "sql-common/json_dom.h"
#include "sql-common/json_error_handler.h"
#include "sql-common/json_path.h"
#include "sql-common/my_decimal.h"
#include "sql_string.h"
#include "template_utils.h"
namespace {
void CoutDefaultDepthHandler() { std::cout << "Doc too deep"; }
class CoutSerializationErrorHandler : public JsonSerializationErrorHandler {
public:
void KeyTooBig() const override { std::cout << "Key too big"; }
void ValueTooBig() const override { std::cout << "Value too big"; }
void TooDeep() const override { CoutDefaultDepthHandler(); }
void InvalidJson() const override { std::cout << "Invalid JSON"; }
void InternalError(const char *message) const override {
std::cout << "Internal error: " << message;
}
bool CheckStack() const override {
std::cout << "Checking stack\n";
return false;
}
};
} // namespace
int main() {
Json_object o;
for (size_t i = 0; i < 1000; ++i) {
o.add_alias(std::to_string(i),
new (std::nothrow)
Json_string(std::string("key_") + std::to_string(i)));
}
// Make sure Json_wrapper::seek is visible
Json_wrapper_vector hits(PSI_NOT_INSTRUMENTED);
const bool need_only_one{false};
const char *json_path = R"($**."512")";
Json_path path(PSI_NOT_INSTRUMENTED);
size_t bad_index;
parse_path(std::strlen(json_path), json_path, &path, &bad_index);
Json_wrapper wr(&o);
wr.set_alias();
StringBuffer<20000> buf;
if (wr.to_binary(CoutSerializationErrorHandler(), &buf)) {
std::cout << "error";
} else {
const json_binary::Value v(
json_binary::parse_binary(buf.ptr(), buf.length()));
std::string std_string;
v.to_pretty_std_string(&std_string, CoutDefaultDepthHandler);
std::cout << "1. Binary_val[" << std_string << "]" << std::endl;
}
wr.seek(path, path.leg_count(), &hits, true, need_only_one);
for (auto &hit : hits) {
String buffer;
hit.to_string(&buffer, false, nullptr, [] { assert(false); });
std::cout << std::string_view{buffer.ptr(), buffer.length()} << std::endl;
}
// Make sure Json_dom::parse is visible and error handling works
{
const std::string json{"[{\"key\":123},146]"};
Json_dom_ptr dom(Json_dom::parse(
json.c_str(), json.length(),
[](const char *, size_t) { assert(false); }, [] { assert(false); }));
if (dom != nullptr) std::cout << "1. success" << std::endl;
}
{
const std::string json{
"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[["
R"([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{"key":123}]]]]]]]]]]]]]]]]]]]]]]]]]])"
"]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]"
"]]]]"};
Json_dom_ptr dom(Json_dom::parse(
json.c_str(), json.length(),
[](const char *err_mesg, size_t err_code) {
std::cout << "2. parse_error [" << err_code << "]: " << err_mesg
<< std::endl;
},
[] { std::cout << "2. depth_error" << std::endl; }));
if (dom != nullptr) assert(false);
}
{
const std::string json{"[&&"};
Json_dom_ptr dom(Json_dom::parse(
json.c_str(), json.length(),
[](const char *err_mesg, size_t err_code) {
std::cout << "3. parse_error [" << err_code << "]: " << err_mesg
<< std::endl;
},
[] { assert(false); }));
if (dom != nullptr) assert(false);
}
{
my_decimal m;
double2my_decimal(0, 3.14000000001, &m);
const Json_decimal jd(m);
if (json_binary::serialize(&jd, CoutSerializationErrorHandler(), &buf))
std::cout << "ERRROR!!" << std::endl;
json_binary::Value v = json_binary::parse_binary(buf.ptr(), buf.length());
std::string std_string;
if (v.to_std_string(&std_string, CoutDefaultDepthHandler))
std::cout << "ERRROR!!" << std::endl;
std::cout << "4. val[" << std_string << "]" << std::endl;
}
{
/* DATETIME scalar */
MYSQL_TIME dt;
std::memset(&dt, 0, sizeof dt);
dt.year = 1988;
dt.month = 12;
dt.day = 15;
dt.time_type = MYSQL_TIMESTAMP_DATE;
const Json_datetime jd(dt, MYSQL_TYPE_DATETIME);
if (json_binary::serialize(&jd, CoutSerializationErrorHandler(), &buf))
std::cout << "ERRROR!!" << std::endl;
json_binary::Value v = json_binary::parse_binary(buf.ptr(), buf.length());
// Test call to get_free_space.
size_t free_space;
v.get_free_space(CoutSerializationErrorHandler(), &free_space);
std::cout << "5.1. free space: " << free_space << std::endl;
std::string std_string;
if (v.to_pretty_std_string(&std_string, CoutDefaultDepthHandler))
std::cout << "ERRROR!!" << std::endl;
std::cout << "5.2. val[" << std_string << "]" << std::endl;
}
// Test if contains_wr is exposed
{
const std::string json_1{"[{\"key\":123},146]"};
Json_dom_ptr dom1(Json_dom::parse(
json_1.c_str(), json_1.length(),
[](const char *, size_t) { assert(false); }, [] { assert(false); }));
Json_wrapper json_wrapper = Json_wrapper(std::move(dom1));
const std::string json_2{"{\"key\":123}"};
Json_dom_ptr dom2(Json_dom::parse(
json_2.c_str(), json_2.length(),
[](const char *, size_t) { assert(false); }, [] { assert(false); }));
Json_wrapper json_containee = Json_wrapper(std::move(dom2));
bool result;
if (json_wrapper_contains(json_wrapper, json_containee, &result)) {
assert(false);
} else {
std::cout << "6.1. it is: " << std::boolalpha << result
<< " that json_1 contains json_2\n";
}
if (json_wrapper_contains(json_containee, json_wrapper, &result)) {
assert(false);
} else {
std::cout << "6.2. it is: " << std::boolalpha << result
<< " that json_2 contains json_1\n";
}
}
{
const std::string json{"[\"Alice2\", 225, 165.5, 155.2, \"female\"]"};
Json_dom_ptr dom(Json_dom::parse(
json.c_str(), json.length(),
[](const char *, size_t) { assert(false); }, [] { assert(false); }));
Json_array *arr = down_cast<Json_array *>(dom.get());
Json_dom_ptr dom1(Json_dom::parse(
"1", 1, [](const char *, size_t) { assert(false); },
[] { assert(false); }));
Json_dom_ptr dom2(Json_dom::parse(
"155.2", 5, [](const char *, size_t) { assert(false); },
[] { assert(false); }));
// Sort array and use binary search to lookup values
arr->sort();
bool result = arr->binary_search(dom1.get());
std::cout << "7.1. it is: " << std::boolalpha << result
<< " that array contains 1\n";
result = arr->binary_search(dom2.get());
std::cout << "7.2. it is: " << std::boolalpha << result
<< " that array contains 155.2\n";
}
// Make sure json_type_name() is visible.
{
std::cout << "8.1. Type of empty wrapper is "
<< json_type_name(Json_wrapper{}) << ".\n";
{
Json_array array;
std::cout << "8.2. Type of array is "
<< json_type_name(Json_wrapper{&array, /*alias=*/true})
<< ".\n";
}
{
Json_string string;
std::cout << "8.3. Type of string is "
<< json_type_name(Json_wrapper{&string, /*alias=*/true})
<< ".\n";
}
{
Json_opaque blob{MYSQL_TYPE_BLOB};
std::cout << "8.4. Type of blob is "
<< json_type_name(Json_wrapper{&blob, /*alias=*/true}) << ".\n";
}
}
// Make sure coerce_* functions are visible.
{
{
Json_wrapper jw = Json_wrapper(
create_dom_ptr<Json_string>("2015-01-15 23:24:25.000000"));
MYSQL_TIME ltime;
bool res = jw.coerce_date(
[](const char *, int) { std::cout << "9.1. ERROR \n"; },
[](MYSQL_TIME_STATUS &) { std::cout << "9.1. checking \n"; }, &ltime);
std::cout << "9.1. 2015-01-15 23:24:25.000000 is" << (res ? " NOT " : " ")
<< "a valid DATE \n";
}
{
Json_wrapper jw = Json_wrapper(
create_dom_ptr<Json_string>("2015-99-15 23:24:25.000000"));
MYSQL_TIME ltime;
bool res = jw.coerce_date(
[](const char *, int) { std::cout << "9.2. ERROR \n"; },
[](MYSQL_TIME_STATUS &) { std::cout << "9.2. checking \n"; }, &ltime);
std::cout << "9.2. 2015-99-15 23:24:25.000000 is" << (res ? " NOT " : " ")
<< "a valid DATE \n";
}
{
Json_wrapper jw = Json_wrapper(
create_dom_ptr<Json_string>("2015-99-15 23:24:25.000000"));
double res = jw.coerce_real(
[](const char *, int) { std::cout << "9.3. ERROR \n"; });
std::cout << "9.3. 2015-99-15 23:24:25.000000 coerced to DOUBLE is "
<< res << "\n";
}
{
Json_wrapper jw =
Json_wrapper(create_dom_ptr<Json_string>("1988.9999999"));
my_decimal dec;
jw.coerce_decimal([](const char *, int) { std::cout << "9.4. ERROR \n"; },
&dec);
int len = 128;
const std::unique_ptr<char[]> buff(new char[len]{'\0'});
decimal2string(&dec, buff.get(), &len);
std::cout << "9.4. 1988.9999999 coerced to DECIMAL is " << buff << "\n";
}
{
Json_wrapper jw = Json_wrapper(create_dom_ptr<Json_string>("1988"));
double res = jw.coerce_int(
[](const char *, int) { std::cout << "9.5. ERROR \n"; });
std::cout << "9.5. 1988 coerced to INTEGER is " << res << "\n";
}
{
Json_wrapper jw = Json_wrapper(
create_dom_ptr<Json_string>("2015-01-15 23:24:25.000000"));
MYSQL_TIME ltime;
bool res = jw.coerce_time(
[](const char *, int) { std::cout << "9.6. ERROR \n"; },
[](MYSQL_TIME_STATUS &) { std::cout << "9.6. checking \n"; }, &ltime);
std::cout << "9.6. 2023-12-11 09:23:00.360900 is" << (res ? " NOT " : " ")
<< "a valid TIME \n";
}
}
return 0;
}

61
client/logger.cc Normal file
View file

@ -0,0 +1,61 @@
/*
Copyright (c) 2015, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "client/logger.h"
#include <time.h>
#include <iostream>
#include <locale>
#include <memory>
using namespace std;
ostream &operator<<(ostream &os, const Datetime &) {
const char format[] = "%Y-%m-%d %X";
const time_t t(time(nullptr));
const tm tm(*localtime(&t));
const size_t date_length{50};
const std::unique_ptr<char[]> date{new char[date_length]};
strftime(date.get(), date_length, format, &tm);
os << date.get() << " ";
return os;
}
ostream &operator<<(ostream &os, const Gen_spaces &gen) {
return os << gen.m_spaces;
}
int Log::Log_buff::sync() {
const string sout(str());
if (m_enabled && sout.length() > 0) {
m_os << Datetime() << "[" << m_logc << "]"
<< Gen_spaces(8 - m_logc.length()) << sout;
}
str("");
m_os.flush();
return 0;
}

76
client/logger.h Normal file
View file

@ -0,0 +1,76 @@
#ifndef LOGGER_UTIL_INCLUDED
#define LOGGER_UTIL_INCLUDED
/*
Copyright (c) 2015, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <stddef.h>
#include <ostream>
#include <sstream>
#include <string>
struct Datetime {};
std::ostream &operator<<(std::ostream &os, const Datetime &dt);
class Gen_spaces {
public:
explicit Gen_spaces(int s) { m_spaces.assign(s, ' '); }
std::ostream &operator<<(std::ostream &os) { return os; }
friend std::ostream &operator<<(std::ostream &os, const Gen_spaces &gen);
private:
std::string m_spaces;
};
std::ostream &operator<<(std::ostream &os, const Gen_spaces &gen);
class Log : public std::ostream {
public:
Log(std::ostream &str, std::string logclass)
: std::ostream(nullptr), m_buffer(str, logclass) {
this->init(&m_buffer);
}
void enabled(bool s) { m_buffer.enabled(s); }
private:
class Log_buff : public std::stringbuf {
public:
Log_buff(std::ostream &str, std::string &logc)
: m_os(str), m_logc(logc), m_enabled(true) {}
void set_log_class(std::string &s) { m_logc = s; }
void enabled(bool s) { m_enabled = s; }
bool is_enabled() { return m_enabled; }
int sync() override;
private:
std::ostream &m_os;
std::string m_logc;
bool m_enabled;
};
Log_buff m_buffer;
};
#endif /* LOGGER_UTIL_INCLUDED */

View file

@ -0,0 +1,51 @@
# Copyright (c) 2021, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
ADD_WSHADOW_WARNING()
SET(MIGRATE_KEYRING_SOURCE
# Logger
${CMAKE_CURRENT_SOURCE_DIR}/../logger.cc
# Options handling
options.cc
# Components subsystem
components.cc
# Main
migrate_keyring.cc
)
SET(MIGRATE_KEYRING_LIBRARIES
${CMAKE_DL_LIBS}
minchassis
mysys
mysqlclient
OpenSSL::SSL OpenSSL::Crypto
)
MYSQL_ADD_EXECUTABLE(mysql_migrate_keyring
${MIGRATE_KEYRING_SOURCE}
LINK_LIBRARIES ${MIGRATE_KEYRING_LIBRARIES}
)

View file

@ -0,0 +1,382 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <scope_guard.h>
#include "components.h"
#include "options.h" /* command line options */
#include "utilities.h" /* Error logging */
using options::Options;
namespace components {
registry_type_t *components_registry = nullptr;
dynamic_loader_type_t *components_dynamic_loader = nullptr;
void init_components_subsystem() {
minimal_chassis_init((&components_registry), nullptr);
components_registry->acquire(
"dynamic_loader",
reinterpret_cast<my_h_service *>(&components_dynamic_loader));
}
void deinit_components_subsystem() {
components_registry->release(
reinterpret_cast<my_h_service>(components_dynamic_loader));
minimal_chassis_deinit(components_registry, nullptr);
}
Keyring_component_load::Keyring_component_load(const std::string component_name,
const std::string type)
: dynamic_loader_(components_dynamic_loader),
component_path_("file://"),
type_(type) {
if (Options::s_component_dir != nullptr)
component_path_.append(Options::s_component_dir);
component_path_ += "/" + component_name;
log_debug << "Loading: " << component_path_ << std::endl;
const char *urn[] = {component_path_.c_str()};
const bool load_status = dynamic_loader_->load(urn, 1);
if (load_status)
log_error << "Failed to load " << type_ << " keyring: " << component_path_
<< std::endl;
else
log_debug << "Successfully loaded " << type_
<< " keyring: " << component_path_ << std::endl;
ok_ = !load_status;
}
Keyring_component_load::~Keyring_component_load() {
if (ok_) {
const char *urn[] = {component_path_.c_str()};
log_debug << "Unloading: " << component_path_ << std::endl;
const bool load_status = dynamic_loader_->unload(urn, 1);
if (load_status)
log_error << "Failed to unload " << type_
<< " keyring: " << component_path_ << std::endl;
else
log_debug << "Successfully unloaded " << type_
<< " keyring: " << component_path_ << std::endl;
ok_ = false;
}
}
Keyring_services::Keyring_services(const std::string implementation_name,
const std::string instance_path)
: registry_(components_registry),
implementation_name_(implementation_name),
keyring_load_service_(
std::string{"keyring_load."}.append(implementation_name).c_str(),
registry_),
ok_(false) {
if (keyring_load_service_) {
log_error << "Failed to acquire keyring_load service" << std::endl;
return;
}
if (keyring_load_service_->load(
Options::s_component_dir,
instance_path.length() ? instance_path.c_str() : nullptr) != 0) {
const std::string message("Failed to initialize keyring");
log_error << message << std::endl;
return;
}
log_debug << "Successfully acquired keyring error service handles for "
<< implementation_name_ << std::endl;
ok_ = true;
}
Keyring_services::~Keyring_services() {
ok_ = false;
if (!registry_) return;
log_debug << "Successfully released keyring error service handles for "
<< implementation_name_ << std::endl;
}
Source_keyring_services::Source_keyring_services(
const std::string implementation_name, const std::string instance_path)
: Keyring_services(implementation_name, instance_path),
keyring_keys_metadata_service_("keyring_keys_metadata_iterator",
keyring_load_service_, registry_),
keyring_reader_service_("keyring_reader_with_status",
keyring_load_service_, registry_) {
if (keyring_keys_metadata_service_ || keyring_reader_service_) {
log_error << "Failed to acquire keyring metadata iterator and keyring "
"reader services for "
<< implementation_name_ << std::endl;
ok_ = false;
return;
}
log_debug << "Successfully acquired keyring metarata iterator and kering "
"reader services' handles for "
<< implementation_name_ << std::endl;
}
Source_keyring_services::~Source_keyring_services() {
if (registry_ == nullptr) return;
log_debug << "Successfully released keyring metadata iterator and reader "
"service handles for "
<< implementation_name_ << std::endl;
}
Destination_keyring_services::Destination_keyring_services(
const std::string implementation_name, const std::string instance_path)
: Keyring_services(implementation_name, instance_path),
keyring_writer_service_("keyring_writer", keyring_load_service_,
registry_) {
if (keyring_writer_service_) {
log_error << "Failed to acquire keyring writer service handle for "
<< implementation_name_ << std::endl;
ok_ = false;
return;
}
log_debug << "Successfully acquired keyring writer service handle for "
<< implementation_name_ << std::endl;
}
Destination_keyring_services::~Destination_keyring_services() {
if (!registry_) return;
log_debug << "Successfully released keyring writer service handle for "
<< implementation_name_ << std::endl;
}
Keyring_migrate::Keyring_migrate(Source_keyring_services &src,
Destination_keyring_services &dst,
bool online_migration)
: src_(src), dst_(dst), mysql_connection_(online_migration) {
if (!src_.ok() || !dst_.ok()) return;
if (online_migration && !mysql_connection_.ok()) return;
if (lock_source_keyring() == false) {
log_error << "Failed to lock source keyring" << std::endl;
return;
}
auto iterator = src_.metadata_iterator();
if (iterator->init(&iterator_) != 0) {
log_error << "Error creating source keyring iterator" << std::endl;
return;
}
ok_ = true;
}
bool Keyring_migrate::lock_source_keyring() {
if (Options::s_online_migration == false) return true;
if (!mysql_connection_.ok()) return false;
const std::string lock_statement("SET GLOBAL KEYRING_OPERATIONS=0");
return mysql_connection_.execute(lock_statement);
}
bool Keyring_migrate::unlock_source_keyring() {
if (Options::s_online_migration == false || !mysql_connection_.ok())
return true;
const std::string unlock_statement("SET GLOBAL KEYRING_OPERATIONS=1");
return mysql_connection_.execute(unlock_statement);
}
bool Keyring_migrate::migrate_keys() {
if (!ok_)
log_error << "Cannot migrate keys. Check that source and destination "
"keyrings are initialized properly."
<< std::endl;
auto metadata_iterator = src_.metadata_iterator();
auto reader = src_.reader();
auto writer = dst_.writer();
size_t migrated_count = 0;
size_t skipped_count = 0;
bool retval = true;
bool next_ok = true;
size_t data_id_length = 0;
size_t auth_id_length = 0;
for (; metadata_iterator->is_valid(iterator_) && next_ok;
next_ok = !metadata_iterator->next(iterator_)) {
data_id_length = 0;
auth_id_length = 0;
/* Fetch length */
if (metadata_iterator->get_length(iterator_, &data_id_length,
&auth_id_length) != 0) {
log_error << "Could not fetch next available key content from keyring"
<< std::endl;
retval = false;
break;
}
const std::unique_ptr<char[]> data_id(new char[data_id_length + 1]);
const std::unique_ptr<char[]> auth_id(new char[auth_id_length + 1]);
if (data_id.get() == nullptr || auth_id.get() == nullptr) {
log_error << "Failed to allocated required memory for data_id and auth_id"
<< std::endl;
retval = false;
break;
}
/* Fetch metadata of next available key */
if (metadata_iterator->get(iterator_, data_id.get(), data_id_length + 1,
auth_id.get(), auth_id_length + 1) != 0) {
log_error << "Could not fetch next available key content from keyring"
<< std::endl;
retval = false;
break;
}
/* Fetch key details */
my_h_keyring_reader_object reader_object = nullptr;
const bool status =
reader->init(data_id.get(), auth_id.get(), &reader_object);
if (status == true) {
log_error << "Keyring reported error" << std::endl;
retval = false;
break;
}
if (reader_object == nullptr) {
log_warning << "Could not find data pointed by data_id: " << data_id.get()
<< ", auth_id: " << auth_id.get() << ". Skipping"
<< std::endl;
++skipped_count;
continue;
}
auto cleanup_guard = create_scope_guard([&] {
if (reader_object != nullptr) {
if (reader->deinit(reader_object) != 0)
log_error << "Failed to deallocated reader_object" << std::endl;
}
reader_object = nullptr;
});
size_t data_size, data_type_size;
if (reader->fetch_length(reader_object, &data_size, &data_type_size) != 0) {
log_warning << "Could not find data pointed by data_id: " << data_id.get()
<< ", auth_id: " << auth_id.get() << ". Skipping"
<< std::endl;
++skipped_count;
continue;
}
if (data_size > maximum_size_) {
log_warning << "Length (" << data_size
<< ") of data identified by data_id: " << data_id.get()
<< ", auth_id: " << auth_id.get()
<< " exceeds maximum supported"
" length by migration tool ("
<< maximum_size_ << "). Skipping" << std::endl;
++skipped_count;
continue;
}
const std::unique_ptr<unsigned char[]> data_buffer(
new unsigned char[data_size]);
const std::unique_ptr<char[]> data_type_buffer(
new char[data_type_size + 1]);
if (data_buffer.get() == nullptr || data_type_buffer.get() == nullptr) {
log_error << "Failed to allocated required memory for data pointed by "
"data_id: "
<< data_id.get() << ", auth_id: " << auth_id.get()
<< ". Stopping." << std::endl;
retval = false;
break;
}
memset(data_buffer.get(), 0, data_size);
memset(data_type_buffer.get(), 0, data_type_size + 1);
if (reader->fetch(reader_object, data_buffer.get(), data_size, &data_size,
data_type_buffer.get(), data_type_size + 1,
&data_type_size) != 0) {
log_warning << "Could not find data pointed by data_id: " << data_id.get()
<< ", auth_id: " << auth_id.get() << ". Skipping"
<< std::endl;
++skipped_count;
continue;
}
/* Write to destination keyring */
if (data_size > 0 && data_type_size > 0) {
const bool write_status =
writer->store(data_id.get(), auth_id.get(), data_buffer.get(),
data_size, data_type_buffer.get());
memset(data_buffer.get(), 0, data_size);
memset(data_type_buffer.get(), 0, data_type_size + 1);
if (write_status == true) {
log_error << "Failed to write data pointed by data_id: "
<< data_id.get() << ", auth_id: " << auth_id.get()
<< " into destination keyring" << std::endl;
retval = false;
break;
}
log_debug << "Successfully migrated data with data_id: " << data_id.get()
<< ", auth_id: " << auth_id.get() << "." << std::endl;
}
++migrated_count;
}
if (metadata_iterator->deinit(iterator_) != 0) {
log_error << "Failed to deinitialize source iterator" << std::endl;
retval = false;
}
iterator_ = nullptr;
if (retval) {
log_info << "Successfully migrated " << migrated_count << " keys. Skipped "
<< skipped_count << " keys." << std::endl;
} else {
log_error << "Failed to migrate all keys to destination keyring. Please "
"check log for more details"
<< std::endl;
}
return retval;
}
Keyring_migrate::~Keyring_migrate() {
if (unlock_source_keyring() == false) {
log_error << "Failed to unlock source keyring. Please unlock it manually."
<< std::endl;
}
}
} // namespace components

View file

@ -0,0 +1,149 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 COMPONENTS_INCLUDED
#define COMPONENTS_INCLUDED
#include <mysql/components/minimal_chassis.h> /* Minimal chassis */
#include <mysql/components/my_service.h>
#include <mysql/components/services/keyring_keys_metadata_iterator.h>
#include <mysql/components/services/keyring_load.h>
#include <mysql/components/services/keyring_reader_with_status.h>
#include <mysql/components/services/keyring_writer.h>
#include "client/logger.h" /* Log */
#include "options.h" /* Mysql_connection */
namespace components {
using registry_type_t = SERVICE_TYPE_NO_CONST(registry);
using dynamic_loader_type_t = SERVICE_TYPE_NO_CONST(dynamic_loader);
using keyring_load_t = SERVICE_TYPE_NO_CONST(keyring_load);
using keyring_keys_metadata_iterator_t =
SERVICE_TYPE_NO_CONST(keyring_keys_metadata_iterator);
using keyring_reader_with_status_t =
SERVICE_TYPE_NO_CONST(keyring_reader_with_status);
using keyring_writer_t = SERVICE_TYPE_NO_CONST(keyring_writer);
using const_registry_type_t = SERVICE_TYPE(registry);
using const_dynamic_loader_type_t = SERVICE_TYPE(dynamic_loader);
using const_keyring_keys_metadata_iterator_t =
SERVICE_TYPE(keyring_keys_metadata_iterator);
using const_keyring_load_t = SERVICE_TYPE(keyring_load);
using const_keyring_reader_with_status_t =
SERVICE_TYPE(keyring_reader_with_status);
using const_keyring_writer_t = SERVICE_TYPE(keyring_writer);
void init_components_subsystem();
void deinit_components_subsystem();
class Keyring_component_load final {
public:
Keyring_component_load(const std::string component_name,
const std::string type);
~Keyring_component_load();
bool ok() { return ok_; }
private:
dynamic_loader_type_t *dynamic_loader_;
std::string component_path_;
std::string type_;
bool ok_;
};
class Keyring_services {
public:
Keyring_services(const std::string implementation_name,
const std::string instance_path);
virtual ~Keyring_services();
bool ok() { return ok_; }
protected:
registry_type_t *registry_;
std::string implementation_name_;
my_service<const_keyring_load_t> keyring_load_service_;
bool ok_;
};
class Source_keyring_services final : public Keyring_services {
public:
Source_keyring_services(const std::string implementation_name,
const std::string instance_path);
~Source_keyring_services();
const_keyring_keys_metadata_iterator_t *metadata_iterator() {
return keyring_keys_metadata_service_;
}
const_keyring_reader_with_status_t *reader() {
return keyring_reader_service_;
}
private:
my_service<const_keyring_keys_metadata_iterator_t>
keyring_keys_metadata_service_;
my_service<const_keyring_reader_with_status_t> keyring_reader_service_;
};
class Destination_keyring_services final : public Keyring_services {
public:
Destination_keyring_services(const std::string implementation_name,
const std::string instance_path);
~Destination_keyring_services();
const_keyring_writer_t *writer() { return keyring_writer_service_; }
private:
my_service<const_keyring_writer_t> keyring_writer_service_;
};
class Keyring_migrate final {
public:
Keyring_migrate(Source_keyring_services &src,
Destination_keyring_services &dst, bool online_migration);
bool migrate_keys();
~Keyring_migrate();
bool lock_source_keyring();
bool unlock_source_keyring();
bool ok() { return ok_; }
private:
Source_keyring_services &src_;
Destination_keyring_services &dst_;
my_h_keyring_keys_metadata_iterator iterator_{nullptr};
options::Mysql_connection mysql_connection_;
bool ok_{false};
const size_t maximum_size_{16384};
};
} // namespace components
#endif // !COMPONENTS_INCLUDED

View file

@ -0,0 +1,146 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <cstdlib>
#include <iostream>
#include <memory>
#include <string>
/* <openssl/applink.c> is included in client library */
#include <my_dbug.h> /* DEBUG macros */
#include <my_sys.h> /* MY_INIT */
#include <scope_guard.h>
#include "components.h"
#include "options.h"
#include "utilities.h"
using components::deinit_components_subsystem;
using components::Destination_keyring_services;
using components::init_components_subsystem;
using components::Keyring_component_load;
using components::Keyring_migrate;
using components::Source_keyring_services;
using options::deinit_connection_basic;
using options::init_connection_basic;
using options::Options;
using options::process_options;
Log log_debug(std::cout, "DEBUG");
Log log_info(std::cout, "NOTE");
Log log_warning(std::cerr, "WARNING");
Log log_error(std::cerr, "ERROR");
class Migration_setup {
public:
explicit Migration_setup(char *progname) {
MY_INIT(progname);
init_components_subsystem();
init_connection_basic();
log_debug.enabled(false);
}
~Migration_setup() {
deinit_connection_basic();
deinit_components_subsystem();
my_end(0);
}
};
int main(int argc, char **argv) {
/* Initialization */
const Migration_setup migration_setup(argv[0]);
DBUG_TRACE;
DBUG_PROCESS(argv[0]);
const int exit_status = EXIT_FAILURE;
int exit_code;
if (process_options(&argc, &argv, exit_code) == false) {
return exit_code;
}
{
Keyring_component_load source_component_load(Options::s_source_keyring,
"source");
if (!source_component_load.ok()) {
log_error << "Error loading source keyring component. Exiting."
<< std::endl;
return exit_status;
}
Keyring_component_load destination_component_load(
Options::s_destination_keyring, "destination");
if (!destination_component_load.ok()) {
log_error << "Error loading destination keyring component. Exiting."
<< std::endl;
return exit_status;
}
Source_keyring_services source_service(
Options::s_source_keyring,
Options::s_source_keyring_configuration_dir
? Options::s_source_keyring_configuration_dir
: "");
if (!source_service.ok()) {
log_error << "Failed to load required services from source keyring. "
"Exiting."
<< std::endl;
return exit_status;
}
Destination_keyring_services destination_service(
Options::s_destination_keyring,
Options::s_destination_keyring_configuration_dir != nullptr
? Options::s_destination_keyring_configuration_dir
: "");
if (!destination_service.ok()) {
log_error << "Failed to load required services from destination "
"keyring. Exiting."
<< std::endl;
return exit_status;
}
Keyring_migrate keyring_migrate(source_service, destination_service,
Options::s_online_migration);
if (!keyring_migrate.ok()) {
log_error << "Error migrating keys from: " << Options::s_source_keyring
<< " to: " << Options::s_destination_keyring
<< ". See log for more details" << std::endl;
return exit_status;
}
log_info << "Successfully loaded source and destination "
"keyrings. Initiating migration."
<< std::endl;
if (!keyring_migrate.migrate_keys()) {
log_error << "Error migrating keys from: " << Options::s_source_keyring
<< " to: " << Options::s_destination_keyring
<< ". See log for more details" << std::endl;
return exit_status;
}
log_info << "Key migration successful." << std::endl;
}
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,380 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <sys/types.h>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <utility>
#include <my_alloc.h> /* MEM_ROOT */
#include <my_default.h> /* print_defaults */
#include <my_getopt.h> /* Options handling */
#include <my_inttypes.h> /* typedefs */
#include <my_macros.h> /* STRINGIFY_ARG */
#include <mysql.h> /* MYSQL */
#include <mysql/service_mysql_alloc.h>/* my_strdup */
#include <mysql_com.h> /* get_tty_password */
#include <print_version.h> /* print_version */
#include <typelib.h> /* find_type_or_exit */
#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
#include "m_string.h"
#include "mysql/strings/m_ctype.h" /* Character set */
#include "nulls.h"
#include "template_utils.h"
#include "options.h"
#include "utilities.h"
/* TLS variables */
#include "client/include/sslopt-vars.h"
namespace options {
/** MEM_ROOT for arguments */
static MEM_ROOT argv_alloc{PSI_NOT_INSTRUMENTED, 512};
enum migration_options {
OPT_COMPONENT_DIR = 512,
OPT_SOURCE_KEYRING,
OPT_SOURCE_KEYRING_CONFIG_DIR,
OPT_DESTINATION_KEYRING,
OPT_DESTINATION_KEYRING_CONFIG_DIR,
OPT_ONLINE_MIGRATION,
OPT_SSL_MODE,
OPT_SSL_CA,
OPT_SSL_CAPATH,
OPT_SSL_CERT,
OPT_SSL_CIPHER,
OPT_SSL_KEY,
OPT_SSL_CRL,
OPT_SSL_CRLPATH,
OPT_TLS_VERSION,
OPT_SSL_FIPS_MODE,
OPT_TLS_CIPHERSUITES,
OPT_SERVER_PUBLIC_KEY,
OPT_SSL_SESSION_DATA,
OPT_SSL_SESSION_DATA_CONTINUE_ON_FAILED_REUSE,
OPT_TLS_SNI_SERVERNAME,
/* Add new value above this */
OPT_LAST
};
bool Options::s_help = false;
bool Options::s_verbose = false;
char *Options::s_component_dir = nullptr;
char *Options::s_source_keyring = nullptr;
char *Options::s_source_keyring_configuration_dir = nullptr;
char *Options::s_destination_keyring = nullptr;
char *Options::s_destination_keyring_configuration_dir = nullptr;
bool Options::s_online_migration = false;
char *Options::s_hostname = nullptr;
unsigned int Options::s_port = 0;
char *Options::s_username = nullptr;
char *Options::s_password = nullptr;
char *Options::s_socket = nullptr;
bool Options::s_tty_password = false;
/* Caching sha2 password variables */
#include "client/include/caching_sha2_passwordopt-vars.h"
/** Options group */
static const char *load_default_groups[] = {"mysql_migrate_keyring", nullptr};
/** Command line options */
static struct my_option my_long_options[] = {
{"help", '?', "Display this help and exit.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"version", 'V', "Output version information and exit.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"component_dir", OPT_COMPONENT_DIR, "Directory for components/plugins.",
&Options::s_component_dir, &Options::s_component_dir, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"source_keyring", OPT_SOURCE_KEYRING,
"Source keyring name (without extension)", &Options::s_source_keyring,
&Options::s_source_keyring, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"source_keyring_configuration_dir", OPT_SOURCE_KEYRING_CONFIG_DIR,
"Source keyring configuration directory",
&Options::s_source_keyring_configuration_dir,
&Options::s_source_keyring_configuration_dir, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"destination_keyring", OPT_DESTINATION_KEYRING,
"Destination keyring component name (without extension)",
&Options::s_destination_keyring, &Options::s_destination_keyring, nullptr,
GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"destination_keyring_configuration_dir",
OPT_DESTINATION_KEYRING_CONFIG_DIR,
"Destination keyring configuration directory",
&Options::s_destination_keyring_configuration_dir,
&Options::s_destination_keyring_configuration_dir, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"online_migration", OPT_ONLINE_MIGRATION,
"Signal the utility that source of migration is an active server",
&Options::s_online_migration, &Options::s_online_migration, nullptr,
GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"host", 'h', "Connect to host.", &Options::s_hostname,
&Options::s_hostname, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"port", 'P',
"Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&Options::s_port, &Options::s_port, nullptr, GET_UINT, REQUIRED_ARG, 0, 0,
0, nullptr, 0, nullptr},
#ifndef _WIN32
{"socket", 'S', "The socket file to use for connection.",
&Options::s_socket, &Options::s_socket, nullptr, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
#endif // _WIN32
{"user", 'u', "User for login if not current user.", &Options::s_username,
&Options::s_username, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"password", 'p',
"Password to use when connecting to server. If password is not given it's "
"asked from the tty.",
nullptr, nullptr, nullptr, GET_PASSWORD, OPT_ARG, 0, 0, 0, nullptr, 0,
nullptr},
/* TLS options */
#include "client/include/sslopt-longopts.h"
/* Caching sha2 password options */
#include "client/include/caching_sha2_passwordopt-longopts.h"
{"verbose", 'v', "Write more.", nullptr, nullptr, nullptr, GET_NO_ARG,
NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
/* Must be the last one */
{nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
0, nullptr, 0, nullptr}};
static void usage(bool version_only) {
print_version();
if (version_only) return;
std::cout << ORACLE_WELCOME_COPYRIGHT_NOTICE("2021") << std::endl;
std::cout << "MySQL Keyring Migration Utility" << std::endl;
std::cout << "Usage: " << my_progname << " [OPTIONS] " << std::endl;
my_print_help(my_long_options);
print_defaults("my", load_default_groups);
my_print_variables(my_long_options);
}
bool get_one_option(int optid, const struct my_option *opt, char *argument) {
switch (optid) {
case 'V':
Options::s_help = true;
usage(true);
break;
case 'I':
[[fallthrough]];
case '?':
Options::s_help = true;
usage(false);
break;
case 'v':
log_debug.enabled(!(argument == disabled_my_option));
break;
case 'p':
if (argument == disabled_my_option) {
// Don't require password
static char empty_password[] = {'\0'};
assert(empty_password[0] ==
'\0'); // Check that it has not been overwritten
argument = empty_password;
}
if (argument) {
char *start = argument;
my_free(Options::s_password);
Options::s_password =
my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
while (*argument) *argument++ = 'x'; /* Destroy argument */
if (*start) start[1] = 0; /* Cut length of argument */
Options::s_tty_password = false;
} else
Options::s_tty_password = true;
break;
/* Handle TLS options */
#include "client/include/sslopt-case.h"
}
return false;
}
static bool check_options_for_sanity() {
if (Options::s_component_dir == nullptr || !*Options::s_component_dir ||
Options::s_source_keyring == nullptr || !*Options::s_source_keyring ||
Options::s_destination_keyring == nullptr ||
!*Options::s_destination_keyring) {
log_error << "Location of components (--component-dir) and details of "
"source (--source-keyirng) and destination "
"(--destination-keyring) components is mandatory"
<< std::endl;
return false;
}
if (strcmp(Options::s_source_keyring, Options::s_destination_keyring) == 0) {
log_error << "Source and destination cannot be the same." << std::endl;
return false;
}
return true;
}
static bool get_options(int argc, char **argv, int &exit_code) {
exit_code = handle_options(&argc, &argv, my_long_options, get_one_option);
if (exit_code != 0) {
log_error << "Failed to parse command line arguments." << std::endl;
return false;
}
if (Options::s_help == true) {
exit_code = EXIT_SUCCESS;
return false;
}
if (check_options_for_sanity() == false) return false;
if (Options::s_tty_password) Options::s_password = get_tty_password(NullS);
return true;
}
bool process_options(int *argc, char ***argv, int &exit_code) {
exit_code = 0;
#ifdef _WIN32
/* Convert command line parameters from UTF16LE to UTF8MB4. */
my_win_translate_command_line_args(&my_charset_utf8mb4_bin, argc, argv);
#endif
my_getopt_use_args_separator = true;
if (load_defaults("my", load_default_groups, argc, argv, &argv_alloc)) {
log_error << "Failed to load default options groups" << std::endl;
return false;
}
my_getopt_use_args_separator = false;
const bool save_skip_unknown = my_getopt_skip_unknown;
my_getopt_skip_unknown = true;
const bool ret = get_options(*argc, *argv, exit_code);
my_getopt_skip_unknown = save_skip_unknown;
return ret;
}
/* MYSQL Handle used to connect to an active server */
void init_connection_basic() {}
void deinit_connection_basic() {
if (Options::s_password != nullptr) {
char *start = Options::s_password;
while (*start) *start++ = 'x';
my_free(Options::s_password);
Options::s_password = nullptr;
}
}
const char *default_charset = MYSQL_AUTODETECT_CHARSET_NAME;
Mysql_connection::Mysql_connection(bool connect) : ok_(false), mysql(nullptr) {
if (connect == false) return;
mysql_library_init(0, nullptr, nullptr);
mysql = new (std::nothrow) MYSQL();
if (mysql == nullptr) {
log_error << "Failed to allocate memory for MYSQL structure" << std::endl;
return;
}
if (mysql_init(mysql) == nullptr) {
log_error << " Failed to initialize MySQL connection structure"
<< std::endl;
return;
}
if (SSL_SET_OPTIONS(mysql) != 0) {
log_error << "Failed to set SSL options" << std::endl;
return;
}
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
if (Options::s_component_dir != nullptr && *Options::s_component_dir) {
if (mysql_options(mysql, MYSQL_PLUGIN_DIR, Options::s_component_dir) != 0) {
log_error << "Failed to set plugin directory" << std::endl;
return;
}
}
if (mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr) != 0) {
log_error << "Failed to reset connection attributes" << std::endl;
return;
}
if (mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name",
"mysql_migrate_keyring") != 0) {
log_error << "Failed to add program name to connection attributes"
<< std::endl;
return;
}
set_server_public_key(mysql);
set_get_server_public_key_option(mysql);
if (!mysql_real_connect(mysql, Options::s_hostname, Options::s_username,
Options::s_password, NullS, Options::s_port,
Options::s_socket, CLIENT_REMEMBER_OPTIONS)) {
log_error << "Failed to connect to server. Received error: "
<< mysql_error(mysql) << std::endl;
return;
}
if (ssl_client_check_post_connect_ssl_setup(
mysql, [](const char *err) { log_error << err << std::endl; }))
return;
log_info << "Successfully connected to MySQL server" << std::endl;
ok_ = true;
}
Mysql_connection::~Mysql_connection() {
if (mysql != nullptr) {
mysql_close(mysql);
delete mysql;
mysql = nullptr;
}
mysql_library_end();
ok_ = false;
}
bool Mysql_connection::execute(std::string command) {
if (!ok_) {
log_error << "Connection to MySQL server is not initialized." << std::endl;
return false;
}
if (mysql_real_query(mysql, command.c_str(), command.length())) {
log_error << "Failed to execute: " << command
<< ". Server error: " << mysql_error(mysql) << std::endl;
return false;
}
return true;
}
} // namespace options

View file

@ -0,0 +1,106 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 OPTIONS_INCLUDED
#define OPTIONS_INCLUDED
struct MYSQL;
namespace options {
/**
Command line options container
*/
class Options {
public:
/** Help */
static bool s_help;
/** Be loud */
static bool s_verbose;
/** Component directory location */
static char *s_component_dir;
/** Source keyring - Component or plugin */
static char *s_source_keyring;
/** Source Keyring configuration path - If it is not in component dir */
static char *s_source_keyring_configuration_dir;
/** Destination keyring - Must be a component */
static char *s_destination_keyring;
/** Destination Keyring configuration path - If it is not in component dir */
static char *s_destination_keyring_configuration_dir;
/*
Following parameters are needed if migration involves an active MySQL server
*/
/** Flag for online migration */
static bool s_online_migration;
/** Hostname */
static char *s_hostname;
/** Port */
static unsigned int s_port;
/** Socket */
static char *s_socket;
/** User name */
static char *s_username;
/** Password */
static char *s_password;
/** Password to be fetched */
static bool s_tty_password;
};
/**
Process command line options
@param [in, out] argc Number of arguments
@param [in, out] argv Command line argument array
@param [out] exit_code Exit code
@returns status of argument processing
@retval true Success
@retval false Failure
*/
bool process_options(int *argc, char ***argv, int &exit_code);
/** Initialize MYSQL connection structures */
void init_connection_basic();
/** Deinitialize MYSQL connection structures */
void deinit_connection_basic();
class Mysql_connection {
public:
explicit Mysql_connection(bool connect);
~Mysql_connection();
bool execute(std::string command);
bool ok() { return ok_; }
private:
bool ok_;
MYSQL *mysql;
};
} // namespace options
#endif // !OPTIONS_INCLUDED

View file

@ -0,0 +1,33 @@
/*
Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 UTILITIES_INCLUDED
#define UTILITIES_INCLUDED
#include "client/logger.h" /* Logging */
extern Log log_debug, log_info, log_warning, log_error;
#endif // !UTILITIES_INCLUDED

View file

@ -0,0 +1,103 @@
/* Copyright (c) 2021, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 include/multi_factor_passwordopt-vars.h
*/
#include "client/include/multi_factor_passwordopt-vars.h"
#include "my_getopt.h"
#include "mysql.h"
#include "mysql/service_mysql_alloc.h" // my_free, my_strdup
#include "nulls.h"
char *opt_password[MAX_AUTH_FACTORS] = {nullptr};
bool tty_password[MAX_AUTH_FACTORS] = {false};
/**
Helper method used by clients to parse password set as part of command line.
This method checks if password value is specified or not. If not then a flag
is set to let client accept password from terminal.
@param opt password option
@param argument value specified for --password<1,2,3> or --password
*/
void parse_command_line_password_option(const struct my_option *opt,
char *argument) {
if (argument == disabled_my_option) {
// Don't require password
static char empty_password[] = {'\0'};
assert(empty_password[0] ==
'\0'); // Check that it has not been overwritten
argument = empty_password;
}
/*
password options can be --password or --password1 or --password2 or
--password3. Thus extract factor from option.
*/
unsigned int factor = 0;
if (strcmp(opt->name, "password"))
factor = opt->name[strlen("password")] - '0' - 1;
if (argument) {
char *start = argument;
my_free(opt_password[factor]);
opt_password[factor] =
my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
while (*argument) *argument++ = 'x'; // Destroy argument
if (*start) start[1] = 0;
tty_password[factor] = false;
} else
tty_password[factor] = true;
}
/**
Helper method used by clients to set password in mysql->options
*/
void set_password_options(MYSQL *mysql) {
for (unsigned int factor = 1; factor <= MAX_AUTH_FACTORS; factor++) {
/**
If tty_password is true get password from terminal and update in
opt_password and set tty_password to false
*/
if (tty_password[factor - 1]) {
opt_password[factor - 1] = get_tty_password(NullS);
tty_password[factor - 1] = false;
}
/**
If opt_password is populated call mysql_options4()
*/
if (opt_password[factor - 1]) {
mysql_options4(mysql, MYSQL_OPT_USER_PASSWORD, &factor,
opt_password[factor - 1]);
}
}
}
void free_passwords() {
for (unsigned int factor = 1; factor <= MAX_AUTH_FACTORS; factor++) {
if (opt_password[factor - 1]) {
my_free(opt_password[factor - 1]);
opt_password[factor - 1] = nullptr;
}
}
}

52
client/multi_option.cc Normal file
View file

@ -0,0 +1,52 @@
/*
Copyright (c) 2012, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "multi_option.h"
void Multi_option::add_value(char *value, bool clear) {
if (option_values == nullptr) {
option_values = reinterpret_cast<Multi_option_container *>(my_malloc(
PSI_NOT_INSTRUMENTED, sizeof(Multi_option_container), MYF(MY_WME)));
// in a rare case when the allocation fails
if (option_values == nullptr) return;
new (option_values) Multi_option_container(PSI_NOT_INSTRUMENTED);
} else if (clear)
option_values->clear();
option_values->emplace_back(value);
}
void Multi_option::set_mysql_options(MYSQL *mysql, mysql_option option) {
if (option_values)
for (auto const &init_command : *option_values)
mysql_options(mysql, option, init_command);
}
void Multi_option::free() {
if (option_values != nullptr) {
option_values->~Multi_option_container();
my_free(option_values);
option_values = nullptr;
}
}

79
client/multi_option.h Normal file
View file

@ -0,0 +1,79 @@
/*
Copyright (c) 2012, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "mysql.h"
#include "mysql/service_mysql_alloc.h"
#include "prealloced_array.h"
#ifndef _MULTI_OPTION_H_
#define _MULTI_OPTION_H_
/**
Class for handling multiple options like e.g. --init-command,
--init-command-add
*/
class Multi_option {
/**
Type of the internal container
*/
using Multi_option_container = Prealloced_array<char *, 5>;
public:
/**
Constaexpr constructor
*/
constexpr Multi_option() : option_values(nullptr) {}
/**
Adds option value to the container
@param value [in]: value of the option
@param clear [in]: if true the container will be cleared before adding the
command
*/
void add_value(char *value, bool clear);
/**
Sets options to MYSQL structure.
@param mysql [in, out]: pointer to MYSQL structure to be augmented with the
option
@param option [in]: option to be set
*/
void set_mysql_options(MYSQL *mysql, mysql_option option);
/**
Free the commands
*/
void free();
private:
/**
The internal container with values
*/
Multi_option_container *option_values;
};
#endif //_MULTI_OPTION_H_

54
client/my_readline.h Normal file
View file

@ -0,0 +1,54 @@
#ifndef CLIENT_MY_READLINE_INCLUDED
#define CLIENT_MY_READLINE_INCLUDED
/*
Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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
*/
/* readline for batch mode */
#include "my_inttypes.h"
#include "my_io.h"
struct LINE_BUFFER {
File file;
char *buffer; /* The buffer itself, grown as needed. */
char *end; /* Pointer at buffer end */
char *start_of_line, *end_of_line;
uint bufread; /* Number of bytes to get with each read(). */
uint eof;
ulong max_size;
ulong read_length; /* Length of last read string */
int error;
bool truncated;
};
extern LINE_BUFFER *batch_readline_init(ulong max_size, FILE *file);
extern LINE_BUFFER *batch_readline_command(LINE_BUFFER *buffer, char *str);
extern char *batch_readline(LINE_BUFFER *buffer, bool binary_mode);
extern void batch_readline_end(LINE_BUFFER *buffer);
static const unsigned long int batch_io_size = 16 * 1024 * 1024;
#endif /* CLIENT_MY_READLINE_INCLUDED */

5890
client/mysql.cc Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,875 @@
/*
Copyright (c) 2013, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "client/include/client_priv.h"
#include "m_string.h"
#ifdef _WIN32
#include "mysql/strings/m_ctype.h"
#endif
#include "my_alloc.h"
#include "my_compiler.h"
#include "my_dbug.h"
#include "my_default.h"
#include "my_inttypes.h"
#include "my_macros.h"
#include "my_shm_defaults.h"
#include "mysql/service_mysql_alloc.h"
#include "mysqld_error.h"
#include "nulls.h"
#include "print_version.h"
#include "typelib.h"
#include "welcome_copyright_notice.h" // ORACLE_WELCOME_COPYRIGHT_NOTICE
using namespace std;
static MEM_ROOT argv_alloc{PSI_NOT_INSTRUMENTED, 512};
static char *opt_host = nullptr;
static char *opt_user = nullptr;
static uint opt_port = 0;
static uint opt_protocol = 0;
static char *opt_socket = nullptr;
static MYSQL mysql_handle;
static char *password = nullptr;
static bool password_provided = false;
static bool g_expire_password_on_exit = false;
static bool opt_use_default = false;
#if defined(_WIN32)
static const char *shared_memory_base_name = default_shared_memory_base_name;
#endif
#include "client/include/sslopt-vars.h"
static const char *load_default_groups[] = {"mysql_secure_installation",
"mysql", "client", nullptr};
static struct my_option my_connection_options[] = {
{"help", '?', "Display this help and exit.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"host", 'h', "Connect to host.", &opt_host, &opt_host, nullptr,
GET_STR_ALLOC, REQUIRED_ARG, (longlong) "localhost", 0, 0, nullptr, 0,
nullptr},
{"password", 'p',
"Password to connect to the server. If password is not "
"given it's asked from the tty.",
nullptr, nullptr, nullptr, GET_PASSWORD, OPT_ARG, 0, 0, 0, nullptr, 0,
nullptr},
#ifdef _WIN32
{"pipe", 'W', "Use named pipes to connect to server.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#endif
{"port", 'P',
"Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&opt_port, &opt_port, nullptr, GET_UINT, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol to use for connection (tcp, socket, pipe, memory).", nullptr,
nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
#if defined(_WIN32)
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
"Base name of shared memory.", &shared_memory_base_name,
&shared_memory_base_name, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"socket", 'S', "Socket file to be used for connection.", &opt_socket,
&opt_socket, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
#include "client/include/sslopt-longopts.h"
{"user", 'u', "User for login if not root.", &opt_user, &opt_user, nullptr,
GET_STR_ALLOC, REQUIRED_ARG, (longlong) "root", 0, 0, nullptr, 0, nullptr},
{"use-default", 'D', "Execute with no user interactivity", &opt_use_default,
&opt_use_default, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
/* End token */
{nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
0, nullptr, 0, nullptr}};
static void usage() {
print_version();
fprintf(stdout, ORACLE_WELCOME_COPYRIGHT_NOTICE("2013"));
fprintf(stdout, "\nMySQL Configuration Utility.");
fprintf(stdout, "Usage: %s [OPTIONS]\n", my_progname);
my_print_help(my_connection_options);
print_defaults("my", load_default_groups);
my_print_variables(my_connection_options);
}
static void free_resources() {
if (opt_host) my_free(opt_host);
if (opt_socket) my_free(opt_socket);
if (opt_user) my_free(opt_user);
if (password) my_free(password);
mysql_close(&mysql_handle);
}
extern "C" {
static bool my_arguments_get_one_option(int optid,
const struct my_option *opt
[[maybe_unused]],
char *argument) {
switch (optid) {
case '?':
usage();
free_resources();
exit(0);
case 'p':
if (argument) {
char *start = argument;
my_free(password);
password = my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
while (*argument) {
*argument++ = 'x'; // Destroy argument
}
if (*start) start[1] = 0;
} else
password = get_tty_password(NullS);
password_provided = true;
break;
#include "client/include/sslopt-case.h"
case OPT_MYSQL_PROTOCOL:
opt_protocol =
find_type_or_exit(argument, &sql_protocol_typelib, opt->name);
break;
case 'W':
#ifdef _WIN32
opt_protocol = MYSQL_PROTOCOL_PIPE;
#endif
break;
}
return false;
}
}
/* Initialize options for the given connection handle. */
static void init_connection_options(MYSQL *mysql) {
SSL_SET_OPTIONS(mysql);
if (opt_protocol)
mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
#if defined(_WIN32)
if (shared_memory_base_name)
mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
}
/**
Reads the response from stdin and returns the first character.
If global variable opt_use_default is true then the default_answer is
returned instead.
@param opt_message Optional message do be displayed.
@param default_answer Answer to be given if no interactivity is allowed.
@return First character of input string
*/
static int get_response(const char *opt_message, int default_answer = -1) {
int a = 0;
int b = 0;
int i = 0;
if (opt_message) {
fprintf(stdout, "%s", opt_message);
if (opt_use_default == true && default_answer != -1) {
fprintf(stdout, " %c \n", (char)default_answer);
return default_answer;
}
}
do {
if (i == 1) b = a;
a = getchar();
i++;
} while (a != '\n');
return b;
}
/**
Takes a mysql query and an optional message as arguments.
It displays the message if provided one and then runs the query.
If the query is run successfully, the success message is displayed.
Else, the failure message along with the actual failure is displayed.
If the server is not found running, the program is exited.
@param query The mysql query which is to be executed.
@param opt_message The optional message to be displayed.
*/
static void execute_query_with_message(const char *query,
const char *opt_message) {
if (opt_message) fprintf(stdout, "%s", opt_message);
if (!mysql_query(&mysql_handle, query))
fprintf(stdout, "Success.\n\n");
else if ((mysql_errno(&mysql_handle) == ER_PROCACCESS_DENIED_ERROR) ||
(mysql_errno(&mysql_handle) == ER_TABLEACCESS_DENIED_ERROR) ||
(mysql_errno(&mysql_handle) == ER_COLUMNACCESS_DENIED_ERROR)) {
fprintf(stdout,
"The user provided does not have enough permissions "
"to continue.\nmysql_secure_installation is exiting.\n");
free_resources();
exit(1);
} else
fprintf(stdout, " ... Failed! Error: %s\n", mysql_error(&mysql_handle));
if (mysql_errno(&mysql_handle) == CR_SERVER_GONE_ERROR) {
free_resources();
exit(1);
}
}
/**
Takes a mysql query and the length of the query in bytes
as the input. If the query fails on running, a message
along with the failure details is displayed.
@param query The mysql query which is to be executed.
@param length Length of the query in bytes.
@return false in case of success
true in case of failure
*/
static bool execute_query(const char **query, size_t length) {
if (!mysql_real_query(&mysql_handle, (const char *)*query, (ulong)length))
return false;
else if (mysql_errno(&mysql_handle) == CR_SERVER_GONE_ERROR) {
fprintf(stdout, " ... Failed! Error: %s\n", mysql_error(&mysql_handle));
free_resources();
exit(1);
}
if ((mysql_errno(&mysql_handle) == ER_PROCACCESS_DENIED_ERROR) ||
(mysql_errno(&mysql_handle) == ER_TABLEACCESS_DENIED_ERROR) ||
(mysql_errno(&mysql_handle) == ER_COLUMNACCESS_DENIED_ERROR)) {
fprintf(stdout,
"The user provided does not have enough permissions "
"to continue.\nmysql_secure_installation is exiting.\n");
free_resources();
exit(1);
}
return true;
}
/**
Checks if the validate_password component is installed and returns true
if it is.
*/
static bool validate_password_exists() {
MYSQL_ROW row;
bool res = true;
const char *query =
"SELECT component_urn FROM mysql.component WHERE component_urn "
"= \'file://component_validate_password\'";
if (!execute_query(&query, strlen(query)))
DBUG_PRINT("info", ("query success!"));
MYSQL_RES *result = mysql_store_result(&mysql_handle);
if (!result) return false;
row = mysql_fetch_row(result);
if (!row) res = false;
mysql_free_result(result);
return res;
}
/**
Installs validate_password component and sets the password validation policy.
@return Returns 1 on successfully setting the component and 0 in case of
of any error.
*/
static int install_password_validation_component() {
int reply;
int component_set = 0;
const char *strength = nullptr;
bool option_read = false;
reply= get_response((const char *) "\nVALIDATE PASSWORD COMPONENT can be "
"used to test passwords\nand improve "
"security. It checks the strength of "
"password\nand allows the users to set "
"only those passwords which are\nsecure "
"enough. Would you like to setup VALIDATE "
"PASSWORD component?\n\nPress y|Y for Yes,"
" any other key for No: ", 'y');
if (reply == (int)'y' || reply == (int)'Y') {
const char *query_tmp;
query_tmp = "INSTALL COMPONENT 'file://component_validate_password'";
if (!execute_query(&query_tmp, strlen(query_tmp))) {
component_set = 1;
while (!option_read) {
reply= get_response((const char *) "\nThere are three levels of "
"password validation policy:\n\n"
"LOW Length >= 8\n"
"MEDIUM Length >= 8, numeric, mixed case, and special characters\n"
"STRONG Length >= 8, numeric, mixed case, special characters and dictionary"
" file\n\n"
"Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: ",'2');
switch (reply) {
case (int)'0':
strength = "LOW";
option_read = true;
break;
case (int)'1':
strength = "MEDIUM";
option_read = true;
break;
case (int)'2':
strength = "STRONG";
option_read = true;
break;
default:
fprintf(stdout, "\nInvalid option provided.\n");
}
}
char *query, *end;
const int tmp = sizeof("SET GLOBAL validate_password.policy = ") + 3;
const size_t strength_length = strlen(strength);
/*
query string needs memory which is at least the length of initial part
of query plus twice the size of variable being appended.
*/
query = (char *)my_malloc(PSI_NOT_INSTRUMENTED,
(strength_length * 2 + tmp) * sizeof(char),
MYF(MY_WME));
end = my_stpcpy(query, "SET GLOBAL validate_password.policy = ");
*end++ = '\'';
end += mysql_real_escape_string_quote(&mysql_handle, end, strength,
(ulong)strength_length, '\'');
*end++ = '\'';
const char *query_const = query;
if (!execute_query(&query_const, (unsigned int)(end - query)))
DBUG_PRINT("info", ("query success!"));
my_free(query);
} else
fprintf(stdout,
"The password validation component is not available. "
"Proceeding with the further steps without the component.\n");
}
return (component_set);
}
/**
Checks the password strength and displays it to the user.
@param password_string Password string whose strength
is to be estimated
*/
static void estimate_password_strength(char *password_string) {
char *query, *end;
const size_t tmp = sizeof("SELECT validate_password_strength(") + 3;
const size_t password_length = strlen(password_string);
/*
query string needs memory which is at least the length of initial part
of query plus twice the size of variable being appended.
*/
query = (char *)my_malloc(PSI_NOT_INSTRUMENTED,
(password_length * 2 + tmp) * sizeof(char),
MYF(MY_WME));
end = my_stpcpy(query, "SELECT validate_password_strength(");
*end++ = '\'';
end += mysql_real_escape_string_quote(&mysql_handle, end, password_string,
(ulong)password_length, '\'');
*end++ = '\'';
*end++ = ')';
const char *query_const = query;
if (!execute_query(&query_const, (unsigned int)(end - query))) {
MYSQL_RES *result = mysql_store_result(&mysql_handle);
MYSQL_ROW row = mysql_fetch_row(result);
printf("\nEstimated strength of the password: %s \n", row[0]);
mysql_free_result(result);
}
my_free(query);
}
/**
During rpm deployments the password expires immediately and needs to be
renewed before the DBA can set the final password. This helper subroutine
will use an active connection to set a password.
@param mysql The MYSQL handle
@param password A password character string
Function might fail with an error message which can be retrieved using
mysql_error(mysql)
@return Success or failure
@retval true success
@retval false failure
*/
static bool mysql_set_password(MYSQL *mysql, char *password) {
const size_t password_len = strlen(password);
char *query, *end;
query =
(char *)my_malloc(PSI_NOT_INSTRUMENTED, password_len + 50, MYF(MY_WME));
end = my_stpmov(query, "SET PASSWORD=");
*end++ = '\'';
end += mysql_real_escape_string_quote(mysql, end, password,
(ulong)password_len, '\'');
*end++ = '\'';
if (mysql_real_query(mysql, query, (ulong)(end - query))) {
my_free(query);
return false;
}
my_free(query);
return true;
}
/**
Expires the password for all users if executed with sufficient
privileges. This is primarily used as a helper function during rpm
deployments.
@param mysql The MYSQL handle
Function might fail with an error message which can be retrieved using
mysql_error(mysql)
@return Success or failure
@retval true success
@retval false failure
*/
static bool mysql_expire_password(MYSQL *mysql) {
char sql[] = "UPDATE mysql.user SET password_expired= 'Y'";
const size_t sql_len = strlen(sql);
if (mysql_real_query(mysql, sql, (ulong)sql_len)) return false;
return true;
}
/**
Sets the user password with the string provided during the flow
of the method. It checks for the strength of the password before
changing it and displays the same to the user. The user can decide
if he wants to continue with the password, or provide a new one,
depending on the strength displayed.
@param component_set 1 if validate_password component is set and
0 if it is not.
*/
static void set_opt_user_password(int component_set) {
char *password1 = nullptr, *password2 = nullptr;
int reply = 0;
for (;;) {
if (password1) {
my_free(password1);
password1 = nullptr;
}
if (password2) {
my_free(password2);
password2 = nullptr;
}
password1 = get_tty_password("\nNew password: ");
if (password1[0] == '\0') {
fprintf(stdout, "Sorry, you can't use an empty password here.\n");
continue;
}
password2 = get_tty_password("\nRe-enter new password: ");
if (strcmp(password1, password2)) {
fprintf(stdout, "Sorry, passwords do not match.\n");
continue;
}
if (component_set == 1) {
estimate_password_strength(password1);
reply = get_response((
const char *)"Do you wish to continue with the "
"password provided?(Press y|Y for "
"Yes, any other key for No) : ");
}
const size_t pass_length = strlen(password1);
if ((!component_set) || (reply == (int)'y' || reply == (int)'Y')) {
char *query = nullptr, *end;
const int tmp = sizeof("SET PASSWORD=") + 3;
/*
query string needs memory which is at least the length of initial part
of query plus twice the size of variable being appended.
*/
query = (char *)my_malloc(PSI_NOT_INSTRUMENTED,
(pass_length * 2 + tmp) * sizeof(char),
MYF(MY_WME));
end = my_stpcpy(query, "SET PASSWORD=");
*end++ = '\'';
end += mysql_real_escape_string_quote(&mysql_handle, end, password1,
(ulong)pass_length, '\'');
*end++ = '\'';
my_free(password1);
my_free(password2);
password1 = nullptr;
password2 = nullptr;
const char *query_const = query;
if (!execute_query(&query_const, (unsigned int)(end - query))) {
my_free(query);
break;
} else
fprintf(stdout, " ... Failed! Error: %s\n", mysql_error(&mysql_handle));
}
}
}
/**
Takes the opt_user's password as an input from the user and checks its
validity by trying to connect to the server with it. The connection to the
server is opened in this function.
@return Returns 1 if a password already exists and 0 if it doesn't.
*/
static int get_opt_user_password() {
bool using_temporary_password = false;
int res;
if (!password_provided) {
/*
No password is provided on the command line. Attempt to connect using
a blank password.
*/
MYSQL *con = mysql_real_connect(&mysql_handle, opt_host, opt_user, "", "",
opt_port, opt_socket, 0);
if (con != nullptr ||
mysql_errno(&mysql_handle) == ER_MUST_CHANGE_PASSWORD_LOGIN) {
fprintf(stdout, "Connecting to MySQL using a blank password.\n");
my_free(password);
password = nullptr;
mysql_close(con);
} else {
char prompt[128];
snprintf(prompt, sizeof(prompt) - 1,
"Enter password for user %s: ", opt_user);
// Request password from user
password = get_tty_password(prompt);
}
init_connection_options(&mysql_handle);
} // if !password_provided
/*
A password candidate is identified. Use it to establish a connection.
*/
if (!mysql_real_connect(&mysql_handle, opt_host, opt_user, password, "",
opt_port, opt_socket, 0)) {
if (mysql_errno(&mysql_handle) == ER_MUST_CHANGE_PASSWORD_LOGIN) {
bool can = true;
init_connection_options(&mysql_handle);
mysql_options(&mysql_handle, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
&can);
if (!mysql_real_connect(&mysql_handle, opt_host, opt_user, password, "",
opt_port, opt_socket, 0)) {
fprintf(stdout, "Error: %s\n", mysql_error(&mysql_handle));
free_resources();
exit(1);
}
/*
Password worked but has expired. If this happens during a silent
deployment using the rpm package system we cannot stop and ask
for a password. Instead we just renew the previous password and set
it to expire.
*/
if (using_temporary_password) {
if (!mysql_set_password(&mysql_handle, password)) {
fprintf(stdout, "... Failed! Error: %s\n",
mysql_error(&mysql_handle));
free_resources();
exit(1);
}
g_expire_password_on_exit = true;
} else {
/*
This path is only executed if no temporary password can be found and
should only happen when manual interaction is possible.
*/
fprintf(stdout,
"\nThe existing password for the user account %s has "
"expired. Please set a new password.\n",
opt_user);
set_opt_user_password(0);
}
} else {
fprintf(stdout, "Error: %s\n", mysql_error(&mysql_handle));
free_resources();
exit(1);
}
}
res = (password && password[0] != '\0') ? 1 : 0;
return (res);
}
/**
Takes the user and the host from result set and drops those users.
@param result The result set from which rows are to be fetched.
*/
static void drop_users(MYSQL_RES *result) {
MYSQL_ROW row;
char *user_tmp, *host_tmp;
while ((row = mysql_fetch_row(result))) {
char *query, *end;
size_t user_length, host_length;
const int tmp = sizeof("DROP USER ") + 5;
user_tmp = row[0];
host_tmp = row[1];
user_length = strlen(user_tmp);
host_length = strlen(host_tmp);
/*
query string needs memory which is at least the length of initial part
of query plus twice the size of variable being appended.
*/
query = (char *)my_malloc(
PSI_NOT_INSTRUMENTED,
((user_length + host_length) * 2 + tmp) * sizeof(char), MYF(MY_WME));
end = my_stpcpy(query, "DROP USER ");
*end++ = '\'';
end += mysql_real_escape_string_quote(&mysql_handle, end, user_tmp,
(ulong)user_length, '\'');
*end++ = '\'';
*end++ = '@';
*end++ = '\'';
end += mysql_real_escape_string_quote(&mysql_handle, end, host_tmp,
(ulong)host_length, '\'');
*end++ = '\'';
const char *query_const = query;
if (!execute_query(&query_const, (unsigned int)(end - query)))
DBUG_PRINT("info", ("query success!"));
my_free(query);
}
}
/**
Removes all the anonymous users for better security.
*/
static void remove_anonymous_users() {
int reply;
reply= get_response((const char *) "By default, a MySQL installation has an "
"anonymous user,\nallowing anyone to log "
"into MySQL without having to have\na user "
"account created for them. This is intended "
"only for\ntesting, and to make the "
"installation go a bit smoother.\nYou should "
"remove them before moving into a production\n"
"environment.\n\nRemove anonymous users? "
"(Press y|Y for Yes, any other key for No) : ", 'y');
if (reply == (int)'y' || reply == (int)'Y') {
const char *query;
query = "SELECT USER, HOST FROM mysql.user WHERE USER=''";
if (!execute_query(&query, strlen(query)))
DBUG_PRINT("info", ("query success!"));
MYSQL_RES *result = mysql_store_result(&mysql_handle);
if (result) drop_users(result);
mysql_free_result(result);
fprintf(stdout, "Success.\n\n");
} else
fprintf(stdout, "\n ... skipping.\n\n");
}
/**
Drops all the root users with a remote host.
*/
static void remove_remote_root() {
int reply;
reply= get_response((const char *) "\nNormally, root should only be "
"allowed to connect from\n'localhost'. "
"This ensures that someone cannot guess at"
"\nthe root password from the network.\n\n"
"Disallow root login remotely? (Press y|Y "
"for Yes, any other key for No) : ", 'y');
if (reply == (int)'y' || reply == (int)'Y') {
const char *query;
query =
"SELECT USER, HOST FROM mysql.user WHERE USER='root' "
"AND HOST NOT IN ('localhost', '127.0.0.1', '::1')";
if (!execute_query(&query, strlen(query)))
DBUG_PRINT("info", ("query success!"));
MYSQL_RES *result = mysql_store_result(&mysql_handle);
if (result) drop_users(result);
mysql_free_result(result);
fprintf(stdout, "Success.\n\n");
} else
fprintf(stdout, "\n ... skipping.\n");
}
/**
Removes test database and deletes the rows corresponding to them
from mysql.db table.
*/
static void remove_test_database() {
int reply;
reply= get_response((const char *) "By default, MySQL comes with a database "
"named 'test' that\nanyone can access. "
"This is also intended only for testing,\n"
"and should be removed before moving into "
"a production\nenvironment.\n\n\nRemove "
"test database and access to it? (Press "
"y|Y for Yes, any other key for No) : ", 'y');
if (reply == (int)'y' || reply == (int)'Y') {
execute_query_with_message((const char *)"DROP DATABASE IF EXISTS test",
(const char *)" - Dropping test database...\n");
execute_query_with_message((const char *) "DELETE FROM mysql.db WHERE "
"Db='test' OR Db='test\\_%'",
(const char *) " - Removing privileges on test "
"database...\n");
} else
fprintf(stdout, "\n ... skipping.\n");
}
/**
Refreshes the in-memory details through
FLUSH PRIVILEGES.
*/
static void reload_privilege_tables() {
int reply;
reply= get_response((const char *) "Reloading the privilege tables will "
"ensure that all changes\nmade so far "
"will take effect immediately.\n\nReload "
"privilege tables now? (Press y|Y for "
"Yes, any other key for No) : ", 'y');
if (reply == (int)'y' || reply == (int)'Y') {
execute_query_with_message((const char *)"FLUSH PRIVILEGES", nullptr);
} else
fprintf(stdout, "\n ... skipping.\n");
}
int main(int argc, char *argv[]) {
int reply;
int rc;
int hadpass, component_set = 0;
MY_INIT(argv[0]);
DBUG_TRACE;
DBUG_PROCESS(argv[0]);
if (mysql_init(&mysql_handle) == nullptr) {
printf("... Failed to initialize the MySQL client framework.\n");
exit(1);
}
#ifdef _WIN32
/* Convert command line parameters from UTF16LE to UTF8MB4. */
my_win_translate_command_line_args(&my_charset_utf8mb4_bin, &argc, &argv);
#endif
my_getopt_use_args_separator = true;
if (load_defaults("my", load_default_groups, &argc, &argv, &argv_alloc)) {
my_end(0);
free_resources();
exit(1);
}
my_getopt_use_args_separator = false;
if ((rc = my_handle_options(&argc, &argv, my_connection_options,
my_arguments_get_one_option, nullptr, true))) {
assert(0);
}
init_connection_options(&mysql_handle);
fprintf(stdout, "\nSecuring the MySQL server deployment.\n\n");
hadpass = get_opt_user_password();
if (!validate_password_exists())
component_set = install_password_validation_component();
else {
fprintf(stdout,
"The 'validate_password' component is installed on the server.\n"
"The subsequent steps will run with the existing "
"configuration\nof the component.\n");
component_set = 1;
}
if (!hadpass) {
fprintf(stdout, "Please set the password for %s here.\n", opt_user);
set_opt_user_password(component_set);
} else if (opt_use_default == false) {
char prompt[256];
fprintf(stdout, "Using existing password for %s.\n", opt_user);
if (component_set == 1) estimate_password_strength(password);
snprintf(prompt, sizeof(prompt) - 1,
"Change the password for %s ? ((Press y|Y "
"for Yes, any other key for No) : ",
opt_user);
reply = get_response(prompt, 'n');
if (reply == (int)'y' || reply == (int)'Y')
set_opt_user_password(component_set);
else
fprintf(stdout, "\n ... skipping.\n");
}
// Remove anonymous users
remove_anonymous_users();
// Disallow remote root login
remove_remote_root();
// Remove test database
remove_test_database();
/*
During an unattended rpm deployment a temporary password is created and
stored in a file by 'mysqld --initialize'. This program uses this password
to perform security configurations after the bootstrap phase, but it needs
to be marked for expiration upon exit so the DBA will remember to set a new
one.
*/
if (g_expire_password_on_exit == true) {
if (mysql_expire_password(&mysql_handle) == false) {
fprintf(stdout,
"... Failed to expire password!\n"
"** Please consult the MySQL server documentation. **\n"
"Error: %s\n",
mysql_error(&mysql_handle));
// Reload privilege tables before exiting
reload_privilege_tables();
free_resources();
exit(1);
}
}
// Reload privilege tables
reload_privilege_tables();
fprintf(stdout, "All done! \n");
free_resources();
return 0;
}

1541
client/mysqladmin.cc Normal file

File diff suppressed because it is too large Load diff

3534
client/mysqlbinlog.cc Normal file

File diff suppressed because it is too large Load diff

49
client/mysqlbinlog.h Normal file
View file

@ -0,0 +1,49 @@
/* Copyright (c) 2015, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 MYSQLBINLOG_INCLUDED
#define MYSQLBINLOG_INCLUDED
#include <stdarg.h>
#include <sys/types.h>
#include "my_compiler.h"
#include "my_inttypes.h"
extern bool force_opt;
extern bool short_form;
extern ulong opt_server_id_mask;
extern ulong opt_binlog_rows_event_max_size;
/*
error() is used in macro BINLOG_ERROR which is invoked in
rpl_gtid.h, hence the early forward declaration.
*/
void error(const char *format, ...) MY_ATTRIBUTE((format(printf, 1, 2)));
void warning(const char *format, ...) MY_ATTRIBUTE((format(printf, 1, 2)));
void error_or_warning(const char *format, va_list args, const char *msg)
MY_ATTRIBUTE((format(printf, 1, 0)));
void sql_print_error(const char *format, ...)
MY_ATTRIBUTE((format(printf, 1, 2)));
#endif // MYSQLBINLOG_INCLUDED

6466
client/mysqldump.cc Normal file

File diff suppressed because it is too large Load diff

723
client/mysqlimport.cc Normal file
View file

@ -0,0 +1,723 @@
/*
Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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
*/
/*
** mysqlimport.c - Imports all given files
** into a table(s).
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include "client/include/client_priv.h"
#include "compression.h"
#include "m_string.h"
#include "my_alloc.h"
#include "my_dbug.h"
#include "my_default.h"
#include "my_inttypes.h"
#include "my_io.h"
#include "my_macros.h"
#include "my_systime.h"
#include "mysql/service_mysql_alloc.h"
#include "mysql/strings/int2str.h"
#include "mysql_version.h"
#include "nulls.h"
#include "print_version.h"
#include "strxmov.h"
#include "thr_cond.h"
#include "thr_mutex.h"
#include "typelib.h"
#include "welcome_copyright_notice.h" /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
/* Global Thread counter */
uint counter;
native_mutex_t init_mutex;
native_mutex_t counter_mutex;
native_cond_t count_threshold;
static int db_error_with_table(MYSQL *mysql, char *table);
static int db_error(MYSQL *mysql);
static char *field_escape(char *to, const char *from, uint length);
static char *add_load_option(char *ptr, const char *object,
const char *statement);
static bool verbose = false, lock_tables = false, ignore_errors = false,
opt_delete = false, replace = false, silent = false, ignore = false,
opt_compress = false, opt_low_priority = false;
static bool debug_info_flag = false, debug_check_flag = false;
static uint opt_use_threads = 0, opt_local_file = 0, my_end_arg = 0;
static char *current_user = nullptr, *current_host = nullptr,
*current_db = nullptr, *fields_terminated = nullptr,
*lines_terminated = nullptr, *enclosed = nullptr,
*opt_enclosed = nullptr, *escaped = nullptr, *opt_columns = nullptr;
static const char *default_charset = MYSQL_AUTODETECT_CHARSET_NAME;
static uint opt_enable_cleartext_plugin = 0;
static bool using_opt_enable_cleartext_plugin = false;
static uint opt_mysql_port = 0, opt_protocol = 0;
static char *opt_bind_addr = nullptr;
static char *opt_mysql_unix_port = nullptr;
static char *opt_plugin_dir = nullptr, *opt_default_auth = nullptr;
static longlong opt_ignore_lines = -1;
static uint opt_zstd_compress_level = default_zstd_compression_level;
static char *opt_compress_algorithm = nullptr;
#include "client/include/caching_sha2_passwordopt-vars.h"
#include "client/include/multi_factor_passwordopt-vars.h"
#include "client/include/sslopt-vars.h"
#if defined(_WIN32)
static char *shared_memory_base_name = nullptr;
#endif
static struct my_option my_long_options[] = {
{"bind-address", 0, "IP address to bind to.", (uchar **)&opt_bind_addr,
(uchar **)&opt_bind_addr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"character-sets-dir", OPT_CHARSETS_DIR,
"Directory for character set files.", &charsets_dir, &charsets_dir,
nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"default-character-set", OPT_DEFAULT_CHARSET,
"Set the default character set.", &default_charset, &default_charset,
nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"columns", 'c',
"Use only these columns to import the data to. Give the column names in a "
"comma separated list. This is same as giving columns to LOAD DATA "
"INFILE.",
&opt_columns, &opt_columns, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"compress", 'C', "Use compression in server/client protocol.",
&opt_compress, &opt_compress, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
0, nullptr},
#ifdef NDEBUG
{"debug", '#', "This is a non-debug version. Catch this and exit.", nullptr,
nullptr, nullptr, GET_DISABLED, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-check", OPT_DEBUG_CHECK,
"This is a non-debug version. Catch this and exit.", nullptr, nullptr,
nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-info", OPT_DEBUG_INFO,
"This is a non-debug version. Catch this and exit.", nullptr, nullptr,
nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#else
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", nullptr,
nullptr, nullptr, GET_STR, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-check", OPT_DEBUG_CHECK,
"Check memory and open file usage at exit.", &debug_check_flag,
&debug_check_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
&debug_info_flag, &debug_info_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"default_auth", OPT_DEFAULT_AUTH,
"Default authentication client-side plugin to use.", &opt_default_auth,
&opt_default_auth, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"delete", 'd', "First delete all rows from table.", &opt_delete,
&opt_delete, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
"Enable/disable the clear text authentication plugin.",
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, nullptr,
GET_BOOL, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"fields-terminated-by", OPT_FTB,
"Fields in the input file are terminated by the given string.",
&fields_terminated, &fields_terminated, nullptr, GET_STR, REQUIRED_ARG, 0,
0, 0, nullptr, 0, nullptr},
{"fields-enclosed-by", OPT_ENC,
"Fields in the import file are enclosed by the given character.",
&enclosed, &enclosed, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"fields-optionally-enclosed-by", OPT_O_ENC,
"Fields in the input file are optionally enclosed by the given character.",
&opt_enclosed, &opt_enclosed, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"fields-escaped-by", OPT_ESC,
"Fields in the input file are escaped by the given character.", &escaped,
&escaped, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"force", 'f', "Continue even if we get an SQL error.", &ignore_errors,
&ignore_errors, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"help", '?', "Displays this help and exits.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"host", 'h', "Connect to host.", &current_host, &current_host, nullptr,
GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"ignore", 'i', "If duplicate unique key was found, keep old row.", &ignore,
&ignore, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"ignore-lines", OPT_IGN_LINES, "Ignore first n lines of data infile.",
&opt_ignore_lines, &opt_ignore_lines, nullptr, GET_LL, REQUIRED_ARG, 0, 0,
0, nullptr, 0, nullptr},
{"lines-terminated-by", OPT_LTB,
"Lines in the input file are terminated by the given string.",
&lines_terminated, &lines_terminated, nullptr, GET_STR, REQUIRED_ARG, 0, 0,
0, nullptr, 0, nullptr},
{"local", 'L', "Read all files through the client.", &opt_local_file,
&opt_local_file, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"lock-tables", 'l', "Lock all tables for write (this disables threads).",
&lock_tables, &lock_tables, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"low-priority", OPT_LOW_PRIORITY,
"Use LOW_PRIORITY when updating the table.", &opt_low_priority,
&opt_low_priority, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
#include "client/include/multi_factor_passwordopt-longopts.h"
#ifdef _WIN32
{"pipe", 'W', "Use named pipes to connect to server.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#endif
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
&opt_plugin_dir, &opt_plugin_dir, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"port", 'P',
"Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&opt_mysql_port, &opt_mysql_port, nullptr, GET_UINT, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol to use for connection (tcp, socket, pipe, memory).", nullptr,
nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"replace", 'r', "If duplicate unique key was found, replace old row.",
&replace, &replace, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
#if defined(_WIN32)
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
"Base name of shared memory.", &shared_memory_base_name,
&shared_memory_base_name, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"silent", 's', "Be more silent.", &silent, &silent, nullptr, GET_BOOL,
NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"socket", 'S', "The socket file to use for connection.",
&opt_mysql_unix_port, &opt_mysql_unix_port, nullptr, GET_STR, REQUIRED_ARG,
0, 0, 0, nullptr, 0, nullptr},
#include "client/include/caching_sha2_passwordopt-longopts.h"
#include "client/include/sslopt-longopts.h"
{"use-threads", OPT_USE_THREADS,
"Load files in parallel. The argument is the number "
"of threads to use for loading data.",
&opt_use_threads, &opt_use_threads, nullptr, GET_UINT, REQUIRED_ARG, 0, 0,
0, nullptr, 0, nullptr},
{"user", 'u', "User for login if not current user.", &current_user,
&current_user, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"verbose", 'v', "Print info about the various stages.", &verbose, &verbose,
nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"version", 'V', "Output version information and exit.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"compression-algorithms", 0,
"Use compression algorithm in server/client protocol. Valid values "
"are any combination of 'zstd','zlib','uncompressed'.",
&opt_compress_algorithm, &opt_compress_algorithm, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"zstd-compression-level", 0,
"Use this compression level in the client/server protocol, in case "
"--compression-algorithms=zstd. Valid range is between 1 and 22, "
"inclusive. Default is 3.",
&opt_zstd_compress_level, &opt_zstd_compress_level, nullptr, GET_UINT,
REQUIRED_ARG, 3, 1, 22, nullptr, 0, nullptr},
{nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
0, nullptr, 0, nullptr}};
static const char *load_default_groups[] = {"mysqlimport", "client", nullptr};
static void usage(void) {
print_version();
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
printf(
"\
Loads tables from text files in various formats. The base name of the\n\
text file must be the name of the table that should be used.\n\
If one uses sockets to connect to the MySQL server, the server will open and\n\
read the text file directly. In other cases the client will open the text\n\
file. The SQL command 'LOAD DATA INFILE' is used to import the rows.\n");
printf("\nUsage: %s [OPTIONS] database textfile...", my_progname);
print_defaults("my", load_default_groups);
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
extern "C" {
static bool get_one_option(int optid, const struct my_option *opt,
char *argument) {
switch (optid) {
PARSE_COMMAND_LINE_PASSWORD_OPTION;
#ifdef _WIN32
case 'W':
opt_protocol = MYSQL_PROTOCOL_PIPE;
opt_local_file = 1;
break;
#endif
case OPT_ENABLE_CLEARTEXT_PLUGIN:
using_opt_enable_cleartext_plugin = true;
break;
case OPT_MYSQL_PROTOCOL:
opt_protocol =
find_type_or_exit(argument, &sql_protocol_typelib, opt->name);
break;
case '#':
DBUG_PUSH(argument ? argument : "d:t:o");
debug_check_flag = true;
break;
#include "client/include/sslopt-case.h"
case 'V':
print_version();
exit(0);
case 'I':
case '?':
usage();
exit(0);
case 'C':
CLIENT_WARN_DEPRECATED("--compress", "--compression-algorithms");
break;
}
return false;
}
} // extern "C"
static int get_options(int *argc, char ***argv) {
int ho_error;
if ((ho_error = handle_options(argc, argv, my_long_options, get_one_option)))
exit(ho_error);
if (debug_info_flag) my_end_arg = MY_CHECK_ERROR | MY_GIVE_INFO;
if (debug_check_flag) my_end_arg = MY_CHECK_ERROR;
if (enclosed && opt_enclosed) {
fprintf(stderr,
"You can't use ..enclosed.. and ..optionally-enclosed.. at the "
"same time.\n");
return (1);
}
if (replace && ignore) {
fprintf(
stderr,
"You can't use --ignore (-i) and --replace (-r) at the same time.\n");
return (1);
}
if (*argc < 2) {
usage();
return 1;
}
current_db = *((*argv)++);
(*argc)--;
return (0);
}
static int write_to_table(char *filename, MYSQL *mysql) {
char tablename[FN_REFLEN], hard_path[FN_REFLEN],
escaped_name[FN_REFLEN * 2 + 1], sql_statement[FN_REFLEN * 16 + 256],
escaped_tablename[FN_REFLEN * 2 + 1], *end;
DBUG_TRACE;
DBUG_PRINT("enter", ("filename: %s", filename));
fn_format(tablename, filename, "", "", 1 | 2); /* removes path & ext. */
if (!opt_local_file)
my_stpcpy(hard_path, filename);
else
my_load_path(hard_path, filename, nullptr); /* filename includes the path */
mysql_real_escape_string_quote(mysql, escaped_tablename, tablename,
(unsigned long)strlen(tablename), '`');
if (opt_delete) {
if (verbose)
fprintf(stdout, "Deleting the old data from table %s\n", tablename);
snprintf(sql_statement, FN_REFLEN * 16 + 256, "DELETE FROM `%s`",
escaped_tablename);
if (mysql_query(mysql, sql_statement))
return db_error_with_table(mysql, tablename);
}
to_unix_path(hard_path);
if (verbose) {
if (opt_local_file)
fprintf(stdout, "Loading data from LOCAL file: %s into %s\n", hard_path,
tablename);
else
fprintf(stdout, "Loading data from SERVER file: %s into %s\n", hard_path,
tablename);
}
if (opt_local_file)
mysql_options(mysql, MYSQL_OPT_LOAD_DATA_LOCAL_DIR, filename);
mysql_real_escape_string_quote(mysql, escaped_name, hard_path,
(unsigned long)strlen(hard_path), '\'');
sprintf(sql_statement, "LOAD DATA %s %s INFILE '%s'",
opt_low_priority ? "LOW_PRIORITY" : "", opt_local_file ? "LOCAL" : "",
escaped_name);
end = strend(sql_statement);
if (replace) end = my_stpcpy(end, " REPLACE");
if (ignore) end = my_stpcpy(end, " IGNORE");
end = my_stpcpy(end, " INTO TABLE `");
end = my_stpcpy(end, escaped_tablename);
end = my_stpcpy(end, "`");
if (fields_terminated || enclosed || opt_enclosed || escaped)
end = my_stpcpy(end, " FIELDS");
end = add_load_option(end, fields_terminated, " TERMINATED BY");
end = add_load_option(end, enclosed, " ENCLOSED BY");
end = add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
end = add_load_option(end, escaped, " ESCAPED BY");
end = add_load_option(end, lines_terminated, " LINES TERMINATED BY");
if (opt_ignore_lines >= 0)
end = my_stpcpy(
longlong10_to_str(opt_ignore_lines, my_stpcpy(end, " IGNORE "), 10),
" LINES");
if (opt_columns)
end = my_stpcpy(my_stpcpy(my_stpcpy(end, " ("), opt_columns), ")");
*end = '\0';
if (mysql_query(mysql, sql_statement))
return db_error_with_table(mysql, tablename);
if (!silent) {
if (mysql_info(mysql)) /* If NULL-pointer, print nothing */
{
fprintf(stdout, "%s.%s: %s\n", current_db, tablename, mysql_info(mysql));
}
}
return 0;
}
static int lock_table(MYSQL *mysql, int tablecount, char **raw_tablename) {
DYNAMIC_STRING query;
int i;
char tablename[FN_REFLEN];
if (verbose) fprintf(stdout, "Locking tables for write\n");
init_dynamic_string(&query, "LOCK TABLES ", 256);
for (i = 0; i < tablecount; i++) {
fn_format(tablename, raw_tablename[i], "", "", 1 | 2);
dynstr_append(&query, tablename);
dynstr_append(&query, " WRITE,");
}
if (mysql_real_query(mysql, query.str, (ulong)(query.length - 1)))
return db_error(mysql); /* We shall continue here, if --force was given */
return 0;
}
static MYSQL *db_connect(char *host, char *database, char *user, char *) {
MYSQL *mysql;
if (verbose) fprintf(stdout, "Connecting to %s\n", host ? host : "localhost");
if (opt_use_threads && !lock_tables) {
native_mutex_lock(&init_mutex);
if (!(mysql = mysql_init(nullptr))) {
native_mutex_unlock(&init_mutex);
return nullptr;
}
native_mutex_unlock(&init_mutex);
} else if (!(mysql = mysql_init(nullptr)))
return nullptr;
if (opt_compress) mysql_options(mysql, MYSQL_OPT_COMPRESS, NullS);
if (opt_compress_algorithm)
mysql_options(mysql, MYSQL_OPT_COMPRESSION_ALGORITHMS,
opt_compress_algorithm);
mysql_options(mysql, MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
&opt_zstd_compress_level);
if (SSL_SET_OPTIONS(mysql)) {
fprintf(stderr, "%s", SSL_SET_OPTIONS_ERROR);
return nullptr;
}
if (opt_protocol)
mysql_options(mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
if (opt_bind_addr) mysql_options(mysql, MYSQL_OPT_BIND, opt_bind_addr);
#if defined(_WIN32)
if (shared_memory_base_name)
mysql_options(mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
if (opt_plugin_dir && *opt_plugin_dir)
mysql_options(mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
if (opt_default_auth && *opt_default_auth)
mysql_options(mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
if (using_opt_enable_cleartext_plugin)
mysql_options(mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
(char *)&opt_enable_cleartext_plugin);
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr);
mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name",
"mysqlimport");
set_server_public_key(mysql);
set_get_server_public_key_option(mysql);
set_password_options(mysql);
if (!(mysql_real_connect(mysql, host, user, nullptr, database, opt_mysql_port,
opt_mysql_unix_port, 0))) {
ignore_errors = false; /* NO RETURN FROM db_error */
db_error(mysql);
if (mysql) mysql_close(mysql);
return nullptr;
}
if (ssl_client_check_post_connect_ssl_setup(
mysql, [](const char *err) { fprintf(stderr, "%s\n", err); })) {
if (mysql) mysql_close(mysql);
return nullptr;
}
if (verbose) fprintf(stdout, "Selecting database %s\n", database);
if (mysql_select_db(mysql, database)) {
ignore_errors = false;
db_error(mysql);
if (mysql) mysql_close(mysql);
return nullptr;
}
return mysql;
}
static void db_disconnect(char *host, MYSQL *mysql) {
if (verbose)
fprintf(stdout, "Disconnecting from %s\n", host ? host : "localhost");
if (mysql) mysql_close(mysql);
}
static int safe_exit(int error) {
if (ignore_errors) return 0;
return error;
}
static int db_error_with_table(MYSQL *mysql, char *table) {
my_printf_error(0, "Error: %d, %s, when using table: %s", MYF(0),
mysql_errno(mysql), mysql_error(mysql), table);
return safe_exit(1);
}
static int db_error(MYSQL *mysql) {
my_printf_error(0, "Error: %d %s", MYF(0), mysql_errno(mysql),
mysql_error(mysql));
return safe_exit(1);
}
static char *add_load_option(char *ptr, const char *object,
const char *statement) {
if (object) {
/* Don't escape hex constants */
if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
ptr = strxmov(ptr, " ", statement, " ", object, NullS);
else {
/* char constant; escape */
ptr = strxmov(ptr, " ", statement, " '", NullS);
ptr = field_escape(ptr, object, (uint)strlen(object));
*ptr++ = '\'';
}
}
return ptr;
}
/*
** Allow the user to specify field terminator strings like:
** "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
** This is done by doubleing ' and add a end -\ if needed to avoid
** syntax errors from the SQL parser.
*/
static char *field_escape(char *to, const char *from, uint length) {
const char *end;
uint end_backslashes = 0;
for (end = from + length; from != end; from++) {
*to++ = *from;
if (*from == '\\')
end_backslashes ^= 1; /* find odd number of backslashes */
else {
if (*from == '\'' && !end_backslashes)
*to++ = *from; /* We want a duplicate of "'" for MySQL */
end_backslashes = 0;
}
}
/* Add missing backslashes if user has specified odd number of backs.*/
if (end_backslashes) *to++ = '\\';
return to;
}
int exitcode = 0;
extern "C" {
static void *worker_thread(void *arg) {
int error;
char *raw_table_name = (char *)arg;
MYSQL *mysql = nullptr;
if (mysql_thread_init()) goto error;
if (!(mysql = db_connect(current_host, current_db, current_user,
opt_password[0]))) {
goto error;
}
if (mysql_query(mysql, "/*!40101 set @@character_set_database=binary */;") &&
(error = db_error(mysql))) {
if (exitcode == 0) exitcode = error;
/* We shall continue here, if --force was given */
goto error;
}
/*
We are not currently catching the error here.
*/
if ((error = write_to_table(raw_table_name, mysql))) {
if (exitcode == 0) exitcode = error;
goto error;
}
error:
if (mysql) db_disconnect(current_host, mysql);
native_mutex_lock(&counter_mutex);
counter--;
native_cond_signal(&count_threshold);
native_mutex_unlock(&counter_mutex);
mysql_thread_end();
my_thread_exit(nullptr);
return nullptr;
}
} // extern "C"
int main(int argc, char **argv) {
int error = 0;
MY_INIT(argv[0]);
MYSQL *mysql = nullptr;
my_getopt_use_args_separator = true;
MEM_ROOT alloc{PSI_NOT_INSTRUMENTED, 512};
if (load_defaults("my", load_default_groups, &argc, &argv, &alloc)) return 1;
my_getopt_use_args_separator = false;
if (get_options(&argc, &argv)) {
return (1);
}
if (opt_use_threads && !lock_tables) {
char **save_argv;
uint worker_thread_count = 0, table_count = 0, i = 0;
my_thread_handle *worker_threads; /* Thread descriptor */
my_thread_attr_t attr; /* Thread attributes */
my_thread_attr_init(&attr);
my_thread_attr_setdetachstate(&attr, MY_THREAD_CREATE_JOINABLE);
native_mutex_init(&init_mutex, nullptr);
native_mutex_init(&counter_mutex, nullptr);
native_cond_init(&count_threshold);
/* Count the number of tables. This number denotes the total number
of threads spawn.
*/
save_argv = argv;
for (table_count = 0; *argv != nullptr; argv++) table_count++;
argv = save_argv;
if (!(worker_threads = (my_thread_handle *)my_malloc(
PSI_NOT_INSTRUMENTED, table_count * sizeof(*worker_threads),
MYF(0)))) {
exitcode = -2;
goto end;
}
for (counter = 0; *argv != nullptr; argv++) /* Loop through tables */
{
native_mutex_lock(&counter_mutex);
while (counter == opt_use_threads) {
struct timespec abstime;
set_timespec(&abstime, 3);
native_cond_timedwait(&count_threshold, &counter_mutex, &abstime);
}
/* Before exiting the lock we set ourselves up for the next thread */
counter++;
native_mutex_unlock(&counter_mutex);
/* now create the thread */
if (my_thread_create(&worker_threads[worker_thread_count], &attr,
worker_thread, (void *)*argv) != 0) {
native_mutex_lock(&counter_mutex);
counter--;
native_mutex_unlock(&counter_mutex);
fprintf(stderr, "%s: Could not create thread\n", my_progname);
continue;
}
worker_thread_count++;
}
/*
We loop until we know that all children have cleaned up.
*/
native_mutex_lock(&counter_mutex);
while (counter) {
struct timespec abstime;
set_timespec(&abstime, 3);
native_cond_timedwait(&count_threshold, &counter_mutex, &abstime);
}
native_mutex_unlock(&counter_mutex);
native_mutex_destroy(&init_mutex);
native_mutex_destroy(&counter_mutex);
native_cond_destroy(&count_threshold);
my_thread_attr_destroy(&attr);
for (i = 0; i < worker_thread_count; i++) {
if (my_thread_join(&worker_threads[i], nullptr))
fprintf(stderr, "%s: Could not join worker thread.\n", my_progname);
}
my_free(worker_threads);
} else {
if (!(mysql = db_connect(current_host, current_db, current_user,
opt_password[0]))) {
exitcode = 1;
goto end;
}
if (mysql_query(mysql,
"/*!40101 set @@character_set_database=binary */;") &&
(error = db_error(mysql))) {
if (exitcode == 0) exitcode = error;
/* We shall continue here, if --force was given */
goto end;
}
if (lock_tables && (error = lock_table(mysql, argc, argv))) {
if (exitcode == 0) exitcode = error;
goto end;
}
for (; *argv != nullptr; argv++)
if ((error = write_to_table(*argv, mysql))) {
if (exitcode == 0) exitcode = error;
break;
}
}
end:
db_disconnect(current_host, mysql);
free_passwords();
#if defined(_WIN32)
my_free(shared_memory_base_name);
#endif
my_end(my_end_arg);
return (exitcode);
}

872
client/mysqlshow.cc Normal file
View file

@ -0,0 +1,872 @@
/*
Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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
*/
/* Show databases, tables or columns */
#include <mysql.h>
#include <mysqld_error.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "client/include/caching_sha2_passwordopt-vars.h"
#include "client/include/client_priv.h"
#include "client/include/sslopt-vars.h"
#include "compression.h"
#include "m_string.h"
#include "my_alloc.h"
#include "my_dbug.h"
#include "my_default.h"
#include "my_inttypes.h"
#include "my_macros.h"
#include "my_sys.h"
#include "mysql/service_mysql_alloc.h"
#include "mysql/strings/m_ctype.h"
#include "nulls.h"
#include "print_version.h"
#include "strxnmov.h"
#include "typelib.h"
#include "welcome_copyright_notice.h" /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
static char *host = nullptr, *user = nullptr;
static bool opt_show_keys = false, opt_compress = false, opt_count = false,
opt_status = false;
static bool opt_table_type = false;
static bool debug_info_flag = false, debug_check_flag = false;
static uint my_end_arg = 0;
static uint opt_verbose = 0;
static const char *default_charset = MYSQL_AUTODETECT_CHARSET_NAME;
static char *opt_plugin_dir = nullptr, *opt_default_auth = nullptr;
static uint opt_enable_cleartext_plugin = 0;
static bool using_opt_enable_cleartext_plugin = false;
static uint opt_zstd_compress_level = default_zstd_compression_level;
static char *opt_compress_algorithm = nullptr;
#include "client/include/multi_factor_passwordopt-vars.h"
#if defined(_WIN32)
static char *shared_memory_base_name = nullptr;
#endif
static uint opt_protocol = 0;
static char *opt_bind_addr = nullptr;
static void get_options(int *argc, char ***argv);
static uint opt_mysql_port = 0;
static int list_dbs(MYSQL *mysql, const char *wild);
static int list_tables(MYSQL *mysql, const char *db, const char *table);
static int list_table_status(MYSQL *mysql, const char *db, const char *table);
static int list_fields(MYSQL *mysql, const char *db, const char *table,
const char *field);
static void print_header(const char *header, size_t head_length, ...);
static void print_row(const char *header, size_t head_length, ...);
static void print_trailer(size_t length, ...);
static void print_res_header(MYSQL_RES *result);
static void print_res_top(MYSQL_RES *result);
static void print_res_row(MYSQL_RES *result, MYSQL_ROW cur);
static const char *load_default_groups[] = {"mysqlshow", "client", nullptr};
static char *opt_mysql_unix_port = nullptr;
int main(int argc, char **argv) {
int error;
bool first_argument_uses_wildcards = false;
char *wild;
MYSQL mysql;
MY_INIT(argv[0]);
my_getopt_use_args_separator = true;
MEM_ROOT alloc{PSI_NOT_INSTRUMENTED, 512};
if (load_defaults("my", load_default_groups, &argc, &argv, &alloc)) exit(1);
my_getopt_use_args_separator = false;
get_options(&argc, &argv);
wild = nullptr;
if (argc) {
char *pos = argv[argc - 1], *to;
for (to = pos; *pos; pos++, to++) {
switch (*pos) {
case '*':
*pos = '%';
first_argument_uses_wildcards = true;
break;
case '?':
*pos = '_';
first_argument_uses_wildcards = true;
break;
case '%':
case '_':
first_argument_uses_wildcards = true;
break;
case '\\':
pos++;
default:
break;
}
*to = *pos;
}
*to = *pos; /* just to copy a '\0' if '\\' was used */
}
if (first_argument_uses_wildcards)
wild = argv[--argc];
else if (argc == 3) /* We only want one field */
wild = argv[--argc];
if (argc > 2) {
fprintf(stderr, "%s: Too many arguments\n", my_progname);
exit(1);
}
mysql_init(&mysql);
if (opt_compress) mysql_options(&mysql, MYSQL_OPT_COMPRESS, NullS);
if (SSL_SET_OPTIONS(&mysql)) {
fprintf(stderr, "%s", SSL_SET_OPTIONS_ERROR);
exit(1);
}
if (opt_protocol)
mysql_options(&mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
if (opt_bind_addr) mysql_options(&mysql, MYSQL_OPT_BIND, opt_bind_addr);
#if defined(_WIN32)
if (shared_memory_base_name)
mysql_options(&mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
shared_memory_base_name);
#endif
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
if (opt_compress_algorithm)
mysql_options(&mysql, MYSQL_OPT_COMPRESSION_ALGORITHMS,
opt_compress_algorithm);
mysql_options(&mysql, MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
&opt_zstd_compress_level);
if (opt_plugin_dir && *opt_plugin_dir)
mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
if (using_opt_enable_cleartext_plugin)
mysql_options(&mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
(char *)&opt_enable_cleartext_plugin);
mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr);
mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name",
"mysqlshow");
set_server_public_key(&mysql);
set_get_server_public_key_option(&mysql);
set_password_options(&mysql);
if (!(mysql_real_connect(&mysql, host, user, nullptr,
(first_argument_uses_wildcards) ? "" : argv[0],
opt_mysql_port, opt_mysql_unix_port, 0))) {
fprintf(stderr, "%s: %s\n", my_progname, mysql_error(&mysql));
exit(1);
}
if (ssl_client_check_post_connect_ssl_setup(
&mysql, [](const char *err) { fprintf(stderr, "%s\n", err); })) {
mysql_close(&mysql);
free_passwords();
mysql_server_end();
my_end(my_end_arg);
exit(1);
}
switch (argc) {
case 0:
error = list_dbs(&mysql, wild);
break;
case 1:
if (opt_status)
error = list_table_status(&mysql, argv[0], wild);
else
error = list_tables(&mysql, argv[0], wild);
break;
default:
if (opt_status && !wild)
error = list_table_status(&mysql, argv[0], argv[1]);
else
error = list_fields(&mysql, argv[0], argv[1], wild);
break;
}
mysql_close(&mysql); /* Close & free connection */
free_passwords();
#if defined(_WIN32)
my_free(shared_memory_base_name);
#endif
mysql_server_end();
my_end(my_end_arg);
exit(error ? 1 : 0);
}
static struct my_option my_long_options[] = {
{"bind-address", 0, "IP address to bind to.", (uchar **)&opt_bind_addr,
(uchar **)&opt_bind_addr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"character-sets-dir", 'c', "Directory for character set files.",
&charsets_dir, &charsets_dir, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"default-character-set", OPT_DEFAULT_CHARSET,
"Set the default character set.", &default_charset, &default_charset,
nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"count", OPT_COUNT,
"Show number of rows per table (may be slow for non-MyISAM tables).",
&opt_count, &opt_count, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"compress", 'C', "Use compression in server/client protocol.",
&opt_compress, &opt_compress, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
0, nullptr},
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", nullptr,
nullptr, nullptr, GET_STR, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"debug-check", OPT_DEBUG_CHECK,
"Check memory and open file usage at exit.", &debug_check_flag,
&debug_check_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
&debug_info_flag, &debug_info_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"default_auth", OPT_DEFAULT_AUTH,
"Default authentication client-side plugin to use.", &opt_default_auth,
&opt_default_auth, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
"Enable/disable the clear text authentication plugin.",
&opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin, nullptr,
GET_BOOL, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"help", '?', "Display this help and exit.", nullptr, nullptr, nullptr,
GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"host", 'h', "Connect to host.", &host, &host, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"status", 'i', "Shows a lot of extra information about each table.",
&opt_status, &opt_status, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"keys", 'k', "Show keys for table.", &opt_show_keys, &opt_show_keys,
nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#include "client/include/multi_factor_passwordopt-longopts.h"
{"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
&opt_plugin_dir, &opt_plugin_dir, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
{"port", 'P',
"Port number to use for connection or 0 for default to, in "
"order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
"/etc/services, "
#endif
"built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
&opt_mysql_port, &opt_mysql_port, nullptr, GET_UINT, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#ifdef _WIN32
{"pipe", 'W', "Use named pipes to connect to server.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
#endif
{"protocol", OPT_MYSQL_PROTOCOL,
"The protocol to use for connection (tcp, socket, pipe, memory).", nullptr,
nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
#if defined(_WIN32)
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
"Base name of shared memory.", &shared_memory_base_name,
&shared_memory_base_name, nullptr, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
nullptr, 0, nullptr},
#endif
{"show-table-type", 't', "Show table type column.", &opt_table_type,
&opt_table_type, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"socket", 'S', "The socket file to use for connection.",
&opt_mysql_unix_port, &opt_mysql_unix_port, nullptr, GET_STR, REQUIRED_ARG,
0, 0, 0, nullptr, 0, nullptr},
#include "client/include/caching_sha2_passwordopt-longopts.h"
#include "client/include/sslopt-longopts.h"
{"user", 'u', "User for login if not current user.", &user, &user, nullptr,
GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"verbose", 'v',
"More verbose output; you can use this multiple times to get even more "
"verbose output.",
nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0,
nullptr},
{"version", 'V', "Output version information and exit.", nullptr, nullptr,
nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"compression-algorithms", 0,
"Use compression algorithm in server/client protocol. Valid values "
"are any combination of 'zstd','zlib','uncompressed'.",
&opt_compress_algorithm, &opt_compress_algorithm, nullptr, GET_STR,
REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
{"zstd-compression-level", 0,
"Use this compression level in the client/server protocol, in case "
"--compression-algorithms=zstd. Valid range is between 1 and 22, "
"inclusive. Default is 3.",
&opt_zstd_compress_level, &opt_zstd_compress_level, nullptr, GET_UINT,
REQUIRED_ARG, 3, 1, 22, nullptr, 0, nullptr},
{nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
0, nullptr, 0, nullptr}};
static void usage(void) {
print_version();
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
puts(
"Shows the structure of a MySQL database (databases, tables, and "
"columns).\n");
printf("Usage: %s [OPTIONS] [database [table [column]]]\n", my_progname);
puts(
"\n\
If last argument contains a shell or SQL wildcard (*,?,% or _) then only\n\
what\'s matched by the wildcard is shown.\n\
If no database is given then all matching databases are shown.\n\
If no table is given, then all matching tables in database are shown.\n\
If no column is given, then all matching columns and column types in table\n\
are shown.");
print_defaults("my", load_default_groups);
my_print_help(my_long_options);
my_print_variables(my_long_options);
}
extern "C" {
static bool get_one_option(int optid, const struct my_option *opt,
char *argument) {
switch (optid) {
case 'v':
opt_verbose++;
break;
PARSE_COMMAND_LINE_PASSWORD_OPTION;
case 'W':
#ifdef _WIN32
opt_protocol = MYSQL_PROTOCOL_PIPE;
#endif
break;
case (int)OPT_ENABLE_CLEARTEXT_PLUGIN:
using_opt_enable_cleartext_plugin = true;
break;
case OPT_MYSQL_PROTOCOL:
opt_protocol =
find_type_or_exit(argument, &sql_protocol_typelib, opt->name);
break;
case '#':
DBUG_PUSH(argument ? argument : "d:t:o");
debug_check_flag = true;
break;
#include "client/include/sslopt-case.h"
case 'V':
print_version();
exit(0);
case '?':
case 'I': /* Info */
usage();
exit(0);
case 'C':
CLIENT_WARN_DEPRECATED("--compress", "--compression-algorithms");
break;
}
return false;
}
} // extern "C"
static void get_options(int *argc, char ***argv) {
int ho_error;
if ((ho_error = handle_options(argc, argv, my_long_options, get_one_option)))
exit(ho_error);
if (opt_count) {
/*
We need to set verbose to 2 as we need to change the output to include
the number-of-rows column
*/
opt_verbose = 2;
}
if (debug_info_flag) my_end_arg = MY_CHECK_ERROR | MY_GIVE_INFO;
if (debug_check_flag) my_end_arg = MY_CHECK_ERROR;
return;
}
static int list_dbs(MYSQL *mysql, const char *wild) {
const char *header;
size_t length = 0;
uint counter = 0;
ulong rowcount = 0L;
char tables[NAME_LEN + 1], rows[NAME_LEN + 1];
char query[NAME_LEN + 100];
MYSQL_FIELD *field;
MYSQL_RES *result;
MYSQL_ROW row = nullptr, rrow;
if (!(result = mysql_list_dbs(mysql, wild))) {
fprintf(stderr, "%s: Cannot list databases: %s\n", my_progname,
mysql_error(mysql));
return 1;
}
/*
If a wildcard was used, but there was only one row and it's name is an
exact match, we'll assume they really wanted to see the contents of that
database. This is because it is fairly common for database names to
contain the underscore (_), like INFORMATION_SCHEMA.
*/
if (wild && mysql_num_rows(result) == 1) {
row = mysql_fetch_row(result);
if (!my_strcasecmp(&my_charset_latin1, row[0], wild)) {
mysql_free_result(result);
if (opt_status)
return list_table_status(mysql, wild, nullptr);
else
return list_tables(mysql, wild, nullptr);
}
}
if (wild) printf("Wildcard: %s\n", wild);
header = "Databases";
length = strlen(header);
field = mysql_fetch_field(result);
if (length < field->max_length) length = field->max_length;
if (!opt_verbose)
print_header(header, length, NullS);
else if (opt_verbose == 1)
print_header(header, length, "Tables", 6, NullS);
else
print_header(header, length, "Tables", 6, "Total Rows", 12, NullS);
/* The first row may have already been read up above. */
while (row || (row = mysql_fetch_row(result))) {
counter++;
if (opt_verbose) {
if (!(mysql_select_db(mysql, row[0]))) {
MYSQL_RES *tresult = mysql_list_tables(mysql, (char *)nullptr);
if (mysql_affected_rows(mysql) > 0) {
sprintf(tables, "%6lu", (ulong)mysql_affected_rows(mysql));
rowcount = 0;
if (opt_verbose > 1) {
/* Print the count of tables and rows for each database */
MYSQL_ROW trow;
while ((trow = mysql_fetch_row(tresult))) {
snprintf(query, sizeof(query), "SELECT COUNT(*) FROM `%s`",
trow[0]);
if (!(mysql_query(mysql, query))) {
MYSQL_RES *rresult;
if ((rresult = mysql_store_result(mysql))) {
rrow = mysql_fetch_row(rresult);
rowcount += (ulong)my_strtoull(rrow[0], (char **)nullptr, 10);
mysql_free_result(rresult);
}
}
}
sprintf(rows, "%12lu", rowcount);
}
} else {
sprintf(tables, "%6d", 0);
sprintf(rows, "%12d", 0);
}
mysql_free_result(tresult);
} else {
my_stpcpy(tables, "N/A");
my_stpcpy(rows, "N/A");
}
}
if (!opt_verbose)
print_row(row[0], length, 0);
else if (opt_verbose == 1)
print_row(row[0], length, tables, 6, NullS);
else
print_row(row[0], length, tables, 6, rows, 12, NullS);
row = nullptr;
}
print_trailer(length, (opt_verbose > 0 ? 6 : 0), (opt_verbose > 1 ? 12 : 0),
0);
if (counter && opt_verbose)
printf("%u row%s in set.\n", counter, (counter > 1) ? "s" : "");
mysql_free_result(result);
return 0;
}
static int list_tables(MYSQL *mysql, const char *db, const char *table) {
const char *header;
size_t head_length;
uint counter = 0;
char query[2 * NAME_LEN + 100], rows[2 * NAME_LEN + 2], fields[16];
MYSQL_FIELD *field;
MYSQL_RES *result = nullptr;
MYSQL_ROW row, rrow;
if (mysql_select_db(mysql, db)) {
fprintf(stderr, "%s: Cannot connect to db %s: %s\n", my_progname, db,
mysql_error(mysql));
return 1;
}
if (table) {
/*
We just hijack the 'rows' variable for a bit to store the escaped
table name
*/
mysql_real_escape_string_quote(mysql, rows, table,
(unsigned long)strlen(table), '\'');
snprintf(query, sizeof(query), "show%s tables like '%s'",
opt_table_type ? " full" : "", rows);
} else
snprintf(query, sizeof(query), "show%s tables",
opt_table_type ? " full" : "");
if (mysql_query(mysql, query) || !(result = mysql_store_result(mysql))) {
fprintf(stderr, "%s: Cannot list tables in %s: %s\n", my_progname, db,
mysql_error(mysql));
exit(1);
}
printf("Database: %s", db);
if (table) printf(" Wildcard: %s", table);
putchar('\n');
header = "Tables";
head_length = strlen(header);
field = mysql_fetch_field(result);
if (head_length < field->max_length) head_length = field->max_length;
if (opt_table_type) {
if (!opt_verbose)
print_header(header, head_length, "table_type", 10, NullS);
else if (opt_verbose == 1)
print_header(header, head_length, "table_type", 10, "Columns", 8, NullS);
else {
print_header(header, head_length, "table_type", 10, "Columns", 8,
"Total Rows", 10, NullS);
}
} else {
if (!opt_verbose)
print_header(header, head_length, NullS);
else if (opt_verbose == 1)
print_header(header, head_length, "Columns", 8, NullS);
else
print_header(header, head_length, "Columns", 8, "Total Rows", 10, NullS);
}
while ((row = mysql_fetch_row(result))) {
counter++;
if (opt_verbose > 0) {
if (!(mysql_select_db(mysql, db))) {
mysql_real_escape_string_quote(mysql, rows, row[0],
(unsigned long)strlen(row[0]), '`');
snprintf(query, sizeof(query), "SELECT * FROM `%s` LIMIT 0", rows);
MYSQL_RES *rresult = (0 == mysql_query(mysql, query))
? mysql_store_result(mysql)
: nullptr;
ulong rowcount = 0L;
if (!rresult) {
my_stpcpy(fields, "N/A");
my_stpcpy(rows, "N/A");
} else {
sprintf(fields, "%8u", (uint)mysql_num_fields(rresult));
mysql_free_result(rresult);
if (opt_verbose > 1) {
/* Print the count of rows for each table */
snprintf(query, sizeof(query), "SELECT COUNT(*) FROM `%s`", row[0]);
if (!(mysql_query(mysql, query))) {
if ((rresult = mysql_store_result(mysql))) {
rrow = mysql_fetch_row(rresult);
rowcount +=
(unsigned long)my_strtoull(rrow[0], (char **)nullptr, 10);
mysql_free_result(rresult);
}
sprintf(rows, "%10lu", rowcount);
} else
sprintf(rows, "%10d", 0);
}
}
} else {
my_stpcpy(fields, "N/A");
my_stpcpy(rows, "N/A");
}
}
if (opt_table_type) {
if (!opt_verbose)
print_row(row[0], head_length, row[1], 10, NullS);
else if (opt_verbose == 1)
print_row(row[0], head_length, row[1], 10, fields, 8, NullS);
else
print_row(row[0], head_length, row[1], 10, fields, 8, rows, 10, NullS);
} else {
if (!opt_verbose)
print_row(row[0], head_length, NullS);
else if (opt_verbose == 1)
print_row(row[0], head_length, fields, 8, NullS);
else
print_row(row[0], head_length, fields, 8, rows, 10, NullS);
}
}
print_trailer(
head_length,
(opt_table_type ? 10
: opt_verbose > 0 ? 8
: 0),
(opt_table_type ? (opt_verbose > 0 ? 8 : 0) : (opt_verbose > 1 ? 10 : 0)),
!opt_table_type ? 0
: opt_verbose > 1 ? 10
: 0,
0);
if (counter && opt_verbose)
printf("%u row%s in set.\n\n", counter, (counter > 1) ? "s" : "");
mysql_free_result(result);
return 0;
}
static int list_table_status(MYSQL *mysql, const char *db, const char *wild) {
char query[NAME_LEN + 100];
size_t len;
MYSQL_RES *result;
MYSQL_ROW row;
len = sizeof(query);
len -= snprintf(query, len, "show table status from `%s`", db);
if (wild && wild[0] && len)
strxnmov(query + strlen(query), len - 1, " like '", wild, "'", NullS);
if (mysql_query(mysql, query) || !(result = mysql_store_result(mysql))) {
fprintf(stderr, "%s: Cannot get status for db: %s, table: %s: %s\n",
my_progname, db, wild ? wild : "", mysql_error(mysql));
if (mysql_errno(mysql) == ER_PARSE_ERROR)
fprintf(stderr,
"This error probably means that your MySQL server doesn't "
"support the\n\'show table status' command.\n");
return 1;
}
printf("Database: %s", db);
if (wild) printf(" Wildcard: %s", wild);
putchar('\n');
print_res_header(result);
while ((row = mysql_fetch_row(result))) print_res_row(result, row);
print_res_top(result);
mysql_free_result(result);
return 0;
}
/*
list fields uses field interface as an example of how to parse
a MYSQL FIELD
*/
static int list_fields(MYSQL *mysql, const char *db, const char *table,
const char *wild) {
char query[NAME_LEN + 100];
size_t len;
MYSQL_RES *result;
MYSQL_ROW row;
ulong rows = 0;
if (mysql_select_db(mysql, db)) {
fprintf(stderr, "%s: Cannot connect to db: %s: %s\n", my_progname, db,
mysql_error(mysql));
return 1;
}
if (opt_count) {
snprintf(query, sizeof(query), "select count(*) from `%s`", table);
if (mysql_query(mysql, query) || !(result = mysql_store_result(mysql))) {
fprintf(stderr, "%s: Cannot get record count for db: %s, table: %s: %s\n",
my_progname, db, table, mysql_error(mysql));
return 1;
}
row = mysql_fetch_row(result);
rows = (ulong)my_strtoull(row[0], (char **)nullptr, 10);
mysql_free_result(result);
}
len = sizeof(query);
len -= snprintf(query, len, "show /*!32332 FULL */ columns from `%s`", table);
if (wild && wild[0] && len)
strxnmov(query + strlen(query), len - 1, " like '", wild, "'", NullS);
if (mysql_query(mysql, query) || !(result = mysql_store_result(mysql))) {
fprintf(stderr, "%s: Cannot list columns in db: %s, table: %s: %s\n",
my_progname, db, table, mysql_error(mysql));
return 1;
}
printf("Database: %s Table: %s", db, table);
if (opt_count) printf(" Rows: %lu", rows);
if (wild && wild[0]) printf(" Wildcard: %s", wild);
putchar('\n');
print_res_header(result);
while ((row = mysql_fetch_row(result))) print_res_row(result, row);
print_res_top(result);
mysql_free_result(result);
if (opt_show_keys) {
snprintf(query, sizeof(query), "show keys from `%s`", table);
if (mysql_query(mysql, query) || !(result = mysql_store_result(mysql))) {
fprintf(stderr, "%s: Cannot list keys in db: %s, table: %s: %s\n",
my_progname, db, table, mysql_error(mysql));
return 1;
}
if (mysql_num_rows(result)) {
print_res_header(result);
while ((row = mysql_fetch_row(result))) print_res_row(result, row);
print_res_top(result);
} else
puts("Table has no keys");
mysql_free_result(result);
}
return 0;
}
/*****************************************************************************
General functions to print a nice ascii-table from data
*****************************************************************************/
static void print_header(const char *header, size_t head_length, ...) {
va_list args;
size_t length, i, str_length, pre_space;
const char *field;
va_start(args, head_length);
putchar('+');
field = header;
length = head_length;
for (;;) {
for (i = 0; i < length + 2; i++) putchar('-');
putchar('+');
if (!(field = va_arg(args, char *))) break;
length = va_arg(args, uint);
}
va_end(args);
putchar('\n');
va_start(args, head_length);
field = header;
length = head_length;
putchar('|');
for (;;) {
str_length = strlen(field);
if (str_length > length) str_length = length + 1;
pre_space = ((length - str_length) / 2) + 1;
for (i = 0; i < pre_space; i++) putchar(' ');
for (i = 0; i < str_length; i++) putchar(field[i]);
length = length + 2 - str_length - pre_space;
for (i = 0; i < length; i++) putchar(' ');
putchar('|');
if (!(field = va_arg(args, char *))) break;
length = va_arg(args, uint);
}
va_end(args);
putchar('\n');
va_start(args, head_length);
putchar('+');
field = header;
length = head_length;
for (;;) {
for (i = 0; i < length + 2; i++) putchar('-');
putchar('+');
if (!(field = va_arg(args, char *))) break;
length = va_arg(args, uint);
}
va_end(args);
putchar('\n');
}
static void print_row(const char *header, size_t head_length, ...) {
va_list args;
const char *field;
size_t i, length, field_length;
va_start(args, head_length);
field = header;
length = head_length;
for (;;) {
putchar('|');
putchar(' ');
fputs(field, stdout);
field_length = strlen(field);
for (i = field_length; i <= length; i++) putchar(' ');
if (!(field = va_arg(args, char *))) break;
length = va_arg(args, uint);
}
va_end(args);
putchar('|');
putchar('\n');
}
static void print_trailer(size_t head_length, ...) {
va_list args;
size_t length, i;
va_start(args, head_length);
length = head_length;
putchar('+');
for (;;) {
for (i = 0; i < length + 2; i++) putchar('-');
putchar('+');
if (!(length = va_arg(args, uint))) break;
}
va_end(args);
putchar('\n');
}
static void print_res_header(MYSQL_RES *result) {
MYSQL_FIELD *field;
print_res_top(result);
mysql_field_seek(result, 0);
putchar('|');
while ((field = mysql_fetch_field(result))) {
printf(" %-*s|", (int)field->max_length + 1, field->name);
}
putchar('\n');
print_res_top(result);
}
static void print_res_top(MYSQL_RES *result) {
uint i, length;
MYSQL_FIELD *field;
putchar('+');
mysql_field_seek(result, 0);
while ((field = mysql_fetch_field(result))) {
if ((length = strlen(field->name)) > field->max_length)
field->max_length = length;
else
length = field->max_length;
for (i = length + 2; i-- > 0;) putchar('-');
putchar('+');
}
putchar('\n');
}
static void print_res_row(MYSQL_RES *result, MYSQL_ROW cur) {
uint i, length;
MYSQL_FIELD *field;
putchar('|');
mysql_field_seek(result, 0);
for (i = 0; i < mysql_num_fields(result); i++) {
field = mysql_fetch_field(result);
length = field->max_length;
printf(" %-*s|", length + 1, cur[i] ? (char *)cur[i] : "");
}
putchar('\n');
}

2074
client/mysqlslap.cc Normal file

File diff suppressed because it is too large Load diff

11544
client/mysqltest.cc Normal file

File diff suppressed because it is too large Load diff

77
client/mysqltest/error.h Normal file
View file

@ -0,0 +1,77 @@
#ifndef ERROR_INCLUDED
#define ERROR_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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
///
/// This file declares the Error class.
#include <cstdint>
#include <cstring>
#include "mysql_com.h" // SQLSTATE_LENGTH
enum error_type { ERR_ERRNO = 1, ERR_SQLSTATE };
/// Class representing an error.
///
/// Contains following information
/// * Error code
/// * Error type
/// * SQLSTATE
///
/// If an error type value is
/// * ERR_ERRNO, then SQLSTATE value is "00000"
/// * ERR_SQLSTATE, then error code value is 0
class Error {
public:
Error(std::uint32_t error_code, const char *sqlstate, error_type type) {
this->m_error_code = error_code;
this->m_type = type;
std::strcpy(this->m_sqlstate, sqlstate);
}
/// Return a sqlstate for an error.
///
/// @retval SQLSTATE string
const char *sqlstate() { return m_sqlstate; }
/// Return an error code
///
/// @retval Error code
std::uint32_t error_code() { return m_error_code; }
/// Return an error type
///
/// @retval Error type (ERR_ERRNO or ERR_SQLSTATE)
error_type type() { return m_type; }
private:
std::uint32_t m_error_code;
error_type m_type;
char m_sqlstate[SQLSTATE_LENGTH + 1]; // '\0' terminated string
};
#endif // ERROR_INCLUDED

View file

@ -0,0 +1,53 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/error_names.h"
static st_error global_error_names[] = {
{"<No error>", static_cast<int>(-1), "", nullptr, nullptr, 0},
#ifndef IN_DOXYGEN
#include "mysqlclient_ername.h"
#include "mysqld_ername.h"
#endif /* IN_DOXYGEN */
{nullptr, 0, nullptr, nullptr, nullptr, 0}};
int get_errcode_from_name(std::string error_name) {
for (st_error *error = global_error_names; error->name; error++) {
if (error_name.compare(error->name) == 0) return error->error_code;
}
// Unknown SQL error name, return -1
return -1;
}
const char *get_errname_from_code(int error_code) {
// Return an empty string if error code is 0.
if (!error_code) return "";
for (st_error *error = global_error_names; error->error_code; error++) {
if (error->error_code == error_code) return error->name;
}
// Unknown SQL error code, return "<Unknown>" keyword.
return "<Unknown>";
}

View file

@ -0,0 +1,53 @@
#ifndef ERROR_NAMES_INCLUDED
#define ERROR_NAMES_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 <string>
struct st_error {
const char *name;
int error_code;
const char *description;
const char *odbc_state;
const char *jdbc_state;
unsigned int error_index;
};
/// Get an error code from an error name string.
///
/// @param error_name Error name string
///
/// @retval -1 if error name is unknown, error code otherwise.
int get_errcode_from_name(std::string error_name);
/// Get an error name from an error code.
///
/// @param error_code Error code
///
/// @retval "<Unknown>" keyword if error code is unknown, error name
/// otherwise.
const char *get_errname_from_code(int error_code);
#endif // ERROR_NAMES_INCLUDED

View file

@ -0,0 +1,56 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/expected_errors.h"
std::string Expected_errors::error_list() {
std::string error_list("");
for (std::size_t i = 0; i < m_errors.size(); i++) {
if (i > 0) error_list.append(",");
if (m_errors.at(i)->type() == ERR_ERRNO)
error_list.append(std::to_string(m_errors.at(i)->error_code()));
else
error_list.append(m_errors.at(i)->sqlstate());
}
return error_list;
}
std::vector<unsigned int> Expected_errors::errors() {
std::vector<unsigned int> errors;
for (std::size_t i = 0; i < m_errors.size(); i++) {
errors.push_back(m_errors.at(i)->error_code());
}
return errors;
}
void Expected_errors::add_error(const char *sqlstate, error_type type) {
std::unique_ptr<Error> new_error(new Error(0, sqlstate, type));
m_errors.push_back(std::move(new_error));
}
void Expected_errors::add_error(std::uint32_t error_code, error_type type) {
std::unique_ptr<Error> new_error(new Error(error_code, "00000", type));
m_errors.push_back(std::move(new_error));
}

View file

@ -0,0 +1,97 @@
#ifndef EXPECTED_ERRORS_INCLUDED
#define EXPECTED_ERRORS_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/error.h"
#include <memory>
#include <string>
#include <vector>
#define MAX_ERROR_COUNT 20
/// Class representing a list of error codes passed as argument to
/// mysqltest command <code>--error</code>.
class Expected_errors {
public:
typedef std::vector<std::unique_ptr<Error>>::iterator iterator;
Expected_errors() = default;
~Expected_errors() = default;
iterator begin() { return m_errors.begin(); }
iterator end() { return m_errors.end(); }
/// Return a sqlstate of the first error in the list.
///
/// @retval SQLSTATE string
const char *sqlstate() { return m_errors[0]->sqlstate(); }
/// Return an error type of the first error in the list.
///
/// @retval Error type (ERR_ERRNO or ERR_SQLSTATE)
error_type type() { return m_errors[0]->type(); }
/// Return length of the list containing errors.
///
/// @retval Length value
std::size_t count() { return m_errors.size(); }
/// Return list of error codes
///
/// @retval List of error codes
std::string error_list();
/// Return list of error codes in the list
///
/// @retval List of error codes
std::vector<std::uint32_t> errors();
/// Return an error code of the first error in the list.
///
/// @retval Error code
unsigned int error_code() { return m_errors[0]->error_code(); }
/// Add a new error to the existing list of errors.
///
/// @param sqlstate SQLSTATE string
/// @param type Error type
void add_error(const char *sqlstate, error_type type);
/// Add a new error to the existing list of errors.
///
/// @param error_code Error number
/// @param type Error type
void add_error(std::uint32_t error_code, error_type type);
/// Delete all errors from the vector.
void clear_list() { m_errors.clear(); }
private:
// List containing expected errors
std::vector<std::unique_ptr<Error>> m_errors;
};
#endif // EXPECTED_ERRORS_INCLUDED

View file

@ -0,0 +1,71 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/expected_warnings.h"
void Expected_warnings::add_warning(std::uint32_t warning_code,
const char *warning_name,
bool once_property) {
for (std::size_t i = 0; i < m_warnings.size(); i++) {
// Warning already exist, don't add it.
if (m_warnings.at(i)->warning_code() == warning_code) return;
}
// Add a new warning to the existing list.
std::unique_ptr<Warning> new_warning(
new Warning(warning_code, warning_name, once_property));
m_warnings.push_back(std::move(new_warning));
}
void Expected_warnings::remove_warning(std::uint32_t error_code,
bool once_property) {
for (std::size_t i = 0; i < m_warnings.size(); i++) {
if (m_warnings.at(i)->warning_code() == error_code) {
if (once_property)
m_warnings.at(i)->set_ignore_warning(true);
else
m_warnings.erase(begin() + i);
}
}
}
void Expected_warnings::update_list() {
for (std::size_t i = 0; i < m_warnings.size(); i++) {
if (m_warnings.at(i)->expired()) {
m_warnings.erase(begin() + i);
i--;
} else if (m_warnings.at(i)->ignore_warning()) {
m_warnings.at(i)->set_ignore_warning(false);
}
}
}
std::string Expected_warnings::warnings_list() {
std::string warnings;
for (std::size_t i = 0; i < m_warnings.size(); i++) {
if (i > 0) warnings.append(",");
warnings.append(m_warnings.at(i)->warning_name());
}
return warnings;
}

View file

@ -0,0 +1,91 @@
#ifndef EXPECTED_WARNINGS_INCLUDED
#define EXPECTED_WARNINGS_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/warning.h"
#include <memory>
#include <vector>
/// Class representing any one of the following list.
/// * List of disabled warnings
/// * List of enabled warnings
class Expected_warnings {
public:
typedef std::vector<std::unique_ptr<Warning>>::iterator iterator;
Expected_warnings() = default;
~Expected_warnings() = default;
iterator begin() { return m_warnings.begin(); }
iterator end() { return m_warnings.end(); }
/// Return length of the list containing warnings.
///
/// @retval Length value
std::size_t count() { return m_warnings.size(); }
/// Delete all warnings from the vector.
void clear_list() { m_warnings.clear(); }
/// Add a new warning to the existing list of warnings only if it
/// doesn't exist.
///
/// @param warning_code Warning number
/// @param warning_name Warning name
/// @param once_property Flag value representing the scope of a warning.
void add_warning(std::uint32_t warning_code, const char *warning_name,
bool once_property);
/// Remove a warning from the existing list of warnings if it exists.
/// If "ONCE" argument is specified, don't remove the warning, set a
/// flag to ignore disabling or enabling of it for the next statement
/// only.
///
/// @param warning_code Warning number
/// @param once_property Flag value representing the scope of a
/// disabled warning
void remove_warning(std::uint32_t warning_code, bool once_property);
/// Update the list of disabled or enabled warnings.
///
/// * Remove all the warnings which are disabled or enabled only for
/// one statement. These warnings are expired after the execution of
/// next statement.
///
/// * Reset ignore_warning flag value to 0 if it set to 1.
void update_list();
/// Return a list of symbolic names of disabled or enabled warnings.
///
/// @retval String containing symbolic names of disabled warnings
std::string warnings_list();
private:
// List containing disabled or enabled warnings.
std::vector<std::unique_ptr<Warning>> m_warnings;
};
#endif // EXPECTED_WARNINGS_INCLUDED

122
client/mysqltest/logfile.cc Normal file
View file

@ -0,0 +1,122 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/logfile.h"
#include <cstring>
#include <iostream>
#include <string>
Logfile::Logfile() : m_file(nullptr), m_bytes_written(0) {
std::memset(m_filename, 0, sizeof(m_filename));
}
bool Logfile::flush() {
if (m_file && std::fflush(m_file)) {
// Flush failed, thrown an error.
std::cerr << "Failed to flush the contents to file '" << m_filename
<< "': " << std::strerror(errno) << ", errno: " << errno
<< std::endl;
return true;
}
return false;
}
bool Logfile::open(const char *dirname, const char *filename, const char *ext) {
if (!filename) {
m_file = stdout;
} else {
fn_format(m_filename, filename, dirname, ext,
*dirname ? MY_REPLACE_DIR | MY_REPLACE_EXT : MY_REPLACE_EXT);
this->close();
// Open a file, print an error message if the operation fails.
if ((m_file = std::fopen(m_filename, "wb+")) == nullptr) {
std::cerr << "Failed to open log file '" << m_filename
<< "': " << std::strerror(errno) << ", errno: " << errno
<< std::endl;
return true;
}
}
return false;
}
bool Logfile::write(const char *data, std::size_t length) {
if (length > 0) {
if (std::fwrite(data, 1, length, m_file) != length) {
std::cerr << "Failed to write " << length << "bytes to '" << m_filename
<< "': " << std::strerror(errno) << ", errno: " << errno
<< std::endl;
return true;
}
m_bytes_written += length;
}
return false;
}
void Logfile::close() {
if (m_file) {
if (m_file == stdout)
std::fflush(m_file);
else
std::fclose(m_file);
}
m_file = nullptr;
}
void Logfile::show_tail(unsigned int lines) {
if (!m_file || m_file == stdout || lines == 0) return;
// Move to end of the file.
if (std::fseek(m_file, 0, SEEK_END) != 0) {
std::cerr << "fseek() failed: " << std::strerror(errno)
<< ", errno: " << errno << std::endl;
return;
}
int position = std::ftell(m_file);
unsigned int count = 0;
while (position) {
std::fseek(m_file, --position, SEEK_SET);
// Read one character at a time, and stop reading when N number of
// newline characters are found.
if ((std::fgetc(m_file) == '\n') && (count++ == lines)) break;
}
std::cerr << std::endl
<< "The result from queries just before the failure was:"
<< std::endl;
char buffer[256];
std::size_t bytes;
if (count <= lines) std::fseek(m_file, 0L, SEEK_SET);
while ((bytes = std::fread(buffer, 1, sizeof(buffer), m_file)) > 0) {
if (std::fwrite(buffer, 1, bytes, stderr) != bytes)
std::cerr << "fwrite failed: " << std::strerror(errno)
<< ", errno: " << errno << std::endl;
}
std::fflush(stderr);
}

View file

@ -0,0 +1,89 @@
#ifndef LOGFILE_INCLUDED
#define LOGFILE_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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
///
/// This file declares the Log file class.
#include "my_io.h"
#include "my_sys.h"
class Logfile {
public:
Logfile();
Logfile(const Logfile &) = default;
virtual ~Logfile() { close(); }
/// Return file name.
///
/// @retval Name of the file.
const char *file_name() const { return m_filename; }
/// Return number bytes written into a log file.
///
/// @retval Number bytes written into a log file.
std::size_t bytes_written() const { return m_bytes_written; }
/// Flush any unwritten content from the stream's buffer to the
/// associated file.
///
/// @retval False if successful, true otherwise.
bool flush();
/// Construct a file path using directory name, file name and extension
/// arguments and open it in write/update mode.
///
/// @param dirname Directory name
/// @param filename File name
/// @param ext Extension name
///
/// @retval False if successful, true otherwise.
bool open(const char *dirname, const char *filename, const char *ext);
/// Write the contents in data array to a file.
///
/// @param data Pointer to the array to be written
/// @param length Length of the buffer
///
/// @retval False if successful, true otherwise.
bool write(const char *data, std::size_t length);
/// Print the last N number of lines from a file to stderr.
///
/// @param lines Number of lines
void show_tail(unsigned int lines);
private:
/// Close the given file stream.
void close();
char m_filename[FN_REFLEN];
FILE *m_file;
std::size_t m_bytes_written;
};
#endif // LOGFILE_INCLUDED

View file

@ -0,0 +1,264 @@
/* Copyright (c) 2019, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "client/mysqltest/regular_expressions.h"
#include "my_compiler.h"
#include "mysql/strings/m_ctype.h"
[[noreturn]] extern void die(const char *fmt, ...)
MY_ATTRIBUTE((format(printf, 1, 2)));
/*
Filter for queries that can be run using the
MySQL Prepared Statements C API.
*/
static const char *const ps_re_str =
"^("
"[[:space:]]*REPLACE[[:space:]]|"
"[[:space:]]*INSERT[[:space:]]|"
"[[:space:]]*UPDATE[[:space:]]|"
"[[:space:]]*DELETE[[:space:]]|"
"[[:space:]]*SELECT[[:space:]]|"
"[[:space:]]*CREATE[[:space:]]+DATABASE[[:space:]]|"
"[[:space:]]*CREATE[[:space:]]+INDEX[[:space:]]|"
"[[:space:]]*CREATE[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*CREATE[[:space:]]+USER[[:space:]]|"
"[[:space:]]*CREATE[[:space:]]+TEMPORARY[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+DATABASE[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+INDEX[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+USER[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+VIEW[[:space:]]|"
"[[:space:]]*DROP[[:space:]]+TEMPORARY[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*ALTER[[:space:]]+USER[[:space:]]|"
"[[:space:]]*RENAME[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*RENAME[[:space:]]+USER[[:space:]]|"
"[[:space:]]*TRUNCATE[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*ANALYZE[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*CHECKSUM[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*CHECKSUM[[:space:]]+TABLES[[:space:]]|"
"[[:space:]]*OPTIMIZE[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*REPAIR[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*GRANT[[:space:]]|"
"[[:space:]]*KILL[[:space:]]|"
"[[:space:]]*REVOKE[[:space:]]+ALL[[:space:]]+PRIVILEGES[[:space:]]|"
"[[:space:]]*DO[[:space:]]|"
"[[:space:]]*CALL[[:space:]]|"
"[[:space:]]*COMMIT[[:space:]]|"
"[[:space:]]*SET[[:space:]]+OPTION[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+CREATE[[:space:]]+TABLE[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+CREATE[[:space:]]+PROCEDURE[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+CREATE[[:space:]]+FUNCTION[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+CREATE[[:space:]]+VIEW[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+CREATE[[:space:]]+EVENT[[:space:]]|"
"[[:space:]]*INSTALL[[:space:]]+PLUGIN[[:space:]]|"
"[[:space:]]*UNINSTALL[[:space:]]+PLUGIN[[:space:]]|"
"[[:space:]]*RESET[[:space:]]+MASTER[[:space:]]|"
"[[:space:]]*RESET[[:space:]]+SLAVE[[:space:]]|"
"[[:space:]]*RESET[[:space:]]+QUERY[[:space:]]+CACHE[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+BINLOG[[:space:]]+EVENTS[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+MASTER[[:space:]]+LOGS[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+MASTER[[:space:]]+STATUS[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+BINARY[[:space:]]+LOGS[[:space:]]|"
"[[:space:]]*SHOW[[:space:]]+SLAVE[[:space:]]+STATUS[[:space:]]|"
"[[:space:]]*SLAVE[[:space:]]+START[[:space:]]|"
"[[:space:]]*SLAVE[[:space:]]+STOP[[:space:]]|"
"[[:space:]]*DELETE[[:space:]]+MULTI[[:space:]]|"
"[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|"
"[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])";
/*
Filter for queries that can be run using the
Stored procedures.
*/
static const char *const sp_re_str = ps_re_str;
/*
Filter for queries that can be run as views.
*/
static const char *const view_re_str =
"^("
"[[:space:]]*SELECT[[:space:]])";
const char *const opt_trace_re_str =
"^("
"[[:space:]]*INSERT[[:space:]]|"
"[[:space:]]*UPDATE[[:space:]]|"
"[[:space:]]*DELETE[[:space:]]|"
"[[:space:]]*EXPLAIN[[:space:]]|"
"[[:space:]]*SELECT[[:space:]])";
/* Filter for queries that can be converted to EXPLAIN. */
static const char *const explain_re_str =
"^("
"[[:space:]]*(SELECT|DELETE|UPDATE|INSERT|REPLACE)[[:space:]])";
/* Precompiled regular expressions. */
std::regex ps_re(ps_re_str,
std::regex_constants::nosubs | std::regex_constants::icase);
std::regex sp_re(sp_re_str,
std::regex_constants::nosubs | std::regex_constants::icase);
std::regex view_re(view_re_str,
std::regex_constants::nosubs | std::regex_constants::icase);
std::regex opt_trace_re(opt_trace_re_str, std::regex_constants::nosubs |
std::regex_constants::icase);
std::regex explain_re(explain_re_str, std::regex_constants::nosubs |
std::regex_constants::icase);
extern CHARSET_INFO *charset_info;
/**
Execute all substitutions on val.
@param[in] val Pointer to the character string to be used as
input for the regex replace operation.
@param[in,out] r Pointer to the st_replace_regex structure which
holds arguments and information for the command.
@param[in,out] len Pointer to variable holding length of input string.
@retval True If substituition was made.
@retval False If no substituition was made.
@note
r->buf points at the resulting buffer with all substitutions done.
len points at length of resulting buffer.
r->even_buf and r->odd_buf might have been reallocated.
r->even_buf_len and r->odd_buf_len might have been changed.
@todo
At some point figure out if there is a way to do everything in one pass.
*/
int multi_reg_replace(struct st_replace_regex *r, char *val, size_t *len) {
size_t i;
char *in_buf, *out_buf;
int *buf_len_p;
in_buf = val;
out_buf = r->even_buf;
buf_len_p = &r->even_buf_len;
r->buf = nullptr;
/*
For each substitution, perform replacement only if the input buffer
is not empty.
*/
if (*len > 0) {
for (i = 0; i < r->regex_arr.size(); i++) {
try {
struct st_regex re(r->regex_arr[i]);
char *save_out_buf = out_buf;
std::regex rpat(re.pattern, (re.icase == 0)
? std::regex_constants::ECMAScript
: std::regex_constants::icase);
std::string sin = std::string(in_buf, *len);
std::string sout;
/*
We use iterators instead of using the input buffer directly as
it may include the null character (0x00) and characters succeeding
them will be ignored unless we specify the start and end positions
of the input string explicitly.
*/
std::regex_replace(std::back_inserter(sout), sin.begin(), sin.end(),
rpat, re.replace, std::regex_constants::format_sed);
/*
If some replacement is performed, write the replaced string into the
output buffer.
*/
if (sout.compare(sin) != 0) {
*len = sout.length();
if (*len >= (uint)*buf_len_p) {
uint need_buf_len = (*len) + 1;
out_buf = (char *)my_realloc(PSI_NOT_INSTRUMENTED, out_buf,
need_buf_len, MYF(MY_WME + MY_FAE));
*buf_len_p = need_buf_len;
}
// Copy result to output buffer.
strncpy(out_buf, sout.c_str(), *len + 1);
// If the buffer has been reallocated, make adjustments
if (save_out_buf != out_buf) {
if (save_out_buf == r->even_buf)
r->even_buf = out_buf;
else
r->odd_buf = out_buf;
}
r->buf = out_buf;
if (in_buf == val) in_buf = r->odd_buf;
std::swap(in_buf, out_buf);
buf_len_p =
(out_buf == r->even_buf) ? &r->even_buf_len : &r->odd_buf_len;
}
} catch (const std::regex_error &e) {
die("Error in replace_regex for `/%s/%s/` : %s",
(r->regex_arr[i]).pattern, (r->regex_arr[i]).replace, e.what());
}
}
}
return (r->buf == nullptr);
}
/**
Function to check if a protocol's regular expression matches the query
string.
@param re Pointer to a precompiled regular expression.
@param str Pointer to character string in which the pattern needs to be
searched.
@retval 1 If the pattern is found.
@retval 0 If the pattern is not found.
*/
int search_protocol_re(std::regex *re, const char *str) {
while (my_isspace(charset_info, *str)) str++;
if (str[0] == '/' && str[1] == '*') {
const char *comm_end = strstr(str, "*/");
if (!comm_end) die("Statement is unterminated comment");
str = comm_end + 2;
}
// Check if statement matches the pattern string
if (std::regex_search(str, *re, std::regex_constants::match_continuous)) {
/*
Simulate the "[^;]*$" check which follows the SQL prefix
in the regex used to filter statements to be run with ps/
sp protocol as using it directly in the regex is currently
not possible due to an issue in the standard regex library.
*/
if ((re == &ps_re || re == &sp_re) && strchr(str, ';') != nullptr) return 0;
// Match found
return 1;
} else {
return 0;
}
}

View file

@ -0,0 +1,66 @@
/* Copyright (c) 2019, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 REGULAR_EXPRESSIONS_INCLUDED
#define REGULAR_EXPRESSIONS_INCLUDED
#include <regex>
#include "mysql/components/services/bits/psi_bits.h"
#include "prealloced_array.h"
extern std::regex explain_re;
extern std::regex opt_trace_re;
extern std::regex ps_re;
extern std::regex sp_re;
extern std::regex view_re;
struct st_regex {
char *pattern; /* Pattern to be replaced */
char *replace; /* String or expression to replace the pattern with */
int icase; /* true if the match is case insensitive */
};
struct st_replace_regex {
st_replace_regex() : regex_arr(PSI_NOT_INSTRUMENTED) {}
/* stores a list of st_regex subsitutions */
Prealloced_array<st_regex, 128> regex_arr;
/*
Temporary storage areas for substitutions. To reduce unnessary copying
and memory freeing/allocation, we pre-allocate two buffers, and alternate
their use, one for input/one for output, the roles changing on the next
st_regex substitution. At the end of substitutions, buf points to the
one containing the final result.
*/
char *buf{nullptr};
char *even_buf{nullptr};
char *odd_buf{nullptr};
int even_buf_len{0};
int odd_buf_len{0};
};
int multi_reg_replace(struct st_replace_regex *r, char *val, size_t *len);
int search_protocol_re(std::regex *re, const char *str);
#endif // REGULAR_EXPRESSIONS_INCLUDED

View file

@ -0,0 +1,93 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/secondary_engine.h"
#include "client/mysqltest/error_names.h"
#include "client/mysqltest/utils.h"
#include <assert.h>
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <unordered_map>
static int offload_count_after = 0;
static int offload_count_before = 0;
/// Get secondary engine execution count value.
//
/// @param mysql mysql handle
/// @param mode Mode value (either "after" or "before")
///
/// @retval True if the query fails, false otherwise.
bool Secondary_engine::offload_count(MYSQL *mysql, const char *mode) {
std::string offload_count;
const char *query =
"SHOW GLOBAL STATUS LIKE 'Secondary_engine_execution_count'";
if (query_get_string(mysql, query, 1, &offload_count)) {
int error = mysql_errno(mysql);
if (error == 0 || error == 1104 || error == 2006) return false;
std::cerr << "mysqltest: Query '" << query << "' failed, ERROR " << error
<< " (" << mysql_sqlstate(mysql) << "): " << mysql_error(mysql)
<< std::endl;
return true;
}
if (!std::strcmp(mode, "before")) {
offload_count_before = get_int_val(offload_count.c_str());
} else if (!std::strcmp(mode, "after")) {
if (!offload_count_after) {
offload_count_after = get_int_val(offload_count.c_str());
} else {
offload_count_after =
offload_count_after + get_int_val(offload_count.c_str());
}
}
return false;
}
/// Report secondary engine execution count value.
///
/// @param filename File to store the count value
void Secondary_engine::report_offload_count(const char *filename) {
if (!offload_count_after && offload_count_after < offload_count_before)
offload_count_after = offload_count_before;
int count_val = offload_count_after - offload_count_before;
assert(count_val >= 0);
std::ofstream report_file(filename, std::ios::out);
if (report_file.is_open()) {
std::string count = std::to_string(count_val);
report_file << count << std::endl;
}
report_file.close();
}

View file

@ -0,0 +1,51 @@
#ifndef SECONDARY_ENGINE_INCLUDED
#define SECONDARY_ENGINE_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 <string>
#include <vector>
#include "mysql.h"
class Secondary_engine {
public:
Secondary_engine() = default;
~Secondary_engine() = default;
/// Get the secondary engine execution count value.
///
/// @param mysql mysql handle
/// @param mode Mode value (either "after" or "before")
///
/// @retval True if the query fails, false otherwise.
bool offload_count(MYSQL *mysql, const char *mode);
/// Report secondary engine execution count value.
///
/// @param filename File to store the count value
void report_offload_count(const char *filename);
};
#endif // SECONDARY_ENGINE_INCLUDED

85
client/mysqltest/utils.cc Normal file
View file

@ -0,0 +1,85 @@
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 "client/mysqltest/utils.h"
#include <cstring>
#include <iostream>
#include <stdexcept>
/// Run a query and return one field in the result set from the first
/// row and column.
///
/// @param mysql mysql handle
/// @param query Query string
/// @param column Column value
/// @param str String object to store the rvalue
///
/// @retval True if fails to get the value, true otherwise.
bool query_get_string(MYSQL *mysql, const char *query, int column,
std::string *str) {
MYSQL_RES *res = nullptr;
MYSQL_ROW row;
if (mysql_query(mysql, query)) {
mysql_free_result(res);
return true;
}
if (((res = mysql_store_result(mysql)) == nullptr) ||
((row = mysql_fetch_row(res)) == nullptr)) {
mysql_free_result(res);
str = nullptr;
return true;
}
str->assign(row[column] ? row[column] : "NULL");
mysql_free_result(res);
return false;
}
/// Use stoi function to get the integer value from a string.
///
/// @param str String which may contain an integer or an alphanumeric
/// string.
///
/// @retval Integer value corresponding to the contents of the string,
/// if conversion is successful, or -1 if integer is out of
/// range, or if the conversion fails.
int get_int_val(const char *str) {
int value;
std::size_t size;
try {
value = std::stoi(str, &size, 10);
if (size != std::strlen(str)) value = -1;
} catch (const std::out_of_range &) {
std::fprintf(stderr, "Integer value '%s' is out of range. ", str);
value = -1;
} catch (const std::invalid_argument &) {
value = -1;
}
return value;
}

53
client/mysqltest/utils.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef UTILS_INCLUDED
#define UTILS_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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 <string>
#include "mysql.h"
/// Run a query and return one field in the result set from the first
/// row and column.
///
/// @param mysql mysql handle
/// @param query Query string
/// @param column Column value
/// @param str String object to store the rvalue
///
/// @retval True if fails to get the value, true otherwise.
bool query_get_string(MYSQL *mysql, const char *query, int column,
std::string *str);
/// Use stoi function to get the integer value from a string.
///
/// @param str String which may contain an integer or an alphanumeric
/// string.
///
/// @retval Integer value corresponding to the contents of the string,
/// if conversion is successful, or -1 if integer is out of
/// range, or if the conversion fails.
int get_int_val(const char *str);
#endif // UTILS_INCLUDED

View file

@ -0,0 +1,83 @@
#ifndef WARNING_INCLUDED
#define WARNING_INCLUDED
// Copyright (c) 2018, 2024, 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 designed to work 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 either included with
// the program or referenced in the documentation.
//
// 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
///
/// This file declares the Warning class.
#include <cstdint>
#include <string>
/// Class representing a warning.
///
/// Contains following information
/// * A flag representing whether to ignore a warning or not
/// * A flag representing the scope of a warning
/// * Warning name
/// * Warning number
class Warning {
public:
Warning(std::uint32_t warning_code, const char *warning_name, bool once) {
this->m_ignore_warning = false;
this->m_once_property = once;
this->m_warning_code = warning_code;
this->m_warning_name.assign(warning_name);
}
/// Check if a warning is disabled/enabled for next statement only.
///
/// @retval True if the warning is disabled or enabled for next
/// statement only, false otherwise.
bool expired() { return m_once_property; }
/// Return ignore_warning flag value
///
/// @retval True if ignore_warning flag is set, false otherwise.
bool ignore_warning() { return m_ignore_warning; }
/// Return a symbolic name representing a warning
///
/// @retval Symbolic name for a warning.
const char *warning_name() { return m_warning_name.c_str(); }
/// Return a warning code
///
/// @retval Warning code
std::uint32_t warning_code() { return m_warning_code; }
/// Set ignore_warning flag
///
/// @param value Boolean value for ignore_warning flag
void set_ignore_warning(bool value) { m_ignore_warning = value; }
private:
bool m_ignore_warning;
bool m_once_property;
std::string m_warning_name;
std::uint32_t m_warning_code;
};
#endif // WARNING_INCLUDED

202
client/path.cc Normal file
View file

@ -0,0 +1,202 @@
/*
Copyright (c) 2012, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "client/path.h"
#include <stddef.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "my_dir.h"
#include "my_inttypes.h"
#include "my_io.h"
#include "my_sys.h"
#ifndef _WIN32
#include <pwd.h>
#endif
Path::Path() = default;
Path::Path(const std::string &s) { path(s); }
Path::Path(const Path &p) {
m_filename = p.m_filename;
m_path = p.m_path;
}
bool Path::path_getcwd() {
char path[FN_REFLEN];
if (my_getwd(path, FN_REFLEN - 1, MYF(MY_WME))) return false;
m_path.clear();
m_path.append(path);
trim();
return true;
}
void Path::trim() {
if (m_path.length() <= 1) return;
std::string::iterator it = m_path.end();
--it;
while ((*it) == FN_LIBCHAR && m_path.length() > 1) {
m_path.erase(it--);
}
}
void Path::parent_directory(Path *out) {
size_t idx = m_path.rfind(FN_DIRSEP);
if (idx == std::string::npos) {
out->path("");
} else
out->path(m_path.substr(0, idx));
}
Path &Path::up() {
size_t idx = m_path.rfind(FN_DIRSEP);
if (idx == std::string::npos) {
m_path.clear();
} else
m_path.assign(m_path.substr(0, idx));
return *this;
}
Path &Path::append(const std::string &path) {
if (m_path.length() > 1 && path[0] != FN_LIBCHAR) m_path.append(FN_DIRSEP);
m_path.append(path);
trim();
return *this;
}
Path &Path::filename_append(const std::string &ext) {
m_filename.append(ext);
trim();
return *this;
}
void Path::path(const std::string &p) {
m_path.clear();
m_path.append(p);
trim();
}
void Path::filename(const std::string &f) { m_filename = f; }
void Path::path(const Path &p) { path(p.m_path); }
void Path::filename(const Path &p) { path(p.m_filename); }
bool Path::qpath(const std::string &qp) {
size_t idx = qp.rfind(FN_DIRSEP);
if (idx == std::string::npos) {
m_filename = qp;
m_path.clear();
} else {
filename(qp.substr(idx + 1, qp.size() - idx));
path(qp.substr(0, idx));
}
if (is_qualified_path())
return true;
else
return false;
}
bool Path::normalize_path() {
if (!m_path.length()) return false;
char real_path[FN_REFLEN];
size_t real_path_len;
real_path_len = cleanup_dirname(real_path, m_path.c_str());
if (real_path_len > FN_REFLEN) return false;
if (my_realpath(real_path, real_path, MYF(0))) return false;
m_path.clear();
m_path.append(real_path);
trim();
return true;
}
bool Path::is_qualified_path() { return m_filename.length() > 0; }
bool Path::exists() {
if (!is_qualified_path()) {
MY_DIR *dir = my_dir(m_path.c_str(), MY_WANT_STAT | MY_DONT_SORT);
if (dir == nullptr) return false;
my_dirend(dir);
return true;
} else {
MY_STAT s;
std::string qpath(m_path);
qpath.append(FN_DIRSEP).append(m_filename);
if (my_stat(qpath.c_str(), &s, MYF(0)) == nullptr) return false;
if (!MY_S_ISREG(s.st_mode)) return false;
return true;
}
}
const std::string Path::to_str() {
std::string qpath(m_path);
if (m_filename.length() != 0) {
qpath.append(FN_DIRSEP);
qpath.append(m_filename);
}
return qpath;
}
bool Path::empty() {
if (!exists()) return true;
MY_DIR *dir;
bool ret = false;
if (!(dir = my_dir(m_path.c_str(), MY_WANT_STAT | MY_DONT_SORT)))
ret = false;
else {
if (dir->number_off_files == 2) ret = true;
}
my_dirend(dir);
return ret;
}
#ifndef _WIN32
void Path::get_homedir() {
struct passwd *pwd;
pwd = getpwuid(geteuid());
if (pwd == nullptr) return;
if (pwd->pw_dir != nullptr)
path(pwd->pw_dir);
else
path("");
}
#endif
std::ostream &operator<<(std::ostream &op, const Path &p) {
std::string qpath(p.m_path);
if (p.m_filename.length() != 0) {
qpath.append(FN_DIRSEP);
qpath.append(p.m_filename);
}
return op << qpath;
}

90
client/path.h Normal file
View file

@ -0,0 +1,90 @@
/*
Copyright (c) 2012, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 PATH_UTIL_INCLUDED
#define PATH_UTIL_INCLUDED
#include <ostream>
#include <string>
/**
A helper class for handling file paths. The class can handle the memory
on its own or it can wrap an external string.
@note This is a rather trivial wrapper which doesn't handle malformed paths
or filenames very well.
@see unittest/gunit/path-t.cc
*/
class Path {
public:
Path();
Path(const std::string &s);
Path(const Path &p);
bool path_getcwd();
void trim();
void parent_directory(Path *out);
Path &up();
Path &append(const std::string &path);
Path &filename_append(const std::string &ext);
void path(const std::string &p);
void filename(const std::string &f);
void path(const Path &p);
void filename(const Path &p);
bool qpath(const std::string &qp);
bool normalize_path();
bool is_qualified_path();
bool exists();
const std::string to_str();
bool empty();
#ifndef _WIN32
void get_homedir();
#endif
friend std::ostream &operator<<(std::ostream &op, const Path &p);
private:
std::string m_path;
std::string m_filename;
};
std::ostream &operator<<(std::ostream &op, const Path &p);
#endif

98
client/pattern_matcher.cc Normal file
View file

@ -0,0 +1,98 @@
/*
Copyright (c) 2017, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 "pattern_matcher.h"
#include "my_dbug.h"
#include "my_sys.h"
struct CHARSET_INFO;
/**
@brief Parses concatenated patterns and adds them to internal pattern list
@param[in] patterns concatenated patterns
@param[in] delimiter delimiter for pattern concatenation
@return number of added patterns
*/
size_t Pattern_matcher::add_patterns(const std::string &patterns,
char delimiter) {
DBUG_TRACE;
const size_t length = patterns.length();
size_t pattern_count = 0;
// we don't parse empty patterns
if (length == 0) return pattern_count;
size_t first = 0;
size_t last = 0;
do {
// find end of the token
if ((last = patterns.find(delimiter, first)) == std::string::npos)
last = length;
// we store only tokens that are not empty
if (last - first > 0) {
m_patterns.emplace(patterns, first, last - first);
++pattern_count;
}
first = last + 1;
} while (last != length);
return pattern_count;
}
/**
@brief Verifies whether text matches any of the matcher internal patterns
@param[in] text string to search for patterns
@param[in] info charset information for comparison rules
@return result of matching the text to internal patterns
@retval true at least one pattern matches provided string
@retval false string does not match any of the patterns
*/
bool Pattern_matcher::is_matching(const std::string &text,
const CHARSET_INFO *info) const {
DBUG_TRACE;
// traverse all patterns, return true on first match
for (auto &pattern : m_patterns) {
if (info->coll->wildcmp(info, text.c_str(), text.c_str() + text.length(),
pattern.c_str(), pattern.c_str() + pattern.length(),
WILD_ESCAPE, WILD_ONE, WILD_MANY) == 0) {
return true;
}
}
// none of the patterns matched
return false;
}
/**
@brief Removes all previously stored patterns from pattern matcher
*/
void Pattern_matcher::clear() { m_patterns.clear(); }

55
client/pattern_matcher.h Normal file
View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2017, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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 <string>
#include <unordered_set>
#include "mysql/strings/m_ctype.h"
/**
Enables comparison of strings against particular set of patterns. Patterns
may contain wildcards (WILD_ONE/WILD_MANY/WILD_ESCAPE). Pattern strings may
be added to the class through a special method. Matching method traverses all
of the patterns within pattern matcher in search for a match.
*/
class Pattern_matcher {
public:
size_t add_patterns(const std::string &patterns, char delimiter = ':');
bool is_matching(const std::string &text, const CHARSET_INFO *info) const;
void clear();
private:
/** any (single) character wild card */
const static char WILD_ONE = '?';
/** zero or many characters wild card */
const static char WILD_MANY = '*';
/** escape sequence character */
const static char WILD_ESCAPE = '\\';
/** used for storing matcher patterns */
std::unordered_set<std::string> m_patterns;
};

261
client/readline.cc Normal file
View file

@ -0,0 +1,261 @@
/*
Copyright (c) 2000, 2024, 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 designed to work 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 either included with
the program or referenced in the documentation.
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
*/
/* readline for batch mode */
#include <stdio.h>
#include <sys/types.h>
#include "client/my_readline.h"
#include "m_string.h"
#include "my_dbug.h"
#include "my_dir.h"
#include "my_inttypes.h"
#include "my_io.h"
#include "my_sys.h"
#include "my_thread_local.h"
#include "mysql/service_mysql_alloc.h"
static bool init_line_buffer(LINE_BUFFER *buffer, File file, ulong size,
ulong max_size);
static bool init_line_buffer_from_string(LINE_BUFFER *buffer, char *str);
static size_t fill_buffer(LINE_BUFFER *buffer);
static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length);
LINE_BUFFER *batch_readline_init(ulong max_size, FILE *file) {
LINE_BUFFER *line_buff;
#ifndef _WIN32
MY_STAT input_file_stat;
if (my_fstat(fileno(file), &input_file_stat) ||
MY_S_ISDIR(input_file_stat.st_mode) ||
MY_S_ISBLK(input_file_stat.st_mode))
return nullptr;
#endif
if (!(line_buff =
(LINE_BUFFER *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*line_buff),
MYF(MY_WME | MY_ZEROFILL))))
return nullptr;
if (init_line_buffer(line_buff, my_fileno(file), batch_io_size, max_size)) {
my_free(line_buff);
return nullptr;
}
return line_buff;
}
char *batch_readline(LINE_BUFFER *line_buff,
bool binary_mode [[maybe_unused]]) {
char *pos;
ulong out_length;
if (!(pos = intern_read_line(line_buff, &out_length))) return nullptr;
if (out_length && pos[out_length - 1] == '\n') {
#if defined(_WIN32)
/*
On Windows platforms we also need to remove '\r',
unconditionally.
*/
/* Remove '\n' */
if (--out_length && pos[out_length - 1] == '\r') /* Remove '\r' */
out_length--;
#else
/*
On Unix-like platforms we only remove it if we are not
on binary mode.
*/
/* Remove '\n' */
if (--out_length && !binary_mode && pos[out_length - 1] == '\r')
/* Remove '\r' */
out_length--;
#endif
}
line_buff->read_length = out_length;
pos[out_length] = 0;
DBUG_DUMP("Query: ", (unsigned char *)pos, out_length);
return pos;
}
void batch_readline_end(LINE_BUFFER *line_buff) {
if (line_buff) {
my_free(line_buff->buffer);
my_free(line_buff);
}
}
LINE_BUFFER *batch_readline_command(LINE_BUFFER *line_buff, char *str) {
if (!line_buff)
if (!(line_buff =
(LINE_BUFFER *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*line_buff),
MYF(MY_WME | MY_ZEROFILL))))
return nullptr;
if (init_line_buffer_from_string(line_buff, str)) {
my_free(line_buff);
return nullptr;
}
return line_buff;
}
/*****************************************************************************
Functions to handle buffered readings of lines from a stream
******************************************************************************/
static bool init_line_buffer(LINE_BUFFER *buffer, File file, ulong size,
ulong max_buffer) {
buffer->file = file;
buffer->bufread = size;
buffer->max_size = max_buffer;
if (!(buffer->buffer = (char *)my_malloc(
PSI_NOT_INSTRUMENTED, buffer->bufread + 1, MYF(MY_WME | MY_FAE))))
return true;
buffer->end_of_line = buffer->end = buffer->buffer;
buffer->buffer[0] = 0; /* For easy start test */
return false;
}
/*
init_line_buffer_from_string can be called on the same buffer
several times. the resulting buffer will contain a
concatenation of all strings separated by spaces
*/
static bool init_line_buffer_from_string(LINE_BUFFER *buffer, char *str) {
const uint old_length = (uint)(buffer->end - buffer->buffer);
const uint length = (uint)strlen(str);
if (!(buffer->buffer = buffer->start_of_line = buffer->end_of_line =
(char *)my_realloc(PSI_NOT_INSTRUMENTED, (uchar *)buffer->buffer,
old_length + length + 2,
MYF(MY_FAE | MY_ALLOW_ZERO_PTR))))
return true;
buffer->end = buffer->buffer + old_length;
if (old_length) buffer->end[-1] = ' ';
memcpy(buffer->end, str, length);
buffer->end[length] = '\n';
buffer->end[length + 1] = 0;
buffer->end += length + 1;
buffer->eof = 1;
buffer->max_size = 1;
return false;
}
/*
Fill the buffer retaining the last n bytes at the beginning of the
newly filled buffer (for backward context). Returns the number of new
bytes read from disk.
*/
static size_t fill_buffer(LINE_BUFFER *buffer) {
size_t read_count;
const uint bufbytes = (uint)(buffer->end - buffer->start_of_line);
if (buffer->eof) return 0; /* Everything read */
/* See if we need to grow the buffer. */
for (;;) {
const uint start_offset = (uint)(buffer->start_of_line - buffer->buffer);
read_count = (buffer->bufread - bufbytes) / batch_io_size;
if ((read_count *= batch_io_size)) break;
if (buffer->bufread * 2 > buffer->max_size) {
/*
So we must grow the buffer but we cannot due to the max_size limit.
Return 0 w/o setting buffer->eof to signal this condition.
*/
return 0;
}
buffer->bufread *= 2;
if (!(buffer->buffer =
(char *)my_realloc(PSI_NOT_INSTRUMENTED, buffer->buffer,
buffer->bufread + 1, MYF(MY_WME | MY_FAE)))) {
buffer->error = my_errno();
return (size_t)-1;
}
buffer->start_of_line = buffer->buffer + start_offset;
buffer->end = buffer->buffer + bufbytes;
}
/* Shift stuff down. */
if (buffer->start_of_line != buffer->buffer) {
memmove(buffer->buffer, buffer->start_of_line, bufbytes);
buffer->end = buffer->buffer + bufbytes;
}
/* Read in new stuff. */
if ((read_count = my_read(buffer->file, (uchar *)buffer->end, read_count,
MYF(MY_WME))) == MY_FILE_ERROR) {
buffer->error = my_errno();
return (size_t)-1;
}
DBUG_PRINT("fill_buff", ("Got %lu bytes", (ulong)read_count));
if (!read_count) {
buffer->eof = 1;
/* Kludge to pretend every nonempty file ends with a newline. */
if (bufbytes && buffer->end[-1] != '\n') {
read_count = 1;
*buffer->end = '\n';
}
}
buffer->end_of_line = (buffer->start_of_line = buffer->buffer) + bufbytes;
buffer->end += read_count;
*buffer->end = 0; /* Sentinel */
return read_count;
}
char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length) {
char *pos;
size_t length;
DBUG_TRACE;
buffer->start_of_line = buffer->end_of_line;
for (;;) {
pos = buffer->end_of_line;
while (*pos != '\n' && pos != buffer->end) pos++;
if (pos == buffer->end) {
/*
fill_buffer() can return NULL on EOF (in which case we abort),
on error, or when the internal buffer has hit the size limit.
In the latter case return what we have read so far and signal
string truncation.
*/
if (!(length = fill_buffer(buffer))) {
if (buffer->eof) return nullptr;
} else if (length == (size_t)-1)
return nullptr;
else
continue;
pos--; /* break line here */
buffer->truncated = true;
} else
buffer->truncated = false;
buffer->end_of_line = pos + 1;
*out_length = (ulong)(pos + 1 - buffer->eof - buffer->start_of_line);
DBUG_DUMP("Query: ", (unsigned char *)buffer->start_of_line, *out_length);
return buffer->start_of_line;
}
}

114
cmake/abi_check.cmake Normal file
View file

@ -0,0 +1,114 @@
# Copyright (c) 2009, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
#
# Headers which need to be checked for abi/api compatibility are in
# API_PREPROCESSOR_HEADER. plugin.h is tested implicitly via
# plugin_audit.h and plugin_ftparser.h.
#
# We use gcc specific preprocessing command and sed/diff, so it will
# only be run on Unix and only if gcc is used. On some Unixes,
# (Solaris) sed or diff might act differently from GNU, so we run only
# on systems we can trust.
# On Windows we use the Windows subsystem for Linux and gcc and sed
# installed in it, if available.
SET(RUN_ABI_CHECK 0)
IF(LINUX AND MY_COMPILER_IS_GNU)
SET(RUN_ABI_CHECK 1)
ELSEIF(WIN32)
FIND_PROGRAM(WSL_EXECUTABLE wsl HINTS C:/Windows/Sysnative)
IF (WSL_EXECUTABLE)
SET (COMPILER "gcc")
# Check that the compiler is available under WSL.
EXECUTE_PROCESS(
COMMAND ${WSL_EXECUTABLE} which ${COMPILER}
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE COMPILER_LOCATION)
IF (COMPILER_LOCATION STREQUAL "/usr/bin/gcc")
SET(RUN_ABI_CHECK 1)
MESSAGE(STATUS "Will do ABI check using ${WSL_EXECUTABLE} (gcc/sed)")
ENDIF()
ENDIF()
ENDIF()
SET(API_PREPROCESSOR_HEADER
${CMAKE_SOURCE_DIR}/include/mysql/plugin_audit.h
${CMAKE_SOURCE_DIR}/include/mysql/plugin_ftparser.h
${CMAKE_SOURCE_DIR}/include/mysql.h
${CMAKE_SOURCE_DIR}/include/mysql/client_plugin.h
${CMAKE_SOURCE_DIR}/include/mysql/plugin_auth.h
${CMAKE_SOURCE_DIR}/include/mysql/plugin_keyring.h
)
IF(NOT WITHOUT_SERVER)
LIST(APPEND API_PREPROCESSOR_HEADER
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_thread_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_mutex_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_rwlock_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_cond_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_file_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_socket_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_table_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_mdl_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_idle_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_stage_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_statement_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_transaction_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_memory_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_error_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_system_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/psi/psi_abi_metric_v1.h
${CMAKE_SOURCE_DIR}/include/mysql/services.h
)
ENDIF()
IF(MY_COMPILER_IS_GNU)
IF(CMAKE_C_COMPILER MATCHES "ccache$")
SET(COMPILER ${CMAKE_C_COMPILER_ARG1})
STRING(REGEX REPLACE "^ " "" COMPILER ${COMPILER})
ELSE()
SET(COMPILER ${CMAKE_C_COMPILER})
ENDIF()
ENDIF()
IF(RUN_ABI_CHECK)
UNSET(API_PP_FILES)
FOREACH(file ${API_PREPROCESSOR_HEADER})
LIST(APPEND API_PP_FILES ${file}.pp)
ENDFOREACH()
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_BINARY_DIR}/abi_check.out
COMMAND ${CMAKE_COMMAND}
-DCOMPILER=${COMPILER}
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
-DBINARY_DIR=${CMAKE_BINARY_DIR}
-DWSL_EXECUTABLE=${WSL_EXECUTABLE}
"-DABI_HEADERS=${API_PREPROCESSOR_HEADER}"
-P ${CMAKE_SOURCE_DIR}/cmake/do_abi_check.cmake
DEPENDS ${API_PREPROCESSOR_HEADER} ${API_PP_FILES}
VERBATIM
)
ADD_CUSTOM_TARGET(abi_check ALL
DEPENDS ${CMAKE_BINARY_DIR}/abi_check.out
)
ENDIF()

View file

@ -0,0 +1,64 @@
# Copyright (c) 2021, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# Wrap ADD_CUSTOM_TARGET to get rid of Warning MSB8065: File not created
# Custom build for ... succeeded, but specified output ... has not been created.
#
# For the Visual Studio Generator, we generate an extra
# 'cmake -E touch cmakefiles/${target_name}'
#
# Note that we handle only *one* COMMAND.
# This is good enough for the current codebase.
FUNCTION(MY_ADD_CUSTOM_TARGET TARGET_NAME)
CMAKE_PARSE_ARGUMENTS(CUSTOM_ARG
"ALL"
"COMMENT;WORKING_DIRECTORY"
"COMMAND;DEPENDS"
${ARGN}
)
SET(TARGET_COMMAND)
IF(CUSTOM_ARG_ALL)
LIST(APPEND TARGET_COMMAND "ALL")
ENDIF()
IF(CUSTOM_ARG_DEPENDS)
LIST(APPEND TARGET_COMMAND "DEPENDS" ${CUSTOM_ARG_DEPENDS})
ENDIF()
IF(CUSTOM_ARG_COMMAND)
LIST(APPEND TARGET_COMMAND "COMMAND" ${CUSTOM_ARG_COMMAND})
ENDIF()
IF(CMAKE_GENERATOR MATCHES "Visual Studio")
STRING(TOLOWER "${TARGET_NAME}" target_name)
LIST(APPEND TARGET_COMMAND
"COMMAND" "${CMAKE_COMMAND}" -E touch cmakefiles/${target_name})
ENDIF()
IF(CUSTOM_ARG_COMMENT)
LIST(APPEND TARGET_COMMAND "COMMENT" ${CUSTOM_ARG_COMMENT})
ENDIF()
IF(CUSTOM_ARG_WORKING_DIRECTORY)
LIST(APPEND
TARGET_COMMAND "WORKING_DIRECTORY" ${CUSTOM_ARG_WORKING_DIRECTORY})
ENDIF()
ADD_CUSTOM_TARGET(${TARGET_NAME} ${TARGET_COMMAND})
ENDFUNCTION(MY_ADD_CUSTOM_TARGET)

148
cmake/bison.cmake Normal file
View file

@ -0,0 +1,148 @@
# Copyright (c) 2009, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# This should be REQUIRED, but we have to support source tarball build.
# https://dev.mysql.com/doc/refman/8.0/en/source-installation.html
SET(MIN_BISON_VERSION_REQUIRED "3.0.4")
# Bison seems to be stuck at version 2.3 in macOS.
# Look for alternative custom installations, e.g.
# /opt/bison-3.8.2/bin
IF(APPLE AND NOT DEFINED BISON_EXECUTABLE)
SET(OPT_BISON_DIR "/opt")
IF(IS_DIRECTORY "${OPT_BISON_DIR}")
SET(PREFERRED_BISON_VERSION "3.8.2")
FILE(GLOB FOUND_BISON_BIN_DIRS
LIST_DIRECTORIES true
"${OPT_BISON_DIR}/bison-*/bin"
)
IF(FOUND_BISON_BIN_DIRS)
# FILE GLOB seems to sort entries, but we need to REVERSE the list:
# NATURAL uses strverscmp(3)
LIST(SORT FOUND_BISON_BIN_DIRS COMPARE NATURAL ORDER DESCENDING)
IF(IS_DIRECTORY "${OPT_BISON_DIR}/bison-${PREFERRED_BISON_VERSION}/bin")
SET(BISON_PATHS "${OPT_BISON_DIR}/bison-${PREFERRED_BISON_VERSION}/bin")
LIST(REMOVE_ITEM FOUND_BISON_BIN_DIRS "${BISON_PATHS}")
ENDIF()
FOREACH(path ${FOUND_BISON_BIN_DIRS})
LIST(APPEND BISON_PATHS ${path})
ENDFOREACH()
MESSAGE(STATUS "Looking for bison in ${BISON_PATHS}")
FIND_PROGRAM(BISON_EXECUTABLE bison
NO_DEFAULT_PATH
PATHS ${BISON_PATHS})
ENDIF()
ENDIF()
ENDIF()
# Look for HOMEBREW bison before the standard OS version.
# Note that it is *not* symlinked like most other executables.
# /usr/local/opt/bison/bin/bison
# /usr/local/opt/bison -> ../Cellar/bison/3.8.2
# /opt/homebrew/opt/bison
IF(APPLE AND NOT DEFINED BISON_EXECUTABLE)
FIND_PROGRAM(BREW_EXECUTABLE brew)
IF(BREW_EXECUTABLE)
EXECUTE_PROCESS(COMMAND ${BREW_EXECUTABLE} --prefix bison
OUTPUT_VARIABLE BREW_BISON_PREFIX_OUTPUT
RESULT_VARIABLE BREW_BISON_PREFIX_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
IF(BREW_BISON_PREFIX_RESULT EQUAL 0)
SET(BISON_HOMEBREW_PATH "${BREW_BISON_PREFIX_OUTPUT}/bin")
ENDIF()
ENDIF()
FIND_PROGRAM(BISON_EXECUTABLE bison
NO_DEFAULT_PATH
PATHS "${BISON_HOMEBREW_PATH}" "${HOMEBREW_HOME}/bison/bin")
ENDIF()
# Look for winflexbison3, see e.g.
# https://github.com/lexxmark/winflexbison/releases
# or
# https://chocolatey.org/install
# choco install winflexbison3
IF(WIN32 AND NOT DEFINED BISON_EXECUTABLE)
SET(MY_BISON_PATHS
c:/bin/bin
c:/bin/lib/winflexbison3/tools
c:/ProgramData/chocolatey/bin
)
FOREACH(_path ${MY_BISON_PATHS})
FILE(TO_NATIVE_PATH ${_path} NATIVE_PATH)
LIST(APPEND NATIVE_BISON_PATHS "${NATIVE_PATH}")
ENDFOREACH()
MESSAGE(STATUS "Looking for win_bison in ${NATIVE_BISON_PATHS}")
FIND_PROGRAM(BISON_EXECUTABLE
NAMES win_bison win-bison
NO_DEFAULT_PATH
PATHS ${NATIVE_BISON_PATHS}
)
# Look for Flex also, we may need it later.
IF(BISON_EXECUTABLE)
FIND_PROGRAM(FLEX_EXECUTABLE
NAMES flex win-flex win_flex
NO_DEFAULT_PATH
PATHS ${NATIVE_BISON_PATHS}
)
FIND_PATH(FLEX_INCLUDE_DIR FlexLexer.h
NO_DEFAULT_PATH
PATHS ${NATIVE_BISON_PATHS}
)
ENDIF()
ENDIF()
FIND_PACKAGE(BISON)
IF(NOT BISON_FOUND)
MESSAGE(WARNING "No bison found!!")
MESSAGE(WARNING "If you have bison in a non-standard location, "
"you can do 'cmake -DBISON_EXECUTABLE=</path/to/bison-executable>"
)
IF(APPLE)
MESSAGE(WARNING "We recommend Homebrew bison.")
ENDIF()
RETURN()
ENDIF()
IF(BISON_VERSION VERSION_LESS "${MIN_BISON_VERSION_REQUIRED}")
MESSAGE(WARNING "Bison version ${BISON_VERSION} is old.")
MESSAGE(WARNING "If you have a newer bison in a non-standard location, "
"you can do 'cmake -DBISON_EXECUTABLE=</path/to/bison-executable>"
)
IF(APPLE)
MESSAGE(WARNING "We recommend Homebrew bison.")
ENDIF()
MESSAGE(FATAL_ERROR
"Please update to version ${MIN_BISON_VERSION_REQUIRED} or higher"
)
ENDIF()
# TODO(tdidriks): replace with "--warnings=all"
# Legacy backward compatibility suppressions:
# * no-yacc: for --yacc
# * no-precedence: for useless precedence or/and associativity rules
SET(BISON_FLAGS_WARNINGS
"--warnings=all,no-yacc,no-precedence"
CACHE INTERNAL "BISON 3.x flags")

81
cmake/boost.cmake Normal file
View file

@ -0,0 +1,81 @@
# Copyright (c) 2014, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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(BOOST_PACKAGE_NAME "boost_1_84_0")
# Always use the bundled version.
SET(BOOST_SOURCE_DIR ${CMAKE_SOURCE_DIR}/extra/boost)
# Contains all header files we need.
# (All the directories that contain at least one needed file).
SET(BOOST_INCLUDE_DIR ${BOOST_SOURCE_DIR}/${BOOST_PACKAGE_NAME})
# We have a limited set of patches/bugfixes here:
SET(BOOST_PATCHES_DIR
"${CMAKE_SOURCE_DIR}/include/${BOOST_PACKAGE_NAME}/patches")
ADD_LIBRARY(boost INTERFACE)
ADD_LIBRARY(extra::boost ALIAS boost)
TARGET_INCLUDE_DIRECTORIES(boost SYSTEM BEFORE INTERFACE
${BOOST_PATCHES_DIR} ${BOOST_INCLUDE_DIR})
IF(NOT WIN32)
# See boost/container_hash/hash.hpp
# We pretend that the compiler is pre-c++98, in order to hide the
# usage of std::unary_function<..> (which was removed in C++17)
# For windows: see boost/config/stdlib/dinkumware.hpp
TARGET_COMPILE_DEFINITIONS(boost INTERFACE BOOST_NO_CXX98_FUNCTION_BASE)
ENDIF()
MESSAGE(STATUS "BOOST_PATCHES_DIR ${BOOST_PATCHES_DIR}")
MESSAGE(STATUS "BOOST_INCLUDE_DIR ${BOOST_INCLUDE_DIR}")
IF(NOT WIN32)
FILE(GLOB_RECURSE BOOST_PATCHES_LIST
RELATIVE ${BOOST_PATCHES_DIR}
${BOOST_PATCHES_DIR}/*.hpp
)
SET(DIFF_COMMAND_LIST "#! /bin/bash")
FOREACH(PATCHED_FILE ${BOOST_PATCHES_LIST})
SET(ORIGINAL_FILE_PATH "${BOOST_INCLUDE_DIR}/${PATCHED_FILE}")
SET(PATCHED_FILE_PATH "${BOOST_PATCHES_DIR}/${PATCHED_FILE}")
LIST(APPEND DIFF_COMMAND_LIST
"diff -u ${ORIGINAL_FILE_PATH} ${PATCHED_FILE_PATH}")
ENDFOREACH()
# Add true, to get zero exit status.
LIST(APPEND DIFF_COMMAND_LIST "true")
STRING(REPLACE ";" "\n" DIFF_COMMAND_LINES "${DIFF_COMMAND_LIST}")
FILE(GENERATE
OUTPUT ${CMAKE_BINARY_DIR}/boost_patch_diffs
CONTENT "${DIFF_COMMAND_LINES}"
)
ADD_CUSTOM_TARGET(show_boost_patches
COMMAND bash ${CMAKE_BINARY_DIR}/boost_patch_diffs
DEPENDS ${CMAKE_BINARY_DIR}/boost_patch_diffs
)
ENDIF()

View file

@ -0,0 +1,88 @@
# Copyright (c) 2012, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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(CheckCCompilerFlag)
INCLUDE(CheckCXXCompilerFlag)
INCLUDE(cmake/floating_point.cmake)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Compiler options
IF(UNIX)
IF(MY_COMPILER_IS_GNU_OR_CLANG AND NOT SOLARIS)
SET(SECTIONS_FLAG "-ffunction-sections -fdata-sections")
ELSE()
SET(SECTIONS_FLAG)
ENDIF()
# Default GCC flags
IF(MY_COMPILER_IS_GNU)
SET(COMMON_C_FLAGS "-fno-omit-frame-pointer")
# Disable inline optimizations for valgrind testing to avoid false positives
IF(WITH_VALGRIND)
STRING_PREPEND(COMMON_C_FLAGS "-fno-inline ")
ENDIF()
# Disable floating point expression contractions to avoid result differences
IF(HAVE_C_FLOATING_POINT_FUSED_MADD)
STRING_APPEND(COMMON_C_FLAGS " -ffp-contract=off")
ENDIF()
SET(COMMON_CXX_FLAGS "-std=c++20 -fno-omit-frame-pointer")
# Disable inline optimizations for valgrind testing to avoid false positives
IF(WITH_VALGRIND)
STRING_PREPEND(COMMON_CXX_FLAGS "-fno-inline ")
ENDIF()
# Disable floating point expression contractions to avoid result differences
IF(HAVE_CXX_FLOATING_POINT_FUSED_MADD)
STRING_APPEND(COMMON_CXX_FLAGS " -ffp-contract=off")
ENDIF()
ENDIF()
# Default Clang flags
IF(MY_COMPILER_IS_CLANG)
SET(COMMON_C_FLAGS "-fno-omit-frame-pointer")
SET(COMMON_CXX_FLAGS "-std=c++20 -fno-omit-frame-pointer")
ENDIF()
# Faster TLS model
# libprotobuf-lite.so.24.4: cannot allocate memory in static TLS block
IF(MY_COMPILER_IS_GNU_OR_CLANG
AND NOT LINUX_ARM
AND NOT SOLARIS AND NOT LINUX_RHEL6 AND NOT LINUX_ALPINE)
STRING_APPEND(COMMON_C_FLAGS " -ftls-model=initial-exec")
STRING_APPEND(COMMON_CXX_FLAGS " -ftls-model=initial-exec")
ENDIF()
# Use STRING_PREPEND here, so command-line input can override our defaults.
STRING_PREPEND(CMAKE_C_FLAGS "${COMMON_C_FLAGS} ")
STRING_PREPEND(CMAKE_C_FLAGS_RELWITHDEBINFO "${SECTIONS_FLAG} ")
STRING_PREPEND(CMAKE_C_FLAGS_RELEASE "${SECTIONS_FLAG} ")
STRING_PREPEND(CMAKE_C_FLAGS_MINSIZEREL "${SECTIONS_FLAG} ")
STRING_PREPEND(CMAKE_CXX_FLAGS "${COMMON_CXX_FLAGS} ")
STRING_PREPEND(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${SECTIONS_FLAG} ")
STRING_PREPEND(CMAKE_CXX_FLAGS_RELEASE "${SECTIONS_FLAG} ")
STRING_PREPEND(CMAKE_CXX_FLAGS_MINSIZEREL "${SECTIONS_FLAG} ")
ENDIF()

View file

@ -0,0 +1,62 @@
# Copyright (c) 2010, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# This file includes build settings used for MySQL release
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckLibraryExists)
OPTION(DEBUG_EXTNAME "" ON)
IF(LINUX AND CMAKE_BUILD_TYPE)
IF(CMAKE_BUILD_TYPE_UPPER MATCHES "REL")
OPTION(REPRODUCIBLE_BUILD "" ON)
ENDIF()
ENDIF()
IF(NOT COMPILATION_COMMENT)
SET(COMPILATION_COMMENT "MySQL Community (GPL)")
ENDIF()
IF(NOT COMPILATION_COMMENT_SERVER)
SET(COMPILATION_COMMENT_SERVER "MySQL Community Server (GPL)")
ENDIF()
IF(LINUX)
IF(NOT IGNORE_AIO_CHECK)
# Ensure aio is available on Linux (required by InnoDB)
CHECK_INCLUDE_FILES(libaio.h HAVE_LIBAIO_H)
CHECK_LIBRARY_EXISTS(aio io_queue_init "" HAVE_LIBAIO)
IF(NOT HAVE_LIBAIO_H OR NOT HAVE_LIBAIO)
MESSAGE(FATAL_ERROR "
aio is required on Linux, you need to install the required library:
Debian/Ubuntu: apt-get install libaio-dev
RedHat/Fedora/Oracle Linux: yum install libaio-devel
SuSE: zypper install libaio-devel
If you really do not want it, pass -DIGNORE_AIO_CHECK to cmake.
")
ENDIF()
ENDIF()
ENDIF()

View file

@ -0,0 +1,38 @@
# Copyright (c) 2009, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# Charsets and collations
IF(NOT DEFAULT_CHARSET)
SET(DEFAULT_CHARSET "utf8mb4")
ENDIF()
IF(NOT DEFAULT_COLLATION)
SET(DEFAULT_COLLATION "utf8mb4_0900_ai_ci")
ENDIF()
IF(WITH_EXTRA_CHARSETS AND NOT WITH_EXTRA_CHARSETS STREQUAL "all")
MESSAGE(WARNING "Option WITH_EXTRA_CHARSETS is no longer supported")
ENDIF()
SET(MYSQL_DEFAULT_CHARSET_NAME "${DEFAULT_CHARSET}")
SET(MYSQL_DEFAULT_COLLATION_NAME "${DEFAULT_COLLATION}")

View file

@ -0,0 +1,96 @@
# Copyright (c) 2006, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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 various cmake policies. This must be done *after* CMAKE_MINIMUM_REQUIRED.
# Explicitly set CMP0018 and CMP0022 = NEW since newer versions of
# CMake has OLD as default even if OLD is deprecated.
# See cmake --help-policy CMP0018 / CMP0022
CMAKE_POLICY(SET CMP0018 NEW)
CMAKE_POLICY(SET CMP0022 NEW)
# Disallow use of the LOCATION property for build targets.
CMAKE_POLICY(SET CMP0026 NEW)
# Include TARGET_OBJECTS expressions.
CMAKE_POLICY(SET CMP0051 NEW)
# INTERPROCEDURAL_OPTIMIZATION is enforced when enabled (CMake 3.9+)
IF(POLICY CMP0069)
CMAKE_POLICY(SET CMP0069 NEW)
ENDIF()
# Do not produce ``<tgt>_LIB_DEPENDS`` cache entries to propagate library
# link dependencies. In cmake code, use this instead:
# GET_TARGET_PROPERTY(TARGET_LIB_DEPENDS ${target} LINK_LIBRARIES)
IF(POLICY CMP0073)
CMAKE_POLICY(SET CMP0073 NEW)
ENDIF()
# In CMake 3.12 and above, the
#
# * ``check_include_file`` macro in the ``CheckIncludeFile`` module, the
# * ``check_include_file_cxx`` macro in the
# ``CheckIncludeFileCXX`` module, and the
# * ``check_include_files`` macro in the ``CheckIncludeFiles`` module
#
# now prefer to link the check executable to the libraries listed in the
# ``CMAKE_REQUIRED_LIBRARIES`` variable.
IF(POLICY CMP0075)
CMAKE_POLICY(SET CMP0075 NEW)
ENDIF()
# versionadded:: 3.15
# In CMake 3.14 and below, MSVC runtime library selection flags are added to
# the default ``CMAKE_<LANG>_FLAGS_<CONFIG>`` cache entries by CMake
# automatically.
#
# .. note::
#
# Once the policy has taken effect at the top of a project, that choice
# must be used throughout the tree. In projects that have nested projects
# in subdirectories, be sure to convert everything together.
#
# https://cmake.org/cmake/help/latest/policy/CMP0091.html
# This policy was introduced in CMake version 3.15. It may be set by
# cmake_policy() or cmake_minimum_required(). If it is not set, CMake
# does not warn, and uses OLD behavior.
#
# We have code in cmake/os/Windows.cmake to handle the OLD behaviour.
# Whenever we add 3rd party stuff: be sure to keep the policy.
# Also look for CMAKE_MSVC_RUNTIME_LIBRARY and MSVC_RUNTIME_LIBRARY
# in 3rd party cmake code.
IF(POLICY CMP0091)
# Explicitly setting it to OLD will issue a warning for some cmake versions,
# so just keep the default behaviour, see above.
# CMAKE_POLICY(SET CMP0091 OLD)
ENDIF()
# versionadded:: 3.18
# It is not allowed to create an ``ALIAS`` target with the same name as an
# another target.
# The ``OLD`` behavior for this policy is to allow target overwrite.
# The ``NEW`` behavior of this policy is to prevent target overwriting.
IF(POLICY CMP0107)
CMAKE_POLICY(SET CMP0107 NEW)
ENDIF()

196
cmake/compile_flags.cmake Normal file
View file

@ -0,0 +1,196 @@
# Copyright (c) 2014, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
## ADD_COMPILE_FLAGS(<source files> COMPILE_FLAGS <flags>)
## Use this for adding compiler flags to source files.
FUNCTION(ADD_COMPILE_FLAGS)
SET(FILES "")
SET(FLAGS "")
SET(COMPILE_FLAGS_SEEN)
FOREACH(ARG ${ARGV})
IF(ARG STREQUAL "COMPILE_FLAGS")
SET(COMPILE_FLAGS_SEEN 1)
ELSEIF(COMPILE_FLAGS_SEEN)
LIST(APPEND FLAGS ${ARG})
IF(${ARG} MATCHES "^-D")
MESSAGE(WARNING
"${ARG} should be in COMPILE_DEFINITIONS not COMPILE_FLAGS")
ENDIF()
ELSE()
LIST(APPEND FILES ${ARG})
ENDIF()
ENDFOREACH()
FOREACH(FILE ${FILES})
FOREACH(FLAG ${FLAGS})
GET_SOURCE_FILE_PROPERTY(PROP ${FILE} COMPILE_FLAGS)
IF(NOT PROP)
SET(PROP ${FLAG})
ELSE()
STRING_APPEND(PROP " ${FLAG}")
ENDIF()
SET_SOURCE_FILES_PROPERTIES(
${FILE} PROPERTIES COMPILE_FLAGS "${PROP}"
)
ENDFOREACH()
ENDFOREACH()
ENDFUNCTION(ADD_COMPILE_FLAGS)
## MY_ADD_COMPILE_DEFINITIONS(<source files> COMPILE_DEFINITIONS <flags>)
## Use this for adding preprocessor flags VAR or VAR=value to source files.
## cmake will prefix with '-D' and sort all COMPILE_DEFINITIONS alphabetically.
FUNCTION(MY_ADD_COMPILE_DEFINITIONS)
SET(FILES "")
SET(FLAGS "")
SET(COMPILE_DEFINITIONS_SEEN)
FOREACH(ARG ${ARGV})
IF(ARG STREQUAL "COMPILE_DEFINITIONS")
SET(COMPILE_DEFINITIONS_SEEN 1)
ELSEIF(COMPILE_DEFINITIONS_SEEN)
LIST(APPEND FLAGS ${ARG})
ELSE()
LIST(APPEND FILES ${ARG})
ENDIF()
ENDFOREACH()
FOREACH(FILE ${FILES})
GET_SOURCE_FILE_PROPERTY(DEFS ${FILE} COMPILE_DEFINITIONS)
IF(NOT DEFS)
SET(DEFS ${FLAGS})
ELSE()
LIST(APPEND DEFS ${FLAGS})
ENDIF()
SET_SOURCE_FILES_PROPERTIES(
${FILE} PROPERTIES COMPILE_DEFINITIONS "${DEFS}")
ENDFOREACH()
ENDFUNCTION(MY_ADD_COMPILE_DEFINITIONS)
# -flto[=n] or -flto=auto or -flto=jobserver
SET(MY_COMPILER_FLAG_FLTO " -flto(=[0-9a-z]+)?")
# Remove compiler flag/pattern from CMAKE_C_FLAGS or CMAKE_CXX_FLAGS
FUNCTION(REMOVE_CMAKE_COMPILER_FLAGS FLAG_VAR PATTERN)
STRING(REGEX REPLACE "${PATTERN}" "" ${FLAG_VAR} "${${FLAG_VAR}}")
SET(${FLAG_VAR} "${${FLAG_VAR}}" PARENT_SCOPE)
ENDFUNCTION()
# Set CMAKE_C_FLAGS and CMAKE_CXX_FLAGS to 'rpm --eval %optflags'
FUNCTION(ADD_LINUX_RPM_FLAGS)
EXECUTE_PROCESS(COMMAND ${MY_RPM} --eval %optflags
OUTPUT_VARIABLE RPM_EVAL_OPTFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RPM_EVAL_RESULT
)
IF(RPM_EVAL_RESULT EQUAL 0)
STRING_APPEND(CMAKE_C_FLAGS " ${RPM_EVAL_OPTFLAGS}")
STRING_APPEND(CMAKE_CXX_FLAGS " ${RPM_EVAL_OPTFLAGS}")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
ELSE()
MESSAGE(FATAL_ERROR
"WITH_PACKAGE_FLAGS=on but rpm --eval %optflags failed")
ENDIF()
ENDFUNCTION(ADD_LINUX_RPM_FLAGS)
# Set CMAKE_C_FLAGS and CMAKE_CXX_FLAGS to
# dpkg-buildflags --get <lang>FLAGS CPPFLAGS
# Set CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS and
# CMAKE_SHARED_LINKER_FLAGS to
# dpkg-buildflags --get LDFLAGS
FUNCTION(ADD_LINUX_DEB_FLAGS)
FOREACH(flag CPPFLAGS CFLAGS CXXFLAGS LDFLAGS)
EXECUTE_PROCESS(COMMAND ${MY_DPKG_BUILDFLAGS} --get ${flag}
OUTPUT_VARIABLE GET_${flag}
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE GET_RESULT
)
IF(NOT GET_RESULT EQUAL 0)
MESSAGE(FATAL_ERROR
"WITH_PACKAGE_FLAGS=on but dpkg-buildflags --get failed")
ENDIF()
SET(CMAKE_C_FLAGS "${GET_CFLAGS} ${GET_CPPFLAGS}" PARENT_SCOPE)
SET(CMAKE_CXX_FLAGS "${GET_CXXFLAGS} ${GET_CPPFLAGS}" PARENT_SCOPE)
SET(CMAKE_EXE_LINKER_FLAGS "${GET_LDFLAGS}" PARENT_SCOPE)
SET(CMAKE_MODULE_LINKER_FLAGS "${GET_LDFLAGS}" PARENT_SCOPE)
SET(CMAKE_SHARED_LINKER_FLAGS "${GET_LDFLAGS}" PARENT_SCOPE)
ENDFOREACH()
ENDFUNCTION(ADD_LINUX_DEB_FLAGS)
# See if we can do "-fuse-ld=${LINKER}" for gcc/clang on Linux.
# If compilation/linking succeeds, we extend misc cmake LINKER_FLAGS,
# and set OUTPUT_RESULT to 1.
FUNCTION(CHECK_ALTERNATIVE_LINKER LINKER OUTPUT_RESULT)
SET(ACCEPTED_VERSION 1)
CMAKE_PUSH_CHECK_STATE(RESET)
SET(CMAKE_REQUIRED_LIBRARIES "-fuse-ld=${LINKER}")
CHECK_C_SOURCE_COMPILES("int main() {}" C_LD_${LINKER}_RESULT)
CHECK_CXX_SOURCE_COMPILES("int main() {}" CXX_LD_${LINKER}_RESULT)
IF(C_LD_${LINKER}_RESULT AND CXX_LD_${LINKER}_RESULT)
IF(${LINKER} STREQUAL "mold")
FIND_PROGRAM(MOLD_EXECUTABLE "mold")
IF(MOLD_EXECUTABLE)
EXECUTE_PROCESS(COMMAND ${MOLD_EXECUTABLE} --version
OUTPUT_VARIABLE MOLD_OUTPUT
RESULT_VARIABLE MOLD_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
STRING(REGEX MATCH "^mold ([.0-9]+)" VERSION "${MOLD_OUTPUT}")
IF(NOT CMAKE_MATCH_1 OR CMAKE_MATCH_1 VERSION_LESS "2.0.0")
MESSAGE(STATUS
"This version of mold has an incompatible version: ${MOLD_OUTPUT}")
SET(ACCEPTED_VERSION 0)
ENDIF()
ENDIF()
ENDIF()
ENDIF()
IF(ACCEPTED_VERSION AND C_LD_${LINKER}_RESULT AND CXX_LD_${LINKER}_RESULT)
FOREACH(flag
CMAKE_EXE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS
)
STRING_APPEND(${flag} " -fuse-ld=${LINKER}")
SET(${flag} ${${flag}} PARENT_SCOPE)
ENDFOREACH()
SET(${OUTPUT_RESULT} 1 PARENT_SCOPE)
ELSE()
SET(${OUTPUT_RESULT} 0 PARENT_SCOPE)
MESSAGE(STATUS "Cannot use ${LINKER} on this platform")
ENDIF()
CMAKE_POP_CHECK_STATE()
ENDFUNCTION(CHECK_ALTERNATIVE_LINKER)
FUNCTION(EXCLUDE_FROM_MSVC_PGO TARGET_LIB)
# Exclude archive from PGO on Windows to avoid linker error LNK1248
IF(MSVC AND ((FPROFILE_GENERATE OR FPROFILE_USE)))
TARGET_COMPILE_OPTIONS(${TARGET_LIB} PRIVATE /GL-)
ENDIF()
ENDFUNCTION(EXCLUDE_FROM_MSVC_PGO)
FUNCTION(EXCLUDE_FILE_FROM_MSVC_PGO TARGET_FILE)
# Exclude archive from PGO on Windows to avoid linker error LNK1248
IF(MSVC AND ((FPROFILE_GENERATE OR FPROFILE_USE)))
ADD_COMPILE_FLAGS(${TARGET_FILE} COMPILE_FLAGS /GL-)
ENDIF()
ENDFUNCTION(EXCLUDE_FILE_FROM_MSVC_PGO)

152
cmake/component.cmake Normal file
View file

@ -0,0 +1,152 @@
# Copyright (c) 2013, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
# MYSQL_ADD_COMPONENT(component sources... options/keywords...)
MACRO(MYSQL_ADD_COMPONENT component_arg)
SET(COMPONENT_OPTIONS
MODULE_ONLY # generate dynamic library
SKIP_INSTALL
STATIC # generate new static library
TEST_ONLY # include library only with test distribution
)
SET(COMPONENT_ONE_VALUE_KW
)
SET(COMPONENT_MULTI_VALUE_KW
LINK_LIBRARIES # lib1 ... libN
)
CMAKE_PARSE_ARGUMENTS(ARG
"${COMPONENT_OPTIONS}"
"${COMPONENT_ONE_VALUE_KW}"
"${COMPONENT_MULTI_VALUE_KW}"
${ARGN}
)
SET(component ${component_arg})
SET(SOURCES ${ARG_UNPARSED_ARGUMENTS})
STRING(TOUPPER ${component} component)
STRING(TOLOWER ${component} component_lower)
STRING(TOLOWER component_${component} target)
GET_PROPERTY(CWD_DEFINITIONS DIRECTORY PROPERTY COMPILE_DEFINITIONS)
LIST(FIND CWD_DEFINITIONS "MYSQL_SERVER" FOUND_DEFINITION)
IF(NOT FOUND_DEFINITION EQUAL -1)
MESSAGE(FATAL_ERROR
"component ${component} has -DMYSQL_SERVER")
ENDIF()
# If not dynamic component, add it to list of built-ins
IF (ARG_STATIC)
IF (NOT "${component}" STREQUAL "MYSQL_SERVER")
MESSAGE(FATAL_ERROR "Only one server built-in component is expected.")
ENDIF()
ENDIF()
# Build either static library or module
IF (ARG_STATIC)
SET(kind STATIC)
ELSEIF(ARG_MODULE_ONLY)
SET(kind MODULE)
ELSE()
MESSAGE(FATAL_ERROR "Unknown component type ${target}")
ENDIF()
ADD_VERSION_INFO(${kind} SOURCES "")
ADD_LIBRARY(${target} ${kind} ${SOURCES})
TARGET_COMPILE_DEFINITIONS(${target} PUBLIC MYSQL_COMPONENT)
IF(COMPRESS_DEBUG_SECTIONS)
MY_TARGET_LINK_OPTIONS(${target}
"LINKER:--compress-debug-sections=zlib")
ENDIF()
IF(ARG_LINK_LIBRARIES)
TARGET_LINK_LIBRARIES(${target} ${ARG_LINK_LIBRARIES})
ENDIF()
SET_TARGET_PROPERTIES(${target} PROPERTIES PREFIX "")
ADD_DEPENDENCIES(${target} GenError)
IF (ARG_MODULE_ONLY)
SET_TARGET_PROPERTIES(${target} PROPERTIES OUTPUT_NAME "${target}")
# Store all components in the same directory, for easier testing.
SET_TARGET_PROPERTIES(${target} PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugin_output_directory
)
# For APPLE: adjust path dependecy for SSL shared libraries.
SET_PATH_TO_CUSTOM_SSL_FOR_APPLE(${target})
IF(APPLE)
TARGET_LINK_OPTIONS(${target} PRIVATE LINKER:-no_warn_duplicate_libraries)
ENDIF()
IF(WIN32_CLANG AND WITH_ASAN)
TARGET_LINK_LIBRARIES(${target}
"${ASAN_LIB_DIR}/clang_rt.asan_dll_thunk-x86_64.lib")
ENDIF()
# To hide the component symbols in the shared object
IF(UNIX)
# Use this also for component libraries and tests.
SET(COMPONENT_COMPILE_VISIBILITY
"-fvisibility=hidden" CACHE INTERNAL
"Use -fvisibility=hidden for components" FORCE)
TARGET_COMPILE_OPTIONS(${target} PRIVATE "-fvisibility=hidden")
ENDIF()
IF(NOT ARG_SKIP_INSTALL)
# Install dynamic library.
IF(ARG_TEST_ONLY)
SET(INSTALL_COMPONENT Test)
ELSE()
SET(INSTALL_COMPONENT Server)
ENDIF()
ADD_INSTALL_RPATH_FOR_OPENSSL(${target})
MYSQL_INSTALL_TARGET(${target}
DESTINATION ${INSTALL_PLUGINDIR}
COMPONENT ${INSTALL_COMPONENT})
INSTALL_DEBUG_TARGET(${target}
DESTINATION ${INSTALL_PLUGINDIR}/debug
COMPONENT ${INSTALL_COMPONENT})
ENDIF()
ENDIF()
ADD_DEPENDENCIES(component_all ${target})
ENDMACRO(MYSQL_ADD_COMPONENT)
# Add all CMake projects under components
MACRO(CONFIGURE_COMPONENTS)
FILE(GLOB dirs_components ${CMAKE_SOURCE_DIR}/components/*)
FILE(GLOB dirs_components_test ${CMAKE_SOURCE_DIR}/components/test/*)
FOREACH(dir ${dirs_components} ${dirs_components_test})
IF (EXISTS ${dir}/CMakeLists.txt)
ADD_SUBDIRECTORY(${dir})
ENDIF()
ENDFOREACH()
ENDMACRO()

View file

@ -0,0 +1 @@
@CMAKE_CONFIGURABLE_FILE_CONTENT@

View file

@ -0,0 +1,74 @@
# Copyright (c) 2020, 2024, 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 designed to work 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 either included with
# the program or referenced in the documentation.
#
# 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
IF(EXISTS "./${library_version}")
RETURN()
ENDIF()
EXECUTE_PROCESS(
COMMAND ${CMAKE_COMMAND} -E copy
"${library_directory}/${library_version}" "./${library_version}"
)
IF(NOT "${library_version}" STREQUAL "${library_name}")
EXECUTE_PROCESS(
COMMAND ${CMAKE_COMMAND} -E create_symlink
"${library_version}" "${library_name}"
)
ENDIF()
IF(NOT "${library_version}" STREQUAL "${library_soname}")
EXECUTE_PROCESS(
COMMAND ${CMAKE_COMMAND} -E create_symlink
"${library_version}" "${library_soname}"
)
ENDIF()
# Some of the pre-built libraries come without execute bit set.
EXECUTE_PROCESS(
COMMAND chmod +x "./${library_version}")
EXECUTE_PROCESS(
COMMAND ${PATCHELF_EXECUTABLE} --version
OUTPUT_VARIABLE PATCHELF_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
STRING(REPLACE "patchelf" "" PATCHELF_VERSION "${PATCHELF_VERSION}")
IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND
PATCHELF_VERSION VERSION_LESS "0.14.5")
SET(PATCHELF_PAGE_SIZE_ARGS --page-size 65536)
ENDIF()
# Patch RPATH so that we find NEEDED libraries at load time.
IF(subdir)
EXECUTE_PROCESS(
COMMAND ${PATCHELF_EXECUTABLE} ${PATCHELF_PAGE_SIZE_ARGS}
--set-rpath "$ORIGIN/.." "./${library_version}"
)
ELSE()
EXECUTE_PROCESS(
COMMAND ${PATCHELF_EXECUTABLE} ${PATCHELF_PAGE_SIZE_ARGS}
--set-rpath "$ORIGIN" "./${library_version}"
)
ENDIF()

Some files were not shown because too many files have changed in this diff Show more