mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
Merge branch 'master' into add-reading-from-archives-support
This commit is contained in:
commit
f604fb82b2
@ -21,7 +21,6 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
|||||||
ExperimentalAutoDetectBinPacking: true
|
ExperimentalAutoDetectBinPacking: true
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
TabWidth: 4
|
TabWidth: 4
|
||||||
IndentWidth: 4
|
|
||||||
Standard: Cpp11
|
Standard: Cpp11
|
||||||
PointerAlignment: Middle
|
PointerAlignment: Middle
|
||||||
MaxEmptyLinesToKeep: 2
|
MaxEmptyLinesToKeep: 2
|
||||||
|
97
.clang-tidy
97
.clang-tidy
@ -23,9 +23,12 @@ Checks: '*,
|
|||||||
-bugprone-implicit-widening-of-multiplication-result,
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
-bugprone-narrowing-conversions,
|
-bugprone-narrowing-conversions,
|
||||||
-bugprone-not-null-terminated-result,
|
-bugprone-not-null-terminated-result,
|
||||||
|
-bugprone-reserved-identifier, # useful but too slow, TODO retry when https://reviews.llvm.org/rG1c282052624f9d0bd273bde0b47b30c96699c6c7 is merged
|
||||||
-bugprone-unchecked-optional-access,
|
-bugprone-unchecked-optional-access,
|
||||||
|
|
||||||
-cert-dcl16-c,
|
-cert-dcl16-c,
|
||||||
|
-cert-dcl37-c,
|
||||||
|
-cert-dcl51-cpp,
|
||||||
-cert-err58-cpp,
|
-cert-err58-cpp,
|
||||||
-cert-msc32-c,
|
-cert-msc32-c,
|
||||||
-cert-msc51-cpp,
|
-cert-msc51-cpp,
|
||||||
@ -38,6 +41,8 @@ Checks: '*,
|
|||||||
-clang-analyzer-security.insecureAPI.strcpy,
|
-clang-analyzer-security.insecureAPI.strcpy,
|
||||||
|
|
||||||
-cppcoreguidelines-avoid-c-arrays,
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
|
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
|
-cppcoreguidelines-avoid-do-while,
|
||||||
-cppcoreguidelines-avoid-goto,
|
-cppcoreguidelines-avoid-goto,
|
||||||
-cppcoreguidelines-avoid-magic-numbers,
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||||
@ -105,6 +110,8 @@ Checks: '*,
|
|||||||
-misc-const-correctness,
|
-misc-const-correctness,
|
||||||
-misc-no-recursion,
|
-misc-no-recursion,
|
||||||
-misc-non-private-member-variables-in-classes,
|
-misc-non-private-member-variables-in-classes,
|
||||||
|
-misc-confusable-identifiers, # useful but slooow
|
||||||
|
-misc-use-anonymous-namespace,
|
||||||
|
|
||||||
-modernize-avoid-c-arrays,
|
-modernize-avoid-c-arrays,
|
||||||
-modernize-concat-nested-namespaces,
|
-modernize-concat-nested-namespaces,
|
||||||
@ -125,10 +132,12 @@ Checks: '*,
|
|||||||
-portability-simd-intrinsics,
|
-portability-simd-intrinsics,
|
||||||
|
|
||||||
-readability-braces-around-statements,
|
-readability-braces-around-statements,
|
||||||
|
-readability-convert-member-functions-to-static,
|
||||||
-readability-else-after-return,
|
-readability-else-after-return,
|
||||||
-readability-function-cognitive-complexity,
|
-readability-function-cognitive-complexity,
|
||||||
-readability-function-size,
|
-readability-function-size,
|
||||||
-readability-identifier-length,
|
-readability-identifier-length,
|
||||||
|
-readability-identifier-naming, # useful but too slow
|
||||||
-readability-implicit-bool-conversion,
|
-readability-implicit-bool-conversion,
|
||||||
-readability-isolate-declaration,
|
-readability-isolate-declaration,
|
||||||
-readability-magic-numbers,
|
-readability-magic-numbers,
|
||||||
@ -140,72 +149,32 @@ Checks: '*,
|
|||||||
-readability-uppercase-literal-suffix,
|
-readability-uppercase-literal-suffix,
|
||||||
-readability-use-anyofallof,
|
-readability-use-anyofallof,
|
||||||
|
|
||||||
-zirkon-*,
|
-zircon-*,
|
||||||
|
|
||||||
-misc-*, # temporarily disabled due to being too slow
|
|
||||||
# also disable checks in other categories which are aliases of checks in misc-*:
|
|
||||||
# https://releases.llvm.org/15.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/list.html
|
|
||||||
-cert-dcl54-cpp, # alias of misc-new-delete-overloads
|
|
||||||
-hicpp-new-delete-operators, # alias of misc-new-delete-overloads
|
|
||||||
-cert-fio38-c, # alias of misc-non-copyable-objects
|
|
||||||
-cert-dcl03-c, # alias of misc-static-assert
|
|
||||||
-hicpp-static-assert, # alias of misc-static-assert
|
|
||||||
-cert-err09-cpp, # alias of misc-throw-by-value-catch-by-reference
|
|
||||||
-cert-err61-cpp, # alias of misc-throw-by-value-catch-by-reference
|
|
||||||
-cppcoreguidelines-c-copy-assignment-signature, # alias of misc-unconventional-assign-operator
|
|
||||||
-cppcoreguidelines-non-private-member-variables-in-classes, # alias of misc-non-private-member-variables-in-classes
|
|
||||||
'
|
'
|
||||||
|
|
||||||
WarningsAsErrors: '*'
|
WarningsAsErrors: '*'
|
||||||
|
|
||||||
# TODO: use dictionary syntax for CheckOptions when minimum clang-tidy level rose to 15
|
|
||||||
# some-check.SomeOption: 'some value'
|
|
||||||
# instead of
|
|
||||||
# - key: some-check.SomeOption
|
|
||||||
# value: 'some value'
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: readability-identifier-naming.ClassCase
|
readability-identifier-naming.ClassCase: CamelCase
|
||||||
value: CamelCase
|
readability-identifier-naming.EnumCase: CamelCase
|
||||||
- key: readability-identifier-naming.EnumCase
|
readability-identifier-naming.LocalVariableCase: lower_case
|
||||||
value: CamelCase
|
readability-identifier-naming.StaticConstantCase: aNy_CasE
|
||||||
- key: readability-identifier-naming.LocalVariableCase
|
readability-identifier-naming.MemberCase: lower_case
|
||||||
value: lower_case
|
readability-identifier-naming.PrivateMemberPrefix: ''
|
||||||
- key: readability-identifier-naming.StaticConstantCase
|
readability-identifier-naming.ProtectedMemberPrefix: ''
|
||||||
value: aNy_CasE
|
readability-identifier-naming.PublicMemberCase: lower_case
|
||||||
- key: readability-identifier-naming.MemberCase
|
readability-identifier-naming.MethodCase: camelBack
|
||||||
value: lower_case
|
readability-identifier-naming.PrivateMethodPrefix: ''
|
||||||
- key: readability-identifier-naming.PrivateMemberPrefix
|
readability-identifier-naming.ProtectedMethodPrefix: ''
|
||||||
value: ''
|
readability-identifier-naming.ParameterPackCase: lower_case
|
||||||
- key: readability-identifier-naming.ProtectedMemberPrefix
|
readability-identifier-naming.StructCase: CamelCase
|
||||||
value: ''
|
readability-identifier-naming.TemplateTemplateParameterCase: CamelCase
|
||||||
- key: readability-identifier-naming.PublicMemberCase
|
readability-identifier-naming.TemplateParameterCase: lower_case
|
||||||
value: lower_case
|
readability-identifier-naming.TypeTemplateParameterCase: CamelCase
|
||||||
- key: readability-identifier-naming.MethodCase
|
readability-identifier-naming.TypedefCase: CamelCase
|
||||||
value: camelBack
|
readability-identifier-naming.UnionCase: CamelCase
|
||||||
- key: readability-identifier-naming.PrivateMethodPrefix
|
modernize-loop-convert.UseCxx20ReverseRanges: false
|
||||||
value: ''
|
performance-move-const-arg.CheckTriviallyCopyableMove: false
|
||||||
- key: readability-identifier-naming.ProtectedMethodPrefix
|
# Workaround clang-tidy bug: https://github.com/llvm/llvm-project/issues/46097
|
||||||
value: ''
|
readability-identifier-naming.TypeTemplateParameterIgnoredRegexp: expr-type
|
||||||
- key: readability-identifier-naming.ParameterPackCase
|
cppcoreguidelines-avoid-do-while.IgnoreMacros: true
|
||||||
value: lower_case
|
|
||||||
- key: readability-identifier-naming.StructCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: readability-identifier-naming.TemplateTemplateParameterCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: readability-identifier-naming.TemplateUsingCase
|
|
||||||
value: lower_case
|
|
||||||
- key: readability-identifier-naming.TypeTemplateParameterCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: readability-identifier-naming.TypedefCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: readability-identifier-naming.UnionCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: readability-identifier-naming.UsingCase
|
|
||||||
value: CamelCase
|
|
||||||
- key: modernize-loop-convert.UseCxx20ReverseRanges
|
|
||||||
value: false
|
|
||||||
- key: performance-move-const-arg.CheckTriviallyCopyableMove
|
|
||||||
value: false
|
|
||||||
# Workaround clang-tidy bug: https://github.com/llvm/llvm-project/issues/46097
|
|
||||||
- key: readability-identifier-naming.TypeTemplateParameterIgnoredRegexp
|
|
||||||
value: expr-type
|
|
||||||
|
16
.clangd
Normal file
16
.clangd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Diagnostics:
|
||||||
|
# clangd does parse .clang-tidy, but some checks are too slow to run in
|
||||||
|
# clang-tidy build, so let's enable them explicitly for clangd at least.
|
||||||
|
ClangTidy:
|
||||||
|
# The following checks had been disabled due to slowliness with C++23,
|
||||||
|
# for more details see [1].
|
||||||
|
#
|
||||||
|
# [1]: https://github.com/llvm/llvm-project/issues/61418
|
||||||
|
#
|
||||||
|
# But the code base had been written in a style that had been checked
|
||||||
|
# by this check, so at least, let's enable it for clangd.
|
||||||
|
Add: [
|
||||||
|
# configured in .clang-tidy
|
||||||
|
readability-identifier-naming,
|
||||||
|
bugprone-reserved-identifier,
|
||||||
|
]
|
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -2,16 +2,16 @@
|
|||||||
A technical comment, you are free to remove or leave it as it is when PR is created
|
A technical comment, you are free to remove or leave it as it is when PR is created
|
||||||
The following categories are used in the next scripts, update them accordingly
|
The following categories are used in the next scripts, update them accordingly
|
||||||
utils/changelog/changelog.py
|
utils/changelog/changelog.py
|
||||||
tests/ci/run_check.py
|
tests/ci/cancel_and_rerun_workflow_lambda/app.py
|
||||||
-->
|
-->
|
||||||
### Changelog category (leave one):
|
### Changelog category (leave one):
|
||||||
- New Feature
|
- New Feature
|
||||||
- Improvement
|
- Improvement
|
||||||
- Bug Fix (user-visible misbehavior in official stable or prestable release)
|
|
||||||
- Performance Improvement
|
- Performance Improvement
|
||||||
- Backward Incompatible Change
|
- Backward Incompatible Change
|
||||||
- Build/Testing/Packaging Improvement
|
- Build/Testing/Packaging Improvement
|
||||||
- Documentation (changelog entry is not required)
|
- Documentation (changelog entry is not required)
|
||||||
|
- Bug Fix (user-visible misbehavior in an official stable release)
|
||||||
- Not for changelog (changelog entry is not required)
|
- Not for changelog (changelog entry is not required)
|
||||||
|
|
||||||
|
|
||||||
|
70
.github/workflows/backport_branches.yml
vendored
70
.github/workflows/backport_branches.yml
vendored
@ -9,8 +9,22 @@ on: # yamllint disable-line rule:truthy
|
|||||||
branches:
|
branches:
|
||||||
- 'backport/**'
|
- 'backport/**'
|
||||||
jobs:
|
jobs:
|
||||||
|
CheckLabels:
|
||||||
|
runs-on: [self-hosted, style-checker]
|
||||||
|
# Run the first check always, even if the CI is cancelled
|
||||||
|
if: ${{ always() }}
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Labels check
|
||||||
|
run: |
|
||||||
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
|
python3 run_check.py
|
||||||
PythonUnitTests:
|
PythonUnitTests:
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
|
needs: CheckLabels
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: ClickHouse/checkout@v1
|
uses: ClickHouse/checkout@v1
|
||||||
@ -22,6 +36,7 @@ jobs:
|
|||||||
python3 -m unittest discover -s . -p '*_test.py'
|
python3 -m unittest discover -s . -p '*_test.py'
|
||||||
DockerHubPushAarch64:
|
DockerHubPushAarch64:
|
||||||
runs-on: [self-hosted, style-checker-aarch64]
|
runs-on: [self-hosted, style-checker-aarch64]
|
||||||
|
needs: CheckLabels
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: ClickHouse/checkout@v1
|
uses: ClickHouse/checkout@v1
|
||||||
@ -38,6 +53,7 @@ jobs:
|
|||||||
path: ${{ runner.temp }}/docker_images_check/changed_images_aarch64.json
|
path: ${{ runner.temp }}/docker_images_check/changed_images_aarch64.json
|
||||||
DockerHubPushAmd64:
|
DockerHubPushAmd64:
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
|
needs: CheckLabels
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: ClickHouse/checkout@v1
|
uses: ClickHouse/checkout@v1
|
||||||
@ -79,7 +95,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: changed_images
|
name: changed_images
|
||||||
path: ${{ runner.temp }}/changed_images.json
|
path: ${{ runner.temp }}/changed_images.json
|
||||||
CompatibilityCheck:
|
CompatibilityCheckX86:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebRelease]
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
@ -98,12 +114,43 @@ jobs:
|
|||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ env.REPORTS_PATH }}
|
path: ${{ env.REPORTS_PATH }}
|
||||||
- name: CompatibilityCheck
|
- name: CompatibilityCheckX86
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
mkdir -p "$TEMP_PATH"
|
mkdir -p "$TEMP_PATH"
|
||||||
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (amd64)" --check-glibc --check-distributions
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
CompatibilityCheckAarch64:
|
||||||
|
needs: [BuilderDebAarch64]
|
||||||
|
runs-on: [self-hosted, style-checker]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/compatibility_check
|
||||||
|
REPO_COPY=${{runner.temp}}/compatibility_check/ClickHouse
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
EOF
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: CompatibilityCheckAarch64
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (aarch64)" --check-glibc
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
@ -302,6 +349,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
clear-repository: true
|
clear-repository: true
|
||||||
submodules: true
|
submodules: true
|
||||||
|
- name: Apply sparse checkout for contrib # in order to check that it doesn't break build
|
||||||
|
run: |
|
||||||
|
rm -rf "$GITHUB_WORKSPACE/contrib" && echo 'removed'
|
||||||
|
git -C "$GITHUB_WORKSPACE" checkout . && echo 'restored'
|
||||||
|
"$GITHUB_WORKSPACE/contrib/update-submodules.sh" && echo 'OK'
|
||||||
|
du -hs "$GITHUB_WORKSPACE/contrib" ||:
|
||||||
|
find "$GITHUB_WORKSPACE/contrib" -type f | wc -l ||:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
@ -421,8 +475,9 @@ jobs:
|
|||||||
- name: Check docker clickhouse/clickhouse-server building
|
- name: Check docker clickhouse/clickhouse-server building
|
||||||
run: |
|
run: |
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 docker_server.py --release-type head --no-push
|
python3 docker_server.py --release-type head --no-push \
|
||||||
python3 docker_server.py --release-type head --no-push --no-ubuntu \
|
--image-repo clickhouse/clickhouse-server --image-path docker/server
|
||||||
|
python3 docker_server.py --release-type head --no-push \
|
||||||
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
@ -549,7 +604,7 @@ jobs:
|
|||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
InstallPackagesTestAarch64:
|
InstallPackagesTestAarch64:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebAarch64]
|
||||||
runs-on: [self-hosted, style-checker-aarch64]
|
runs-on: [self-hosted, style-checker-aarch64]
|
||||||
steps:
|
steps:
|
||||||
- name: Set envs
|
- name: Set envs
|
||||||
@ -741,7 +796,8 @@ jobs:
|
|||||||
- FunctionalStatefulTestDebug
|
- FunctionalStatefulTestDebug
|
||||||
- StressTestTsan
|
- StressTestTsan
|
||||||
- IntegrationTestsRelease
|
- IntegrationTestsRelease
|
||||||
- CompatibilityCheck
|
- CompatibilityCheckX86
|
||||||
|
- CompatibilityCheckAarch64
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
|
1
.github/workflows/cherry_pick.yml
vendored
1
.github/workflows/cherry_pick.yml
vendored
@ -35,7 +35,6 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Cherry pick
|
- name: Cherry pick
|
||||||
run: |
|
run: |
|
||||||
sudo pip install GitPython
|
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 cherry_pick.py
|
python3 cherry_pick.py
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
|
2
.github/workflows/debug.yml
vendored
2
.github/workflows/debug.yml
vendored
@ -2,7 +2,7 @@
|
|||||||
name: Debug
|
name: Debug
|
||||||
|
|
||||||
'on':
|
'on':
|
||||||
[push, pull_request, release, workflow_dispatch, workflow_call]
|
[push, pull_request, pull_request_review, release, workflow_dispatch, workflow_call]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
DebugInfo:
|
DebugInfo:
|
||||||
|
4
.github/workflows/docs_check.yml
vendored
4
.github/workflows/docs_check.yml
vendored
@ -13,9 +13,11 @@ on: # yamllint disable-line rule:truthy
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths:
|
paths:
|
||||||
|
- 'CHANGELOG.md'
|
||||||
|
- 'README.md'
|
||||||
|
- 'SECURITY.md'
|
||||||
- 'docker/docs/**'
|
- 'docker/docs/**'
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'website/**'
|
|
||||||
- 'utils/check-style/aspell-ignore/**'
|
- 'utils/check-style/aspell-ignore/**'
|
||||||
jobs:
|
jobs:
|
||||||
CheckLabels:
|
CheckLabels:
|
||||||
|
118
.github/workflows/docs_release.yml
vendored
118
.github/workflows/docs_release.yml
vendored
@ -1,118 +0,0 @@
|
|||||||
name: DocsReleaseChecks
|
|
||||||
|
|
||||||
env:
|
|
||||||
# Force the stdout and stderr streams to be unbuffered
|
|
||||||
PYTHONUNBUFFERED: 1
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: master-release
|
|
||||||
cancel-in-progress: true
|
|
||||||
'on':
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- '.github/**'
|
|
||||||
- 'docker/docs/release/**'
|
|
||||||
- 'docs/**'
|
|
||||||
- 'utils/list-versions/version_date.tsv'
|
|
||||||
- 'website/**'
|
|
||||||
- 'utils/check-style/aspell-ignore/**'
|
|
||||||
workflow_dispatch:
|
|
||||||
jobs:
|
|
||||||
DockerHubPushAarch64:
|
|
||||||
runs-on: [self-hosted, style-checker-aarch64]
|
|
||||||
steps:
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: ClickHouse/checkout@v1
|
|
||||||
with:
|
|
||||||
clear-repository: true
|
|
||||||
- name: Images check
|
|
||||||
run: |
|
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
|
||||||
python3 docker_images_check.py --suffix aarch64
|
|
||||||
- name: Upload images files to artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images_aarch64
|
|
||||||
path: ${{ runner.temp }}/docker_images_check/changed_images_aarch64.json
|
|
||||||
DockerHubPushAmd64:
|
|
||||||
runs-on: [self-hosted, style-checker]
|
|
||||||
steps:
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: ClickHouse/checkout@v1
|
|
||||||
with:
|
|
||||||
clear-repository: true
|
|
||||||
- name: Images check
|
|
||||||
run: |
|
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
|
||||||
python3 docker_images_check.py --suffix amd64
|
|
||||||
- name: Upload images files to artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images_amd64
|
|
||||||
path: ${{ runner.temp }}/docker_images_check/changed_images_amd64.json
|
|
||||||
DockerHubPush:
|
|
||||||
needs: [DockerHubPushAmd64, DockerHubPushAarch64]
|
|
||||||
runs-on: [self-hosted, style-checker]
|
|
||||||
steps:
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: ClickHouse/checkout@v1
|
|
||||||
with:
|
|
||||||
clear-repository: true
|
|
||||||
- name: Download changed aarch64 images
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images_aarch64
|
|
||||||
path: ${{ runner.temp }}
|
|
||||||
- name: Download changed amd64 images
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images_amd64
|
|
||||||
path: ${{ runner.temp }}
|
|
||||||
- name: Images check
|
|
||||||
run: |
|
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
|
||||||
python3 docker_manifests_merge.py --suffix amd64 --suffix aarch64
|
|
||||||
- name: Upload images files to artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images
|
|
||||||
path: ${{ runner.temp }}/changed_images.json
|
|
||||||
DocsRelease:
|
|
||||||
needs: DockerHubPush
|
|
||||||
runs-on: [self-hosted, func-tester]
|
|
||||||
steps:
|
|
||||||
- name: Set envs
|
|
||||||
# https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions#multiline-strings
|
|
||||||
run: |
|
|
||||||
cat >> "$GITHUB_ENV" << 'EOF'
|
|
||||||
TEMP_PATH=${{runner.temp}}/docs_release
|
|
||||||
REPO_COPY=${{runner.temp}}/docs_release/ClickHouse
|
|
||||||
CLOUDFLARE_TOKEN=${{secrets.CLOUDFLARE}}
|
|
||||||
ROBOT_CLICKHOUSE_SSH_KEY<<RCSK
|
|
||||||
${{secrets.ROBOT_CLICKHOUSE_SSH_KEY}}
|
|
||||||
RCSK
|
|
||||||
EOF
|
|
||||||
- name: Check out repository code
|
|
||||||
uses: ClickHouse/checkout@v1
|
|
||||||
with:
|
|
||||||
clear-repository: true
|
|
||||||
- name: Download changed images
|
|
||||||
uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: changed_images
|
|
||||||
path: ${{ env.TEMP_PATH }}
|
|
||||||
- name: Docs Release
|
|
||||||
run: |
|
|
||||||
sudo rm -fr "$TEMP_PATH"
|
|
||||||
mkdir -p "$TEMP_PATH"
|
|
||||||
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
|
||||||
cd "$REPO_COPY/tests/ci"
|
|
||||||
python3 docs_release.py
|
|
||||||
- name: Cleanup
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
|
||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
|
||||||
sudo rm -fr "$TEMP_PATH"
|
|
875
.github/workflows/master.yml
vendored
875
.github/workflows/master.yml
vendored
File diff suppressed because it is too large
Load Diff
17
.github/workflows/nightly.yml
vendored
17
.github/workflows/nightly.yml
vendored
@ -72,6 +72,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: changed_images
|
name: changed_images
|
||||||
path: ${{ runner.temp }}/changed_images.json
|
path: ${{ runner.temp }}/changed_images.json
|
||||||
|
Codebrowser:
|
||||||
|
needs: [DockerHubPush]
|
||||||
|
uses: ./.github/workflows/woboq.yml
|
||||||
BuilderCoverity:
|
BuilderCoverity:
|
||||||
needs: DockerHubPush
|
needs: DockerHubPush
|
||||||
runs-on: [self-hosted, builder]
|
runs-on: [self-hosted, builder]
|
||||||
@ -107,7 +110,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
curl --form token="${COVERITY_TOKEN}" \
|
curl --form token="${COVERITY_TOKEN}" \
|
||||||
--form email='security+coverity@clickhouse.com' \
|
--form email='security+coverity@clickhouse.com' \
|
||||||
--form file="@$TEMP_PATH/$BUILD_NAME/coverity-scan.tar.zst" \
|
--form file="@$TEMP_PATH/$BUILD_NAME/coverity-scan.tar.gz" \
|
||||||
--form version="${GITHUB_REF#refs/heads/}-${GITHUB_SHA::6}" \
|
--form version="${GITHUB_REF#refs/heads/}-${GITHUB_SHA::6}" \
|
||||||
--form description="Nighly Scan: $(date +'%Y-%m-%dT%H:%M:%S')" \
|
--form description="Nighly Scan: $(date +'%Y-%m-%dT%H:%M:%S')" \
|
||||||
https://scan.coverity.com/builds?project=ClickHouse%2FClickHouse
|
https://scan.coverity.com/builds?project=ClickHouse%2FClickHouse
|
||||||
@ -118,13 +121,15 @@ jobs:
|
|||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH" "$CACHES_PATH"
|
sudo rm -fr "$TEMP_PATH" "$CACHES_PATH"
|
||||||
SonarCloud:
|
SonarCloud:
|
||||||
|
# TODO: Remove if: whenever SonarCloud supports c++23
|
||||||
|
if: ${{ false }}
|
||||||
runs-on: [self-hosted, builder]
|
runs-on: [self-hosted, builder]
|
||||||
env:
|
env:
|
||||||
SONAR_SCANNER_VERSION: 4.7.0.2747
|
SONAR_SCANNER_VERSION: 4.8.0.2856
|
||||||
SONAR_SERVER_URL: "https://sonarcloud.io"
|
SONAR_SERVER_URL: "https://sonarcloud.io"
|
||||||
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
|
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
|
||||||
CC: clang-15
|
CC: clang-16
|
||||||
CXX: clang++-15
|
CXX: clang++-16
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: ClickHouse/checkout@v1
|
uses: ClickHouse/checkout@v1
|
||||||
@ -154,7 +159,7 @@ jobs:
|
|||||||
- name: Set Up Build Tools
|
- name: Set Up Build Tools
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -yq git cmake ccache python3 ninja-build
|
sudo apt-get install -yq git cmake ccache ninja-build python3 yasm
|
||||||
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
|
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
|
||||||
- name: Run build-wrapper
|
- name: Run build-wrapper
|
||||||
run: |
|
run: |
|
||||||
@ -173,4 +178,4 @@ jobs:
|
|||||||
--define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" \
|
--define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" \
|
||||||
--define sonar.projectKey="ClickHouse_ClickHouse" \
|
--define sonar.projectKey="ClickHouse_ClickHouse" \
|
||||||
--define sonar.organization="clickhouse-java" \
|
--define sonar.organization="clickhouse-java" \
|
||||||
--define sonar.exclusions="**/*.java,**/*.ts,**/*.js,**/*.css,**/*.sql"
|
--define sonar.exclusions="**/*.java,**/*.ts,**/*.js,**/*.css,**/*.sql" \
|
||||||
|
272
.github/workflows/pull_request.yml
vendored
272
.github/workflows/pull_request.yml
vendored
@ -13,9 +13,11 @@ on: # yamllint disable-line rule:truthy
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
|
- 'CHANGELOG.md'
|
||||||
|
- 'README.md'
|
||||||
|
- 'SECURITY.md'
|
||||||
- 'docker/docs/**'
|
- 'docker/docs/**'
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- 'website/**'
|
|
||||||
- 'utils/check-style/aspell-ignore/**'
|
- 'utils/check-style/aspell-ignore/**'
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
##################################### SMALL CHECKS #######################################
|
##################################### SMALL CHECKS #######################################
|
||||||
@ -35,7 +37,6 @@ jobs:
|
|||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 run_check.py
|
python3 run_check.py
|
||||||
PythonUnitTests:
|
PythonUnitTests:
|
||||||
needs: CheckLabels
|
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
@ -172,7 +173,7 @@ jobs:
|
|||||||
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH" "$CACHES_PATH"
|
sudo rm -fr "$TEMP_PATH" "$CACHES_PATH"
|
||||||
CompatibilityCheck:
|
CompatibilityCheckX86:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebRelease]
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
@ -191,12 +192,43 @@ jobs:
|
|||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ env.REPORTS_PATH }}
|
path: ${{ env.REPORTS_PATH }}
|
||||||
- name: CompatibilityCheck
|
- name: CompatibilityCheckX86
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
mkdir -p "$TEMP_PATH"
|
mkdir -p "$TEMP_PATH"
|
||||||
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (amd64)" --check-glibc --check-distributions
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
CompatibilityCheckAarch64:
|
||||||
|
needs: [BuilderDebAarch64]
|
||||||
|
runs-on: [self-hosted, style-checker]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/compatibility_check
|
||||||
|
REPO_COPY=${{runner.temp}}/compatibility_check/ClickHouse
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
EOF
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: CompatibilityCheckAarch64
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (aarch64)" --check-glibc
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
@ -518,6 +550,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
clear-repository: true
|
clear-repository: true
|
||||||
submodules: true
|
submodules: true
|
||||||
|
- name: Apply sparse checkout for contrib # in order to check that it doesn't break build
|
||||||
|
run: |
|
||||||
|
rm -rf "$GITHUB_WORKSPACE/contrib" && echo 'removed'
|
||||||
|
git -C "$GITHUB_WORKSPACE" checkout . && echo 'restored'
|
||||||
|
"$GITHUB_WORKSPACE/contrib/update-submodules.sh" && echo 'OK'
|
||||||
|
du -hs "$GITHUB_WORKSPACE/contrib" ||:
|
||||||
|
find "$GITHUB_WORKSPACE/contrib" -type f | wc -l ||:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
@ -884,8 +923,9 @@ jobs:
|
|||||||
- name: Check docker clickhouse/clickhouse-server building
|
- name: Check docker clickhouse/clickhouse-server building
|
||||||
run: |
|
run: |
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 docker_server.py --release-type head --no-push
|
python3 docker_server.py --release-type head --no-push \
|
||||||
python3 docker_server.py --release-type head --no-push --no-ubuntu \
|
--image-repo clickhouse/clickhouse-server --image-path docker/server
|
||||||
|
python3 docker_server.py --release-type head --no-push \
|
||||||
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
@ -1021,7 +1061,7 @@ jobs:
|
|||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
InstallPackagesTestAarch64:
|
InstallPackagesTestAarch64:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebAarch64]
|
||||||
runs-on: [self-hosted, style-checker-aarch64]
|
runs-on: [self-hosted, style-checker-aarch64]
|
||||||
steps:
|
steps:
|
||||||
- name: Set envs
|
- name: Set envs
|
||||||
@ -1268,6 +1308,40 @@ jobs:
|
|||||||
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
FunctionalStatelessTestReleaseAnalyzer:
|
||||||
|
needs: [BuilderDebRelease]
|
||||||
|
runs-on: [self-hosted, func-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/stateless_analyzer
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Stateless tests (release, analyzer)
|
||||||
|
REPO_COPY=${{runner.temp}}/stateless_analyzer/ClickHouse
|
||||||
|
KILL_TIMEOUT=10800
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Functional test
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 functional_test_check.py "$CHECK_NAME" "$KILL_TIMEOUT"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
FunctionalStatelessTestReleaseS3_0:
|
FunctionalStatelessTestReleaseS3_0:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebRelease]
|
||||||
runs-on: [self-hosted, func-tester]
|
runs-on: [self-hosted, func-tester]
|
||||||
@ -3103,10 +3177,10 @@ jobs:
|
|||||||
- name: Set envs
|
- name: Set envs
|
||||||
run: |
|
run: |
|
||||||
cat >> "$GITHUB_ENV" << 'EOF'
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
TEMP_PATH=${{runner.temp}}/stress_thread
|
TEMP_PATH=${{runner.temp}}/stress_asan
|
||||||
REPORTS_PATH=${{runner.temp}}/reports_dir
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
CHECK_NAME=Stress test (asan)
|
CHECK_NAME=Stress test (asan)
|
||||||
REPO_COPY=${{runner.temp}}/stress_thread/ClickHouse
|
REPO_COPY=${{runner.temp}}/stress_asan/ClickHouse
|
||||||
EOF
|
EOF
|
||||||
- name: Download json reports
|
- name: Download json reports
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
@ -3265,6 +3339,142 @@ jobs:
|
|||||||
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
##############################################################################################
|
||||||
|
######################################### UPGRADE CHECK ######################################
|
||||||
|
##############################################################################################
|
||||||
|
UpgradeCheckAsan:
|
||||||
|
needs: [BuilderDebAsan]
|
||||||
|
runs-on: [self-hosted, stress-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/upgrade_asan
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Upgrade check (asan)
|
||||||
|
REPO_COPY=${{runner.temp}}/upgrade_asan/ClickHouse
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Upgrade check
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 upgrade_check.py "$CHECK_NAME"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
UpgradeCheckTsan:
|
||||||
|
needs: [BuilderDebTsan]
|
||||||
|
# same as for stress test with tsan
|
||||||
|
runs-on: [self-hosted, func-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/upgrade_thread
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Upgrade check (tsan)
|
||||||
|
REPO_COPY=${{runner.temp}}/upgrade_thread/ClickHouse
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Upgrade check
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 upgrade_check.py "$CHECK_NAME"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
UpgradeCheckMsan:
|
||||||
|
needs: [BuilderDebMsan]
|
||||||
|
runs-on: [self-hosted, stress-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/upgrade_memory
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Upgrade check (msan)
|
||||||
|
REPO_COPY=${{runner.temp}}/upgrade_memory/ClickHouse
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Upgrade check
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 upgrade_check.py "$CHECK_NAME"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
UpgradeCheckDebug:
|
||||||
|
needs: [BuilderDebDebug]
|
||||||
|
runs-on: [self-hosted, stress-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/upgrade_debug
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Upgrade check (debug)
|
||||||
|
REPO_COPY=${{runner.temp}}/upgrade_debug/ClickHouse
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Upgrade check
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 upgrade_check.py "$CHECK_NAME"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
##############################################################################################
|
##############################################################################################
|
||||||
##################################### AST FUZZERS ############################################
|
##################################### AST FUZZERS ############################################
|
||||||
##############################################################################################
|
##############################################################################################
|
||||||
@ -4579,6 +4789,7 @@ jobs:
|
|||||||
- FunctionalStatelessTestReleaseDatabaseReplicated2
|
- FunctionalStatelessTestReleaseDatabaseReplicated2
|
||||||
- FunctionalStatelessTestReleaseDatabaseReplicated3
|
- FunctionalStatelessTestReleaseDatabaseReplicated3
|
||||||
- FunctionalStatelessTestReleaseWideParts
|
- FunctionalStatelessTestReleaseWideParts
|
||||||
|
- FunctionalStatelessTestReleaseAnalyzer
|
||||||
- FunctionalStatelessTestAarch64
|
- FunctionalStatelessTestAarch64
|
||||||
- FunctionalStatelessTestAsan0
|
- FunctionalStatelessTestAsan0
|
||||||
- FunctionalStatelessTestAsan1
|
- FunctionalStatelessTestAsan1
|
||||||
@ -4654,7 +4865,8 @@ jobs:
|
|||||||
- UnitTestsMsan
|
- UnitTestsMsan
|
||||||
- UnitTestsUBsan
|
- UnitTestsUBsan
|
||||||
- UnitTestsReleaseClang
|
- UnitTestsReleaseClang
|
||||||
- CompatibilityCheck
|
- CompatibilityCheckX86
|
||||||
|
- CompatibilityCheckAarch64
|
||||||
- IntegrationTestsFlakyCheck
|
- IntegrationTestsFlakyCheck
|
||||||
- SQLancerTestRelease
|
- SQLancerTestRelease
|
||||||
- SQLancerTestDebug
|
- SQLancerTestDebug
|
||||||
@ -4669,3 +4881,41 @@ jobs:
|
|||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 finish_check.py
|
python3 finish_check.py
|
||||||
python3 merge_pr.py --check-approved
|
python3 merge_pr.py --check-approved
|
||||||
|
##############################################################################################
|
||||||
|
########################### SQLLOGIC TEST ###################################################
|
||||||
|
##############################################################################################
|
||||||
|
SQLLogicTestRelease:
|
||||||
|
needs: [BuilderDebRelease]
|
||||||
|
runs-on: [self-hosted, func-tester]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/sqllogic_debug
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
CHECK_NAME=Sqllogic test (release)
|
||||||
|
REPO_COPY=${{runner.temp}}/sqllogic_debug/ClickHouse
|
||||||
|
KILL_TIMEOUT=10800
|
||||||
|
EOF
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: Clear repository
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$GITHUB_WORKSPACE" && mkdir "$GITHUB_WORKSPACE"
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Sqllogic test
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci"
|
||||||
|
python3 sqllogic_test.py "$CHECK_NAME" "$KILL_TIMEOUT"
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
23
.github/workflows/pull_request_approved.yml
vendored
Normal file
23
.github/workflows/pull_request_approved.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: PullRequestApprovedCI
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Force the stdout and stderr streams to be unbuffered
|
||||||
|
PYTHONUNBUFFERED: 1
|
||||||
|
|
||||||
|
on: # yamllint disable-line rule:truthy
|
||||||
|
pull_request_review:
|
||||||
|
types:
|
||||||
|
- submitted
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
MergeOnApproval:
|
||||||
|
runs-on: [self-hosted, style-checker]
|
||||||
|
steps:
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Merge approved PR
|
||||||
|
run: |
|
||||||
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
|
python3 merge_pr.py --check-approved
|
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@ -7,15 +7,28 @@ on: # yamllint disable-line rule:truthy
|
|||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: 'Release tag'
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ReleasePublish:
|
ReleasePublish:
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set tag from input
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
echo "GITHUB_TAG=${{ github.event.inputs.tag }}" >> "$GITHUB_ENV"
|
||||||
|
- name: Set tag from REF
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
run: |
|
||||||
|
echo "GITHUB_TAG=${GITHUB_REF#refs/tags/}" >> "$GITHUB_ENV"
|
||||||
- name: Deploy packages and assets
|
- name: Deploy packages and assets
|
||||||
run: |
|
run: |
|
||||||
GITHUB_TAG="${GITHUB_REF#refs/tags/}"
|
curl --silent --data '' --no-buffer \
|
||||||
curl --silent --data '' \
|
|
||||||
'${{ secrets.PACKAGES_RELEASE_URL }}/release/'"${GITHUB_TAG}"'?binary=binary_darwin&binary=binary_darwin_aarch64&sync=true'
|
'${{ secrets.PACKAGES_RELEASE_URL }}/release/'"${GITHUB_TAG}"'?binary=binary_darwin&binary=binary_darwin_aarch64&sync=true'
|
||||||
############################################################################################
|
############################################################################################
|
||||||
##################################### Docker images #######################################
|
##################################### Docker images #######################################
|
||||||
@ -23,16 +36,26 @@ jobs:
|
|||||||
DockerServerImages:
|
DockerServerImages:
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set tag from input
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
run: |
|
||||||
|
echo "GITHUB_TAG=${{ github.event.inputs.tag }}" >> "$GITHUB_ENV"
|
||||||
|
- name: Set tag from REF
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
run: |
|
||||||
|
echo "GITHUB_TAG=${GITHUB_REF#refs/tags/}" >> "$GITHUB_ENV"
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: ClickHouse/checkout@v1
|
uses: ClickHouse/checkout@v1
|
||||||
with:
|
with:
|
||||||
clear-repository: true
|
clear-repository: true
|
||||||
fetch-depth: 0 # otherwise we will have no version info
|
fetch-depth: 0 # otherwise we will have no version info
|
||||||
|
ref: ${{ env.GITHUB_TAG }}
|
||||||
- name: Check docker clickhouse/clickhouse-server building
|
- name: Check docker clickhouse/clickhouse-server building
|
||||||
run: |
|
run: |
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 docker_server.py --release-type auto --version "${{ github.ref }}"
|
python3 docker_server.py --release-type auto --version "$GITHUB_TAG" \
|
||||||
python3 docker_server.py --release-type auto --version "${{ github.ref }}" --no-ubuntu \
|
--image-repo clickhouse/clickhouse-server --image-path docker/server
|
||||||
|
python3 docker_server.py --release-type auto --version "$GITHUB_TAG" \
|
||||||
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
|
54
.github/workflows/release_branches.yml
vendored
54
.github/workflows/release_branches.yml
vendored
@ -71,7 +71,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: changed_images
|
name: changed_images
|
||||||
path: ${{ runner.temp }}/changed_images.json
|
path: ${{ runner.temp }}/changed_images.json
|
||||||
CompatibilityCheck:
|
CompatibilityCheckX86:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebRelease]
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
@ -90,12 +90,43 @@ jobs:
|
|||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ${{ env.REPORTS_PATH }}
|
path: ${{ env.REPORTS_PATH }}
|
||||||
- name: CompatibilityCheck
|
- name: CompatibilityCheckX86
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
mkdir -p "$TEMP_PATH"
|
mkdir -p "$TEMP_PATH"
|
||||||
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (amd64)" --check-glibc --check-distributions
|
||||||
|
- name: Cleanup
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
docker ps --quiet | xargs --no-run-if-empty docker kill ||:
|
||||||
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
CompatibilityCheckAarch64:
|
||||||
|
needs: [BuilderDebAarch64]
|
||||||
|
runs-on: [self-hosted, style-checker]
|
||||||
|
steps:
|
||||||
|
- name: Set envs
|
||||||
|
run: |
|
||||||
|
cat >> "$GITHUB_ENV" << 'EOF'
|
||||||
|
TEMP_PATH=${{runner.temp}}/compatibility_check
|
||||||
|
REPO_COPY=${{runner.temp}}/compatibility_check/ClickHouse
|
||||||
|
REPORTS_PATH=${{runner.temp}}/reports_dir
|
||||||
|
EOF
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: ClickHouse/checkout@v1
|
||||||
|
with:
|
||||||
|
clear-repository: true
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.REPORTS_PATH }}
|
||||||
|
- name: CompatibilityCheckAarch64
|
||||||
|
run: |
|
||||||
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
mkdir -p "$TEMP_PATH"
|
||||||
|
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
|
||||||
|
cd "$REPO_COPY/tests/ci" && python3 compatibility_check.py --check-name "Compatibility check (aarch64)" --check-glibc
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
@ -375,6 +406,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
clear-repository: true
|
clear-repository: true
|
||||||
submodules: true
|
submodules: true
|
||||||
|
- name: Apply sparse checkout for contrib # in order to check that it doesn't break build
|
||||||
|
run: |
|
||||||
|
rm -rf "$GITHUB_WORKSPACE/contrib" && echo 'removed'
|
||||||
|
git -C "$GITHUB_WORKSPACE" checkout . && echo 'restored'
|
||||||
|
"$GITHUB_WORKSPACE/contrib/update-submodules.sh" && echo 'OK'
|
||||||
|
du -hs "$GITHUB_WORKSPACE/contrib" ||:
|
||||||
|
find "$GITHUB_WORKSPACE/contrib" -type f | wc -l ||:
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
@ -494,8 +532,9 @@ jobs:
|
|||||||
- name: Check docker clickhouse/clickhouse-server building
|
- name: Check docker clickhouse/clickhouse-server building
|
||||||
run: |
|
run: |
|
||||||
cd "$GITHUB_WORKSPACE/tests/ci"
|
cd "$GITHUB_WORKSPACE/tests/ci"
|
||||||
python3 docker_server.py --release-type head --no-push
|
python3 docker_server.py --release-type head --no-push \
|
||||||
python3 docker_server.py --release-type head --no-push --no-ubuntu \
|
--image-repo clickhouse/clickhouse-server --image-path docker/server
|
||||||
|
python3 docker_server.py --release-type head --no-push \
|
||||||
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
--image-repo clickhouse/clickhouse-keeper --image-path docker/keeper
|
||||||
- name: Cleanup
|
- name: Cleanup
|
||||||
if: always()
|
if: always()
|
||||||
@ -641,7 +680,7 @@ jobs:
|
|||||||
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
InstallPackagesTestAarch64:
|
InstallPackagesTestAarch64:
|
||||||
needs: [BuilderDebRelease]
|
needs: [BuilderDebAarch64]
|
||||||
runs-on: [self-hosted, style-checker-aarch64]
|
runs-on: [self-hosted, style-checker-aarch64]
|
||||||
steps:
|
steps:
|
||||||
- name: Set envs
|
- name: Set envs
|
||||||
@ -1947,7 +1986,8 @@ jobs:
|
|||||||
- IntegrationTestsTsan1
|
- IntegrationTestsTsan1
|
||||||
- IntegrationTestsTsan2
|
- IntegrationTestsTsan2
|
||||||
- IntegrationTestsTsan3
|
- IntegrationTestsTsan3
|
||||||
- CompatibilityCheck
|
- CompatibilityCheckX86
|
||||||
|
- CompatibilityCheckAarch64
|
||||||
runs-on: [self-hosted, style-checker]
|
runs-on: [self-hosted, style-checker]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
|
7
.github/workflows/woboq.yml
vendored
7
.github/workflows/woboq.yml
vendored
@ -6,9 +6,8 @@ env:
|
|||||||
concurrency:
|
concurrency:
|
||||||
group: woboq
|
group: woboq
|
||||||
on: # yamllint disable-line rule:truthy
|
on: # yamllint disable-line rule:truthy
|
||||||
schedule:
|
|
||||||
- cron: '0 */18 * * *'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
workflow_call:
|
||||||
jobs:
|
jobs:
|
||||||
# don't use dockerhub push because this image updates so rarely
|
# don't use dockerhub push because this image updates so rarely
|
||||||
WoboqCodebrowser:
|
WoboqCodebrowser:
|
||||||
@ -26,6 +25,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
clear-repository: true
|
clear-repository: true
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
- name: Download json reports
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
path: ${{ env.IMAGES_PATH }}
|
||||||
- name: Codebrowser
|
- name: Codebrowser
|
||||||
run: |
|
run: |
|
||||||
sudo rm -fr "$TEMP_PATH"
|
sudo rm -fr "$TEMP_PATH"
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -129,7 +129,6 @@ website/package-lock.json
|
|||||||
/.ccls-cache
|
/.ccls-cache
|
||||||
|
|
||||||
# clangd cache
|
# clangd cache
|
||||||
/.clangd
|
|
||||||
/.cache
|
/.cache
|
||||||
|
|
||||||
/compile_commands.json
|
/compile_commands.json
|
||||||
@ -161,6 +160,7 @@ website/package-lock.json
|
|||||||
tests/queries/0_stateless/test_*
|
tests/queries/0_stateless/test_*
|
||||||
tests/queries/0_stateless/*.binary
|
tests/queries/0_stateless/*.binary
|
||||||
tests/queries/0_stateless/*.generated-expect
|
tests/queries/0_stateless/*.generated-expect
|
||||||
|
tests/queries/0_stateless/*.expect.history
|
||||||
|
|
||||||
# rust
|
# rust
|
||||||
/rust/**/target
|
/rust/**/target
|
||||||
|
14
.gitmodules
vendored
14
.gitmodules
vendored
@ -267,7 +267,7 @@
|
|||||||
url = https://github.com/ClickHouse/nats.c
|
url = https://github.com/ClickHouse/nats.c
|
||||||
[submodule "contrib/vectorscan"]
|
[submodule "contrib/vectorscan"]
|
||||||
path = contrib/vectorscan
|
path = contrib/vectorscan
|
||||||
url = https://github.com/VectorCamp/vectorscan
|
url = https://github.com/VectorCamp/vectorscan.git
|
||||||
[submodule "contrib/c-ares"]
|
[submodule "contrib/c-ares"]
|
||||||
path = contrib/c-ares
|
path = contrib/c-ares
|
||||||
url = https://github.com/ClickHouse/c-ares
|
url = https://github.com/ClickHouse/c-ares
|
||||||
@ -296,6 +296,12 @@
|
|||||||
[submodule "contrib/libdivide"]
|
[submodule "contrib/libdivide"]
|
||||||
path = contrib/libdivide
|
path = contrib/libdivide
|
||||||
url = https://github.com/ridiculousfish/libdivide
|
url = https://github.com/ridiculousfish/libdivide
|
||||||
|
[submodule "contrib/libbcrypt"]
|
||||||
|
path = contrib/libbcrypt
|
||||||
|
url = https://github.com/rg3/libbcrypt.git
|
||||||
|
[submodule "contrib/ulid-c"]
|
||||||
|
path = contrib/ulid-c
|
||||||
|
url = https://github.com/ClickHouse/ulid-c.git
|
||||||
[submodule "contrib/aws-crt-cpp"]
|
[submodule "contrib/aws-crt-cpp"]
|
||||||
path = contrib/aws-crt-cpp
|
path = contrib/aws-crt-cpp
|
||||||
url = https://github.com/ClickHouse/aws-crt-cpp
|
url = https://github.com/ClickHouse/aws-crt-cpp
|
||||||
@ -336,3 +342,9 @@
|
|||||||
path = contrib/libarchive
|
path = contrib/libarchive
|
||||||
url = https://github.com/libarchive/libarchive.git
|
url = https://github.com/libarchive/libarchive.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
|
[submodule "contrib/libfiu"]
|
||||||
|
path = contrib/libfiu
|
||||||
|
url = https://github.com/ClickHouse/libfiu.git
|
||||||
|
[submodule "contrib/isa-l"]
|
||||||
|
path = contrib/isa-l
|
||||||
|
url = https://github.com/ClickHouse/isa-l.git
|
||||||
|
516
CHANGELOG.md
516
CHANGELOG.md
@ -1,9 +1,525 @@
|
|||||||
### Table of Contents
|
### Table of Contents
|
||||||
|
**[ClickHouse release v23.4, 2023-04-26](#234)**<br/>
|
||||||
|
**[ClickHouse release v23.3 LTS, 2023-03-30](#233)**<br/>
|
||||||
|
**[ClickHouse release v23.2, 2023-02-23](#232)**<br/>
|
||||||
**[ClickHouse release v23.1, 2023-01-25](#231)**<br/>
|
**[ClickHouse release v23.1, 2023-01-25](#231)**<br/>
|
||||||
**[Changelog for 2022](https://clickhouse.com/docs/en/whats-new/changelog/2022/)**<br/>
|
**[Changelog for 2022](https://clickhouse.com/docs/en/whats-new/changelog/2022/)**<br/>
|
||||||
|
|
||||||
# 2023 Changelog
|
# 2023 Changelog
|
||||||
|
|
||||||
|
### <a id="234"></a> ClickHouse release 23.4, 2023-04-26
|
||||||
|
|
||||||
|
#### Backward Incompatible Change
|
||||||
|
* Formatter '%M' in function formatDateTime() now prints the month name instead of the minutes. This makes the behavior consistent with MySQL. The previous behavior can be restored using setting "formatdatetime_parsedatetime_m_is_month_name = 0". [#47246](https://github.com/ClickHouse/ClickHouse/pull/47246) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* This change makes sense only if you are using the virtual filesystem cache. If `path` in the virtual filesystem cache configuration is not empty and is not an absolute path, then it will be put in `<clickhouse server data directory>/caches/<path_from_cache_config>`. [#48784](https://github.com/ClickHouse/ClickHouse/pull/48784) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Primary/secondary indices and sorting keys with identical expressions are now rejected. This behavior can be disabled using setting `allow_suspicious_indices`. [#48536](https://github.com/ClickHouse/ClickHouse/pull/48536) ([凌涛](https://github.com/lingtaolf)).
|
||||||
|
|
||||||
|
#### New Feature
|
||||||
|
* Support new aggregate function `quantileGK`/`quantilesGK`, like [approx_percentile](https://spark.apache.org/docs/latest/api/sql/index.html#approx_percentile) in spark. Greenwald-Khanna algorithm refer to http://infolab.stanford.edu/~datar/courses/cs361a/papers/quantiles.pdf. [#46428](https://github.com/ClickHouse/ClickHouse/pull/46428) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Add a statement `SHOW COLUMNS` which shows distilled information from system.columns. [#48017](https://github.com/ClickHouse/ClickHouse/pull/48017) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Added `LIGHTWEIGHT` and `PULL` modifiers for `SYSTEM SYNC REPLICA` query. `LIGHTWEIGHT` version waits for fetches and drop-ranges only (merges and mutations are ignored). `PULL` version pulls new entries from ZooKeeper and does not wait for them. Fixes [#47794](https://github.com/ClickHouse/ClickHouse/issues/47794). [#48085](https://github.com/ClickHouse/ClickHouse/pull/48085) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Add `kafkaMurmurHash` function for compatibility with Kafka DefaultPartitioner. Closes [#47834](https://github.com/ClickHouse/ClickHouse/issues/47834). [#48185](https://github.com/ClickHouse/ClickHouse/pull/48185) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Allow to easily create a user with the same grants as the current user by using `GRANT CURRENT GRANTS`. [#48262](https://github.com/ClickHouse/ClickHouse/pull/48262) ([pufit](https://github.com/pufit)).
|
||||||
|
* Add statistical aggregate function `kolmogorovSmirnovTest`. Close [#48228](https://github.com/ClickHouse/ClickHouse/issues/48228). [#48325](https://github.com/ClickHouse/ClickHouse/pull/48325) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||||
|
* Added a `lost_part_count` column to the `system.replicas` table. The column value shows the total number of lost parts in the corresponding table. Value is stored in zookeeper and can be used instead of not persistent `ReplicatedDataLoss` profile event for monitoring. [#48526](https://github.com/ClickHouse/ClickHouse/pull/48526) ([Sergei Trifonov](https://github.com/serxa)).
|
||||||
|
* Add `soundex` function for compatibility. Closes [#39880](https://github.com/ClickHouse/ClickHouse/issues/39880). [#48567](https://github.com/ClickHouse/ClickHouse/pull/48567) ([FriendLey](https://github.com/FriendLey)).
|
||||||
|
* Support `Map` type for JSONExtract. [#48629](https://github.com/ClickHouse/ClickHouse/pull/48629) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Add `PrettyJSONEachRow` format to output pretty JSON with new line delimiters and 4 space indents. [#48898](https://github.com/ClickHouse/ClickHouse/pull/48898) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add `ParquetMetadata` input format to read Parquet file metadata. [#48911](https://github.com/ClickHouse/ClickHouse/pull/48911) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add `extractKeyValuePairs` function to extract key value pairs from strings. Input strings might contain noise (i.e. log files / do not need to be 100% formatted in key-value-pair format), the algorithm will look for key value pairs matching the arguments passed to the function. As of now, function accepts the following arguments: `data_column` (mandatory), `key_value_pair_delimiter` (defaults to `:`), `pair_delimiters` (defaults to `\space \, \;`) and `quoting_character` (defaults to double quotes). [#43606](https://github.com/ClickHouse/ClickHouse/pull/43606) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||||
|
* Functions replaceOne(), replaceAll(), replaceRegexpOne() and replaceRegexpAll() can now be called with non-const pattern and replacement arguments. [#46589](https://github.com/ClickHouse/ClickHouse/pull/46589) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Added functions to work with columns of type `Map`: `mapConcat`, `mapSort`, `mapExists`. [#48071](https://github.com/ClickHouse/ClickHouse/pull/48071) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
|
||||||
|
#### Performance Improvement
|
||||||
|
* Reading files in `Parquet` format is now much faster. IO and decoding are parallelized (controlled by `max_threads` setting), and only required data ranges are read. [#47964](https://github.com/ClickHouse/ClickHouse/pull/47964) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||||
|
* If we run a mutation with IN (subquery) like this: `ALTER TABLE t UPDATE col='new value' WHERE id IN (SELECT id FROM huge_table)` and the table `t` has multiple parts than for each part a set for subquery `SELECT id FROM huge_table` is built in memory. And if there are many parts then this might consume a lot of memory (and lead to an OOM) and CPU. The solution is to introduce a short-lived cache of sets that are currently being built by mutation tasks. If another task of the same mutation is executed concurrently it can look up the set in the cache, wait for it to be built and reuse it. [#46835](https://github.com/ClickHouse/ClickHouse/pull/46835) ([Alexander Gololobov](https://github.com/davenger)).
|
||||||
|
* Only check dependencies if necessary when applying `ALTER TABLE` queries. [#48062](https://github.com/ClickHouse/ClickHouse/pull/48062) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Optimize function `mapUpdate`. [#48118](https://github.com/ClickHouse/ClickHouse/pull/48118) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Now an internal query to local replica is sent explicitly and data from it received through loopback interface. Setting `prefer_localhost_replica` is not respected for parallel replicas. This is needed for better scheduling and makes the code cleaner: the initiator is only responsible for coordinating of the reading process and merging results, continuously answering for requests while all the secondary queries read the data. Note: Using loopback interface is not so performant, otherwise some replicas could starve for tasks which could lead to even slower query execution and not utilizing all possible resources. The initialization of the coordinator is now even more lazy. All incoming requests contain the information about the reading algorithm we initialize the coordinator with it when first request comes. If any replica decides to read with a different algorithm–an exception will be thrown and a query will be aborted. [#48246](https://github.com/ClickHouse/ClickHouse/pull/48246) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||||
|
* Do not build set for the right side of `IN` clause with subquery when it is used only for analysis of skip indexes, and they are disabled by setting (`use_skip_indexes=0`). Previously it might affect the performance of queries. [#48299](https://github.com/ClickHouse/ClickHouse/pull/48299) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Query processing is parallelized right after reading `FROM file(...)`. Related to [#38755](https://github.com/ClickHouse/ClickHouse/issues/38755). [#48525](https://github.com/ClickHouse/ClickHouse/pull/48525) ([Igor Nikonov](https://github.com/devcrafter)). Query processing is parallelized right after reading from any data source. Affected data sources are mostly simple or external storages like table functions `url`, `file`. [#48727](https://github.com/ClickHouse/ClickHouse/pull/48727) ([Igor Nikonov](https://github.com/devcrafter)). This is controlled by the setting `parallelize_output_from_storages` which is not enabled by default.
|
||||||
|
* Lowered contention of ThreadPool mutex (may increase performance for a huge amount of small jobs). [#48750](https://github.com/ClickHouse/ClickHouse/pull/48750) ([Sergei Trifonov](https://github.com/serxa)).
|
||||||
|
* Reduce memory usage for multiple `ALTER DELETE` mutations. [#48522](https://github.com/ClickHouse/ClickHouse/pull/48522) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Remove the excessive connection attempts if the `skip_unavailable_shards` setting is enabled. [#48771](https://github.com/ClickHouse/ClickHouse/pull/48771) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
|
||||||
|
#### Experimental Feature
|
||||||
|
* Entries in the query cache are now squashed to max_block_size and compressed. [#45912](https://github.com/ClickHouse/ClickHouse/pull/45912) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* It is now possible to define per-user quotas in the query cache. [#48284](https://github.com/ClickHouse/ClickHouse/pull/48284) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Some fixes for parallel replicas [#48433](https://github.com/ClickHouse/ClickHouse/pull/48433) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||||
|
* Implement zero-copy-replication (an experimental feature) on encrypted disks. [#48741](https://github.com/ClickHouse/ClickHouse/pull/48741) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
|
||||||
|
#### Improvement
|
||||||
|
* Increase default value for `connect_timeout_with_failover_ms` to 1000 ms (because of adding async connections in https://github.com/ClickHouse/ClickHouse/pull/47229) . Closes [#5188](https://github.com/ClickHouse/ClickHouse/issues/5188). [#49009](https://github.com/ClickHouse/ClickHouse/pull/49009) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Several improvements around data lakes: - Make `Iceberg` work with non-partitioned data. - Support `Iceberg` format version v2 (previously only v1 was supported) - Support reading partitioned data for `DeltaLake`/`Hudi` - Faster reading of `DeltaLake` metadata by using Delta's checkpoint files - Fixed incorrect `Hudi` reads: previously it incorrectly chose which data to read and therefore was able to read correctly only small size tables - Made these engines to pickup updates of changed data (previously the state was set on table creation) - Make proper testing for `Iceberg`/`DeltaLake`/`Hudi` using spark. [#47307](https://github.com/ClickHouse/ClickHouse/pull/47307) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Add async connection to socket and async writing to socket. Make creating connections and sending query/external tables async across shards. Refactor code with fibers. Closes [#46931](https://github.com/ClickHouse/ClickHouse/issues/46931). We will be able to increase `connect_timeout_with_failover_ms` by default after this PR (https://github.com/ClickHouse/ClickHouse/issues/5188). [#47229](https://github.com/ClickHouse/ClickHouse/pull/47229) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Support config sections `keeper`/`keeper_server` as an alternative to `zookeeper`. Close [#34766](https://github.com/ClickHouse/ClickHouse/issues/34766) , [#34767](https://github.com/ClickHouse/ClickHouse/issues/34767). [#35113](https://github.com/ClickHouse/ClickHouse/pull/35113) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* It is possible to set _secure_ flag in named_collections for a dictionary with a ClickHouse table source. Addresses [#38450](https://github.com/ClickHouse/ClickHouse/issues/38450) . [#46323](https://github.com/ClickHouse/ClickHouse/pull/46323) ([Ilya Golshtein](https://github.com/ilejn)).
|
||||||
|
* `bitCount` function support `FixedString` and `String` data type. [#49044](https://github.com/ClickHouse/ClickHouse/pull/49044) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Added configurable retries for all operations with [Zoo]Keeper for Backup queries. [#47224](https://github.com/ClickHouse/ClickHouse/pull/47224) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||||
|
* Enable `use_environment_credentials` for S3 by default, so the entire provider chain is constructed by default. [#47397](https://github.com/ClickHouse/ClickHouse/pull/47397) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Currently, the JSON_VALUE function is similar as spark's get_json_object function, which support to get value from JSON string by a path like '$.key'. But still has something different - 1. in spark's get_json_object will return null while the path is not exist, but in JSON_VALUE will return empty string; - 2. in spark's get_json_object will return a complex type value, such as a JSON object/array value, but in JSON_VALUE will return empty string. [#47494](https://github.com/ClickHouse/ClickHouse/pull/47494) ([KevinyhZou](https://github.com/KevinyhZou)).
|
||||||
|
* For `use_structure_from_insertion_table_in_table_functions` more flexible insert table structure propagation to table function. Fixed an issue with name mapping and using virtual columns. No more need for 'auto' setting. [#47962](https://github.com/ClickHouse/ClickHouse/pull/47962) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Do not continue retrying to connect to Keeper if the query is killed or over limits. [#47985](https://github.com/ClickHouse/ClickHouse/pull/47985) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Support Enum output/input in `BSONEachRow`, allow all map key types and avoid extra calculations on output. [#48122](https://github.com/ClickHouse/ClickHouse/pull/48122) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Support more ClickHouse types in `ORC`/`Arrow`/`Parquet` formats: Enum(8|16), (U)Int(128|256), Decimal256 (for ORC), allow reading IPv4 from Int32 values (ORC outputs IPv4 as Int32, and we couldn't read it back), fix reading Nullable(IPv6) from binary data for `ORC`. [#48126](https://github.com/ClickHouse/ClickHouse/pull/48126) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add columns `perform_ttl_move_on_insert`, `load_balancing` for table `system.storage_policies`, modify column `volume_type` type to `Enum8`. [#48167](https://github.com/ClickHouse/ClickHouse/pull/48167) ([lizhuoyu5](https://github.com/lzydmxy)).
|
||||||
|
* Added support for `BACKUP ALL` command which backups all tables and databases, including temporary and system ones. [#48189](https://github.com/ClickHouse/ClickHouse/pull/48189) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Function mapFromArrays supports `Map` type as an input. [#48207](https://github.com/ClickHouse/ClickHouse/pull/48207) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* The output of some SHOW PROCESSLIST is now sorted. [#48241](https://github.com/ClickHouse/ClickHouse/pull/48241) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Per-query/per-server throttling for remote IO/local IO/BACKUPs (server settings: `max_remote_read_network_bandwidth_for_server`, `max_remote_write_network_bandwidth_for_server`, `max_local_read_bandwidth_for_server`, `max_local_write_bandwidth_for_server`, `max_backup_bandwidth_for_server`, settings: `max_remote_read_network_bandwidth`, `max_remote_write_network_bandwidth`, `max_local_read_bandwidth`, `max_local_write_bandwidth`, `max_backup_bandwidth`). [#48242](https://github.com/ClickHouse/ClickHouse/pull/48242) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Support more types in `CapnProto` format: Map, (U)Int(128|256), Decimal(128|256). Allow integer conversions during input/output. [#48257](https://github.com/ClickHouse/ClickHouse/pull/48257) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Don't throw CURRENT_WRITE_BUFFER_IS_EXHAUSTED for normal behaviour. [#48288](https://github.com/ClickHouse/ClickHouse/pull/48288) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Add new setting `keeper_map_strict_mode` which enforces extra guarantees on operations made on top of `KeeperMap` tables. [#48293](https://github.com/ClickHouse/ClickHouse/pull/48293) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Check primary key type for simple dictionary is native unsigned integer type Add setting `check_dictionary_primary_key ` for compatibility(set `check_dictionary_primary_key =false` to disable checking). [#48335](https://github.com/ClickHouse/ClickHouse/pull/48335) ([lizhuoyu5](https://github.com/lzydmxy)).
|
||||||
|
* Don't replicate mutations for `KeeperMap` because it's unnecessary. [#48354](https://github.com/ClickHouse/ClickHouse/pull/48354) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Allow to write/read unnamed tuple as nested Message in Protobuf format. Tuple elements and Message fields are matched by position. [#48390](https://github.com/ClickHouse/ClickHouse/pull/48390) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Support `additional_table_filters` and `additional_result_filter` settings in the new planner. Also, add a documentation entry for `additional_result_filter`. [#48405](https://github.com/ClickHouse/ClickHouse/pull/48405) ([Dmitry Novik](https://github.com/novikd)).
|
||||||
|
* `parseDateTime` now understands format string '%f' (fractional seconds). [#48420](https://github.com/ClickHouse/ClickHouse/pull/48420) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Format string "%f" in formatDateTime() now prints "000000" if the formatted value has no fractional seconds, the previous behavior (single zero) can be restored using setting "formatdatetime_f_prints_single_zero = 1". [#48422](https://github.com/ClickHouse/ClickHouse/pull/48422) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Don't replicate DELETE and TRUNCATE for KeeperMap. [#48434](https://github.com/ClickHouse/ClickHouse/pull/48434) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Generate valid Decimals and Bools in generateRandom function. [#48436](https://github.com/ClickHouse/ClickHouse/pull/48436) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Allow trailing commas in expression list of SELECT query, for example `SELECT a, b, c, FROM table`. Closes [#37802](https://github.com/ClickHouse/ClickHouse/issues/37802). [#48438](https://github.com/ClickHouse/ClickHouse/pull/48438) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Override `CLICKHOUSE_USER` and `CLICKHOUSE_PASSWORD` environment variables with `--user` and `--password` client parameters. Closes [#38909](https://github.com/ClickHouse/ClickHouse/issues/38909). [#48440](https://github.com/ClickHouse/ClickHouse/pull/48440) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Added retries to loading of data parts in `MergeTree` tables in case of retryable errors. [#48442](https://github.com/ClickHouse/ClickHouse/pull/48442) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Add support for `Date`, `Date32`, `DateTime`, `DateTime64` data types to `arrayMin`, `arrayMax`, `arrayDifference` functions. Closes [#21645](https://github.com/ClickHouse/ClickHouse/issues/21645). [#48445](https://github.com/ClickHouse/ClickHouse/pull/48445) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Add support for `{server_uuid}` macro. It is useful for identifying replicas in autoscaled clusters when new replicas are constantly added and removed in runtime. This closes [#48554](https://github.com/ClickHouse/ClickHouse/issues/48554). [#48563](https://github.com/ClickHouse/ClickHouse/pull/48563) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* The installation script will create a hard link instead of copying if it is possible. [#48578](https://github.com/ClickHouse/ClickHouse/pull/48578) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Support `SHOW TABLE` syntax meaning the same as `SHOW CREATE TABLE`. Closes [#48580](https://github.com/ClickHouse/ClickHouse/issues/48580). [#48591](https://github.com/ClickHouse/ClickHouse/pull/48591) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* HTTP temporary buffers now support working by evicting data from the virtual filesystem cache. [#48664](https://github.com/ClickHouse/ClickHouse/pull/48664) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Make Schema inference works for `CREATE AS SELECT`. Closes [#47599](https://github.com/ClickHouse/ClickHouse/issues/47599). [#48679](https://github.com/ClickHouse/ClickHouse/pull/48679) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Added a `replicated_max_mutations_in_one_entry` setting for `ReplicatedMergeTree` that allows limiting the number of mutation commands per one `MUTATE_PART` entry (default is 10000). [#48731](https://github.com/ClickHouse/ClickHouse/pull/48731) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* In AggregateFunction types, don't count unused arena bytes as `read_bytes`. [#48745](https://github.com/ClickHouse/ClickHouse/pull/48745) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Fix some MySQL-related settings not being handled with the MySQL dictionary source + named collection. Closes [#48402](https://github.com/ClickHouse/ClickHouse/issues/48402). [#48759](https://github.com/ClickHouse/ClickHouse/pull/48759) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* If a user set `max_single_part_upload_size` to a very large value, it can lead to a crash due to a bug in the AWS S3 SDK. This fixes [#47679](https://github.com/ClickHouse/ClickHouse/issues/47679). [#48816](https://github.com/ClickHouse/ClickHouse/pull/48816) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix data race in `RabbitMQ` ([report](https://pastila.nl/?004f7100/de1505289ab5bb355e67ebe6c7cc8707)), refactor the code. [#48845](https://github.com/ClickHouse/ClickHouse/pull/48845) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Add aliases `name` and `part_name` form `system.parts` and `system.part_log`. Closes [#48718](https://github.com/ClickHouse/ClickHouse/issues/48718). [#48850](https://github.com/ClickHouse/ClickHouse/pull/48850) ([sichenzhao](https://github.com/sichenzhao)).
|
||||||
|
* Functions "arrayDifferenceSupport()", "arrayCumSum()" and "arrayCumSumNonNegative()" now support input arrays of wide integer types (U)Int128/256. [#48866](https://github.com/ClickHouse/ClickHouse/pull/48866) ([cluster](https://github.com/infdahai)).
|
||||||
|
* Multi-line history in clickhouse-client is now no longer padded. This makes pasting more natural. [#48870](https://github.com/ClickHouse/ClickHouse/pull/48870) ([Joanna Hulboj](https://github.com/jh0x)).
|
||||||
|
* Implement a slight improvement for the rare case when ClickHouse is run inside LXC and LXCFS is used. The LXCFS has an issue: sometimes it returns an error "Transport endpoint is not connected" on reading from the file inside `/proc`. This error was correctly logged into ClickHouse's server log. We have additionally workaround this issue by reopening a file. This is a minuscule change. [#48922](https://github.com/ClickHouse/ClickHouse/pull/48922) ([Real](https://github.com/RunningXie)).
|
||||||
|
* Improve memory accounting for prefetches. Randomise prefetch settings In CI. [#48973](https://github.com/ClickHouse/ClickHouse/pull/48973) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Correctly set headers for native copy operations on GCS. [#48981](https://github.com/ClickHouse/ClickHouse/pull/48981) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Add support for specifying setting names in the command line with dashes instead of underscores, for example, `--max-threads` instead of `--max_threads`. Additionally, support Unicode dash characters like `—` instead of `--` - this is useful when you communicate with a team in another company, and a manager from that team copy-pasted code from MS Word. [#48985](https://github.com/ClickHouse/ClickHouse/pull/48985) ([alekseygolub](https://github.com/alekseygolub)).
|
||||||
|
* Add fallback to password authentication when authentication with SSL user certificate has failed. Closes [#48974](https://github.com/ClickHouse/ClickHouse/issues/48974). [#48989](https://github.com/ClickHouse/ClickHouse/pull/48989) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Improve the embedded dashboard. Close [#46671](https://github.com/ClickHouse/ClickHouse/issues/46671). [#49036](https://github.com/ClickHouse/ClickHouse/pull/49036) ([Kevin Zhang](https://github.com/Kinzeng)).
|
||||||
|
* Add profile events for log messages, so you can easily see the count of log messages by severity. [#49042](https://github.com/ClickHouse/ClickHouse/pull/49042) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* In previous versions, the `LineAsString` format worked inconsistently when the parallel parsing was enabled or not, in presence of DOS or macOS Classic line breaks. This closes [#49039](https://github.com/ClickHouse/ClickHouse/issues/49039). [#49052](https://github.com/ClickHouse/ClickHouse/pull/49052) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* The exception message about the unparsed query parameter will also tell about the name of the parameter. Reimplement [#48878](https://github.com/ClickHouse/ClickHouse/issues/48878). Close [#48772](https://github.com/ClickHouse/ClickHouse/issues/48772). [#49061](https://github.com/ClickHouse/ClickHouse/pull/49061) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
|
||||||
|
#### Build/Testing/Packaging Improvement
|
||||||
|
* Update time zones. The following were updated: Africa/Cairo, Africa/Casablanca, Africa/El_Aaiun, America/Bogota, America/Cambridge_Bay, America/Ciudad_Juarez, America/Godthab, America/Inuvik, America/Iqaluit, America/Nuuk, America/Ojinaga, America/Pangnirtung, America/Rankin_Inlet, America/Resolute, America/Whitehorse, America/Yellowknife, Asia/Gaza, Asia/Hebron, Asia/Kuala_Lumpur, Asia/Singapore, Canada/Yukon, Egypt, Europe/Kirov, Europe/Volgograd, Singapore. [#48572](https://github.com/ClickHouse/ClickHouse/pull/48572) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Reduce the number of dependencies in the header files to speed up the build. [#47984](https://github.com/ClickHouse/ClickHouse/pull/47984) ([Dmitry Novik](https://github.com/novikd)).
|
||||||
|
* Randomize compression of marks and indices in tests. [#48286](https://github.com/ClickHouse/ClickHouse/pull/48286) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Bump internal ZSTD from 1.5.4 to 1.5.5. [#46797](https://github.com/ClickHouse/ClickHouse/pull/46797) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Randomize vertical merges from compact to wide parts in tests. [#48287](https://github.com/ClickHouse/ClickHouse/pull/48287) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Support for CRC32 checksum in HDFS. Fix performance issues. [#48614](https://github.com/ClickHouse/ClickHouse/pull/48614) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Remove remainders of GCC support. [#48671](https://github.com/ClickHouse/ClickHouse/pull/48671) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Add CI run with new analyzer infrastructure enabled. [#48719](https://github.com/ClickHouse/ClickHouse/pull/48719) ([Dmitry Novik](https://github.com/novikd)).
|
||||||
|
|
||||||
|
#### Bug Fix (user-visible misbehavior in an official stable release)
|
||||||
|
|
||||||
|
* Fix system.query_views_log for MVs that are pushed from background threads [#46668](https://github.com/ClickHouse/ClickHouse/pull/46668) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix several `RENAME COLUMN` bugs [#46946](https://github.com/ClickHouse/ClickHouse/pull/46946) ([alesapin](https://github.com/alesapin)).
|
||||||
|
* Fix minor hiliting issues in clickhouse-format [#47610](https://github.com/ClickHouse/ClickHouse/pull/47610) ([Natasha Murashkina](https://github.com/murfel)).
|
||||||
|
* Fix a bug in LLVM's libc++ leading to a crash for uploading parts to S3 which size is greater than INT_MAX [#47693](https://github.com/ClickHouse/ClickHouse/pull/47693) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix overflow in the `sparkbar` function [#48121](https://github.com/ClickHouse/ClickHouse/pull/48121) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Fix race in S3 [#48190](https://github.com/ClickHouse/ClickHouse/pull/48190) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Disable JIT for aggregate functions due to inconsistent behavior [#48195](https://github.com/ClickHouse/ClickHouse/pull/48195) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix alter formatting (minor) [#48289](https://github.com/ClickHouse/ClickHouse/pull/48289) ([Natasha Murashkina](https://github.com/murfel)).
|
||||||
|
* Fix CPU usage in RabbitMQ (was worsened in 23.2 after [#44404](https://github.com/ClickHouse/ClickHouse/issues/44404)) [#48311](https://github.com/ClickHouse/ClickHouse/pull/48311) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Fix crash in EXPLAIN PIPELINE for Merge over Distributed [#48320](https://github.com/ClickHouse/ClickHouse/pull/48320) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix serializing LowCardinality as Arrow dictionary [#48361](https://github.com/ClickHouse/ClickHouse/pull/48361) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Reset downloader for cache file segment in TemporaryFileStream [#48386](https://github.com/ClickHouse/ClickHouse/pull/48386) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Fix possible SYSTEM SYNC REPLICA stuck in case of DROP/REPLACE PARTITION [#48391](https://github.com/ClickHouse/ClickHouse/pull/48391) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix a startup error when loading a distributed table that depends on a dictionary [#48419](https://github.com/ClickHouse/ClickHouse/pull/48419) ([MikhailBurdukov](https://github.com/MikhailBurdukov)).
|
||||||
|
* Don't check dependencies when renaming system tables automatically [#48431](https://github.com/ClickHouse/ClickHouse/pull/48431) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Update only affected rows in KeeperMap storage [#48435](https://github.com/ClickHouse/ClickHouse/pull/48435) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix possible segfault in the VFS cache [#48469](https://github.com/ClickHouse/ClickHouse/pull/48469) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* `toTimeZone` function throws an error when no constant string is provided [#48471](https://github.com/ClickHouse/ClickHouse/pull/48471) ([Jordi Villar](https://github.com/jrdi)).
|
||||||
|
* Fix logical error with IPv4 in Protobuf, add support for Date32 [#48486](https://github.com/ClickHouse/ClickHouse/pull/48486) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* "changed" flag in system.settings was calculated incorrectly for settings with multiple values [#48516](https://github.com/ClickHouse/ClickHouse/pull/48516) ([MikhailBurdukov](https://github.com/MikhailBurdukov)).
|
||||||
|
* Fix storage `Memory` with enabled compression [#48517](https://github.com/ClickHouse/ClickHouse/pull/48517) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Fix bracketed-paste mode messing up password input in the event of client reconnection [#48528](https://github.com/ClickHouse/ClickHouse/pull/48528) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||||
|
* Fix nested map for keys of IP and UUID types [#48556](https://github.com/ClickHouse/ClickHouse/pull/48556) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Fix an uncaught exception in case of parallel loader for hashed dictionaries [#48571](https://github.com/ClickHouse/ClickHouse/pull/48571) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* The `groupArray` aggregate function correctly works for empty result over nullable types [#48593](https://github.com/ClickHouse/ClickHouse/pull/48593) ([lgbo](https://github.com/lgbo-ustc)).
|
||||||
|
* Fix bug in Keeper when a node is not created with scheme `auth` in ACL sometimes. [#48595](https://github.com/ClickHouse/ClickHouse/pull/48595) ([Aleksei Filatov](https://github.com/aalexfvk)).
|
||||||
|
* Allow IPv4 comparison operators with UInt [#48611](https://github.com/ClickHouse/ClickHouse/pull/48611) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Fix possible error from cache [#48636](https://github.com/ClickHouse/ClickHouse/pull/48636) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Async inserts with empty data will no longer throw exception. [#48663](https://github.com/ClickHouse/ClickHouse/pull/48663) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Fix table dependencies in case of failed RENAME TABLE [#48683](https://github.com/ClickHouse/ClickHouse/pull/48683) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* If the primary key has duplicate columns (which is only possible for projections), in previous versions it might lead to a bug [#48838](https://github.com/ClickHouse/ClickHouse/pull/48838) ([Amos Bird](https://github.com/amosbird)).
|
||||||
|
* Fix for a race condition in ZooKeeper when joining send_thread/receive_thread [#48849](https://github.com/ClickHouse/ClickHouse/pull/48849) ([Alexander Gololobov](https://github.com/davenger)).
|
||||||
|
* Fix unexpected part name error when trying to drop a ignored detached part with zero copy replication [#48862](https://github.com/ClickHouse/ClickHouse/pull/48862) ([Michael Lex](https://github.com/mlex)).
|
||||||
|
* Fix reading `Date32` Parquet/Arrow column into not a `Date32` column [#48864](https://github.com/ClickHouse/ClickHouse/pull/48864) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix `UNKNOWN_IDENTIFIER` error while selecting from table with row policy and column with dots [#48976](https://github.com/ClickHouse/ClickHouse/pull/48976) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix aggregation by empty nullable strings [#48999](https://github.com/ClickHouse/ClickHouse/pull/48999) ([LiuNeng](https://github.com/liuneng1994)).
|
||||||
|
|
||||||
|
### <a id="233"></a> ClickHouse release 23.3 LTS, 2023-03-30
|
||||||
|
|
||||||
|
#### Upgrade Notes
|
||||||
|
* Lightweight DELETEs are production ready and enabled by default. The `DELETE` query for MergeTree tables is now available by default.
|
||||||
|
* The behavior of `*domain*RFC` and `netloc` functions is slightly changed: relaxed the set of symbols that are allowed in the URL authority for better conformance. [#46841](https://github.com/ClickHouse/ClickHouse/pull/46841) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Prohibited creating tables based on KafkaEngine with DEFAULT/EPHEMERAL/ALIAS/MATERIALIZED statements for columns. [#47138](https://github.com/ClickHouse/ClickHouse/pull/47138) ([Aleksandr Musorin](https://github.com/AVMusorin)).
|
||||||
|
* An "asynchronous connection drain" feature is removed. Related settings and metrics are removed as well. It was an internal feature, so the removal should not affect users who had never heard about that feature. [#47486](https://github.com/ClickHouse/ClickHouse/pull/47486) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Support 256-bit Decimal data type (more than 38 digits) in `arraySum`/`Min`/`Max`/`Avg`/`Product`, `arrayCumSum`/`CumSumNonNegative`, `arrayDifference`, array construction, IN operator, query parameters, `groupArrayMovingSum`, statistical functions, `min`/`max`/`any`/`argMin`/`argMax`, PostgreSQL wire protocol, MySQL table engine and function, `sumMap`, `mapAdd`, `mapSubtract`, `arrayIntersect`. Add support for big integers in `arrayIntersect`. Statistical aggregate functions involving moments (such as `corr` or various `TTest`s) will use `Float64` as their internal representation (they were using `Decimal128` before this change, but it was pointless), and these functions can return `nan` instead of `inf` in case of infinite variance. Some functions were allowed on `Decimal256` data types but returned `Decimal128` in previous versions - now it is fixed. This closes [#47569](https://github.com/ClickHouse/ClickHouse/issues/47569). This closes [#44864](https://github.com/ClickHouse/ClickHouse/issues/44864). This closes [#28335](https://github.com/ClickHouse/ClickHouse/issues/28335). [#47594](https://github.com/ClickHouse/ClickHouse/pull/47594) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Make backup_threads/restore_threads server settings (instead of user settings). [#47881](https://github.com/ClickHouse/ClickHouse/pull/47881) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Do not allow const and non-deterministic secondary indices [#46839](https://github.com/ClickHouse/ClickHouse/pull/46839) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
|
||||||
|
#### New Feature
|
||||||
|
* Add a new mode for splitting the work on replicas using settings `parallel_replicas_custom_key` and `parallel_replicas_custom_key_filter_type`. If the cluster consists of a single shard with multiple replicas, up to `max_parallel_replicas` will be randomly picked and turned into shards. For each shard, a corresponding filter is added to the query on the initiator before being sent to the shard. If the cluster consists of multiple shards, it will behave the same as `sample_key` but with the possibility to define an arbitrary key. [#45108](https://github.com/ClickHouse/ClickHouse/pull/45108) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* An option to display partial result on cancel: Added query setting `partial_result_on_first_cancel` allowing the canceled query (e.g. due to Ctrl-C) to return a partial result. [#45689](https://github.com/ClickHouse/ClickHouse/pull/45689) ([Alexey Perevyshin](https://github.com/alexX512)).
|
||||||
|
* Added support of arbitrary tables engines for temporary tables (except for Replicated and KeeperMap engines). Close [#31497](https://github.com/ClickHouse/ClickHouse/issues/31497). [#46071](https://github.com/ClickHouse/ClickHouse/pull/46071) ([Roman Vasin](https://github.com/rvasin)).
|
||||||
|
* Add support for replication of user-defined SQL functions using centralized storage in Keeper. [#46085](https://github.com/ClickHouse/ClickHouse/pull/46085) ([Aleksei Filatov](https://github.com/aalexfvk)).
|
||||||
|
* Implement `system.server_settings` (similar to `system.settings`), which will contain server configurations. [#46550](https://github.com/ClickHouse/ClickHouse/pull/46550) ([pufit](https://github.com/pufit)).
|
||||||
|
* Support for `UNDROP TABLE` query. Closes [#46811](https://github.com/ClickHouse/ClickHouse/issues/46811). [#47241](https://github.com/ClickHouse/ClickHouse/pull/47241) ([chen](https://github.com/xiedeyantu)).
|
||||||
|
* Allow separate grants for named collections (e.g. to be able to give `SHOW/CREATE/ALTER/DROP named collection` access only to certain collections, instead of all at once). Closes [#40894](https://github.com/ClickHouse/ClickHouse/issues/40894). Add new access type `NAMED_COLLECTION_CONTROL` which is not given to user default unless explicitly added to the user config (is required to be able to do `GRANT ALL`), also `show_named_collections` is no longer obligatory to be manually specified for user default to be able to have full access rights as was in 23.2. [#46241](https://github.com/ClickHouse/ClickHouse/pull/46241) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Allow nested custom disks. Previously custom disks supported only flat disk structure. [#47106](https://github.com/ClickHouse/ClickHouse/pull/47106) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Introduce a function `widthBucket` (with a `WIDTH_BUCKET` alias for compatibility). [#42974](https://github.com/ClickHouse/ClickHouse/issues/42974). [#46790](https://github.com/ClickHouse/ClickHouse/pull/46790) ([avoiderboi](https://github.com/avoiderboi)).
|
||||||
|
* Add new function `parseDateTime`/`parseDateTimeInJodaSyntax` according to the specified format string. parseDateTime parses String to DateTime in MySQL syntax, parseDateTimeInJodaSyntax parses in Joda syntax. [#46815](https://github.com/ClickHouse/ClickHouse/pull/46815) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Use `dummy UInt8` for the default structure of table function `null`. Closes [#46930](https://github.com/ClickHouse/ClickHouse/issues/46930). [#47006](https://github.com/ClickHouse/ClickHouse/pull/47006) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Support for date format with a comma, like `Dec 15, 2021` in the `parseDateTimeBestEffort` function. Closes [#46816](https://github.com/ClickHouse/ClickHouse/issues/46816). [#47071](https://github.com/ClickHouse/ClickHouse/pull/47071) ([chen](https://github.com/xiedeyantu)).
|
||||||
|
* Add settings `http_wait_end_of_query` and `http_response_buffer_size` that corresponds to URL params `wait_end_of_query` and `buffer_size` for the HTTP interface. This allows changing these settings in the profiles. [#47108](https://github.com/ClickHouse/ClickHouse/pull/47108) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Add `system.dropped_tables` table that shows tables that were dropped from `Atomic` databases but were not completely removed yet. [#47364](https://github.com/ClickHouse/ClickHouse/pull/47364) ([chen](https://github.com/xiedeyantu)).
|
||||||
|
* Add `INSTR` as alias of `positionCaseInsensitive` for MySQL compatibility. Closes [#47529](https://github.com/ClickHouse/ClickHouse/issues/47529). [#47535](https://github.com/ClickHouse/ClickHouse/pull/47535) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Added `toDecimalString` function allowing to convert numbers to string with fixed precision. [#47838](https://github.com/ClickHouse/ClickHouse/pull/47838) ([Andrey Zvonov](https://github.com/zvonand)).
|
||||||
|
* Add a merge tree setting `max_number_of_mutations_for_replica`. It limits the number of part mutations per replica to the specified amount. Zero means no limit on the number of mutations per replica (the execution can still be constrained by other settings). [#48047](https://github.com/ClickHouse/ClickHouse/pull/48047) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Add the Map-related function `mapFromArrays`, which allows the creation of a map from a pair of arrays. [#31125](https://github.com/ClickHouse/ClickHouse/pull/31125) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Allow control of compression in Parquet/ORC/Arrow output formats, adds support for more compression input formats. This closes [#13541](https://github.com/ClickHouse/ClickHouse/issues/13541). [#47114](https://github.com/ClickHouse/ClickHouse/pull/47114) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add SSL User Certificate authentication to the native protocol. Closes [#47077](https://github.com/ClickHouse/ClickHouse/issues/47077). [#47596](https://github.com/ClickHouse/ClickHouse/pull/47596) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Add *OrNull() and *OrZero() variants for `parseDateTime`, add alias `str_to_date` for MySQL parity. [#48000](https://github.com/ClickHouse/ClickHouse/pull/48000) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Added operator `REGEXP` (similar to operators "LIKE", "IN", "MOD" etc.) for better compatibility with MySQL [#47869](https://github.com/ClickHouse/ClickHouse/pull/47869) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
|
||||||
|
#### Performance Improvement
|
||||||
|
* Marks in memory are now compressed, using 3-6x less memory. [#47290](https://github.com/ClickHouse/ClickHouse/pull/47290) ([Michael Kolupaev](https://github.com/al13n321)).
|
||||||
|
* Backups for large numbers of files were unbelievably slow in previous versions. Not anymore. Now they are unbelievably fast. [#47251](https://github.com/ClickHouse/ClickHouse/pull/47251) ([Alexey Milovidov](https://github.com/alexey-milovidov)). Introduced a separate thread pool for backup's IO operations. This will allow scaling it independently of other pools and increase performance. [#47174](https://github.com/ClickHouse/ClickHouse/pull/47174) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). Use MultiRead request and retries for collecting metadata at the final stage of backup processing. [#47243](https://github.com/ClickHouse/ClickHouse/pull/47243) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)). If a backup and restoring data are both in S3 then server-side copy should be used from now on. [#47546](https://github.com/ClickHouse/ClickHouse/pull/47546) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Fixed excessive reading in queries with `FINAL`. [#47801](https://github.com/ClickHouse/ClickHouse/pull/47801) ([Nikita Taranov](https://github.com/nickitat)).
|
||||||
|
* Setting `max_final_threads` would be set to the number of cores at server startup (by the same algorithm as used for `max_threads`). This improves the concurrency of `final` execution on servers with high number of CPUs. [#47915](https://github.com/ClickHouse/ClickHouse/pull/47915) ([Nikita Taranov](https://github.com/nickitat)).
|
||||||
|
* Allow executing reading pipeline for DIRECT dictionary with CLICKHOUSE source in multiple threads. To enable set `dictionary_use_async_executor=1` in `SETTINGS` section for source in `CREATE DICTIONARY` statement. [#47986](https://github.com/ClickHouse/ClickHouse/pull/47986) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Optimize one nullable key aggregate performance. [#45772](https://github.com/ClickHouse/ClickHouse/pull/45772) ([LiuNeng](https://github.com/liuneng1994)).
|
||||||
|
* Implemented lowercase `tokenbf_v1` index utilization for `hasTokenOrNull`, `hasTokenCaseInsensitive` and `hasTokenCaseInsensitiveOrNull`. [#46252](https://github.com/ClickHouse/ClickHouse/pull/46252) ([ltrk2](https://github.com/ltrk2)).
|
||||||
|
* Optimize functions `position` and `LIKE` by searching the first two chars using SIMD. [#46289](https://github.com/ClickHouse/ClickHouse/pull/46289) ([Jiebin Sun](https://github.com/jiebinn)).
|
||||||
|
* Optimize queries from the `system.detached_parts`, which could be significantly large. Added several sources with respect to the block size limitation; in each block, an IO thread pool is used to calculate the part size, i.e. to make syscalls in parallel. [#46624](https://github.com/ClickHouse/ClickHouse/pull/46624) ([Sema Checherinda](https://github.com/CheSema)).
|
||||||
|
* Increase the default value of `max_replicated_merges_in_queue` for ReplicatedMergeTree tables from 16 to 1000. It allows faster background merge operation on clusters with a very large number of replicas, such as clusters with shared storage in ClickHouse Cloud. [#47050](https://github.com/ClickHouse/ClickHouse/pull/47050) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Updated `clickhouse-copier` to use `GROUP BY` instead of `DISTINCT` to get the list of partitions. For large tables, this reduced the select time from over 500s to under 1s. [#47386](https://github.com/ClickHouse/ClickHouse/pull/47386) ([Clayton McClure](https://github.com/cmcclure-twilio)).
|
||||||
|
* Fix performance degradation in `ASOF JOIN`. [#47544](https://github.com/ClickHouse/ClickHouse/pull/47544) ([Ongkong](https://github.com/ongkong)).
|
||||||
|
* Even more batching in Keeper. Improve performance by avoiding breaking batches on read requests. [#47978](https://github.com/ClickHouse/ClickHouse/pull/47978) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Allow PREWHERE for Merge with different DEFAULT expressions for columns. [#46831](https://github.com/ClickHouse/ClickHouse/pull/46831) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
|
||||||
|
#### Experimental Feature
|
||||||
|
* Parallel replicas: Improved the overall performance by better utilizing the local replica, and forbid the reading with parallel replicas from non-replicated MergeTree by default. [#47858](https://github.com/ClickHouse/ClickHouse/pull/47858) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||||
|
* Support filter push down to left table for JOIN with `Join`, `Dictionary` and `EmbeddedRocksDB` tables if the experimental Analyzer is enabled. [#47280](https://github.com/ClickHouse/ClickHouse/pull/47280) ([Maksim Kita](https://github.com/kitaisreal)).
|
||||||
|
* Now ReplicatedMergeTree with zero copy replication has less load to Keeper. [#47676](https://github.com/ClickHouse/ClickHouse/pull/47676) ([alesapin](https://github.com/alesapin)).
|
||||||
|
* Fix create materialized view with MaterializedPostgreSQL [#40807](https://github.com/ClickHouse/ClickHouse/pull/40807) ([Maksim Buren](https://github.com/maks-buren630501)).
|
||||||
|
|
||||||
|
#### Improvement
|
||||||
|
* Enable `input_format_json_ignore_unknown_keys_in_named_tuple` by default. [#46742](https://github.com/ClickHouse/ClickHouse/pull/46742) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Allow errors to be ignored while pushing to MATERIALIZED VIEW (add new setting `materialized_views_ignore_errors`, by default to `false`, but it is set to `true` for flushing logs to `system.*_log` tables unconditionally). [#46658](https://github.com/ClickHouse/ClickHouse/pull/46658) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Track the file queue of distributed sends in memory. [#45491](https://github.com/ClickHouse/ClickHouse/pull/45491) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Now `X-ClickHouse-Query-Id` and `X-ClickHouse-Timezone` headers are added to responses in all queries via HTTP protocol. Previously it was done only for `SELECT` queries. [#46364](https://github.com/ClickHouse/ClickHouse/pull/46364) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* External tables from `MongoDB`: support for connection to a replica set via a URI with a host:port enum and support for the readPreference option in MongoDB dictionaries. Example URI: mongodb://db0.example.com:27017,db1.example.com:27017,db2.example.com:27017/?replicaSet=myRepl&readPreference=primary. [#46524](https://github.com/ClickHouse/ClickHouse/pull/46524) ([artem-yadr](https://github.com/artem-yadr)).
|
||||||
|
* This improvement should be invisible for users. Re-implement projection analysis on top of query plan. Added setting `query_plan_optimize_projection=1` to switch between old and new version. Fixes [#44963](https://github.com/ClickHouse/ClickHouse/issues/44963). [#46537](https://github.com/ClickHouse/ClickHouse/pull/46537) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Use Parquet format v2 instead of v1 in output format by default. Add setting `output_format_parquet_version` to control parquet version, possible values `1.0`, `2.4`, `2.6`, `2.latest` (default). [#46617](https://github.com/ClickHouse/ClickHouse/pull/46617) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* It is now possible to use the new configuration syntax to configure Kafka topics with periods (`.`) in their name. [#46752](https://github.com/ClickHouse/ClickHouse/pull/46752) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Fix heuristics that check hyperscan patterns for problematic repeats. [#46819](https://github.com/ClickHouse/ClickHouse/pull/46819) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Don't report ZK node exists to system.errors when a block was created concurrently by a different replica. [#46820](https://github.com/ClickHouse/ClickHouse/pull/46820) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Increase the limit for opened files in `clickhouse-local`. It will be able to read from `web` tables on servers with a huge number of CPU cores. Do not back off reading from the URL table engine in case of too many opened files. This closes [#46852](https://github.com/ClickHouse/ClickHouse/issues/46852). [#46853](https://github.com/ClickHouse/ClickHouse/pull/46853) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Exceptions thrown when numbers cannot be parsed now have an easier-to-read exception message. [#46917](https://github.com/ClickHouse/ClickHouse/pull/46917) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Added update `system.backups` after every processed task to track the progress of backups. [#46989](https://github.com/ClickHouse/ClickHouse/pull/46989) ([Aleksandr Musorin](https://github.com/AVMusorin)).
|
||||||
|
* Allow types conversion in Native input format. Add settings `input_format_native_allow_types_conversion` that controls it (enabled by default). [#46990](https://github.com/ClickHouse/ClickHouse/pull/46990) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Allow IPv4 in the `range` function to generate IP ranges. [#46995](https://github.com/ClickHouse/ClickHouse/pull/46995) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Improve exception message when it's impossible to move a part from one volume/disk to another. [#47032](https://github.com/ClickHouse/ClickHouse/pull/47032) ([alesapin](https://github.com/alesapin)).
|
||||||
|
* Support `Bool` type in `JSONType` function. Previously `Null` type was mistakenly returned for bool values. [#47046](https://github.com/ClickHouse/ClickHouse/pull/47046) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Use `_request_body` parameter to configure predefined HTTP queries. [#47086](https://github.com/ClickHouse/ClickHouse/pull/47086) ([Constantine Peresypkin](https://github.com/pkit)).
|
||||||
|
* Automatic indentation in the built-in UI SQL editor when Enter is pressed. [#47113](https://github.com/ClickHouse/ClickHouse/pull/47113) ([Alexey Korepanov](https://github.com/alexkorep)).
|
||||||
|
* Self-extraction with 'sudo' will attempt to set uid and gid of extracted files to running user. [#47116](https://github.com/ClickHouse/ClickHouse/pull/47116) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Previously, the `repeat` function's second argument only accepted an unsigned integer type, which meant it could not accept values such as -1. This behavior differed from that of the Spark function. In this update, the repeat function has been modified to match the behavior of the Spark function. It now accepts the same types of inputs, including negative integers. Extensive testing has been performed to verify the correctness of the updated implementation. [#47134](https://github.com/ClickHouse/ClickHouse/pull/47134) ([KevinyhZou](https://github.com/KevinyhZou)). Note: the changelog entry was rewritten by ChatGPT.
|
||||||
|
* Remove `::__1` part from stacktraces. Display `std::basic_string<char, ...` as `String` in stacktraces. [#47171](https://github.com/ClickHouse/ClickHouse/pull/47171) ([Mike Kot](https://github.com/myrrc)).
|
||||||
|
* Reimplement interserver mode to avoid replay attacks (note, that change is backward compatible with older servers). [#47213](https://github.com/ClickHouse/ClickHouse/pull/47213) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Improve recognition of regular expression groups and refine the regexp_tree dictionary. [#47218](https://github.com/ClickHouse/ClickHouse/pull/47218) ([Han Fei](https://github.com/hanfei1991)).
|
||||||
|
* Keeper improvement: Add new 4LW `clrs` to clean resources used by Keeper (e.g. release unused memory). [#47256](https://github.com/ClickHouse/ClickHouse/pull/47256) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Add optional arguments to codecs `DoubleDelta(bytes_size)`, `Gorilla(bytes_size)`, `FPC(level, float_size)`, this allows using these codecs without column type in `clickhouse-compressor`. Fix possible aborts and arithmetic errors in `clickhouse-compressor` with these codecs. Fixes: https://github.com/ClickHouse/ClickHouse/discussions/47262. [#47271](https://github.com/ClickHouse/ClickHouse/pull/47271) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add support for big int types to the `runningDifference` function. Closes [#47194](https://github.com/ClickHouse/ClickHouse/issues/47194). [#47322](https://github.com/ClickHouse/ClickHouse/pull/47322) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Add an expiration window for S3 credentials that have an expiration time to avoid `ExpiredToken` errors in some edge cases. It can be controlled with `expiration_window_seconds` config, the default is 120 seconds. [#47423](https://github.com/ClickHouse/ClickHouse/pull/47423) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Support Decimals and Date32 in `Avro` format. [#47434](https://github.com/ClickHouse/ClickHouse/pull/47434) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Do not start the server if an interrupted conversion from `Ordinary` to `Atomic` was detected, print a better error message with troubleshooting instructions. [#47487](https://github.com/ClickHouse/ClickHouse/pull/47487) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Add a new column `kind` to the `system.opentelemetry_span_log`. This column holds the value of [SpanKind](https://opentelemetry.io/docs/reference/specification/trace/api/#spankind) defined in OpenTelemtry. [#47499](https://github.com/ClickHouse/ClickHouse/pull/47499) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* Allow reading/writing nested arrays in `Protobuf` format with only the root field name as column name. Previously column name should've contained all nested field names (like `a.b.c Array(Array(Array(UInt32)))`, now you can use just `a Array(Array(Array(UInt32)))`. [#47650](https://github.com/ClickHouse/ClickHouse/pull/47650) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Added an optional `STRICT` modifier for `SYSTEM SYNC REPLICA` which makes the query wait for the replication queue to become empty (just like it worked before https://github.com/ClickHouse/ClickHouse/pull/45648). [#47659](https://github.com/ClickHouse/ClickHouse/pull/47659) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Improve the naming of some OpenTelemetry span logs. [#47667](https://github.com/ClickHouse/ClickHouse/pull/47667) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* Prevent using too long chains of aggregate function combinators (they can lead to slow queries in the analysis stage). This closes [#47715](https://github.com/ClickHouse/ClickHouse/issues/47715). [#47716](https://github.com/ClickHouse/ClickHouse/pull/47716) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Support for subquery in parameterized views; resolves [#46741](https://github.com/ClickHouse/ClickHouse/issues/46741) [#47725](https://github.com/ClickHouse/ClickHouse/pull/47725) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Fix memory leak in MySQL integration (reproduces with `connection_auto_close=1`). [#47732](https://github.com/ClickHouse/ClickHouse/pull/47732) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Improved error handling in the code related to Decimal parameters, resulting in more informative error messages. Previously, when incorrect Decimal parameters were supplied, the error message generated was unclear or unhelpful. With this update, the error message printed has been fixed to provide more detailed and useful information, making it easier to identify and correct issues related to Decimal parameters. [#47812](https://github.com/ClickHouse/ClickHouse/pull/47812) ([Yu Feng](https://github.com/Vigor-jpg)). Note: this changelog entry is rewritten by ChatGPT.
|
||||||
|
* The parameter `exact_rows_before_limit` is used to make `rows_before_limit_at_least` is designed to accurately reflect the number of rows returned before the limit is reached. This pull request addresses issues encountered when the query involves distributed processing across multiple shards or sorting operations. Prior to this update, these scenarios were not functioning as intended. [#47874](https://github.com/ClickHouse/ClickHouse/pull/47874) ([Amos Bird](https://github.com/amosbird)).
|
||||||
|
* ThreadPools metrics introspection. [#47880](https://github.com/ClickHouse/ClickHouse/pull/47880) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Add `WriteBufferFromS3Microseconds` and `WriteBufferFromS3RequestsErrors` profile events. [#47885](https://github.com/ClickHouse/ClickHouse/pull/47885) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Add `--link` and `--noninteractive` (`-y`) options to ClickHouse install. Closes [#47750](https://github.com/ClickHouse/ClickHouse/issues/47750). [#47887](https://github.com/ClickHouse/ClickHouse/pull/47887) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Fixed `UNKNOWN_TABLE` exception when attaching to a materialized view that has dependent tables that are not available. This might be useful when trying to restore state from a backup. [#47975](https://github.com/ClickHouse/ClickHouse/pull/47975) ([MikhailBurdukov](https://github.com/MikhailBurdukov)).
|
||||||
|
* Fix case when the (optional) path is not added to an encrypted disk configuration. [#47981](https://github.com/ClickHouse/ClickHouse/pull/47981) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Support for CTE in parameterized views Implementation: Updated to allow query parameters while evaluating scalar subqueries. [#48065](https://github.com/ClickHouse/ClickHouse/pull/48065) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Support big integers `(U)Int128/(U)Int256`, `Map` with any key type and `DateTime64` with any precision (not only 3 and 6). [#48119](https://github.com/ClickHouse/ClickHouse/pull/48119) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Allow skipping errors related to unknown enum values in row input formats. [#48133](https://github.com/ClickHouse/ClickHouse/pull/48133) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
|
||||||
|
#### Build/Testing/Packaging Improvement
|
||||||
|
* ClickHouse now builds with `C++23`. [#47424](https://github.com/ClickHouse/ClickHouse/pull/47424) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Fuzz `EXPLAIN` queries in the AST Fuzzer. [#47803](https://github.com/ClickHouse/ClickHouse/pull/47803) [#47852](https://github.com/ClickHouse/ClickHouse/pull/47852) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Split stress test and the automated backward compatibility check (now Upgrade check). [#44879](https://github.com/ClickHouse/ClickHouse/pull/44879) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Updated the Ubuntu Image for Docker to calm down some bogus security reports. [#46784](https://github.com/ClickHouse/ClickHouse/pull/46784) ([Julio Jimenez](https://github.com/juliojimenez)). Please note that ClickHouse has no dependencies and does not require Docker.
|
||||||
|
* Adds a prompt to allow the removal of an existing `clickhouse` download when using "curl | sh" download of ClickHouse. Prompt is "ClickHouse binary clickhouse already exists. Overwrite? \[y/N\]". [#46859](https://github.com/ClickHouse/ClickHouse/pull/46859) ([Dan Roscigno](https://github.com/DanRoscigno)).
|
||||||
|
* Fix error during server startup on old distros (e.g. Amazon Linux 2) and on ARM that glibc 2.28 symbols are not found. [#47008](https://github.com/ClickHouse/ClickHouse/pull/47008) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Prepare for clang 16. [#47027](https://github.com/ClickHouse/ClickHouse/pull/47027) ([Amos Bird](https://github.com/amosbird)).
|
||||||
|
* Added a CI check which ensures ClickHouse can run with an old glibc on ARM. [#47063](https://github.com/ClickHouse/ClickHouse/pull/47063) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Add a style check to prevent incorrect usage of the `NDEBUG` macro. [#47699](https://github.com/ClickHouse/ClickHouse/pull/47699) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Speed up the build a little. [#47714](https://github.com/ClickHouse/ClickHouse/pull/47714) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Bump `vectorscan` to 5.4.9. [#47955](https://github.com/ClickHouse/ClickHouse/pull/47955) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Add a unit test to assert Apache Arrow's fatal logging does not abort. It covers the changes in [ClickHouse/arrow#16](https://github.com/ClickHouse/arrow/pull/16). [#47958](https://github.com/ClickHouse/ClickHouse/pull/47958) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||||
|
* Restore the ability of native macOS debug server build to start. [#48050](https://github.com/ClickHouse/ClickHouse/pull/48050) ([Robert Schulze](https://github.com/rschu1ze)). Note: this change is only relevant for development, as the ClickHouse official builds are done with cross-compilation.
|
||||||
|
|
||||||
|
#### Bug Fix (user-visible misbehavior in an official stable release)
|
||||||
|
* Fix formats parser resetting, test processing bad messages in `Kafka` [#45693](https://github.com/ClickHouse/ClickHouse/pull/45693) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix data size calculation in Keeper [#46086](https://github.com/ClickHouse/ClickHouse/pull/46086) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fixed a bug in automatic retries of `DROP TABLE` query with `ReplicatedMergeTree` tables and `Atomic` databases. In rare cases it could lead to `Can't get data for node /zk_path/log_pointer` and `The specified key does not exist` errors if the ZooKeeper session expired during DROP and a new replicated table with the same path in ZooKeeper was created in parallel. [#46384](https://github.com/ClickHouse/ClickHouse/pull/46384) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Fix incorrect alias recursion while normalizing queries that prevented some queries to run. [#46609](https://github.com/ClickHouse/ClickHouse/pull/46609) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Fix IPv4/IPv6 serialization/deserialization in binary formats [#46616](https://github.com/ClickHouse/ClickHouse/pull/46616) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* ActionsDAG: do not change result of `and` during optimization [#46653](https://github.com/ClickHouse/ClickHouse/pull/46653) ([Salvatore Mesoraca](https://github.com/aiven-sal)).
|
||||||
|
* Improve query cancellation when a client dies [#46681](https://github.com/ClickHouse/ClickHouse/pull/46681) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Fix arithmetic operations in aggregate optimization [#46705](https://github.com/ClickHouse/ClickHouse/pull/46705) ([Duc Canh Le](https://github.com/canhld94)).
|
||||||
|
* Fix possible `clickhouse-local`'s abort on JSONEachRow schema inference [#46731](https://github.com/ClickHouse/ClickHouse/pull/46731) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix changing an expired role [#46772](https://github.com/ClickHouse/ClickHouse/pull/46772) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Fix combined PREWHERE column accumulation from multiple steps [#46785](https://github.com/ClickHouse/ClickHouse/pull/46785) ([Alexander Gololobov](https://github.com/davenger)).
|
||||||
|
* Use initial range for fetching file size in HTTP read buffer. Without this change, some remote files couldn't be processed. [#46824](https://github.com/ClickHouse/ClickHouse/pull/46824) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix the incorrect progress bar while using the URL tables [#46830](https://github.com/ClickHouse/ClickHouse/pull/46830) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix MSan report in `maxIntersections` function [#46847](https://github.com/ClickHouse/ClickHouse/pull/46847) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix a bug in `Map` data type [#46856](https://github.com/ClickHouse/ClickHouse/pull/46856) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix wrong results of some LIKE searches when the LIKE pattern contains quoted non-quotable characters [#46875](https://github.com/ClickHouse/ClickHouse/pull/46875) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Fix - WITH FILL would produce abort when the Filling Transform processing an empty block [#46897](https://github.com/ClickHouse/ClickHouse/pull/46897) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Fix date and int inference from string in JSON [#46972](https://github.com/ClickHouse/ClickHouse/pull/46972) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix bug in zero-copy replication disk choice during fetch [#47010](https://github.com/ClickHouse/ClickHouse/pull/47010) ([alesapin](https://github.com/alesapin)).
|
||||||
|
* Fix a typo in systemd service definition [#47051](https://github.com/ClickHouse/ClickHouse/pull/47051) ([Palash Goel](https://github.com/palash-goel)).
|
||||||
|
* Fix the NOT_IMPLEMENTED error with CROSS JOIN and algorithm = auto [#47068](https://github.com/ClickHouse/ClickHouse/pull/47068) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Fix the problem that the 'ReplicatedMergeTree' table failed to insert two similar data when the 'part_type' is configured as 'InMemory' mode (experimental feature). [#47121](https://github.com/ClickHouse/ClickHouse/pull/47121) ([liding1992](https://github.com/liding1992)).
|
||||||
|
* External dictionaries / library-bridge: Fix error "unknown library method 'extDict_libClone'" [#47136](https://github.com/ClickHouse/ClickHouse/pull/47136) ([alex filatov](https://github.com/phil-88)).
|
||||||
|
* Fix race condition in a grace hash join with limit [#47153](https://github.com/ClickHouse/ClickHouse/pull/47153) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Fix concrete columns PREWHERE support [#47154](https://github.com/ClickHouse/ClickHouse/pull/47154) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix possible deadlock in Query Status [#47161](https://github.com/ClickHouse/ClickHouse/pull/47161) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Forbid insert select for the same `Join` table, as it leads to a deadlock [#47260](https://github.com/ClickHouse/ClickHouse/pull/47260) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Skip merged partitions for `min_age_to_force_merge_seconds` merges [#47303](https://github.com/ClickHouse/ClickHouse/pull/47303) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Modify find_first_symbols, so it works as expected for find_first_not_symbols [#47304](https://github.com/ClickHouse/ClickHouse/pull/47304) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||||
|
* Fix big numbers inference in CSV [#47410](https://github.com/ClickHouse/ClickHouse/pull/47410) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Disable logical expression optimizer for expression with aliases. [#47451](https://github.com/ClickHouse/ClickHouse/pull/47451) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Fix error in `decodeURLComponent` [#47457](https://github.com/ClickHouse/ClickHouse/pull/47457) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix explain graph with projection [#47473](https://github.com/ClickHouse/ClickHouse/pull/47473) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Fix query parameters [#47488](https://github.com/ClickHouse/ClickHouse/pull/47488) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Parameterized view: a bug fix. [#47495](https://github.com/ClickHouse/ClickHouse/pull/47495) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Fuzzer of data formats, and the corresponding fixes. [#47519](https://github.com/ClickHouse/ClickHouse/pull/47519) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix monotonicity check for `DateTime64` [#47526](https://github.com/ClickHouse/ClickHouse/pull/47526) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix "block structure mismatch" for a Nullable LowCardinality column [#47537](https://github.com/ClickHouse/ClickHouse/pull/47537) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Proper fix for a bug in Apache Parquet [#45878](https://github.com/ClickHouse/ClickHouse/issues/45878) [#47538](https://github.com/ClickHouse/ClickHouse/pull/47538) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix `BSONEachRow` parallel parsing when document size is invalid [#47540](https://github.com/ClickHouse/ClickHouse/pull/47540) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Preserve error in `system.distribution_queue` on `SYSTEM FLUSH DISTRIBUTED` [#47541](https://github.com/ClickHouse/ClickHouse/pull/47541) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Check for duplicate column in `BSONEachRow` format [#47609](https://github.com/ClickHouse/ClickHouse/pull/47609) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix wait for zero copy lock during move [#47631](https://github.com/ClickHouse/ClickHouse/pull/47631) ([alesapin](https://github.com/alesapin)).
|
||||||
|
* Fix aggregation by partitions [#47634](https://github.com/ClickHouse/ClickHouse/pull/47634) ([Nikita Taranov](https://github.com/nickitat)).
|
||||||
|
* Fix bug in tuple as array serialization in `BSONEachRow` format [#47690](https://github.com/ClickHouse/ClickHouse/pull/47690) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix crash in `polygonsSymDifferenceCartesian` [#47702](https://github.com/ClickHouse/ClickHouse/pull/47702) ([pufit](https://github.com/pufit)).
|
||||||
|
* Fix reading from storage `File` compressed files with `zlib` and `gzip` compression [#47796](https://github.com/ClickHouse/ClickHouse/pull/47796) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Improve empty query detection for PostgreSQL (for pgx golang driver) [#47854](https://github.com/ClickHouse/ClickHouse/pull/47854) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix DateTime monotonicity check for LowCardinality types [#47860](https://github.com/ClickHouse/ClickHouse/pull/47860) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Use restore_threads (not backup_threads) for RESTORE ASYNC [#47861](https://github.com/ClickHouse/ClickHouse/pull/47861) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix DROP COLUMN with ReplicatedMergeTree containing projections [#47883](https://github.com/ClickHouse/ClickHouse/pull/47883) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix for Replicated database recovery [#47901](https://github.com/ClickHouse/ClickHouse/pull/47901) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Hotfix for too verbose warnings in HTTP [#47903](https://github.com/ClickHouse/ClickHouse/pull/47903) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Fix "Field value too long" in `catboostEvaluate` [#47970](https://github.com/ClickHouse/ClickHouse/pull/47970) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Fix [#36971](https://github.com/ClickHouse/ClickHouse/issues/36971): Watchdog: exit with non-zero code if child process exits [#47973](https://github.com/ClickHouse/ClickHouse/pull/47973) ([Коренберг Марк](https://github.com/socketpair)).
|
||||||
|
* Fix for "index file `cidx` is unexpectedly long" [#48010](https://github.com/ClickHouse/ClickHouse/pull/48010) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Fix MaterializedPostgreSQL query to get attributes (replica-identity) [#48015](https://github.com/ClickHouse/ClickHouse/pull/48015) ([Solomatov Sergei](https://github.com/solomatovs)).
|
||||||
|
* parseDateTime(): Fix UB (signed integer overflow) [#48019](https://github.com/ClickHouse/ClickHouse/pull/48019) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Use unique names for Records in Avro to avoid reusing its schema [#48057](https://github.com/ClickHouse/ClickHouse/pull/48057) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Correctly set TCP/HTTP socket timeouts in Keeper [#48108](https://github.com/ClickHouse/ClickHouse/pull/48108) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Fix possible member call on null pointer in `Avro` format [#48184](https://github.com/ClickHouse/ClickHouse/pull/48184) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
|
||||||
|
### <a id="232"></a> ClickHouse release 23.2, 2023-02-23
|
||||||
|
|
||||||
|
#### Backward Incompatible Change
|
||||||
|
* Extend function "toDayOfWeek()" (alias: "DAYOFWEEK") with a mode argument that encodes whether the week starts on Monday or Sunday and whether counting starts at 0 or 1. For consistency with other date time functions, the mode argument was inserted between the time and the time zone arguments. This breaks existing usage of the (previously undocumented) 2-argument syntax "toDayOfWeek(time, time_zone)". A fix is to rewrite the function into "toDayOfWeek(time, 0, time_zone)". [#45233](https://github.com/ClickHouse/ClickHouse/pull/45233) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Rename setting `max_query_cache_size` to `filesystem_cache_max_download_size`. [#45614](https://github.com/ClickHouse/ClickHouse/pull/45614) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* The `default` user will not have permissions for access type `SHOW NAMED COLLECTION` by default (e.g. `default` user will no longer be able to grant ALL to other users as it was before, therefore this PR is backward incompatible). [#46010](https://github.com/ClickHouse/ClickHouse/pull/46010) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* If the SETTINGS clause is specified before the FORMAT clause, the settings will be applied to formatting as well. [#46003](https://github.com/ClickHouse/ClickHouse/pull/46003) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Remove support for setting `materialized_postgresql_allow_automatic_update` (which was by default turned off). [#46106](https://github.com/ClickHouse/ClickHouse/pull/46106) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Slightly improve performance of `countDigits` on realistic datasets. This closed [#44518](https://github.com/ClickHouse/ClickHouse/issues/44518). In previous versions, `countDigits(0)` returned `0`; now it returns `1`, which is more correct, and follows the existing documentation. [#46187](https://github.com/ClickHouse/ClickHouse/pull/46187) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Disallow creation of new columns compressed by a combination of codecs "Delta" or "DoubleDelta" followed by codecs "Gorilla" or "FPC". This can be bypassed using setting "allow_suspicious_codecs = true". [#45652](https://github.com/ClickHouse/ClickHouse/pull/45652) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
|
||||||
|
#### New Feature
|
||||||
|
* Add `StorageIceberg` and table function `iceberg` to access iceberg table store on S3. [#45384](https://github.com/ClickHouse/ClickHouse/pull/45384) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Allow configuring storage as `SETTINGS disk = '<disk_name>'` (instead of `storage_policy`) and with explicit disk creation `SETTINGS disk = disk(type=s3, ...)`. [#41976](https://github.com/ClickHouse/ClickHouse/pull/41976) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Expose `ProfileEvents` counters in `system.part_log`. [#38614](https://github.com/ClickHouse/ClickHouse/pull/38614) ([Bharat Nallan](https://github.com/bharatnc)).
|
||||||
|
* Enrichment of the existing `ReplacingMergeTree` engine to allow duplicate the insertion. It leverages the power of both `ReplacingMergeTree` and `CollapsingMergeTree` in one MergeTree engine. Deleted data are not returned when queried, but not removed from disk neither. [#41005](https://github.com/ClickHouse/ClickHouse/pull/41005) ([youennL-cs](https://github.com/youennL-cs)).
|
||||||
|
* Add `generateULID` function. Closes [#36536](https://github.com/ClickHouse/ClickHouse/issues/36536). [#44662](https://github.com/ClickHouse/ClickHouse/pull/44662) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Add `corrMatrix` aggregate function, calculating each two columns. In addition, since Aggregatefunctions `covarSamp` and `covarPop` are similar to `corr`, I add `covarSampMatrix`, `covarPopMatrix` by the way. @alexey-milovidov closes [#44587](https://github.com/ClickHouse/ClickHouse/issues/44587). [#44680](https://github.com/ClickHouse/ClickHouse/pull/44680) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||||
|
* Introduce arrayShuffle function for random array permutations. [#45271](https://github.com/ClickHouse/ClickHouse/pull/45271) ([Joanna Hulboj](https://github.com/jh0x)).
|
||||||
|
* Support types `FIXED_SIZE_BINARY` type in Arrow, `FIXED_LENGTH_BYTE_ARRAY` in `Parquet` and match them to `FixedString`. Add settings `output_format_parquet_fixed_string_as_fixed_byte_array/output_format_arrow_fixed_string_as_fixed_byte_array` to control default output type for FixedString. Closes [#45326](https://github.com/ClickHouse/ClickHouse/issues/45326). [#45340](https://github.com/ClickHouse/ClickHouse/pull/45340) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Add a new column `last_exception_time` to system.replication_queue. [#45457](https://github.com/ClickHouse/ClickHouse/pull/45457) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* Add two new functions which allow for user-defined keys/seeds with SipHash{64,128}. [#45513](https://github.com/ClickHouse/ClickHouse/pull/45513) ([Salvatore Mesoraca](https://github.com/aiven-sal)).
|
||||||
|
* Allow a three-argument version for table function `format`. close [#45808](https://github.com/ClickHouse/ClickHouse/issues/45808). [#45873](https://github.com/ClickHouse/ClickHouse/pull/45873) ([FFFFFFFHHHHHHH](https://github.com/FFFFFFFHHHHHHH)).
|
||||||
|
* Add `JodaTime` format support for 'x','w','S'. Refer to https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html. [#46073](https://github.com/ClickHouse/ClickHouse/pull/46073) ([zk_kiger](https://github.com/zk-kiger)).
|
||||||
|
* Support window function `ntile`. ([lgbo](https://github.com/lgbo-ustc)).
|
||||||
|
* Add setting `final` to implicitly apply the `FINAL` modifier to every table. [#40945](https://github.com/ClickHouse/ClickHouse/pull/40945) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||||
|
* Added `arrayPartialSort` and `arrayPartialReverseSort` functions. [#46296](https://github.com/ClickHouse/ClickHouse/pull/46296) ([Joanna Hulboj](https://github.com/jh0x)).
|
||||||
|
* The new http parameter `client_protocol_version` allows setting a client protocol version for HTTP responses using the Native format. [#40397](https://github.com/ClickHouse/ClickHouse/issues/40397). [#46360](https://github.com/ClickHouse/ClickHouse/pull/46360) ([Geoff Genz](https://github.com/genzgd)).
|
||||||
|
* Add new function `regexpExtract`, like spark function `REGEXP_EXTRACT` for compatibility. It is similar to the existing function `extract`. [#46469](https://github.com/ClickHouse/ClickHouse/pull/46469) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Add new function `JSONArrayLength`, which returns the number of elements in the outermost JSON array. The function returns NULL if the input JSON string is invalid. [#46631](https://github.com/ClickHouse/ClickHouse/pull/46631) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
|
||||||
|
#### Performance Improvement
|
||||||
|
* The introduced logic works if PREWHERE condition is a conjunction of multiple conditions (cond1 AND cond2 AND ... ). It groups those conditions that require reading the same columns into steps. After each step the corresponding part of the full condition is computed and the result rows might be filtered. This allows to read fewer rows in the next steps thus saving IO bandwidth and doing less computation. This logic is disabled by default for now. It will be enabled by default in one of the future releases once it is known to not have any regressions, so it is highly encouraged to be used for testing. It can be controlled by 2 settings: "enable_multiple_prewhere_read_steps" and "move_all_conditions_to_prewhere". [#46140](https://github.com/ClickHouse/ClickHouse/pull/46140) ([Alexander Gololobov](https://github.com/davenger)).
|
||||||
|
* An option added to aggregate partitions independently if table partition key and group by key are compatible. Controlled by the setting `allow_aggregate_partitions_independently`. Disabled by default because of limited applicability (please refer to the docs). [#45364](https://github.com/ClickHouse/ClickHouse/pull/45364) ([Nikita Taranov](https://github.com/nickitat)).
|
||||||
|
* Allow using Vertical merge algorithm with parts in Compact format. This will allow ClickHouse server to use much less memory for background operations. This closes [#46084](https://github.com/ClickHouse/ClickHouse/issues/46084). [#45681](https://github.com/ClickHouse/ClickHouse/pull/45681) [#46282](https://github.com/ClickHouse/ClickHouse/pull/46282) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Optimize `Parquet` reader by using batch reader. [#45878](https://github.com/ClickHouse/ClickHouse/pull/45878) ([LiuNeng](https://github.com/liuneng1994)).
|
||||||
|
* Add new `local_filesystem_read_method` method `io_uring` based on the asynchronous Linux [io_uring](https://kernel.dk/io_uring.pdf) subsystem, improving read performance almost universally compared to the default `pread` method. [#38456](https://github.com/ClickHouse/ClickHouse/pull/38456) ([Saulius Valatka](https://github.com/sauliusvl)).
|
||||||
|
* Rewrite aggregate functions with `if` expression as argument when logically equivalent. For example, `avg(if(cond, col, null))` can be rewritten to avgIf(cond, col). It is helpful in performance. [#44730](https://github.com/ClickHouse/ClickHouse/pull/44730) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Improve lower/upper function performance with avx512 instructions. [#37894](https://github.com/ClickHouse/ClickHouse/pull/37894) ([yaqi-zhao](https://github.com/yaqi-zhao)).
|
||||||
|
* Remove the limitation that on systems with >=32 cores and SMT disabled ClickHouse uses only half of the cores (the case when you disable Hyper Threading in BIOS). [#44973](https://github.com/ClickHouse/ClickHouse/pull/44973) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Improve performance of function `multiIf` by columnar executing, speed up by 2.3x. [#45296](https://github.com/ClickHouse/ClickHouse/pull/45296) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Add fast path for function `position` when the needle is empty. [#45382](https://github.com/ClickHouse/ClickHouse/pull/45382) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Enable `query_plan_remove_redundant_sorting` optimization by default. Optimization implemented in [#45420](https://github.com/ClickHouse/ClickHouse/issues/45420). [#45567](https://github.com/ClickHouse/ClickHouse/pull/45567) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||||
|
* Increased HTTP Transfer Encoding chunk size to improve performance of large queries using the HTTP interface. [#45593](https://github.com/ClickHouse/ClickHouse/pull/45593) ([Geoff Genz](https://github.com/genzgd)).
|
||||||
|
* Fixed performance of short `SELECT` queries that read from tables with large number of `Array`/`Map`/`Nested` columns. [#45630](https://github.com/ClickHouse/ClickHouse/pull/45630) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Improve performance of filtering for big integers and decimal types. [#45949](https://github.com/ClickHouse/ClickHouse/pull/45949) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* This change could effectively reduce the overhead of obtaining the filter from ColumnNullable(UInt8) and improve the overall query performance. To evaluate the impact of this change, we adopted TPC-H benchmark but revised the column types from non-nullable to nullable, and we measured the QPS of its queries as the performance indicator. [#45962](https://github.com/ClickHouse/ClickHouse/pull/45962) ([Zhiguo Zhou](https://github.com/ZhiguoZh)).
|
||||||
|
* Make the `_part` and `_partition_id` virtual column be `LowCardinality(String)` type. Closes [#45964](https://github.com/ClickHouse/ClickHouse/issues/45964). [#45975](https://github.com/ClickHouse/ClickHouse/pull/45975) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Improve the performance of Decimal conversion when the scale does not change. [#46095](https://github.com/ClickHouse/ClickHouse/pull/46095) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Allow to increase prefetching for read data. [#46168](https://github.com/ClickHouse/ClickHouse/pull/46168) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Rewrite `arrayExists(x -> x = 1, arr)` -> `has(arr, 1)`, which improve performance by 1.34x. [#46188](https://github.com/ClickHouse/ClickHouse/pull/46188) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Fix too big memory usage for vertical merges on non-remote disk. Respect `max_insert_delayed_streams_for_parallel_write` for the remote disk. [#46275](https://github.com/ClickHouse/ClickHouse/pull/46275) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Update zstd to v1.5.4. It has some minor improvements in performance and compression ratio. If you run replicas with different versions of ClickHouse you may see reasonable error messages `Data after merge/mutation is not byte-identical to data on another replicas.` with explanation. These messages are Ok and you should not worry. [#46280](https://github.com/ClickHouse/ClickHouse/pull/46280) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Fix performance degradation caused by [#39737](https://github.com/ClickHouse/ClickHouse/issues/39737). [#46309](https://github.com/ClickHouse/ClickHouse/pull/46309) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* The `replicas_status` handle will answer quickly even in case of a large replication queue. [#46310](https://github.com/ClickHouse/ClickHouse/pull/46310) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Add avx512 support for aggregate function `sum`, function unary arithmetic, function comparison. [#37870](https://github.com/ClickHouse/ClickHouse/pull/37870) ([zhao zhou](https://github.com/zzachimed)).
|
||||||
|
* Rewrote the code around marks distribution and the overall coordination of the reading in order to achieve the maximum performance improvement. This closes [#34527](https://github.com/ClickHouse/ClickHouse/issues/34527). [#43772](https://github.com/ClickHouse/ClickHouse/pull/43772) ([Nikita Mikhaylov](https://github.com/nikitamikhaylov)).
|
||||||
|
* Remove redundant DISTINCT clauses in query (subqueries). Implemented on top of query plan. It does similar optimization as `optimize_duplicate_order_by_and_distinct` regarding DISTINCT clauses. Can be enabled via `query_plan_remove_redundant_distinct` setting. Related to [#42648](https://github.com/ClickHouse/ClickHouse/issues/42648). [#44176](https://github.com/ClickHouse/ClickHouse/pull/44176) ([Igor Nikonov](https://github.com/devcrafter)).
|
||||||
|
* A few query rewrite optimizations: `sumIf(123, cond) -> 123 * countIf(1, cond)`, `sum(if(cond, 123, 0)) -> 123 * countIf(cond)`, `sum(if(cond, 0, 123)) -> 123 * countIf(not(cond))` [#44728](https://github.com/ClickHouse/ClickHouse/pull/44728) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Improved how memory bound merging and aggregation in order on top query plan interact. Previously we fell back to explicit sorting for AIO in some cases when it wasn't actually needed. [#45892](https://github.com/ClickHouse/ClickHouse/pull/45892) ([Nikita Taranov](https://github.com/nickitat)).
|
||||||
|
* Concurrent merges are scheduled using round-robin by default to ensure fair and starvation-free operation. Previously in heavily overloaded shards, big merges could possibly be starved by smaller merges due to the use of strict priority scheduling. Added `background_merges_mutations_scheduling_policy` server config option to select scheduling algorithm (`round_robin` or `shortest_task_first`). [#46247](https://github.com/ClickHouse/ClickHouse/pull/46247) ([Sergei Trifonov](https://github.com/serxa)).
|
||||||
|
|
||||||
|
#### Improvement
|
||||||
|
* Enable retries for INSERT by default in case of ZooKeeper session loss. We already use it in production. [#46308](https://github.com/ClickHouse/ClickHouse/pull/46308) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Add ability to ignore unknown keys in JSON object for named tuples (`input_format_json_ignore_unknown_keys_in_named_tuple`). [#45678](https://github.com/ClickHouse/ClickHouse/pull/45678) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Support optimizing the `where` clause with sorting key expression move to `prewhere` for query with `final`. [#38893](https://github.com/ClickHouse/ClickHouse/issues/38893). [#38950](https://github.com/ClickHouse/ClickHouse/pull/38950) ([hexiaoting](https://github.com/hexiaoting)).
|
||||||
|
* Add new metrics for backups: num_processed_files and processed_files_size described actual number of processed files. [#42244](https://github.com/ClickHouse/ClickHouse/pull/42244) ([Aleksandr](https://github.com/AVMusorin)).
|
||||||
|
* Added retries on interserver DNS errors. [#43179](https://github.com/ClickHouse/ClickHouse/pull/43179) ([Anton Kozlov](https://github.com/tonickkozlov)).
|
||||||
|
* Keeper improvement: try preallocating space on the disk to avoid undefined out-of-space issues. Introduce setting `max_log_file_size` for the maximum size of Keeper's Raft log files. [#44370](https://github.com/ClickHouse/ClickHouse/pull/44370) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Optimize behavior for a replica delay api logic in case the replica is read-only. [#45148](https://github.com/ClickHouse/ClickHouse/pull/45148) ([mateng915](https://github.com/mateng0915)).
|
||||||
|
* Ask for the password in clickhouse-client interactively in a case when the empty password is wrong. Closes [#46702](https://github.com/ClickHouse/ClickHouse/issues/46702). [#46730](https://github.com/ClickHouse/ClickHouse/pull/46730) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Mark `Gorilla` compression on columns of non-Float* type as suspicious. [#45376](https://github.com/ClickHouse/ClickHouse/pull/45376) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Show replica name that is executing a merge in the `postpone_reason` column. [#45458](https://github.com/ClickHouse/ClickHouse/pull/45458) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* Save exception stack trace in part_log. [#45459](https://github.com/ClickHouse/ClickHouse/pull/45459) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* The `regexp_tree` dictionary is polished and now it is compatible with https://github.com/ua-parser/uap-core. [#45631](https://github.com/ClickHouse/ClickHouse/pull/45631) ([Han Fei](https://github.com/hanfei1991)).
|
||||||
|
* Updated checking of `SYSTEM SYNC REPLICA`, resolves [#45508](https://github.com/ClickHouse/ClickHouse/issues/45508) [#45648](https://github.com/ClickHouse/ClickHouse/pull/45648) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Rename setting `replication_alter_partitions_sync` to `alter_sync`. [#45659](https://github.com/ClickHouse/ClickHouse/pull/45659) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* The `generateRandom` table function and the engine now support `LowCardinality` data types. This is useful for testing, for example you can write `INSERT INTO table SELECT * FROM generateRandom() LIMIT 1000`. This is needed to debug [#45590](https://github.com/ClickHouse/ClickHouse/issues/45590). [#45661](https://github.com/ClickHouse/ClickHouse/pull/45661) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* The experimental query result cache now provides more modular configuration settings. [#45679](https://github.com/ClickHouse/ClickHouse/pull/45679) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Renamed "query result cache" to "query cache". [#45682](https://github.com/ClickHouse/ClickHouse/pull/45682) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* add `SYSTEM SYNC FILE CACHE` command. It will do the `sync` syscall. [#8921](https://github.com/ClickHouse/ClickHouse/issues/8921). [#45685](https://github.com/ClickHouse/ClickHouse/pull/45685) ([DR](https://github.com/freedomDR)).
|
||||||
|
* Add a new S3 setting `allow_head_object_request`. This PR makes usage of `GetObjectAttributes` request instead of `HeadObject` introduced in https://github.com/ClickHouse/ClickHouse/pull/45288 optional (and disabled by default). [#45701](https://github.com/ClickHouse/ClickHouse/pull/45701) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Add ability to override connection settings based on connection names (that said that now you can forget about storing password for each connection, you can simply put everything into `~/.clickhouse-client/config.xml` and even use different history files for them, which can be also useful). [#45715](https://github.com/ClickHouse/ClickHouse/pull/45715) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Arrow format: support the duration type. Closes [#45669](https://github.com/ClickHouse/ClickHouse/issues/45669). [#45750](https://github.com/ClickHouse/ClickHouse/pull/45750) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Extend the logging in the Query Cache to improve investigations of the caching behavior. [#45751](https://github.com/ClickHouse/ClickHouse/pull/45751) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* The query cache's server-level settings are now reconfigurable at runtime. [#45758](https://github.com/ClickHouse/ClickHouse/pull/45758) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Hide password in logs when a table function's arguments are specified with a named collection. [#45774](https://github.com/ClickHouse/ClickHouse/pull/45774) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Improve internal S3 client to correctly deduce regions and redirections for different types of URLs. [#45783](https://github.com/ClickHouse/ClickHouse/pull/45783) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Add support for Map, IPv4 and IPv6 types in generateRandom. Mostly useful for testing. [#45785](https://github.com/ClickHouse/ClickHouse/pull/45785) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Support empty/notEmpty for IP types. [#45799](https://github.com/ClickHouse/ClickHouse/pull/45799) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* The column `num_processed_files` was split into two columns: `num_files` (for BACKUP) and `files_read` (for RESTORE). The column `processed_files_size` was split into two columns: `total_size` (for BACKUP) and `bytes_read` (for RESTORE). [#45800](https://github.com/ClickHouse/ClickHouse/pull/45800) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Add support for `SHOW ENGINES` query for MySQL compatibility. [#45859](https://github.com/ClickHouse/ClickHouse/pull/45859) ([Filatenkov Artur](https://github.com/FArthur-cmd)).
|
||||||
|
* Improved how the obfuscator deals with queries. [#45867](https://github.com/ClickHouse/ClickHouse/pull/45867) ([Raúl Marín](https://github.com/Algunenano)).
|
||||||
|
* Improve behaviour of conversion into Date for boundary value 65535 (2149-06-06). [#46042](https://github.com/ClickHouse/ClickHouse/pull/46042) [#45914](https://github.com/ClickHouse/ClickHouse/pull/45914) ([Joanna Hulboj](https://github.com/jh0x)).
|
||||||
|
* Add setting `check_referential_table_dependencies` to check referential dependencies on `DROP TABLE`. This PR solves [#38326](https://github.com/ClickHouse/ClickHouse/issues/38326). [#45936](https://github.com/ClickHouse/ClickHouse/pull/45936) ([Vitaly Baranov](https://github.com/vitlibar)).
|
||||||
|
* Fix `tupleElement` to return `Null` when having `Null` argument. Closes [#45894](https://github.com/ClickHouse/ClickHouse/issues/45894). [#45952](https://github.com/ClickHouse/ClickHouse/pull/45952) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Throw an error on no files satisfying the S3 wildcard. Closes [#45587](https://github.com/ClickHouse/ClickHouse/issues/45587). [#45957](https://github.com/ClickHouse/ClickHouse/pull/45957) ([chen](https://github.com/xiedeyantu)).
|
||||||
|
* Use cluster state data to check concurrent backup/restore. [#45982](https://github.com/ClickHouse/ClickHouse/pull/45982) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* ClickHouse Client: Use "exact" matching for fuzzy search, which has correct case ignorance and more appropriate algorithm for matching SQL queries. [#46000](https://github.com/ClickHouse/ClickHouse/pull/46000) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Forbid wrong create View syntax `CREATE View X TO Y AS SELECT`. Closes [#4331](https://github.com/ClickHouse/ClickHouse/issues/4331). [#46043](https://github.com/ClickHouse/ClickHouse/pull/46043) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Storage `Log` family support setting the `storage_policy`. Closes [#43421](https://github.com/ClickHouse/ClickHouse/issues/43421). [#46044](https://github.com/ClickHouse/ClickHouse/pull/46044) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Improve `JSONColumns` format when the result is empty. Closes [#46024](https://github.com/ClickHouse/ClickHouse/issues/46024). [#46053](https://github.com/ClickHouse/ClickHouse/pull/46053) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Add reference implementation for SipHash128. [#46065](https://github.com/ClickHouse/ClickHouse/pull/46065) ([Salvatore Mesoraca](https://github.com/aiven-sal)).
|
||||||
|
* Add a new metric to record allocations times and bytes using mmap. [#46068](https://github.com/ClickHouse/ClickHouse/pull/46068) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Currently for functions like `leftPad`, `rightPad`, `leftPadUTF8`, `rightPadUTF8`, the second argument `length` must be UInt8|16|32|64|128|256. Which is too strict for clickhouse users, besides, it is not consistent with other similar functions like `arrayResize`, `substring` and so on. [#46103](https://github.com/ClickHouse/ClickHouse/pull/46103) ([李扬](https://github.com/taiyang-li)).
|
||||||
|
* Fix assertion in the `welchTTest` function in debug build when the resulting statistics is NaN. Unified the behavior with other similar functions. Change the behavior of `studentTTest` to return NaN instead of throwing an exception because the previous behavior was inconvenient. This closes [#41176](https://github.com/ClickHouse/ClickHouse/issues/41176) This closes [#42162](https://github.com/ClickHouse/ClickHouse/issues/42162). [#46141](https://github.com/ClickHouse/ClickHouse/pull/46141) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* More convenient usage of big integers and ORDER BY WITH FILL. Allow using plain integers for start and end points in WITH FILL when ORDER BY big (128-bit and 256-bit) integers. Fix the wrong result for big integers with negative start or end points. This closes [#16733](https://github.com/ClickHouse/ClickHouse/issues/16733). [#46152](https://github.com/ClickHouse/ClickHouse/pull/46152) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Add `parts`, `active_parts` and `total_marks` columns to `system.tables` on [issue](https://github.com/ClickHouse/ClickHouse/issues/44336). [#46161](https://github.com/ClickHouse/ClickHouse/pull/46161) ([attack204](https://github.com/attack204)).
|
||||||
|
* Functions "multi[Fuzzy]Match(Any|AnyIndex|AllIndices}" now reject regexes which will likely evaluate very slowly in vectorscan. [#46167](https://github.com/ClickHouse/ClickHouse/pull/46167) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* When `insert_null_as_default` is enabled and column doesn't have defined default value, the default of column type will be used. Also this PR fixes using default values on nulls in case of LowCardinality columns. [#46171](https://github.com/ClickHouse/ClickHouse/pull/46171) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Prefer explicitly defined access keys for S3 clients. If `use_environment_credentials` is set to `true`, and the user has provided the access key through query or config, they will be used instead of the ones from the environment variable. [#46191](https://github.com/ClickHouse/ClickHouse/pull/46191) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Add an alias "DATE_FORMAT()" for function "formatDateTime()" to improve compatibility with MySQL's SQL dialect, extend function `formatDateTime` with substitutions "a", "b", "c", "h", "i", "k", "l" "r", "s", "W". ### Documentation entry for user-facing changes User-readable short description: `DATE_FORMAT` is an alias of `formatDateTime`. Formats a Time according to the given Format string. Format is a constant expression, so you cannot have multiple formats for a single result column. (Provide link to [formatDateTime](https://clickhouse.com/docs/en/sql-reference/functions/date-time-functions/#formatdatetime)). [#46302](https://github.com/ClickHouse/ClickHouse/pull/46302) ([Jake Bamrah](https://github.com/JakeBamrah)).
|
||||||
|
* Add `ProfileEvents` and `CurrentMetrics` about the callback tasks for parallel replicas (`s3Cluster` and `MergeTree` tables). [#46313](https://github.com/ClickHouse/ClickHouse/pull/46313) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Add support for `DELETE` and `UPDATE` for tables using `KeeperMap` storage engine. [#46330](https://github.com/ClickHouse/ClickHouse/pull/46330) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* Allow writing RENAME queries with query parameters. Resolves [#45778](https://github.com/ClickHouse/ClickHouse/issues/45778). [#46407](https://github.com/ClickHouse/ClickHouse/pull/46407) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Fix parameterized SELECT queries with REPLACE transformer. Resolves [#33002](https://github.com/ClickHouse/ClickHouse/issues/33002). [#46420](https://github.com/ClickHouse/ClickHouse/pull/46420) ([Nikolay Degterinsky](https://github.com/evillique)).
|
||||||
|
* Exclude the internal database used for temporary/external tables from the calculation of asynchronous metric "NumberOfDatabases". This makes the behavior consistent with system table "system.databases". [#46435](https://github.com/ClickHouse/ClickHouse/pull/46435) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Added `last_exception_time` column into distribution_queue table. [#46564](https://github.com/ClickHouse/ClickHouse/pull/46564) ([Aleksandr](https://github.com/AVMusorin)).
|
||||||
|
* Support for IN clause with parameter in parameterized views. [#46583](https://github.com/ClickHouse/ClickHouse/pull/46583) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
* Do not load named collections on server startup (load them on first access instead). [#46607](https://github.com/ClickHouse/ClickHouse/pull/46607) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
|
||||||
|
|
||||||
|
#### Build/Testing/Packaging Improvement
|
||||||
|
* Introduce GWP-ASan implemented by the LLVM runtime. This closes [#27039](https://github.com/ClickHouse/ClickHouse/issues/27039). [#45226](https://github.com/ClickHouse/ClickHouse/pull/45226) ([Han Fei](https://github.com/hanfei1991)).
|
||||||
|
* We want to make our tests less stable and more flaky: add randomization for merge tree settings in tests. [#38983](https://github.com/ClickHouse/ClickHouse/pull/38983) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Enable the HDFS support in PowerPC and which helps to fixes the following functional tests 02113_hdfs_assert.sh, 02244_hdfs_cluster.sql and 02368_cancel_write_into_hdfs.sh. [#44949](https://github.com/ClickHouse/ClickHouse/pull/44949) ([MeenaRenganathan22](https://github.com/MeenaRenganathan22)).
|
||||||
|
* Add systemd.service file for clickhouse-keeper. Fixes [#44293](https://github.com/ClickHouse/ClickHouse/issues/44293). [#45568](https://github.com/ClickHouse/ClickHouse/pull/45568) ([Mikhail f. Shiryaev](https://github.com/Felixoid)).
|
||||||
|
* ClickHouse's fork of poco was moved from "contrib/" to "base/poco/". [#46075](https://github.com/ClickHouse/ClickHouse/pull/46075) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Add an option for `clickhouse-watchdog` to restart the child process. This does not make a lot of use. [#46312](https://github.com/ClickHouse/ClickHouse/pull/46312) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* If the environment variable `CLICKHOUSE_DOCKER_RESTART_ON_EXIT` is set to 1, the Docker container will run `clickhouse-server` as a child instead of the first process, and restart it when it exited. [#46391](https://github.com/ClickHouse/ClickHouse/pull/46391) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix Systemd service file. [#46461](https://github.com/ClickHouse/ClickHouse/pull/46461) ([SuperDJY](https://github.com/cmsxbc)).
|
||||||
|
* Raised the minimum Clang version needed to build ClickHouse from 12 to 15. [#46710](https://github.com/ClickHouse/ClickHouse/pull/46710) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Upgrade Intel QPL from v0.3.0 to v1.0.0 2. Build libaccel-config and link it statically to QPL library instead of dynamically. [#45809](https://github.com/ClickHouse/ClickHouse/pull/45809) ([jasperzhu](https://github.com/jinjunzh)).
|
||||||
|
|
||||||
|
|
||||||
|
#### Bug Fix (user-visible misbehavior in official stable release)
|
||||||
|
|
||||||
|
* Flush data exactly by `rabbitmq_flush_interval_ms` or by `rabbitmq_max_block_size` in `StorageRabbitMQ`. Closes [#42389](https://github.com/ClickHouse/ClickHouse/issues/42389). Closes [#45160](https://github.com/ClickHouse/ClickHouse/issues/45160). [#44404](https://github.com/ClickHouse/ClickHouse/pull/44404) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Use PODArray to render in sparkBar function, so we can control the memory usage. Close [#44467](https://github.com/ClickHouse/ClickHouse/issues/44467). [#44489](https://github.com/ClickHouse/ClickHouse/pull/44489) ([Duc Canh Le](https://github.com/canhld94)).
|
||||||
|
* Fix functions (quantilesExactExclusive, quantilesExactInclusive) return unsorted array element. [#45379](https://github.com/ClickHouse/ClickHouse/pull/45379) ([wujunfu](https://github.com/wujunfu)).
|
||||||
|
* Fix uncaught exception in HTTPHandler when open telemetry is enabled. [#45456](https://github.com/ClickHouse/ClickHouse/pull/45456) ([Frank Chen](https://github.com/FrankChen021)).
|
||||||
|
* Don't infer Dates from 8 digit numbers. It could lead to wrong data to be read. [#45581](https://github.com/ClickHouse/ClickHouse/pull/45581) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fixes to correctly use `odbc_bridge_use_connection_pooling` setting. [#45591](https://github.com/ClickHouse/ClickHouse/pull/45591) ([Bharat Nallan](https://github.com/bharatnc)).
|
||||||
|
* When the callback in the cache is called, it is possible that this cache is destructed. To keep it safe, we capture members by value. It's also safe for task schedule because it will be deactivated before storage is destroyed. Resolve [#45548](https://github.com/ClickHouse/ClickHouse/issues/45548). [#45601](https://github.com/ClickHouse/ClickHouse/pull/45601) ([Han Fei](https://github.com/hanfei1991)).
|
||||||
|
* Fix data corruption when codecs Delta or DoubleDelta are combined with codec Gorilla. [#45615](https://github.com/ClickHouse/ClickHouse/pull/45615) ([Robert Schulze](https://github.com/rschu1ze)).
|
||||||
|
* Correctly check types when using N-gram bloom filter index to avoid invalid reads. [#45617](https://github.com/ClickHouse/ClickHouse/pull/45617) ([Antonio Andelic](https://github.com/antonio2368)).
|
||||||
|
* A couple of segfaults have been reported around `c-ares`. They were introduced in my previous pull requests. I have fixed them with the help of Alexander Tokmakov. [#45629](https://github.com/ClickHouse/ClickHouse/pull/45629) ([Arthur Passos](https://github.com/arthurpassos)).
|
||||||
|
* Fix key description when encountering duplicate primary keys. This can happen in projections. See [#45590](https://github.com/ClickHouse/ClickHouse/issues/45590) for details. [#45686](https://github.com/ClickHouse/ClickHouse/pull/45686) ([Amos Bird](https://github.com/amosbird)).
|
||||||
|
* Set compression method and level for backup Closes [#45690](https://github.com/ClickHouse/ClickHouse/issues/45690). [#45737](https://github.com/ClickHouse/ClickHouse/pull/45737) ([Pradeep Chhetri](https://github.com/chhetripradeep)).
|
||||||
|
* Should use `select_query_typed.limitByOffset()` instead of `select_query_typed.limitOffset()`. [#45817](https://github.com/ClickHouse/ClickHouse/pull/45817) ([刘陶峰](https://github.com/taofengliu)).
|
||||||
|
* When use experimental analyzer, queries like `SELECT number FROM numbers(100) LIMIT 10 OFFSET 10;` get wrong results (empty result for this sql). That is caused by an unnecessary offset step added by planner. [#45822](https://github.com/ClickHouse/ClickHouse/pull/45822) ([刘陶峰](https://github.com/taofengliu)).
|
||||||
|
* Backward compatibility - allow implicit narrowing conversion from UInt64 to IPv4 - required for "INSERT ... VALUES ..." expression. [#45865](https://github.com/ClickHouse/ClickHouse/pull/45865) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Bugfix IPv6 parser for mixed ip4 address with missed first octet (like `::.1.2.3`). [#45871](https://github.com/ClickHouse/ClickHouse/pull/45871) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Add the `query_kind` column to the `system.processes` table and the `SHOW PROCESSLIST` query. Remove duplicate code. It fixes a bug: the global configuration parameter `max_concurrent_select_queries` was not respected to queries with `INTERSECT` or `EXCEPT` chains. [#45872](https://github.com/ClickHouse/ClickHouse/pull/45872) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* Fix crash in a function `stochasticLinearRegression`. Found by WingFuzz. [#45985](https://github.com/ClickHouse/ClickHouse/pull/45985) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Fix crash in `SELECT` queries with `INTERSECT` and `EXCEPT` modifiers that read data from tables with enabled sparse columns (controlled by setting `ratio_of_defaults_for_sparse_serialization`). [#45987](https://github.com/ClickHouse/ClickHouse/pull/45987) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Fix read in order optimization for DESC sorting with FINAL, close [#45815](https://github.com/ClickHouse/ClickHouse/issues/45815). [#46009](https://github.com/ClickHouse/ClickHouse/pull/46009) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Fix reading of non existing nested columns with multiple level in compact parts. [#46045](https://github.com/ClickHouse/ClickHouse/pull/46045) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix elapsed column in system.processes (10x error). [#46047](https://github.com/ClickHouse/ClickHouse/pull/46047) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Follow-up fix for Replace domain IP types (IPv4, IPv6) with native https://github.com/ClickHouse/ClickHouse/pull/43221. [#46087](https://github.com/ClickHouse/ClickHouse/pull/46087) ([Yakov Olkhovskiy](https://github.com/yakov-olkhovskiy)).
|
||||||
|
* Fix environment variable substitution in the configuration when a parameter already has a value. This closes [#46131](https://github.com/ClickHouse/ClickHouse/issues/46131). This closes [#9547](https://github.com/ClickHouse/ClickHouse/issues/9547). [#46144](https://github.com/ClickHouse/ClickHouse/pull/46144) ([pufit](https://github.com/pufit)).
|
||||||
|
* Fix incorrect predicate push down with grouping sets. Closes [#45947](https://github.com/ClickHouse/ClickHouse/issues/45947). [#46151](https://github.com/ClickHouse/ClickHouse/pull/46151) ([flynn](https://github.com/ucasfl)).
|
||||||
|
* Fix possible pipeline stuck error on `fulls_sorting_join` with constant keys. [#46175](https://github.com/ClickHouse/ClickHouse/pull/46175) ([Vladimir C](https://github.com/vdimir)).
|
||||||
|
* Never rewrite tuple functions as literals during formatting to avoid incorrect results. [#46232](https://github.com/ClickHouse/ClickHouse/pull/46232) ([Salvatore Mesoraca](https://github.com/aiven-sal)).
|
||||||
|
* Fix possible out of bounds error while reading LowCardinality(Nullable) in Arrow format. [#46270](https://github.com/ClickHouse/ClickHouse/pull/46270) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix `SYSTEM UNFREEZE` queries failing with the exception `CANNOT_PARSE_INPUT_ASSERTION_FAILED`. [#46325](https://github.com/ClickHouse/ClickHouse/pull/46325) ([Aleksei Filatov](https://github.com/aalexfvk)).
|
||||||
|
* Fix possible crash which can be caused by an integer overflow while deserializing aggregating state of a function that stores HashTable. [#46349](https://github.com/ClickHouse/ClickHouse/pull/46349) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Fix possible `LOGICAL_ERROR` in asynchronous inserts with invalid data sent in format `VALUES`. [#46350](https://github.com/ClickHouse/ClickHouse/pull/46350) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Fixed a LOGICAL_ERROR on an attempt to execute `ALTER ... MOVE PART ... TO TABLE`. This type of query was never actually supported. [#46359](https://github.com/ClickHouse/ClickHouse/pull/46359) ([Alexander Tokmakov](https://github.com/tavplubix)).
|
||||||
|
* Fix s3Cluster schema inference in parallel distributed insert select when `parallel_distributed_insert_select` is enabled. [#46381](https://github.com/ClickHouse/ClickHouse/pull/46381) ([Kruglov Pavel](https://github.com/Avogar)).
|
||||||
|
* Fix queries like `ALTER TABLE ... UPDATE nested.arr1 = nested.arr2 ...`, where `arr1` and `arr2` are fields of the same `Nested` column. [#46387](https://github.com/ClickHouse/ClickHouse/pull/46387) ([Anton Popov](https://github.com/CurtizJ)).
|
||||||
|
* Scheduler may fail to schedule a task. If it happens, the whole MulityPartUpload should be aborted and `UploadHelper` must wait for already scheduled tasks. [#46451](https://github.com/ClickHouse/ClickHouse/pull/46451) ([Dmitry Novik](https://github.com/novikd)).
|
||||||
|
* Fix PREWHERE for Merge with different default types (fixes some `NOT_FOUND_COLUMN_IN_BLOCK` when the default type for the column differs, also allow `PREWHERE` when the type of column is the same across tables, and prohibit it, only if it differs). [#46454](https://github.com/ClickHouse/ClickHouse/pull/46454) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Fix a crash that could happen when constant values are used in `ORDER BY`. Fixes [#46466](https://github.com/ClickHouse/ClickHouse/issues/46466). [#46493](https://github.com/ClickHouse/ClickHouse/pull/46493) ([Nikolai Kochetov](https://github.com/KochetovNicolai)).
|
||||||
|
* Do not throw exception if `disk` setting was specified on query level, but `storage_policy` was specified in config merge tree settings section. `disk` will override setting from config. [#46533](https://github.com/ClickHouse/ClickHouse/pull/46533) ([Kseniia Sumarokova](https://github.com/kssenii)).
|
||||||
|
* Fix an invalid processing of constant `LowCardinality` argument in function `arrayMap`. This bug could lead to a segfault in release, and logical error `Bad cast` in debug build. [#46569](https://github.com/ClickHouse/ClickHouse/pull/46569) ([Alexey Milovidov](https://github.com/alexey-milovidov)).
|
||||||
|
* fixes [#46557](https://github.com/ClickHouse/ClickHouse/issues/46557). [#46611](https://github.com/ClickHouse/ClickHouse/pull/46611) ([Alexander Gololobov](https://github.com/davenger)).
|
||||||
|
* Fix endless restarts of clickhouse-server systemd unit if server cannot start within 1m30sec (Disable timeout logic for starting clickhouse-server from systemd service). [#46613](https://github.com/ClickHouse/ClickHouse/pull/46613) ([Azat Khuzhin](https://github.com/azat)).
|
||||||
|
* Allocated during asynchronous inserts memory buffers were deallocated in the global context and MemoryTracker counters for corresponding user and query were not updated correctly. That led to false positive OOM exceptions. [#46622](https://github.com/ClickHouse/ClickHouse/pull/46622) ([Dmitry Novik](https://github.com/novikd)).
|
||||||
|
* Updated to not clear on_expression from table_join as its used by future analyze runs resolves [#45185](https://github.com/ClickHouse/ClickHouse/issues/45185). [#46487](https://github.com/ClickHouse/ClickHouse/pull/46487) ([SmitaRKulkarni](https://github.com/SmitaRKulkarni)).
|
||||||
|
|
||||||
|
|
||||||
### <a id="231"></a> ClickHouse release 23.1, 2023-01-26
|
### <a id="231"></a> ClickHouse release 23.1, 2023-01-26
|
||||||
|
|
||||||
### ClickHouse release 23.1
|
### ClickHouse release 23.1
|
||||||
|
186
CMakeLists.txt
186
CMakeLists.txt
@ -57,8 +57,8 @@ if (ENABLE_CHECK_HEAVY_BUILDS)
|
|||||||
# set CPU time limit to 1000 seconds
|
# set CPU time limit to 1000 seconds
|
||||||
set (RLIMIT_CPU 1000)
|
set (RLIMIT_CPU 1000)
|
||||||
|
|
||||||
# gcc10/gcc10/clang -fsanitize=memory is too heavy
|
# -fsanitize=memory is too heavy
|
||||||
if (SANITIZE STREQUAL "memory" OR COMPILER_GCC)
|
if (SANITIZE STREQUAL "memory")
|
||||||
set (RLIMIT_DATA 10000000000) # 10G
|
set (RLIMIT_DATA 10000000000) # 10G
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -102,6 +102,17 @@ if (ENABLE_FUZZING)
|
|||||||
set (ENABLE_PROTOBUF 1)
|
set (ENABLE_PROTOBUF 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option (ENABLE_WOBOQ_CODEBROWSER "Build for woboq codebrowser" OFF)
|
||||||
|
|
||||||
|
if (ENABLE_WOBOQ_CODEBROWSER)
|
||||||
|
set (ENABLE_EMBEDDED_COMPILER 0)
|
||||||
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-poison-system-directories")
|
||||||
|
# woboq codebrowser uses clang tooling, and they could add default system
|
||||||
|
# clang includes, and later clang will warn for those added by itself
|
||||||
|
# includes.
|
||||||
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-poison-system-directories")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Global libraries
|
# Global libraries
|
||||||
# See:
|
# See:
|
||||||
# - default_libs.cmake
|
# - default_libs.cmake
|
||||||
@ -121,6 +132,7 @@ if (ENABLE_COLORED_BUILD AND CMAKE_GENERATOR STREQUAL "Ninja")
|
|||||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
|
||||||
# ... such manually setting of flags can be removed once CMake supports a variable to
|
# ... such manually setting of flags can be removed once CMake supports a variable to
|
||||||
# activate colors in *all* build systems: https://gitlab.kitware.com/cmake/cmake/-/issues/15502
|
# activate colors in *all* build systems: https://gitlab.kitware.com/cmake/cmake/-/issues/15502
|
||||||
|
# --> available since CMake 3.24: https://stackoverflow.com/a/73349744
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
include (cmake/check_flags.cmake)
|
include (cmake/check_flags.cmake)
|
||||||
@ -134,24 +146,15 @@ if (COMPILER_CLANG)
|
|||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -gdwarf-aranges")
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -gdwarf-aranges")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (HAS_USE_CTOR_HOMING)
|
# See https://blog.llvm.org/posts/2021-04-05-constructor-homing-for-debug-info/
|
||||||
# For more info see https://blog.llvm.org/posts/2021-04-05-constructor-homing-for-debug-info/
|
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO")
|
||||||
if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG" OR CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -fuse-ctor-homing")
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Xclang -fuse-ctor-homing")
|
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Xclang -fuse-ctor-homing")
|
||||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Xclang -fuse-ctor-homing")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
no_warning(enum-constexpr-conversion) # breaks Protobuf in clang-16
|
no_warning(enum-constexpr-conversion) # breaks Protobuf in clang-16
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# If compiler has support for -Wreserved-identifier. It is difficult to detect by clang version,
|
|
||||||
# because there are two different branches of clang: clang and AppleClang.
|
|
||||||
# (AppleClang is not supported by ClickHouse, but some developers have misfortune to use it).
|
|
||||||
if (HAS_RESERVED_IDENTIFIER)
|
|
||||||
add_compile_definitions (HAS_RESERVED_IDENTIFIER)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
option(ENABLE_TESTS "Provide unit_test_dbms target with Google.Test unit tests" ON)
|
option(ENABLE_TESTS "Provide unit_test_dbms target with Google.Test unit tests" ON)
|
||||||
option(ENABLE_EXAMPLES "Build all example programs in 'examples' subdirectories" OFF)
|
option(ENABLE_EXAMPLES "Build all example programs in 'examples' subdirectories" OFF)
|
||||||
option(ENABLE_BENCHMARKS "Build all benchmark programs in 'benchmarks' subdirectories" OFF)
|
option(ENABLE_BENCHMARKS "Build all benchmark programs in 'benchmarks' subdirectories" OFF)
|
||||||
@ -178,32 +181,11 @@ else ()
|
|||||||
set(NO_WHOLE_ARCHIVE --no-whole-archive)
|
set(NO_WHOLE_ARCHIVE --no-whole-archive)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option(ENABLE_CURL_BUILD "Enable curl, azure, sentry build on by default except MacOS." ON)
|
|
||||||
if (OS_DARWIN)
|
|
||||||
# Disable the curl, azure, senry build on MacOS
|
|
||||||
set (ENABLE_CURL_BUILD OFF)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Ignored if `lld` is used
|
|
||||||
option(ADD_GDB_INDEX_FOR_GOLD "Add .gdb-index to resulting binaries for gold linker.")
|
|
||||||
|
|
||||||
if (NOT CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE")
|
if (NOT CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE")
|
||||||
# Can be lld or ld-lld or lld-13 or /path/to/lld.
|
# Can be lld or ld-lld or lld-13 or /path/to/lld.
|
||||||
if (LINKER_NAME MATCHES "lld" AND OS_LINUX)
|
if (LINKER_NAME MATCHES "lld")
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gdb-index")
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gdb-index")
|
||||||
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gdb-index")
|
|
||||||
message (STATUS "Adding .gdb-index via --gdb-index linker option.")
|
message (STATUS "Adding .gdb-index via --gdb-index linker option.")
|
||||||
# we use another tool for gdb-index, because gold linker removes section .debug_aranges, which used inside clickhouse stacktraces
|
|
||||||
# http://sourceware-org.1504.n7.nabble.com/gold-No-debug-aranges-section-when-linking-with-gdb-index-td540965.html#a556932
|
|
||||||
elseif (LINKER_NAME MATCHES "gold$" AND ADD_GDB_INDEX_FOR_GOLD)
|
|
||||||
find_program (GDB_ADD_INDEX_EXE NAMES "gdb-add-index" DOC "Path to gdb-add-index executable")
|
|
||||||
if (NOT GDB_ADD_INDEX_EXE)
|
|
||||||
set (USE_GDB_ADD_INDEX 0)
|
|
||||||
message (WARNING "Cannot add gdb index to binaries, because gold linker is used, but gdb-add-index executable not found.")
|
|
||||||
else()
|
|
||||||
set (USE_GDB_ADD_INDEX 1)
|
|
||||||
message (STATUS "gdb-add-index found: ${GDB_ADD_INDEX_EXE}")
|
|
||||||
endif()
|
|
||||||
endif ()
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -235,7 +217,7 @@ endif ()
|
|||||||
|
|
||||||
# Create BuildID when using lld. For other linkers it is created by default.
|
# Create BuildID when using lld. For other linkers it is created by default.
|
||||||
# (NOTE: LINKER_NAME can be either path or name, and in different variants)
|
# (NOTE: LINKER_NAME can be either path or name, and in different variants)
|
||||||
if (LINKER_NAME MATCHES "lld" AND OS_LINUX)
|
if (LINKER_NAME MATCHES "lld")
|
||||||
# SHA1 is not cryptographically secure but it is the best what lld is offering.
|
# SHA1 is not cryptographically secure but it is the best what lld is offering.
|
||||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=sha1")
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=sha1")
|
||||||
endif ()
|
endif ()
|
||||||
@ -288,8 +270,8 @@ endif ()
|
|||||||
option (ENABLE_BUILD_PATH_MAPPING "Enable remapping of file source paths in debug info, predefined preprocessor macros, and __builtin_FILE(). It's used to generate reproducible builds. See https://reproducible-builds.org/docs/build-path" ${ENABLE_BUILD_PATH_MAPPING_DEFAULT})
|
option (ENABLE_BUILD_PATH_MAPPING "Enable remapping of file source paths in debug info, predefined preprocessor macros, and __builtin_FILE(). It's used to generate reproducible builds. See https://reproducible-builds.org/docs/build-path" ${ENABLE_BUILD_PATH_MAPPING_DEFAULT})
|
||||||
|
|
||||||
if (ENABLE_BUILD_PATH_MAPPING)
|
if (ENABLE_BUILD_PATH_MAPPING)
|
||||||
set (COMPILER_FLAGS "${COMPILER_FLAGS} -ffile-prefix-map=${CMAKE_SOURCE_DIR}=.")
|
set (COMPILER_FLAGS "${COMPILER_FLAGS} -ffile-prefix-map=${PROJECT_SOURCE_DIR}=.")
|
||||||
set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -ffile-prefix-map=${CMAKE_SOURCE_DIR}=.")
|
set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -ffile-prefix-map=${PROJECT_SOURCE_DIR}=.")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option (ENABLE_BUILD_PROFILING "Enable profiling of build time" OFF)
|
option (ENABLE_BUILD_PROFILING "Enable profiling of build time" OFF)
|
||||||
@ -301,59 +283,39 @@ if (ENABLE_BUILD_PROFILING)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set (CMAKE_CXX_STANDARD 20)
|
set (CMAKE_CXX_STANDARD 23)
|
||||||
set (CMAKE_CXX_EXTENSIONS ON) # Same as gnu++2a (ON) vs c++2a (OFF): https://cmake.org/cmake/help/latest/prop_tgt/CXX_EXTENSIONS.html
|
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
set (CMAKE_C_STANDARD 11)
|
set (CMAKE_C_STANDARD 11)
|
||||||
set (CMAKE_C_EXTENSIONS ON)
|
set (CMAKE_C_EXTENSIONS ON) # required by most contribs written in C
|
||||||
set (CMAKE_C_STANDARD_REQUIRED ON)
|
set (CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
if (COMPILER_GCC OR COMPILER_CLANG)
|
# Compiler-specific coverage flags e.g. -fcoverage-mapping
|
||||||
# Enable C++14 sized global deallocation functions. It should be enabled by setting -std=c++14 but I'm not sure.
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# falign-functions=32 prevents from random performance regressions with the code change. Thus, providing more stable
|
|
||||||
# benchmarks.
|
|
||||||
if (COMPILER_GCC OR COMPILER_CLANG)
|
|
||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -falign-functions=32")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (ARCH_AMD64)
|
|
||||||
# align branches within a 32-Byte boundary to avoid the potential performance loss when code layout change,
|
|
||||||
# which makes benchmark results more stable.
|
|
||||||
set(BRANCHES_WITHIN_32B_BOUNDARIES "-mbranches-within-32B-boundaries")
|
|
||||||
if (COMPILER_GCC)
|
|
||||||
# gcc is in assembler, need to add "-Wa," prefix
|
|
||||||
set(BRANCHES_WITHIN_32B_BOUNDARIES "-Wa,${BRANCHES_WITHIN_32B_BOUNDARIES}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
|
||||||
check_cxx_compiler_flag("${BRANCHES_WITHIN_32B_BOUNDARIES}" HAS_BRANCHES_WITHIN_32B_BOUNDARIES)
|
|
||||||
if (HAS_BRANCHES_WITHIN_32B_BOUNDARIES)
|
|
||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${BRANCHES_WITHIN_32B_BOUNDARIES}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (COMPILER_GCC)
|
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Compiler-specific coverage flags e.g. -fcoverage-mapping for gcc
|
|
||||||
option(WITH_COVERAGE "Profile the resulting binary/binaries" OFF)
|
option(WITH_COVERAGE "Profile the resulting binary/binaries" OFF)
|
||||||
|
|
||||||
if (WITH_COVERAGE AND COMPILER_CLANG)
|
if (COMPILER_CLANG)
|
||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
|
# Enable C++14 sized global deallocation functions. It should be enabled by setting -std=c++14 but I'm not sure.
|
||||||
# If we want to disable coverage for specific translation units
|
# See https://reviews.llvm.org/D112921
|
||||||
set(WITHOUT_COVERAGE "-fno-profile-instr-generate -fno-coverage-mapping")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation")
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WITH_COVERAGE AND COMPILER_GCC)
|
# falign-functions=32 prevents from random performance regressions with the code change. Thus, providing more stable
|
||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fprofile-arcs -ftest-coverage")
|
# benchmarks.
|
||||||
set(COVERAGE_OPTION "-lgcov")
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -falign-functions=32")
|
||||||
set(WITHOUT_COVERAGE "-fno-profile-arcs -fno-test-coverage")
|
|
||||||
endif()
|
if (ARCH_AMD64)
|
||||||
|
# align branches within a 32-Byte boundary to avoid the potential performance loss when code layout change,
|
||||||
|
# which makes benchmark results more stable.
|
||||||
|
set(BRANCHES_WITHIN_32B_BOUNDARIES "-mbranches-within-32B-boundaries")
|
||||||
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} ${BRANCHES_WITHIN_32B_BOUNDARIES}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (WITH_COVERAGE)
|
||||||
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
|
||||||
|
# If we want to disable coverage for specific translation units
|
||||||
|
set(WITHOUT_COVERAGE "-fno-profile-instr-generate -fno-coverage-mapping")
|
||||||
|
endif()
|
||||||
|
endif ()
|
||||||
|
|
||||||
set (COMPILER_FLAGS "${COMPILER_FLAGS}")
|
set (COMPILER_FLAGS "${COMPILER_FLAGS}")
|
||||||
|
|
||||||
@ -391,11 +353,6 @@ if (COMPILER_CLANG)
|
|||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstrict-vtable-pointers")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstrict-vtable-pointers")
|
||||||
|
|
||||||
# Set new experimental pass manager, it's a performance, build time and binary size win.
|
|
||||||
# Can be removed after https://reviews.llvm.org/D66490 merged and released to at least two versions of clang.
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-new-pass-manager")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexperimental-new-pass-manager")
|
|
||||||
|
|
||||||
# We cannot afford to use LTO when compiling unit tests, and it's not enough
|
# We cannot afford to use LTO when compiling unit tests, and it's not enough
|
||||||
# to only supply -fno-lto at the final linking stage. So we disable it
|
# to only supply -fno-lto at the final linking stage. So we disable it
|
||||||
# completely.
|
# completely.
|
||||||
@ -434,15 +391,22 @@ else()
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
option (ENABLE_GWP_ASAN "Enable Gwp-Asan" ON)
|
option (ENABLE_GWP_ASAN "Enable Gwp-Asan" ON)
|
||||||
if (NOT OS_LINUX AND NOT OS_ANDROID)
|
# We use mmap for allocations more heavily in debug builds,
|
||||||
|
# but GWP-ASan also wants to use mmap frequently,
|
||||||
|
# and due to a large number of memory mappings,
|
||||||
|
# it does not work together well.
|
||||||
|
if ((NOT OS_LINUX AND NOT OS_ANDROID) OR (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG"))
|
||||||
set(ENABLE_GWP_ASAN OFF)
|
set(ENABLE_GWP_ASAN OFF)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
option (ENABLE_FIU "Enable Fiu" ON)
|
||||||
|
|
||||||
option(WERROR "Enable -Werror compiler option" ON)
|
option(WERROR "Enable -Werror compiler option" ON)
|
||||||
|
|
||||||
if (WERROR)
|
if (WERROR)
|
||||||
# Don't pollute CMAKE_CXX_FLAGS with -Werror as it will break some CMake checks.
|
# Don't pollute CMAKE_CXX_FLAGS with -Werror as it will break some CMake checks.
|
||||||
# Instead, adopt modern cmake usage requirement.
|
# Instead, adopt modern cmake usage requirement.
|
||||||
|
# TODO: Set CMAKE_COMPILE_WARNING_AS_ERROR (cmake 3.24)
|
||||||
target_compile_options(global-group INTERFACE "-Werror")
|
target_compile_options(global-group INTERFACE "-Werror")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
@ -457,8 +421,11 @@ endif ()
|
|||||||
|
|
||||||
set (CMAKE_POSTFIX_VARIABLE "CMAKE_${CMAKE_BUILD_TYPE_UC}_POSTFIX")
|
set (CMAKE_POSTFIX_VARIABLE "CMAKE_${CMAKE_BUILD_TYPE_UC}_POSTFIX")
|
||||||
|
|
||||||
set (CMAKE_POSITION_INDEPENDENT_CODE OFF)
|
if (NOT SANITIZE)
|
||||||
if (OS_LINUX AND NOT ARCH_AARCH64)
|
set (CMAKE_POSITION_INDEPENDENT_CODE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (OS_LINUX AND NOT (ARCH_AARCH64 OR ARCH_S390X) AND NOT SANITIZE)
|
||||||
# Slightly more efficient code can be generated
|
# Slightly more efficient code can be generated
|
||||||
# It's disabled for ARM because otherwise ClickHouse cannot run on Android.
|
# It's disabled for ARM because otherwise ClickHouse cannot run on Android.
|
||||||
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-pie")
|
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-pie")
|
||||||
@ -476,7 +443,12 @@ enable_testing() # Enable for tests without binary
|
|||||||
|
|
||||||
option(ENABLE_OPENSSL "This option performs a build with OpenSSL. NOTE! This option is insecure and should never be used. By default, ClickHouse uses and only supports BoringSSL" OFF)
|
option(ENABLE_OPENSSL "This option performs a build with OpenSSL. NOTE! This option is insecure and should never be used. By default, ClickHouse uses and only supports BoringSSL" OFF)
|
||||||
|
|
||||||
option(ENABLE_OPENSSL_DYNAMIC "This option removes SSL from ClickHouse and will link to the OpenSSL version supplied by OS." OFF)
|
if (ARCH_S390X)
|
||||||
|
set(ENABLE_OPENSSL_DYNAMIC_DEFAULT ON)
|
||||||
|
else ()
|
||||||
|
set(ENABLE_OPENSSL_DYNAMIC_DEFAULT OFF)
|
||||||
|
endif ()
|
||||||
|
option(ENABLE_OPENSSL_DYNAMIC "This option removes SSL from ClickHouse and will link to the OpenSSL version supplied by OS." ${ENABLE_OPENSSL_DYNAMIC_DEFAULT})
|
||||||
|
|
||||||
# when installing to /usr - place configs to /etc but for /usr/local place to /usr/local/etc
|
# when installing to /usr - place configs to /etc but for /usr/local place to /usr/local/etc
|
||||||
if (CMAKE_INSTALL_PREFIX STREQUAL "/usr")
|
if (CMAKE_INSTALL_PREFIX STREQUAL "/usr")
|
||||||
@ -556,6 +528,26 @@ include (cmake/print_flags.cmake)
|
|||||||
|
|
||||||
if (ENABLE_RUST)
|
if (ENABLE_RUST)
|
||||||
add_subdirectory (rust)
|
add_subdirectory (rust)
|
||||||
|
|
||||||
|
# With LTO Rust adds few symbols with global visiblity, the most common is
|
||||||
|
# rust_eh_personality. And this leads to linking errors because multiple
|
||||||
|
# Rust libraries contains the same symbol.
|
||||||
|
#
|
||||||
|
# If it was shared library, that we could use version script for linker to
|
||||||
|
# hide this symbols, but libraries are static.
|
||||||
|
#
|
||||||
|
# we could in theory compile everything to one library but this will be a
|
||||||
|
# mess
|
||||||
|
#
|
||||||
|
# But this should be OK since CI has lots of other builds that are done
|
||||||
|
# without LTO and it will find multiple definitions if there will be any.
|
||||||
|
#
|
||||||
|
# More information about this behaviour in Rust can be found here
|
||||||
|
# - https://github.com/rust-lang/rust/issues/44322
|
||||||
|
# - https://alanwu.space/post/symbol-hygiene/
|
||||||
|
if (ENABLE_THINLTO)
|
||||||
|
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory (base)
|
add_subdirectory (base)
|
||||||
@ -576,7 +568,7 @@ if (NATIVE_BUILD_TARGETS
|
|||||||
)
|
)
|
||||||
message (STATUS "Building native targets...")
|
message (STATUS "Building native targets...")
|
||||||
|
|
||||||
set (NATIVE_BUILD_DIR "${CMAKE_BINARY_DIR}/native")
|
set (NATIVE_BUILD_DIR "${PROJECT_BINARY_DIR}/native")
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${NATIVE_BUILD_DIR}"
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${NATIVE_BUILD_DIR}"
|
||||||
@ -586,11 +578,11 @@ if (NATIVE_BUILD_TARGETS
|
|||||||
COMMAND ${CMAKE_COMMAND}
|
COMMAND ${CMAKE_COMMAND}
|
||||||
"-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
|
"-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
|
||||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||||
"-DENABLE_CCACHE=${ENABLE_CCACHE}"
|
"-DCOMPILER_CACHE=${COMPILER_CACHE}"
|
||||||
# Avoid overriding .cargo/config.toml with native toolchain.
|
# Avoid overriding .cargo/config.toml with native toolchain.
|
||||||
"-DENABLE_RUST=OFF"
|
"-DENABLE_RUST=OFF"
|
||||||
"-DENABLE_CLICKHOUSE_SELF_EXTRACTING=${ENABLE_CLICKHOUSE_SELF_EXTRACTING}"
|
"-DENABLE_CLICKHOUSE_SELF_EXTRACTING=${ENABLE_CLICKHOUSE_SELF_EXTRACTING}"
|
||||||
${CMAKE_SOURCE_DIR}
|
${PROJECT_SOURCE_DIR}
|
||||||
WORKING_DIRECTORY "${NATIVE_BUILD_DIR}"
|
WORKING_DIRECTORY "${NATIVE_BUILD_DIR}"
|
||||||
COMMAND_ECHO STDOUT)
|
COMMAND_ECHO STDOUT)
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ endif()
|
|||||||
if (NOT "$ENV{CFLAGS}" STREQUAL ""
|
if (NOT "$ENV{CFLAGS}" STREQUAL ""
|
||||||
OR NOT "$ENV{CXXFLAGS}" STREQUAL ""
|
OR NOT "$ENV{CXXFLAGS}" STREQUAL ""
|
||||||
OR NOT "$ENV{LDFLAGS}" STREQUAL ""
|
OR NOT "$ENV{LDFLAGS}" STREQUAL ""
|
||||||
OR CMAKE_C_FLAGS OR CMAKE_CXX_FLAGS OR CMAKE_EXE_LINKER_FLAGS OR CMAKE_SHARED_LINKER_FLAGS OR CMAKE_MODULE_LINKER_FLAGS
|
OR CMAKE_C_FLAGS OR CMAKE_CXX_FLAGS OR CMAKE_EXE_LINKER_FLAGS OR CMAKE_MODULE_LINKER_FLAGS
|
||||||
OR CMAKE_C_FLAGS_INIT OR CMAKE_CXX_FLAGS_INIT OR CMAKE_EXE_LINKER_FLAGS_INIT OR CMAKE_SHARED_LINKER_FLAGS_INIT OR CMAKE_MODULE_LINKER_FLAGS_INIT)
|
OR CMAKE_C_FLAGS_INIT OR CMAKE_CXX_FLAGS_INIT OR CMAKE_EXE_LINKER_FLAGS_INIT OR CMAKE_MODULE_LINKER_FLAGS_INIT)
|
||||||
|
|
||||||
# if $ENV
|
# if $ENV
|
||||||
message("CFLAGS: $ENV{CFLAGS}")
|
message("CFLAGS: $ENV{CFLAGS}")
|
||||||
@ -36,7 +36,6 @@ if (NOT "$ENV{CFLAGS}" STREQUAL ""
|
|||||||
message("CMAKE_C_FLAGS_INIT: ${CMAKE_C_FLAGS_INIT}")
|
message("CMAKE_C_FLAGS_INIT: ${CMAKE_C_FLAGS_INIT}")
|
||||||
message("CMAKE_CXX_FLAGS_INIT: ${CMAKE_CXX_FLAGS_INIT}")
|
message("CMAKE_CXX_FLAGS_INIT: ${CMAKE_CXX_FLAGS_INIT}")
|
||||||
message("CMAKE_EXE_LINKER_FLAGS_INIT: ${CMAKE_EXE_LINKER_FLAGS_INIT}")
|
message("CMAKE_EXE_LINKER_FLAGS_INIT: ${CMAKE_EXE_LINKER_FLAGS_INIT}")
|
||||||
message("CMAKE_SHARED_LINKER_FLAGS_INIT: ${CMAKE_SHARED_LINKER_FLAGS_INIT}")
|
|
||||||
message("CMAKE_MODULE_LINKER_FLAGS_INIT: ${CMAKE_MODULE_LINKER_FLAGS_INIT}")
|
message("CMAKE_MODULE_LINKER_FLAGS_INIT: ${CMAKE_MODULE_LINKER_FLAGS_INIT}")
|
||||||
|
|
||||||
message(FATAL_ERROR "
|
message(FATAL_ERROR "
|
||||||
@ -84,7 +83,10 @@ if (OS MATCHES "Linux"
|
|||||||
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-aarch64.cmake" CACHE INTERNAL "")
|
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-aarch64.cmake" CACHE INTERNAL "")
|
||||||
elseif (ARCH MATCHES "^(ppc64le.*|PPC64LE.*)")
|
elseif (ARCH MATCHES "^(ppc64le.*|PPC64LE.*)")
|
||||||
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-ppc64le.cmake" CACHE INTERNAL "")
|
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-ppc64le.cmake" CACHE INTERNAL "")
|
||||||
|
elseif (ARCH MATCHES "^(s390x.*|S390X.*)")
|
||||||
|
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-s390x.cmake" CACHE INTERNAL "")
|
||||||
else ()
|
else ()
|
||||||
message (FATAL_ERROR "Unsupported architecture: ${ARCH}")
|
message (FATAL_ERROR "Unsupported architecture: ${ARCH}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
36
README.md
36
README.md
@ -1,7 +1,12 @@
|
|||||||
[![ClickHouse — open source distributed column-oriented DBMS](https://github.com/ClickHouse/clickhouse-presentations/raw/master/images/logo-400x240.png)](https://clickhouse.com)
|
[<img alt="ClickHouse — open source distributed column-oriented DBMS" width="400px" src="https://clickhouse.com/images/ch_gh_logo_rounded.png" />](https://clickhouse.com?utm_source=github)
|
||||||
|
|
||||||
ClickHouse® is an open-source column-oriented database management system that allows generating analytical data reports in real-time.
|
ClickHouse® is an open-source column-oriented database management system that allows generating analytical data reports in real-time.
|
||||||
|
|
||||||
|
## How To Install (Linux, macOS, FreeBSD)
|
||||||
|
```
|
||||||
|
curl https://clickhouse.com/ | sh
|
||||||
|
```
|
||||||
|
|
||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
* [Official website](https://clickhouse.com/) has a quick high-level overview of ClickHouse on the main page.
|
* [Official website](https://clickhouse.com/) has a quick high-level overview of ClickHouse on the main page.
|
||||||
@ -9,19 +14,32 @@ ClickHouse® is an open-source column-oriented database management system that a
|
|||||||
* [Tutorial](https://clickhouse.com/docs/en/getting_started/tutorial/) shows how to set up and query a small ClickHouse cluster.
|
* [Tutorial](https://clickhouse.com/docs/en/getting_started/tutorial/) shows how to set up and query a small ClickHouse cluster.
|
||||||
* [Documentation](https://clickhouse.com/docs/en/) provides more in-depth information.
|
* [Documentation](https://clickhouse.com/docs/en/) provides more in-depth information.
|
||||||
* [YouTube channel](https://www.youtube.com/c/ClickHouseDB) has a lot of content about ClickHouse in video format.
|
* [YouTube channel](https://www.youtube.com/c/ClickHouseDB) has a lot of content about ClickHouse in video format.
|
||||||
* [Slack](https://clickhousedb.slack.com/) and [Telegram](https://telegram.me/clickhouse_en) allow chatting with ClickHouse users in real-time.
|
* [Slack](https://clickhouse.com/slack) and [Telegram](https://telegram.me/clickhouse_en) allow chatting with ClickHouse users in real-time.
|
||||||
* [Blog](https://clickhouse.com/blog/) contains various ClickHouse-related articles, as well as announcements and reports about events.
|
* [Blog](https://clickhouse.com/blog/) contains various ClickHouse-related articles, as well as announcements and reports about events.
|
||||||
* [Code Browser (Woboq)](https://clickhouse.com/codebrowser/ClickHouse/index.html) with syntax highlight and navigation.
|
* [Code Browser (Woboq)](https://clickhouse.com/codebrowser/ClickHouse/index.html) with syntax highlight and navigation.
|
||||||
* [Code Browser (github.dev)](https://github.dev/ClickHouse/ClickHouse) with syntax highlight, powered by github.dev.
|
* [Code Browser (github.dev)](https://github.dev/ClickHouse/ClickHouse) with syntax highlight, powered by github.dev.
|
||||||
* [Contacts](https://clickhouse.com/company/contact) can help to get your questions answered if there are any.
|
* [Contacts](https://clickhouse.com/company/contact) can help to get your questions answered if there are any.
|
||||||
|
|
||||||
## Upcoming Events
|
## Upcoming Events
|
||||||
* [**ClickHouse Workshop**](https://clickhouse.com/company/events/2023-02-15-clickhouse-workshop?utm_source=github&utm_medium=social&utm_campaign=workshop) - Feb 15 & 16 - In this 2-day (3 hrs per day) free training, topics range from introductory content to a deep dive on interacting with and understanding your data. There will be both live training and hands-on labs.
|
|
||||||
* [**v23.2 Release Webinar**](https://clickhouse.com/company/events/v23-2-release-webinar?utm_source=github&utm_medium=social&utm_campaign=release-webinar-2023-02) - Feb 23 - 23.2 is rapidly approaching. Original creator, co-founder, and CTO of ClickHouse Alexey Milovidov will walk us through the highlights of the release.
|
* [**v23.5 Release Webinar**](https://clickhouse.com/company/events/v23-5-release-webinar?utm_source=github&utm_medium=social&utm_campaign=release-webinar-2023-05) - May 31 - 23.5 is rapidly approaching. Original creator, co-founder, and CTO of ClickHouse Alexey Milovidov will walk us through the highlights of the release.
|
||||||
* [**ClickHouse Meetup in Amsterdam**](https://www.meetup.com/clickhouse-netherlands-user-group/events/291485868/) - Mar 9 - The first ClickHouse Amsterdam Meetup of 2023 is here! 🎉 Join us for short lightning talks and long discussions. Food, drinks & good times on us.
|
* [**ClickHouse Meetup in Barcelona**](https://www.meetup.com/clickhouse-barcelona-user-group/events/292892669) - May 25
|
||||||
* [**ClickHouse Meetup in SF Bay Area**](https://www.meetup.com/clickhouse-silicon-valley-meetup-group/events/291490121/) - Mar 14 - A night to meet with ClickHouse team in the San Francisco area! Food and drink are a given...but networking is the primary focus.
|
* [**ClickHouse Meetup in London**](https://www.meetup.com/clickhouse-london-user-group/events/292892824) - May 25
|
||||||
* [**ClickHouse Meetup in Austin**](https://www.meetup.com/clickhouse-austin-user-group/events/291486654/) - Mar 16 - The first ClickHouse Meetup in Austin is happening soon! Interested in speaking, let us know!
|
* [**ClickHouse Meetup in San Francisco**](https://www.meetup.com/clickhouse-silicon-valley-meetup-group/events/293426725/) - Jun 7
|
||||||
|
* [**ClickHouse Meetup in Stockholm**](https://www.meetup.com/clickhouse-berlin-user-group/events/292892466) - Jun 13
|
||||||
|
|
||||||
|
Also, keep an eye out for upcoming meetups in Amsterdam, Boston, NYC, Beijing, and Toronto. Somewhere else you want us to be? Please feel free to reach out to tyler <at> clickhouse <dot> com.
|
||||||
|
|
||||||
## Recent Recordings
|
## Recent Recordings
|
||||||
* **FOSDEM 2023**: In the "Fast and Streaming Data" room Alexey gave a talk entitled "Building Analytical Apps With ClickHouse" that looks at the landscape of data tools, an interesting data set, and how you can interact with data quickly. Check out the recording on **[YouTube](https://www.youtube.com/watch?v=JlcI2Vfz_uk)**.
|
* **Recent Meetup Videos**: [Meetup Playlist](https://www.youtube.com/playlist?list=PL0Z2YDlm0b3iNDUzpY1S3L_iV4nARda_U) Whenever possible recordings of the ClickHouse Community Meetups are edited and presented as individual talks. Current featuring "Modern SQL in 2023", "Fast, Concurrent, and Consistent Asynchronous INSERTS in ClickHouse", and "Full-Text Indices: Design and Experiments"
|
||||||
* **Recording available**: [**v23.1 Release Webinar**](https://www.youtube.com/watch?v=zYSZXBnTMSE) 23.1 is the ClickHouse New Year release. Original creator, co-founder, and CTO of ClickHouse Alexey Milovidov will walk us through the highlights of the release. Inverted indices, query cache, and so -- very -- much more.
|
* **Recording available**: [**v23.4 Release Webinar**](https://www.youtube.com/watch?v=4rrf6bk_mOg) Faster Parquet Reading, Asynchonous Connections to Reoplicas, Trailing Comma before FROM, extractKeyValuePairs, integrations updates, and so much more! Watch it now!
|
||||||
|
* **All release webinar recordings**: [YouTube playlist](https://www.youtube.com/playlist?list=PL0Z2YDlm0b3jAlSy1JxyP8zluvXaN3nxU)
|
||||||
|
|
||||||
|
|
||||||
|
## Interested in joining ClickHouse and making it your full time job?
|
||||||
|
|
||||||
|
We are a globally diverse and distributed team, united behind a common goal of creating industry-leading, real-time analytics. Here, you will have an opportunity to solve some of the most cutting edge technical challenges and have direct ownership of your work and vision. If you are a contributor by nature, a thinker as well as a doer - we’ll definitely click!
|
||||||
|
|
||||||
|
Check out our **current openings** here: https://clickhouse.com/company/careers
|
||||||
|
|
||||||
|
Cant find what you are looking for, but want to let us know you are interested in joining ClickHouse? Email careers@clickhouse.com!
|
||||||
|
17
SECURITY.md
17
SECURITY.md
@ -13,19 +13,16 @@ The following versions of ClickHouse server are currently being supported with s
|
|||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
|:-|:-|
|
|:-|:-|
|
||||||
| 23.1 | ✔️ |
|
| 23.4 | ✔️ |
|
||||||
| 22.12 | ✔️ |
|
| 23.3 | ✔️ |
|
||||||
| 22.11 | ✔️ |
|
| 23.2 | ✔️ |
|
||||||
|
| 23.1 | ❌ |
|
||||||
|
| 22.12 | ❌ |
|
||||||
|
| 22.11 | ❌ |
|
||||||
| 22.10 | ❌ |
|
| 22.10 | ❌ |
|
||||||
| 22.9 | ❌ |
|
| 22.9 | ❌ |
|
||||||
| 22.8 | ✔️ |
|
| 22.8 | ✔️ |
|
||||||
| 22.7 | ❌ |
|
| 22.* | ❌ |
|
||||||
| 22.6 | ❌ |
|
|
||||||
| 22.5 | ❌ |
|
|
||||||
| 22.4 | ❌ |
|
|
||||||
| 22.3 | ✔️ |
|
|
||||||
| 22.2 | ❌ |
|
|
||||||
| 22.1 | ❌ |
|
|
||||||
| 21.* | ❌ |
|
| 21.* | ❌ |
|
||||||
| 20.* | ❌ |
|
| 20.* | ❌ |
|
||||||
| 19.* | ❌ |
|
| 19.* | ❌ |
|
||||||
|
@ -2,6 +2,10 @@ if (USE_CLANG_TIDY)
|
|||||||
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
|
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# TODO: Remove this. We like to compile with C++23 (set by top-level CMakeLists) but Clang crashes with our libcxx
|
||||||
|
# when instantiated from JSON.cpp. Try again when libcxx(abi) and Clang are upgraded to 16.
|
||||||
|
set (CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
set (SRCS
|
set (SRCS
|
||||||
argsToConfig.cpp
|
argsToConfig.cpp
|
||||||
coverage.cpp
|
coverage.cpp
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <base/extended_types.h>
|
#include <base/extended_types.h>
|
||||||
|
#include <base/Decimal_fwd.h>
|
||||||
|
|
||||||
#if !defined(NO_SANITIZE_UNDEFINED)
|
#if !defined(NO_SANITIZE_UNDEFINED)
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
@ -19,23 +20,6 @@ using Decimal64 = Decimal<Int64>;
|
|||||||
using Decimal128 = Decimal<Int128>;
|
using Decimal128 = Decimal<Int128>;
|
||||||
using Decimal256 = Decimal<Int256>;
|
using Decimal256 = Decimal<Int256>;
|
||||||
|
|
||||||
template <class T>
|
|
||||||
concept is_decimal =
|
|
||||||
std::is_same_v<T, Decimal32>
|
|
||||||
|| std::is_same_v<T, Decimal64>
|
|
||||||
|| std::is_same_v<T, Decimal128>
|
|
||||||
|| std::is_same_v<T, Decimal256>
|
|
||||||
|| std::is_same_v<T, DateTime64>;
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
concept is_over_big_int =
|
|
||||||
std::is_same_v<T, Int128>
|
|
||||||
|| std::is_same_v<T, UInt128>
|
|
||||||
|| std::is_same_v<T, Int256>
|
|
||||||
|| std::is_same_v<T, UInt256>
|
|
||||||
|| std::is_same_v<T, Decimal128>
|
|
||||||
|| std::is_same_v<T, Decimal256>;
|
|
||||||
|
|
||||||
template <class T> struct NativeTypeT { using Type = T; };
|
template <class T> struct NativeTypeT { using Type = T; };
|
||||||
template <is_decimal T> struct NativeTypeT<T> { using Type = typename T::NativeType; };
|
template <is_decimal T> struct NativeTypeT<T> { using Type = typename T::NativeType; };
|
||||||
template <class T> using NativeType = typename NativeTypeT<T>::Type;
|
template <class T> using NativeType = typename NativeTypeT<T>::Type;
|
||||||
|
46
base/base/Decimal_fwd.h
Normal file
46
base/base/Decimal_fwd.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <base/types.h>
|
||||||
|
|
||||||
|
namespace wide
|
||||||
|
{
|
||||||
|
|
||||||
|
template <size_t Bits, typename Signed>
|
||||||
|
class integer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using Int128 = wide::integer<128, signed>;
|
||||||
|
using UInt128 = wide::integer<128, unsigned>;
|
||||||
|
using Int256 = wide::integer<256, signed>;
|
||||||
|
using UInt256 = wide::integer<256, unsigned>;
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
|
||||||
|
template <class> struct Decimal;
|
||||||
|
|
||||||
|
using Decimal32 = Decimal<Int32>;
|
||||||
|
using Decimal64 = Decimal<Int64>;
|
||||||
|
using Decimal128 = Decimal<Int128>;
|
||||||
|
using Decimal256 = Decimal<Int256>;
|
||||||
|
|
||||||
|
class DateTime64;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
concept is_decimal =
|
||||||
|
std::is_same_v<T, Decimal32>
|
||||||
|
|| std::is_same_v<T, Decimal64>
|
||||||
|
|| std::is_same_v<T, Decimal128>
|
||||||
|
|| std::is_same_v<T, Decimal256>
|
||||||
|
|| std::is_same_v<T, DateTime64>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
concept is_over_big_int =
|
||||||
|
std::is_same_v<T, Int128>
|
||||||
|
|| std::is_same_v<T, UInt128>
|
||||||
|
|| std::is_same_v<T, Int256>
|
||||||
|
|| std::is_same_v<T, UInt256>
|
||||||
|
|| std::is_same_v<T, Decimal128>
|
||||||
|
|| std::is_same_v<T, Decimal256>;
|
||||||
|
}
|
@ -51,3 +51,15 @@ namespace DB
|
|||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct hash<DB::IPv6>
|
||||||
|
{
|
||||||
|
size_t operator()(const DB::IPv6 & x) const
|
||||||
|
{
|
||||||
|
return std::hash<DB::IPv6::UnderlyingType>()(x.toUnderType());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -466,9 +466,8 @@ JSON::Pos JSON::searchField(const char * data, size_t size) const
|
|||||||
{
|
{
|
||||||
if (!it->hasEscapes())
|
if (!it->hasEscapes())
|
||||||
{
|
{
|
||||||
if (static_cast<int>(size) + 2 > it->dataEnd() - it->data())
|
const auto current_name = it->getRawName();
|
||||||
continue;
|
if (current_name.size() == size && 0 == memcmp(current_name.data(), data, size))
|
||||||
if (!strncmp(data, it->data() + 1, size))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept> // for std::logic_error
|
#include <stdexcept> // for std::logic_error
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
@ -326,5 +327,16 @@ namespace ZeroTraits
|
|||||||
inline void set(StringRef & x) { x.size = 0; }
|
inline void set(StringRef & x) { x.size = 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace PackedZeroTraits
|
||||||
|
{
|
||||||
|
template <typename Second, template <typename, typename> class PackedPairNoInit>
|
||||||
|
inline bool check(const PackedPairNoInit<StringRef, Second> p)
|
||||||
|
{ return 0 == p.key.size; }
|
||||||
|
|
||||||
|
template <typename Second, template <typename, typename> class PackedPairNoInit>
|
||||||
|
inline void set(PackedPairNoInit<StringRef, Second> & p)
|
||||||
|
{ p.key.size = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream & os, const StringRef & str);
|
std::ostream & operator<<(std::ostream & os, const StringRef & str);
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "TypePair.h"
|
|
||||||
|
|
||||||
/// General-purpose typelist. Easy on compilation times as it does not use recursion.
|
/// General-purpose typelist. Easy on compilation times as it does not use recursion.
|
||||||
template <typename ...Args>
|
template <typename ...Args>
|
||||||
@ -28,7 +27,7 @@ namespace TypeListUtils /// In some contexts it's more handy to use functions in
|
|||||||
constexpr Root<Args...> changeRoot(TypeList<Args...>) { return {}; }
|
constexpr Root<Args...> changeRoot(TypeList<Args...>) { return {}; }
|
||||||
|
|
||||||
template <typename F, typename ...Args>
|
template <typename F, typename ...Args>
|
||||||
constexpr void forEach(TypeList<Args...>, F && f) { (std::forward<F>(f)(Id<Args>{}), ...); }
|
constexpr void forEach(TypeList<Args...>, F && f) { (std::forward<F>(f)(TypeList<Args>{}), ...); }
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TypeListLeft, typename TypeListRight>
|
template <typename TypeListLeft, typename TypeListRight>
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
template <typename T, typename V> struct TypePair {};
|
|
||||||
template <typename T> struct Id {};
|
|
@ -3,13 +3,29 @@
|
|||||||
#include <Poco/Util/LayeredConfiguration.h>
|
#include <Poco/Util/LayeredConfiguration.h>
|
||||||
#include <Poco/Util/MapConfiguration.h>
|
#include <Poco/Util/MapConfiguration.h>
|
||||||
|
|
||||||
|
void argsToConfig(const Poco::Util::Application::ArgVec & argv,
|
||||||
void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::LayeredConfiguration & config, int priority)
|
Poco::Util::LayeredConfiguration & config,
|
||||||
|
int priority,
|
||||||
|
const std::unordered_set<std::string>* alias_names)
|
||||||
{
|
{
|
||||||
/// Parsing all args and converting to config layer
|
/// Parsing all args and converting to config layer
|
||||||
/// Test: -- --1=1 --1=2 --3 5 7 8 -9 10 -11=12 14= 15== --16==17 --=18 --19= --20 21 22 --23 --24 25 --26 -27 28 ---29=30 -- ----31 32 --33 3-4
|
/// Test: -- --1=1 --1=2 --3 5 7 8 -9 10 -11=12 14= 15== --16==17 --=18 --19= --20 21 22 --23 --24 25 --26 -27 28 ---29=30 -- ----31 32 --33 3-4
|
||||||
Poco::AutoPtr<Poco::Util::MapConfiguration> map_config = new Poco::Util::MapConfiguration;
|
Poco::AutoPtr<Poco::Util::MapConfiguration> map_config = new Poco::Util::MapConfiguration;
|
||||||
std::string key;
|
std::string key;
|
||||||
|
|
||||||
|
auto add_arg = [&map_config, &alias_names](const std::string & k, const std::string & v)
|
||||||
|
{
|
||||||
|
map_config->setString(k, v);
|
||||||
|
|
||||||
|
if (alias_names && !alias_names->contains(k))
|
||||||
|
{
|
||||||
|
std::string alias_key = k;
|
||||||
|
std::replace(alias_key.begin(), alias_key.end(), '-', '_');
|
||||||
|
if (alias_names->contains(alias_key))
|
||||||
|
map_config->setString(alias_key, v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (const auto & arg : argv)
|
for (const auto & arg : argv)
|
||||||
{
|
{
|
||||||
auto key_start = arg.find_first_not_of('-');
|
auto key_start = arg.find_first_not_of('-');
|
||||||
@ -19,7 +35,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
|
|||||||
// old saved '--key', will set to some true value "1"
|
// old saved '--key', will set to some true value "1"
|
||||||
if (!key.empty() && pos_minus != std::string::npos && pos_minus < key_start)
|
if (!key.empty() && pos_minus != std::string::npos && pos_minus < key_start)
|
||||||
{
|
{
|
||||||
map_config->setString(key, "1");
|
add_arg(key, "1");
|
||||||
key = "";
|
key = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +45,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
|
|||||||
{
|
{
|
||||||
if (pos_minus == std::string::npos || pos_minus > key_start)
|
if (pos_minus == std::string::npos || pos_minus > key_start)
|
||||||
{
|
{
|
||||||
map_config->setString(key, arg);
|
add_arg(key, arg);
|
||||||
}
|
}
|
||||||
key = "";
|
key = "";
|
||||||
}
|
}
|
||||||
@ -55,7 +71,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
|
|||||||
if (arg.size() > pos_eq)
|
if (arg.size() > pos_eq)
|
||||||
value = arg.substr(pos_eq + 1);
|
value = arg.substr(pos_eq + 1);
|
||||||
|
|
||||||
map_config->setString(key, value);
|
add_arg(key, value);
|
||||||
key = "";
|
key = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Poco/Util/Application.h>
|
#include <Poco/Util/Application.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Poco::Util
|
namespace Poco::Util
|
||||||
{
|
{
|
||||||
@ -8,4 +10,7 @@ class LayeredConfiguration; // NOLINT(cppcoreguidelines-virtual-class-destructor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Import extra command line arguments to configuration. These are command line arguments after --.
|
/// Import extra command line arguments to configuration. These are command line arguments after --.
|
||||||
void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::LayeredConfiguration & config, int priority);
|
void argsToConfig(const Poco::Util::Application::ArgVec & argv,
|
||||||
|
Poco::Util::LayeredConfiguration & config,
|
||||||
|
int priority,
|
||||||
|
const std::unordered_set<std::string>* registered_alias_names = nullptr);
|
||||||
|
@ -12,21 +12,22 @@
|
|||||||
template <typename To, typename From>
|
template <typename To, typename From>
|
||||||
std::decay_t<To> bit_cast(const From & from)
|
std::decay_t<To> bit_cast(const From & from)
|
||||||
{
|
{
|
||||||
/**
|
/** Assume the source value is 0xAABBCCDD (i.e. sizeof(from) == 4).
|
||||||
* Assume the source value is 0xAABBCCDD (i.e. sizeof(from) == 4).
|
* Its BE representation is 0xAABBCCDD, the LE representation is 0xDDCCBBAA.
|
||||||
* Its BE representation is 0xAABBCCDD, the LE representation is 0xDDCCBBAA.
|
* Further assume, sizeof(res) == 8 and that res is initially zeroed out.
|
||||||
* Further assume, sizeof(res) == 8 and that res is initially zeroed out.
|
* With LE, the result after bit_cast will be 0xDDCCBBAA00000000 --> input value == output value.
|
||||||
* With LE, the result after bit_cast will be 0xDDCCBBAA00000000 --> input value == output value.
|
* With BE, the result after bit_cast will be 0x00000000AABBCCDD --> input value == output value.
|
||||||
* With BE, the result after bit_cast will be 0x00000000AABBCCDD --> input value == output value.
|
*/
|
||||||
*/
|
|
||||||
To res {};
|
To res {};
|
||||||
if constexpr (std::endian::native == std::endian::little)
|
if constexpr (std::endian::native == std::endian::little)
|
||||||
memcpy(static_cast<void*>(&res), &from, std::min(sizeof(res), sizeof(from)));
|
{
|
||||||
|
memcpy(static_cast<void*>(&res), &from, std::min(sizeof(res), sizeof(from)));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t offset_to = (sizeof(res) > sizeof(from)) ? (sizeof(res) - sizeof(from)) : 0;
|
uint32_t offset_to = (sizeof(res) > sizeof(from)) ? (sizeof(res) - sizeof(from)) : 0;
|
||||||
uint32_t offset_from = (sizeof(from) > sizeof(res)) ? (sizeof(from) - sizeof(res)) : 0;
|
uint32_t offset_from = (sizeof(from) > sizeof(res)) ? (sizeof(from) - sizeof(res)) : 0;
|
||||||
memcpy(reinterpret_cast<char *>(&res) + offset_to, reinterpret_cast<const char *>(&from) + offset_from, std::min(sizeof(res), sizeof(from)));
|
memcpy(reinterpret_cast<char *>(&res) + offset_to, reinterpret_cast<const char *>(&from) + offset_from, std::min(sizeof(res), sizeof(from)));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#if WITH_COVERAGE
|
#if WITH_COVERAGE
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wreserved-identifier"
|
||||||
|
|
||||||
# include <mutex>
|
# include <mutex>
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@
|
|||||||
#define NO_INLINE __attribute__((__noinline__))
|
#define NO_INLINE __attribute__((__noinline__))
|
||||||
#define MAY_ALIAS __attribute__((__may_alias__))
|
#define MAY_ALIAS __attribute__((__may_alias__))
|
||||||
|
|
||||||
#if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__PPC__) && !(defined(__riscv) && (__riscv_xlen == 64))
|
#if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__PPC__) && !defined(__s390x__) && !(defined(__riscv) && (__riscv_xlen == 64))
|
||||||
# error "The only supported platforms are x86_64 and AArch64, PowerPC (work in progress) and RISC-V 64 (experimental)"
|
# error "The only supported platforms are x86_64 and AArch64, PowerPC (work in progress), s390x (work in progress) and RISC-V 64 (experimental)"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Check for presence of address sanitizer
|
/// Check for presence of address sanitizer
|
||||||
@ -73,18 +73,6 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ADDRESS_SANITIZER)
|
|
||||||
# define BOOST_USE_ASAN 1
|
|
||||||
# define BOOST_USE_UCONTEXT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(THREAD_SANITIZER)
|
|
||||||
# define BOOST_USE_TSAN 1
|
|
||||||
# define BOOST_USE_UCONTEXT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// TODO: Strange enough, there is no way to detect UB sanitizer.
|
|
||||||
|
|
||||||
/// Explicitly allow undefined behaviour for certain functions. Use it as a function attribute.
|
/// Explicitly allow undefined behaviour for certain functions. Use it as a function attribute.
|
||||||
/// It is useful in case when compiler cannot see (and exploit) it, but UBSan can.
|
/// It is useful in case when compiler cannot see (and exploit) it, but UBSan can.
|
||||||
/// Example: multiplication of signed integers with possibility of overflow when both sides are from user input.
|
/// Example: multiplication of signed integers with possibility of overflow when both sides are from user input.
|
||||||
|
@ -34,9 +34,51 @@
|
|||||||
* If no such characters, returns nullptr.
|
* If no such characters, returns nullptr.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct SearchSymbols
|
||||||
|
{
|
||||||
|
static constexpr auto BUFFER_SIZE = 16;
|
||||||
|
|
||||||
|
SearchSymbols() = default;
|
||||||
|
|
||||||
|
explicit SearchSymbols(std::string in)
|
||||||
|
: str(std::move(in))
|
||||||
|
{
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
if (str.size() > BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("SearchSymbols can contain at most " + std::to_string(BUFFER_SIZE) + " symbols and " + std::to_string(str.size()) + " was provided\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
char tmp_safety_buffer[BUFFER_SIZE] = {0};
|
||||||
|
|
||||||
|
memcpy(tmp_safety_buffer, str.data(), str.size());
|
||||||
|
|
||||||
|
simd_vector = _mm_loadu_si128(reinterpret_cast<const __m128i *>(tmp_safety_buffer));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
__m128i simd_vector;
|
||||||
|
#endif
|
||||||
|
std::string str;
|
||||||
|
};
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template <char ...chars> constexpr bool is_in(char x) { return ((x == chars) || ...); }
|
template <char ...chars> constexpr bool is_in(char x) { return ((x == chars) || ...); } // NOLINT(misc-redundant-expression)
|
||||||
|
|
||||||
|
static bool is_in(char c, const char * symbols, size_t num_chars)
|
||||||
|
{
|
||||||
|
for (size_t i = 0u; i < num_chars; ++i)
|
||||||
|
{
|
||||||
|
if (c == symbols[i])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__SSE2__)
|
#if defined(__SSE2__)
|
||||||
template <char s0>
|
template <char s0>
|
||||||
@ -53,6 +95,43 @@ inline __m128i mm_is_in(__m128i bytes)
|
|||||||
__m128i eq = mm_is_in<s1, tail...>(bytes);
|
__m128i eq = mm_is_in<s1, tail...>(bytes);
|
||||||
return _mm_or_si128(eq0, eq);
|
return _mm_or_si128(eq0, eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline __m128i mm_is_in(__m128i bytes, const char * symbols, size_t num_chars)
|
||||||
|
{
|
||||||
|
__m128i accumulator = _mm_setzero_si128();
|
||||||
|
for (size_t i = 0; i < num_chars; ++i)
|
||||||
|
{
|
||||||
|
__m128i eq = _mm_cmpeq_epi8(bytes, _mm_set1_epi8(symbols[i]));
|
||||||
|
accumulator = _mm_or_si128(accumulator, eq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::array<__m128i, 16u> mm_is_in_prepare(const char * symbols, size_t num_chars)
|
||||||
|
{
|
||||||
|
std::array<__m128i, 16u> result {};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_chars; ++i)
|
||||||
|
{
|
||||||
|
result[i] = _mm_set1_epi8(symbols[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline __m128i mm_is_in_execute(__m128i bytes, const std::array<__m128i, 16u> & needles)
|
||||||
|
{
|
||||||
|
__m128i accumulator = _mm_setzero_si128();
|
||||||
|
|
||||||
|
for (const auto & needle : needles)
|
||||||
|
{
|
||||||
|
__m128i eq = _mm_cmpeq_epi8(bytes, needle);
|
||||||
|
accumulator = _mm_or_si128(accumulator, eq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <bool positive>
|
template <bool positive>
|
||||||
@ -99,6 +178,32 @@ inline const char * find_first_symbols_sse2(const char * const begin, const char
|
|||||||
return return_mode == ReturnMode::End ? end : nullptr;
|
return return_mode == ReturnMode::End ? end : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool positive, ReturnMode return_mode>
|
||||||
|
inline const char * find_first_symbols_sse2(const char * const begin, const char * const end, const char * symbols, size_t num_chars)
|
||||||
|
{
|
||||||
|
const char * pos = begin;
|
||||||
|
|
||||||
|
#if defined(__SSE2__)
|
||||||
|
const auto needles = mm_is_in_prepare(symbols, num_chars);
|
||||||
|
for (; pos + 15 < end; pos += 16)
|
||||||
|
{
|
||||||
|
__m128i bytes = _mm_loadu_si128(reinterpret_cast<const __m128i *>(pos));
|
||||||
|
|
||||||
|
__m128i eq = mm_is_in_execute(bytes, needles);
|
||||||
|
|
||||||
|
uint16_t bit_mask = maybe_negate<positive>(uint16_t(_mm_movemask_epi8(eq)));
|
||||||
|
if (bit_mask)
|
||||||
|
return pos + __builtin_ctz(bit_mask);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (; pos < end; ++pos)
|
||||||
|
if (maybe_negate<positive>(is_in(*pos, symbols, num_chars)))
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
return return_mode == ReturnMode::End ? end : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <bool positive, ReturnMode return_mode, char... symbols>
|
template <bool positive, ReturnMode return_mode, char... symbols>
|
||||||
inline const char * find_last_symbols_sse2(const char * const begin, const char * const end)
|
inline const char * find_last_symbols_sse2(const char * const begin, const char * const end)
|
||||||
@ -159,26 +264,61 @@ inline const char * find_first_symbols_sse42(const char * const begin, const cha
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (; pos < end; ++pos)
|
for (; pos < end; ++pos)
|
||||||
if ( (num_chars >= 1 && maybe_negate<positive>(*pos == c01))
|
if ( (num_chars == 1 && maybe_negate<positive>(is_in<c01>(*pos)))
|
||||||
|| (num_chars >= 2 && maybe_negate<positive>(*pos == c02))
|
|| (num_chars == 2 && maybe_negate<positive>(is_in<c01, c02>(*pos)))
|
||||||
|| (num_chars >= 3 && maybe_negate<positive>(*pos == c03))
|
|| (num_chars == 3 && maybe_negate<positive>(is_in<c01, c02, c03>(*pos)))
|
||||||
|| (num_chars >= 4 && maybe_negate<positive>(*pos == c04))
|
|| (num_chars == 4 && maybe_negate<positive>(is_in<c01, c02, c03, c04>(*pos)))
|
||||||
|| (num_chars >= 5 && maybe_negate<positive>(*pos == c05))
|
|| (num_chars == 5 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05>(*pos)))
|
||||||
|| (num_chars >= 6 && maybe_negate<positive>(*pos == c06))
|
|| (num_chars == 6 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06>(*pos)))
|
||||||
|| (num_chars >= 7 && maybe_negate<positive>(*pos == c07))
|
|| (num_chars == 7 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07>(*pos)))
|
||||||
|| (num_chars >= 8 && maybe_negate<positive>(*pos == c08))
|
|| (num_chars == 8 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08>(*pos)))
|
||||||
|| (num_chars >= 9 && maybe_negate<positive>(*pos == c09))
|
|| (num_chars == 9 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09>(*pos)))
|
||||||
|| (num_chars >= 10 && maybe_negate<positive>(*pos == c10))
|
|| (num_chars == 10 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10>(*pos)))
|
||||||
|| (num_chars >= 11 && maybe_negate<positive>(*pos == c11))
|
|| (num_chars == 11 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11>(*pos)))
|
||||||
|| (num_chars >= 12 && maybe_negate<positive>(*pos == c12))
|
|| (num_chars == 12 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12>(*pos)))
|
||||||
|| (num_chars >= 13 && maybe_negate<positive>(*pos == c13))
|
|| (num_chars == 13 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13>(*pos)))
|
||||||
|| (num_chars >= 14 && maybe_negate<positive>(*pos == c14))
|
|| (num_chars == 14 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14>(*pos)))
|
||||||
|| (num_chars >= 15 && maybe_negate<positive>(*pos == c15))
|
|| (num_chars == 15 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15>(*pos)))
|
||||||
|| (num_chars >= 16 && maybe_negate<positive>(*pos == c16)))
|
|| (num_chars == 16 && maybe_negate<positive>(is_in<c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, c16>(*pos))))
|
||||||
return pos;
|
return pos;
|
||||||
return return_mode == ReturnMode::End ? end : nullptr;
|
return return_mode == ReturnMode::End ? end : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool positive, ReturnMode return_mode>
|
||||||
|
inline const char * find_first_symbols_sse42(const char * const begin, const char * const end, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
const char * pos = begin;
|
||||||
|
|
||||||
|
const auto num_chars = symbols.str.size();
|
||||||
|
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
constexpr int mode = _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT;
|
||||||
|
|
||||||
|
const __m128i set = symbols.simd_vector;
|
||||||
|
|
||||||
|
for (; pos + 15 < end; pos += 16)
|
||||||
|
{
|
||||||
|
__m128i bytes = _mm_loadu_si128(reinterpret_cast<const __m128i *>(pos));
|
||||||
|
|
||||||
|
if constexpr (positive)
|
||||||
|
{
|
||||||
|
if (_mm_cmpestrc(set, num_chars, bytes, 16, mode))
|
||||||
|
return pos + _mm_cmpestri(set, num_chars, bytes, 16, mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_mm_cmpestrc(set, num_chars, bytes, 16, mode | _SIDD_NEGATIVE_POLARITY))
|
||||||
|
return pos + _mm_cmpestri(set, num_chars, bytes, 16, mode | _SIDD_NEGATIVE_POLARITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (; pos < end; ++pos)
|
||||||
|
if (maybe_negate<positive>(is_in(*pos, symbols.str.data(), num_chars)))
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
return return_mode == ReturnMode::End ? end : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/// NOTE No SSE 4.2 implementation for find_last_symbols_or_null. Not worth to do.
|
/// NOTE No SSE 4.2 implementation for find_last_symbols_or_null. Not worth to do.
|
||||||
|
|
||||||
@ -194,6 +334,17 @@ inline const char * find_first_symbols_dispatch(const char * begin, const char *
|
|||||||
return find_first_symbols_sse2<positive, return_mode, symbols...>(begin, end);
|
return find_first_symbols_sse2<positive, return_mode, symbols...>(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <bool positive, ReturnMode return_mode>
|
||||||
|
inline const char * find_first_symbols_dispatch(const std::string_view haystack, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
if (symbols.str.size() >= 5)
|
||||||
|
return find_first_symbols_sse42<positive, return_mode>(haystack.begin(), haystack.end(), symbols);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
return find_first_symbols_sse2<positive, return_mode>(haystack.begin(), haystack.end(), symbols.str.data(), symbols.str.size());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -211,6 +362,11 @@ inline char * find_first_symbols(char * begin, char * end)
|
|||||||
return const_cast<char *>(detail::find_first_symbols_dispatch<true, detail::ReturnMode::End, symbols...>(begin, end));
|
return const_cast<char *>(detail::find_first_symbols_dispatch<true, detail::ReturnMode::End, symbols...>(begin, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char * find_first_symbols(std::string_view haystack, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
return detail::find_first_symbols_dispatch<true, detail::ReturnMode::End>(haystack, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
template <char... symbols>
|
template <char... symbols>
|
||||||
inline const char * find_first_not_symbols(const char * begin, const char * end)
|
inline const char * find_first_not_symbols(const char * begin, const char * end)
|
||||||
{
|
{
|
||||||
@ -223,6 +379,11 @@ inline char * find_first_not_symbols(char * begin, char * end)
|
|||||||
return const_cast<char *>(detail::find_first_symbols_dispatch<false, detail::ReturnMode::End, symbols...>(begin, end));
|
return const_cast<char *>(detail::find_first_symbols_dispatch<false, detail::ReturnMode::End, symbols...>(begin, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char * find_first_not_symbols(std::string_view haystack, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
return detail::find_first_symbols_dispatch<false, detail::ReturnMode::End>(haystack, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
template <char... symbols>
|
template <char... symbols>
|
||||||
inline const char * find_first_symbols_or_null(const char * begin, const char * end)
|
inline const char * find_first_symbols_or_null(const char * begin, const char * end)
|
||||||
{
|
{
|
||||||
@ -235,6 +396,11 @@ inline char * find_first_symbols_or_null(char * begin, char * end)
|
|||||||
return const_cast<char *>(detail::find_first_symbols_dispatch<true, detail::ReturnMode::Nullptr, symbols...>(begin, end));
|
return const_cast<char *>(detail::find_first_symbols_dispatch<true, detail::ReturnMode::Nullptr, symbols...>(begin, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char * find_first_symbols_or_null(std::string_view haystack, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
return detail::find_first_symbols_dispatch<true, detail::ReturnMode::Nullptr>(haystack, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
template <char... symbols>
|
template <char... symbols>
|
||||||
inline const char * find_first_not_symbols_or_null(const char * begin, const char * end)
|
inline const char * find_first_not_symbols_or_null(const char * begin, const char * end)
|
||||||
{
|
{
|
||||||
@ -247,6 +413,10 @@ inline char * find_first_not_symbols_or_null(char * begin, char * end)
|
|||||||
return const_cast<char *>(detail::find_first_symbols_dispatch<false, detail::ReturnMode::Nullptr, symbols...>(begin, end));
|
return const_cast<char *>(detail::find_first_symbols_dispatch<false, detail::ReturnMode::Nullptr, symbols...>(begin, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const char * find_first_not_symbols_or_null(std::string_view haystack, const SearchSymbols & symbols)
|
||||||
|
{
|
||||||
|
return detail::find_first_symbols_dispatch<false, detail::ReturnMode::Nullptr>(haystack, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
template <char... symbols>
|
template <char... symbols>
|
||||||
inline const char * find_last_symbols_or_null(const char * begin, const char * end)
|
inline const char * find_last_symbols_or_null(const char * begin, const char * end)
|
||||||
|
215
base/base/hex.h
Normal file
215
base/base/hex.h
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <cstring>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/// Maps 0..15 to 0..9A..F or 0..9a..f correspondingly.
|
||||||
|
|
||||||
|
constexpr inline std::string_view hex_digit_to_char_uppercase_table = "0123456789ABCDEF";
|
||||||
|
constexpr inline std::string_view hex_digit_to_char_lowercase_table = "0123456789abcdef";
|
||||||
|
|
||||||
|
constexpr char hexDigitUppercase(unsigned char c)
|
||||||
|
{
|
||||||
|
return hex_digit_to_char_uppercase_table[c];
|
||||||
|
}
|
||||||
|
constexpr char hexDigitLowercase(unsigned char c)
|
||||||
|
{
|
||||||
|
return hex_digit_to_char_lowercase_table[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps 0..255 to 00..FF or 00..ff correspondingly
|
||||||
|
|
||||||
|
constexpr inline std::string_view hex_byte_to_char_uppercase_table = //
|
||||||
|
"000102030405060708090A0B0C0D0E0F"
|
||||||
|
"101112131415161718191A1B1C1D1E1F"
|
||||||
|
"202122232425262728292A2B2C2D2E2F"
|
||||||
|
"303132333435363738393A3B3C3D3E3F"
|
||||||
|
"404142434445464748494A4B4C4D4E4F"
|
||||||
|
"505152535455565758595A5B5C5D5E5F"
|
||||||
|
"606162636465666768696A6B6C6D6E6F"
|
||||||
|
"707172737475767778797A7B7C7D7E7F"
|
||||||
|
"808182838485868788898A8B8C8D8E8F"
|
||||||
|
"909192939495969798999A9B9C9D9E9F"
|
||||||
|
"A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
|
||||||
|
"B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
|
||||||
|
"C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
|
||||||
|
"D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
|
||||||
|
"E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
|
||||||
|
"F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF";
|
||||||
|
|
||||||
|
constexpr inline std::string_view hex_byte_to_char_lowercase_table = //
|
||||||
|
"000102030405060708090a0b0c0d0e0f"
|
||||||
|
"101112131415161718191a1b1c1d1e1f"
|
||||||
|
"202122232425262728292a2b2c2d2e2f"
|
||||||
|
"303132333435363738393a3b3c3d3e3f"
|
||||||
|
"404142434445464748494a4b4c4d4e4f"
|
||||||
|
"505152535455565758595a5b5c5d5e5f"
|
||||||
|
"606162636465666768696a6b6c6d6e6f"
|
||||||
|
"707172737475767778797a7b7c7d7e7f"
|
||||||
|
"808182838485868788898a8b8c8d8e8f"
|
||||||
|
"909192939495969798999a9b9c9d9e9f"
|
||||||
|
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
|
||||||
|
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
|
||||||
|
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
|
||||||
|
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
|
||||||
|
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
|
||||||
|
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
|
||||||
|
|
||||||
|
inline void writeHexByteUppercase(UInt8 byte, void * out)
|
||||||
|
{
|
||||||
|
memcpy(out, &hex_byte_to_char_uppercase_table[static_cast<size_t>(byte) * 2], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void writeHexByteLowercase(UInt8 byte, void * out)
|
||||||
|
{
|
||||||
|
memcpy(out, &hex_byte_to_char_lowercase_table[static_cast<size_t>(byte) * 2], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline std::string_view bin_byte_to_char_table = //
|
||||||
|
"0000000000000001000000100000001100000100000001010000011000000111"
|
||||||
|
"0000100000001001000010100000101100001100000011010000111000001111"
|
||||||
|
"0001000000010001000100100001001100010100000101010001011000010111"
|
||||||
|
"0001100000011001000110100001101100011100000111010001111000011111"
|
||||||
|
"0010000000100001001000100010001100100100001001010010011000100111"
|
||||||
|
"0010100000101001001010100010101100101100001011010010111000101111"
|
||||||
|
"0011000000110001001100100011001100110100001101010011011000110111"
|
||||||
|
"0011100000111001001110100011101100111100001111010011111000111111"
|
||||||
|
"0100000001000001010000100100001101000100010001010100011001000111"
|
||||||
|
"0100100001001001010010100100101101001100010011010100111001001111"
|
||||||
|
"0101000001010001010100100101001101010100010101010101011001010111"
|
||||||
|
"0101100001011001010110100101101101011100010111010101111001011111"
|
||||||
|
"0110000001100001011000100110001101100100011001010110011001100111"
|
||||||
|
"0110100001101001011010100110101101101100011011010110111001101111"
|
||||||
|
"0111000001110001011100100111001101110100011101010111011001110111"
|
||||||
|
"0111100001111001011110100111101101111100011111010111111001111111"
|
||||||
|
"1000000010000001100000101000001110000100100001011000011010000111"
|
||||||
|
"1000100010001001100010101000101110001100100011011000111010001111"
|
||||||
|
"1001000010010001100100101001001110010100100101011001011010010111"
|
||||||
|
"1001100010011001100110101001101110011100100111011001111010011111"
|
||||||
|
"1010000010100001101000101010001110100100101001011010011010100111"
|
||||||
|
"1010100010101001101010101010101110101100101011011010111010101111"
|
||||||
|
"1011000010110001101100101011001110110100101101011011011010110111"
|
||||||
|
"1011100010111001101110101011101110111100101111011011111010111111"
|
||||||
|
"1100000011000001110000101100001111000100110001011100011011000111"
|
||||||
|
"1100100011001001110010101100101111001100110011011100111011001111"
|
||||||
|
"1101000011010001110100101101001111010100110101011101011011010111"
|
||||||
|
"1101100011011001110110101101101111011100110111011101111011011111"
|
||||||
|
"1110000011100001111000101110001111100100111001011110011011100111"
|
||||||
|
"1110100011101001111010101110101111101100111011011110111011101111"
|
||||||
|
"1111000011110001111100101111001111110100111101011111011011110111"
|
||||||
|
"1111100011111001111110101111101111111100111111011111111011111111";
|
||||||
|
|
||||||
|
inline void writeBinByte(UInt8 byte, void * out)
|
||||||
|
{
|
||||||
|
memcpy(out, &bin_byte_to_char_table[static_cast<size_t>(byte) * 8], 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produces hex representation of an unsigned int with leading zeros (for checksums)
|
||||||
|
template <typename TUInt>
|
||||||
|
inline void writeHexUIntImpl(TUInt uint_, char * out, std::string_view table)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
TUInt value;
|
||||||
|
UInt8 uint8[sizeof(TUInt)];
|
||||||
|
};
|
||||||
|
|
||||||
|
value = uint_;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(TUInt); ++i)
|
||||||
|
{
|
||||||
|
if constexpr (std::endian::native == std::endian::little)
|
||||||
|
memcpy(out + i * 2, &table[static_cast<size_t>(uint8[sizeof(TUInt) - 1 - i]) * 2], 2);
|
||||||
|
else
|
||||||
|
memcpy(out + i * 2, &table[static_cast<size_t>(uint8[i]) * 2], 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TUInt>
|
||||||
|
inline void writeHexUIntUppercase(TUInt uint_, char * out)
|
||||||
|
{
|
||||||
|
writeHexUIntImpl(uint_, out, hex_byte_to_char_uppercase_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TUInt>
|
||||||
|
inline void writeHexUIntLowercase(TUInt uint_, char * out)
|
||||||
|
{
|
||||||
|
writeHexUIntImpl(uint_, out, hex_byte_to_char_lowercase_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TUInt>
|
||||||
|
std::string getHexUIntUppercase(TUInt uint_)
|
||||||
|
{
|
||||||
|
std::string res(sizeof(TUInt) * 2, '\0');
|
||||||
|
writeHexUIntUppercase(uint_, res.data());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TUInt>
|
||||||
|
std::string getHexUIntLowercase(TUInt uint_)
|
||||||
|
{
|
||||||
|
std::string res(sizeof(TUInt) * 2, '\0');
|
||||||
|
writeHexUIntLowercase(uint_, res.data());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps 0..9, A..F, a..f to 0..15. Other chars are mapped to implementation specific value.
|
||||||
|
|
||||||
|
constexpr inline std::string_view hex_char_to_digit_table
|
||||||
|
= {"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" //0-9
|
||||||
|
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" //A-Z
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" //a-z
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||||
|
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",
|
||||||
|
256};
|
||||||
|
|
||||||
|
constexpr UInt8 unhex(char c)
|
||||||
|
{
|
||||||
|
return hex_char_to_digit_table[static_cast<UInt8>(c)];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr UInt8 unhex2(const char * data)
|
||||||
|
{
|
||||||
|
return static_cast<UInt8>(unhex(data[0])) * 0x10 + static_cast<UInt8>(unhex(data[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr UInt16 unhex4(const char * data)
|
||||||
|
{
|
||||||
|
return static_cast<UInt16>(unhex(data[0])) * 0x1000 + static_cast<UInt16>(unhex(data[1])) * 0x100
|
||||||
|
+ static_cast<UInt16>(unhex(data[2])) * 0x10 + static_cast<UInt16>(unhex(data[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TUInt>
|
||||||
|
constexpr TUInt unhexUInt(const char * data)
|
||||||
|
{
|
||||||
|
TUInt res = 0;
|
||||||
|
if constexpr ((sizeof(TUInt) <= 8) || ((sizeof(TUInt) % 8) != 0))
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeof(TUInt) * 2; ++i, ++data)
|
||||||
|
{
|
||||||
|
res <<= 4;
|
||||||
|
res += unhex(*data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeof(TUInt) / 8; ++i, data += 16)
|
||||||
|
{
|
||||||
|
res <<= 64;
|
||||||
|
res += unhexUInt<UInt64>(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
13
base/base/interpolate.h
Normal file
13
base/base/interpolate.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
/** Linear interpolation in logarithmic coordinates.
|
||||||
|
* Exponential interpolation is related to linear interpolation
|
||||||
|
* exactly in same way as geometric mean is related to arithmetic mean.
|
||||||
|
*/
|
||||||
|
constexpr double interpolateExponential(double min, double max, double ratio)
|
||||||
|
{
|
||||||
|
assert(min > 0 && ratio >= 0 && ratio <= 1);
|
||||||
|
return min * std::pow(max / min, ratio);
|
||||||
|
}
|
@ -1,6 +1,4 @@
|
|||||||
#ifdef HAS_RESERVED_IDENTIFIER
|
|
||||||
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||||
#endif
|
|
||||||
|
|
||||||
/// This code was based on the code by Fedor Korotkiy https://www.linkedin.com/in/fedor-korotkiy-659a1838/
|
/// This code was based on the code by Fedor Korotkiy https://www.linkedin.com/in/fedor-korotkiy-659a1838/
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
Self & operator=(T && rhs) { t = std::move(rhs); return *this;}
|
Self & operator=(T && rhs) { t = std::move(rhs); return *this;}
|
||||||
|
|
||||||
// NOLINTBEGIN(google-explicit-constructor)
|
// NOLINTBEGIN(google-explicit-constructor)
|
||||||
operator const T & () const { return t; }
|
constexpr operator const T & () const { return t; }
|
||||||
operator T & () { return t; }
|
operator T & () { return t; }
|
||||||
// NOLINTEND(google-explicit-constructor)
|
// NOLINTEND(google-explicit-constructor)
|
||||||
|
|
||||||
|
@ -13,11 +13,7 @@ using char8_t = unsigned char;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// This is needed for more strict aliasing. https://godbolt.org/z/xpJBSb https://stackoverflow.com/a/57453713
|
/// This is needed for more strict aliasing. https://godbolt.org/z/xpJBSb https://stackoverflow.com/a/57453713
|
||||||
#if !defined(PVS_STUDIO) /// But PVS-Studio does not treat it correctly.
|
|
||||||
using UInt8 = char8_t;
|
using UInt8 = char8_t;
|
||||||
#else
|
|
||||||
using UInt8 = uint8_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using UInt16 = uint16_t;
|
using UInt16 = uint16_t;
|
||||||
using UInt32 = uint32_t;
|
using UInt32 = uint32_t;
|
||||||
|
@ -5,44 +5,6 @@
|
|||||||
#include <bit>
|
#include <bit>
|
||||||
|
|
||||||
|
|
||||||
inline void reverseMemcpy(void * dst, const void * src, size_t size)
|
|
||||||
{
|
|
||||||
uint8_t * uint_dst = reinterpret_cast<uint8_t *>(dst);
|
|
||||||
const uint8_t * uint_src = reinterpret_cast<const uint8_t *>(src);
|
|
||||||
|
|
||||||
uint_dst += size;
|
|
||||||
while (size)
|
|
||||||
{
|
|
||||||
--uint_dst;
|
|
||||||
*uint_dst = *uint_src;
|
|
||||||
++uint_src;
|
|
||||||
--size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline T unalignedLoadLE(const void * address)
|
|
||||||
{
|
|
||||||
T res {};
|
|
||||||
if constexpr (std::endian::native == std::endian::little)
|
|
||||||
memcpy(&res, address, sizeof(res));
|
|
||||||
else
|
|
||||||
reverseMemcpy(&res, address, sizeof(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void unalignedStoreLE(void * address,
|
|
||||||
const typename std::enable_if<true, T>::type & src)
|
|
||||||
{
|
|
||||||
static_assert(std::is_trivially_copyable_v<T>);
|
|
||||||
if constexpr (std::endian::native == std::endian::little)
|
|
||||||
memcpy(address, &src, sizeof(src));
|
|
||||||
else
|
|
||||||
reverseMemcpy(address, &src, sizeof(src));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T unalignedLoad(const void * address)
|
inline T unalignedLoad(const void * address)
|
||||||
{
|
{
|
||||||
@ -62,3 +24,70 @@ inline void unalignedStore(void * address,
|
|||||||
static_assert(std::is_trivially_copyable_v<T>);
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
memcpy(address, &src, sizeof(src));
|
memcpy(address, &src, sizeof(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void reverseMemcpy(void * dst, const void * src, size_t size)
|
||||||
|
{
|
||||||
|
uint8_t * uint_dst = reinterpret_cast<uint8_t *>(dst);
|
||||||
|
const uint8_t * uint_src = reinterpret_cast<const uint8_t *>(src);
|
||||||
|
|
||||||
|
uint_dst += size;
|
||||||
|
while (size)
|
||||||
|
{
|
||||||
|
--uint_dst;
|
||||||
|
*uint_dst = *uint_src;
|
||||||
|
++uint_src;
|
||||||
|
--size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::endian endian, typename T>
|
||||||
|
inline T unalignedLoadEndian(const void * address)
|
||||||
|
{
|
||||||
|
T res {};
|
||||||
|
if constexpr (std::endian::native == endian)
|
||||||
|
memcpy(&res, address, sizeof(res));
|
||||||
|
else
|
||||||
|
reverseMemcpy(&res, address, sizeof(res));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::endian endian, typename T>
|
||||||
|
inline void unalignedStoreEndian(void * address, T & src)
|
||||||
|
{
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>);
|
||||||
|
if constexpr (std::endian::native == endian)
|
||||||
|
memcpy(address, &src, sizeof(src));
|
||||||
|
else
|
||||||
|
reverseMemcpy(address, &src, sizeof(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T unalignedLoadLittleEndian(const void * address)
|
||||||
|
{
|
||||||
|
return unalignedLoadEndian<std::endian::little, T>(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void unalignedStoreLittleEndian(void * address,
|
||||||
|
const typename std::enable_if<true, T>::type & src)
|
||||||
|
{
|
||||||
|
unalignedStoreEndian<std::endian::little>(address, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T unalignedLoadBigEndian(const void * address)
|
||||||
|
{
|
||||||
|
return unalignedLoadEndian<std::endian::big, T>(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline void unalignedStoreBigEndian(void * address,
|
||||||
|
const typename std::enable_if<true, T>::type & src)
|
||||||
|
{
|
||||||
|
unalignedStoreEndian<std::endian::big>(address, src);
|
||||||
|
}
|
||||||
|
@ -5,10 +5,8 @@ constexpr size_t KiB = 1024;
|
|||||||
constexpr size_t MiB = 1024 * KiB;
|
constexpr size_t MiB = 1024 * KiB;
|
||||||
constexpr size_t GiB = 1024 * MiB;
|
constexpr size_t GiB = 1024 * MiB;
|
||||||
|
|
||||||
#ifdef HAS_RESERVED_IDENTIFIER
|
#pragma clang diagnostic push
|
||||||
# pragma clang diagnostic push
|
#pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// NOLINTBEGIN(google-runtime-int)
|
// NOLINTBEGIN(google-runtime-int)
|
||||||
constexpr size_t operator"" _KiB(unsigned long long val) { return val * KiB; }
|
constexpr size_t operator"" _KiB(unsigned long long val) { return val * KiB; }
|
||||||
@ -16,6 +14,4 @@ constexpr size_t operator"" _MiB(unsigned long long val) { return val * MiB; }
|
|||||||
constexpr size_t operator"" _GiB(unsigned long long val) { return val * GiB; }
|
constexpr size_t operator"" _GiB(unsigned long long val) { return val * GiB; }
|
||||||
// NOLINTEND(google-runtime-int)
|
// NOLINTEND(google-runtime-int)
|
||||||
|
|
||||||
#ifdef HAS_RESERVED_IDENTIFIER
|
#pragma clang diagnostic pop
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
@ -155,13 +155,13 @@ struct common_type<wide::integer<Bits, Signed>, Arithmetic>
|
|||||||
std::is_floating_point_v<Arithmetic>,
|
std::is_floating_point_v<Arithmetic>,
|
||||||
Arithmetic,
|
Arithmetic,
|
||||||
std::conditional_t<
|
std::conditional_t<
|
||||||
sizeof(Arithmetic) < Bits * sizeof(long),
|
sizeof(Arithmetic) * 8 < Bits,
|
||||||
wide::integer<Bits, Signed>,
|
wide::integer<Bits, Signed>,
|
||||||
std::conditional_t<
|
std::conditional_t<
|
||||||
Bits * sizeof(long) < sizeof(Arithmetic),
|
Bits < sizeof(Arithmetic) * 8,
|
||||||
Arithmetic,
|
Arithmetic,
|
||||||
std::conditional_t<
|
std::conditional_t<
|
||||||
Bits * sizeof(long) == sizeof(Arithmetic) && (std::is_same_v<Signed, signed> || std::is_signed_v<Arithmetic>),
|
Bits == sizeof(Arithmetic) * 8 && (std::is_same_v<Signed, signed> || std::is_signed_v<Arithmetic>),
|
||||||
Arithmetic,
|
Arithmetic,
|
||||||
wide::integer<Bits, Signed>>>>>;
|
wide::integer<Bits, Signed>>>>>;
|
||||||
};
|
};
|
||||||
@ -314,7 +314,14 @@ struct integer<Bits, Signed>::_impl
|
|||||||
|
|
||||||
const T alpha = t / static_cast<T>(max_int);
|
const T alpha = t / static_cast<T>(max_int);
|
||||||
|
|
||||||
if (alpha <= static_cast<T>(max_int))
|
/** Here we have to use strict comparison.
|
||||||
|
* The max_int is 2^64 - 1.
|
||||||
|
* When casted to floating point type, it will be rounded to the closest representable number,
|
||||||
|
* which is 2^64.
|
||||||
|
* But 2^64 is not representable in uint64_t,
|
||||||
|
* so the maximum representable number will be strictly less.
|
||||||
|
*/
|
||||||
|
if (alpha < static_cast<T>(max_int))
|
||||||
self = static_cast<uint64_t>(alpha);
|
self = static_cast<uint64_t>(alpha);
|
||||||
else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations.
|
else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations.
|
||||||
set_multiplier<double>(self, static_cast<double>(alpha));
|
set_multiplier<double>(self, static_cast<double>(alpha));
|
||||||
@ -360,7 +367,7 @@ struct integer<Bits, Signed>::_impl
|
|||||||
constexpr const unsigned to_copy = min_bits / base_bits;
|
constexpr const unsigned to_copy = min_bits / base_bits;
|
||||||
|
|
||||||
for (unsigned i = 0; i < to_copy; ++i)
|
for (unsigned i = 0; i < to_copy; ++i)
|
||||||
self.items[little(i)] = rhs.items[little(i)];
|
self.items[little(i)] = rhs.items[integer<Bits2, Signed2>::_impl::little(i)];
|
||||||
|
|
||||||
if constexpr (Bits > Bits2)
|
if constexpr (Bits > Bits2)
|
||||||
{
|
{
|
||||||
@ -732,9 +739,10 @@ public:
|
|||||||
if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(rhs)))
|
if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(rhs)))
|
||||||
return is_negative(rhs);
|
return is_negative(rhs);
|
||||||
|
|
||||||
|
integer<Bits, Signed> t = rhs;
|
||||||
for (unsigned i = 0; i < item_count; ++i)
|
for (unsigned i = 0; i < item_count; ++i)
|
||||||
{
|
{
|
||||||
base_type rhs_item = get_item(rhs, big(i));
|
base_type rhs_item = get_item(t, big(i));
|
||||||
|
|
||||||
if (lhs.items[big(i)] != rhs_item)
|
if (lhs.items[big(i)] != rhs_item)
|
||||||
return lhs.items[big(i)] > rhs_item;
|
return lhs.items[big(i)] > rhs_item;
|
||||||
@ -757,9 +765,10 @@ public:
|
|||||||
if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(rhs)))
|
if (std::numeric_limits<T>::is_signed && (is_negative(lhs) != is_negative(rhs)))
|
||||||
return is_negative(lhs);
|
return is_negative(lhs);
|
||||||
|
|
||||||
|
integer<Bits, Signed> t = rhs;
|
||||||
for (unsigned i = 0; i < item_count; ++i)
|
for (unsigned i = 0; i < item_count; ++i)
|
||||||
{
|
{
|
||||||
base_type rhs_item = get_item(rhs, big(i));
|
base_type rhs_item = get_item(t, big(i));
|
||||||
|
|
||||||
if (lhs.items[big(i)] != rhs_item)
|
if (lhs.items[big(i)] != rhs_item)
|
||||||
return lhs.items[big(i)] < rhs_item;
|
return lhs.items[big(i)] < rhs_item;
|
||||||
@ -779,9 +788,10 @@ public:
|
|||||||
{
|
{
|
||||||
if constexpr (should_keep_size<T>())
|
if constexpr (should_keep_size<T>())
|
||||||
{
|
{
|
||||||
|
integer<Bits, Signed> t = rhs;
|
||||||
for (unsigned i = 0; i < item_count; ++i)
|
for (unsigned i = 0; i < item_count; ++i)
|
||||||
{
|
{
|
||||||
base_type rhs_item = get_item(rhs, any(i));
|
base_type rhs_item = get_item(t, any(i));
|
||||||
|
|
||||||
if (lhs.items[any(i)] != rhs_item)
|
if (lhs.items[any(i)] != rhs_item)
|
||||||
return false;
|
return false;
|
||||||
@ -1239,7 +1249,7 @@ constexpr integer<Bits, Signed>::operator long double() const noexcept
|
|||||||
for (unsigned i = 0; i < _impl::item_count; ++i)
|
for (unsigned i = 0; i < _impl::item_count; ++i)
|
||||||
{
|
{
|
||||||
long double t = res;
|
long double t = res;
|
||||||
res *= std::numeric_limits<base_type>::max();
|
res *= static_cast<long double>(std::numeric_limits<base_type>::max());
|
||||||
res += t;
|
res += t;
|
||||||
res += tmp.items[_impl::big(i)];
|
res += tmp.items[_impl::big(i)];
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,6 @@ struct fmt::formatter<wide::integer<Bits, Signed>>
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const wide::integer<Bits, Signed> & value, FormatContext & ctx)
|
auto format(const wide::integer<Bits, Signed> & value, FormatContext & ctx)
|
||||||
{
|
{
|
||||||
return format_to(ctx.out(), "{}", to_string(value));
|
return fmt::format_to(ctx.out(), "{}", to_string(value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -195,7 +195,6 @@ long splice(int fd_in, off_t *off_in, int fd_out, off_t *off_out, size_t len, un
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if !defined(__aarch64__)
|
|
||||||
struct statx {
|
struct statx {
|
||||||
uint32_t stx_mask;
|
uint32_t stx_mask;
|
||||||
uint32_t stx_blksize;
|
uint32_t stx_blksize;
|
||||||
@ -226,7 +225,6 @@ int statx(int fd, const char *restrict path, int flag,
|
|||||||
{
|
{
|
||||||
return syscall(SYS_statx, fd, path, flag, mask, statxbuf);
|
return syscall(SYS_statx, fd, path, flag, mask, statxbuf);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <syscall.h>
|
#include <syscall.h>
|
||||||
@ -237,6 +235,17 @@ ssize_t getrandom(void *buf, size_t buflen, unsigned flags)
|
|||||||
return syscall(SYS_getrandom, buf, buflen, flags);
|
return syscall(SYS_getrandom, buf, buflen, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Structure for scatter/gather I/O. */
|
||||||
|
struct iovec
|
||||||
|
{
|
||||||
|
void *iov_base; /* Pointer to data. */
|
||||||
|
size_t iov_len; /* Length of data. */
|
||||||
|
};
|
||||||
|
|
||||||
|
ssize_t preadv(int __fd, const struct iovec *__iovec, int __count, __off_t __offset)
|
||||||
|
{
|
||||||
|
return syscall(SYS_preadv, __fd, __iovec, __count, (long)(__offset), (long)(__offset>>32));
|
||||||
|
}
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
81
base/glibc-compatibility/musl/expf.c
Normal file
81
base/glibc-compatibility/musl/expf.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
|
||||||
|
/*
|
||||||
|
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* ====================================================
|
||||||
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||||
|
* Permission to use, copy, modify, and distribute this
|
||||||
|
* software is freely granted, provided that this notice
|
||||||
|
* is preserved.
|
||||||
|
* ====================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libm.h"
|
||||||
|
|
||||||
|
static const float
|
||||||
|
half[2] = {0.5,-0.5},
|
||||||
|
ln2hi = 6.9314575195e-1f, /* 0x3f317200 */
|
||||||
|
ln2lo = 1.4286067653e-6f, /* 0x35bfbe8e */
|
||||||
|
invln2 = 1.4426950216e+0f, /* 0x3fb8aa3b */
|
||||||
|
/*
|
||||||
|
* Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
|
||||||
|
* |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
|
||||||
|
*/
|
||||||
|
P1 = 1.6666625440e-1f, /* 0xaaaa8f.0p-26 */
|
||||||
|
P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
|
||||||
|
|
||||||
|
float expf(float x)
|
||||||
|
{
|
||||||
|
float_t hi, lo, c, xx, y;
|
||||||
|
int k, sign;
|
||||||
|
uint32_t hx;
|
||||||
|
|
||||||
|
GET_FLOAT_WORD(hx, x);
|
||||||
|
sign = hx >> 31; /* sign bit of x */
|
||||||
|
hx &= 0x7fffffff; /* high word of |x| */
|
||||||
|
|
||||||
|
/* special cases */
|
||||||
|
if (hx >= 0x42aeac50) { /* if |x| >= -87.33655f or NaN */
|
||||||
|
if (hx >= 0x42b17218 && !sign) { /* x >= 88.722839f */
|
||||||
|
/* overflow */
|
||||||
|
x *= 0x1p127f;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
if (sign) {
|
||||||
|
/* underflow */
|
||||||
|
FORCE_EVAL(-0x1p-149f/x);
|
||||||
|
if (hx >= 0x42cff1b5) /* x <= -103.972084f */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* argument reduction */
|
||||||
|
if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */
|
||||||
|
if (hx > 0x3f851592) /* if |x| > 1.5 ln2 */
|
||||||
|
k = invln2*x + half[sign];
|
||||||
|
else
|
||||||
|
k = 1 - sign - sign;
|
||||||
|
hi = x - k*ln2hi; /* k*ln2hi is exact here */
|
||||||
|
lo = k*ln2lo;
|
||||||
|
x = hi - lo;
|
||||||
|
} else if (hx > 0x39000000) { /* |x| > 2**-14 */
|
||||||
|
k = 0;
|
||||||
|
hi = x;
|
||||||
|
lo = 0;
|
||||||
|
} else {
|
||||||
|
/* raise inexact */
|
||||||
|
FORCE_EVAL(0x1p127f + x);
|
||||||
|
return 1 + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* x is now in primary range */
|
||||||
|
xx = x*x;
|
||||||
|
c = x - xx*(P1+xx*P2);
|
||||||
|
y = 1 + (x*c/(2-c) - lo + hi);
|
||||||
|
if (k == 0)
|
||||||
|
return y;
|
||||||
|
return scalbnf(y, k);
|
||||||
|
}
|
@ -8,3 +8,8 @@ int fallocate(int fd, int mode, off_t base, off_t len)
|
|||||||
{
|
{
|
||||||
return syscall(SYS_fallocate, fd, mode, base, len);
|
return syscall(SYS_fallocate, fd, mode, base, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fallocate64(int fd, int mode, off_t base, off_t len)
|
||||||
|
{
|
||||||
|
return fallocate(fd, mode, base, len);
|
||||||
|
}
|
||||||
|
@ -78,9 +78,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Disable warnings by PVS-Studio
|
|
||||||
//-V::GA
|
|
||||||
|
|
||||||
static const double
|
static const double
|
||||||
pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
|
pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
|
||||||
a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
|
a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
|
||||||
|
@ -85,9 +85,6 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Disable warnings by PVS-Studio
|
|
||||||
//-V::GA
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "libm.h"
|
#include "libm.h"
|
||||||
|
@ -155,7 +155,7 @@ static inline long double fp_barrierl(long double x)
|
|||||||
static inline void fp_force_evalf(float x)
|
static inline void fp_force_evalf(float x)
|
||||||
{
|
{
|
||||||
volatile float y;
|
volatile float y;
|
||||||
y = x; //-V1001
|
y = x;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ static inline void fp_force_evalf(float x)
|
|||||||
static inline void fp_force_eval(double x)
|
static inline void fp_force_eval(double x)
|
||||||
{
|
{
|
||||||
volatile double y;
|
volatile double y;
|
||||||
y = x; //-V1001
|
y = x;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -173,7 +173,7 @@ static inline void fp_force_eval(double x)
|
|||||||
static inline void fp_force_evall(long double x)
|
static inline void fp_force_evall(long double x)
|
||||||
{
|
{
|
||||||
volatile long double y;
|
volatile long double y;
|
||||||
y = x; //-V1001
|
y = x;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ float logf(float x)
|
|||||||
tmp = ix - OFF;
|
tmp = ix - OFF;
|
||||||
i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
|
i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
|
||||||
k = (int32_t)tmp >> 23; /* arithmetic shift */
|
k = (int32_t)tmp >> 23; /* arithmetic shift */
|
||||||
iz = ix - (tmp & 0x1ff << 23);
|
iz = ix - (tmp & 0xff800000);
|
||||||
invc = T[i].invc;
|
invc = T[i].invc;
|
||||||
logc = T[i].logc;
|
logc = T[i].logc;
|
||||||
z = (double_t)asfloat(iz);
|
z = (double_t)asfloat(iz);
|
||||||
|
@ -3,9 +3,6 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Disable warnings by PVS-Studio
|
|
||||||
//-V::GA
|
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "libm.h"
|
#include "libm.h"
|
||||||
|
@ -9,3 +9,8 @@ ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs)
|
|||||||
/// There was cancellable syscall (syscall_cp), but I don't care.
|
/// There was cancellable syscall (syscall_cp), but I don't care.
|
||||||
return syscall(SYS_pwritev, fd, iov, count, (long)(ofs), (long)(ofs>>32));
|
return syscall(SYS_pwritev, fd, iov, count, (long)(ofs), (long)(ofs>>32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t pwritev64(int fd, const struct iovec *iov, int count, off_t ofs)
|
||||||
|
{
|
||||||
|
return pwritev(fd, iov, count, ofs);
|
||||||
|
}
|
||||||
|
31
base/glibc-compatibility/musl/scalbnf.c
Normal file
31
base/glibc-compatibility/musl/scalbnf.c
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
float scalbnf(float x, int n)
|
||||||
|
{
|
||||||
|
union {float f; uint32_t i;} u;
|
||||||
|
float_t y = x;
|
||||||
|
|
||||||
|
if (n > 127) {
|
||||||
|
y *= 0x1p127f;
|
||||||
|
n -= 127;
|
||||||
|
if (n > 127) {
|
||||||
|
y *= 0x1p127f;
|
||||||
|
n -= 127;
|
||||||
|
if (n > 127)
|
||||||
|
n = 127;
|
||||||
|
}
|
||||||
|
} else if (n < -126) {
|
||||||
|
y *= 0x1p-126f;
|
||||||
|
n += 126;
|
||||||
|
if (n < -126) {
|
||||||
|
y *= 0x1p-126f;
|
||||||
|
n += 126;
|
||||||
|
if (n < -126)
|
||||||
|
n = -126;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
u.i = (uint32_t)(0x7f+n)<<23;
|
||||||
|
x = y * u.f;
|
||||||
|
return x;
|
||||||
|
}
|
@ -31,7 +31,8 @@ TRAP(argp_state_help)
|
|||||||
TRAP(argp_usage)
|
TRAP(argp_usage)
|
||||||
TRAP(asctime)
|
TRAP(asctime)
|
||||||
TRAP(clearenv)
|
TRAP(clearenv)
|
||||||
TRAP(crypt)
|
// Redefined at contrib/libbcrypt/crypt_blowfish/wrapper.c:186
|
||||||
|
// TRAP(crypt)
|
||||||
TRAP(ctime)
|
TRAP(ctime)
|
||||||
TRAP(cuserid)
|
TRAP(cuserid)
|
||||||
TRAP(drand48)
|
TRAP(drand48)
|
||||||
|
@ -455,7 +455,7 @@ auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)
|
|||||||
typedef typename RngType::result_type rtype;
|
typedef typename RngType::result_type rtype;
|
||||||
rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
|
rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
|
||||||
% upper_bound;
|
% upper_bound;
|
||||||
for (;;) { //-V1044
|
for (;;) {
|
||||||
rtype r = rng() - RngType::min();
|
rtype r = rng() - RngType::min();
|
||||||
if (r >= threshold)
|
if (r >= threshold)
|
||||||
return r % upper_bound;
|
return r % upper_bound;
|
||||||
|
@ -930,7 +930,7 @@ struct rxs_m_xs_mixin {
|
|||||||
constexpr bitcount_t shift = bits - xtypebits;
|
constexpr bitcount_t shift = bits - xtypebits;
|
||||||
constexpr bitcount_t mask = (1 << opbits) - 1;
|
constexpr bitcount_t mask = (1 << opbits) - 1;
|
||||||
bitcount_t rshift =
|
bitcount_t rshift =
|
||||||
opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0; //-V547
|
opbits ? bitcount_t(internal >> (bits - opbits)) & mask : 0;
|
||||||
internal ^= internal >> (opbits + rshift);
|
internal ^= internal >> (opbits + rshift);
|
||||||
internal *= mcg_multiplier<itype>::multiplier();
|
internal *= mcg_multiplier<itype>::multiplier();
|
||||||
xtype result = internal >> shift;
|
xtype result = internal >> shift;
|
||||||
@ -952,7 +952,7 @@ struct rxs_m_xs_mixin {
|
|||||||
|
|
||||||
internal *= mcg_unmultiplier<itype>::unmultiplier();
|
internal *= mcg_unmultiplier<itype>::unmultiplier();
|
||||||
|
|
||||||
bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; //-V547
|
bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;
|
||||||
internal = unxorshift(internal, bits, opbits + rshift);
|
internal = unxorshift(internal, bits, opbits + rshift);
|
||||||
|
|
||||||
return internal;
|
return internal;
|
||||||
@ -977,7 +977,7 @@ struct rxs_m_mixin {
|
|||||||
: 2;
|
: 2;
|
||||||
constexpr bitcount_t shift = bits - xtypebits;
|
constexpr bitcount_t shift = bits - xtypebits;
|
||||||
constexpr bitcount_t mask = (1 << opbits) - 1;
|
constexpr bitcount_t mask = (1 << opbits) - 1;
|
||||||
bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0; //-V547
|
bitcount_t rshift = opbits ? (internal >> (bits - opbits)) & mask : 0;
|
||||||
internal ^= internal >> (opbits + rshift);
|
internal ^= internal >> (opbits + rshift);
|
||||||
internal *= mcg_multiplier<itype>::multiplier();
|
internal *= mcg_multiplier<itype>::multiplier();
|
||||||
xtype result = internal >> shift;
|
xtype result = internal >> shift;
|
||||||
@ -1368,7 +1368,7 @@ void extended<table_pow2,advance_pow2,baseclass,extvalclass,kdd>::selfinit()
|
|||||||
// - any strange correlations would only be apparent if we
|
// - any strange correlations would only be apparent if we
|
||||||
// were to backstep the generator so that the base generator
|
// were to backstep the generator so that the base generator
|
||||||
// was generating the same values again
|
// was generating the same values again
|
||||||
result_type xdiff = baseclass::operator()() - baseclass::operator()(); //-V501
|
result_type xdiff = baseclass::operator()() - baseclass::operator()();
|
||||||
for (size_t i = 0; i < table_size; ++i) {
|
for (size_t i = 0; i < table_size; ++i) {
|
||||||
data_[i] = baseclass::operator()() ^ xdiff;
|
data_[i] = baseclass::operator()() ^ xdiff;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ if (ENABLE_SSL)
|
|||||||
-Wno-unreachable-code-return
|
-Wno-unreachable-code-return
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
-Wno-zero-as-null-pointer-constant
|
-Wno-zero-as-null-pointer-constant
|
||||||
|
-Wno-used-but-marked-unused
|
||||||
)
|
)
|
||||||
target_include_directories (_poco_crypto SYSTEM PUBLIC "include")
|
target_include_directories (_poco_crypto SYSTEM PUBLIC "include")
|
||||||
target_link_libraries (_poco_crypto PUBLIC Poco::Foundation OpenSSL::SSL OpenSSL::Crypto)
|
target_link_libraries (_poco_crypto PUBLIC Poco::Foundation OpenSSL::SSL OpenSSL::Crypto)
|
||||||
|
@ -18,121 +18,124 @@
|
|||||||
#define Crypto_Cipher_INCLUDED
|
#define Crypto_Cipher_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/RefCountedObject.h"
|
|
||||||
#include "Poco/AutoPtr.h"
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
#include "Poco/RefCountedObject.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class CryptoTransform;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API Cipher: public Poco::RefCountedObject
|
|
||||||
/// Represents the abstract base class from which all implementations of
|
|
||||||
/// symmetric/asymmetric encryption algorithms must inherit. Use the CipherFactory
|
|
||||||
/// class to obtain an instance of this class:
|
|
||||||
///
|
|
||||||
/// CipherFactory& factory = CipherFactory::defaultFactory();
|
|
||||||
/// // Creates a 256-bit AES cipher
|
|
||||||
/// Cipher* pCipher = factory.createCipher(CipherKey("aes-256"));
|
|
||||||
/// Cipher* pRSACipher = factory.createCipher(RSAKey(RSAKey::KL_1024, RSAKey::EXP_SMALL));
|
|
||||||
///
|
|
||||||
/// Check the different Key constructors on how to initialize/create
|
|
||||||
/// a key. The above example auto-generates random keys.
|
|
||||||
///
|
|
||||||
/// Note that you won't be able to decrypt data encrypted with a random key
|
|
||||||
/// once the Cipher is destroyed unless you persist the generated key and IV.
|
|
||||||
/// An example usage for random keys is to encrypt data saved in a temporary
|
|
||||||
/// file.
|
|
||||||
///
|
|
||||||
/// Once your key is set up, you can use the Cipher object to encrypt or
|
|
||||||
/// decrypt strings or, in conjunction with a CryptoInputStream or a
|
|
||||||
/// CryptoOutputStream, to encrypt streams of data.
|
|
||||||
///
|
|
||||||
/// Since encrypted strings will contain arbitrary binary data that will cause
|
|
||||||
/// problems in applications that are not binary-safe (eg., when sending
|
|
||||||
/// encrypted data in e-mails), the encryptString() and decryptString() can
|
|
||||||
/// encode (or decode, respectively) encrypted data using a "transport encoding".
|
|
||||||
/// Supported encodings are Base64 and BinHex.
|
|
||||||
///
|
|
||||||
/// The following example encrypts and decrypts a string utilizing Base64
|
|
||||||
/// encoding:
|
|
||||||
///
|
|
||||||
/// std::string plainText = "This is my secret information";
|
|
||||||
/// std::string encrypted = pCipher->encryptString(plainText, Cipher::ENC_BASE64);
|
|
||||||
/// std::string decrypted = pCipher->decryptString(encrypted, Cipher::ENC_BASE64);
|
|
||||||
///
|
|
||||||
/// In order to encrypt a stream of data (eg. to encrypt files), you can use
|
|
||||||
/// a CryptoStream:
|
|
||||||
///
|
|
||||||
/// // Create an output stream that will encrypt all data going through it
|
|
||||||
/// // and write pass it to the underlying file stream.
|
|
||||||
/// Poco::FileOutputStream sink("encrypted.dat");
|
|
||||||
/// CryptoOutputStream encryptor(sink, pCipher->createEncryptor());
|
|
||||||
///
|
|
||||||
/// Poco::FileInputStream source("source.txt");
|
|
||||||
/// Poco::StreamCopier::copyStream(source, encryptor);
|
|
||||||
///
|
|
||||||
/// // Always close output streams to flush all internal buffers
|
|
||||||
/// encryptor.close();
|
|
||||||
/// sink.close();
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
typedef Poco::AutoPtr<Cipher> Ptr;
|
|
||||||
typedef std::vector<unsigned char> ByteVec;
|
|
||||||
|
|
||||||
enum Encoding
|
|
||||||
/// Transport encoding to use for encryptString() and decryptString().
|
|
||||||
{
|
|
||||||
ENC_NONE = 0x00, /// Plain binary output
|
|
||||||
ENC_BASE64 = 0x01, /// Base64-encoded output
|
|
||||||
ENC_BINHEX = 0x02, /// BinHex-encoded output
|
|
||||||
ENC_BASE64_NO_LF = 0x81, /// Base64-encoded output, no linefeeds
|
|
||||||
ENC_BINHEX_NO_LF = 0x82 /// BinHex-encoded output, no linefeeds
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Cipher();
|
|
||||||
/// Destroys the Cipher.
|
|
||||||
|
|
||||||
virtual const std::string& name() const = 0;
|
|
||||||
/// Returns the name of the Cipher.
|
|
||||||
|
|
||||||
virtual CryptoTransform* createEncryptor() = 0;
|
|
||||||
/// Creates an encryptor object to be used with a CryptoStream.
|
|
||||||
|
|
||||||
virtual CryptoTransform* createDecryptor() = 0;
|
|
||||||
/// Creates a decryptor object to be used with a CryptoStream.
|
|
||||||
|
|
||||||
virtual std::string encryptString(const std::string& str, Encoding encoding = ENC_NONE);
|
|
||||||
/// Directly encrypt a string and encode it using the given encoding.
|
|
||||||
|
|
||||||
virtual std::string decryptString(const std::string& str, Encoding encoding = ENC_NONE);
|
|
||||||
/// Directly decrypt a string that is encoded with the given encoding.
|
|
||||||
|
|
||||||
virtual void encrypt(std::istream& source, std::ostream& sink, Encoding encoding = ENC_NONE);
|
|
||||||
/// Directly encrypts an input stream and encodes it using the given encoding.
|
|
||||||
|
|
||||||
virtual void decrypt(std::istream& source, std::ostream& sink, Encoding encoding = ENC_NONE);
|
|
||||||
/// Directly decrypt an input stream that is encoded with the given encoding.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Cipher();
|
|
||||||
/// Creates a new Cipher object.
|
|
||||||
|
|
||||||
private:
|
|
||||||
Cipher(const Cipher&);
|
|
||||||
Cipher& operator = (const Cipher&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class CryptoTransform;
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API Cipher : public Poco::RefCountedObject
|
||||||
|
/// Represents the abstract base class from which all implementations of
|
||||||
|
/// symmetric/asymmetric encryption algorithms must inherit. Use the CipherFactory
|
||||||
|
/// class to obtain an instance of this class:
|
||||||
|
///
|
||||||
|
/// CipherFactory& factory = CipherFactory::defaultFactory();
|
||||||
|
/// // Creates a 256-bit AES cipher
|
||||||
|
/// Cipher* pCipher = factory.createCipher(CipherKey("aes-256"));
|
||||||
|
/// Cipher* pRSACipher = factory.createCipher(RSAKey(RSAKey::KL_1024, RSAKey::EXP_SMALL));
|
||||||
|
///
|
||||||
|
/// Check the different Key constructors on how to initialize/create
|
||||||
|
/// a key. The above example auto-generates random keys.
|
||||||
|
///
|
||||||
|
/// Note that you won't be able to decrypt data encrypted with a random key
|
||||||
|
/// once the Cipher is destroyed unless you persist the generated key and IV.
|
||||||
|
/// An example usage for random keys is to encrypt data saved in a temporary
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// Once your key is set up, you can use the Cipher object to encrypt or
|
||||||
|
/// decrypt strings or, in conjunction with a CryptoInputStream or a
|
||||||
|
/// CryptoOutputStream, to encrypt streams of data.
|
||||||
|
///
|
||||||
|
/// Since encrypted strings will contain arbitrary binary data that will cause
|
||||||
|
/// problems in applications that are not binary-safe (eg., when sending
|
||||||
|
/// encrypted data in e-mails), the encryptString() and decryptString() can
|
||||||
|
/// encode (or decode, respectively) encrypted data using a "transport encoding".
|
||||||
|
/// Supported encodings are Base64 and BinHex.
|
||||||
|
///
|
||||||
|
/// The following example encrypts and decrypts a string utilizing Base64
|
||||||
|
/// encoding:
|
||||||
|
///
|
||||||
|
/// std::string plainText = "This is my secret information";
|
||||||
|
/// std::string encrypted = pCipher->encryptString(plainText, Cipher::ENC_BASE64);
|
||||||
|
/// std::string decrypted = pCipher->decryptString(encrypted, Cipher::ENC_BASE64);
|
||||||
|
///
|
||||||
|
/// In order to encrypt a stream of data (eg. to encrypt files), you can use
|
||||||
|
/// a CryptoStream:
|
||||||
|
///
|
||||||
|
/// // Create an output stream that will encrypt all data going through it
|
||||||
|
/// // and write pass it to the underlying file stream.
|
||||||
|
/// Poco::FileOutputStream sink("encrypted.dat");
|
||||||
|
/// CryptoOutputStream encryptor(sink, pCipher->createEncryptor());
|
||||||
|
///
|
||||||
|
/// Poco::FileInputStream source("source.txt");
|
||||||
|
/// Poco::StreamCopier::copyStream(source, encryptor);
|
||||||
|
///
|
||||||
|
/// // Always close output streams to flush all internal buffers
|
||||||
|
/// encryptor.close();
|
||||||
|
/// sink.close();
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Poco::AutoPtr<Cipher> Ptr;
|
||||||
|
typedef std::vector<unsigned char> ByteVec;
|
||||||
|
|
||||||
|
enum Encoding
|
||||||
|
/// Transport encoding to use for encryptString() and decryptString().
|
||||||
|
{
|
||||||
|
ENC_NONE = 0x00, /// Plain binary output
|
||||||
|
ENC_BASE64 = 0x01, /// Base64-encoded output
|
||||||
|
ENC_BINHEX = 0x02, /// BinHex-encoded output
|
||||||
|
ENC_BASE64_NO_LF = 0x81, /// Base64-encoded output, no linefeeds
|
||||||
|
ENC_BINHEX_NO_LF = 0x82 /// BinHex-encoded output, no linefeeds
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~Cipher();
|
||||||
|
/// Destroys the Cipher.
|
||||||
|
|
||||||
|
virtual const std::string & name() const = 0;
|
||||||
|
/// Returns the name of the Cipher.
|
||||||
|
|
||||||
|
virtual CryptoTransform * createEncryptor() = 0;
|
||||||
|
/// Creates an encryptor object to be used with a CryptoStream.
|
||||||
|
|
||||||
|
virtual CryptoTransform * createDecryptor() = 0;
|
||||||
|
/// Creates a decryptor object to be used with a CryptoStream.
|
||||||
|
|
||||||
|
virtual std::string encryptString(const std::string & str, Encoding encoding = ENC_NONE);
|
||||||
|
/// Directly encrypt a string and encode it using the given encoding.
|
||||||
|
|
||||||
|
virtual std::string decryptString(const std::string & str, Encoding encoding = ENC_NONE);
|
||||||
|
/// Directly decrypt a string that is encoded with the given encoding.
|
||||||
|
|
||||||
|
virtual void encrypt(std::istream & source, std::ostream & sink, Encoding encoding = ENC_NONE);
|
||||||
|
/// Directly encrypts an input stream and encodes it using the given encoding.
|
||||||
|
|
||||||
|
virtual void decrypt(std::istream & source, std::ostream & sink, Encoding encoding = ENC_NONE);
|
||||||
|
/// Directly decrypt an input stream that is encoded with the given encoding.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Cipher();
|
||||||
|
/// Creates a new Cipher object.
|
||||||
|
|
||||||
|
private:
|
||||||
|
Cipher(const Cipher &);
|
||||||
|
Cipher & operator=(const Cipher &);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_Cipher_INCLUDED
|
#endif // Crypto_Cipher_INCLUDED
|
||||||
|
@ -21,55 +21,58 @@
|
|||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class Cipher;
|
|
||||||
class CipherKey;
|
|
||||||
class RSAKey;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CipherFactory
|
|
||||||
/// A factory for Cipher objects. See the Cipher class for examples on how to
|
|
||||||
/// use the CipherFactory.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
CipherFactory();
|
|
||||||
/// Creates a new CipherFactory object.
|
|
||||||
|
|
||||||
virtual ~CipherFactory();
|
|
||||||
/// Destroys the CipherFactory.
|
|
||||||
|
|
||||||
Cipher* createCipher(const CipherKey& key);
|
|
||||||
/// Creates a Cipher object for the given Cipher name. Valid cipher
|
|
||||||
/// names depend on the OpenSSL version the library is linked with;
|
|
||||||
/// see the output of
|
|
||||||
///
|
|
||||||
/// openssl enc --help
|
|
||||||
///
|
|
||||||
/// for a list of supported block and stream ciphers.
|
|
||||||
///
|
|
||||||
/// Common examples are:
|
|
||||||
///
|
|
||||||
/// * AES: "aes-128", "aes-256"
|
|
||||||
/// * DES: "des", "des3"
|
|
||||||
/// * Blowfish: "bf"
|
|
||||||
|
|
||||||
Cipher* createCipher(const RSAKey& key, RSAPaddingMode paddingMode = RSA_PADDING_PKCS1);
|
|
||||||
/// Creates a RSACipher using the given RSA key and padding mode
|
|
||||||
/// for public key encryption/private key decryption.
|
|
||||||
|
|
||||||
static CipherFactory& defaultFactory();
|
|
||||||
/// Returns the default CipherFactory.
|
|
||||||
|
|
||||||
private:
|
|
||||||
CipherFactory(const CipherFactory&);
|
|
||||||
CipherFactory& operator = (const CipherFactory&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class Cipher;
|
||||||
|
class CipherKey;
|
||||||
|
class RSAKey;
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API CipherFactory
|
||||||
|
/// A factory for Cipher objects. See the Cipher class for examples on how to
|
||||||
|
/// use the CipherFactory.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CipherFactory();
|
||||||
|
/// Creates a new CipherFactory object.
|
||||||
|
|
||||||
|
virtual ~CipherFactory();
|
||||||
|
/// Destroys the CipherFactory.
|
||||||
|
|
||||||
|
Cipher * createCipher(const CipherKey & key);
|
||||||
|
/// Creates a Cipher object for the given Cipher name. Valid cipher
|
||||||
|
/// names depend on the OpenSSL version the library is linked with;
|
||||||
|
/// see the output of
|
||||||
|
///
|
||||||
|
/// openssl enc --help
|
||||||
|
///
|
||||||
|
/// for a list of supported block and stream ciphers.
|
||||||
|
///
|
||||||
|
/// Common examples are:
|
||||||
|
///
|
||||||
|
/// * AES: "aes-128", "aes-256"
|
||||||
|
/// * DES: "des", "des3"
|
||||||
|
/// * Blowfish: "bf"
|
||||||
|
|
||||||
|
Cipher * createCipher(const RSAKey & key, RSAPaddingMode paddingMode = RSA_PADDING_PKCS1);
|
||||||
|
/// Creates a RSACipher using the given RSA key and padding mode
|
||||||
|
/// for public key encryption/private key decryption.
|
||||||
|
|
||||||
|
static CipherFactory & defaultFactory();
|
||||||
|
/// Returns the default CipherFactory.
|
||||||
|
|
||||||
|
private:
|
||||||
|
CipherFactory(const CipherFactory &);
|
||||||
|
CipherFactory & operator=(const CipherFactory &);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CipherFactory_INCLUDED
|
#endif // Crypto_CipherFactory_INCLUDED
|
||||||
|
@ -18,52 +18,55 @@
|
|||||||
#define Crypto_CipherImpl_INCLUDED
|
#define Crypto_CipherImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include <openssl/evp.h>
|
||||||
#include "Poco/Crypto/Cipher.h"
|
#include "Poco/Crypto/Cipher.h"
|
||||||
#include "Poco/Crypto/CipherKey.h"
|
#include "Poco/Crypto/CipherKey.h"
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include <openssl/evp.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class CipherImpl: public Cipher
|
|
||||||
/// An implementation of the Cipher class for OpenSSL's crypto library.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
CipherImpl(const CipherKey& key);
|
|
||||||
/// Creates a new CipherImpl object for the given CipherKey.
|
|
||||||
|
|
||||||
virtual ~CipherImpl();
|
|
||||||
/// Destroys the CipherImpl.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns the name of the cipher.
|
|
||||||
|
|
||||||
CryptoTransform* createEncryptor();
|
|
||||||
/// Creates an encryptor object.
|
|
||||||
|
|
||||||
CryptoTransform* createDecryptor();
|
|
||||||
/// Creates a decryptor object.
|
|
||||||
|
|
||||||
private:
|
|
||||||
CipherKey _key;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Inlines
|
|
||||||
//
|
|
||||||
inline const std::string& CipherImpl::name() const
|
|
||||||
{
|
{
|
||||||
return _key.name();
|
|
||||||
|
|
||||||
|
class CipherImpl : public Cipher
|
||||||
|
/// An implementation of the Cipher class for OpenSSL's crypto library.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CipherImpl(const CipherKey & key);
|
||||||
|
/// Creates a new CipherImpl object for the given CipherKey.
|
||||||
|
|
||||||
|
virtual ~CipherImpl();
|
||||||
|
/// Destroys the CipherImpl.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns the name of the cipher.
|
||||||
|
|
||||||
|
CryptoTransform * createEncryptor();
|
||||||
|
/// Creates an encryptor object.
|
||||||
|
|
||||||
|
CryptoTransform * createDecryptor();
|
||||||
|
/// Creates a decryptor object.
|
||||||
|
|
||||||
|
private:
|
||||||
|
CipherKey _key;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inlines
|
||||||
|
//
|
||||||
|
inline const std::string & CipherImpl::name() const
|
||||||
|
{
|
||||||
|
return _key.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CipherImpl_INCLUDED
|
#endif // Crypto_CipherImpl_INCLUDED
|
||||||
|
@ -18,184 +18,186 @@
|
|||||||
#define Crypto_CipherKey_INCLUDED
|
#define Crypto_CipherKey_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/Crypto/CipherKeyImpl.h"
|
#include "Poco/Crypto/CipherKeyImpl.h"
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CipherKey
|
|
||||||
/// CipherKey stores the key information for decryption/encryption of data.
|
|
||||||
/// To create a random key, using the following code:
|
|
||||||
///
|
|
||||||
/// CipherKey key("aes-256");
|
|
||||||
///
|
|
||||||
/// Note that you won't be able to decrypt data encrypted with a random key
|
|
||||||
/// once the Cipher is destroyed unless you persist the generated key and IV.
|
|
||||||
/// An example usage for random keys is to encrypt data saved in a temporary
|
|
||||||
/// file.
|
|
||||||
///
|
|
||||||
/// To create a key using a human-readable password
|
|
||||||
/// string, use the following code. We create a AES Cipher and
|
|
||||||
/// use a salt value to make the key more robust:
|
|
||||||
///
|
|
||||||
/// std::string password = "secret";
|
|
||||||
/// std::string salt("asdff8723lasdf(**923412");
|
|
||||||
/// CipherKey key("aes-256", password, salt);
|
|
||||||
///
|
|
||||||
/// You may also control the digest and the number of iterations used to generate the key
|
|
||||||
/// by specifying the specific values. Here we create a key with the same data as before,
|
|
||||||
/// except that we use 100 iterations instead of DEFAULT_ITERATION_COUNT, and sha1 instead of
|
|
||||||
/// the default md5:
|
|
||||||
///
|
|
||||||
/// std::string password = "secret";
|
|
||||||
/// std::string salt("asdff8723lasdf(**923412");
|
|
||||||
/// std::string digest ("sha1");
|
|
||||||
/// CipherKey key("aes-256", password, salt, 100, digest);
|
|
||||||
///
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
typedef CipherKeyImpl::Mode Mode;
|
|
||||||
typedef CipherKeyImpl::ByteVec ByteVec;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
DEFAULT_ITERATION_COUNT = 2000
|
|
||||||
/// Default iteration count to use with
|
|
||||||
/// generateKey(). RSA security recommends
|
|
||||||
/// an iteration count of at least 1000.
|
|
||||||
};
|
|
||||||
|
|
||||||
CipherKey(const std::string& name,
|
|
||||||
const std::string& passphrase,
|
|
||||||
const std::string& salt = "",
|
|
||||||
int iterationCount = DEFAULT_ITERATION_COUNT,
|
|
||||||
const std::string& digest = "md5");
|
|
||||||
/// Creates a new CipherKeyImpl object using the given
|
|
||||||
/// cipher name, passphrase, salt value, iteration count and digest.
|
|
||||||
|
|
||||||
CipherKey(const std::string& name,
|
|
||||||
const ByteVec& key,
|
|
||||||
const ByteVec& iv);
|
|
||||||
/// Creates a new CipherKeyImpl object using the given cipher
|
|
||||||
/// name, key and initialization vector (IV).
|
|
||||||
///
|
|
||||||
/// The size of the IV must match the cipher's expected
|
|
||||||
/// IV size (see ivSize()), except for GCM mode, which allows
|
|
||||||
/// a custom IV size.
|
|
||||||
|
|
||||||
CipherKey(const std::string& name);
|
|
||||||
/// Creates a new CipherKeyImpl object. Autoinitializes key and
|
|
||||||
/// initialization vector.
|
|
||||||
|
|
||||||
~CipherKey();
|
|
||||||
/// Destroys the CipherKeyImpl.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns the name of the Cipher.
|
|
||||||
|
|
||||||
int keySize() const;
|
|
||||||
/// Returns the key size of the Cipher.
|
|
||||||
|
|
||||||
int blockSize() const;
|
|
||||||
/// Returns the block size of the Cipher.
|
|
||||||
|
|
||||||
int ivSize() const;
|
|
||||||
/// Returns the IV size of the Cipher.
|
|
||||||
|
|
||||||
Mode mode() const;
|
|
||||||
/// Returns the Cipher's mode of operation.
|
|
||||||
|
|
||||||
const ByteVec& getKey() const;
|
|
||||||
/// Returns the key for the Cipher.
|
|
||||||
|
|
||||||
void setKey(const ByteVec& key);
|
|
||||||
/// Sets the key for the Cipher.
|
|
||||||
|
|
||||||
const ByteVec& getIV() const;
|
|
||||||
/// Returns the initialization vector (IV) for the Cipher.
|
|
||||||
|
|
||||||
void setIV(const ByteVec& iv);
|
|
||||||
/// Sets the initialization vector (IV) for the Cipher.
|
|
||||||
///
|
|
||||||
/// The size of the vector must match the cipher's expected
|
|
||||||
/// IV size (see ivSize()), except for GCM mode, which allows
|
|
||||||
/// a custom IV size.
|
|
||||||
|
|
||||||
CipherKeyImpl::Ptr impl();
|
|
||||||
/// Returns the impl object
|
|
||||||
|
|
||||||
private:
|
|
||||||
CipherKeyImpl::Ptr _pImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline const std::string& CipherKey::name() const
|
|
||||||
{
|
{
|
||||||
return _pImpl->name();
|
|
||||||
|
|
||||||
|
class Crypto_API CipherKey
|
||||||
|
/// CipherKey stores the key information for decryption/encryption of data.
|
||||||
|
/// To create a random key, using the following code:
|
||||||
|
///
|
||||||
|
/// CipherKey key("aes-256");
|
||||||
|
///
|
||||||
|
/// Note that you won't be able to decrypt data encrypted with a random key
|
||||||
|
/// once the Cipher is destroyed unless you persist the generated key and IV.
|
||||||
|
/// An example usage for random keys is to encrypt data saved in a temporary
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// To create a key using a human-readable password
|
||||||
|
/// string, use the following code. We create a AES Cipher and
|
||||||
|
/// use a salt value to make the key more robust:
|
||||||
|
///
|
||||||
|
/// std::string password = "secret";
|
||||||
|
/// std::string salt("asdff8723lasdf(**923412");
|
||||||
|
/// CipherKey key("aes-256", password, salt);
|
||||||
|
///
|
||||||
|
/// You may also control the digest and the number of iterations used to generate the key
|
||||||
|
/// by specifying the specific values. Here we create a key with the same data as before,
|
||||||
|
/// except that we use 100 iterations instead of DEFAULT_ITERATION_COUNT, and sha1 instead of
|
||||||
|
/// the default md5:
|
||||||
|
///
|
||||||
|
/// std::string password = "secret";
|
||||||
|
/// std::string salt("asdff8723lasdf(**923412");
|
||||||
|
/// std::string digest ("sha1");
|
||||||
|
/// CipherKey key("aes-256", password, salt, 100, digest);
|
||||||
|
///
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef CipherKeyImpl::Mode Mode;
|
||||||
|
typedef CipherKeyImpl::ByteVec ByteVec;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DEFAULT_ITERATION_COUNT = 2000
|
||||||
|
/// Default iteration count to use with
|
||||||
|
/// generateKey(). RSA security recommends
|
||||||
|
/// an iteration count of at least 1000.
|
||||||
|
};
|
||||||
|
|
||||||
|
CipherKey(
|
||||||
|
const std::string & name,
|
||||||
|
const std::string & passphrase,
|
||||||
|
const std::string & salt = "",
|
||||||
|
int iterationCount = DEFAULT_ITERATION_COUNT,
|
||||||
|
const std::string & digest = "md5");
|
||||||
|
/// Creates a new CipherKeyImpl object using the given
|
||||||
|
/// cipher name, passphrase, salt value, iteration count and digest.
|
||||||
|
|
||||||
|
CipherKey(const std::string & name, const ByteVec & key, const ByteVec & iv);
|
||||||
|
/// Creates a new CipherKeyImpl object using the given cipher
|
||||||
|
/// name, key and initialization vector (IV).
|
||||||
|
///
|
||||||
|
/// The size of the IV must match the cipher's expected
|
||||||
|
/// IV size (see ivSize()), except for GCM mode, which allows
|
||||||
|
/// a custom IV size.
|
||||||
|
|
||||||
|
CipherKey(const std::string & name);
|
||||||
|
/// Creates a new CipherKeyImpl object. Autoinitializes key and
|
||||||
|
/// initialization vector.
|
||||||
|
|
||||||
|
~CipherKey();
|
||||||
|
/// Destroys the CipherKeyImpl.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns the name of the Cipher.
|
||||||
|
|
||||||
|
int keySize() const;
|
||||||
|
/// Returns the key size of the Cipher.
|
||||||
|
|
||||||
|
int blockSize() const;
|
||||||
|
/// Returns the block size of the Cipher.
|
||||||
|
|
||||||
|
int ivSize() const;
|
||||||
|
/// Returns the IV size of the Cipher.
|
||||||
|
|
||||||
|
Mode mode() const;
|
||||||
|
/// Returns the Cipher's mode of operation.
|
||||||
|
|
||||||
|
const ByteVec & getKey() const;
|
||||||
|
/// Returns the key for the Cipher.
|
||||||
|
|
||||||
|
void setKey(const ByteVec & key);
|
||||||
|
/// Sets the key for the Cipher.
|
||||||
|
|
||||||
|
const ByteVec & getIV() const;
|
||||||
|
/// Returns the initialization vector (IV) for the Cipher.
|
||||||
|
|
||||||
|
void setIV(const ByteVec & iv);
|
||||||
|
/// Sets the initialization vector (IV) for the Cipher.
|
||||||
|
///
|
||||||
|
/// The size of the vector must match the cipher's expected
|
||||||
|
/// IV size (see ivSize()), except for GCM mode, which allows
|
||||||
|
/// a custom IV size.
|
||||||
|
|
||||||
|
CipherKeyImpl::Ptr impl();
|
||||||
|
/// Returns the impl object
|
||||||
|
|
||||||
|
private:
|
||||||
|
CipherKeyImpl::Ptr _pImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline const std::string & CipherKey::name() const
|
||||||
|
{
|
||||||
|
return _pImpl->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int CipherKey::keySize() const
|
||||||
|
{
|
||||||
|
return _pImpl->keySize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int CipherKey::blockSize() const
|
||||||
|
{
|
||||||
|
return _pImpl->blockSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int CipherKey::ivSize() const
|
||||||
|
{
|
||||||
|
return _pImpl->ivSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline CipherKey::Mode CipherKey::mode() const
|
||||||
|
{
|
||||||
|
return _pImpl->mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const CipherKey::ByteVec & CipherKey::getKey() const
|
||||||
|
{
|
||||||
|
return _pImpl->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void CipherKey::setKey(const CipherKey::ByteVec & key)
|
||||||
|
{
|
||||||
|
_pImpl->setKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const CipherKey::ByteVec & CipherKey::getIV() const
|
||||||
|
{
|
||||||
|
return _pImpl->getIV();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void CipherKey::setIV(const CipherKey::ByteVec & iv)
|
||||||
|
{
|
||||||
|
_pImpl->setIV(iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline CipherKeyImpl::Ptr CipherKey::impl()
|
||||||
|
{
|
||||||
|
return _pImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline int CipherKey::keySize() const
|
|
||||||
{
|
|
||||||
return _pImpl->keySize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline int CipherKey::blockSize() const
|
|
||||||
{
|
|
||||||
return _pImpl->blockSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline int CipherKey::ivSize() const
|
|
||||||
{
|
|
||||||
return _pImpl->ivSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline CipherKey::Mode CipherKey::mode() const
|
|
||||||
{
|
|
||||||
return _pImpl->mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const CipherKey::ByteVec& CipherKey::getKey() const
|
|
||||||
{
|
|
||||||
return _pImpl->getKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void CipherKey::setKey(const CipherKey::ByteVec& key)
|
|
||||||
{
|
|
||||||
_pImpl->setKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const CipherKey::ByteVec& CipherKey::getIV() const
|
|
||||||
{
|
|
||||||
return _pImpl->getIV();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void CipherKey::setIV(const CipherKey::ByteVec& iv)
|
|
||||||
{
|
|
||||||
_pImpl->setIV(iv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline CipherKeyImpl::Ptr CipherKey::impl()
|
|
||||||
{
|
|
||||||
return _pImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CipherKey_INCLUDED
|
#endif // Crypto_CipherKey_INCLUDED
|
||||||
|
@ -18,151 +18,151 @@
|
|||||||
#define Crypto_CipherKeyImpl_INCLUDED
|
#define Crypto_CipherKeyImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
struct evp_cipher_st;
|
struct evp_cipher_st;
|
||||||
typedef struct evp_cipher_st EVP_CIPHER;
|
typedef struct evp_cipher_st EVP_CIPHER;
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class CipherKeyImpl: public RefCountedObject
|
|
||||||
/// An implementation of the CipherKey class for OpenSSL's crypto library.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
typedef std::vector<unsigned char> ByteVec;
|
|
||||||
typedef Poco::AutoPtr<CipherKeyImpl> Ptr;
|
|
||||||
|
|
||||||
enum Mode
|
|
||||||
/// Cipher mode of operation. This mode determines how multiple blocks
|
|
||||||
/// are connected; this is essential to improve security.
|
|
||||||
{
|
|
||||||
MODE_STREAM_CIPHER, /// Stream cipher
|
|
||||||
MODE_ECB, /// Electronic codebook (plain concatenation)
|
|
||||||
MODE_CBC, /// Cipher block chaining (default)
|
|
||||||
MODE_CFB, /// Cipher feedback
|
|
||||||
MODE_OFB, /// Output feedback
|
|
||||||
MODE_CTR, /// Counter mode
|
|
||||||
MODE_GCM, /// Galois/Counter mode
|
|
||||||
MODE_CCM /// Counter with CBC-MAC
|
|
||||||
};
|
|
||||||
|
|
||||||
CipherKeyImpl(const std::string& name,
|
|
||||||
const std::string& passphrase,
|
|
||||||
const std::string& salt,
|
|
||||||
int iterationCount,
|
|
||||||
const std::string& digest);
|
|
||||||
/// Creates a new CipherKeyImpl object, using
|
|
||||||
/// the given cipher name, passphrase, salt value
|
|
||||||
/// and iteration count.
|
|
||||||
|
|
||||||
CipherKeyImpl(const std::string& name,
|
|
||||||
const ByteVec& key,
|
|
||||||
const ByteVec& iv);
|
|
||||||
/// Creates a new CipherKeyImpl object, using the
|
|
||||||
/// given cipher name, key and initialization vector.
|
|
||||||
|
|
||||||
CipherKeyImpl(const std::string& name);
|
|
||||||
/// Creates a new CipherKeyImpl object. Autoinitializes key
|
|
||||||
/// and initialization vector.
|
|
||||||
|
|
||||||
virtual ~CipherKeyImpl();
|
|
||||||
/// Destroys the CipherKeyImpl.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns the name of the Cipher.
|
|
||||||
|
|
||||||
int keySize() const;
|
|
||||||
/// Returns the key size of the Cipher.
|
|
||||||
|
|
||||||
int blockSize() const;
|
|
||||||
/// Returns the block size of the Cipher.
|
|
||||||
|
|
||||||
int ivSize() const;
|
|
||||||
/// Returns the IV size of the Cipher.
|
|
||||||
|
|
||||||
Mode mode() const;
|
|
||||||
/// Returns the Cipher's mode of operation.
|
|
||||||
|
|
||||||
const ByteVec& getKey() const;
|
|
||||||
/// Returns the key for the Cipher.
|
|
||||||
|
|
||||||
void setKey(const ByteVec& key);
|
|
||||||
/// Sets the key for the Cipher.
|
|
||||||
|
|
||||||
const ByteVec& getIV() const;
|
|
||||||
/// Returns the initialization vector (IV) for the Cipher.
|
|
||||||
|
|
||||||
void setIV(const ByteVec& iv);
|
|
||||||
/// Sets the initialization vector (IV) for the Cipher.
|
|
||||||
|
|
||||||
const EVP_CIPHER* cipher();
|
|
||||||
/// Returns the cipher object
|
|
||||||
|
|
||||||
private:
|
|
||||||
void generateKey(const std::string& passphrase,
|
|
||||||
const std::string& salt,
|
|
||||||
int iterationCount);
|
|
||||||
/// Generates key and IV from a password and optional salt string.
|
|
||||||
|
|
||||||
void generateKey();
|
|
||||||
/// Generates key and IV from random data.
|
|
||||||
|
|
||||||
void getRandomBytes(ByteVec& vec, std::size_t count);
|
|
||||||
/// Stores random bytes in vec.
|
|
||||||
|
|
||||||
private:
|
|
||||||
const EVP_CIPHER* _pCipher;
|
|
||||||
const EVP_MD* _pDigest;
|
|
||||||
std::string _name;
|
|
||||||
ByteVec _key;
|
|
||||||
ByteVec _iv;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Inlines
|
|
||||||
//
|
|
||||||
inline const std::string& CipherKeyImpl::name() const
|
|
||||||
{
|
{
|
||||||
return _name;
|
|
||||||
|
|
||||||
|
class CipherKeyImpl : public RefCountedObject
|
||||||
|
/// An implementation of the CipherKey class for OpenSSL's crypto library.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::vector<unsigned char> ByteVec;
|
||||||
|
typedef Poco::AutoPtr<CipherKeyImpl> Ptr;
|
||||||
|
|
||||||
|
enum Mode
|
||||||
|
/// Cipher mode of operation. This mode determines how multiple blocks
|
||||||
|
/// are connected; this is essential to improve security.
|
||||||
|
{
|
||||||
|
MODE_STREAM_CIPHER, /// Stream cipher
|
||||||
|
MODE_ECB, /// Electronic codebook (plain concatenation)
|
||||||
|
MODE_CBC, /// Cipher block chaining (default)
|
||||||
|
MODE_CFB, /// Cipher feedback
|
||||||
|
MODE_OFB, /// Output feedback
|
||||||
|
MODE_CTR, /// Counter mode
|
||||||
|
MODE_GCM, /// Galois/Counter mode
|
||||||
|
MODE_CCM /// Counter with CBC-MAC
|
||||||
|
};
|
||||||
|
|
||||||
|
CipherKeyImpl(
|
||||||
|
const std::string & name,
|
||||||
|
const std::string & passphrase,
|
||||||
|
const std::string & salt,
|
||||||
|
int iterationCount,
|
||||||
|
const std::string & digest);
|
||||||
|
/// Creates a new CipherKeyImpl object, using
|
||||||
|
/// the given cipher name, passphrase, salt value
|
||||||
|
/// and iteration count.
|
||||||
|
|
||||||
|
CipherKeyImpl(const std::string & name, const ByteVec & key, const ByteVec & iv);
|
||||||
|
/// Creates a new CipherKeyImpl object, using the
|
||||||
|
/// given cipher name, key and initialization vector.
|
||||||
|
|
||||||
|
CipherKeyImpl(const std::string & name);
|
||||||
|
/// Creates a new CipherKeyImpl object. Autoinitializes key
|
||||||
|
/// and initialization vector.
|
||||||
|
|
||||||
|
virtual ~CipherKeyImpl();
|
||||||
|
/// Destroys the CipherKeyImpl.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns the name of the Cipher.
|
||||||
|
|
||||||
|
int keySize() const;
|
||||||
|
/// Returns the key size of the Cipher.
|
||||||
|
|
||||||
|
int blockSize() const;
|
||||||
|
/// Returns the block size of the Cipher.
|
||||||
|
|
||||||
|
int ivSize() const;
|
||||||
|
/// Returns the IV size of the Cipher.
|
||||||
|
|
||||||
|
Mode mode() const;
|
||||||
|
/// Returns the Cipher's mode of operation.
|
||||||
|
|
||||||
|
const ByteVec & getKey() const;
|
||||||
|
/// Returns the key for the Cipher.
|
||||||
|
|
||||||
|
void setKey(const ByteVec & key);
|
||||||
|
/// Sets the key for the Cipher.
|
||||||
|
|
||||||
|
const ByteVec & getIV() const;
|
||||||
|
/// Returns the initialization vector (IV) for the Cipher.
|
||||||
|
|
||||||
|
void setIV(const ByteVec & iv);
|
||||||
|
/// Sets the initialization vector (IV) for the Cipher.
|
||||||
|
|
||||||
|
const EVP_CIPHER * cipher();
|
||||||
|
/// Returns the cipher object
|
||||||
|
|
||||||
|
private:
|
||||||
|
void generateKey(const std::string & passphrase, const std::string & salt, int iterationCount);
|
||||||
|
/// Generates key and IV from a password and optional salt string.
|
||||||
|
|
||||||
|
void generateKey();
|
||||||
|
/// Generates key and IV from random data.
|
||||||
|
|
||||||
|
void getRandomBytes(ByteVec & vec, std::size_t count);
|
||||||
|
/// Stores random bytes in vec.
|
||||||
|
|
||||||
|
private:
|
||||||
|
const EVP_CIPHER * _pCipher;
|
||||||
|
const EVP_MD * _pDigest;
|
||||||
|
std::string _name;
|
||||||
|
ByteVec _key;
|
||||||
|
ByteVec _iv;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inlines
|
||||||
|
//
|
||||||
|
inline const std::string & CipherKeyImpl::name() const
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const CipherKeyImpl::ByteVec & CipherKeyImpl::getKey() const
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void CipherKeyImpl::setKey(const ByteVec & key)
|
||||||
|
{
|
||||||
|
poco_assert(key.size() == static_cast<ByteVec::size_type>(keySize()));
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const CipherKeyImpl::ByteVec & CipherKeyImpl::getIV() const
|
||||||
|
{
|
||||||
|
return _iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const EVP_CIPHER * CipherKeyImpl::cipher()
|
||||||
|
{
|
||||||
|
return _pCipher;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline const CipherKeyImpl::ByteVec& CipherKeyImpl::getKey() const
|
|
||||||
{
|
|
||||||
return _key;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void CipherKeyImpl::setKey(const ByteVec& key)
|
|
||||||
{
|
|
||||||
poco_assert(key.size() == static_cast<ByteVec::size_type>(keySize()));
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const CipherKeyImpl::ByteVec& CipherKeyImpl::getIV() const
|
|
||||||
{
|
|
||||||
return _iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const EVP_CIPHER* CipherKeyImpl::cipher()
|
|
||||||
{
|
|
||||||
return _pCipher;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CipherKeyImpl_INCLUDED
|
#endif // Crypto_CipherKeyImpl_INCLUDED
|
||||||
|
@ -24,39 +24,37 @@
|
|||||||
#define POCO_EXTERNAL_OPENSSL_SLPRO 2
|
#define POCO_EXTERNAL_OPENSSL_SLPRO 2
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Foundation.h"
|
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
|
#include "Poco/Foundation.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef OPENSSL_VERSION_PREREQ
|
#ifndef OPENSSL_VERSION_PREREQ
|
||||||
#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)
|
# if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)
|
||||||
#define OPENSSL_VERSION_PREREQ(maj, min) \
|
# define OPENSSL_VERSION_PREREQ(maj, min) ((OPENSSL_VERSION_MAJOR << 16) + OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
|
||||||
((OPENSSL_VERSION_MAJOR << 16) + OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
|
# else
|
||||||
#else
|
# define OPENSSL_VERSION_PREREQ(maj, min) (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | ((min) << 20)))
|
||||||
#define OPENSSL_VERSION_PREREQ(maj, min) \
|
# endif
|
||||||
(OPENSSL_VERSION_NUMBER >= (((maj) << 28) | ((min) << 20)))
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum RSAPaddingMode
|
enum RSAPaddingMode
|
||||||
/// The padding mode used for RSA public key encryption.
|
/// The padding mode used for RSA public key encryption.
|
||||||
{
|
{
|
||||||
RSA_PADDING_PKCS1,
|
RSA_PADDING_PKCS1,
|
||||||
/// PKCS #1 v1.5 padding. This currently is the most widely used mode.
|
/// PKCS #1 v1.5 padding. This currently is the most widely used mode.
|
||||||
|
|
||||||
RSA_PADDING_PKCS1_OAEP,
|
RSA_PADDING_PKCS1_OAEP,
|
||||||
/// EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty
|
/// EME-OAEP as defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty
|
||||||
/// encoding parameter. This mode is recommended for all new applications.
|
/// encoding parameter. This mode is recommended for all new applications.
|
||||||
|
|
||||||
RSA_PADDING_SSLV23,
|
RSA_PADDING_SSLV23,
|
||||||
/// PKCS #1 v1.5 padding with an SSL-specific modification that denotes
|
/// PKCS #1 v1.5 padding with an SSL-specific modification that denotes
|
||||||
/// that the server is SSL3 capable.
|
/// that the server is SSL3 capable.
|
||||||
|
|
||||||
RSA_PADDING_NONE
|
RSA_PADDING_NONE
|
||||||
/// Raw RSA encryption. This mode should only be used to implement cryptographically
|
/// Raw RSA encryption. This mode should only be used to implement cryptographically
|
||||||
/// sound padding modes in the application code. Encrypting user data directly with RSA
|
/// sound padding modes in the application code. Encrypting user data directly with RSA
|
||||||
/// is insecure.
|
/// is insecure.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -68,128 +66,51 @@ enum RSAPaddingMode
|
|||||||
// Crypto_API functions as being imported from a DLL, whereas this DLL sees symbols
|
// Crypto_API functions as being imported from a DLL, whereas this DLL sees symbols
|
||||||
// defined with this macro as being exported.
|
// defined with this macro as being exported.
|
||||||
//
|
//
|
||||||
#if defined(_WIN32)
|
|
||||||
#if defined(POCO_DLL)
|
|
||||||
#if defined(Crypto_EXPORTS)
|
|
||||||
#define Crypto_API __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define Crypto_API __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(Crypto_API)
|
#if !defined(Crypto_API)
|
||||||
#if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined (__GNUC__) && (__GNUC__ >= 4)
|
# if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
#define Crypto_API __attribute__ ((visibility ("default")))
|
# define Crypto_API __attribute__((visibility("default")))
|
||||||
#else
|
# else
|
||||||
#define Crypto_API
|
# define Crypto_API
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Automatically link Crypto and OpenSSL libraries.
|
// Automatically link Crypto and OpenSSL libraries.
|
||||||
//
|
//
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#if !defined(POCO_NO_AUTOMATIC_LIBS)
|
|
||||||
#if defined(POCO_INTERNAL_OPENSSL_MSVC_VER)
|
|
||||||
#if defined(POCO_EXTERNAL_OPENSSL)
|
|
||||||
#pragma message("External OpenSSL defined but internal headers used - possible mismatch!")
|
|
||||||
#endif // POCO_EXTERNAL_OPENSSL
|
|
||||||
#if !defined(_DEBUG)
|
|
||||||
#define POCO_DEBUG_SUFFIX ""
|
|
||||||
#if !defined (_DLL)
|
|
||||||
#define POCO_STATIC_SUFFIX "mt"
|
|
||||||
#else // _DLL
|
|
||||||
#define POCO_STATIC_SUFFIX ""
|
|
||||||
#endif
|
|
||||||
#else // _DEBUG
|
|
||||||
#define POCO_DEBUG_SUFFIX "d"
|
|
||||||
#if !defined (_DLL)
|
|
||||||
#define POCO_STATIC_SUFFIX "mt"
|
|
||||||
#else // _DLL
|
|
||||||
#define POCO_STATIC_SUFFIX ""
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#pragma comment(lib, "libcrypto" POCO_STATIC_SUFFIX POCO_DEBUG_SUFFIX ".lib")
|
|
||||||
#pragma comment(lib, "libssl" POCO_STATIC_SUFFIX POCO_DEBUG_SUFFIX ".lib")
|
|
||||||
#if !defined(_WIN64) && !defined (_DLL) && \
|
|
||||||
(POCO_INTERNAL_OPENSSL_MSVC_VER == 120) && \
|
|
||||||
(POCO_MSVC_VERSION < POCO_INTERNAL_OPENSSL_MSVC_VER)
|
|
||||||
#pragma comment(lib, "libPreVS2013CRT" POCO_STATIC_SUFFIX POCO_DEBUG_SUFFIX ".lib")
|
|
||||||
#endif
|
|
||||||
#if !defined (_DLL) && (POCO_MSVS_VERSION >= 2015)
|
|
||||||
#pragma comment(lib, "legacy_stdio_definitions.lib")
|
|
||||||
#pragma comment(lib, "legacy_stdio_wide_specifiers.lib")
|
|
||||||
#endif
|
|
||||||
#elif defined(POCO_EXTERNAL_OPENSSL)
|
|
||||||
#if POCO_EXTERNAL_OPENSSL == POCO_EXTERNAL_OPENSSL_SLPRO
|
|
||||||
#if defined(POCO_DLL)
|
|
||||||
#if OPENSSL_VERSION_PREREQ(1,1)
|
|
||||||
#pragma comment(lib, "libcrypto.lib")
|
|
||||||
#pragma comment(lib, "libssl.lib")
|
|
||||||
#else
|
|
||||||
#pragma comment(lib, "libeay32.lib")
|
|
||||||
#pragma comment(lib, "ssleay32.lib")
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if OPENSSL_VERSION_PREREQ(1,1)
|
|
||||||
#if defined(_WIN64)
|
|
||||||
#pragma comment(lib, "libcrypto64" POCO_LIB_SUFFIX)
|
|
||||||
#pragma comment(lib, "libssl64" POCO_LIB_SUFFIX)
|
|
||||||
#else
|
|
||||||
#pragma comment(lib, "libcrypto32" POCO_LIB_SUFFIX)
|
|
||||||
#pragma comment(lib, "libssl32" POCO_LIB_SUFFIX)
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#pragma comment(lib, "libeay32" POCO_LIB_SUFFIX)
|
|
||||||
#pragma comment(lib, "ssleay32" POCO_LIB_SUFFIX)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#elif POCO_EXTERNAL_OPENSSL == POCO_EXTERNAL_OPENSSL_DEFAULT
|
|
||||||
#if OPENSSL_VERSION_PREREQ(1,1)
|
|
||||||
#pragma comment(lib, "libcrypto.lib")
|
|
||||||
#pragma comment(lib, "libssl.lib")
|
|
||||||
#else
|
|
||||||
#pragma comment(lib, "libeay32.lib")
|
|
||||||
#pragma comment(lib, "ssleay32.lib")
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif // POCO_INTERNAL_OPENSSL_MSVC_VER
|
|
||||||
#if !defined(Crypto_EXPORTS)
|
|
||||||
#pragma comment(lib, "PocoCrypto" POCO_LIB_SUFFIX)
|
|
||||||
#endif
|
|
||||||
#endif // POCO_NO_AUTOMATIC_LIBS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
void Crypto_API initializeCrypto();
|
void Crypto_API initializeCrypto();
|
||||||
/// Initialize the Crypto library, as well as the underlying OpenSSL
|
/// Initialize the Crypto library, as well as the underlying OpenSSL
|
||||||
/// libraries, by calling OpenSSLInitializer::initialize().
|
/// libraries, by calling OpenSSLInitializer::initialize().
|
||||||
///
|
///
|
||||||
/// Should be called before using any class from the Crypto library.
|
/// Should be called before using any class from the Crypto library.
|
||||||
/// The Crypto library will be initialized automatically, through
|
/// The Crypto library will be initialized automatically, through
|
||||||
/// OpenSSLInitializer instances held by various Crypto classes
|
/// OpenSSLInitializer instances held by various Crypto classes
|
||||||
/// (Cipher, CipherKey, RSAKey, X509Certificate).
|
/// (Cipher, CipherKey, RSAKey, X509Certificate).
|
||||||
/// However, it is recommended to call initializeCrypto()
|
/// However, it is recommended to call initializeCrypto()
|
||||||
/// in any case at application startup.
|
/// in any case at application startup.
|
||||||
///
|
///
|
||||||
/// Can be called multiple times; however, for every call to
|
/// Can be called multiple times; however, for every call to
|
||||||
/// initializeCrypto(), a matching call to uninitializeCrypto()
|
/// initializeCrypto(), a matching call to uninitializeCrypto()
|
||||||
/// must be performed.
|
/// must be performed.
|
||||||
|
|
||||||
|
|
||||||
void Crypto_API uninitializeCrypto();
|
void Crypto_API uninitializeCrypto();
|
||||||
/// Uninitializes the Crypto library by calling
|
/// Uninitializes the Crypto library by calling
|
||||||
/// OpenSSLInitializer::uninitialize().
|
/// OpenSSLInitializer::uninitialize().
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_Crypto_INCLUDED
|
#endif // Crypto_Crypto_INCLUDED
|
||||||
|
@ -23,34 +23,37 @@
|
|||||||
#include "Poco/Exception.h"
|
#include "Poco/Exception.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
POCO_DECLARE_EXCEPTION(Crypto_API, CryptoException, Poco::Exception)
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API OpenSSLException : public CryptoException
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
OpenSSLException(int code = 0);
|
|
||||||
OpenSSLException(const std::string& msg, int code = 0);
|
|
||||||
OpenSSLException(const std::string& msg, const std::string& arg, int code = 0);
|
|
||||||
OpenSSLException(const std::string& msg, const Poco::Exception& exc, int code = 0);
|
|
||||||
OpenSSLException(const OpenSSLException& exc);
|
|
||||||
~OpenSSLException() throw();
|
|
||||||
OpenSSLException& operator = (const OpenSSLException& exc);
|
|
||||||
const char* name() const throw();
|
|
||||||
const char* className() const throw();
|
|
||||||
Poco::Exception* clone() const;
|
|
||||||
void rethrow() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setExtMessage();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
POCO_DECLARE_EXCEPTION(Crypto_API, CryptoException, Poco::Exception)
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API OpenSSLException : public CryptoException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenSSLException(int code = 0);
|
||||||
|
OpenSSLException(const std::string & msg, int code = 0);
|
||||||
|
OpenSSLException(const std::string & msg, const std::string & arg, int code = 0);
|
||||||
|
OpenSSLException(const std::string & msg, const Poco::Exception & exc, int code = 0);
|
||||||
|
OpenSSLException(const OpenSSLException & exc);
|
||||||
|
~OpenSSLException() throw();
|
||||||
|
OpenSSLException & operator=(const OpenSSLException & exc);
|
||||||
|
const char * name() const throw();
|
||||||
|
const char * className() const throw();
|
||||||
|
Poco::Exception * clone() const;
|
||||||
|
void rethrow() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setExtMessage();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CryptoException_INCLUDED
|
#endif // Crypto_CryptoException_INCLUDED
|
||||||
|
@ -19,174 +19,177 @@
|
|||||||
#define Crypto_CryptoStream_INCLUDED
|
#define Crypto_CryptoStream_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/BufferedStreamBuf.h"
|
|
||||||
#include "Poco/Buffer.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "Poco/Buffer.h"
|
||||||
|
#include "Poco/BufferedStreamBuf.h"
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class CryptoTransform;
|
|
||||||
class Cipher;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CryptoStreamBuf: public Poco::BufferedStreamBuf
|
|
||||||
/// This stream buffer performs cryptographic transformation on the data
|
|
||||||
/// going through it.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
CryptoStreamBuf(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
CryptoStreamBuf(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
|
|
||||||
virtual ~CryptoStreamBuf();
|
|
||||||
|
|
||||||
void close();
|
|
||||||
/// Flushes all buffers and finishes the encryption.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int readFromDevice(char* buffer, std::streamsize length);
|
|
||||||
int writeToDevice(const char* buffer, std::streamsize length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CryptoTransform* _pTransform;
|
|
||||||
std::istream* _pIstr;
|
|
||||||
std::ostream* _pOstr;
|
|
||||||
bool _eof;
|
|
||||||
|
|
||||||
Poco::Buffer<unsigned char> _buffer;
|
|
||||||
|
|
||||||
CryptoStreamBuf(const CryptoStreamBuf&);
|
|
||||||
CryptoStreamBuf& operator = (const CryptoStreamBuf&);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CryptoIOS: public virtual std::ios
|
|
||||||
/// The base class for CryptoInputStream and CryptoOutputStream.
|
|
||||||
///
|
|
||||||
/// This class is needed to ensure correct initialization order of the
|
|
||||||
/// stream buffer and base classes.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
CryptoIOS(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
CryptoIOS(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
~CryptoIOS();
|
|
||||||
CryptoStreamBuf* rdbuf();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
CryptoStreamBuf _buf;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CryptoInputStream: public CryptoIOS, public std::istream
|
class CryptoTransform;
|
||||||
/// This stream transforms all data passing through it using the given
|
class Cipher;
|
||||||
/// CryptoTransform.
|
|
||||||
///
|
|
||||||
/// Use a CryptoTransform object provided by Cipher::createEncrytor() or
|
|
||||||
/// Cipher::createDecryptor() to create an encrypting or decrypting stream,
|
|
||||||
/// respectively.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CryptoInputStream(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
/// Create a new CryptoInputStream object. The CryptoInputStream takes the
|
|
||||||
/// ownership of the given CryptoTransform object.
|
|
||||||
|
|
||||||
CryptoInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
|
||||||
/// Create a new encrypting CryptoInputStream object using the given cipher.
|
|
||||||
|
|
||||||
~CryptoInputStream();
|
|
||||||
/// Destroys the CryptoInputStream.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API CryptoOutputStream: public CryptoIOS, public std::ostream
|
class Crypto_API CryptoStreamBuf : public Poco::BufferedStreamBuf
|
||||||
/// This stream transforms all data passing through it using the given
|
/// This stream buffer performs cryptographic transformation on the data
|
||||||
/// CryptoTransform.
|
/// going through it.
|
||||||
///
|
{
|
||||||
/// Use a CryptoTransform object provided by Cipher::createEncrytor() or
|
public:
|
||||||
/// Cipher::createDecryptor() to create an encrypting or decrypting stream,
|
CryptoStreamBuf(std::istream & istr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
/// respectively.
|
CryptoStreamBuf(std::ostream & ostr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
///
|
|
||||||
/// After all data has been passed through the stream, close() must be called
|
|
||||||
/// to ensure completion of cryptographic transformation.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CryptoOutputStream(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize = 8192);
|
|
||||||
/// Create a new CryptoOutputStream object. The CryptoOutputStream takes the
|
|
||||||
/// ownership of the given CryptoTransform object.
|
|
||||||
|
|
||||||
CryptoOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
virtual ~CryptoStreamBuf();
|
||||||
/// Create a new decrypting CryptoOutputStream object using the given cipher.
|
|
||||||
|
|
||||||
~CryptoOutputStream();
|
void close();
|
||||||
/// Destroys the CryptoOutputStream.
|
/// Flushes all buffers and finishes the encryption.
|
||||||
|
|
||||||
void close();
|
protected:
|
||||||
/// Flushes all buffers and finishes the encryption.
|
int readFromDevice(char * buffer, std::streamsize length);
|
||||||
};
|
int writeToDevice(const char * buffer, std::streamsize length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CryptoTransform * _pTransform;
|
||||||
|
std::istream * _pIstr;
|
||||||
|
std::ostream * _pOstr;
|
||||||
|
bool _eof;
|
||||||
|
|
||||||
|
Poco::Buffer<unsigned char> _buffer;
|
||||||
|
|
||||||
|
CryptoStreamBuf(const CryptoStreamBuf &);
|
||||||
|
CryptoStreamBuf & operator=(const CryptoStreamBuf &);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API DecryptingInputStream: public CryptoIOS, public std::istream
|
class Crypto_API CryptoIOS : public virtual std::ios
|
||||||
/// This stream decrypts all data passing through it using the given
|
/// The base class for CryptoInputStream and CryptoOutputStream.
|
||||||
/// Cipher.
|
///
|
||||||
{
|
/// This class is needed to ensure correct initialization order of the
|
||||||
public:
|
/// stream buffer and base classes.
|
||||||
DecryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
{
|
||||||
/// Create a new DecryptingInputStream object using the given cipher.
|
public:
|
||||||
|
CryptoIOS(std::istream & istr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
|
CryptoIOS(std::ostream & ostr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
|
~CryptoIOS();
|
||||||
|
CryptoStreamBuf * rdbuf();
|
||||||
|
|
||||||
~DecryptingInputStream();
|
protected:
|
||||||
/// Destroys the DecryptingInputStream.
|
CryptoStreamBuf _buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API DecryptingOutputStream: public CryptoIOS, public std::ostream
|
class Crypto_API CryptoInputStream : public CryptoIOS, public std::istream
|
||||||
/// This stream decrypts all data passing through it using the given
|
/// This stream transforms all data passing through it using the given
|
||||||
/// Cipher.
|
/// CryptoTransform.
|
||||||
{
|
///
|
||||||
public:
|
/// Use a CryptoTransform object provided by Cipher::createEncrytor() or
|
||||||
DecryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
/// Cipher::createDecryptor() to create an encrypting or decrypting stream,
|
||||||
/// Create a new DecryptingOutputStream object using the given cipher.
|
/// respectively.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CryptoInputStream(std::istream & istr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
|
/// Create a new CryptoInputStream object. The CryptoInputStream takes the
|
||||||
|
/// ownership of the given CryptoTransform object.
|
||||||
|
|
||||||
~DecryptingOutputStream();
|
CryptoInputStream(std::istream & istr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
/// Destroys the DecryptingOutputStream.
|
/// Create a new encrypting CryptoInputStream object using the given cipher.
|
||||||
|
|
||||||
void close();
|
~CryptoInputStream();
|
||||||
/// Flushes all buffers and finishes the decryption.
|
/// Destroys the CryptoInputStream.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API EncryptingInputStream: public CryptoIOS, public std::istream
|
class Crypto_API CryptoOutputStream : public CryptoIOS, public std::ostream
|
||||||
/// This stream encrypts all data passing through it using the given
|
/// This stream transforms all data passing through it using the given
|
||||||
/// Cipher.
|
/// CryptoTransform.
|
||||||
{
|
///
|
||||||
public:
|
/// Use a CryptoTransform object provided by Cipher::createEncrytor() or
|
||||||
EncryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
/// Cipher::createDecryptor() to create an encrypting or decrypting stream,
|
||||||
/// Create a new EncryptingInputStream object using the given cipher.
|
/// respectively.
|
||||||
|
///
|
||||||
|
/// After all data has been passed through the stream, close() must be called
|
||||||
|
/// to ensure completion of cryptographic transformation.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CryptoOutputStream(std::ostream & ostr, CryptoTransform * pTransform, std::streamsize bufferSize = 8192);
|
||||||
|
/// Create a new CryptoOutputStream object. The CryptoOutputStream takes the
|
||||||
|
/// ownership of the given CryptoTransform object.
|
||||||
|
|
||||||
~EncryptingInputStream();
|
CryptoOutputStream(std::ostream & ostr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
/// Destroys the EncryptingInputStream.
|
/// Create a new decrypting CryptoOutputStream object using the given cipher.
|
||||||
};
|
|
||||||
|
~CryptoOutputStream();
|
||||||
|
/// Destroys the CryptoOutputStream.
|
||||||
|
|
||||||
|
void close();
|
||||||
|
/// Flushes all buffers and finishes the encryption.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API EncryptingOutputStream: public CryptoIOS, public std::ostream
|
class Crypto_API DecryptingInputStream : public CryptoIOS, public std::istream
|
||||||
/// This stream encrypts all data passing through it using the given
|
/// This stream decrypts all data passing through it using the given
|
||||||
/// Cipher.
|
/// Cipher.
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EncryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize = 8192);
|
DecryptingInputStream(std::istream & istr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
/// Create a new EncryptingOutputStream object using the given cipher.
|
/// Create a new DecryptingInputStream object using the given cipher.
|
||||||
|
|
||||||
~EncryptingOutputStream();
|
~DecryptingInputStream();
|
||||||
/// Destroys the EncryptingOutputStream.
|
/// Destroys the DecryptingInputStream.
|
||||||
|
};
|
||||||
void close();
|
|
||||||
/// Flushes all buffers and finishes the encryption.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class Crypto_API DecryptingOutputStream : public CryptoIOS, public std::ostream
|
||||||
|
/// This stream decrypts all data passing through it using the given
|
||||||
|
/// Cipher.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DecryptingOutputStream(std::ostream & ostr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
|
/// Create a new DecryptingOutputStream object using the given cipher.
|
||||||
|
|
||||||
|
~DecryptingOutputStream();
|
||||||
|
/// Destroys the DecryptingOutputStream.
|
||||||
|
|
||||||
|
void close();
|
||||||
|
/// Flushes all buffers and finishes the decryption.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API EncryptingInputStream : public CryptoIOS, public std::istream
|
||||||
|
/// This stream encrypts all data passing through it using the given
|
||||||
|
/// Cipher.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EncryptingInputStream(std::istream & istr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
|
/// Create a new EncryptingInputStream object using the given cipher.
|
||||||
|
|
||||||
|
~EncryptingInputStream();
|
||||||
|
/// Destroys the EncryptingInputStream.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API EncryptingOutputStream : public CryptoIOS, public std::ostream
|
||||||
|
/// This stream encrypts all data passing through it using the given
|
||||||
|
/// Cipher.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EncryptingOutputStream(std::ostream & ostr, Cipher & cipher, std::streamsize bufferSize = 8192);
|
||||||
|
/// Create a new EncryptingOutputStream object using the given cipher.
|
||||||
|
|
||||||
|
~EncryptingOutputStream();
|
||||||
|
/// Destroys the EncryptingOutputStream.
|
||||||
|
|
||||||
|
void close();
|
||||||
|
/// Flushes all buffers and finishes the encryption.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CryptoStream_INCLUDED
|
#endif // Crypto_CryptoStream_INCLUDED
|
||||||
|
@ -18,70 +18,71 @@
|
|||||||
#define Crypto_CryptoTransform_INCLUDED
|
#define Crypto_CryptoTransform_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include <ios>
|
#include <ios>
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class Crypto_API CryptoTransform
|
|
||||||
/// This interface represents the basic operations for cryptographic
|
|
||||||
/// transformations to be used with a CryptoInputStream or a
|
|
||||||
/// CryptoOutputStream.
|
|
||||||
///
|
|
||||||
/// Implementations of this class are returned by the Cipher class to
|
|
||||||
/// perform encryption or decryption of data.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
CryptoTransform();
|
|
||||||
/// Creates a new CryptoTransform object.
|
|
||||||
|
|
||||||
virtual ~CryptoTransform();
|
|
||||||
/// Destroys the CryptoTransform.
|
|
||||||
|
|
||||||
virtual std::size_t blockSize() const = 0;
|
|
||||||
/// Returns the block size for this CryptoTransform.
|
|
||||||
|
|
||||||
virtual int setPadding(int padding);
|
|
||||||
/// Enables or disables padding. By default encryption operations are padded using standard block
|
|
||||||
/// padding and the padding is checked and removed when decrypting. If the padding parameter is zero then
|
|
||||||
/// no padding is performed, the total amount of data encrypted or decrypted must then be a multiple of
|
|
||||||
/// the block size or an error will occur.
|
|
||||||
|
|
||||||
virtual std::string getTag(std::size_t tagSize = 16) = 0;
|
|
||||||
/// Returns the GCM tag after encrypting using GCM mode.
|
|
||||||
///
|
|
||||||
/// Must be called after finalize().
|
|
||||||
|
|
||||||
virtual void setTag(const std::string& tag) = 0;
|
|
||||||
/// Sets the GCM tag for authenticated decryption using GCM mode.
|
|
||||||
///
|
|
||||||
/// Must be set before finalize() is called, otherwise
|
|
||||||
/// decryption will fail.
|
|
||||||
|
|
||||||
virtual std::streamsize transform(
|
|
||||||
const unsigned char* input,
|
|
||||||
std::streamsize inputLength,
|
|
||||||
unsigned char* output,
|
|
||||||
std::streamsize outputLength) = 0;
|
|
||||||
/// Transforms a chunk of data. The inputLength is arbitrary and does not
|
|
||||||
/// need to be a multiple of the block size. The output buffer has a maximum
|
|
||||||
/// capacity of the given outputLength that must be at least
|
|
||||||
/// inputLength + blockSize() - 1
|
|
||||||
/// Returns the number of bytes written to the output buffer.
|
|
||||||
|
|
||||||
virtual std::streamsize finalize(unsigned char* output, std::streamsize length) = 0;
|
|
||||||
/// Finalizes the transformation. The output buffer must contain enough
|
|
||||||
/// space for at least two blocks, ie.
|
|
||||||
/// length >= 2*blockSize()
|
|
||||||
/// must be true. Returns the number of bytes written to the output
|
|
||||||
/// buffer.
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class Crypto_API CryptoTransform
|
||||||
|
/// This interface represents the basic operations for cryptographic
|
||||||
|
/// transformations to be used with a CryptoInputStream or a
|
||||||
|
/// CryptoOutputStream.
|
||||||
|
///
|
||||||
|
/// Implementations of this class are returned by the Cipher class to
|
||||||
|
/// perform encryption or decryption of data.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CryptoTransform();
|
||||||
|
/// Creates a new CryptoTransform object.
|
||||||
|
|
||||||
|
virtual ~CryptoTransform();
|
||||||
|
/// Destroys the CryptoTransform.
|
||||||
|
|
||||||
|
virtual std::size_t blockSize() const = 0;
|
||||||
|
/// Returns the block size for this CryptoTransform.
|
||||||
|
|
||||||
|
virtual int setPadding(int padding);
|
||||||
|
/// Enables or disables padding. By default encryption operations are padded using standard block
|
||||||
|
/// padding and the padding is checked and removed when decrypting. If the padding parameter is zero then
|
||||||
|
/// no padding is performed, the total amount of data encrypted or decrypted must then be a multiple of
|
||||||
|
/// the block size or an error will occur.
|
||||||
|
|
||||||
|
virtual std::string getTag(std::size_t tagSize = 16) = 0;
|
||||||
|
/// Returns the GCM tag after encrypting using GCM mode.
|
||||||
|
///
|
||||||
|
/// Must be called after finalize().
|
||||||
|
|
||||||
|
virtual void setTag(const std::string & tag) = 0;
|
||||||
|
/// Sets the GCM tag for authenticated decryption using GCM mode.
|
||||||
|
///
|
||||||
|
/// Must be set before finalize() is called, otherwise
|
||||||
|
/// decryption will fail.
|
||||||
|
|
||||||
|
virtual std::streamsize
|
||||||
|
transform(const unsigned char * input, std::streamsize inputLength, unsigned char * output, std::streamsize outputLength)
|
||||||
|
= 0;
|
||||||
|
/// Transforms a chunk of data. The inputLength is arbitrary and does not
|
||||||
|
/// need to be a multiple of the block size. The output buffer has a maximum
|
||||||
|
/// capacity of the given outputLength that must be at least
|
||||||
|
/// inputLength + blockSize() - 1
|
||||||
|
/// Returns the number of bytes written to the output buffer.
|
||||||
|
|
||||||
|
virtual std::streamsize finalize(unsigned char * output, std::streamsize length) = 0;
|
||||||
|
/// Finalizes the transformation. The output buffer must contain enough
|
||||||
|
/// space for at least two blocks, ie.
|
||||||
|
/// length >= 2*blockSize()
|
||||||
|
/// must be true. Returns the number of bytes written to the output
|
||||||
|
/// buffer.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_CryptoTransform_INCLUDED
|
#endif // Crypto_CryptoTransform_INCLUDED
|
||||||
|
@ -18,63 +18,66 @@
|
|||||||
#define Crypto_DigestEngine_INCLUDED
|
#define Crypto_DigestEngine_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <openssl/evp.h>
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/DigestEngine.h"
|
#include "Poco/DigestEngine.h"
|
||||||
#include <openssl/evp.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API DigestEngine: public Poco::DigestEngine
|
|
||||||
/// This class implements a Poco::DigestEngine for all
|
|
||||||
/// digest algorithms supported by OpenSSL.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
DigestEngine(const std::string& name);
|
|
||||||
/// Creates a DigestEngine using the digest with the given name
|
|
||||||
/// (e.g., "MD5", "SHA1", "SHA256", "SHA512", etc.).
|
|
||||||
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
|
||||||
///
|
|
||||||
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
|
||||||
|
|
||||||
~DigestEngine();
|
|
||||||
/// Destroys the DigestEngine.
|
|
||||||
|
|
||||||
const std::string& algorithm() const;
|
|
||||||
/// Returns the name of the digest algorithm.
|
|
||||||
|
|
||||||
int nid() const;
|
|
||||||
/// Returns the NID (OpenSSL object identifier) of the digest algorithm.
|
|
||||||
|
|
||||||
// DigestEngine
|
|
||||||
std::size_t digestLength() const;
|
|
||||||
void reset();
|
|
||||||
const Poco::DigestEngine::Digest& digest();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void updateImpl(const void* data, std::size_t length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string _name;
|
|
||||||
EVP_MD_CTX* _pContext;
|
|
||||||
Poco::DigestEngine::Digest _digest;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline const std::string& DigestEngine::algorithm() const
|
|
||||||
{
|
{
|
||||||
return _name;
|
|
||||||
|
|
||||||
|
class Crypto_API DigestEngine : public Poco::DigestEngine
|
||||||
|
/// This class implements a Poco::DigestEngine for all
|
||||||
|
/// digest algorithms supported by OpenSSL.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DigestEngine(const std::string & name);
|
||||||
|
/// Creates a DigestEngine using the digest with the given name
|
||||||
|
/// (e.g., "MD5", "SHA1", "SHA256", "SHA512", etc.).
|
||||||
|
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
||||||
|
///
|
||||||
|
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
||||||
|
|
||||||
|
~DigestEngine();
|
||||||
|
/// Destroys the DigestEngine.
|
||||||
|
|
||||||
|
const std::string & algorithm() const;
|
||||||
|
/// Returns the name of the digest algorithm.
|
||||||
|
|
||||||
|
int nid() const;
|
||||||
|
/// Returns the NID (OpenSSL object identifier) of the digest algorithm.
|
||||||
|
|
||||||
|
// DigestEngine
|
||||||
|
std::size_t digestLength() const;
|
||||||
|
void reset();
|
||||||
|
const Poco::DigestEngine::Digest & digest();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateImpl(const void * data, std::size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _name;
|
||||||
|
EVP_MD_CTX * _pContext;
|
||||||
|
Poco::DigestEngine::Digest _digest;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline const std::string & DigestEngine::algorithm() const
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_DigestEngine_INCLUDED
|
#endif // Crypto_DigestEngine_INCLUDED
|
||||||
|
@ -19,83 +19,85 @@
|
|||||||
#define Crypto_ECDSADigestEngine_INCLUDED
|
#define Crypto_ECDSADigestEngine_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/Crypto/ECKey.h"
|
|
||||||
#include "Poco/DigestEngine.h"
|
|
||||||
#include "Poco/Crypto/DigestEngine.h"
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
#include "Poco/Crypto/DigestEngine.h"
|
||||||
|
#include "Poco/Crypto/ECKey.h"
|
||||||
|
#include "Poco/DigestEngine.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class Crypto_API ECDSADigestEngine: public Poco::DigestEngine
|
|
||||||
/// This class implements a Poco::DigestEngine that can be
|
|
||||||
/// used to compute a secure digital signature.
|
|
||||||
///
|
|
||||||
/// First another Poco::Crypto::DigestEngine is created and
|
|
||||||
/// used to compute a cryptographic hash of the data to be
|
|
||||||
/// signed. Then, the hash value is encrypted, using
|
|
||||||
/// the ECDSA private key.
|
|
||||||
///
|
|
||||||
/// To verify a signature, pass it to the verify()
|
|
||||||
/// member function. It will decrypt the signature
|
|
||||||
/// using the ECDSA public key and compare the resulting
|
|
||||||
/// hash with the actual hash of the data.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
|
|
||||||
ECDSADigestEngine(const ECKey& key, const std::string &name);
|
|
||||||
/// Creates the ECDSADigestEngine with the given ECDSA key,
|
|
||||||
/// using the hash algorithm with the given name
|
|
||||||
/// (e.g., "SHA1", "SHA256", "SHA512", etc.).
|
|
||||||
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
|
||||||
///
|
|
||||||
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
|
||||||
|
|
||||||
~ECDSADigestEngine();
|
|
||||||
/// Destroys the ECDSADigestEngine.
|
|
||||||
|
|
||||||
std::size_t digestLength() const;
|
|
||||||
/// Returns the length of the digest in bytes.
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
/// Resets the engine so that a new
|
|
||||||
/// digest can be computed.
|
|
||||||
|
|
||||||
const DigestEngine::Digest& digest();
|
|
||||||
/// Finishes the computation of the digest
|
|
||||||
/// (the first time it's called) and
|
|
||||||
/// returns the message digest.
|
|
||||||
///
|
|
||||||
/// Can be called multiple times.
|
|
||||||
|
|
||||||
const DigestEngine::Digest& signature();
|
|
||||||
/// Signs the digest using the ECDSADSA algorithm
|
|
||||||
/// and the private key (the first time it's
|
|
||||||
/// called) and returns the result.
|
|
||||||
///
|
|
||||||
/// Can be called multiple times.
|
|
||||||
|
|
||||||
bool verify(const DigestEngine::Digest& signature);
|
|
||||||
/// Verifies the data against the signature.
|
|
||||||
///
|
|
||||||
/// Returns true if the signature can be verified, false otherwise.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void updateImpl(const void* data, std::size_t length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
ECKey _key;
|
|
||||||
Poco::Crypto::DigestEngine _engine;
|
|
||||||
Poco::DigestEngine::Digest _digest;
|
|
||||||
Poco::DigestEngine::Digest _signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class Crypto_API ECDSADigestEngine : public Poco::DigestEngine
|
||||||
|
/// This class implements a Poco::DigestEngine that can be
|
||||||
|
/// used to compute a secure digital signature.
|
||||||
|
///
|
||||||
|
/// First another Poco::Crypto::DigestEngine is created and
|
||||||
|
/// used to compute a cryptographic hash of the data to be
|
||||||
|
/// signed. Then, the hash value is encrypted, using
|
||||||
|
/// the ECDSA private key.
|
||||||
|
///
|
||||||
|
/// To verify a signature, pass it to the verify()
|
||||||
|
/// member function. It will decrypt the signature
|
||||||
|
/// using the ECDSA public key and compare the resulting
|
||||||
|
/// hash with the actual hash of the data.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ECDSADigestEngine(const ECKey & key, const std::string & name);
|
||||||
|
/// Creates the ECDSADigestEngine with the given ECDSA key,
|
||||||
|
/// using the hash algorithm with the given name
|
||||||
|
/// (e.g., "SHA1", "SHA256", "SHA512", etc.).
|
||||||
|
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
||||||
|
///
|
||||||
|
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
||||||
|
|
||||||
|
~ECDSADigestEngine();
|
||||||
|
/// Destroys the ECDSADigestEngine.
|
||||||
|
|
||||||
|
std::size_t digestLength() const;
|
||||||
|
/// Returns the length of the digest in bytes.
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
/// Resets the engine so that a new
|
||||||
|
/// digest can be computed.
|
||||||
|
|
||||||
|
const DigestEngine::Digest & digest();
|
||||||
|
/// Finishes the computation of the digest
|
||||||
|
/// (the first time it's called) and
|
||||||
|
/// returns the message digest.
|
||||||
|
///
|
||||||
|
/// Can be called multiple times.
|
||||||
|
|
||||||
|
const DigestEngine::Digest & signature();
|
||||||
|
/// Signs the digest using the ECDSADSA algorithm
|
||||||
|
/// and the private key (the first time it's
|
||||||
|
/// called) and returns the result.
|
||||||
|
///
|
||||||
|
/// Can be called multiple times.
|
||||||
|
|
||||||
|
bool verify(const DigestEngine::Digest & signature);
|
||||||
|
/// Verifies the data against the signature.
|
||||||
|
///
|
||||||
|
/// Returns true if the signature can be verified, false otherwise.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateImpl(const void * data, std::size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ECKey _key;
|
||||||
|
Poco::Crypto::DigestEngine _engine;
|
||||||
|
Poco::DigestEngine::Digest _digest;
|
||||||
|
Poco::DigestEngine::Digest _signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_ECDSADigestEngine_INCLUDED
|
#endif // Crypto_ECDSADigestEngine_INCLUDED
|
||||||
|
@ -20,116 +20,119 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/KeyPair.h"
|
|
||||||
#include "Poco/Crypto/ECKeyImpl.h"
|
#include "Poco/Crypto/ECKeyImpl.h"
|
||||||
|
#include "Poco/Crypto/KeyPair.h"
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class X509Certificate;
|
|
||||||
class PKCS12Container;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API ECKey : public KeyPair
|
|
||||||
/// This class stores an EC key pair, consisting
|
|
||||||
/// of private and public key. Storage of the private
|
|
||||||
/// key is optional.
|
|
||||||
///
|
|
||||||
/// If a private key is available, the ECKey can be
|
|
||||||
/// used for decrypting data (encrypted with the public key)
|
|
||||||
/// or computing secure digital signatures.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
ECKey(const EVPPKey& key);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC key.
|
|
||||||
|
|
||||||
ECKey(const X509Certificate& cert);
|
|
||||||
/// Extracts the EC public key from the given certificate.
|
|
||||||
|
|
||||||
ECKey(const PKCS12Container& cert);
|
|
||||||
/// Extracts the EC private key from the given certificate.
|
|
||||||
|
|
||||||
ECKey(const std::string& eccGroup);
|
|
||||||
/// Creates the ECKey. Creates a new public/private key pair using the given parameters.
|
|
||||||
/// Can be used to sign data and verify signatures.
|
|
||||||
|
|
||||||
ECKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase = "");
|
|
||||||
/// Creates the ECKey, by reading public and private key from the given files and
|
|
||||||
/// using the given passphrase for the private key.
|
|
||||||
///
|
|
||||||
/// Cannot be used for signing or decryption unless a private key is available.
|
|
||||||
///
|
|
||||||
/// If a private key is specified, you don't need to specify a public key file.
|
|
||||||
/// OpenSSL will auto-create the public key from the private key.
|
|
||||||
|
|
||||||
ECKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream = 0, const std::string& privateKeyPassphrase = "");
|
|
||||||
/// Creates the ECKey, by reading public and private key from the given streams and
|
|
||||||
/// using the given passphrase for the private key.
|
|
||||||
///
|
|
||||||
/// Cannot be used for signing or decryption unless a private key is available.
|
|
||||||
///
|
|
||||||
/// If a private key is specified, you don't need to specify a public key file.
|
|
||||||
/// OpenSSL will auto-create the public key from the private key.
|
|
||||||
|
|
||||||
~ECKey();
|
|
||||||
/// Destroys the ECKey.
|
|
||||||
|
|
||||||
ECKeyImpl::Ptr impl() const;
|
|
||||||
/// Returns the impl object.
|
|
||||||
|
|
||||||
static std::string getCurveName(int nid = -1);
|
|
||||||
/// Returns elliptical curve name corresponding to
|
|
||||||
/// the given nid; if nid is not found, returns
|
|
||||||
/// empty string.
|
|
||||||
///
|
|
||||||
/// If nid is -1, returns first curve name.
|
|
||||||
///
|
|
||||||
/// If no curves are found, returns empty string;
|
|
||||||
|
|
||||||
static int getCurveNID(std::string& name);
|
|
||||||
/// Returns the NID of the specified curve.
|
|
||||||
///
|
|
||||||
/// If name is empty, returns the first curve NID
|
|
||||||
/// and updates the name accordingly.
|
|
||||||
|
|
||||||
static bool hasCurve(const std::string& name);
|
|
||||||
/// Returns true if the named curve is found,
|
|
||||||
/// false otherwise.
|
|
||||||
|
|
||||||
private:
|
|
||||||
ECKeyImpl::Ptr _pImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline ECKeyImpl::Ptr ECKey::impl() const
|
|
||||||
{
|
{
|
||||||
return _pImpl;
|
|
||||||
|
|
||||||
|
class X509Certificate;
|
||||||
|
class PKCS12Container;
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API ECKey : public KeyPair
|
||||||
|
/// This class stores an EC key pair, consisting
|
||||||
|
/// of private and public key. Storage of the private
|
||||||
|
/// key is optional.
|
||||||
|
///
|
||||||
|
/// If a private key is available, the ECKey can be
|
||||||
|
/// used for decrypting data (encrypted with the public key)
|
||||||
|
/// or computing secure digital signatures.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ECKey(const EVPPKey & key);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC key.
|
||||||
|
|
||||||
|
ECKey(const X509Certificate & cert);
|
||||||
|
/// Extracts the EC public key from the given certificate.
|
||||||
|
|
||||||
|
ECKey(const PKCS12Container & cert);
|
||||||
|
/// Extracts the EC private key from the given certificate.
|
||||||
|
|
||||||
|
ECKey(const std::string & eccGroup);
|
||||||
|
/// Creates the ECKey. Creates a new public/private key pair using the given parameters.
|
||||||
|
/// Can be used to sign data and verify signatures.
|
||||||
|
|
||||||
|
ECKey(const std::string & publicKeyFile, const std::string & privateKeyFile, const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the ECKey, by reading public and private key from the given files and
|
||||||
|
/// using the given passphrase for the private key.
|
||||||
|
///
|
||||||
|
/// Cannot be used for signing or decryption unless a private key is available.
|
||||||
|
///
|
||||||
|
/// If a private key is specified, you don't need to specify a public key file.
|
||||||
|
/// OpenSSL will auto-create the public key from the private key.
|
||||||
|
|
||||||
|
ECKey(std::istream * pPublicKeyStream, std::istream * pPrivateKeyStream = 0, const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the ECKey, by reading public and private key from the given streams and
|
||||||
|
/// using the given passphrase for the private key.
|
||||||
|
///
|
||||||
|
/// Cannot be used for signing or decryption unless a private key is available.
|
||||||
|
///
|
||||||
|
/// If a private key is specified, you don't need to specify a public key file.
|
||||||
|
/// OpenSSL will auto-create the public key from the private key.
|
||||||
|
|
||||||
|
~ECKey();
|
||||||
|
/// Destroys the ECKey.
|
||||||
|
|
||||||
|
ECKeyImpl::Ptr impl() const;
|
||||||
|
/// Returns the impl object.
|
||||||
|
|
||||||
|
static std::string getCurveName(int nid = -1);
|
||||||
|
/// Returns elliptical curve name corresponding to
|
||||||
|
/// the given nid; if nid is not found, returns
|
||||||
|
/// empty string.
|
||||||
|
///
|
||||||
|
/// If nid is -1, returns first curve name.
|
||||||
|
///
|
||||||
|
/// If no curves are found, returns empty string;
|
||||||
|
|
||||||
|
static int getCurveNID(std::string & name);
|
||||||
|
/// Returns the NID of the specified curve.
|
||||||
|
///
|
||||||
|
/// If name is empty, returns the first curve NID
|
||||||
|
/// and updates the name accordingly.
|
||||||
|
|
||||||
|
static bool hasCurve(const std::string & name);
|
||||||
|
/// Returns true if the named curve is found,
|
||||||
|
/// false otherwise.
|
||||||
|
|
||||||
|
private:
|
||||||
|
ECKeyImpl::Ptr _pImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline ECKeyImpl::Ptr ECKey::impl() const
|
||||||
|
{
|
||||||
|
return _pImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::string ECKey::getCurveName(int nid)
|
||||||
|
{
|
||||||
|
return ECKeyImpl::getCurveName(nid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int ECKey::getCurveNID(std::string & name)
|
||||||
|
{
|
||||||
|
return ECKeyImpl::getCurveNID(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool ECKey::hasCurve(const std::string & name)
|
||||||
|
{
|
||||||
|
return ECKeyImpl::hasCurve(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline std::string ECKey::getCurveName(int nid)
|
|
||||||
{
|
|
||||||
return ECKeyImpl::getCurveName(nid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline int ECKey::getCurveNID(std::string& name)
|
|
||||||
{
|
|
||||||
return ECKeyImpl::getCurveNID(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ECKey::hasCurve(const std::string& name)
|
|
||||||
{
|
|
||||||
return ECKeyImpl::hasCurve(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_ECKey_INCLUDED
|
#endif // Crypto_ECKey_INCLUDED
|
||||||
|
@ -19,156 +19,125 @@
|
|||||||
#define Crypto_ECKeyImplImpl_INCLUDED
|
#define Crypto_ECKeyImplImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/objects.h>
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/EVPPKey.h"
|
#include "Poco/Crypto/EVPPKey.h"
|
||||||
#include "Poco/Crypto/KeyPairImpl.h"
|
#include "Poco/Crypto/KeyPairImpl.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
|
||||||
#include <istream>
|
|
||||||
#include <ostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <openssl/objects.h>
|
|
||||||
#include <openssl/ec.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class X509Certificate;
|
|
||||||
class PKCS12Container;
|
|
||||||
|
|
||||||
|
|
||||||
class ECKeyImpl: public KeyPairImpl
|
|
||||||
/// Elliptic Curve key clas implementation.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
typedef Poco::AutoPtr<ECKeyImpl> Ptr;
|
|
||||||
typedef std::vector<unsigned char> ByteVec;
|
|
||||||
|
|
||||||
ECKeyImpl(const EVPPKey& key);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC key.
|
|
||||||
|
|
||||||
ECKeyImpl(const X509Certificate& cert);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC public key from the given certificate.
|
|
||||||
|
|
||||||
ECKeyImpl(const PKCS12Container& cert);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC private key from the given certificate.
|
|
||||||
|
|
||||||
ECKeyImpl(int eccGroup);
|
|
||||||
/// Creates the ECKey of the specified group. Creates a new public/private keypair using the given parameters.
|
|
||||||
/// Can be used to sign data and verify signatures.
|
|
||||||
|
|
||||||
ECKeyImpl(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase);
|
|
||||||
/// Creates the ECKey, by reading public and private key from the given files and
|
|
||||||
/// using the given passphrase for the private key. Can only by used for signing if
|
|
||||||
/// a private key is available.
|
|
||||||
|
|
||||||
ECKeyImpl(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase);
|
|
||||||
/// Creates the ECKey. Can only by used for signing if pPrivKey
|
|
||||||
/// is not null. If a private key file is specified, you don't need to
|
|
||||||
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
|
||||||
|
|
||||||
~ECKeyImpl();
|
|
||||||
/// Destroys the ECKeyImpl.
|
|
||||||
|
|
||||||
EC_KEY* getECKey();
|
|
||||||
/// Returns the OpenSSL EC key.
|
|
||||||
|
|
||||||
const EC_KEY* getECKey() const;
|
|
||||||
/// Returns the OpenSSL EC key.
|
|
||||||
|
|
||||||
int size() const;
|
|
||||||
/// Returns the EC key length in bits.
|
|
||||||
|
|
||||||
int groupId() const;
|
|
||||||
/// Returns the EC key group integer Id.
|
|
||||||
|
|
||||||
std::string groupName() const;
|
|
||||||
/// Returns the EC key group name.
|
|
||||||
|
|
||||||
void save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile = "",
|
|
||||||
const std::string& privateKeyPassphrase = "") const;
|
|
||||||
/// Exports the public and private keys to the given files.
|
|
||||||
///
|
|
||||||
/// If an empty filename is specified, the corresponding key
|
|
||||||
/// is not exported.
|
|
||||||
|
|
||||||
void save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream = 0,
|
|
||||||
const std::string& privateKeyPassphrase = "") const;
|
|
||||||
/// Exports the public and private key to the given streams.
|
|
||||||
///
|
|
||||||
/// If a null pointer is passed for a stream, the corresponding
|
|
||||||
/// key is not exported.
|
|
||||||
|
|
||||||
static std::string getCurveName(int nid = -1);
|
|
||||||
/// Returns elliptical curve name corresponding to
|
|
||||||
/// the given nid; if nid is not found, returns
|
|
||||||
/// empty string.
|
|
||||||
///
|
|
||||||
/// If nid is -1, returns first curve name.
|
|
||||||
///
|
|
||||||
/// If no curves are found, returns empty string;
|
|
||||||
|
|
||||||
static int getCurveNID(std::string& name);
|
|
||||||
/// Returns the NID of the specified curve.
|
|
||||||
///
|
|
||||||
/// If name is empty, returns the first curve NID
|
|
||||||
/// and updates the name accordingly.
|
|
||||||
|
|
||||||
static bool hasCurve(const std::string& name);
|
|
||||||
/// Returns true if the named curve is found,
|
|
||||||
/// false otherwise.
|
|
||||||
|
|
||||||
private:
|
|
||||||
void checkEC(const std::string& method, const std::string& func) const;
|
|
||||||
void freeEC();
|
|
||||||
|
|
||||||
EC_KEY* _pEC;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline EC_KEY* ECKeyImpl::getECKey()
|
|
||||||
{
|
{
|
||||||
return _pEC;
|
|
||||||
|
|
||||||
|
class X509Certificate;
|
||||||
|
class PKCS12Container;
|
||||||
|
|
||||||
|
|
||||||
|
class ECKeyImpl : public KeyPairImpl
|
||||||
|
/// Elliptic Curve key clas implementation.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Poco::AutoPtr<ECKeyImpl> Ptr;
|
||||||
|
typedef std::vector<unsigned char> ByteVec;
|
||||||
|
|
||||||
|
ECKeyImpl(const EVPPKey & key);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC key.
|
||||||
|
|
||||||
|
ECKeyImpl(const X509Certificate & cert);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC public key from the given certificate.
|
||||||
|
|
||||||
|
ECKeyImpl(const PKCS12Container & cert);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC private key from the given certificate.
|
||||||
|
|
||||||
|
ECKeyImpl(int eccGroup);
|
||||||
|
/// Creates the ECKey of the specified group. Creates a new public/private keypair using the given parameters.
|
||||||
|
/// Can be used to sign data and verify signatures.
|
||||||
|
|
||||||
|
ECKeyImpl(const std::string & publicKeyFile, const std::string & privateKeyFile, const std::string & privateKeyPassphrase);
|
||||||
|
/// Creates the ECKey, by reading public and private key from the given files and
|
||||||
|
/// using the given passphrase for the private key. Can only by used for signing if
|
||||||
|
/// a private key is available.
|
||||||
|
|
||||||
|
ECKeyImpl(std::istream * pPublicKeyStream, std::istream * pPrivateKeyStream, const std::string & privateKeyPassphrase);
|
||||||
|
/// Creates the ECKey. Can only by used for signing if pPrivKey
|
||||||
|
/// is not null. If a private key file is specified, you don't need to
|
||||||
|
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
||||||
|
|
||||||
|
~ECKeyImpl();
|
||||||
|
/// Destroys the ECKeyImpl.
|
||||||
|
|
||||||
|
EC_KEY * getECKey();
|
||||||
|
/// Returns the OpenSSL EC key.
|
||||||
|
|
||||||
|
const EC_KEY * getECKey() const;
|
||||||
|
/// Returns the OpenSSL EC key.
|
||||||
|
|
||||||
|
int size() const;
|
||||||
|
/// Returns the EC key length in bits.
|
||||||
|
|
||||||
|
int groupId() const;
|
||||||
|
/// Returns the EC key group integer Id.
|
||||||
|
|
||||||
|
std::string groupName() const;
|
||||||
|
/// Returns the EC key group name.
|
||||||
|
|
||||||
|
static std::string getCurveName(int nid = -1);
|
||||||
|
/// Returns elliptical curve name corresponding to
|
||||||
|
/// the given nid; if nid is not found, returns
|
||||||
|
/// empty string.
|
||||||
|
///
|
||||||
|
/// If nid is -1, returns first curve name.
|
||||||
|
///
|
||||||
|
/// If no curves are found, returns empty string;
|
||||||
|
|
||||||
|
static int getCurveNID(std::string & name);
|
||||||
|
/// Returns the NID of the specified curve.
|
||||||
|
///
|
||||||
|
/// If name is empty, returns the first curve NID
|
||||||
|
/// and updates the name accordingly.
|
||||||
|
|
||||||
|
static bool hasCurve(const std::string & name);
|
||||||
|
/// Returns true if the named curve is found,
|
||||||
|
/// false otherwise.
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkEC(const std::string & method, const std::string & func) const;
|
||||||
|
void freeEC();
|
||||||
|
|
||||||
|
EC_KEY * _pEC;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline EC_KEY * ECKeyImpl::getECKey()
|
||||||
|
{
|
||||||
|
return _pEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const EC_KEY * ECKeyImpl::getECKey() const
|
||||||
|
{
|
||||||
|
return _pEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::string ECKeyImpl::groupName() const
|
||||||
|
{
|
||||||
|
return OBJ_nid2sn(groupId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline const EC_KEY* ECKeyImpl::getECKey() const
|
|
||||||
{
|
|
||||||
return _pEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::string ECKeyImpl::groupName() const
|
|
||||||
{
|
|
||||||
return OBJ_nid2sn(groupId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void ECKeyImpl::save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
EVPPKey(_pEC).save(publicKeyFile, privateKeyFile, privateKeyPassphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void ECKeyImpl::save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
EVPPKey(_pEC).save(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_ECKeyImplImpl_INCLUDED
|
#endif // Crypto_ECKeyImplImpl_INCLUDED
|
||||||
|
@ -19,336 +19,351 @@
|
|||||||
#define Crypto_EVPPKeyImpl_INCLUDED
|
#define Crypto_EVPPKeyImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/CryptoException.h"
|
#include "Poco/Crypto/CryptoException.h"
|
||||||
#include "Poco/StreamCopier.h"
|
#include "Poco/StreamCopier.h"
|
||||||
#include <openssl/ec.h>
|
|
||||||
#include <openssl/rsa.h>
|
|
||||||
#include <openssl/evp.h>
|
|
||||||
#include <openssl/pem.h>
|
|
||||||
#include <sstream>
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class ECKey;
|
|
||||||
class RSAKey;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API EVPPKey
|
|
||||||
/// Utility class for conversion of native keys to EVP.
|
|
||||||
/// Currently, only RSA and EC keys are supported.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
explicit EVPPKey(const std::string& ecCurveName);
|
|
||||||
/// Constructs EVPPKey from ECC curve name.
|
|
||||||
///
|
|
||||||
/// Only EC keys can be wrapped by an EVPPKey
|
|
||||||
/// created using this constructor.
|
|
||||||
|
|
||||||
explicit EVPPKey(const char* ecCurveName);
|
|
||||||
/// Constructs EVPPKey from ECC curve name.
|
|
||||||
///
|
|
||||||
/// Only EC keys can be wrapped by an EVPPKey
|
|
||||||
/// created using this constructor.
|
|
||||||
|
|
||||||
explicit EVPPKey(EVP_PKEY* pEVPPKey);
|
class ECKey;
|
||||||
/// Constructs EVPPKey from EVP_PKEY pointer.
|
class RSAKey;
|
||||||
/// The content behind the supplied pointer is internally duplicated.
|
|
||||||
|
|
||||||
template<typename K>
|
|
||||||
explicit EVPPKey(K* pKey): _pEVPPKey(EVP_PKEY_new())
|
|
||||||
/// Constructs EVPPKey from a "native" OpenSSL (RSA or EC_KEY),
|
|
||||||
/// or a Poco wrapper (RSAKey, ECKey) key pointer.
|
|
||||||
{
|
|
||||||
if (!_pEVPPKey) throw OpenSSLException();
|
|
||||||
setKey(pKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
EVPPKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase = "");
|
class Crypto_API EVPPKey
|
||||||
/// Creates the EVPPKey, by reading public and private key from the given files and
|
/// Utility class for conversion of native keys to EVP.
|
||||||
/// using the given passphrase for the private key. Can only by used for signing if
|
/// Currently, only RSA and EC keys are supported.
|
||||||
/// a private key is available.
|
{
|
||||||
|
public:
|
||||||
|
explicit EVPPKey(const std::string & ecCurveName);
|
||||||
|
/// Constructs EVPPKey from ECC curve name.
|
||||||
|
///
|
||||||
|
/// Only EC keys can be wrapped by an EVPPKey
|
||||||
|
/// created using this constructor.
|
||||||
|
|
||||||
EVPPKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase = "");
|
explicit EVPPKey(const char * ecCurveName);
|
||||||
/// Creates the EVPPKey. Can only by used for signing if pPrivKey
|
/// Constructs EVPPKey from ECC curve name.
|
||||||
/// is not null. If a private key file is specified, you don't need to
|
///
|
||||||
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
/// Only EC keys can be wrapped by an EVPPKey
|
||||||
|
/// created using this constructor.
|
||||||
|
|
||||||
EVPPKey(const EVPPKey& other);
|
explicit EVPPKey(EVP_PKEY * pEVPPKey);
|
||||||
/// Copy constructor.
|
/// Constructs EVPPKey from EVP_PKEY pointer.
|
||||||
|
/// The content behind the supplied pointer is internally duplicated.
|
||||||
|
|
||||||
EVPPKey& operator=(const EVPPKey& other);
|
template <typename K>
|
||||||
/// Assignment operator.
|
explicit EVPPKey(K * pKey) : _pEVPPKey(EVP_PKEY_new())
|
||||||
|
/// Constructs EVPPKey from a "native" OpenSSL (RSA or EC_KEY),
|
||||||
|
/// or a Poco wrapper (RSAKey, ECKey) key pointer.
|
||||||
|
{
|
||||||
|
if (!_pEVPPKey)
|
||||||
|
throw OpenSSLException();
|
||||||
|
setKey(pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVPPKey(const std::string & publicKeyFile, const std::string & privateKeyFile, const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the EVPPKey, by reading public and private key from the given files and
|
||||||
|
/// using the given passphrase for the private key. Can only by used for signing if
|
||||||
|
/// a private key is available.
|
||||||
|
|
||||||
|
EVPPKey(std::istream * pPublicKeyStream, std::istream * pPrivateKeyStream, const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the EVPPKey. Can only by used for signing if pPrivKey
|
||||||
|
/// is not null. If a private key file is specified, you don't need to
|
||||||
|
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
||||||
|
|
||||||
|
EVPPKey(const EVPPKey & other);
|
||||||
|
/// Copy constructor.
|
||||||
|
|
||||||
|
EVPPKey & operator=(const EVPPKey & other);
|
||||||
|
/// Assignment operator.
|
||||||
|
|
||||||
#ifdef POCO_ENABLE_CPP11
|
#ifdef POCO_ENABLE_CPP11
|
||||||
|
|
||||||
EVPPKey(EVPPKey&& other);
|
EVPPKey(EVPPKey && other);
|
||||||
/// Move constructor.
|
/// Move constructor.
|
||||||
|
|
||||||
EVPPKey& operator=(EVPPKey&& other);
|
EVPPKey & operator=(EVPPKey && other);
|
||||||
/// Assignment move operator.
|
/// Assignment move operator.
|
||||||
|
|
||||||
#endif // POCO_ENABLE_CPP11
|
#endif // POCO_ENABLE_CPP11
|
||||||
|
|
||||||
~EVPPKey();
|
~EVPPKey();
|
||||||
/// Destroys the EVPPKey.
|
/// Destroys the EVPPKey.
|
||||||
|
|
||||||
bool operator == (const EVPPKey& other) const;
|
bool operator==(const EVPPKey & other) const;
|
||||||
/// Comparison operator.
|
/// Comparison operator.
|
||||||
/// Returns true if public key components and parameters
|
/// Returns true if public key components and parameters
|
||||||
/// of the other key are equal to this key.
|
/// of the other key are equal to this key.
|
||||||
///
|
///
|
||||||
/// Works as expected when one key contains only public key,
|
/// Works as expected when one key contains only public key,
|
||||||
/// while the other one contains private (thus also public) key.
|
/// while the other one contains private (thus also public) key.
|
||||||
|
|
||||||
bool operator != (const EVPPKey& other) const;
|
bool operator!=(const EVPPKey & other) const;
|
||||||
/// Comparison operator.
|
/// Comparison operator.
|
||||||
/// Returns true if public key components and parameters
|
/// Returns true if public key components and parameters
|
||||||
/// of the other key are different from this key.
|
/// of the other key are different from this key.
|
||||||
///
|
///
|
||||||
/// Works as expected when one key contains only public key,
|
/// Works as expected when one key contains only public key,
|
||||||
/// while the other one contains private (thus also public) key.
|
/// while the other one contains private (thus also public) key.
|
||||||
|
|
||||||
void save(const std::string& publicKeyFile, const std::string& privateKeyFile = "", const std::string& privateKeyPassphrase = "") const;
|
void save(const std::string & publicKeyFile, const std::string & privateKeyFile = "", const std::string & privateKeyPassphrase = "")
|
||||||
/// Exports the public and/or private keys to the given files.
|
const;
|
||||||
///
|
/// Exports the public and/or private keys to the given files.
|
||||||
/// If an empty filename is specified, the corresponding key
|
///
|
||||||
/// is not exported.
|
/// If an empty filename is specified, the corresponding key
|
||||||
|
/// is not exported.
|
||||||
|
|
||||||
void save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream = 0, const std::string& privateKeyPassphrase = "") const;
|
void
|
||||||
/// Exports the public and/or private key to the given streams.
|
save(std::ostream * pPublicKeyStream, std::ostream * pPrivateKeyStream = 0, const std::string & privateKeyPassphrase = "") const;
|
||||||
///
|
/// Exports the public and/or private key to the given streams.
|
||||||
/// If a null pointer is passed for a stream, the corresponding
|
///
|
||||||
/// key is not exported.
|
/// If a null pointer is passed for a stream, the corresponding
|
||||||
|
/// key is not exported.
|
||||||
|
|
||||||
int type() const;
|
int type() const;
|
||||||
/// Returns the EVPPKey type NID.
|
/// Returns the EVPPKey type NID.
|
||||||
|
|
||||||
bool isSupported(int type) const;
|
bool isSupported(int type) const;
|
||||||
/// Returns true if OpenSSL type is supported
|
/// Returns true if OpenSSL type is supported
|
||||||
|
|
||||||
operator const EVP_PKEY*() const;
|
operator const EVP_PKEY *() const;
|
||||||
/// Returns const pointer to the OpenSSL EVP_PKEY structure.
|
/// Returns const pointer to the OpenSSL EVP_PKEY structure.
|
||||||
|
|
||||||
operator EVP_PKEY*();
|
operator EVP_PKEY *();
|
||||||
/// Returns pointer to the OpenSSL EVP_PKEY structure.
|
/// Returns pointer to the OpenSSL EVP_PKEY structure.
|
||||||
|
|
||||||
static EVP_PKEY* duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey);
|
static EVP_PKEY * duplicate(const EVP_PKEY * pFromKey, EVP_PKEY ** pToKey);
|
||||||
/// Duplicates pFromKey into *pToKey and returns
|
/// Duplicates pFromKey into *pToKey and returns
|
||||||
// the pointer to duplicated EVP_PKEY.
|
// the pointer to duplicated EVP_PKEY.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EVPPKey();
|
EVPPKey();
|
||||||
|
|
||||||
static int type(const EVP_PKEY* pEVPPKey);
|
static int type(const EVP_PKEY * pEVPPKey);
|
||||||
void newECKey(const char* group);
|
void newECKey(const char * group);
|
||||||
void duplicate(EVP_PKEY* pEVPPKey);
|
void duplicate(EVP_PKEY * pEVPPKey);
|
||||||
|
|
||||||
void setKey(ECKey* pKey);
|
void setKey(ECKey * pKey);
|
||||||
void setKey(RSAKey* pKey);
|
void setKey(RSAKey * pKey);
|
||||||
void setKey(EC_KEY* pKey);
|
void setKey(EC_KEY * pKey);
|
||||||
void setKey(RSA* pKey);
|
void setKey(RSA * pKey);
|
||||||
static int passCB(char* buf, int size, int, void* pass);
|
static int passCB(char * buf, int size, int, void * pass);
|
||||||
|
|
||||||
typedef EVP_PKEY* (*PEM_read_FILE_Key_fn)(FILE*, EVP_PKEY**, pem_password_cb*, void*);
|
typedef EVP_PKEY * (*PEM_read_FILE_Key_fn)(FILE *, EVP_PKEY **, pem_password_cb *, void *);
|
||||||
typedef EVP_PKEY* (*PEM_read_BIO_Key_fn)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
|
typedef EVP_PKEY * (*PEM_read_BIO_Key_fn)(BIO *, EVP_PKEY **, pem_password_cb *, void *);
|
||||||
typedef void* (*EVP_PKEY_get_Key_fn)(EVP_PKEY*);
|
typedef void * (*EVP_PKEY_get_Key_fn)(EVP_PKEY *);
|
||||||
|
|
||||||
// The following load*() functions are used by both native and EVP_PKEY type key
|
// The following load*() functions are used by both native and EVP_PKEY type key
|
||||||
// loading from BIO/FILE.
|
// loading from BIO/FILE.
|
||||||
// When used for EVP key loading, getFunc is null (ie. native key is not extracted
|
// When used for EVP key loading, getFunc is null (ie. native key is not extracted
|
||||||
// from the loaded EVP_PKEY).
|
// from the loaded EVP_PKEY).
|
||||||
template <typename K, typename F>
|
template <typename K, typename F>
|
||||||
static bool loadKey(K** ppKey,
|
static bool
|
||||||
PEM_read_FILE_Key_fn readFunc,
|
loadKey(K ** ppKey, PEM_read_FILE_Key_fn readFunc, F getFunc, const std::string & keyFile, const std::string & pass = "")
|
||||||
F getFunc,
|
{
|
||||||
const std::string& keyFile,
|
poco_assert_dbg(
|
||||||
const std::string& pass = "")
|
((typeid(K *) == typeid(RSA *) || typeid(K *) == typeid(EC_KEY *)) && getFunc)
|
||||||
{
|
|| ((typeid(K *) == typeid(EVP_PKEY *)) && !getFunc));
|
||||||
poco_assert_dbg (((typeid(K*) == typeid(RSA*) || typeid(K*) == typeid(EC_KEY*)) && getFunc) ||
|
poco_check_ptr(ppKey);
|
||||||
((typeid(K*) == typeid(EVP_PKEY*)) && !getFunc));
|
poco_assert_dbg(!*ppKey);
|
||||||
poco_check_ptr (ppKey);
|
|
||||||
poco_assert_dbg (!*ppKey);
|
|
||||||
|
|
||||||
FILE* pFile = 0;
|
FILE * pFile = 0;
|
||||||
if (!keyFile.empty())
|
if (!keyFile.empty())
|
||||||
{
|
{
|
||||||
if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
|
if (!getFunc)
|
||||||
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
|
*ppKey = (K *)EVP_PKEY_new();
|
||||||
if (pKey)
|
EVP_PKEY * pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY *)*ppKey;
|
||||||
{
|
if (pKey)
|
||||||
pFile = fopen(keyFile.c_str(), "r");
|
{
|
||||||
if (pFile)
|
pFile = fopen(keyFile.c_str(), "r");
|
||||||
{
|
if (pFile)
|
||||||
pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
|
{
|
||||||
void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
|
pem_password_cb * pCB = pass.empty() ? (pem_password_cb *)0 : &passCB;
|
||||||
if (readFunc(pFile, &pKey, pCB, pPassword))
|
void * pPassword = pass.empty() ? (void *)0 : (void *)pass.c_str();
|
||||||
{
|
if (readFunc(pFile, &pKey, pCB, pPassword))
|
||||||
fclose(pFile); pFile = 0;
|
{
|
||||||
if(getFunc)
|
fclose(pFile);
|
||||||
{
|
pFile = 0;
|
||||||
*ppKey = (K*)getFunc(pKey);
|
if (getFunc)
|
||||||
EVP_PKEY_free(pKey);
|
{
|
||||||
}
|
*ppKey = (K *)getFunc(pKey);
|
||||||
else
|
EVP_PKEY_free(pKey);
|
||||||
{
|
}
|
||||||
poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
|
else
|
||||||
*ppKey = (K*)pKey;
|
{
|
||||||
}
|
poco_assert_dbg(typeid(K *) == typeid(EVP_PKEY *));
|
||||||
if(!*ppKey) goto error;
|
*ppKey = (K *)pKey;
|
||||||
return true;
|
}
|
||||||
}
|
if (!*ppKey)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
return true;
|
||||||
else
|
}
|
||||||
{
|
goto error;
|
||||||
if (getFunc) EVP_PKEY_free(pKey);
|
}
|
||||||
throw IOException("ECKeyImpl, cannot open file", keyFile);
|
else
|
||||||
}
|
{
|
||||||
}
|
if (getFunc)
|
||||||
else goto error;
|
EVP_PKEY_free(pKey);
|
||||||
}
|
throw IOException("ECKeyImpl, cannot open file", keyFile);
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (pFile) fclose(pFile);
|
if (pFile)
|
||||||
throw OpenSSLException("EVPKey::loadKey(string)");
|
fclose(pFile);
|
||||||
}
|
throw OpenSSLException("EVPKey::loadKey(string)");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename K, typename F>
|
template <typename K, typename F>
|
||||||
static bool loadKey(K** ppKey,
|
static bool loadKey(K ** ppKey, PEM_read_BIO_Key_fn readFunc, F getFunc, std::istream * pIstr, const std::string & pass = "")
|
||||||
PEM_read_BIO_Key_fn readFunc,
|
{
|
||||||
F getFunc,
|
poco_assert_dbg(
|
||||||
std::istream* pIstr,
|
((typeid(K *) == typeid(RSA *) || typeid(K *) == typeid(EC_KEY *)) && getFunc)
|
||||||
const std::string& pass = "")
|
|| ((typeid(K *) == typeid(EVP_PKEY *)) && !getFunc));
|
||||||
{
|
poco_check_ptr(ppKey);
|
||||||
poco_assert_dbg (((typeid(K*) == typeid(RSA*) || typeid(K*) == typeid(EC_KEY*)) && getFunc) ||
|
poco_assert_dbg(!*ppKey);
|
||||||
((typeid(K*) == typeid(EVP_PKEY*)) && !getFunc));
|
|
||||||
poco_check_ptr(ppKey);
|
|
||||||
poco_assert_dbg(!*ppKey);
|
|
||||||
|
|
||||||
BIO* pBIO = 0;
|
BIO * pBIO = 0;
|
||||||
if (pIstr)
|
if (pIstr)
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
Poco::StreamCopier::copyStream(*pIstr, ostr);
|
Poco::StreamCopier::copyStream(*pIstr, ostr);
|
||||||
std::string key = ostr.str();
|
std::string key = ostr.str();
|
||||||
pBIO = BIO_new_mem_buf(const_cast<char*>(key.data()), static_cast<int>(key.size()));
|
pBIO = BIO_new_mem_buf(const_cast<char *>(key.data()), static_cast<int>(key.size()));
|
||||||
if (pBIO)
|
if (pBIO)
|
||||||
{
|
{
|
||||||
if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
|
if (!getFunc)
|
||||||
EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
|
*ppKey = (K *)EVP_PKEY_new();
|
||||||
if (pKey)
|
EVP_PKEY * pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY *)*ppKey;
|
||||||
{
|
if (pKey)
|
||||||
pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
|
{
|
||||||
void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
|
pem_password_cb * pCB = pass.empty() ? (pem_password_cb *)0 : &passCB;
|
||||||
if (readFunc(pBIO, &pKey, pCB, pPassword))
|
void * pPassword = pass.empty() ? (void *)0 : (void *)pass.c_str();
|
||||||
{
|
if (readFunc(pBIO, &pKey, pCB, pPassword))
|
||||||
BIO_free(pBIO); pBIO = 0;
|
{
|
||||||
if (getFunc)
|
BIO_free(pBIO);
|
||||||
{
|
pBIO = 0;
|
||||||
*ppKey = (K*)getFunc(pKey);
|
if (getFunc)
|
||||||
EVP_PKEY_free(pKey);
|
{
|
||||||
}
|
*ppKey = (K *)getFunc(pKey);
|
||||||
else
|
EVP_PKEY_free(pKey);
|
||||||
{
|
}
|
||||||
poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
|
else
|
||||||
*ppKey = (K*)pKey;
|
{
|
||||||
}
|
poco_assert_dbg(typeid(K *) == typeid(EVP_PKEY *));
|
||||||
if (!*ppKey) goto error;
|
*ppKey = (K *)pKey;
|
||||||
return true;
|
}
|
||||||
}
|
if (!*ppKey)
|
||||||
if (getFunc) EVP_PKEY_free(pKey);
|
goto error;
|
||||||
goto error;
|
return true;
|
||||||
}
|
}
|
||||||
else goto error;
|
if (getFunc)
|
||||||
}
|
EVP_PKEY_free(pKey);
|
||||||
else goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
return false;
|
else
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (pBIO) BIO_free(pBIO);
|
if (pBIO)
|
||||||
throw OpenSSLException("EVPKey::loadKey(stream)");
|
BIO_free(pBIO);
|
||||||
}
|
throw OpenSSLException("EVPKey::loadKey(stream)");
|
||||||
|
}
|
||||||
|
|
||||||
EVP_PKEY* _pEVPPKey;
|
EVP_PKEY * _pEVPPKey;
|
||||||
|
|
||||||
friend class ECKeyImpl;
|
friend class ECKeyImpl;
|
||||||
friend class RSAKeyImpl;
|
friend class RSAKeyImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
inline bool EVPPKey::operator==(const EVPPKey & other) const
|
||||||
|
{
|
||||||
|
poco_check_ptr(other._pEVPPKey);
|
||||||
|
poco_check_ptr(_pEVPPKey);
|
||||||
|
return (1 == EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool EVPPKey::operator!=(const EVPPKey & other) const
|
||||||
|
{
|
||||||
|
return !(other == *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int EVPPKey::type(const EVP_PKEY * pEVPPKey)
|
||||||
|
{
|
||||||
|
if (!pEVPPKey)
|
||||||
|
return NID_undef;
|
||||||
|
|
||||||
|
return EVP_PKEY_type(EVP_PKEY_id(pEVPPKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline int EVPPKey::type() const
|
||||||
|
{
|
||||||
|
return type(_pEVPPKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool EVPPKey::isSupported(int type) const
|
||||||
|
{
|
||||||
|
return type == EVP_PKEY_EC || type == EVP_PKEY_RSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline EVPPKey::operator const EVP_PKEY *() const
|
||||||
|
{
|
||||||
|
return _pEVPPKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline EVPPKey::operator EVP_PKEY *()
|
||||||
|
{
|
||||||
|
return _pEVPPKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void EVPPKey::setKey(EC_KEY * pKey)
|
||||||
|
{
|
||||||
|
if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pKey))
|
||||||
|
throw OpenSSLException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void EVPPKey::setKey(RSA * pKey)
|
||||||
|
{
|
||||||
|
if (!EVP_PKEY_set1_RSA(_pEVPPKey, pKey))
|
||||||
|
throw OpenSSLException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool EVPPKey::operator == (const EVPPKey& other) const
|
|
||||||
{
|
|
||||||
poco_check_ptr (other._pEVPPKey);
|
|
||||||
poco_check_ptr (_pEVPPKey);
|
|
||||||
return (1 == EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey));
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline bool EVPPKey::operator != (const EVPPKey& other) const
|
|
||||||
{
|
|
||||||
return !(other == *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline int EVPPKey::type(const EVP_PKEY* pEVPPKey)
|
|
||||||
{
|
|
||||||
if (!pEVPPKey) return NID_undef;
|
|
||||||
|
|
||||||
return EVP_PKEY_type(EVP_PKEY_id(pEVPPKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline int EVPPKey::type() const
|
|
||||||
{
|
|
||||||
return type(_pEVPPKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool EVPPKey::isSupported(int type) const
|
|
||||||
{
|
|
||||||
return type == EVP_PKEY_EC || type == EVP_PKEY_RSA;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline EVPPKey::operator const EVP_PKEY*() const
|
|
||||||
{
|
|
||||||
return _pEVPPKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline EVPPKey::operator EVP_PKEY*()
|
|
||||||
{
|
|
||||||
return _pEVPPKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void EVPPKey::setKey(EC_KEY* pKey)
|
|
||||||
{
|
|
||||||
if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pKey))
|
|
||||||
throw OpenSSLException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void EVPPKey::setKey(RSA* pKey)
|
|
||||||
{
|
|
||||||
if (!EVP_PKEY_set1_RSA(_pEVPPKey, pKey))
|
|
||||||
throw OpenSSLException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_EVPPKeyImpl_INCLUDED
|
#endif // Crypto_EVPPKeyImpl_INCLUDED
|
||||||
|
@ -23,111 +23,81 @@
|
|||||||
#include "Poco/Crypto/KeyPairImpl.h"
|
#include "Poco/Crypto/KeyPairImpl.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class X509Certificate;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API KeyPair
|
|
||||||
/// This is a parent class for classes storing a key pair, consisting
|
|
||||||
/// of private and public key. Storage of the private key is optional.
|
|
||||||
///
|
|
||||||
/// If a private key is available, the KeyPair can be
|
|
||||||
/// used for decrypting data (encrypted with the public key)
|
|
||||||
/// or computing secure digital signatures.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
KT_RSA = KeyPairImpl::KT_RSA_IMPL,
|
|
||||||
KT_EC = KeyPairImpl::KT_EC_IMPL
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit KeyPair(KeyPairImpl::Ptr pKeyPairImpl = 0);
|
|
||||||
/// Extracts the RSA public key from the given certificate.
|
|
||||||
|
|
||||||
virtual ~KeyPair();
|
|
||||||
/// Destroys the KeyPair.
|
|
||||||
|
|
||||||
virtual int size() const;
|
|
||||||
/// Returns the RSA modulus size.
|
|
||||||
|
|
||||||
virtual void save(const std::string& publicKeyPairFile,
|
|
||||||
const std::string& privateKeyPairFile = "",
|
|
||||||
const std::string& privateKeyPairPassphrase = "") const;
|
|
||||||
/// Exports the public and private keys to the given files.
|
|
||||||
///
|
|
||||||
/// If an empty filename is specified, the corresponding key
|
|
||||||
/// is not exported.
|
|
||||||
|
|
||||||
virtual void save(std::ostream* pPublicKeyPairStream,
|
|
||||||
std::ostream* pPrivateKeyPairStream = 0,
|
|
||||||
const std::string& privateKeyPairPassphrase = "") const;
|
|
||||||
/// Exports the public and private key to the given streams.
|
|
||||||
///
|
|
||||||
/// If a null pointer is passed for a stream, the corresponding
|
|
||||||
/// key is not exported.
|
|
||||||
|
|
||||||
KeyPairImpl::Ptr impl() const;
|
|
||||||
/// Returns the impl object.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns key pair name
|
|
||||||
|
|
||||||
Type type() const;
|
|
||||||
/// Returns key pair type
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeyPairImpl::Ptr _pImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
|
|
||||||
inline int KeyPair::size() const
|
|
||||||
{
|
{
|
||||||
return _pImpl->size();
|
|
||||||
|
|
||||||
|
class X509Certificate;
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API KeyPair
|
||||||
|
/// This is a parent class for classes storing a key pair, consisting
|
||||||
|
/// of private and public key. Storage of the private key is optional.
|
||||||
|
///
|
||||||
|
/// If a private key is available, the KeyPair can be
|
||||||
|
/// used for decrypting data (encrypted with the public key)
|
||||||
|
/// or computing secure digital signatures.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
KT_RSA = KeyPairImpl::KT_RSA_IMPL,
|
||||||
|
KT_EC = KeyPairImpl::KT_EC_IMPL
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit KeyPair(KeyPairImpl::Ptr pKeyPairImpl = 0);
|
||||||
|
/// Extracts the RSA public key from the given certificate.
|
||||||
|
|
||||||
|
virtual ~KeyPair();
|
||||||
|
/// Destroys the KeyPair.
|
||||||
|
|
||||||
|
virtual int size() const;
|
||||||
|
/// Returns the RSA modulus size.
|
||||||
|
|
||||||
|
KeyPairImpl::Ptr impl() const;
|
||||||
|
/// Returns the impl object.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns key pair name
|
||||||
|
|
||||||
|
Type type() const;
|
||||||
|
/// Returns key pair type
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyPairImpl::Ptr _pImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
|
||||||
|
inline int KeyPair::size() const
|
||||||
|
{
|
||||||
|
return _pImpl->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const std::string & KeyPair::name() const
|
||||||
|
{
|
||||||
|
return _pImpl->name();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline KeyPairImpl::Ptr KeyPair::impl() const
|
||||||
|
{
|
||||||
|
return _pImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline KeyPair::Type KeyPair::type() const
|
||||||
|
{
|
||||||
|
return (KeyPair::Type)impl()->type();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline void KeyPair::save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
_pImpl->save(publicKeyFile, privateKeyFile, privateKeyPassphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void KeyPair::save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
_pImpl->save(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& KeyPair::name() const
|
|
||||||
{
|
|
||||||
return _pImpl->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline KeyPairImpl::Ptr KeyPair::impl() const
|
|
||||||
{
|
|
||||||
return _pImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline KeyPair::Type KeyPair::type() const
|
|
||||||
{
|
|
||||||
return (KeyPair::Type)impl()->type();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_KeyPair_INCLUDED
|
#endif // Crypto_KeyPair_INCLUDED
|
||||||
|
@ -19,89 +19,76 @@
|
|||||||
#define Crypto_KeyPairImplImpl_INCLUDED
|
#define Crypto_KeyPairImplImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class KeyPairImpl: public Poco::RefCountedObject
|
|
||||||
/// Class KeyPairImpl
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
KT_RSA_IMPL = 0,
|
|
||||||
KT_EC_IMPL
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Poco::AutoPtr<KeyPairImpl> Ptr;
|
|
||||||
typedef std::vector<unsigned char> ByteVec;
|
|
||||||
|
|
||||||
KeyPairImpl(const std::string& name, Type type);
|
|
||||||
/// Create KeyPairImpl with specified type and name.
|
|
||||||
|
|
||||||
virtual ~KeyPairImpl();
|
|
||||||
/// Destroys the KeyPairImpl.
|
|
||||||
|
|
||||||
virtual int size() const = 0;
|
|
||||||
/// Returns the key size.
|
|
||||||
|
|
||||||
virtual void save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile = "",
|
|
||||||
const std::string& privateKeyPassphrase = "") const = 0;
|
|
||||||
/// Exports the public and private keys to the given files.
|
|
||||||
///
|
|
||||||
/// If an empty filename is specified, the corresponding key
|
|
||||||
/// is not exported.
|
|
||||||
|
|
||||||
virtual void save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream = 0,
|
|
||||||
const std::string& privateKeyPassphrase = "") const = 0;
|
|
||||||
/// Exports the public and private key to the given streams.
|
|
||||||
///
|
|
||||||
/// If a null pointer is passed for a stream, the corresponding
|
|
||||||
/// key is not exported.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns key pair name
|
|
||||||
|
|
||||||
Type type() const;
|
|
||||||
/// Returns key pair type
|
|
||||||
|
|
||||||
private:
|
|
||||||
KeyPairImpl();
|
|
||||||
|
|
||||||
std::string _name;
|
|
||||||
Type _type;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& KeyPairImpl::name() const
|
|
||||||
{
|
{
|
||||||
return _name;
|
|
||||||
|
|
||||||
|
class KeyPairImpl : public Poco::RefCountedObject
|
||||||
|
/// Class KeyPairImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
KT_RSA_IMPL = 0,
|
||||||
|
KT_EC_IMPL
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Poco::AutoPtr<KeyPairImpl> Ptr;
|
||||||
|
typedef std::vector<unsigned char> ByteVec;
|
||||||
|
|
||||||
|
KeyPairImpl(const std::string & name, Type type);
|
||||||
|
/// Create KeyPairImpl with specified type and name.
|
||||||
|
|
||||||
|
virtual ~KeyPairImpl();
|
||||||
|
/// Destroys the KeyPairImpl.
|
||||||
|
|
||||||
|
virtual int size() const = 0;
|
||||||
|
/// Returns the key size.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns key pair name
|
||||||
|
|
||||||
|
Type type() const;
|
||||||
|
/// Returns key pair type
|
||||||
|
|
||||||
|
private:
|
||||||
|
KeyPairImpl();
|
||||||
|
|
||||||
|
std::string _name;
|
||||||
|
Type _type;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string & KeyPairImpl::name() const
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline KeyPairImpl::Type KeyPairImpl::type() const
|
||||||
|
{
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline KeyPairImpl::Type KeyPairImpl::type() const
|
|
||||||
{
|
|
||||||
return _type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_KeyPairImplImpl_INCLUDED
|
#endif // Crypto_KeyPairImplImpl_INCLUDED
|
||||||
|
@ -18,98 +18,100 @@
|
|||||||
#define Crypto_OpenSSLInitializer_INCLUDED
|
#define Crypto_OpenSSLInitializer_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include "Poco/AtomicCounter.h"
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Mutex.h"
|
#include "Poco/Mutex.h"
|
||||||
#include "Poco/AtomicCounter.h"
|
|
||||||
#include <openssl/crypto.h>
|
|
||||||
|
|
||||||
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_NUMBER < 0x010001000L
|
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_NUMBER < 0x010001000L
|
||||||
#include <openssl/fips.h>
|
# include <openssl/fips.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
extern "C"
|
extern "C" {
|
||||||
|
struct CRYPTO_dynlock_value
|
||||||
{
|
{
|
||||||
struct CRYPTO_dynlock_value
|
Poco::FastMutex _mutex;
|
||||||
{
|
|
||||||
Poco::FastMutex _mutex;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API OpenSSLInitializer
|
|
||||||
/// Initializes the OpenSSL library.
|
|
||||||
///
|
|
||||||
/// The class ensures the earliest initialization and the
|
|
||||||
/// latest shutdown of the OpenSSL library.
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OpenSSLInitializer();
|
|
||||||
/// Automatically initialize OpenSSL on startup.
|
|
||||||
|
|
||||||
~OpenSSLInitializer();
|
|
||||||
/// Automatically shut down OpenSSL on exit.
|
|
||||||
|
|
||||||
static void initialize();
|
|
||||||
/// Initializes the OpenSSL machinery.
|
|
||||||
|
|
||||||
static void uninitialize();
|
|
||||||
/// Shuts down the OpenSSL machinery.
|
|
||||||
|
|
||||||
static bool isFIPSEnabled();
|
|
||||||
// Returns true if FIPS mode is enabled, false otherwise.
|
|
||||||
|
|
||||||
static void enableFIPSMode(bool enabled);
|
|
||||||
// Enable or disable FIPS mode. If FIPS is not available, this method doesn't do anything.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SEEDSIZE = 256
|
|
||||||
};
|
|
||||||
|
|
||||||
// OpenSSL multithreading support
|
|
||||||
static void lock(int mode, int n, const char* file, int line);
|
|
||||||
static unsigned long id();
|
|
||||||
static struct CRYPTO_dynlock_value* dynlockCreate(const char* file, int line);
|
|
||||||
static void dynlock(int mode, struct CRYPTO_dynlock_value* lock, const char* file, int line);
|
|
||||||
static void dynlockDestroy(struct CRYPTO_dynlock_value* lock, const char* file, int line);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static Poco::FastMutex* _mutexes;
|
|
||||||
static Poco::AtomicCounter _rc;
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
namespace Poco
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline bool OpenSSLInitializer::isFIPSEnabled()
|
|
||||||
{
|
{
|
||||||
|
namespace Crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API OpenSSLInitializer
|
||||||
|
/// Initializes the OpenSSL library.
|
||||||
|
///
|
||||||
|
/// The class ensures the earliest initialization and the
|
||||||
|
/// latest shutdown of the OpenSSL library.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpenSSLInitializer();
|
||||||
|
/// Automatically initialize OpenSSL on startup.
|
||||||
|
|
||||||
|
~OpenSSLInitializer();
|
||||||
|
/// Automatically shut down OpenSSL on exit.
|
||||||
|
|
||||||
|
static void initialize();
|
||||||
|
/// Initializes the OpenSSL machinery.
|
||||||
|
|
||||||
|
static void uninitialize();
|
||||||
|
/// Shuts down the OpenSSL machinery.
|
||||||
|
|
||||||
|
static bool isFIPSEnabled();
|
||||||
|
// Returns true if FIPS mode is enabled, false otherwise.
|
||||||
|
|
||||||
|
static void enableFIPSMode(bool enabled);
|
||||||
|
// Enable or disable FIPS mode. If FIPS is not available, this method doesn't do anything.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SEEDSIZE = 256
|
||||||
|
};
|
||||||
|
|
||||||
|
// OpenSSL multithreading support
|
||||||
|
static void lock(int mode, int n, const char * file, int line);
|
||||||
|
static unsigned long id();
|
||||||
|
static struct CRYPTO_dynlock_value * dynlockCreate(const char * file, int line);
|
||||||
|
static void dynlock(int mode, struct CRYPTO_dynlock_value * lock, const char * file, int line);
|
||||||
|
static void dynlockDestroy(struct CRYPTO_dynlock_value * lock, const char * file, int line);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Poco::FastMutex * _mutexes;
|
||||||
|
static Poco::AtomicCounter _rc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline bool OpenSSLInitializer::isFIPSEnabled()
|
||||||
|
{
|
||||||
#ifdef OPENSSL_FIPS
|
#ifdef OPENSSL_FIPS
|
||||||
return FIPS_mode() ? true : false;
|
return FIPS_mode() ? true : false;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef OPENSSL_FIPS
|
#ifdef OPENSSL_FIPS
|
||||||
inline void OpenSSLInitializer::enableFIPSMode(bool enabled)
|
inline void OpenSSLInitializer::enableFIPSMode(bool enabled)
|
||||||
{
|
{
|
||||||
FIPS_mode_set(enabled);
|
FIPS_mode_set(enabled);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
inline void OpenSSLInitializer::enableFIPSMode(bool /*enabled*/)
|
inline void OpenSSLInitializer::enableFIPSMode(bool /*enabled*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_OpenSSLInitializer_INCLUDED
|
#endif // Crypto_OpenSSLInitializer_INCLUDED
|
||||||
|
@ -18,142 +18,145 @@
|
|||||||
#define Crypto_PKCS12Container_INCLUDED
|
#define Crypto_PKCS12Container_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <memory>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
#include "Poco/Crypto/EVPPKey.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/Crypto/X509Certificate.h"
|
#include "Poco/Crypto/X509Certificate.h"
|
||||||
#include "Poco/Crypto/EVPPKey.h"
|
|
||||||
#include "Poco/Path.h"
|
#include "Poco/Path.h"
|
||||||
#include <memory>
|
|
||||||
#include <istream>
|
|
||||||
#include <openssl/pkcs12.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class Crypto_API PKCS12Container
|
|
||||||
/// This class implements PKCS#12 container functionality.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
typedef X509Certificate::List CAList;
|
|
||||||
typedef std::vector<std::string> CANameList;
|
|
||||||
|
|
||||||
explicit PKCS12Container(std::istream& istr, const std::string& password = "");
|
|
||||||
/// Creates the PKCS12Container object from a stream.
|
|
||||||
|
|
||||||
explicit PKCS12Container(const std::string& path, const std::string& password = "");
|
class Crypto_API PKCS12Container
|
||||||
/// Creates the PKCS12Container object from a file.
|
/// This class implements PKCS#12 container functionality.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef X509Certificate::List CAList;
|
||||||
|
typedef std::vector<std::string> CANameList;
|
||||||
|
|
||||||
PKCS12Container(const PKCS12Container& cont);
|
explicit PKCS12Container(std::istream & istr, const std::string & password = "");
|
||||||
/// Copy constructor.
|
/// Creates the PKCS12Container object from a stream.
|
||||||
|
|
||||||
PKCS12Container& operator = (const PKCS12Container& cont);
|
explicit PKCS12Container(const std::string & path, const std::string & password = "");
|
||||||
/// Assignment operator.
|
/// Creates the PKCS12Container object from a file.
|
||||||
|
|
||||||
|
PKCS12Container(const PKCS12Container & cont);
|
||||||
|
/// Copy constructor.
|
||||||
|
|
||||||
|
PKCS12Container & operator=(const PKCS12Container & cont);
|
||||||
|
/// Assignment operator.
|
||||||
|
|
||||||
#ifdef POCO_ENABLE_CPP11
|
#ifdef POCO_ENABLE_CPP11
|
||||||
|
|
||||||
PKCS12Container(PKCS12Container&& cont);
|
PKCS12Container(PKCS12Container && cont);
|
||||||
/// Move constructor.
|
/// Move constructor.
|
||||||
|
|
||||||
PKCS12Container& operator = (PKCS12Container&& cont);
|
PKCS12Container & operator=(PKCS12Container && cont);
|
||||||
/// Move assignment operator.
|
/// Move assignment operator.
|
||||||
|
|
||||||
#endif // POCO_ENABLE_CPP11
|
#endif // POCO_ENABLE_CPP11
|
||||||
|
|
||||||
~PKCS12Container();
|
~PKCS12Container();
|
||||||
/// Destroys the PKCS12Container.
|
/// Destroys the PKCS12Container.
|
||||||
|
|
||||||
bool hasKey() const;
|
bool hasKey() const;
|
||||||
/// Returns true if container contains the key.
|
/// Returns true if container contains the key.
|
||||||
|
|
||||||
EVPPKey getKey() const;
|
EVPPKey getKey() const;
|
||||||
/// Return key as openssl EVP_PKEY wrapper object.
|
/// Return key as openssl EVP_PKEY wrapper object.
|
||||||
|
|
||||||
bool hasX509Certificate() const;
|
bool hasX509Certificate() const;
|
||||||
/// Returns true if container has X509 certificate.
|
/// Returns true if container has X509 certificate.
|
||||||
|
|
||||||
const X509Certificate& getX509Certificate() const;
|
const X509Certificate & getX509Certificate() const;
|
||||||
/// Returns the X509 certificate.
|
/// Returns the X509 certificate.
|
||||||
/// Throws NotFoundException if there is no certificate.
|
/// Throws NotFoundException if there is no certificate.
|
||||||
|
|
||||||
const CAList& getCACerts() const;
|
const CAList & getCACerts() const;
|
||||||
/// Returns the list of CA certificates in this container.
|
/// Returns the list of CA certificates in this container.
|
||||||
|
|
||||||
const std::string& getFriendlyName() const;
|
const std::string & getFriendlyName() const;
|
||||||
/// Returns the friendly name of the certificate bag.
|
/// Returns the friendly name of the certificate bag.
|
||||||
|
|
||||||
const CANameList& getFriendlyNamesCA() const;
|
const CANameList & getFriendlyNamesCA() const;
|
||||||
/// Returns a list of CA certificates friendly names.
|
/// Returns a list of CA certificates friendly names.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void load(PKCS12* pPKCS12, const std::string& password = "");
|
void load(PKCS12 * pPKCS12, const std::string & password = "");
|
||||||
std::string extractFriendlyName(X509* pCert);
|
std::string extractFriendlyName(X509 * pCert);
|
||||||
|
|
||||||
#ifdef POCO_ENABLE_CPP11
|
#ifdef POCO_ENABLE_CPP11
|
||||||
typedef std::unique_ptr<X509Certificate> CertPtr;
|
typedef std::unique_ptr<X509Certificate> CertPtr;
|
||||||
#else
|
#else
|
||||||
typedef std::auto_ptr<X509Certificate> CertPtr;
|
typedef std::auto_ptr<X509Certificate> CertPtr;
|
||||||
#endif // #ifdef POCO_ENABLE_CPP11
|
#endif // #ifdef POCO_ENABLE_CPP11
|
||||||
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
EVP_PKEY* _pKey;
|
EVP_PKEY * _pKey;
|
||||||
CertPtr _pX509Cert;
|
CertPtr _pX509Cert;
|
||||||
CAList _caCertList;
|
CAList _caCertList;
|
||||||
CANameList _caCertNames;
|
CANameList _caCertNames;
|
||||||
std::string _pkcsFriendlyName;
|
std::string _pkcsFriendlyName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// inlines
|
// inlines
|
||||||
//
|
//
|
||||||
|
|
||||||
|
inline bool PKCS12Container::hasX509Certificate() const
|
||||||
|
{
|
||||||
|
return _pX509Cert.get() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const X509Certificate & PKCS12Container::getX509Certificate() const
|
||||||
|
{
|
||||||
|
if (!hasX509Certificate())
|
||||||
|
throw NotFoundException("PKCS12Container X509 certificate");
|
||||||
|
return *_pX509Cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string & PKCS12Container::getFriendlyName() const
|
||||||
|
{
|
||||||
|
return _pkcsFriendlyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const PKCS12Container::CAList & PKCS12Container::getCACerts() const
|
||||||
|
{
|
||||||
|
return _caCertList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const PKCS12Container::CANameList & PKCS12Container::getFriendlyNamesCA() const
|
||||||
|
{
|
||||||
|
return _caCertNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool PKCS12Container::hasKey() const
|
||||||
|
{
|
||||||
|
return _pKey != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline EVPPKey PKCS12Container::getKey() const
|
||||||
|
{
|
||||||
|
return EVPPKey(_pKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool PKCS12Container::hasX509Certificate() const
|
|
||||||
{
|
|
||||||
return _pX509Cert.get() != 0;
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline const X509Certificate& PKCS12Container::getX509Certificate() const
|
|
||||||
{
|
|
||||||
if (!hasX509Certificate())
|
|
||||||
throw NotFoundException("PKCS12Container X509 certificate");
|
|
||||||
return *_pX509Cert;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& PKCS12Container::getFriendlyName() const
|
|
||||||
{
|
|
||||||
return _pkcsFriendlyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const PKCS12Container::CAList& PKCS12Container::getCACerts() const
|
|
||||||
{
|
|
||||||
return _caCertList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const PKCS12Container::CANameList& PKCS12Container::getFriendlyNamesCA() const
|
|
||||||
{
|
|
||||||
return _caCertNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool PKCS12Container::hasKey() const
|
|
||||||
{
|
|
||||||
return _pKey != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline EVPPKey PKCS12Container::getKey() const
|
|
||||||
{
|
|
||||||
return EVPPKey(_pKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_PKCS12Container_INCLUDED
|
#endif // Crypto_PKCS12Container_INCLUDED
|
||||||
|
@ -18,60 +18,63 @@
|
|||||||
#define Crypto_RSACipherImpl_INCLUDED
|
#define Crypto_RSACipherImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/Crypto/Cipher.h"
|
|
||||||
#include "Poco/Crypto/RSAKey.h"
|
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
|
#include "Poco/Crypto/Cipher.h"
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
|
#include "Poco/Crypto/RSAKey.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class RSACipherImpl: public Cipher
|
|
||||||
/// An implementation of the Cipher class for
|
|
||||||
/// asymmetric (public-private key) encryption
|
|
||||||
/// based on the the RSA algorithm in OpenSSL's
|
|
||||||
/// crypto library.
|
|
||||||
///
|
|
||||||
/// Encryption is using the public key, decryption
|
|
||||||
/// requires the private key.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
RSACipherImpl(const RSAKey& key, RSAPaddingMode paddingMode);
|
|
||||||
/// Creates a new RSACipherImpl object for the given RSAKey
|
|
||||||
/// and using the given padding mode.
|
|
||||||
|
|
||||||
virtual ~RSACipherImpl();
|
|
||||||
/// Destroys the RSACipherImpl.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns the name of the Cipher.
|
|
||||||
|
|
||||||
CryptoTransform* createEncryptor();
|
|
||||||
/// Creates an encryptor object.
|
|
||||||
|
|
||||||
CryptoTransform* createDecryptor();
|
|
||||||
/// Creates a decryptor object.
|
|
||||||
|
|
||||||
private:
|
|
||||||
RSAKey _key;
|
|
||||||
RSAPaddingMode _paddingMode;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Inlines
|
|
||||||
//
|
|
||||||
inline const std::string& RSACipherImpl::name() const
|
|
||||||
{
|
{
|
||||||
return _key.name();
|
|
||||||
|
|
||||||
|
class RSACipherImpl : public Cipher
|
||||||
|
/// An implementation of the Cipher class for
|
||||||
|
/// asymmetric (public-private key) encryption
|
||||||
|
/// based on the the RSA algorithm in OpenSSL's
|
||||||
|
/// crypto library.
|
||||||
|
///
|
||||||
|
/// Encryption is using the public key, decryption
|
||||||
|
/// requires the private key.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RSACipherImpl(const RSAKey & key, RSAPaddingMode paddingMode);
|
||||||
|
/// Creates a new RSACipherImpl object for the given RSAKey
|
||||||
|
/// and using the given padding mode.
|
||||||
|
|
||||||
|
virtual ~RSACipherImpl();
|
||||||
|
/// Destroys the RSACipherImpl.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns the name of the Cipher.
|
||||||
|
|
||||||
|
CryptoTransform * createEncryptor();
|
||||||
|
/// Creates an encryptor object.
|
||||||
|
|
||||||
|
CryptoTransform * createDecryptor();
|
||||||
|
/// Creates a decryptor object.
|
||||||
|
|
||||||
|
private:
|
||||||
|
RSAKey _key;
|
||||||
|
RSAPaddingMode _paddingMode;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inlines
|
||||||
|
//
|
||||||
|
inline const std::string & RSACipherImpl::name() const
|
||||||
|
{
|
||||||
|
return _key.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_RSACipherImpl_INCLUDED
|
#endif // Crypto_RSACipherImpl_INCLUDED
|
||||||
|
@ -18,94 +18,97 @@
|
|||||||
#define Crypto_RSADigestEngine_INCLUDED
|
#define Crypto_RSADigestEngine_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Crypto/Crypto.h"
|
|
||||||
#include "Poco/Crypto/RSAKey.h"
|
|
||||||
#include "Poco/DigestEngine.h"
|
|
||||||
#include "Poco/Crypto/DigestEngine.h"
|
|
||||||
#include <istream>
|
#include <istream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include "Poco/Crypto/Crypto.h"
|
||||||
|
#include "Poco/Crypto/DigestEngine.h"
|
||||||
|
#include "Poco/Crypto/RSAKey.h"
|
||||||
|
#include "Poco/DigestEngine.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
{
|
||||||
|
namespace Crypto
|
||||||
|
|
||||||
class Crypto_API RSADigestEngine: public Poco::DigestEngine
|
|
||||||
/// This class implements a Poco::DigestEngine that can be
|
|
||||||
/// used to compute a secure digital signature.
|
|
||||||
///
|
|
||||||
/// First another Poco::Crypto::DigestEngine is created and
|
|
||||||
/// used to compute a cryptographic hash of the data to be
|
|
||||||
/// signed. Then, the hash value is encrypted, using
|
|
||||||
/// the RSA private key.
|
|
||||||
///
|
|
||||||
/// To verify a signature, pass it to the verify()
|
|
||||||
/// member function. It will decrypt the signature
|
|
||||||
/// using the RSA public key and compare the resulting
|
|
||||||
/// hash with the actual hash of the data.
|
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
enum DigestType
|
|
||||||
{
|
|
||||||
DIGEST_MD5,
|
|
||||||
DIGEST_SHA1
|
|
||||||
};
|
|
||||||
|
|
||||||
//@ deprecated
|
|
||||||
RSADigestEngine(const RSAKey& key, DigestType digestType = DIGEST_SHA1);
|
|
||||||
/// Creates the RSADigestEngine with the given RSA key,
|
|
||||||
/// using the MD5 or SHA-1 hash algorithm.
|
|
||||||
/// Kept for backward compatibility
|
|
||||||
|
|
||||||
RSADigestEngine(const RSAKey& key, const std::string &name);
|
|
||||||
/// Creates the RSADigestEngine with the given RSA key,
|
|
||||||
/// using the hash algorithm with the given name
|
|
||||||
/// (e.g., "MD5", "SHA1", "SHA256", "SHA512", etc.).
|
|
||||||
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
|
||||||
///
|
|
||||||
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
|
||||||
|
|
||||||
~RSADigestEngine();
|
|
||||||
/// Destroys the RSADigestEngine.
|
|
||||||
|
|
||||||
std::size_t digestLength() const;
|
|
||||||
/// Returns the length of the digest in bytes.
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
/// Resets the engine so that a new
|
|
||||||
/// digest can be computed.
|
|
||||||
|
|
||||||
const DigestEngine::Digest& digest();
|
|
||||||
/// Finishes the computation of the digest
|
|
||||||
/// (the first time it's called) and
|
|
||||||
/// returns the message digest.
|
|
||||||
///
|
|
||||||
/// Can be called multiple times.
|
|
||||||
|
|
||||||
const DigestEngine::Digest& signature();
|
|
||||||
/// Signs the digest using the RSA algorithm
|
|
||||||
/// and the private key (the first time it's
|
|
||||||
/// called) and returns the result.
|
|
||||||
///
|
|
||||||
/// Can be called multiple times.
|
|
||||||
|
|
||||||
bool verify(const DigestEngine::Digest& signature);
|
|
||||||
/// Verifies the data against the signature.
|
|
||||||
///
|
|
||||||
/// Returns true if the signature can be verified, false otherwise.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void updateImpl(const void* data, std::size_t length);
|
|
||||||
|
|
||||||
private:
|
|
||||||
RSAKey _key;
|
|
||||||
Poco::Crypto::DigestEngine _engine;
|
|
||||||
Poco::DigestEngine::Digest _digest;
|
|
||||||
Poco::DigestEngine::Digest _signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
class Crypto_API RSADigestEngine : public Poco::DigestEngine
|
||||||
|
/// This class implements a Poco::DigestEngine that can be
|
||||||
|
/// used to compute a secure digital signature.
|
||||||
|
///
|
||||||
|
/// First another Poco::Crypto::DigestEngine is created and
|
||||||
|
/// used to compute a cryptographic hash of the data to be
|
||||||
|
/// signed. Then, the hash value is encrypted, using
|
||||||
|
/// the RSA private key.
|
||||||
|
///
|
||||||
|
/// To verify a signature, pass it to the verify()
|
||||||
|
/// member function. It will decrypt the signature
|
||||||
|
/// using the RSA public key and compare the resulting
|
||||||
|
/// hash with the actual hash of the data.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum DigestType
|
||||||
|
{
|
||||||
|
DIGEST_MD5,
|
||||||
|
DIGEST_SHA1
|
||||||
|
};
|
||||||
|
|
||||||
|
//@ deprecated
|
||||||
|
RSADigestEngine(const RSAKey & key, DigestType digestType = DIGEST_SHA1);
|
||||||
|
/// Creates the RSADigestEngine with the given RSA key,
|
||||||
|
/// using the MD5 or SHA-1 hash algorithm.
|
||||||
|
/// Kept for backward compatibility
|
||||||
|
|
||||||
|
RSADigestEngine(const RSAKey & key, const std::string & name);
|
||||||
|
/// Creates the RSADigestEngine with the given RSA key,
|
||||||
|
/// using the hash algorithm with the given name
|
||||||
|
/// (e.g., "MD5", "SHA1", "SHA256", "SHA512", etc.).
|
||||||
|
/// See the OpenSSL documentation for a list of supported digest algorithms.
|
||||||
|
///
|
||||||
|
/// Throws a Poco::NotFoundException if no algorithm with the given name exists.
|
||||||
|
|
||||||
|
~RSADigestEngine();
|
||||||
|
/// Destroys the RSADigestEngine.
|
||||||
|
|
||||||
|
std::size_t digestLength() const;
|
||||||
|
/// Returns the length of the digest in bytes.
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
/// Resets the engine so that a new
|
||||||
|
/// digest can be computed.
|
||||||
|
|
||||||
|
const DigestEngine::Digest & digest();
|
||||||
|
/// Finishes the computation of the digest
|
||||||
|
/// (the first time it's called) and
|
||||||
|
/// returns the message digest.
|
||||||
|
///
|
||||||
|
/// Can be called multiple times.
|
||||||
|
|
||||||
|
const DigestEngine::Digest & signature();
|
||||||
|
/// Signs the digest using the RSA algorithm
|
||||||
|
/// and the private key (the first time it's
|
||||||
|
/// called) and returns the result.
|
||||||
|
///
|
||||||
|
/// Can be called multiple times.
|
||||||
|
|
||||||
|
bool verify(const DigestEngine::Digest & signature);
|
||||||
|
/// Verifies the data against the signature.
|
||||||
|
///
|
||||||
|
/// Returns true if the signature can be verified, false otherwise.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateImpl(const void * data, std::size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RSAKey _key;
|
||||||
|
Poco::Crypto::DigestEngine _engine;
|
||||||
|
Poco::DigestEngine::Digest _digest;
|
||||||
|
Poco::DigestEngine::Digest _signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_RSADigestEngine_INCLUDED
|
#endif // Crypto_RSADigestEngine_INCLUDED
|
||||||
|
@ -23,103 +23,102 @@
|
|||||||
#include "Poco/Crypto/RSAKeyImpl.h"
|
#include "Poco/Crypto/RSAKeyImpl.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class X509Certificate;
|
|
||||||
class PKCS12Container;
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API RSAKey : public KeyPair
|
|
||||||
/// This class stores an RSA key pair, consisting
|
|
||||||
/// of private and public key. Storage of the private
|
|
||||||
/// key is optional.
|
|
||||||
///
|
|
||||||
/// If a private key is available, the RSAKey can be
|
|
||||||
/// used for decrypting data (encrypted with the public key)
|
|
||||||
/// or computing secure digital signatures.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
enum KeyLength
|
|
||||||
{
|
|
||||||
KL_512 = 512,
|
|
||||||
KL_1024 = 1024,
|
|
||||||
KL_2048 = 2048,
|
|
||||||
KL_4096 = 4096
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Exponent
|
|
||||||
{
|
|
||||||
EXP_SMALL = 0,
|
|
||||||
EXP_LARGE
|
|
||||||
};
|
|
||||||
|
|
||||||
RSAKey(const EVPPKey& key);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC key.
|
|
||||||
|
|
||||||
RSAKey(const X509Certificate& cert);
|
|
||||||
/// Extracts the RSA public key from the given certificate.
|
|
||||||
|
|
||||||
RSAKey(const PKCS12Container& cert);
|
|
||||||
/// Extracts the RSA private key from the given certificate.
|
|
||||||
|
|
||||||
RSAKey(KeyLength keyLength, Exponent exp);
|
|
||||||
/// Creates the RSAKey. Creates a new public/private keypair using the given parameters.
|
|
||||||
/// Can be used to sign data and verify signatures.
|
|
||||||
|
|
||||||
RSAKey(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile = "",
|
|
||||||
const std::string& privateKeyPassphrase = "");
|
|
||||||
/// Creates the RSAKey, by reading public and private key from the given files and
|
|
||||||
/// using the given passphrase for the private key.
|
|
||||||
///
|
|
||||||
/// Cannot be used for signing or decryption unless a private key is available.
|
|
||||||
///
|
|
||||||
/// If a private key is specified, you don't need to specify a public key file.
|
|
||||||
/// OpenSSL will auto-create the public key from the private key.
|
|
||||||
|
|
||||||
RSAKey(std::istream* pPublicKeyStream,
|
|
||||||
std::istream* pPrivateKeyStream = 0,
|
|
||||||
const std::string& privateKeyPassphrase = "");
|
|
||||||
/// Creates the RSAKey, by reading public and private key from the given streams and
|
|
||||||
/// using the given passphrase for the private key.
|
|
||||||
///
|
|
||||||
/// Cannot be used for signing or decryption unless a private key is available.
|
|
||||||
///
|
|
||||||
/// If a private key is specified, you don't need to specify a public key file.
|
|
||||||
/// OpenSSL will auto-create the public key from the private key.
|
|
||||||
|
|
||||||
~RSAKey();
|
|
||||||
/// Destroys the RSAKey.
|
|
||||||
|
|
||||||
RSAKeyImpl::ByteVec modulus() const;
|
|
||||||
/// Returns the RSA modulus.
|
|
||||||
|
|
||||||
RSAKeyImpl::ByteVec encryptionExponent() const;
|
|
||||||
/// Returns the RSA encryption exponent.
|
|
||||||
|
|
||||||
RSAKeyImpl::ByteVec decryptionExponent() const;
|
|
||||||
/// Returns the RSA decryption exponent.
|
|
||||||
|
|
||||||
RSAKeyImpl::Ptr impl() const;
|
|
||||||
/// Returns the impl object.
|
|
||||||
|
|
||||||
private:
|
|
||||||
RSAKeyImpl::Ptr _pImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline RSAKeyImpl::Ptr RSAKey::impl() const
|
|
||||||
{
|
{
|
||||||
return _pImpl;
|
|
||||||
|
|
||||||
|
class X509Certificate;
|
||||||
|
class PKCS12Container;
|
||||||
|
|
||||||
|
|
||||||
|
class Crypto_API RSAKey : public KeyPair
|
||||||
|
/// This class stores an RSA key pair, consisting
|
||||||
|
/// of private and public key. Storage of the private
|
||||||
|
/// key is optional.
|
||||||
|
///
|
||||||
|
/// If a private key is available, the RSAKey can be
|
||||||
|
/// used for decrypting data (encrypted with the public key)
|
||||||
|
/// or computing secure digital signatures.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum KeyLength
|
||||||
|
{
|
||||||
|
KL_512 = 512,
|
||||||
|
KL_1024 = 1024,
|
||||||
|
KL_2048 = 2048,
|
||||||
|
KL_4096 = 4096
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Exponent
|
||||||
|
{
|
||||||
|
EXP_SMALL = 0,
|
||||||
|
EXP_LARGE
|
||||||
|
};
|
||||||
|
|
||||||
|
RSAKey(const EVPPKey & key);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC key.
|
||||||
|
|
||||||
|
RSAKey(const X509Certificate & cert);
|
||||||
|
/// Extracts the RSA public key from the given certificate.
|
||||||
|
|
||||||
|
RSAKey(const PKCS12Container & cert);
|
||||||
|
/// Extracts the RSA private key from the given certificate.
|
||||||
|
|
||||||
|
RSAKey(KeyLength keyLength, Exponent exp);
|
||||||
|
/// Creates the RSAKey. Creates a new public/private keypair using the given parameters.
|
||||||
|
/// Can be used to sign data and verify signatures.
|
||||||
|
|
||||||
|
RSAKey(const std::string & publicKeyFile, const std::string & privateKeyFile = "", const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the RSAKey, by reading public and private key from the given files and
|
||||||
|
/// using the given passphrase for the private key.
|
||||||
|
///
|
||||||
|
/// Cannot be used for signing or decryption unless a private key is available.
|
||||||
|
///
|
||||||
|
/// If a private key is specified, you don't need to specify a public key file.
|
||||||
|
/// OpenSSL will auto-create the public key from the private key.
|
||||||
|
|
||||||
|
RSAKey(std::istream * pPublicKeyStream, std::istream * pPrivateKeyStream = 0, const std::string & privateKeyPassphrase = "");
|
||||||
|
/// Creates the RSAKey, by reading public and private key from the given streams and
|
||||||
|
/// using the given passphrase for the private key.
|
||||||
|
///
|
||||||
|
/// Cannot be used for signing or decryption unless a private key is available.
|
||||||
|
///
|
||||||
|
/// If a private key is specified, you don't need to specify a public key file.
|
||||||
|
/// OpenSSL will auto-create the public key from the private key.
|
||||||
|
|
||||||
|
~RSAKey();
|
||||||
|
/// Destroys the RSAKey.
|
||||||
|
|
||||||
|
RSAKeyImpl::ByteVec modulus() const;
|
||||||
|
/// Returns the RSA modulus.
|
||||||
|
|
||||||
|
RSAKeyImpl::ByteVec encryptionExponent() const;
|
||||||
|
/// Returns the RSA encryption exponent.
|
||||||
|
|
||||||
|
RSAKeyImpl::ByteVec decryptionExponent() const;
|
||||||
|
/// Returns the RSA decryption exponent.
|
||||||
|
|
||||||
|
RSAKeyImpl::Ptr impl() const;
|
||||||
|
/// Returns the impl object.
|
||||||
|
|
||||||
|
private:
|
||||||
|
RSAKeyImpl::Ptr _pImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline RSAKeyImpl::Ptr RSAKey::impl() const
|
||||||
|
{
|
||||||
|
return _pImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_RSAKey_INCLUDED
|
#endif // Crypto_RSAKey_INCLUDED
|
@ -18,15 +18,15 @@
|
|||||||
#define Crypto_RSAKeyImplImpl_INCLUDED
|
#define Crypto_RSAKeyImplImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
#include "Poco/AutoPtr.h"
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/EVPPKey.h"
|
#include "Poco/Crypto/EVPPKey.h"
|
||||||
#include "Poco/Crypto/KeyPairImpl.h"
|
#include "Poco/Crypto/KeyPairImpl.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/RefCountedObject.h"
|
#include "Poco/RefCountedObject.h"
|
||||||
#include "Poco/AutoPtr.h"
|
|
||||||
#include <istream>
|
|
||||||
#include <ostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
|
|
||||||
struct bignum_st;
|
struct bignum_st;
|
||||||
@ -35,107 +35,94 @@ typedef struct bignum_st BIGNUM;
|
|||||||
typedef struct rsa_st RSA;
|
typedef struct rsa_st RSA;
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class X509Certificate;
|
|
||||||
class PKCS12Container;
|
|
||||||
|
|
||||||
|
|
||||||
class RSAKeyImpl: public KeyPairImpl
|
|
||||||
/// class RSAKeyImpl
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
typedef Poco::AutoPtr<RSAKeyImpl> Ptr;
|
|
||||||
typedef std::vector<unsigned char> ByteVec;
|
|
||||||
|
|
||||||
RSAKeyImpl(const EVPPKey& key);
|
|
||||||
/// Constructs ECKeyImpl by extracting the EC key.
|
|
||||||
|
|
||||||
RSAKeyImpl(const X509Certificate& cert);
|
|
||||||
/// Extracts the RSA public key from the given certificate.
|
|
||||||
|
|
||||||
RSAKeyImpl(const PKCS12Container& cert);
|
|
||||||
/// Extracts the EC private key from the given certificate.
|
|
||||||
|
|
||||||
RSAKeyImpl(int keyLength, unsigned long exponent);
|
|
||||||
/// Creates the RSAKey. Creates a new public/private keypair using the given parameters.
|
|
||||||
/// Can be used to sign data and verify signatures.
|
|
||||||
|
|
||||||
RSAKeyImpl(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase);
|
|
||||||
/// Creates the RSAKey, by reading public and private key from the given files and
|
|
||||||
/// using the given passphrase for the private key. Can only by used for signing if
|
|
||||||
/// a private key is available.
|
|
||||||
|
|
||||||
RSAKeyImpl(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase);
|
|
||||||
/// Creates the RSAKey. Can only by used for signing if pPrivKey
|
|
||||||
/// is not null. If a private key file is specified, you don't need to
|
|
||||||
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
|
||||||
|
|
||||||
~RSAKeyImpl();
|
|
||||||
/// Destroys the RSAKeyImpl.
|
|
||||||
|
|
||||||
RSA* getRSA();
|
|
||||||
/// Returns the OpenSSL RSA object.
|
|
||||||
|
|
||||||
const RSA* getRSA() const;
|
|
||||||
/// Returns the OpenSSL RSA object.
|
|
||||||
|
|
||||||
int size() const;
|
|
||||||
/// Returns the RSA modulus size.
|
|
||||||
|
|
||||||
ByteVec modulus() const;
|
|
||||||
/// Returns the RSA modulus.
|
|
||||||
|
|
||||||
ByteVec encryptionExponent() const;
|
|
||||||
/// Returns the RSA encryption exponent.
|
|
||||||
|
|
||||||
ByteVec decryptionExponent() const;
|
|
||||||
/// Returns the RSA decryption exponent.
|
|
||||||
|
|
||||||
void save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile = "",
|
|
||||||
const std::string& privateKeyPassphrase = "") const;
|
|
||||||
/// Exports the public and private keys to the given files.
|
|
||||||
///
|
|
||||||
/// If an empty filename is specified, the corresponding key
|
|
||||||
/// is not exported.
|
|
||||||
|
|
||||||
void save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream = 0,
|
|
||||||
const std::string& privateKeyPassphrase = "") const;
|
|
||||||
/// Exports the public and private key to the given streams.
|
|
||||||
///
|
|
||||||
/// If a null pointer is passed for a stream, the corresponding
|
|
||||||
/// key is not exported.
|
|
||||||
|
|
||||||
private:
|
|
||||||
RSAKeyImpl();
|
|
||||||
|
|
||||||
void freeRSA();
|
|
||||||
static ByteVec convertToByteVec(const BIGNUM* bn);
|
|
||||||
|
|
||||||
RSA* _pRSA;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline RSA* RSAKeyImpl::getRSA()
|
|
||||||
{
|
{
|
||||||
return _pRSA;
|
|
||||||
|
|
||||||
|
class X509Certificate;
|
||||||
|
class PKCS12Container;
|
||||||
|
|
||||||
|
|
||||||
|
class RSAKeyImpl : public KeyPairImpl
|
||||||
|
/// class RSAKeyImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Poco::AutoPtr<RSAKeyImpl> Ptr;
|
||||||
|
typedef std::vector<unsigned char> ByteVec;
|
||||||
|
|
||||||
|
RSAKeyImpl(const EVPPKey & key);
|
||||||
|
/// Constructs ECKeyImpl by extracting the EC key.
|
||||||
|
|
||||||
|
RSAKeyImpl(const X509Certificate & cert);
|
||||||
|
/// Extracts the RSA public key from the given certificate.
|
||||||
|
|
||||||
|
RSAKeyImpl(const PKCS12Container & cert);
|
||||||
|
/// Extracts the EC private key from the given certificate.
|
||||||
|
|
||||||
|
RSAKeyImpl(int keyLength, unsigned long exponent);
|
||||||
|
/// Creates the RSAKey. Creates a new public/private keypair using the given parameters.
|
||||||
|
/// Can be used to sign data and verify signatures.
|
||||||
|
|
||||||
|
RSAKeyImpl(const std::string & publicKeyFile, const std::string & privateKeyFile, const std::string & privateKeyPassphrase);
|
||||||
|
/// Creates the RSAKey, by reading public and private key from the given files and
|
||||||
|
/// using the given passphrase for the private key. Can only by used for signing if
|
||||||
|
/// a private key is available.
|
||||||
|
|
||||||
|
RSAKeyImpl(std::istream * pPublicKeyStream, std::istream * pPrivateKeyStream, const std::string & privateKeyPassphrase);
|
||||||
|
/// Creates the RSAKey. Can only by used for signing if pPrivKey
|
||||||
|
/// is not null. If a private key file is specified, you don't need to
|
||||||
|
/// specify a public key file. OpenSSL will auto-create it from the private key.
|
||||||
|
|
||||||
|
~RSAKeyImpl();
|
||||||
|
/// Destroys the RSAKeyImpl.
|
||||||
|
|
||||||
|
RSA * getRSA();
|
||||||
|
/// Returns the OpenSSL RSA object.
|
||||||
|
|
||||||
|
const RSA * getRSA() const;
|
||||||
|
/// Returns the OpenSSL RSA object.
|
||||||
|
|
||||||
|
int size() const;
|
||||||
|
/// Returns the RSA modulus size.
|
||||||
|
|
||||||
|
ByteVec modulus() const;
|
||||||
|
/// Returns the RSA modulus.
|
||||||
|
|
||||||
|
ByteVec encryptionExponent() const;
|
||||||
|
/// Returns the RSA encryption exponent.
|
||||||
|
|
||||||
|
ByteVec decryptionExponent() const;
|
||||||
|
/// Returns the RSA decryption exponent.
|
||||||
|
|
||||||
|
private:
|
||||||
|
RSAKeyImpl();
|
||||||
|
|
||||||
|
void freeRSA();
|
||||||
|
static ByteVec convertToByteVec(const BIGNUM * bn);
|
||||||
|
|
||||||
|
RSA * _pRSA;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline RSA * RSAKeyImpl::getRSA()
|
||||||
|
{
|
||||||
|
return _pRSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const RSA * RSAKeyImpl::getRSA() const
|
||||||
|
{
|
||||||
|
return _pRSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
|
|
||||||
inline const RSA* RSAKeyImpl::getRSA() const
|
#endif // Crypto_RSAKeyImplImpl_INCLUDED
|
||||||
{
|
|
||||||
return _pRSA;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_RSAKeyImplImpl_INCLUDED
|
|
||||||
|
@ -18,228 +18,231 @@
|
|||||||
#define Crypto_X509Certificate_INCLUDED
|
#define Crypto_X509Certificate_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
#include "Poco/Crypto/Crypto.h"
|
#include "Poco/Crypto/Crypto.h"
|
||||||
#include "Poco/Crypto/OpenSSLInitializer.h"
|
#include "Poco/Crypto/OpenSSLInitializer.h"
|
||||||
#include "Poco/DateTime.h"
|
#include "Poco/DateTime.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
#include <vector>
|
|
||||||
#include <set>
|
|
||||||
#include <istream>
|
|
||||||
#include <openssl/ssl.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Crypto {
|
|
||||||
|
|
||||||
|
|
||||||
class Crypto_API X509Certificate
|
|
||||||
/// This class represents a X509 Certificate.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Crypto
|
||||||
typedef std::vector<X509Certificate> List;
|
|
||||||
|
|
||||||
enum NID
|
|
||||||
/// Name identifier for extracting information from
|
|
||||||
/// a certificate subject's or issuer's distinguished name.
|
|
||||||
{
|
|
||||||
NID_COMMON_NAME = 13,
|
|
||||||
NID_COUNTRY = 14,
|
|
||||||
NID_LOCALITY_NAME = 15,
|
|
||||||
NID_STATE_OR_PROVINCE = 16,
|
|
||||||
NID_ORGANIZATION_NAME = 17,
|
|
||||||
NID_ORGANIZATION_UNIT_NAME = 18,
|
|
||||||
NID_PKCS9_EMAIL_ADDRESS = 48,
|
|
||||||
NID_SERIAL_NUMBER = 105
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit X509Certificate(std::istream& istr);
|
|
||||||
/// Creates the X509Certificate object by reading
|
|
||||||
/// a certificate in PEM format from a stream.
|
|
||||||
|
|
||||||
explicit X509Certificate(const std::string& path);
|
|
||||||
/// Creates the X509Certificate object by reading
|
|
||||||
/// a certificate in PEM format from a file.
|
|
||||||
|
|
||||||
explicit X509Certificate(X509* pCert);
|
|
||||||
/// Creates the X509Certificate from an existing
|
|
||||||
/// OpenSSL certificate. Ownership is taken of
|
|
||||||
/// the certificate.
|
|
||||||
|
|
||||||
X509Certificate(X509* pCert, bool shared);
|
|
||||||
/// Creates the X509Certificate from an existing
|
|
||||||
/// OpenSSL certificate. Ownership is taken of
|
|
||||||
/// the certificate. If shared is true, the
|
|
||||||
/// certificate's reference count is incremented.
|
|
||||||
|
|
||||||
X509Certificate(const X509Certificate& cert);
|
|
||||||
/// Creates the certificate by copying another one.
|
|
||||||
|
|
||||||
X509Certificate& operator = (const X509Certificate& cert);
|
|
||||||
/// Assigns a certificate.
|
|
||||||
|
|
||||||
void swap(X509Certificate& cert);
|
|
||||||
/// Exchanges the certificate with another one.
|
|
||||||
|
|
||||||
~X509Certificate();
|
|
||||||
/// Destroys the X509Certificate.
|
|
||||||
|
|
||||||
long version() const;
|
|
||||||
/// Returns the version of the certificate.
|
|
||||||
|
|
||||||
const std::string& serialNumber() const;
|
|
||||||
/// Returns the certificate serial number as a
|
|
||||||
/// string in decimal encoding.
|
|
||||||
|
|
||||||
const std::string& issuerName() const;
|
|
||||||
/// Returns the certificate issuer's distinguished name.
|
|
||||||
|
|
||||||
std::string issuerName(NID nid) const;
|
|
||||||
/// Extracts the information specified by the given
|
|
||||||
/// NID (name identifier) from the certificate issuer's
|
|
||||||
/// distinguished name.
|
|
||||||
|
|
||||||
const std::string& subjectName() const;
|
|
||||||
/// Returns the certificate subject's distinguished name.
|
|
||||||
|
|
||||||
std::string subjectName(NID nid) const;
|
|
||||||
/// Extracts the information specified by the given
|
|
||||||
/// NID (name identifier) from the certificate subject's
|
|
||||||
/// distinguished name.
|
|
||||||
|
|
||||||
std::string commonName() const;
|
|
||||||
/// Returns the common name stored in the certificate
|
|
||||||
/// subject's distinguished name.
|
|
||||||
|
|
||||||
void extractNames(std::string& commonName, std::set<std::string>& domainNames) const;
|
|
||||||
/// Extracts the common name and the alias domain names from the
|
|
||||||
/// certificate.
|
|
||||||
|
|
||||||
Poco::DateTime validFrom() const;
|
|
||||||
/// Returns the date and time the certificate is valid from.
|
|
||||||
|
|
||||||
Poco::DateTime expiresOn() const;
|
|
||||||
/// Returns the date and time the certificate expires.
|
|
||||||
|
|
||||||
void save(std::ostream& stream) const;
|
|
||||||
/// Writes the certificate to the given stream.
|
|
||||||
/// The certificate is written in PEM format.
|
|
||||||
|
|
||||||
void save(const std::string& path) const;
|
|
||||||
/// Writes the certificate to the file given by path.
|
|
||||||
/// The certificate is written in PEM format.
|
|
||||||
|
|
||||||
bool issuedBy(const X509Certificate& issuerCertificate) const;
|
|
||||||
/// Checks whether the certificate has been issued by
|
|
||||||
/// the issuer given by issuerCertificate. This can be
|
|
||||||
/// used to validate a certificate chain.
|
|
||||||
///
|
|
||||||
/// Verifies if the certificate has been signed with the
|
|
||||||
/// issuer's private key, using the public key from the issuer
|
|
||||||
/// certificate.
|
|
||||||
///
|
|
||||||
/// Returns true if verification against the issuer certificate
|
|
||||||
/// was successful, false otherwise.
|
|
||||||
|
|
||||||
bool equals(const X509Certificate& otherCertificate) const;
|
|
||||||
/// Checks whether the certificate is equal to
|
|
||||||
/// the other certificate, by comparing the hashes
|
|
||||||
/// of both certificates.
|
|
||||||
///
|
|
||||||
/// Returns true if both certificates are identical,
|
|
||||||
/// otherwise false.
|
|
||||||
|
|
||||||
const X509* certificate() const;
|
|
||||||
/// Returns the underlying OpenSSL certificate.
|
|
||||||
|
|
||||||
X509* dup() const;
|
|
||||||
/// Duplicates and returns the underlying OpenSSL certificate. Note that
|
|
||||||
/// the caller assumes responsibility for the lifecycle of the created
|
|
||||||
/// certificate.
|
|
||||||
|
|
||||||
std::string signatureAlgorithm() const;
|
|
||||||
/// Returns the certificate signature algorithm long name.
|
|
||||||
|
|
||||||
void print(std::ostream& out) const;
|
|
||||||
/// Prints the certificate information to ostream.
|
|
||||||
|
|
||||||
static List readPEM(const std::string& pemFileName);
|
|
||||||
/// Reads and returns a list of certificates from
|
|
||||||
/// the specified PEM file.
|
|
||||||
|
|
||||||
static void writePEM(const std::string& pemFileName, const List& list);
|
|
||||||
/// Writes the list of certificates to the specified PEM file.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void load(std::istream& stream);
|
|
||||||
/// Loads the certificate from the given stream. The
|
|
||||||
/// certificate must be in PEM format.
|
|
||||||
|
|
||||||
void load(const std::string& path);
|
|
||||||
/// Loads the certificate from the given file. The
|
|
||||||
/// certificate must be in PEM format.
|
|
||||||
|
|
||||||
void init();
|
|
||||||
/// Extracts issuer and subject name from the certificate.
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
NAME_BUFFER_SIZE = 256
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string _issuerName;
|
|
||||||
std::string _subjectName;
|
|
||||||
std::string _serialNumber;
|
|
||||||
X509* _pCert;
|
|
||||||
OpenSSLInitializer _openSSLInitializer;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
inline long X509Certificate::version() const
|
|
||||||
{
|
{
|
||||||
// This is defined by standards (X.509 et al) to be
|
|
||||||
// one less than the certificate version.
|
|
||||||
// So, eg. a version 3 certificate will return 2.
|
class Crypto_API X509Certificate
|
||||||
return X509_get_version(_pCert) + 1;
|
/// This class represents a X509 Certificate.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::vector<X509Certificate> List;
|
||||||
|
|
||||||
|
enum NID
|
||||||
|
/// Name identifier for extracting information from
|
||||||
|
/// a certificate subject's or issuer's distinguished name.
|
||||||
|
{
|
||||||
|
NID_COMMON_NAME = 13,
|
||||||
|
NID_COUNTRY = 14,
|
||||||
|
NID_LOCALITY_NAME = 15,
|
||||||
|
NID_STATE_OR_PROVINCE = 16,
|
||||||
|
NID_ORGANIZATION_NAME = 17,
|
||||||
|
NID_ORGANIZATION_UNIT_NAME = 18,
|
||||||
|
NID_PKCS9_EMAIL_ADDRESS = 48,
|
||||||
|
NID_SERIAL_NUMBER = 105
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit X509Certificate(std::istream & istr);
|
||||||
|
/// Creates the X509Certificate object by reading
|
||||||
|
/// a certificate in PEM format from a stream.
|
||||||
|
|
||||||
|
explicit X509Certificate(const std::string & path);
|
||||||
|
/// Creates the X509Certificate object by reading
|
||||||
|
/// a certificate in PEM format from a file.
|
||||||
|
|
||||||
|
explicit X509Certificate(X509 * pCert);
|
||||||
|
/// Creates the X509Certificate from an existing
|
||||||
|
/// OpenSSL certificate. Ownership is taken of
|
||||||
|
/// the certificate.
|
||||||
|
|
||||||
|
X509Certificate(X509 * pCert, bool shared);
|
||||||
|
/// Creates the X509Certificate from an existing
|
||||||
|
/// OpenSSL certificate. Ownership is taken of
|
||||||
|
/// the certificate. If shared is true, the
|
||||||
|
/// certificate's reference count is incremented.
|
||||||
|
|
||||||
|
X509Certificate(const X509Certificate & cert);
|
||||||
|
/// Creates the certificate by copying another one.
|
||||||
|
|
||||||
|
X509Certificate & operator=(const X509Certificate & cert);
|
||||||
|
/// Assigns a certificate.
|
||||||
|
|
||||||
|
void swap(X509Certificate & cert);
|
||||||
|
/// Exchanges the certificate with another one.
|
||||||
|
|
||||||
|
~X509Certificate();
|
||||||
|
/// Destroys the X509Certificate.
|
||||||
|
|
||||||
|
long version() const;
|
||||||
|
/// Returns the version of the certificate.
|
||||||
|
|
||||||
|
const std::string & serialNumber() const;
|
||||||
|
/// Returns the certificate serial number as a
|
||||||
|
/// string in decimal encoding.
|
||||||
|
|
||||||
|
const std::string & issuerName() const;
|
||||||
|
/// Returns the certificate issuer's distinguished name.
|
||||||
|
|
||||||
|
std::string issuerName(NID nid) const;
|
||||||
|
/// Extracts the information specified by the given
|
||||||
|
/// NID (name identifier) from the certificate issuer's
|
||||||
|
/// distinguished name.
|
||||||
|
|
||||||
|
const std::string & subjectName() const;
|
||||||
|
/// Returns the certificate subject's distinguished name.
|
||||||
|
|
||||||
|
std::string subjectName(NID nid) const;
|
||||||
|
/// Extracts the information specified by the given
|
||||||
|
/// NID (name identifier) from the certificate subject's
|
||||||
|
/// distinguished name.
|
||||||
|
|
||||||
|
std::string commonName() const;
|
||||||
|
/// Returns the common name stored in the certificate
|
||||||
|
/// subject's distinguished name.
|
||||||
|
|
||||||
|
void extractNames(std::string & commonName, std::set<std::string> & domainNames) const;
|
||||||
|
/// Extracts the common name and the alias domain names from the
|
||||||
|
/// certificate.
|
||||||
|
|
||||||
|
Poco::DateTime validFrom() const;
|
||||||
|
/// Returns the date and time the certificate is valid from.
|
||||||
|
|
||||||
|
Poco::DateTime expiresOn() const;
|
||||||
|
/// Returns the date and time the certificate expires.
|
||||||
|
|
||||||
|
void save(std::ostream & stream) const;
|
||||||
|
/// Writes the certificate to the given stream.
|
||||||
|
/// The certificate is written in PEM format.
|
||||||
|
|
||||||
|
void save(const std::string & path) const;
|
||||||
|
/// Writes the certificate to the file given by path.
|
||||||
|
/// The certificate is written in PEM format.
|
||||||
|
|
||||||
|
bool issuedBy(const X509Certificate & issuerCertificate) const;
|
||||||
|
/// Checks whether the certificate has been issued by
|
||||||
|
/// the issuer given by issuerCertificate. This can be
|
||||||
|
/// used to validate a certificate chain.
|
||||||
|
///
|
||||||
|
/// Verifies if the certificate has been signed with the
|
||||||
|
/// issuer's private key, using the public key from the issuer
|
||||||
|
/// certificate.
|
||||||
|
///
|
||||||
|
/// Returns true if verification against the issuer certificate
|
||||||
|
/// was successful, false otherwise.
|
||||||
|
|
||||||
|
bool equals(const X509Certificate & otherCertificate) const;
|
||||||
|
/// Checks whether the certificate is equal to
|
||||||
|
/// the other certificate, by comparing the hashes
|
||||||
|
/// of both certificates.
|
||||||
|
///
|
||||||
|
/// Returns true if both certificates are identical,
|
||||||
|
/// otherwise false.
|
||||||
|
|
||||||
|
const X509 * certificate() const;
|
||||||
|
/// Returns the underlying OpenSSL certificate.
|
||||||
|
|
||||||
|
X509 * dup() const;
|
||||||
|
/// Duplicates and returns the underlying OpenSSL certificate. Note that
|
||||||
|
/// the caller assumes responsibility for the lifecycle of the created
|
||||||
|
/// certificate.
|
||||||
|
|
||||||
|
std::string signatureAlgorithm() const;
|
||||||
|
/// Returns the certificate signature algorithm long name.
|
||||||
|
|
||||||
|
void print(std::ostream & out) const;
|
||||||
|
/// Prints the certificate information to ostream.
|
||||||
|
|
||||||
|
static List readPEM(const std::string & pemFileName);
|
||||||
|
/// Reads and returns a list of certificates from
|
||||||
|
/// the specified PEM file.
|
||||||
|
|
||||||
|
static void writePEM(const std::string & pemFileName, const List & list);
|
||||||
|
/// Writes the list of certificates to the specified PEM file.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void load(std::istream & stream);
|
||||||
|
/// Loads the certificate from the given stream. The
|
||||||
|
/// certificate must be in PEM format.
|
||||||
|
|
||||||
|
void load(const std::string & path);
|
||||||
|
/// Loads the certificate from the given file. The
|
||||||
|
/// certificate must be in PEM format.
|
||||||
|
|
||||||
|
void init();
|
||||||
|
/// Extracts issuer and subject name from the certificate.
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NAME_BUFFER_SIZE = 256
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string _issuerName;
|
||||||
|
std::string _subjectName;
|
||||||
|
std::string _serialNumber;
|
||||||
|
X509 * _pCert;
|
||||||
|
OpenSSLInitializer _openSSLInitializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
inline long X509Certificate::version() const
|
||||||
|
{
|
||||||
|
// This is defined by standards (X.509 et al) to be
|
||||||
|
// one less than the certificate version.
|
||||||
|
// So, eg. a version 3 certificate will return 2.
|
||||||
|
return X509_get_version(_pCert) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string & X509Certificate::serialNumber() const
|
||||||
|
{
|
||||||
|
return _serialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string & X509Certificate::issuerName() const
|
||||||
|
{
|
||||||
|
return _issuerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const std::string & X509Certificate::subjectName() const
|
||||||
|
{
|
||||||
|
return _subjectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const X509 * X509Certificate::certificate() const
|
||||||
|
{
|
||||||
|
return _pCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline X509 * X509Certificate::dup() const
|
||||||
|
{
|
||||||
|
return X509_dup(_pCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Crypto
|
||||||
|
|
||||||
inline const std::string& X509Certificate::serialNumber() const
|
|
||||||
{
|
|
||||||
return _serialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& X509Certificate::issuerName() const
|
|
||||||
{
|
|
||||||
return _issuerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& X509Certificate::subjectName() const
|
|
||||||
{
|
|
||||||
return _subjectName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline const X509* X509Certificate::certificate() const
|
|
||||||
{
|
|
||||||
return _pCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline X509* X509Certificate::dup() const
|
|
||||||
{
|
|
||||||
return X509_dup(_pCert);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Crypto_X509Certificate_INCLUDED
|
#endif // Crypto_X509Certificate_INCLUDED
|
||||||
|
@ -22,36 +22,12 @@
|
|||||||
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
|
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
|
||||||
#include <openssl/conf.h>
|
#include <openssl/conf.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(POCO_OS_FAMILY_WINDOWS)
|
|
||||||
#define POCO_STR_HELPER(x) #x
|
|
||||||
#define POCO_STR(x) POCO_STR_HELPER(x)
|
|
||||||
#if defined POCO_INTERNAL_OPENSSL_MSVC_VER
|
|
||||||
#define POCO_INTERNAL_OPENSSL_BUILD \
|
|
||||||
" (POCO internal build, MSVC version " \
|
|
||||||
POCO_STR(POCO_INTERNAL_OPENSSL_MSVC_VER) ")"
|
|
||||||
#else
|
|
||||||
#define POCO_INTERNAL_OPENSSL_BUILD ""
|
|
||||||
#endif
|
|
||||||
#pragma message (OPENSSL_VERSION_TEXT POCO_INTERNAL_OPENSSL_BUILD)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
using Poco::RandomInputStream;
|
using Poco::RandomInputStream;
|
||||||
using Poco::Thread;
|
using Poco::Thread;
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(_DLL) && defined(POCO_INTERNAL_OPENSSL_MSVC_VER)
|
|
||||||
|
|
||||||
#if (POCO_MSVS_VERSION >= 2015)
|
|
||||||
FILE _iob[] = { *stdin, *stdout, *stderr };
|
|
||||||
extern "C" FILE * __cdecl __iob_func(void) { return _iob; }
|
|
||||||
#endif // (POCO_MSVS_VERSION >= 2015)
|
|
||||||
|
|
||||||
#if (POCO_MSVS_VERSION < 2012)
|
|
||||||
extern "C" __declspec(noreturn) void __cdecl __report_rangecheckfailure(void) { ::ExitProcess(1); }
|
|
||||||
#endif // (POCO_MSVS_VERSION < 2012)
|
|
||||||
|
|
||||||
#endif // _MSC_VER && _MT && !POCO_EXTERNAL_OPENSSL && (POCO_MSVS_VERSION < 2013)
|
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco {
|
||||||
@ -100,7 +76,6 @@ void OpenSSLInitializer::initialize()
|
|||||||
int nMutexes = CRYPTO_num_locks();
|
int nMutexes = CRYPTO_num_locks();
|
||||||
_mutexes = new Poco::FastMutex[nMutexes];
|
_mutexes = new Poco::FastMutex[nMutexes];
|
||||||
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
|
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
|
||||||
#ifndef POCO_OS_FAMILY_WINDOWS
|
|
||||||
// Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl).
|
// Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl).
|
||||||
// https://sourceforge.net/p/poco/bugs/110/
|
// https://sourceforge.net/p/poco/bugs/110/
|
||||||
//
|
//
|
||||||
@ -109,7 +84,6 @@ void OpenSSLInitializer::initialize()
|
|||||||
// then a default implementation is used - on Windows and BeOS this uses the system's
|
// then a default implementation is used - on Windows and BeOS this uses the system's
|
||||||
// default thread identifying APIs"
|
// default thread identifying APIs"
|
||||||
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
|
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
|
||||||
#endif
|
|
||||||
CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate);
|
CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate);
|
||||||
CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock);
|
CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock);
|
||||||
CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy);
|
CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy);
|
||||||
@ -124,9 +98,7 @@ void OpenSSLInitializer::uninitialize()
|
|||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
ERR_free_strings();
|
ERR_free_strings();
|
||||||
CRYPTO_set_locking_callback(0);
|
CRYPTO_set_locking_callback(0);
|
||||||
#ifndef POCO_OS_FAMILY_WINDOWS
|
|
||||||
CRYPTO_set_id_callback(0);
|
CRYPTO_set_id_callback(0);
|
||||||
#endif
|
|
||||||
delete [] _mutexes;
|
delete [] _mutexes;
|
||||||
|
|
||||||
CONF_modules_free();
|
CONF_modules_free();
|
||||||
|
@ -102,7 +102,7 @@ RSAKeyImpl::RSAKeyImpl(const std::string& publicKeyFile,
|
|||||||
{
|
{
|
||||||
BIO* bio = BIO_new(BIO_s_file());
|
BIO* bio = BIO_new(BIO_s_file());
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key", publicKeyFile);
|
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key", publicKeyFile);
|
||||||
int rc = BIO_read_filename(bio, publicKeyFile.c_str());
|
int rc = BIO_read_filename(bio, const_cast<char *>(publicKeyFile.c_str()));
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
RSA* pubKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
|
RSA* pubKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
|
||||||
@ -132,7 +132,7 @@ RSAKeyImpl::RSAKeyImpl(const std::string& publicKeyFile,
|
|||||||
{
|
{
|
||||||
BIO* bio = BIO_new(BIO_s_file());
|
BIO* bio = BIO_new(BIO_s_file());
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key", privateKeyFile);
|
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key", privateKeyFile);
|
||||||
int rc = BIO_read_filename(bio, privateKeyFile.c_str());
|
int rc = BIO_read_filename(bio, const_cast<char *>(privateKeyFile.c_str()));
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
RSA* privKey = 0;
|
RSA* privKey = 0;
|
||||||
@ -269,103 +269,6 @@ RSAKeyImpl::ByteVec RSAKeyImpl::decryptionExponent() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RSAKeyImpl::save(const std::string& publicKeyFile,
|
|
||||||
const std::string& privateKeyFile,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
if (!publicKeyFile.empty())
|
|
||||||
{
|
|
||||||
BIO* bio = BIO_new(BIO_s_file());
|
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key file", publicKeyFile);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (BIO_write_filename(bio, const_cast<char*>(publicKeyFile.c_str())))
|
|
||||||
{
|
|
||||||
if (!PEM_write_bio_RSAPublicKey(bio, _pRSA))
|
|
||||||
throw Poco::WriteFileException("Failed to write public key to file", publicKeyFile);
|
|
||||||
}
|
|
||||||
else throw Poco::CreateFileException("Cannot create public key file");
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
BIO_free(bio);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
BIO_free(bio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!privateKeyFile.empty())
|
|
||||||
{
|
|
||||||
BIO* bio = BIO_new(BIO_s_file());
|
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing private key file", privateKeyFile);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (BIO_write_filename(bio, const_cast<char*>(privateKeyFile.c_str())))
|
|
||||||
{
|
|
||||||
int rc = 0;
|
|
||||||
if (privateKeyPassphrase.empty())
|
|
||||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, 0, 0, 0, 0, 0);
|
|
||||||
else
|
|
||||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, EVP_des_ede3_cbc(),
|
|
||||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
|
||||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
|
||||||
if (!rc) throw Poco::FileException("Failed to write private key to file", privateKeyFile);
|
|
||||||
}
|
|
||||||
else throw Poco::CreateFileException("Cannot create private key file", privateKeyFile);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
BIO_free(bio);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
BIO_free(bio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RSAKeyImpl::save(std::ostream* pPublicKeyStream,
|
|
||||||
std::ostream* pPrivateKeyStream,
|
|
||||||
const std::string& privateKeyPassphrase) const
|
|
||||||
{
|
|
||||||
if (pPublicKeyStream)
|
|
||||||
{
|
|
||||||
BIO* bio = BIO_new(BIO_s_mem());
|
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
|
||||||
if (!PEM_write_bio_RSAPublicKey(bio, _pRSA))
|
|
||||||
{
|
|
||||||
BIO_free(bio);
|
|
||||||
throw Poco::WriteFileException("Failed to write public key to stream");
|
|
||||||
}
|
|
||||||
char* pData;
|
|
||||||
long size = BIO_get_mem_data(bio, &pData);
|
|
||||||
pPublicKeyStream->write(pData, static_cast<std::streamsize>(size));
|
|
||||||
BIO_free(bio);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pPrivateKeyStream)
|
|
||||||
{
|
|
||||||
BIO* bio = BIO_new(BIO_s_mem());
|
|
||||||
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
|
|
||||||
int rc = 0;
|
|
||||||
if (privateKeyPassphrase.empty())
|
|
||||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, 0, 0, 0, 0, 0);
|
|
||||||
else
|
|
||||||
rc = PEM_write_bio_RSAPrivateKey(bio, _pRSA, EVP_des_ede3_cbc(),
|
|
||||||
reinterpret_cast<unsigned char*>(const_cast<char*>(privateKeyPassphrase.c_str())),
|
|
||||||
static_cast<int>(privateKeyPassphrase.length()), 0, 0);
|
|
||||||
if (!rc)
|
|
||||||
{
|
|
||||||
BIO_free(bio);
|
|
||||||
throw Poco::FileException("Failed to write private key to stream");
|
|
||||||
}
|
|
||||||
char* pData;
|
|
||||||
long size = BIO_get_mem_data(bio, &pData);
|
|
||||||
pPrivateKeyStream->write(pData, static_cast<std::streamsize>(size));
|
|
||||||
BIO_free(bio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RSAKeyImpl::ByteVec RSAKeyImpl::convertToByteVec(const BIGNUM* bn)
|
RSAKeyImpl::ByteVec RSAKeyImpl::convertToByteVec(const BIGNUM* bn)
|
||||||
{
|
{
|
||||||
int numBytes = BN_num_bytes(bn);
|
int numBytes = BN_num_bytes(bn);
|
||||||
@ -383,4 +286,4 @@ RSAKeyImpl::ByteVec RSAKeyImpl::convertToByteVec(const BIGNUM* bn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace Poco::Crypto
|
} } // namespace Poco::Crypto
|
||||||
|
@ -20,10 +20,6 @@
|
|||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#ifdef _WIN32
|
|
||||||
// fix for WIN32 header conflict
|
|
||||||
#undef X509_NAME
|
|
||||||
#endif
|
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
@ -133,7 +129,7 @@ void X509Certificate::load(const std::string& path)
|
|||||||
|
|
||||||
BIO *pBIO = BIO_new(BIO_s_file());
|
BIO *pBIO = BIO_new(BIO_s_file());
|
||||||
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
|
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
|
||||||
if (!BIO_read_filename(pBIO, path.c_str()))
|
if (!BIO_read_filename(pBIO, const_cast<char *>(path.c_str())))
|
||||||
{
|
{
|
||||||
BIO_free(pBIO);
|
BIO_free(pBIO);
|
||||||
throw Poco::OpenFileException("Cannot open certificate file for reading", path);
|
throw Poco::OpenFileException("Cannot open certificate file for reading", path);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,79 +18,81 @@
|
|||||||
#define Data_ODBC_ConnectionHandle_INCLUDED
|
#define Data_ODBC_ConnectionHandle_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
|
||||||
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqltypes.h>
|
#include <sqltypes.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API ConnectionHandle
|
|
||||||
/// ODBC connection handle class
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
ConnectionHandle(EnvironmentHandle* pEnvironment = 0);
|
|
||||||
/// Creates the ConnectionHandle.
|
|
||||||
|
|
||||||
~ConnectionHandle();
|
|
||||||
/// Creates the ConnectionHandle.
|
|
||||||
|
|
||||||
operator const SQLHDBC& () const;
|
|
||||||
/// Const conversion operator into reference to native type.
|
|
||||||
|
|
||||||
const SQLHDBC& handle() const;
|
|
||||||
/// Returns const reference to handle;
|
|
||||||
|
|
||||||
private:
|
|
||||||
operator SQLHDBC& ();
|
|
||||||
/// Conversion operator into reference to native type.
|
|
||||||
|
|
||||||
SQLHDBC& handle();
|
|
||||||
/// Returns reference to handle;
|
|
||||||
|
|
||||||
ConnectionHandle(const ConnectionHandle&);
|
|
||||||
const ConnectionHandle& operator=(const ConnectionHandle&);
|
|
||||||
|
|
||||||
const EnvironmentHandle* _pEnvironment;
|
|
||||||
SQLHDBC _hdbc;
|
|
||||||
bool _ownsEnvironment;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline ConnectionHandle::operator const SQLHDBC& () const
|
|
||||||
{
|
{
|
||||||
return handle();
|
namespace ODBC
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class ODBC_API ConnectionHandle
|
||||||
|
/// ODBC connection handle class
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectionHandle(EnvironmentHandle * pEnvironment = 0);
|
||||||
|
/// Creates the ConnectionHandle.
|
||||||
|
|
||||||
|
~ConnectionHandle();
|
||||||
|
/// Creates the ConnectionHandle.
|
||||||
|
|
||||||
|
operator const SQLHDBC &() const;
|
||||||
|
/// Const conversion operator into reference to native type.
|
||||||
|
|
||||||
|
const SQLHDBC & handle() const;
|
||||||
|
/// Returns const reference to handle;
|
||||||
|
|
||||||
|
private:
|
||||||
|
operator SQLHDBC &();
|
||||||
|
/// Conversion operator into reference to native type.
|
||||||
|
|
||||||
|
SQLHDBC & handle();
|
||||||
|
/// Returns reference to handle;
|
||||||
|
|
||||||
|
ConnectionHandle(const ConnectionHandle &);
|
||||||
|
const ConnectionHandle & operator=(const ConnectionHandle &);
|
||||||
|
|
||||||
|
const EnvironmentHandle * _pEnvironment;
|
||||||
|
SQLHDBC _hdbc;
|
||||||
|
bool _ownsEnvironment;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline ConnectionHandle::operator const SQLHDBC &() const
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const SQLHDBC & ConnectionHandle::handle() const
|
||||||
|
{
|
||||||
|
return _hdbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline ConnectionHandle::operator SQLHDBC &()
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline SQLHDBC & ConnectionHandle::handle()
|
||||||
|
{
|
||||||
|
return _hdbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
inline const SQLHDBC& ConnectionHandle::handle() const
|
|
||||||
{
|
|
||||||
return _hdbc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline ConnectionHandle::operator SQLHDBC& ()
|
|
||||||
{
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline SQLHDBC& ConnectionHandle::handle()
|
|
||||||
{
|
|
||||||
return _hdbc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,79 +18,84 @@
|
|||||||
#define Data_ODBC_Connector_INCLUDED
|
#define Data_ODBC_Connector_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
|
||||||
#include "Poco/Data/Connector.h"
|
#include "Poco/Data/Connector.h"
|
||||||
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API Connector: public Poco::Data::Connector
|
|
||||||
/// Connector instantiates SqLite SessionImpl objects.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
static const std::string KEY;
|
|
||||||
/// Keyword for creating ODBC sessions.
|
|
||||||
|
|
||||||
Connector();
|
|
||||||
/// Creates the Connector.
|
|
||||||
|
|
||||||
~Connector();
|
|
||||||
/// Destroys the Connector.
|
|
||||||
|
|
||||||
const std::string& name() const;
|
|
||||||
/// Returns the name associated with this connector.
|
|
||||||
|
|
||||||
Poco::AutoPtr<Poco::Data::SessionImpl> createSession(const std::string& connectionString,
|
|
||||||
std::size_t timeout = Poco::Data::SessionImpl::LOGIN_TIMEOUT_DEFAULT);
|
|
||||||
/// Creates a ODBC SessionImpl object and initializes it with the given connectionString.
|
|
||||||
|
|
||||||
static void registerConnector();
|
|
||||||
/// Registers the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory
|
|
||||||
|
|
||||||
static void unregisterConnector();
|
|
||||||
/// Unregisters the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory
|
|
||||||
|
|
||||||
static void bindStringToLongVarChar(bool flag = true);
|
|
||||||
/// If set to true (default), std::string is bound to SQL_LONGVARCHAR.
|
|
||||||
///
|
|
||||||
/// This can cause issues with SQL Server, resulting in an error
|
|
||||||
/// ("The data types varchar and text are incompatible in the equal to operator")
|
|
||||||
/// when comparing against a VARCHAR.
|
|
||||||
///
|
|
||||||
/// Set this to false to bind std::string to SQL_VARCHAR.
|
|
||||||
///
|
|
||||||
/// NOTE: This is a global setting, affecting all sessions.
|
|
||||||
/// This setting should not be changed after the first Session has
|
|
||||||
/// been created.
|
|
||||||
|
|
||||||
static bool stringBoundToLongVarChar();
|
|
||||||
/// Returns true if std::string is bound to SQL_LONGVARCHAR,
|
|
||||||
/// otherwise false (bound to SQL_VARCHAR).
|
|
||||||
|
|
||||||
private:
|
|
||||||
static bool _bindStringToLongVarChar;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// inlines
|
|
||||||
///
|
|
||||||
inline const std::string& Connector::name() const
|
|
||||||
{
|
{
|
||||||
return KEY;
|
namespace ODBC
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class ODBC_API Connector : public Poco::Data::Connector
|
||||||
|
/// Connector instantiates SqLite SessionImpl objects.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const std::string KEY;
|
||||||
|
/// Keyword for creating ODBC sessions.
|
||||||
|
|
||||||
|
Connector();
|
||||||
|
/// Creates the Connector.
|
||||||
|
|
||||||
|
~Connector();
|
||||||
|
/// Destroys the Connector.
|
||||||
|
|
||||||
|
const std::string & name() const;
|
||||||
|
/// Returns the name associated with this connector.
|
||||||
|
|
||||||
|
Poco::AutoPtr<Poco::Data::SessionImpl>
|
||||||
|
createSession(const std::string & connectionString, std::size_t timeout = Poco::Data::SessionImpl::LOGIN_TIMEOUT_DEFAULT);
|
||||||
|
/// Creates a ODBC SessionImpl object and initializes it with the given connectionString.
|
||||||
|
|
||||||
|
static void registerConnector();
|
||||||
|
/// Registers the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory
|
||||||
|
|
||||||
|
static void unregisterConnector();
|
||||||
|
/// Unregisters the Connector under the Keyword Connector::KEY at the Poco::Data::SessionFactory
|
||||||
|
|
||||||
|
static void bindStringToLongVarChar(bool flag = true);
|
||||||
|
/// If set to true (default), std::string is bound to SQL_LONGVARCHAR.
|
||||||
|
///
|
||||||
|
/// This can cause issues with SQL Server, resulting in an error
|
||||||
|
/// ("The data types varchar and text are incompatible in the equal to operator")
|
||||||
|
/// when comparing against a VARCHAR.
|
||||||
|
///
|
||||||
|
/// Set this to false to bind std::string to SQL_VARCHAR.
|
||||||
|
///
|
||||||
|
/// NOTE: This is a global setting, affecting all sessions.
|
||||||
|
/// This setting should not be changed after the first Session has
|
||||||
|
/// been created.
|
||||||
|
|
||||||
|
static bool stringBoundToLongVarChar();
|
||||||
|
/// Returns true if std::string is bound to SQL_LONGVARCHAR,
|
||||||
|
/// otherwise false (bound to SQL_VARCHAR).
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _bindStringToLongVarChar;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// inlines
|
||||||
|
///
|
||||||
|
inline const std::string & Connector::name() const
|
||||||
|
{
|
||||||
|
return KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Connector::stringBoundToLongVarChar()
|
||||||
|
{
|
||||||
|
return _bindStringToLongVarChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
inline bool Connector::stringBoundToLongVarChar()
|
|
||||||
{
|
|
||||||
return _bindStringToLongVarChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Data_ODBC_Connector_INCLUDED
|
#endif // Data_ODBC_Connector_INCLUDED
|
||||||
|
@ -18,222 +18,200 @@
|
|||||||
#define Data_ODBC_Diagnostics_INCLUDED
|
#define Data_ODBC_Diagnostics_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#include <vector>
|
||||||
#include <windows.h>
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#endif
|
#include "Poco/Data/ODBC/Utility.h"
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
template <typename H, SQLSMALLINT handleType>
|
|
||||||
class Diagnostics
|
|
||||||
/// Utility class providing functionality for retrieving ODBC diagnostic
|
|
||||||
/// records. Diagnostics object must be created with corresponding handle
|
|
||||||
/// as constructor argument. During construction, diagnostic records fields
|
|
||||||
/// are populated and the object is ready for querying.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
|
{
|
||||||
static const unsigned int SQL_STATE_SIZE = SQL_SQLSTATE_SIZE + 1;
|
namespace ODBC
|
||||||
static const unsigned int SQL_MESSAGE_LENGTH = SQL_MAX_MESSAGE_LENGTH + 1;
|
{
|
||||||
static const unsigned int SQL_NAME_LENGTH = 128;
|
|
||||||
static const std::string DATA_TRUNCATED;
|
|
||||||
|
|
||||||
struct DiagnosticFields
|
|
||||||
{
|
|
||||||
/// SQLGetDiagRec fields
|
|
||||||
SQLCHAR _sqlState[SQL_STATE_SIZE];
|
|
||||||
SQLCHAR _message[SQL_MESSAGE_LENGTH];
|
|
||||||
SQLINTEGER _nativeError;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector<DiagnosticFields> FieldVec;
|
|
||||||
typedef typename FieldVec::const_iterator Iterator;
|
|
||||||
|
|
||||||
explicit Diagnostics(const H& handle): _handle(handle)
|
|
||||||
/// Creates and initializes the Diagnostics.
|
|
||||||
{
|
|
||||||
std::memset(_connectionName, 0, sizeof(_connectionName));
|
|
||||||
std::memset(_serverName, 0, sizeof(_serverName));
|
|
||||||
diagnostics();
|
|
||||||
}
|
|
||||||
|
|
||||||
~Diagnostics()
|
|
||||||
/// Destroys the Diagnostics.
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string sqlState(int index) const
|
|
||||||
/// Returns SQL state.
|
|
||||||
{
|
|
||||||
poco_assert (index < count());
|
|
||||||
return std::string((char*) _fields[index]._sqlState);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string message(int index) const
|
|
||||||
/// Returns error message.
|
|
||||||
{
|
|
||||||
poco_assert (index < count());
|
|
||||||
return std::string((char*) _fields[index]._message);
|
|
||||||
}
|
|
||||||
|
|
||||||
long nativeError(int index) const
|
|
||||||
/// Returns native error code.
|
|
||||||
{
|
|
||||||
poco_assert (index < count());
|
|
||||||
return _fields[index]._nativeError;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string connectionName() const
|
|
||||||
/// Returns the connection name.
|
|
||||||
/// If there is no active connection, connection name defaults to NONE.
|
|
||||||
/// If connection name is not applicable for query context (such as when querying environment handle),
|
|
||||||
/// connection name defaults to NOT_APPLICABLE.
|
|
||||||
{
|
|
||||||
return std::string((char*) _connectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string serverName() const
|
|
||||||
/// Returns the server name.
|
|
||||||
/// If the connection has not been established, server name defaults to NONE.
|
|
||||||
/// If server name is not applicable for query context (such as when querying environment handle),
|
|
||||||
/// connection name defaults to NOT_APPLICABLE.
|
|
||||||
{
|
|
||||||
return std::string((char*) _serverName);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count() const
|
|
||||||
/// Returns the number of contained diagnostic records.
|
|
||||||
{
|
|
||||||
return (int) _fields.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
/// Resets the diagnostic fields container.
|
|
||||||
{
|
|
||||||
_fields.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const FieldVec& fields() const
|
|
||||||
{
|
|
||||||
return _fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator begin() const
|
|
||||||
{
|
|
||||||
return _fields.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator end() const
|
|
||||||
{
|
|
||||||
return _fields.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Diagnostics& diagnostics()
|
|
||||||
{
|
|
||||||
DiagnosticFields df;
|
|
||||||
SQLSMALLINT count = 1;
|
|
||||||
SQLSMALLINT messageLength = 0;
|
|
||||||
static const std::string none = "None";
|
|
||||||
static const std::string na = "Not applicable";
|
|
||||||
|
|
||||||
reset();
|
|
||||||
|
|
||||||
while (!Utility::isError(SQLGetDiagRec(handleType,
|
|
||||||
_handle,
|
|
||||||
count,
|
|
||||||
df._sqlState,
|
|
||||||
&df._nativeError,
|
|
||||||
df._message,
|
|
||||||
SQL_MESSAGE_LENGTH,
|
|
||||||
&messageLength)))
|
|
||||||
{
|
|
||||||
if (1 == count)
|
|
||||||
{
|
|
||||||
// success of the following two calls is optional
|
|
||||||
// (they fail if connection has not been established yet
|
|
||||||
// or return empty string if not applicable for the context)
|
|
||||||
if (Utility::isError(SQLGetDiagField(handleType,
|
|
||||||
_handle,
|
|
||||||
count,
|
|
||||||
SQL_DIAG_CONNECTION_NAME,
|
|
||||||
_connectionName,
|
|
||||||
sizeof(_connectionName),
|
|
||||||
&messageLength)))
|
|
||||||
{
|
|
||||||
std::size_t len = sizeof(_connectionName) > none.length() ?
|
|
||||||
none.length() : sizeof(_connectionName) - 1;
|
|
||||||
std::memcpy(_connectionName, none.c_str(), len);
|
|
||||||
}
|
|
||||||
else if (0 == _connectionName[0])
|
|
||||||
{
|
|
||||||
std::size_t len = sizeof(_connectionName) > na.length() ?
|
|
||||||
na.length() : sizeof(_connectionName) - 1;
|
|
||||||
std::memcpy(_connectionName, na.c_str(), len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utility::isError(SQLGetDiagField(handleType,
|
|
||||||
_handle,
|
|
||||||
count,
|
|
||||||
SQL_DIAG_SERVER_NAME,
|
|
||||||
_serverName,
|
|
||||||
sizeof(_serverName),
|
|
||||||
&messageLength)))
|
|
||||||
{
|
|
||||||
std::size_t len = sizeof(_serverName) > none.length() ?
|
|
||||||
none.length() : sizeof(_serverName) - 1;
|
|
||||||
std::memcpy(_serverName, none.c_str(), len);
|
|
||||||
}
|
|
||||||
else if (0 == _serverName[0])
|
|
||||||
{
|
|
||||||
std::size_t len = sizeof(_serverName) > na.length() ?
|
|
||||||
na.length() : sizeof(_serverName) - 1;
|
|
||||||
std::memcpy(_serverName, na.c_str(), len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_fields.push_back(df);
|
|
||||||
|
|
||||||
std::memset(df._sqlState, 0, SQL_STATE_SIZE);
|
|
||||||
std::memset(df._message, 0, SQL_MESSAGE_LENGTH);
|
|
||||||
df._nativeError = 0;
|
|
||||||
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
Diagnostics();
|
|
||||||
|
|
||||||
/// SQLGetDiagField fields
|
|
||||||
SQLCHAR _connectionName[SQL_NAME_LENGTH];
|
|
||||||
SQLCHAR _serverName[SQL_NAME_LENGTH];
|
|
||||||
|
|
||||||
/// Diagnostics container
|
|
||||||
FieldVec _fields;
|
|
||||||
|
|
||||||
/// Context handle
|
|
||||||
const H& _handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef Diagnostics<SQLHENV, SQL_HANDLE_ENV> EnvironmentDiagnostics;
|
template <typename H, SQLSMALLINT handleType>
|
||||||
typedef Diagnostics<SQLHDBC, SQL_HANDLE_DBC> ConnectionDiagnostics;
|
class Diagnostics
|
||||||
typedef Diagnostics<SQLHSTMT, SQL_HANDLE_STMT> StatementDiagnostics;
|
/// Utility class providing functionality for retrieving ODBC diagnostic
|
||||||
typedef Diagnostics<SQLHDESC, SQL_HANDLE_DESC> DescriptorDiagnostics;
|
/// records. Diagnostics object must be created with corresponding handle
|
||||||
|
/// as constructor argument. During construction, diagnostic records fields
|
||||||
|
/// are populated and the object is ready for querying.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const unsigned int SQL_STATE_SIZE = SQL_SQLSTATE_SIZE + 1;
|
||||||
|
static const unsigned int SQL_MESSAGE_LENGTH = SQL_MAX_MESSAGE_LENGTH + 1;
|
||||||
|
static const unsigned int SQL_NAME_LENGTH = 128;
|
||||||
|
static const std::string DATA_TRUNCATED;
|
||||||
|
|
||||||
|
struct DiagnosticFields
|
||||||
|
{
|
||||||
|
/// SQLGetDiagRec fields
|
||||||
|
SQLCHAR _sqlState[SQL_STATE_SIZE];
|
||||||
|
SQLCHAR _message[SQL_MESSAGE_LENGTH];
|
||||||
|
SQLINTEGER _nativeError;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<DiagnosticFields> FieldVec;
|
||||||
|
typedef typename FieldVec::const_iterator Iterator;
|
||||||
|
|
||||||
|
explicit Diagnostics(const H & handle) : _handle(handle)
|
||||||
|
/// Creates and initializes the Diagnostics.
|
||||||
|
{
|
||||||
|
std::memset(_connectionName, 0, sizeof(_connectionName));
|
||||||
|
std::memset(_serverName, 0, sizeof(_serverName));
|
||||||
|
diagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Diagnostics()
|
||||||
|
/// Destroys the Diagnostics.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sqlState(int index) const
|
||||||
|
/// Returns SQL state.
|
||||||
|
{
|
||||||
|
poco_assert(index < count());
|
||||||
|
return std::string((char *)_fields[index]._sqlState);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message(int index) const
|
||||||
|
/// Returns error message.
|
||||||
|
{
|
||||||
|
poco_assert(index < count());
|
||||||
|
return std::string((char *)_fields[index]._message);
|
||||||
|
}
|
||||||
|
|
||||||
|
long nativeError(int index) const
|
||||||
|
/// Returns native error code.
|
||||||
|
{
|
||||||
|
poco_assert(index < count());
|
||||||
|
return _fields[index]._nativeError;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string connectionName() const
|
||||||
|
/// Returns the connection name.
|
||||||
|
/// If there is no active connection, connection name defaults to NONE.
|
||||||
|
/// If connection name is not applicable for query context (such as when querying environment handle),
|
||||||
|
/// connection name defaults to NOT_APPLICABLE.
|
||||||
|
{
|
||||||
|
return std::string((char *)_connectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string serverName() const
|
||||||
|
/// Returns the server name.
|
||||||
|
/// If the connection has not been established, server name defaults to NONE.
|
||||||
|
/// If server name is not applicable for query context (such as when querying environment handle),
|
||||||
|
/// connection name defaults to NOT_APPLICABLE.
|
||||||
|
{
|
||||||
|
return std::string((char *)_serverName);
|
||||||
|
}
|
||||||
|
|
||||||
|
int count() const
|
||||||
|
/// Returns the number of contained diagnostic records.
|
||||||
|
{
|
||||||
|
return (int)_fields.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
/// Resets the diagnostic fields container.
|
||||||
|
{
|
||||||
|
_fields.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FieldVec & fields() const { return _fields; }
|
||||||
|
|
||||||
|
Iterator begin() const { return _fields.begin(); }
|
||||||
|
|
||||||
|
Iterator end() const { return _fields.end(); }
|
||||||
|
|
||||||
|
const Diagnostics & diagnostics()
|
||||||
|
{
|
||||||
|
DiagnosticFields df;
|
||||||
|
SQLSMALLINT count = 1;
|
||||||
|
SQLSMALLINT messageLength = 0;
|
||||||
|
static const std::string none = "None";
|
||||||
|
static const std::string na = "Not applicable";
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
while (!Utility::isError(SQLGetDiagRec(
|
||||||
|
handleType, _handle, count, df._sqlState, &df._nativeError, df._message, SQL_MESSAGE_LENGTH, &messageLength)))
|
||||||
|
{
|
||||||
|
if (1 == count)
|
||||||
|
{
|
||||||
|
// success of the following two calls is optional
|
||||||
|
// (they fail if connection has not been established yet
|
||||||
|
// or return empty string if not applicable for the context)
|
||||||
|
if (Utility::isError(SQLGetDiagField(
|
||||||
|
handleType,
|
||||||
|
_handle,
|
||||||
|
count,
|
||||||
|
SQL_DIAG_CONNECTION_NAME,
|
||||||
|
_connectionName,
|
||||||
|
sizeof(_connectionName),
|
||||||
|
&messageLength)))
|
||||||
|
{
|
||||||
|
std::size_t len = sizeof(_connectionName) > none.length() ? none.length() : sizeof(_connectionName) - 1;
|
||||||
|
std::memcpy(_connectionName, none.c_str(), len);
|
||||||
|
}
|
||||||
|
else if (0 == _connectionName[0])
|
||||||
|
{
|
||||||
|
std::size_t len = sizeof(_connectionName) > na.length() ? na.length() : sizeof(_connectionName) - 1;
|
||||||
|
std::memcpy(_connectionName, na.c_str(), len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utility::isError(SQLGetDiagField(
|
||||||
|
handleType, _handle, count, SQL_DIAG_SERVER_NAME, _serverName, sizeof(_serverName), &messageLength)))
|
||||||
|
{
|
||||||
|
std::size_t len = sizeof(_serverName) > none.length() ? none.length() : sizeof(_serverName) - 1;
|
||||||
|
std::memcpy(_serverName, none.c_str(), len);
|
||||||
|
}
|
||||||
|
else if (0 == _serverName[0])
|
||||||
|
{
|
||||||
|
std::size_t len = sizeof(_serverName) > na.length() ? na.length() : sizeof(_serverName) - 1;
|
||||||
|
std::memcpy(_serverName, na.c_str(), len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_fields.push_back(df);
|
||||||
|
|
||||||
|
std::memset(df._sqlState, 0, SQL_STATE_SIZE);
|
||||||
|
std::memset(df._message, 0, SQL_MESSAGE_LENGTH);
|
||||||
|
df._nativeError = 0;
|
||||||
|
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Diagnostics();
|
||||||
|
|
||||||
|
/// SQLGetDiagField fields
|
||||||
|
SQLCHAR _connectionName[SQL_NAME_LENGTH];
|
||||||
|
SQLCHAR _serverName[SQL_NAME_LENGTH];
|
||||||
|
|
||||||
|
/// Diagnostics container
|
||||||
|
FieldVec _fields;
|
||||||
|
|
||||||
|
/// Context handle
|
||||||
|
const H & _handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
typedef Diagnostics<SQLHENV, SQL_HANDLE_ENV> EnvironmentDiagnostics;
|
||||||
|
typedef Diagnostics<SQLHDBC, SQL_HANDLE_DBC> ConnectionDiagnostics;
|
||||||
|
typedef Diagnostics<SQLHSTMT, SQL_HANDLE_STMT> StatementDiagnostics;
|
||||||
|
typedef Diagnostics<SQLHDESC, SQL_HANDLE_DESC> DescriptorDiagnostics;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,76 +19,78 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqltypes.h>
|
#include <sqltypes.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API EnvironmentHandle
|
|
||||||
/// ODBC environment handle class
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
EnvironmentHandle();
|
|
||||||
/// Creates the EnvironmentHandle.
|
|
||||||
|
|
||||||
~EnvironmentHandle();
|
|
||||||
/// Destroys the EnvironmentHandle.
|
|
||||||
|
|
||||||
operator const SQLHENV& () const;
|
|
||||||
/// Const conversion operator into reference to native type.
|
|
||||||
|
|
||||||
const SQLHENV& handle() const;
|
|
||||||
/// Returns const reference to handle.
|
|
||||||
|
|
||||||
private:
|
|
||||||
operator SQLHENV& ();
|
|
||||||
/// Conversion operator into reference to native type.
|
|
||||||
|
|
||||||
SQLHENV& handle();
|
|
||||||
/// Returns reference to handle.
|
|
||||||
|
|
||||||
EnvironmentHandle(const EnvironmentHandle&);
|
|
||||||
const EnvironmentHandle& operator=(const EnvironmentHandle&);
|
|
||||||
|
|
||||||
SQLHENV _henv;
|
|
||||||
bool _isOwner;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// inlines
|
|
||||||
///
|
|
||||||
inline EnvironmentHandle::operator const SQLHENV& () const
|
|
||||||
{
|
{
|
||||||
return handle();
|
namespace ODBC
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class ODBC_API EnvironmentHandle
|
||||||
|
/// ODBC environment handle class
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EnvironmentHandle();
|
||||||
|
/// Creates the EnvironmentHandle.
|
||||||
|
|
||||||
|
~EnvironmentHandle();
|
||||||
|
/// Destroys the EnvironmentHandle.
|
||||||
|
|
||||||
|
operator const SQLHENV &() const;
|
||||||
|
/// Const conversion operator into reference to native type.
|
||||||
|
|
||||||
|
const SQLHENV & handle() const;
|
||||||
|
/// Returns const reference to handle.
|
||||||
|
|
||||||
|
private:
|
||||||
|
operator SQLHENV &();
|
||||||
|
/// Conversion operator into reference to native type.
|
||||||
|
|
||||||
|
SQLHENV & handle();
|
||||||
|
/// Returns reference to handle.
|
||||||
|
|
||||||
|
EnvironmentHandle(const EnvironmentHandle &);
|
||||||
|
const EnvironmentHandle & operator=(const EnvironmentHandle &);
|
||||||
|
|
||||||
|
SQLHENV _henv;
|
||||||
|
bool _isOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// inlines
|
||||||
|
///
|
||||||
|
inline EnvironmentHandle::operator const SQLHENV &() const
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline const SQLHENV & EnvironmentHandle::handle() const
|
||||||
|
{
|
||||||
|
return _henv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline EnvironmentHandle::operator SQLHENV &()
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline SQLHENV & EnvironmentHandle::handle()
|
||||||
|
{
|
||||||
|
return _henv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
inline const SQLHENV& EnvironmentHandle::handle() const
|
|
||||||
{
|
|
||||||
return _henv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline EnvironmentHandle::operator SQLHENV& ()
|
|
||||||
{
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline SQLHENV& EnvironmentHandle::handle()
|
|
||||||
{
|
|
||||||
return _henv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,107 +18,107 @@
|
|||||||
#define Data_ODBC_Error_INCLUDED
|
#define Data_ODBC_Error_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "Poco/Data/ODBC/Diagnostics.h"
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include "Poco/Data/ODBC/Utility.h"
|
#include "Poco/Data/ODBC/Utility.h"
|
||||||
#include "Poco/Data/ODBC/Diagnostics.h"
|
|
||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
#include <vector>
|
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
template <typename H, SQLSMALLINT handleType>
|
|
||||||
class Error
|
|
||||||
/// Class encapsulating ODBC diagnostic record collection. Collection is generated
|
|
||||||
/// during construction. Class provides access and string generation for the collection
|
|
||||||
/// as well as individual diagnostic records.
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
explicit Error(const H& handle) : _diagnostics(handle)
|
{
|
||||||
/// Creates the Error.
|
namespace ODBC
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
~Error()
|
|
||||||
/// Destroys the Error.
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const Diagnostics<H, handleType>& diagnostics() const
|
|
||||||
/// Returns the associated diagnostics.
|
|
||||||
{
|
|
||||||
return _diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count() const
|
|
||||||
/// Returns the count of diagnostic records.
|
|
||||||
{
|
|
||||||
return (int) _diagnostics.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string& toString(int index, std::string& str) const
|
|
||||||
/// Generates the string for the diagnostic record.
|
|
||||||
{
|
|
||||||
if ((index < 0) || (index > (count() - 1)))
|
|
||||||
return str;
|
|
||||||
|
|
||||||
std::string s;
|
|
||||||
Poco::format(s,
|
|
||||||
"===========================\n"
|
|
||||||
"ODBC Diagnostic record #%d:\n"
|
|
||||||
"===========================\n"
|
|
||||||
"SQLSTATE = %s\nNative Error Code = %ld\n%s\n\n",
|
|
||||||
index + 1,
|
|
||||||
_diagnostics.sqlState(index),
|
|
||||||
_diagnostics.nativeError(index),
|
|
||||||
_diagnostics.message(index));
|
|
||||||
|
|
||||||
str.append(s);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const
|
|
||||||
/// Generates the string for the diagnostic record collection.
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
Poco::format(str,
|
|
||||||
"Connection:%s\nServer:%s\n",
|
|
||||||
_diagnostics.connectionName(),
|
|
||||||
_diagnostics.serverName());
|
|
||||||
|
|
||||||
std::string s;
|
|
||||||
for (int i = 0; i < count(); ++i)
|
|
||||||
{
|
|
||||||
s.clear();
|
|
||||||
str.append(toString(i, s));
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Error();
|
|
||||||
|
|
||||||
Diagnostics<H, handleType> _diagnostics;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef Error<SQLHENV, SQL_HANDLE_ENV> EnvironmentError;
|
template <typename H, SQLSMALLINT handleType>
|
||||||
typedef Error<SQLHDBC, SQL_HANDLE_DBC> ConnectionError;
|
class Error
|
||||||
typedef Error<SQLHSTMT, SQL_HANDLE_STMT> StatementError;
|
/// Class encapsulating ODBC diagnostic record collection. Collection is generated
|
||||||
typedef Error<SQLHSTMT, SQL_HANDLE_DESC> DescriptorError;
|
/// during construction. Class provides access and string generation for the collection
|
||||||
|
/// as well as individual diagnostic records.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Error(const H & handle) : _diagnostics(handle)
|
||||||
|
/// Creates the Error.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Error()
|
||||||
|
/// Destroys the Error.
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const Diagnostics<H, handleType> & diagnostics() const
|
||||||
|
/// Returns the associated diagnostics.
|
||||||
|
{
|
||||||
|
return _diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count() const
|
||||||
|
/// Returns the count of diagnostic records.
|
||||||
|
{
|
||||||
|
return (int)_diagnostics.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string & toString(int index, std::string & str) const
|
||||||
|
/// Generates the string for the diagnostic record.
|
||||||
|
{
|
||||||
|
if ((index < 0) || (index > (count() - 1)))
|
||||||
|
return str;
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
Poco::format(
|
||||||
|
s,
|
||||||
|
"===========================\n"
|
||||||
|
"ODBC Diagnostic record #%d:\n"
|
||||||
|
"===========================\n"
|
||||||
|
"SQLSTATE = %s\nNative Error Code = %ld\n%s\n\n",
|
||||||
|
index + 1,
|
||||||
|
_diagnostics.sqlState(index),
|
||||||
|
_diagnostics.nativeError(index),
|
||||||
|
_diagnostics.message(index));
|
||||||
|
|
||||||
|
str.append(s);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const
|
||||||
|
/// Generates the string for the diagnostic record collection.
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
Poco::format(str, "Connection:%s\nServer:%s\n", _diagnostics.connectionName(), _diagnostics.serverName());
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
for (int i = 0; i < count(); ++i)
|
||||||
|
{
|
||||||
|
s.clear();
|
||||||
|
str.append(toString(i, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Error();
|
||||||
|
|
||||||
|
Diagnostics<H, handleType> _diagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
typedef Error<SQLHENV, SQL_HANDLE_ENV> EnvironmentError;
|
||||||
|
typedef Error<SQLHDBC, SQL_HANDLE_DBC> ConnectionError;
|
||||||
|
typedef Error<SQLHSTMT, SQL_HANDLE_STMT> StatementError;
|
||||||
|
typedef Error<SQLHSTMT, SQL_HANDLE_DESC> DescriptorError;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -18,96 +18,94 @@
|
|||||||
#define Data_ODBC_Handle_INCLUDED
|
#define Data_ODBC_Handle_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
|
||||||
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
|
||||||
#include "Poco/Data/ODBC/ConnectionHandle.h"
|
#include "Poco/Data/ODBC/ConnectionHandle.h"
|
||||||
|
#include "Poco/Data/ODBC/EnvironmentHandle.h"
|
||||||
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
#include "Poco/Data/ODBC/Utility.h"
|
#include "Poco/Data/ODBC/Utility.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqltypes.h>
|
#include <sqltypes.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
template <typename H, SQLSMALLINT handleType>
|
|
||||||
class Handle
|
|
||||||
/// ODBC handle class template
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
Handle(const ConnectionHandle& rConnection):
|
{
|
||||||
_rConnection(rConnection),
|
namespace ODBC
|
||||||
_handle(0)
|
{
|
||||||
/// Creates the Handle.
|
|
||||||
{
|
|
||||||
if (Utility::isError(SQLAllocHandle(handleType,
|
|
||||||
_rConnection,
|
|
||||||
&_handle)))
|
|
||||||
{
|
|
||||||
throw ODBCException("Could not allocate statement handle.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Handle()
|
|
||||||
/// Destroys the Handle.
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SQLRETURN rc = SQLFreeHandle(handleType, _handle);
|
|
||||||
// N.B. Destructors should not throw, but neither do we want to
|
|
||||||
// leak resources. So, we throw here in debug mode if things go bad.
|
|
||||||
poco_assert_dbg (!Utility::isError(rc));
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
poco_unexpected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator const H& () const
|
|
||||||
/// Const conversion operator into reference to native type.
|
|
||||||
{
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
const H& handle() const
|
|
||||||
/// Returns const reference to native type.
|
|
||||||
{
|
|
||||||
return _handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Handle(const Handle&);
|
|
||||||
const Handle& operator=(const Handle&);
|
|
||||||
|
|
||||||
operator H& ()
|
|
||||||
/// Conversion operator into reference to native type.
|
|
||||||
{
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
H& handle()
|
|
||||||
/// Returns reference to native type.
|
|
||||||
{
|
|
||||||
return _handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ConnectionHandle& _rConnection;
|
|
||||||
H _handle;
|
|
||||||
|
|
||||||
friend class ODBCStatementImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef Handle<SQLHSTMT, SQL_HANDLE_STMT> StatementHandle;
|
template <typename H, SQLSMALLINT handleType>
|
||||||
typedef Handle<SQLHDESC, SQL_HANDLE_DESC> DescriptorHandle;
|
class Handle
|
||||||
|
/// ODBC handle class template
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Handle(const ConnectionHandle & rConnection) : _rConnection(rConnection), _handle(0)
|
||||||
|
/// Creates the Handle.
|
||||||
|
{
|
||||||
|
if (Utility::isError(SQLAllocHandle(handleType, _rConnection, &_handle)))
|
||||||
|
{
|
||||||
|
throw ODBCException("Could not allocate statement handle.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Handle()
|
||||||
|
/// Destroys the Handle.
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SQLRETURN rc = SQLFreeHandle(handleType, _handle);
|
||||||
|
// N.B. Destructors should not throw, but neither do we want to
|
||||||
|
// leak resources. So, we throw here in debug mode if things go bad.
|
||||||
|
poco_assert_dbg(!Utility::isError(rc));
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
poco_unexpected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const H &() const
|
||||||
|
/// Const conversion operator into reference to native type.
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
const H & handle() const
|
||||||
|
/// Returns const reference to native type.
|
||||||
|
{
|
||||||
|
return _handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Handle(const Handle &);
|
||||||
|
const Handle & operator=(const Handle &);
|
||||||
|
|
||||||
|
operator H &()
|
||||||
|
/// Conversion operator into reference to native type.
|
||||||
|
{
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
H & handle()
|
||||||
|
/// Returns reference to native type.
|
||||||
|
{
|
||||||
|
return _handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConnectionHandle & _rConnection;
|
||||||
|
H _handle;
|
||||||
|
|
||||||
|
friend class ODBCStatementImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
typedef Handle<SQLHSTMT, SQL_HANDLE_STMT> StatementHandle;
|
||||||
|
typedef Handle<SQLHDESC, SQL_HANDLE_DESC> DescriptorHandle;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,9 +21,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "Poco/Foundation.h"
|
#include "Poco/Foundation.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -34,36 +31,23 @@
|
|||||||
// ODBC_API functions as being imported from a DLL, whereas this DLL sees symbols
|
// ODBC_API functions as being imported from a DLL, whereas this DLL sees symbols
|
||||||
// defined with this macro as being exported.
|
// defined with this macro as being exported.
|
||||||
//
|
//
|
||||||
#if defined(_WIN32) && defined(POCO_DLL)
|
|
||||||
#if defined(ODBC_EXPORTS)
|
|
||||||
#define ODBC_API __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define ODBC_API __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined(ODBC_API)
|
#if !defined(ODBC_API)
|
||||||
#if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined (__GNUC__) && (__GNUC__ >= 4)
|
# if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
#define ODBC_API __attribute__ ((visibility ("default")))
|
# define ODBC_API __attribute__((visibility("default")))
|
||||||
#else
|
# else
|
||||||
#define ODBC_API
|
# define ODBC_API
|
||||||
#endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/Unicode.h"
|
#include "Poco/Data/ODBC/Unicode.h"
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Automatically link Data library.
|
// Automatically link Data library.
|
||||||
//
|
//
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#if !defined(POCO_NO_AUTOMATIC_LIBS) && !defined(ODBC_EXPORTS)
|
|
||||||
#pragma comment(lib, "PocoDataODBC" POCO_LIB_SUFFIX)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif // ODBC_ODBC_INCLUDED
|
#endif // ODBC_ODBC_INCLUDED
|
||||||
|
@ -18,133 +18,130 @@
|
|||||||
#define Data_ODBC_ODBCException_INCLUDED
|
#define Data_ODBC_ODBCException_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
#include "Poco/Data/DataException.h"
|
||||||
#include "Poco/Data/ODBC/Utility.h"
|
|
||||||
#include "Poco/Data/ODBC/Diagnostics.h"
|
#include "Poco/Data/ODBC/Diagnostics.h"
|
||||||
#include "Poco/Data/ODBC/Error.h"
|
#include "Poco/Data/ODBC/Error.h"
|
||||||
#include "Poco/Data/DataException.h"
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
|
#include "Poco/Data/ODBC/Utility.h"
|
||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
POCO_DECLARE_EXCEPTION(ODBC_API, ODBCException, Poco::Data::DataException)
|
|
||||||
POCO_DECLARE_EXCEPTION(ODBC_API, InsufficientStorageException, ODBCException)
|
|
||||||
POCO_DECLARE_EXCEPTION(ODBC_API, UnknownDataLengthException, ODBCException)
|
|
||||||
POCO_DECLARE_EXCEPTION(ODBC_API, DataTruncatedException, ODBCException)
|
|
||||||
|
|
||||||
|
|
||||||
template <class H, SQLSMALLINT handleType>
|
|
||||||
class HandleException: public ODBCException
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
HandleException(const H& handle): _error(handle)
|
{
|
||||||
/// Creates HandleException
|
namespace ODBC
|
||||||
{
|
{
|
||||||
message(_error.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleException(const H& handle, const std::string& msg):
|
|
||||||
ODBCException(msg),
|
|
||||||
_error(handle)
|
|
||||||
/// Creates HandleException
|
|
||||||
{
|
|
||||||
extendedMessage(_error.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleException(const H& handle, const std::string& msg, const std::string& arg):
|
|
||||||
ODBCException(msg, arg),
|
|
||||||
_error(handle)
|
|
||||||
/// Creates HandleException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleException(const H& handle, const std::string& msg, const Poco::Exception& exc):
|
|
||||||
ODBCException(msg, exc),
|
|
||||||
_error(handle)
|
|
||||||
/// Creates HandleException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleException(const HandleException& exc):
|
|
||||||
ODBCException(exc),
|
|
||||||
_error(exc._error)
|
|
||||||
/// Creates HandleException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~HandleException() throw()
|
|
||||||
/// Destroys HandleException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleException& operator = (const HandleException& exc)
|
|
||||||
/// Assignment operator
|
|
||||||
{
|
|
||||||
if (&exc != this) _error = exc._error;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* name() const throw()
|
|
||||||
/// Returns the name of the exception
|
|
||||||
{
|
|
||||||
return "ODBC handle exception";
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* className() const throw()
|
|
||||||
/// Returns the HandleException class name.
|
|
||||||
{
|
|
||||||
return typeid(*this).name();
|
|
||||||
}
|
|
||||||
|
|
||||||
Poco::Exception* clone() const
|
|
||||||
/// Clones the HandleException
|
|
||||||
{
|
|
||||||
return new HandleException(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rethrow() const
|
|
||||||
/// Re-throws the HandleException.
|
|
||||||
{
|
|
||||||
throw *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Diagnostics<H, handleType>& diagnostics() const
|
|
||||||
/// Returns error diagnostics.
|
|
||||||
{
|
|
||||||
return _error.diagnostics();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const
|
|
||||||
/// Returns the formatted error diagnostics for the handle.
|
|
||||||
{
|
|
||||||
return Poco::format("ODBC Error: %s\n===================\n%s\n",
|
|
||||||
std::string(what()),
|
|
||||||
_error.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string errorString(const H& handle)
|
|
||||||
/// Returns the error diagnostics string for the handle.
|
|
||||||
{
|
|
||||||
return Error<H, handleType>(handle).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Error<H, handleType> _error;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef HandleException<SQLHENV, SQL_HANDLE_ENV> EnvironmentException;
|
POCO_DECLARE_EXCEPTION(ODBC_API, ODBCException, Poco::Data::DataException)
|
||||||
typedef HandleException<SQLHDBC, SQL_HANDLE_DBC> ConnectionException;
|
POCO_DECLARE_EXCEPTION(ODBC_API, InsufficientStorageException, ODBCException)
|
||||||
typedef HandleException<SQLHSTMT, SQL_HANDLE_STMT> StatementException;
|
POCO_DECLARE_EXCEPTION(ODBC_API, UnknownDataLengthException, ODBCException)
|
||||||
typedef HandleException<SQLHDESC, SQL_HANDLE_DESC> DescriptorException;
|
POCO_DECLARE_EXCEPTION(ODBC_API, DataTruncatedException, ODBCException)
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
template <class H, SQLSMALLINT handleType>
|
||||||
|
class HandleException : public ODBCException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HandleException(const H & handle) : _error(handle)
|
||||||
|
/// Creates HandleException
|
||||||
|
{
|
||||||
|
message(_error.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleException(const H & handle, const std::string & msg) : ODBCException(msg), _error(handle)
|
||||||
|
/// Creates HandleException
|
||||||
|
{
|
||||||
|
extendedMessage(_error.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleException(const H & handle, const std::string & msg, const std::string & arg) : ODBCException(msg, arg), _error(handle)
|
||||||
|
/// Creates HandleException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleException(const H & handle, const std::string & msg, const Poco::Exception & exc)
|
||||||
|
: ODBCException(msg, exc), _error(handle)
|
||||||
|
/// Creates HandleException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleException(const HandleException & exc) : ODBCException(exc), _error(exc._error)
|
||||||
|
/// Creates HandleException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~HandleException() throw()
|
||||||
|
/// Destroys HandleException
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleException & operator=(const HandleException & exc)
|
||||||
|
/// Assignment operator
|
||||||
|
{
|
||||||
|
if (&exc != this)
|
||||||
|
_error = exc._error;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * name() const throw()
|
||||||
|
/// Returns the name of the exception
|
||||||
|
{
|
||||||
|
return "ODBC handle exception";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * className() const throw()
|
||||||
|
/// Returns the HandleException class name.
|
||||||
|
{
|
||||||
|
return typeid(*this).name();
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::Exception * clone() const
|
||||||
|
/// Clones the HandleException
|
||||||
|
{
|
||||||
|
return new HandleException(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rethrow() const
|
||||||
|
/// Re-throws the HandleException.
|
||||||
|
{
|
||||||
|
throw *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Diagnostics<H, handleType> & diagnostics() const
|
||||||
|
/// Returns error diagnostics.
|
||||||
|
{
|
||||||
|
return _error.diagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const
|
||||||
|
/// Returns the formatted error diagnostics for the handle.
|
||||||
|
{
|
||||||
|
return Poco::format("ODBC Error: %s\n===================\n%s\n", std::string(what()), _error.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string errorString(const H & handle)
|
||||||
|
/// Returns the error diagnostics string for the handle.
|
||||||
|
{
|
||||||
|
return Error<H, handleType>(handle).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Error<H, handleType> _error;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef HandleException<SQLHENV, SQL_HANDLE_ENV> EnvironmentException;
|
||||||
|
typedef HandleException<SQLHDBC, SQL_HANDLE_DBC> ConnectionException;
|
||||||
|
typedef HandleException<SQLHSTMT, SQL_HANDLE_STMT> StatementException;
|
||||||
|
typedef HandleException<SQLHDESC, SQL_HANDLE_DESC> DescriptorException;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,75 +18,77 @@
|
|||||||
#define Data_ODBC_ODBCColumn_INCLUDED
|
#define Data_ODBC_ODBCColumn_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
#include "Poco/Data/MetaColumn.h"
|
||||||
#include "Poco/Data/ODBC/Error.h"
|
#include "Poco/Data/ODBC/Error.h"
|
||||||
#include "Poco/Data/ODBC/Handle.h"
|
#include "Poco/Data/ODBC/Handle.h"
|
||||||
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include "Poco/Data/ODBC/ODBCException.h"
|
#include "Poco/Data/ODBC/ODBCException.h"
|
||||||
#include "Poco/Data/MetaColumn.h"
|
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API ODBCMetaColumn: public MetaColumn
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
explicit ODBCMetaColumn(const StatementHandle& rStmt, std::size_t position);
|
|
||||||
/// Creates the ODBCMetaColumn.
|
|
||||||
|
|
||||||
~ODBCMetaColumn();
|
|
||||||
/// Destroys the ODBCMetaColumn.
|
|
||||||
|
|
||||||
std::size_t dataLength() const;
|
|
||||||
/// A numeric value that is either the maximum or actual character length of a character
|
|
||||||
/// string or binary data type. It is the maximum character length for a fixed-length data type,
|
|
||||||
/// or the actual character length for a variable-length data type. Its value always excludes the
|
|
||||||
/// null-termination byte that ends the character string.
|
|
||||||
/// This information is returned from the SQL_DESC_LENGTH record field of the IRD.
|
|
||||||
|
|
||||||
bool isUnsigned() const;
|
|
||||||
/// Returns true if column is unsigned or a non-numeric data type.
|
|
||||||
|
|
||||||
private:
|
|
||||||
ODBCMetaColumn();
|
|
||||||
|
|
||||||
static const int NAME_BUFFER_LENGTH = 2048;
|
|
||||||
|
|
||||||
struct ColumnDescription
|
|
||||||
{
|
|
||||||
SQLCHAR name[NAME_BUFFER_LENGTH];
|
|
||||||
SQLSMALLINT nameBufferLength;
|
|
||||||
SQLSMALLINT dataType;
|
|
||||||
SQLULEN size;
|
|
||||||
SQLSMALLINT decimalDigits;
|
|
||||||
SQLSMALLINT isNullable;
|
|
||||||
};
|
|
||||||
|
|
||||||
void init();
|
|
||||||
void getDescription();
|
|
||||||
|
|
||||||
SQLLEN _dataLength;
|
|
||||||
const StatementHandle& _rStmt;
|
|
||||||
ColumnDescription _columnDesc;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// inlines
|
|
||||||
///
|
|
||||||
inline std::size_t ODBCMetaColumn::dataLength() const
|
|
||||||
{
|
{
|
||||||
return _dataLength;
|
namespace ODBC
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class ODBC_API ODBCMetaColumn : public MetaColumn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ODBCMetaColumn(const StatementHandle & rStmt, std::size_t position);
|
||||||
|
/// Creates the ODBCMetaColumn.
|
||||||
|
|
||||||
|
~ODBCMetaColumn();
|
||||||
|
/// Destroys the ODBCMetaColumn.
|
||||||
|
|
||||||
|
std::size_t dataLength() const;
|
||||||
|
/// A numeric value that is either the maximum or actual character length of a character
|
||||||
|
/// string or binary data type. It is the maximum character length for a fixed-length data type,
|
||||||
|
/// or the actual character length for a variable-length data type. Its value always excludes the
|
||||||
|
/// null-termination byte that ends the character string.
|
||||||
|
/// This information is returned from the SQL_DESC_LENGTH record field of the IRD.
|
||||||
|
|
||||||
|
bool isUnsigned() const;
|
||||||
|
/// Returns true if column is unsigned or a non-numeric data type.
|
||||||
|
|
||||||
|
private:
|
||||||
|
ODBCMetaColumn();
|
||||||
|
|
||||||
|
static const int NAME_BUFFER_LENGTH = 2048;
|
||||||
|
|
||||||
|
struct ColumnDescription
|
||||||
|
{
|
||||||
|
SQLCHAR name[NAME_BUFFER_LENGTH];
|
||||||
|
SQLSMALLINT nameBufferLength;
|
||||||
|
SQLSMALLINT dataType;
|
||||||
|
SQLULEN size;
|
||||||
|
SQLSMALLINT decimalDigits;
|
||||||
|
SQLSMALLINT isNullable;
|
||||||
|
};
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void getDescription();
|
||||||
|
|
||||||
|
SQLLEN _dataLength;
|
||||||
|
const StatementHandle & _rStmt;
|
||||||
|
ColumnDescription _columnDesc;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// inlines
|
||||||
|
///
|
||||||
|
inline std::size_t ODBCMetaColumn::dataLength() const
|
||||||
|
{
|
||||||
|
return _dataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,189 +18,191 @@
|
|||||||
#define Data_ODBC_ODBCStatementImpl_INCLUDED
|
#define Data_ODBC_ODBCStatementImpl_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
#include <sstream>
|
||||||
#include "Poco/Data/ODBC/SessionImpl.h"
|
#include "Poco/Data/Column.h"
|
||||||
#include "Poco/Data/ODBC/Binder.h"
|
#include "Poco/Data/ODBC/Binder.h"
|
||||||
#include "Poco/Data/ODBC/Extractor.h"
|
#include "Poco/Data/ODBC/Extractor.h"
|
||||||
#include "Poco/Data/ODBC/Preparator.h"
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
|
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
|
||||||
|
#include "Poco/Data/ODBC/Preparator.h"
|
||||||
|
#include "Poco/Data/ODBC/SessionImpl.h"
|
||||||
#include "Poco/Data/StatementImpl.h"
|
#include "Poco/Data/StatementImpl.h"
|
||||||
#include "Poco/Data/Column.h"
|
|
||||||
#include "Poco/SharedPtr.h"
|
|
||||||
#include "Poco/Format.h"
|
#include "Poco/Format.h"
|
||||||
#include <sstream>
|
#include "Poco/SharedPtr.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqltypes.h>
|
#include <sqltypes.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API ODBCStatementImpl: public Poco::Data::StatementImpl
|
|
||||||
/// Implements statement functionality needed for ODBC
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
ODBCStatementImpl(SessionImpl& rSession);
|
|
||||||
/// Creates the ODBCStatementImpl.
|
|
||||||
|
|
||||||
~ODBCStatementImpl();
|
|
||||||
/// Destroys the ODBCStatementImpl.
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::size_t columnsReturned() const;
|
|
||||||
/// Returns number of columns returned by query.
|
|
||||||
|
|
||||||
int affectedRowCount() const;
|
|
||||||
/// Returns the number of affected rows.
|
|
||||||
/// Used to find out the number of rows affected by insert or update.
|
|
||||||
|
|
||||||
const MetaColumn& metaColumn(std::size_t pos) const;
|
|
||||||
/// Returns column meta data.
|
|
||||||
|
|
||||||
bool hasNext();
|
|
||||||
/// Returns true if a call to next() will return data.
|
|
||||||
|
|
||||||
std::size_t next();
|
|
||||||
/// Retrieves the next row or set of rows from the resultset.
|
|
||||||
/// Returns the number of rows retrieved.
|
|
||||||
/// Will throw, if the resultset is empty.
|
|
||||||
|
|
||||||
bool canBind() const;
|
|
||||||
/// Returns true if a valid statement is set and we can bind.
|
|
||||||
|
|
||||||
bool canCompile() const;
|
|
||||||
/// Returns true if another compile is possible.
|
|
||||||
|
|
||||||
void compileImpl();
|
|
||||||
/// Compiles the statement, doesn't bind yet.
|
|
||||||
/// Does nothing if the statement has already been compiled.
|
|
||||||
|
|
||||||
void bindImpl();
|
|
||||||
/// Binds all parameters and executes the statement.
|
|
||||||
|
|
||||||
AbstractExtraction::ExtractorPtr extractor();
|
|
||||||
/// Returns the concrete extractor used by the statement.
|
|
||||||
|
|
||||||
AbstractBinding::BinderPtr binder();
|
|
||||||
/// Returns the concrete binder used by the statement.
|
|
||||||
|
|
||||||
std::string nativeSQL();
|
|
||||||
/// Returns the SQL string as modified by the driver.
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef Poco::Data::AbstractBindingVec Bindings;
|
|
||||||
typedef Poco::SharedPtr<Binder> BinderPtr;
|
|
||||||
typedef Poco::Data::AbstractExtractionVec Extractions;
|
|
||||||
typedef Poco::SharedPtr<Preparator> PreparatorPtr;
|
|
||||||
typedef std::vector<PreparatorPtr> PreparatorVec;
|
|
||||||
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
|
|
||||||
typedef std::vector<ExtractorPtr> ExtractorVec;
|
|
||||||
typedef std::vector<ODBCMetaColumn*> ColumnPtrVec;
|
|
||||||
typedef std::vector<ColumnPtrVec> ColumnPtrVecVec;
|
|
||||||
|
|
||||||
static const std::string INVALID_CURSOR_STATE;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
/// Closes the cursor and resets indicator variables.
|
|
||||||
|
|
||||||
void doBind();
|
|
||||||
/// Binds parameters.
|
|
||||||
|
|
||||||
void makeInternalExtractors();
|
|
||||||
/// Creates internal extractors if none were supplied from the user.
|
|
||||||
|
|
||||||
bool isStoredProcedure() const;
|
|
||||||
/// Returns true if SQL is a stored procedure call.
|
|
||||||
|
|
||||||
void doPrepare();
|
|
||||||
/// Prepares placeholders for data returned by statement.
|
|
||||||
/// It is called during statement compilation for SQL statements
|
|
||||||
/// returning data. For stored procedures returning datasets,
|
|
||||||
/// it is called upon the first check for data availability
|
|
||||||
/// (see hasNext() function).
|
|
||||||
|
|
||||||
bool hasData() const;
|
|
||||||
/// Returns true if statement returns data.
|
|
||||||
|
|
||||||
void makeStep();
|
|
||||||
/// Fetches the next row of data.
|
|
||||||
|
|
||||||
bool nextRowReady() const;
|
|
||||||
/// Returns true if there is a row fetched but not yet extracted.
|
|
||||||
|
|
||||||
void putData();
|
|
||||||
/// Called whenever SQLExecute returns SQL_NEED_DATA. This is expected
|
|
||||||
/// behavior for PB_AT_EXEC binding mode.
|
|
||||||
|
|
||||||
void getData();
|
|
||||||
|
|
||||||
void addPreparator();
|
|
||||||
void fillColumns();
|
|
||||||
void checkError(SQLRETURN rc, const std::string& msg="");
|
|
||||||
|
|
||||||
const SQLHDBC& _rConnection;
|
|
||||||
const StatementHandle _stmt;
|
|
||||||
PreparatorVec _preparations;
|
|
||||||
BinderPtr _pBinder;
|
|
||||||
ExtractorVec _extractors;
|
|
||||||
bool _stepCalled;
|
|
||||||
int _nextResponse;
|
|
||||||
ColumnPtrVecVec _columnPtrs;
|
|
||||||
bool _prepared;
|
|
||||||
mutable std::size_t _affectedRowCount;
|
|
||||||
bool _canCompile;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// inlines
|
|
||||||
//
|
|
||||||
inline AbstractExtraction::ExtractorPtr ODBCStatementImpl::extractor()
|
|
||||||
{
|
{
|
||||||
poco_assert_dbg (currentDataSet() < _extractors.size());
|
namespace ODBC
|
||||||
poco_assert_dbg (_extractors[currentDataSet()]);
|
{
|
||||||
return _extractors[currentDataSet()];
|
|
||||||
|
|
||||||
|
class ODBC_API ODBCStatementImpl : public Poco::Data::StatementImpl
|
||||||
|
/// Implements statement functionality needed for ODBC
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ODBCStatementImpl(SessionImpl & rSession);
|
||||||
|
/// Creates the ODBCStatementImpl.
|
||||||
|
|
||||||
|
~ODBCStatementImpl();
|
||||||
|
/// Destroys the ODBCStatementImpl.
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::size_t columnsReturned() const;
|
||||||
|
/// Returns number of columns returned by query.
|
||||||
|
|
||||||
|
int affectedRowCount() const;
|
||||||
|
/// Returns the number of affected rows.
|
||||||
|
/// Used to find out the number of rows affected by insert or update.
|
||||||
|
|
||||||
|
const MetaColumn & metaColumn(std::size_t pos) const;
|
||||||
|
/// Returns column meta data.
|
||||||
|
|
||||||
|
bool hasNext();
|
||||||
|
/// Returns true if a call to next() will return data.
|
||||||
|
|
||||||
|
std::size_t next();
|
||||||
|
/// Retrieves the next row or set of rows from the resultset.
|
||||||
|
/// Returns the number of rows retrieved.
|
||||||
|
/// Will throw, if the resultset is empty.
|
||||||
|
|
||||||
|
bool canBind() const;
|
||||||
|
/// Returns true if a valid statement is set and we can bind.
|
||||||
|
|
||||||
|
bool canCompile() const;
|
||||||
|
/// Returns true if another compile is possible.
|
||||||
|
|
||||||
|
void compileImpl();
|
||||||
|
/// Compiles the statement, doesn't bind yet.
|
||||||
|
/// Does nothing if the statement has already been compiled.
|
||||||
|
|
||||||
|
void bindImpl();
|
||||||
|
/// Binds all parameters and executes the statement.
|
||||||
|
|
||||||
|
AbstractExtraction::ExtractorPtr extractor();
|
||||||
|
/// Returns the concrete extractor used by the statement.
|
||||||
|
|
||||||
|
AbstractBinding::BinderPtr binder();
|
||||||
|
/// Returns the concrete binder used by the statement.
|
||||||
|
|
||||||
|
std::string nativeSQL();
|
||||||
|
/// Returns the SQL string as modified by the driver.
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef Poco::Data::AbstractBindingVec Bindings;
|
||||||
|
typedef Poco::SharedPtr<Binder> BinderPtr;
|
||||||
|
typedef Poco::Data::AbstractExtractionVec Extractions;
|
||||||
|
typedef Poco::SharedPtr<Preparator> PreparatorPtr;
|
||||||
|
typedef std::vector<PreparatorPtr> PreparatorVec;
|
||||||
|
typedef Poco::SharedPtr<Extractor> ExtractorPtr;
|
||||||
|
typedef std::vector<ExtractorPtr> ExtractorVec;
|
||||||
|
typedef std::vector<ODBCMetaColumn *> ColumnPtrVec;
|
||||||
|
typedef std::vector<ColumnPtrVec> ColumnPtrVecVec;
|
||||||
|
|
||||||
|
static const std::string INVALID_CURSOR_STATE;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
/// Closes the cursor and resets indicator variables.
|
||||||
|
|
||||||
|
void doBind();
|
||||||
|
/// Binds parameters.
|
||||||
|
|
||||||
|
void makeInternalExtractors();
|
||||||
|
/// Creates internal extractors if none were supplied from the user.
|
||||||
|
|
||||||
|
bool isStoredProcedure() const;
|
||||||
|
/// Returns true if SQL is a stored procedure call.
|
||||||
|
|
||||||
|
void doPrepare();
|
||||||
|
/// Prepares placeholders for data returned by statement.
|
||||||
|
/// It is called during statement compilation for SQL statements
|
||||||
|
/// returning data. For stored procedures returning datasets,
|
||||||
|
/// it is called upon the first check for data availability
|
||||||
|
/// (see hasNext() function).
|
||||||
|
|
||||||
|
bool hasData() const;
|
||||||
|
/// Returns true if statement returns data.
|
||||||
|
|
||||||
|
void makeStep();
|
||||||
|
/// Fetches the next row of data.
|
||||||
|
|
||||||
|
bool nextRowReady() const;
|
||||||
|
/// Returns true if there is a row fetched but not yet extracted.
|
||||||
|
|
||||||
|
void putData();
|
||||||
|
/// Called whenever SQLExecute returns SQL_NEED_DATA. This is expected
|
||||||
|
/// behavior for PB_AT_EXEC binding mode.
|
||||||
|
|
||||||
|
void getData();
|
||||||
|
|
||||||
|
void addPreparator();
|
||||||
|
void fillColumns();
|
||||||
|
void checkError(SQLRETURN rc, const std::string & msg = "");
|
||||||
|
|
||||||
|
const SQLHDBC & _rConnection;
|
||||||
|
const StatementHandle _stmt;
|
||||||
|
PreparatorVec _preparations;
|
||||||
|
BinderPtr _pBinder;
|
||||||
|
ExtractorVec _extractors;
|
||||||
|
bool _stepCalled;
|
||||||
|
int _nextResponse;
|
||||||
|
ColumnPtrVecVec _columnPtrs;
|
||||||
|
bool _prepared;
|
||||||
|
mutable std::size_t _affectedRowCount;
|
||||||
|
bool _canCompile;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// inlines
|
||||||
|
//
|
||||||
|
inline AbstractExtraction::ExtractorPtr ODBCStatementImpl::extractor()
|
||||||
|
{
|
||||||
|
poco_assert_dbg(currentDataSet() < _extractors.size());
|
||||||
|
poco_assert_dbg(_extractors[currentDataSet()]);
|
||||||
|
return _extractors[currentDataSet()];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline AbstractBinding::BinderPtr ODBCStatementImpl::binder()
|
||||||
|
{
|
||||||
|
poco_assert_dbg(!_pBinder.isNull());
|
||||||
|
return _pBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t ODBCStatementImpl::columnsReturned() const
|
||||||
|
{
|
||||||
|
poco_assert_dbg(currentDataSet() < _preparations.size());
|
||||||
|
poco_assert_dbg(_preparations[currentDataSet()]);
|
||||||
|
return static_cast<std::size_t>(_preparations[currentDataSet()]->columns());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool ODBCStatementImpl::hasData() const
|
||||||
|
{
|
||||||
|
return (columnsReturned() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool ODBCStatementImpl::nextRowReady() const
|
||||||
|
{
|
||||||
|
return (!Utility::isError(_nextResponse));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool ODBCStatementImpl::canCompile() const
|
||||||
|
{
|
||||||
|
return _canCompile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
inline AbstractBinding::BinderPtr ODBCStatementImpl::binder()
|
|
||||||
{
|
|
||||||
poco_assert_dbg (!_pBinder.isNull());
|
|
||||||
return _pBinder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t ODBCStatementImpl::columnsReturned() const
|
|
||||||
{
|
|
||||||
poco_assert_dbg (currentDataSet() < _preparations.size());
|
|
||||||
poco_assert_dbg (_preparations[currentDataSet()]);
|
|
||||||
return static_cast<std::size_t>(_preparations[currentDataSet()]->columns());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ODBCStatementImpl::hasData() const
|
|
||||||
{
|
|
||||||
return (columnsReturned() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ODBCStatementImpl::nextRowReady() const
|
|
||||||
{
|
|
||||||
return (!Utility::isError(_nextResponse));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool ODBCStatementImpl::canCompile() const
|
|
||||||
{
|
|
||||||
return _canCompile;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif // Data_ODBC_ODBCStatementImpl_INCLUDED
|
#endif // Data_ODBC_ODBCStatementImpl_INCLUDED
|
||||||
|
@ -18,94 +18,96 @@
|
|||||||
#define Data_ODBC_Parameter_INCLUDED
|
#define Data_ODBC_Parameter_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "Poco/Data/ODBC/ODBC.h"
|
|
||||||
#include "Poco/Data/ODBC/Handle.h"
|
#include "Poco/Data/ODBC/Handle.h"
|
||||||
#ifdef POCO_OS_FAMILY_WINDOWS
|
#include "Poco/Data/ODBC/ODBC.h"
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
#include <sqlext.h>
|
#include <sqlext.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco {
|
namespace Poco
|
||||||
namespace Data {
|
|
||||||
namespace ODBC {
|
|
||||||
|
|
||||||
|
|
||||||
class ODBC_API Parameter
|
|
||||||
{
|
{
|
||||||
public:
|
namespace Data
|
||||||
explicit Parameter(const StatementHandle& rStmt, std::size_t colNum);
|
|
||||||
/// Creates the Parameter.
|
|
||||||
|
|
||||||
~Parameter();
|
|
||||||
/// Destroys the Parameter.
|
|
||||||
|
|
||||||
std::size_t number() const;
|
|
||||||
/// Returns the column number.
|
|
||||||
|
|
||||||
std::size_t dataType() const;
|
|
||||||
/// Returns the SQL data type.
|
|
||||||
|
|
||||||
std::size_t columnSize() const;
|
|
||||||
/// Returns the the size of the column or expression of the corresponding
|
|
||||||
/// parameter marker as defined by the data source.
|
|
||||||
|
|
||||||
std::size_t decimalDigits() const;
|
|
||||||
/// Returns the number of decimal digits of the column or expression
|
|
||||||
/// of the corresponding parameter as defined by the data source.
|
|
||||||
|
|
||||||
bool isNullable() const;
|
|
||||||
/// Returns true if column allows null values, false otherwise.
|
|
||||||
|
|
||||||
private:
|
|
||||||
Parameter();
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
SQLSMALLINT _dataType;
|
|
||||||
SQLULEN _columnSize;
|
|
||||||
SQLSMALLINT _decimalDigits;
|
|
||||||
SQLSMALLINT _isNullable;
|
|
||||||
|
|
||||||
const StatementHandle& _rStmt;
|
|
||||||
std::size_t _number;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// inlines
|
|
||||||
///
|
|
||||||
inline std::size_t Parameter::number() const
|
|
||||||
{
|
{
|
||||||
return _number;
|
namespace ODBC
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
class ODBC_API Parameter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Parameter(const StatementHandle & rStmt, std::size_t colNum);
|
||||||
|
/// Creates the Parameter.
|
||||||
|
|
||||||
|
~Parameter();
|
||||||
|
/// Destroys the Parameter.
|
||||||
|
|
||||||
|
std::size_t number() const;
|
||||||
|
/// Returns the column number.
|
||||||
|
|
||||||
|
std::size_t dataType() const;
|
||||||
|
/// Returns the SQL data type.
|
||||||
|
|
||||||
|
std::size_t columnSize() const;
|
||||||
|
/// Returns the the size of the column or expression of the corresponding
|
||||||
|
/// parameter marker as defined by the data source.
|
||||||
|
|
||||||
|
std::size_t decimalDigits() const;
|
||||||
|
/// Returns the number of decimal digits of the column or expression
|
||||||
|
/// of the corresponding parameter as defined by the data source.
|
||||||
|
|
||||||
|
bool isNullable() const;
|
||||||
|
/// Returns true if column allows null values, false otherwise.
|
||||||
|
|
||||||
|
private:
|
||||||
|
Parameter();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
SQLSMALLINT _dataType;
|
||||||
|
SQLULEN _columnSize;
|
||||||
|
SQLSMALLINT _decimalDigits;
|
||||||
|
SQLSMALLINT _isNullable;
|
||||||
|
|
||||||
|
const StatementHandle & _rStmt;
|
||||||
|
std::size_t _number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
/// inlines
|
||||||
|
///
|
||||||
|
inline std::size_t Parameter::number() const
|
||||||
|
{
|
||||||
|
return _number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Parameter::dataType() const
|
||||||
|
{
|
||||||
|
return _dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Parameter::columnSize() const
|
||||||
|
{
|
||||||
|
return _columnSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline std::size_t Parameter::decimalDigits() const
|
||||||
|
{
|
||||||
|
return _decimalDigits;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool Parameter::isNullable() const
|
||||||
|
{
|
||||||
|
return SQL_NULLABLE == _isNullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} // namespace Poco::Data::ODBC
|
||||||
|
|
||||||
inline std::size_t Parameter::dataType() const
|
|
||||||
{
|
|
||||||
return _dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t Parameter::columnSize() const
|
|
||||||
{
|
|
||||||
return _columnSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::size_t Parameter::decimalDigits() const
|
|
||||||
{
|
|
||||||
return _decimalDigits;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline bool Parameter::isNullable() const
|
|
||||||
{
|
|
||||||
return SQL_NULLABLE == _isNullable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } } // namespace Poco::Data::ODBC
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user