Merge branch 'master' into StringSearcher

This commit is contained in:
Robert Schulze 2023-02-23 11:54:05 +01:00 committed by GitHub
commit 6aa4e93284
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2803 changed files with 339495 additions and 12193 deletions

View File

@ -512,6 +512,75 @@ jobs:
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"
############################################################################################
#################################### INSTALL PACKAGES ######################################
############################################################################################
InstallPackagesTestRelease:
needs: [BuilderDebRelease]
runs-on: [self-hosted, style-checker]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (amd64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
InstallPackagesTestAarch64:
needs: [BuilderDebAarch64]
runs-on: [self-hosted, style-checker-aarch64]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (arm64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
##############################################################################################
########################### FUNCTIONAl STATELESS TESTS #######################################
##############################################################################################

View File

@ -2,7 +2,7 @@
name: Debug
'on':
[push, pull_request, release, workflow_dispatch, workflow_call]
[push, pull_request, pull_request_review, release, workflow_dispatch, workflow_call]
jobs:
DebugInfo:

View File

@ -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"

View File

@ -946,6 +946,75 @@ jobs:
run: |
cd "$GITHUB_WORKSPACE/tests/ci"
python3 mark_release_ready.py
############################################################################################
#################################### INSTALL PACKAGES ######################################
############################################################################################
InstallPackagesTestRelease:
needs: [BuilderDebRelease]
runs-on: [self-hosted, style-checker]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (amd64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
InstallPackagesTestAarch64:
needs: [BuilderDebAarch64]
runs-on: [self-hosted, style-checker-aarch64]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (arm64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
##############################################################################################
########################### FUNCTIONAl STATELESS TESTS #######################################
##############################################################################################

View File

@ -107,7 +107,7 @@ jobs:
run: |
curl --form token="${COVERITY_TOKEN}" \
--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 description="Nighly Scan: $(date +'%Y-%m-%dT%H:%M:%S')" \
https://scan.coverity.com/builds?project=ClickHouse%2FClickHouse
@ -154,7 +154,7 @@ jobs:
- name: Set Up Build Tools
run: |
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)"
- name: Run build-wrapper
run: |

View File

@ -1021,7 +1021,7 @@ jobs:
docker ps --all --quiet | xargs --no-run-if-empty docker rm -f ||:
sudo rm -fr "$TEMP_PATH"
InstallPackagesTestAarch64:
needs: [BuilderDebRelease]
needs: [BuilderDebAarch64]
runs-on: [self-hosted, style-checker-aarch64]
steps:
- name: Set envs

View 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

View File

@ -604,6 +604,75 @@ jobs:
run: |
cd "$GITHUB_WORKSPACE/tests/ci"
python3 mark_release_ready.py
############################################################################################
#################################### INSTALL PACKAGES ######################################
############################################################################################
InstallPackagesTestRelease:
needs: [BuilderDebRelease]
runs-on: [self-hosted, style-checker]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (amd64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
InstallPackagesTestAarch64:
needs: [BuilderDebAarch64]
runs-on: [self-hosted, style-checker-aarch64]
steps:
- name: Set envs
run: |
cat >> "$GITHUB_ENV" << 'EOF'
TEMP_PATH=${{runner.temp}}/test_install
REPORTS_PATH=${{runner.temp}}/reports_dir
CHECK_NAME=Install packages (arm64)
REPO_COPY=${{runner.temp}}/test_install/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: Test packages installation
run: |
sudo rm -fr "$TEMP_PATH"
mkdir -p "$TEMP_PATH"
cp -r "$GITHUB_WORKSPACE" "$TEMP_PATH"
cd "$REPO_COPY/tests/ci"
python3 install_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"
##############################################################################################
########################### FUNCTIONAl STATELESS TESTS #######################################
##############################################################################################

1
.gitignore vendored
View File

@ -161,6 +161,7 @@ website/package-lock.json
tests/queries/0_stateless/test_*
tests/queries/0_stateless/*.binary
tests/queries/0_stateless/*.generated-expect
tests/queries/0_stateless/*.expect.history
# rust
/rust/**/target

7
.gitmodules vendored
View File

@ -1,7 +1,3 @@
[submodule "contrib/poco"]
path = contrib/poco
url = https://github.com/ClickHouse/poco
branch = clickhouse
[submodule "contrib/zstd"]
path = contrib/zstd
url = https://github.com/facebook/zstd
@ -300,6 +296,9 @@
[submodule "contrib/libdivide"]
path = contrib/libdivide
url = https://github.com/ridiculousfish/libdivide
[submodule "contrib/ulid-c"]
path = contrib/ulid-c
url = https://github.com/ClickHouse/ulid-c.git
[submodule "contrib/aws-crt-cpp"]
path = contrib/aws-crt-cpp
url = https://github.com/ClickHouse/aws-crt-cpp

View File

@ -1,9 +1,192 @@
### Table of Contents
**[ClickHouse release v23.2, 2023-02-23](#232)**<br/>
**[ClickHouse release v23.1, 2023-01-25](#231)**<br/>
**[Changelog for 2022](https://clickhouse.com/docs/en/whats-new/changelog/2022/)**<br/>
# 2023 Changelog
### <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. by default, default user will not longer be able to do 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). Fix integration tests. [#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`.
* 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 or prestable 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
### ClickHouse release 23.1

View File

@ -433,6 +433,11 @@ else()
link_libraries(global-group)
endif ()
option (ENABLE_GWP_ASAN "Enable Gwp-Asan" ON)
if (NOT OS_LINUX AND NOT OS_ANDROID)
set(ENABLE_GWP_ASAN OFF)
endif ()
option(WERROR "Enable -Werror compiler option" ON)
if (WERROR)
@ -453,7 +458,7 @@ endif ()
set (CMAKE_POSTFIX_VARIABLE "CMAKE_${CMAKE_BUILD_TYPE_UC}_POSTFIX")
set (CMAKE_POSITION_INDEPENDENT_CODE OFF)
if (OS_LINUX AND NOT ARCH_AARCH64)
if (OS_LINUX AND NOT (ARCH_AARCH64 OR ARCH_S390X))
# Slightly more efficient code can be generated
# It's disabled for ARM because otherwise ClickHouse cannot run on Android.
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-pie")
@ -471,7 +476,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_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
if (CMAKE_INSTALL_PREFIX STREQUAL "/usr")

View File

@ -84,7 +84,10 @@ if (OS MATCHES "Linux"
set (CMAKE_TOOLCHAIN_FILE "cmake/linux/toolchain-aarch64.cmake" CACHE INTERNAL "")
elseif (ARCH MATCHES "^(ppc64le.*|PPC64LE.*)")
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 ()
message (FATAL_ERROR "Unsupported architecture: ${ARCH}")
endif ()
endif()

View File

@ -2,6 +2,11 @@
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
* [Official website](https://clickhouse.com/) has a quick high-level overview of ClickHouse on the main page.
@ -15,6 +20,13 @@ ClickHouse® is an open-source column-oriented database management system that a
* [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.
## 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.
* [**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 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 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!
## 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)**.
* **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**: [**ClickHouse Meetup at the CHEQ office in Tel Aviv**](https://www.meetup.com/clickhouse-tel-aviv-user-group/events/289599423/) - We are very excited to be holding our next in-person ClickHouse meetup at the CHEQ office in Tel Aviv! Hear from CHEQ, ServiceNow and Contentsquare, as well as a deep dive presentation from ClickHouse CTO Alexey Milovidov. Join us for a fun evening of talks, food and discussion!

View File

@ -1,8 +1,5 @@
if (USE_CLANG_TIDY)
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
endif ()
add_subdirectory (base)
add_subdirectory (pcg-random)
add_subdirectory (poco)
add_subdirectory (widechar_width)
add_subdirectory (readpassphrase)

View File

@ -1,3 +1,7 @@
if (USE_CLANG_TIDY)
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
endif ()
set (SRCS
argsToConfig.cpp
coverage.cpp

View File

@ -12,21 +12,22 @@
template <typename To, typename From>
std::decay_t<To> bit_cast(const From & from)
{
/**
* Assume the source value is 0xAABBCCDD (i.e. sizeof(from) == 4).
* Its BE representation is 0xAABBCCDD, the LE representation is 0xDDCCBBAA.
* 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 BE, the result after bit_cast will be 0x00000000AABBCCDD --> input value == output value.
*/
/** Assume the source value is 0xAABBCCDD (i.e. sizeof(from) == 4).
* Its BE representation is 0xAABBCCDD, the LE representation is 0xDDCCBBAA.
* 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 BE, the result after bit_cast will be 0x00000000AABBCCDD --> input value == output value.
*/
To res {};
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
{
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;
memcpy(reinterpret_cast<char *>(&res) + offset_to, reinterpret_cast<const char *>(&from) + offset_from, std::min(sizeof(res), sizeof(from)));
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;
memcpy(reinterpret_cast<char *>(&res) + offset_to, reinterpret_cast<const char *>(&from) + offset_from, std::min(sizeof(res), sizeof(from)));
}
return res;
}

View File

@ -28,8 +28,8 @@
#define NO_INLINE __attribute__((__noinline__))
#define MAY_ALIAS __attribute__((__may_alias__))
#if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__PPC__) && !(defined(__riscv) && (__riscv_xlen == 64))
# error "The only supported platforms are x86_64 and AArch64, PowerPC (work in progress) and RISC-V 64 (experimental)"
#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), s390x (work in progress) and RISC-V 64 (experimental)"
#endif
/// Check for presence of address sanitizer
@ -127,10 +127,14 @@
/// because SIGABRT is easier to debug than SIGTRAP (the second one makes gdb crazy)
#if !defined(chassert)
#if defined(ABORT_ON_LOGICAL_ERROR)
#define chassert(x) static_cast<bool>(x) ? void(0) : abortOnFailedAssertion(#x)
#define chassert(x) static_cast<bool>(x) ? void(0) : ::DB::abortOnFailedAssertion(#x)
#define UNREACHABLE() abort()
#else
#define chassert(x) ((void)0)
/// Here sizeof() trick is used to suppress unused warning for result,
/// since simple "(void)x" will evaluate the expression, while
/// "sizeof(!(x))" will not.
#define NIL_EXPRESSION(x) (void)sizeof(!(x))
#define chassert(x) NIL_EXPRESSION(x)
#define UNREACHABLE() __builtin_unreachable()
#endif
#endif

View File

@ -33,6 +33,41 @@
#include <base/extended_types.h>
template <typename T>
inline int digits10(T x)
{
if (x < 10ULL)
return 1;
if (x < 100ULL)
return 2;
if (x < 1000ULL)
return 3;
if (x < 1000000000000ULL)
{
if (x < 100000000ULL)
{
if (x < 1000000ULL)
{
if (x < 10000ULL)
return 4;
else
return 5 + (x >= 100000ULL);
}
return 7 + (x >= 10000000ULL);
}
if (x < 10000000000ULL)
return 9 + (x >= 1000000000ULL);
return 11 + (x >= 100000000000ULL);
}
return 12 + digits10(x / 1000000000000ULL);
}
namespace impl
{
@ -312,39 +347,6 @@ namespace convert
}
}
template <typename T>
static inline int digits10(T x)
{
if (x < 10ULL)
return 1;
if (x < 100ULL)
return 2;
if (x < 1000ULL)
return 3;
if (x < 1000000000000ULL)
{
if (x < 100000000ULL)
{
if (x < 1000000ULL)
{
if (x < 10000ULL)
return 4;
else
return 5 + (x >= 100000ULL);
}
return 7 + (x >= 10000000ULL);
}
if (x < 10000000000ULL)
return 9 + (x >= 1000000000ULL);
return 11 + (x >= 100000000000ULL);
}
return 12 + digits10(x / 1000000000000ULL);
}
template <typename T>
static inline char * writeUIntText(T x, char * p)

View File

@ -1,8 +1,8 @@
/** Origin: musl-libc /src/math/exp10.c
* https://www.musl-libc.org/
* http://git.musl-libc.org/cgit/musl/tree/src/math/exp10.c
*/
/*
https://www.musl-libc.org/
http://git.musl-libc.org/cgit/musl/tree/src/math/exp10.c
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
@ -27,146 +27,6 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------
Authors/contributors include:
Alex Dowad
Alexander Monakov
Anthony G. Basile
Arvid Picciani
Bobby Bingham
Boris Brezillon
Brent Cook
Chris Spiegel
Clément Vasseur
Daniel Micay
Denys Vlasenko
Emil Renner Berthing
Felix Fietkau
Felix Janda
Gianluca Anzolin
Hauke Mehrtens
Hiltjo Posthuma
Isaac Dunham
Jaydeep Patil
Jens Gustedt
Jeremy Huntwork
Jo-Philipp Wich
Joakim Sindholt
John Spencer
Josiah Worcester
Justin Cormack
Khem Raj
Kylie McClain
Luca Barbato
Luka Perkov
M Farkas-Dyck (Strake)
Mahesh Bodapati
Michael Forney
Natanael Copa
Nicholas J. Kain
orc
Pascal Cuoq
Petr Hosek
Pierre Carrier
Rich Felker
Richard Pennington
Shiz
sin
Solar Designer
Stefan Kristiansson
Szabolcs Nagy
Timo Teräs
Trutz Behn
Valentin Ochs
William Haddon
Portions of this software are derived from third-party works licensed
under terms compatible with the above MIT license:
The TRE regular expression implementation (src/regex/reg* and
src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed
under a 2-clause BSD license (license text in the source files). The
included version has been heavily modified by Rich Felker in 2012, in
the interests of size, simplicity, and namespace cleanliness.
Much of the math library code (src/math/ * and src/complex/ *) is
Copyright © 1993,2004 Sun Microsystems or
Copyright © 2003-2011 David Schultz or
Copyright © 2003-2009 Steven G. Kargl or
Copyright © 2003-2009 Bruce D. Evans or
Copyright © 2008 Stephen L. Moshier
and labelled as such in comments in the individual source files. All
have been licensed under extremely permissive terms.
The ARM memcpy code (src/string/arm/memcpy_el.S) is Copyright © 2008
The Android Open Source Project and is licensed under a two-clause BSD
license. It was taken from Bionic libc, used on Android.
The implementation of DES for crypt (src/crypt/crypt_des.c) is
Copyright © 1994 David Burren. It is licensed under a BSD license.
The implementation of blowfish crypt (src/crypt/crypt_blowfish.c) was
originally written by Solar Designer and placed into the public
domain. The code also comes with a fallback permissive license for use
in jurisdictions that may not recognize the public domain.
The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011
Valentin Ochs and is licensed under an MIT-style license.
The BSD PRNG implementation (src/prng/random.c) and XSI search API
(src/search/ *.c) functions are Copyright © 2011 Szabolcs Nagy and
licensed under following terms: "Permission to use, copy, modify,
and/or distribute this code for any purpose with or without fee is
hereby granted. There is no warranty."
The x86_64 port was written by Nicholas J. Kain and is licensed under
the standard MIT terms.
The mips and microblaze ports were originally written by Richard
Pennington for use in the ellcc project. The original code was adapted
by Rich Felker for build system and code conventions during upstream
integration. It is licensed under the standard MIT terms.
The mips64 port was contributed by Imagination Technologies and is
licensed under the standard MIT terms.
The powerpc port was also originally written by Richard Pennington,
and later supplemented and integrated by John Spencer. It is licensed
under the standard MIT terms.
All other files which have no copyright comments are original works
produced specifically for use as part of this library, written either
by Rich Felker, the main author of the library, or by one or more
contibutors listed above. Details on authorship of individual files
can be found in the git version control history of the project. The
omission of copyright and license comments in each file is in the
interest of source tree size.
In addition, permission is hereby granted for all public header files
(include/ * and arch/ * /bits/ *) and crt files intended to be linked into
applications (crt/ *, ldso/dlstart.c, and arch/ * /crt_arch.h) to omit
the copyright notice and permission notice otherwise required by the
license, and to use these files without any requirement of
attribution. These files include substantial contributions from:
Bobby Bingham
John Spencer
Nicholas J. Kain
Rich Felker
Richard Pennington
Stefan Kristiansson
Szabolcs Nagy
all of whom have explicitly granted such permission.
This file previously contained text expressing a belief that most of
the files covered by the above exception were sufficiently trivial not
to be subject to copyright, resulting in confusion over whether it
negated the permissions granted in the license. In the spirit of
permissive licensing, and of not having licensing issues being an
obstacle to adoption, that text has been removed.
*/
#include <cmath>

View File

@ -3,9 +3,9 @@
/** exp10 from GNU libm fails to give precise result for integer arguments.
* For example, exp10(3) gives 1000.0000000000001
* despite the fact that 1000 is exactly representable in double and float.
* Better to always use implementation from MUSL.
* Better to always use our own implementation based on a MUSL's one.
*
* Note: the function names are different to avoid confusion with symbols from the system libm.
* Note: the function name is different to avoid confusion with symbols from the system libm.
*/
double preciseExp10(double x);

View File

@ -13,11 +13,7 @@ using char8_t = unsigned char;
#endif
/// 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;
#else
using UInt8 = uint8_t;
#endif
using UInt16 = uint16_t;
using UInt32 = uint32_t;

View File

@ -360,7 +360,7 @@ struct integer<Bits, Signed>::_impl
constexpr const unsigned to_copy = min_bits / base_bits;
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)
{

View File

@ -78,9 +78,6 @@
*
*/
// Disable warnings by PVS-Studio
//-V::GA
static const double
pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */

View File

@ -85,9 +85,6 @@
*
*/
// Disable warnings by PVS-Studio
//-V::GA
#include <stdint.h>
#include <math.h>
#include "libm.h"

View File

@ -155,7 +155,7 @@ static inline long double fp_barrierl(long double x)
static inline void fp_force_evalf(float x)
{
volatile float y;
y = x; //-V1001
y = x;
}
#endif
@ -164,7 +164,7 @@ static inline void fp_force_evalf(float x)
static inline void fp_force_eval(double x)
{
volatile double y;
y = x; //-V1001
y = x;
}
#endif
@ -173,7 +173,7 @@ static inline void fp_force_eval(double x)
static inline void fp_force_evall(long double x)
{
volatile long double y;
y = x; //-V1001
y = x;
}
#endif

View File

@ -3,9 +3,6 @@
* SPDX-License-Identifier: MIT
*/
// Disable warnings by PVS-Studio
//-V::GA
#include <math.h>
#include <stdint.h>
#include "libm.h"

View File

@ -1,2 +1,6 @@
if (USE_CLANG_TIDY)
set (CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_PATH}")
endif ()
add_library(pcg_random INTERFACE)
target_include_directories(pcg_random INTERFACE .)

View File

@ -455,7 +455,7 @@ auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)
typedef typename RngType::result_type rtype;
rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
% upper_bound;
for (;;) { //-V1044
for (;;) {
rtype r = rng() - RngType::min();
if (r >= threshold)
return r % upper_bound;

View File

@ -930,7 +930,7 @@ struct rxs_m_xs_mixin {
constexpr bitcount_t shift = bits - xtypebits;
constexpr bitcount_t mask = (1 << opbits) - 1;
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 *= mcg_multiplier<itype>::multiplier();
xtype result = internal >> shift;
@ -952,7 +952,7 @@ struct rxs_m_xs_mixin {
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);
return internal;
@ -977,7 +977,7 @@ struct rxs_m_mixin {
: 2;
constexpr bitcount_t shift = bits - xtypebits;
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 *= mcg_multiplier<itype>::multiplier();
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
// were to backstep the generator so that the base generator
// 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) {
data_[i] = baseclass::operator()() ^ xdiff;
}

View File

@ -1,5 +1,3 @@
set (LIBRARY_DIR "${ClickHouse_SOURCE_DIR}/contrib/poco")
add_subdirectory (Crypto)
add_subdirectory (Data)
add_subdirectory (Data/ODBC)
@ -7,7 +5,7 @@ add_subdirectory (Foundation)
add_subdirectory (JSON)
add_subdirectory (MongoDB)
add_subdirectory (Net)
add_subdirectory (Net/SSL)
add_subdirectory (NetSSL_OpenSSL)
add_subdirectory (Redis)
add_subdirectory (Util)
add_subdirectory (XML)

View File

@ -0,0 +1,35 @@
if (ENABLE_SSL)
file (GLOB SRCS src/*.cpp)
add_library (_poco_crypto ${SRCS})
add_library (Poco::Crypto ALIAS _poco_crypto)
# TODO: remove these warning exclusions
target_compile_options (_poco_crypto
PRIVATE
-Wno-covered-switch-default
-Wno-deprecated-dynamic-exception-spec
-Wno-extra-semi-stmt
-Wno-missing-noreturn
-Wno-newline-eof
-Wno-old-style-cast
-Wno-shadow
-Wno-shorten-64-to-32
-Wno-sign-compare
-Wno-suggest-destructor-override
-Wno-suggest-override
-Wno-unreachable-code-return
-Wno-unused-parameter
-Wno-zero-as-null-pointer-constant
-Wno-used-but-marked-unused
)
target_include_directories (_poco_crypto SYSTEM PUBLIC "include")
target_link_libraries (_poco_crypto PUBLIC Poco::Foundation OpenSSL::SSL OpenSSL::Crypto)
message (STATUS "Using Poco::Crypto")
else ()
add_library (_poco_crypto INTERFACE)
add_library (Poco::Crypto ALIAS _poco_crypto)
message (STATUS "Not using Poco::Crypto")
endif ()

View File

@ -0,0 +1,141 @@
//
// Cipher.h
//
// Library: Crypto
// Package: Cipher
// Module: Cipher
//
// Definition of the Cipher class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_Cipher_INCLUDED
#define Crypto_Cipher_INCLUDED
#include <istream>
#include <ostream>
#include <vector>
#include "Poco/AutoPtr.h"
#include "Poco/Crypto/Crypto.h"
#include "Poco/RefCountedObject.h"
namespace Poco
{
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
#endif // Crypto_Cipher_INCLUDED

View File

@ -0,0 +1,78 @@
//
// CipherFactory.h
//
// Library: Crypto
// Package: Cipher
// Module: CipherFactory
//
// Definition of the CipherFactory class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CipherFactory_INCLUDED
#define Crypto_CipherFactory_INCLUDED
#include "Poco/Crypto/Crypto.h"
namespace Poco
{
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
#endif // Crypto_CipherFactory_INCLUDED

View File

@ -0,0 +1,72 @@
//
// CipherImpl.h
//
// Library: Crypto
// Package: Cipher
// Module: CipherImpl
//
// Definition of the CipherImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CipherImpl_INCLUDED
#define Crypto_CipherImpl_INCLUDED
#include <openssl/evp.h>
#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CipherKey.h"
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
namespace Poco
{
namespace Crypto
{
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
#endif // Crypto_CipherImpl_INCLUDED

View File

@ -0,0 +1,203 @@
//
// CipherKey.h
//
// Library: Crypto
// Package: Cipher
// Module: CipherKey
//
// Definition of the CipherKey class.
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CipherKey_INCLUDED
#define Crypto_CipherKey_INCLUDED
#include "Poco/Crypto/CipherKeyImpl.h"
#include "Poco/Crypto/Crypto.h"
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:
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
#endif // Crypto_CipherKey_INCLUDED

View File

@ -0,0 +1,168 @@
//
// CipherKeyImpl.h
//
// Library: Crypto
// Package: Cipher
// Module: CipherKeyImpl
//
// Definition of the CipherKeyImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CipherKeyImpl_INCLUDED
#define Crypto_CipherKeyImpl_INCLUDED
#include <vector>
#include "Poco/AutoPtr.h"
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/RefCountedObject.h"
struct evp_cipher_st;
typedef struct evp_cipher_st EVP_CIPHER;
namespace Poco
{
namespace Crypto
{
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
#endif // Crypto_CipherKeyImpl_INCLUDED

View File

@ -0,0 +1,116 @@
//
// Crypto.h
//
// Library: Crypto
// Package: CryptoCore
// Module: Crypto
//
// Basic definitions for the Poco Crypto library.
// This file must be the first file included by every other Crypto
// header file.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_Crypto_INCLUDED
#define Crypto_Crypto_INCLUDED
#define POCO_EXTERNAL_OPENSSL_DEFAULT 1
#define POCO_EXTERNAL_OPENSSL_SLPRO 2
#include <openssl/opensslv.h>
#include "Poco/Foundation.h"
#ifndef OPENSSL_VERSION_PREREQ
# if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR)
# define OPENSSL_VERSION_PREREQ(maj, min) ((OPENSSL_VERSION_MAJOR << 16) + OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
# else
# define OPENSSL_VERSION_PREREQ(maj, min) (OPENSSL_VERSION_NUMBER >= (((maj) << 28) | ((min) << 20)))
# endif
#endif
enum RSAPaddingMode
/// The padding mode used for RSA public key encryption.
{
RSA_PADDING_PKCS1,
/// PKCS #1 v1.5 padding. This currently is the most widely used mode.
RSA_PADDING_PKCS1_OAEP,
/// 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.
RSA_PADDING_SSLV23,
/// PKCS #1 v1.5 padding with an SSL-specific modification that denotes
/// that the server is SSL3 capable.
RSA_PADDING_NONE
/// 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
/// is insecure.
};
//
// The following block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the Crypto_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// Crypto_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
//
#if !defined(Crypto_API)
# if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined(__GNUC__) && (__GNUC__ >= 4)
# define Crypto_API __attribute__((visibility("default")))
# else
# define Crypto_API
# endif
#endif
//
// Automatically link Crypto and OpenSSL libraries.
//
namespace Poco
{
namespace Crypto
{
void Crypto_API initializeCrypto();
/// Initialize the Crypto library, as well as the underlying OpenSSL
/// libraries, by calling OpenSSLInitializer::initialize().
///
/// Should be called before using any class from the Crypto library.
/// The Crypto library will be initialized automatically, through
/// OpenSSLInitializer instances held by various Crypto classes
/// (Cipher, CipherKey, RSAKey, X509Certificate).
/// However, it is recommended to call initializeCrypto()
/// in any case at application startup.
///
/// Can be called multiple times; however, for every call to
/// initializeCrypto(), a matching call to uninitializeCrypto()
/// must be performed.
void Crypto_API uninitializeCrypto();
/// Uninitializes the Crypto library by calling
/// OpenSSLInitializer::uninitialize().
}
} // namespace Poco::Crypto
#endif // Crypto_Crypto_INCLUDED

View File

@ -0,0 +1,59 @@
//
// CryptoException.h
//
//
// Library: Crypto
// Package: Crypto
// Module: CryptoException
//
// Definition of the CryptoException class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CryptoException_INCLUDED
#define Crypto_CryptoException_INCLUDED
#include "Poco/Crypto/Crypto.h"
#include "Poco/Exception.h"
namespace Poco
{
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
#endif // Crypto_CryptoException_INCLUDED

View File

@ -0,0 +1,195 @@
//
// CryptoStream.h
//
// Library: Crypto
// Package: Cipher
// Module: CryptoStream
//
// Definition of the CryptoStreamBuf, CryptoInputStream and CryptoOutputStream
// classes.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CryptoStream_INCLUDED
#define Crypto_CryptoStream_INCLUDED
#include <iostream>
#include "Poco/Buffer.h"
#include "Poco/BufferedStreamBuf.h"
#include "Poco/Crypto/Crypto.h"
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:
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
/// This stream transforms all data passing through it using the given
/// 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
/// This stream transforms all data passing through it using the given
/// CryptoTransform.
///
/// Use a CryptoTransform object provided by Cipher::createEncrytor() or
/// Cipher::createDecryptor() to create an encrypting or decrypting stream,
/// 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.
CryptoOutputStream(std::ostream & ostr, Cipher & cipher, std::streamsize bufferSize = 8192);
/// 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 DecryptingInputStream : public CryptoIOS, public std::istream
/// This stream decrypts all data passing through it using the given
/// Cipher.
{
public:
DecryptingInputStream(std::istream & istr, Cipher & cipher, std::streamsize bufferSize = 8192);
/// Create a new DecryptingInputStream object using the given cipher.
~DecryptingInputStream();
/// Destroys the DecryptingInputStream.
};
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

View File

@ -0,0 +1,88 @@
//
// CryptoTransform.h
//
// Library: Crypto
// Package: Cipher
// Module: CryptoTransform
//
// Definition of the CryptoTransform class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_CryptoTransform_INCLUDED
#define Crypto_CryptoTransform_INCLUDED
#include <ios>
#include "Poco/Crypto/Crypto.h"
namespace Poco
{
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
#endif // Crypto_CryptoTransform_INCLUDED

View File

@ -0,0 +1,83 @@
//
// DigestEngine.h
//
// Library: Crypto
// Package: Digest
// Module: DigestEngine
//
// Definition of the DigestEngine class.
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_DigestEngine_INCLUDED
#define Crypto_DigestEngine_INCLUDED
#include <openssl/evp.h>
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/DigestEngine.h"
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:
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
#endif // Crypto_DigestEngine_INCLUDED

View File

@ -0,0 +1,103 @@
//
// ECDSADigestEngine.h
//
//
// Library: Crypto
// Package: ECDSA
// Module: ECDSADigestEngine
//
// Definition of the ECDSADigestEngine class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_ECDSADigestEngine_INCLUDED
#define Crypto_ECDSADigestEngine_INCLUDED
#include <istream>
#include <ostream>
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/Crypto/ECKey.h"
#include "Poco/DigestEngine.h"
namespace Poco
{
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
#endif // Crypto_ECDSADigestEngine_INCLUDED

View File

@ -0,0 +1,138 @@
//
// ECKey.h
//
//
// Library: Crypto
// Package: EC
// Module: ECKey
//
// Definition of the ECKey class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_ECKey_INCLUDED
#define Crypto_ECKey_INCLUDED
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/ECKeyImpl.h"
#include "Poco/Crypto/KeyPair.h"
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:
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
#endif // Crypto_ECKey_INCLUDED

View File

@ -0,0 +1,173 @@
//
// ECKeyImpl.h
//
//
// Library: Crypto
// Package: EC
// Module: ECKeyImpl
//
// Definition of the ECKeyImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef 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/EVPPKey.h"
#include "Poco/Crypto/KeyPairImpl.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/RefCountedObject.h"
namespace Poco
{
namespace Crypto
{
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.
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;
}
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

View File

@ -0,0 +1,369 @@
//
// EVPPKey.h
//
//
// Library: Crypto
// Package: CryptoCore
// Module: EVPPKey
//
// Definition of the EVPPKey class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef 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/CryptoException.h"
#include "Poco/StreamCopier.h"
namespace Poco
{
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);
/// Constructs EVPPKey from EVP_PKEY pointer.
/// 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 = "");
/// 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
EVPPKey(EVPPKey && other);
/// Move constructor.
EVPPKey & operator=(EVPPKey && other);
/// Assignment move operator.
#endif // POCO_ENABLE_CPP11
~EVPPKey();
/// Destroys the EVPPKey.
bool operator==(const EVPPKey & other) const;
/// Comparison operator.
/// Returns true if public key components and parameters
/// of the other key are equal to this key.
///
/// Works as expected when one key contains only public key,
/// while the other one contains private (thus also public) key.
bool operator!=(const EVPPKey & other) const;
/// Comparison operator.
/// Returns true if public key components and parameters
/// of the other key are different from this key.
///
/// Works as expected when one key contains only 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;
/// Exports the public and/or 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/or private key to the given streams.
///
/// If a null pointer is passed for a stream, the corresponding
/// key is not exported.
int type() const;
/// Returns the EVPPKey type NID.
bool isSupported(int type) const;
/// Returns true if OpenSSL type is supported
operator const EVP_PKEY *() const;
/// Returns const pointer to the OpenSSL EVP_PKEY structure.
operator EVP_PKEY *();
/// Returns pointer to the OpenSSL EVP_PKEY structure.
static EVP_PKEY * duplicate(const EVP_PKEY * pFromKey, EVP_PKEY ** pToKey);
/// Duplicates pFromKey into *pToKey and returns
// the pointer to duplicated EVP_PKEY.
private:
EVPPKey();
static int type(const EVP_PKEY * pEVPPKey);
void newECKey(const char * group);
void duplicate(EVP_PKEY * pEVPPKey);
void setKey(ECKey * pKey);
void setKey(RSAKey * pKey);
void setKey(EC_KEY * pKey);
void setKey(RSA * pKey);
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_BIO_Key_fn)(BIO *, EVP_PKEY **, pem_password_cb *, void *);
typedef void * (*EVP_PKEY_get_Key_fn)(EVP_PKEY *);
// The following load*() functions are used by both native and EVP_PKEY type key
// loading from BIO/FILE.
// When used for EVP key loading, getFunc is null (ie. native key is not extracted
// from the loaded EVP_PKEY).
template <typename K, typename F>
static bool
loadKey(K ** ppKey, PEM_read_FILE_Key_fn readFunc, F getFunc, const std::string & keyFile, const std::string & pass = "")
{
poco_assert_dbg(
((typeid(K *) == typeid(RSA *) || typeid(K *) == typeid(EC_KEY *)) && getFunc)
|| ((typeid(K *) == typeid(EVP_PKEY *)) && !getFunc));
poco_check_ptr(ppKey);
poco_assert_dbg(!*ppKey);
FILE * pFile = 0;
if (!keyFile.empty())
{
if (!getFunc)
*ppKey = (K *)EVP_PKEY_new();
EVP_PKEY * pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY *)*ppKey;
if (pKey)
{
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();
if (readFunc(pFile, &pKey, pCB, pPassword))
{
fclose(pFile);
pFile = 0;
if (getFunc)
{
*ppKey = (K *)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else
{
poco_assert_dbg(typeid(K *) == typeid(EVP_PKEY *));
*ppKey = (K *)pKey;
}
if (!*ppKey)
goto error;
return true;
}
goto error;
}
else
{
if (getFunc)
EVP_PKEY_free(pKey);
throw IOException("ECKeyImpl, cannot open file", keyFile);
}
}
else
goto error;
}
return false;
error:
if (pFile)
fclose(pFile);
throw OpenSSLException("EVPKey::loadKey(string)");
}
template <typename K, typename F>
static bool loadKey(K ** ppKey, PEM_read_BIO_Key_fn readFunc, F getFunc, std::istream * pIstr, const std::string & pass = "")
{
poco_assert_dbg(
((typeid(K *) == typeid(RSA *) || typeid(K *) == typeid(EC_KEY *)) && getFunc)
|| ((typeid(K *) == typeid(EVP_PKEY *)) && !getFunc));
poco_check_ptr(ppKey);
poco_assert_dbg(!*ppKey);
BIO * pBIO = 0;
if (pIstr)
{
std::ostringstream ostr;
Poco::StreamCopier::copyStream(*pIstr, ostr);
std::string key = ostr.str();
pBIO = BIO_new_mem_buf(const_cast<char *>(key.data()), static_cast<int>(key.size()));
if (pBIO)
{
if (!getFunc)
*ppKey = (K *)EVP_PKEY_new();
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();
if (readFunc(pBIO, &pKey, pCB, pPassword))
{
BIO_free(pBIO);
pBIO = 0;
if (getFunc)
{
*ppKey = (K *)getFunc(pKey);
EVP_PKEY_free(pKey);
}
else
{
poco_assert_dbg(typeid(K *) == typeid(EVP_PKEY *));
*ppKey = (K *)pKey;
}
if (!*ppKey)
goto error;
return true;
}
if (getFunc)
EVP_PKEY_free(pKey);
goto error;
}
else
goto error;
}
else
goto error;
}
return false;
error:
if (pBIO)
BIO_free(pBIO);
throw OpenSSLException("EVPKey::loadKey(stream)");
}
EVP_PKEY * _pEVPPKey;
friend class ECKeyImpl;
friend class RSAKeyImpl;
};
//
// 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();
}
}
} // namespace Poco::Crypto
#endif // Crypto_EVPPKeyImpl_INCLUDED

View File

@ -0,0 +1,136 @@
//
// KeyPair.h
//
//
// Library: Crypto
// Package: CryptoCore
// Module: KeyPair
//
// Definition of the KeyPair class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_KeyPair_INCLUDED
#define Crypto_KeyPair_INCLUDED
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/KeyPairImpl.h"
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:
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();
}
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

View File

@ -0,0 +1,110 @@
//
// KeyPairImpl.h
//
//
// Library: Crypto
// Package: CryptoCore
// Module: KeyPairImpl
//
// Definition of the KeyPairImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_KeyPairImplImpl_INCLUDED
#define Crypto_KeyPairImplImpl_INCLUDED
#include <string>
#include <vector>
#include "Poco/AutoPtr.h"
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/RefCountedObject.h"
namespace Poco
{
namespace Crypto
{
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.
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;
}
inline KeyPairImpl::Type KeyPairImpl::type() const
{
return _type;
}
}
} // namespace Poco::Crypto
#endif // Crypto_KeyPairImplImpl_INCLUDED

View File

@ -0,0 +1,117 @@
//
// OpenSSLInitializer.h
//
// Library: Crypto
// Package: CryptoCore
// Module: OpenSSLInitializer
//
// Definition of the OpenSSLInitializer class.
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_OpenSSLInitializer_INCLUDED
#define Crypto_OpenSSLInitializer_INCLUDED
#include <openssl/crypto.h>
#include "Poco/AtomicCounter.h"
#include "Poco/Crypto/Crypto.h"
#include "Poco/Mutex.h"
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_NUMBER < 0x010001000L
# include <openssl/fips.h>
#endif
extern "C" {
struct CRYPTO_dynlock_value
{
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;
};
//
// inlines
//
inline bool OpenSSLInitializer::isFIPSEnabled()
{
#ifdef OPENSSL_FIPS
return FIPS_mode() ? true : false;
#else
return false;
#endif
}
#ifdef OPENSSL_FIPS
inline void OpenSSLInitializer::enableFIPSMode(bool enabled)
{
FIPS_mode_set(enabled);
}
#else
inline void OpenSSLInitializer::enableFIPSMode(bool /*enabled*/)
{
}
#endif
}
} // namespace Poco::Crypto
#endif // Crypto_OpenSSLInitializer_INCLUDED

View File

@ -0,0 +1,162 @@
//
// PKCS12Container.h
//
// Library: Crypto
// Package: Certificate
// Module: PKCS12Container
//
// Definition of the PKCS12Container class.
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_PKCS12Container_INCLUDED
#define Crypto_PKCS12Container_INCLUDED
#include <istream>
#include <memory>
#include <openssl/pkcs12.h>
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/EVPPKey.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Path.h"
namespace Poco
{
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 = "");
/// Creates the PKCS12Container object from a file.
PKCS12Container(const PKCS12Container & cont);
/// Copy constructor.
PKCS12Container & operator=(const PKCS12Container & cont);
/// Assignment operator.
#ifdef POCO_ENABLE_CPP11
PKCS12Container(PKCS12Container && cont);
/// Move constructor.
PKCS12Container & operator=(PKCS12Container && cont);
/// Move assignment operator.
#endif // POCO_ENABLE_CPP11
~PKCS12Container();
/// Destroys the PKCS12Container.
bool hasKey() const;
/// Returns true if container contains the key.
EVPPKey getKey() const;
/// Return key as openssl EVP_PKEY wrapper object.
bool hasX509Certificate() const;
/// Returns true if container has X509 certificate.
const X509Certificate & getX509Certificate() const;
/// Returns the X509 certificate.
/// Throws NotFoundException if there is no certificate.
const CAList & getCACerts() const;
/// Returns the list of CA certificates in this container.
const std::string & getFriendlyName() const;
/// Returns the friendly name of the certificate bag.
const CANameList & getFriendlyNamesCA() const;
/// Returns a list of CA certificates friendly names.
private:
void load(PKCS12 * pPKCS12, const std::string & password = "");
std::string extractFriendlyName(X509 * pCert);
#ifdef POCO_ENABLE_CPP11
typedef std::unique_ptr<X509Certificate> CertPtr;
#else
typedef std::auto_ptr<X509Certificate> CertPtr;
#endif // #ifdef POCO_ENABLE_CPP11
OpenSSLInitializer _openSSLInitializer;
EVP_PKEY * _pKey;
CertPtr _pX509Cert;
CAList _caCertList;
CANameList _caCertNames;
std::string _pkcsFriendlyName;
};
//
// 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);
}
}
} // namespace Poco::Crypto
#endif // Crypto_PKCS12Container_INCLUDED

View File

@ -0,0 +1,80 @@
//
// RSACipherImpl.h
//
// Library: Crypto
// Package: RSA
// Module: RSACipherImpl
//
// Definition of the RSACipherImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_RSACipherImpl_INCLUDED
#define Crypto_RSACipherImpl_INCLUDED
#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 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:
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
#endif // Crypto_RSACipherImpl_INCLUDED

View File

@ -0,0 +1,114 @@
//
// RSADigestEngine.h
//
// Library: Crypto
// Package: RSA
// Module: RSADigestEngine
//
// Definition of the RSADigestEngine class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_RSADigestEngine_INCLUDED
#define Crypto_RSADigestEngine_INCLUDED
#include <istream>
#include <ostream>
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/DigestEngine.h"
namespace Poco
{
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
#endif // Crypto_RSADigestEngine_INCLUDED

View File

@ -0,0 +1,124 @@
//
// RSAKey.h
//
// Library: Crypto
// Package: RSA
// Module: RSAKey
//
// Definition of the RSAKey class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Crypto_RSAKey_INCLUDED
#define Crypto_RSAKey_INCLUDED
#include "Poco/Crypto/Crypto.h"
#include "Poco/Crypto/KeyPair.h"
#include "Poco/Crypto/RSAKeyImpl.h"
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:
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
#endif // Crypto_RSAKey_INCLUDED

View File

@ -0,0 +1,142 @@
//
// RSAKeyImpl.h
//
// Library: Crypto
// Package: RSA
// Module: RSAKeyImpl
//
// Definition of the RSAKeyImpl class.
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef 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/EVPPKey.h"
#include "Poco/Crypto/KeyPairImpl.h"
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/RefCountedObject.h"
struct bignum_st;
struct rsa_st;
typedef struct bignum_st BIGNUM;
typedef struct rsa_st RSA;
namespace Poco
{
namespace Crypto
{
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.
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;
}
inline const RSA * RSAKeyImpl::getRSA() const
{
return _pRSA;
}
}
} // namespace Poco::Crypto
#endif // Crypto_RSAKeyImplImpl_INCLUDED

View File

@ -0,0 +1,248 @@
//
// X509Certificate.h
//
// Library: Crypto
// Package: Certificate
// Module: X509Certificate
//
// Definition of the X509Certificate class.
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef 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/OpenSSLInitializer.h"
#include "Poco/DateTime.h"
#include "Poco/SharedPtr.h"
namespace Poco
{
namespace Crypto
{
class Crypto_API X509Certificate
/// 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
#endif // Crypto_X509Certificate_INCLUDED

View File

@ -0,0 +1,140 @@
//
// Cipher.cpp
//
// Library: Crypto
// Package: Cipher
// Module: Cipher
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CryptoStream.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/HexBinaryEncoder.h"
#include "Poco/HexBinaryDecoder.h"
#include "Poco/StreamCopier.h"
#include "Poco/Exception.h"
#include <sstream>
#include <memory>
namespace Poco {
namespace Crypto {
Cipher::Cipher()
{
}
Cipher::~Cipher()
{
}
std::string Cipher::encryptString(const std::string& str, Encoding encoding)
{
std::istringstream source(str);
std::ostringstream sink;
encrypt(source, sink, encoding);
return sink.str();
}
std::string Cipher::decryptString(const std::string& str, Encoding encoding)
{
std::istringstream source(str);
std::ostringstream sink;
decrypt(source, sink, encoding);
return sink.str();
}
void Cipher::encrypt(std::istream& source, std::ostream& sink, Encoding encoding)
{
CryptoInputStream encryptor(source, createEncryptor());
switch (encoding)
{
case ENC_NONE:
StreamCopier::copyStream(encryptor, sink);
break;
case ENC_BASE64:
case ENC_BASE64_NO_LF:
{
Poco::Base64Encoder encoder(sink);
if (encoding == ENC_BASE64_NO_LF)
{
encoder.rdbuf()->setLineLength(0);
}
StreamCopier::copyStream(encryptor, encoder);
encoder.close();
}
break;
case ENC_BINHEX:
case ENC_BINHEX_NO_LF:
{
Poco::HexBinaryEncoder encoder(sink);
if (encoding == ENC_BINHEX_NO_LF)
{
encoder.rdbuf()->setLineLength(0);
}
StreamCopier::copyStream(encryptor, encoder);
encoder.close();
}
break;
default:
throw Poco::InvalidArgumentException("Invalid argument", "encoding");
}
}
void Cipher::decrypt(std::istream& source, std::ostream& sink, Encoding encoding)
{
CryptoOutputStream decryptor(sink, createDecryptor());
switch (encoding)
{
case ENC_NONE:
StreamCopier::copyStream(source, decryptor);
decryptor.close();
break;
case ENC_BASE64:
case ENC_BASE64_NO_LF:
{
Poco::Base64Decoder decoder(source);
StreamCopier::copyStream(decoder, decryptor);
decryptor.close();
}
break;
case ENC_BINHEX:
case ENC_BINHEX_NO_LF:
{
Poco::HexBinaryDecoder decoder(source);
StreamCopier::copyStream(decoder, decryptor);
decryptor.close();
}
break;
default:
throw Poco::InvalidArgumentException("Invalid argument", "encoding");
}
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,65 @@
//
// CipherFactory.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CipherFactory
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Crypto/Cipher.h"
#include "Poco/Crypto/CipherKey.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/Crypto/CipherImpl.h"
#include "Poco/Crypto/RSACipherImpl.h"
#include "Poco/Exception.h"
#include "Poco/SingletonHolder.h"
#include <openssl/evp.h>
#include <openssl/err.h>
namespace Poco {
namespace Crypto {
CipherFactory::CipherFactory()
{
}
CipherFactory::~CipherFactory()
{
}
namespace
{
static Poco::SingletonHolder<CipherFactory> holder;
}
CipherFactory& CipherFactory::defaultFactory()
{
return *holder.get();
}
Cipher* CipherFactory::createCipher(const CipherKey& key)
{
return new CipherImpl(key);
}
Cipher* CipherFactory::createCipher(const RSAKey& key, RSAPaddingMode paddingMode)
{
return new RSACipherImpl(key, paddingMode);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,272 @@
//
// CipherImpl.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CipherImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CipherImpl.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Exception.h"
#include "Poco/Buffer.h"
#include <openssl/err.h>
namespace Poco {
namespace Crypto {
namespace
{
void throwError()
{
unsigned long err;
std::string msg;
while ((err = ERR_get_error()))
{
if (!msg.empty())
msg.append("; ");
msg.append(ERR_error_string(err, 0));
}
throw Poco::IOException(msg);
}
class CryptoTransformImpl: public CryptoTransform
{
public:
typedef Cipher::ByteVec ByteVec;
enum Direction
{
DIR_ENCRYPT,
DIR_DECRYPT
};
CryptoTransformImpl(
const EVP_CIPHER* pCipher,
const ByteVec& key,
const ByteVec& iv,
Direction dir);
~CryptoTransformImpl();
std::size_t blockSize() const;
int setPadding(int padding);
std::string getTag(std::size_t tagSize);
void setTag(const std::string& tag);
std::streamsize transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength);
std::streamsize finalize(
unsigned char* output,
std::streamsize length);
private:
const EVP_CIPHER* _pCipher;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
EVP_CIPHER_CTX* _pContext;
#else
EVP_CIPHER_CTX _context;
#endif
ByteVec _key;
ByteVec _iv;
};
CryptoTransformImpl::CryptoTransformImpl(
const EVP_CIPHER* pCipher,
const ByteVec& key,
const ByteVec& iv,
Direction dir):
_pCipher(pCipher),
_key(key),
_iv(iv)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
_pContext = EVP_CIPHER_CTX_new();
EVP_CipherInit(
_pContext,
_pCipher,
&_key[0],
_iv.empty() ? 0 : &_iv[0],
(dir == DIR_ENCRYPT) ? 1 : 0);
#else
EVP_CipherInit(
&_context,
_pCipher,
&_key[0],
_iv.empty() ? 0 : &_iv[0],
(dir == DIR_ENCRYPT) ? 1 : 0);
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
if (_iv.size() != EVP_CIPHER_iv_length(_pCipher) && EVP_CIPHER_mode(_pCipher) == EVP_CIPH_GCM_MODE)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL);
#else
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_IVLEN, _iv.size(), NULL);
#endif
if (rc == 0) throwError();
}
#endif
}
CryptoTransformImpl::~CryptoTransformImpl()
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
EVP_CIPHER_CTX_cleanup(_pContext);
EVP_CIPHER_CTX_free(_pContext);
#else
EVP_CIPHER_CTX_cleanup(&_context);
#endif
}
std::size_t CryptoTransformImpl::blockSize() const
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return EVP_CIPHER_CTX_block_size(_pContext);
#else
return EVP_CIPHER_CTX_block_size(&_context);
#endif
}
int CryptoTransformImpl::setPadding(int padding)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
return EVP_CIPHER_CTX_block_size(_pContext);
#else
return EVP_CIPHER_CTX_set_padding(&_context, padding);
#endif
}
std::string CryptoTransformImpl::getTag(std::size_t tagSize)
{
std::string tag;
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
Poco::Buffer<char> buffer(tagSize);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_GET_TAG, tagSize, buffer.begin());
#else
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_GET_TAG, tagSize, buffer.begin());
#endif
if (rc == 0) throwError();
tag.assign(buffer.begin(), tagSize);
#endif
return tag;
}
void CryptoTransformImpl::setTag(const std::string& tag)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
int rc = EVP_CIPHER_CTX_ctrl(_pContext, EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char*>(tag.data()));
#elif OPENSSL_VERSION_NUMBER >= 0x10001000L
int rc = EVP_CIPHER_CTX_ctrl(&_context, EVP_CTRL_GCM_SET_TAG, tag.size(), const_cast<char*>(tag.data()));
#else
int rc = 0;
#endif
if (rc == 0) throwError();
}
std::streamsize CryptoTransformImpl::transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength)
{
poco_assert (outputLength >= (inputLength + blockSize() - 1));
int outLen = static_cast<int>(outputLength);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
int rc = EVP_CipherUpdate(
_pContext,
output,
&outLen,
input,
static_cast<int>(inputLength));
#else
int rc = EVP_CipherUpdate(
&_context,
output,
&outLen,
input,
static_cast<int>(inputLength));
#endif
if (rc == 0)
throwError();
return static_cast<std::streamsize>(outLen);
}
std::streamsize CryptoTransformImpl::finalize(
unsigned char* output,
std::streamsize length)
{
poco_assert (length >= blockSize());
int len = static_cast<int>(length);
// Use the '_ex' version that does not perform implicit cleanup since we
// will call EVP_CIPHER_CTX_cleanup() from the dtor as there is no
// guarantee that finalize() will be called if an error occurred.
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
int rc = EVP_CipherFinal_ex(_pContext, output, &len);
#else
int rc = EVP_CipherFinal_ex(&_context, output, &len);
#endif
if (rc == 0)
throwError();
return static_cast<std::streamsize>(len);
}
}
CipherImpl::CipherImpl(const CipherKey& key):
_key(key)
{
}
CipherImpl::~CipherImpl()
{
}
CryptoTransform* CipherImpl::createEncryptor()
{
CipherKeyImpl::Ptr p = _key.impl();
return new CryptoTransformImpl(p->cipher(), p->getKey(), p->getIV(), CryptoTransformImpl::DIR_ENCRYPT);
}
CryptoTransform* CipherImpl::createDecryptor()
{
CipherKeyImpl::Ptr p = _key.impl();
return new CryptoTransformImpl(p->cipher(), p->getKey(), p->getIV(), CryptoTransformImpl::DIR_DECRYPT);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,49 @@
//
// CipherKey.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CipherKey
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CipherKey.h"
namespace Poco {
namespace Crypto {
CipherKey::CipherKey(const std::string& name,
const std::string& passphrase,
const std::string& salt,
int iterationCount,
const std::string &digest):
_pImpl(new CipherKeyImpl(name, passphrase, salt, iterationCount, digest))
{
}
CipherKey::CipherKey(const std::string& name, const ByteVec& key, const ByteVec& iv):
_pImpl(new CipherKeyImpl(name, key, iv))
{
}
CipherKey::CipherKey(const std::string& name):
_pImpl(new CipherKeyImpl(name))
{
}
CipherKey::~CipherKey()
{
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,222 @@
//
// CipherKeyImpl.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CipherKeyImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CipherKeyImpl.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Crypto/CipherFactory.h"
#include "Poco/Exception.h"
#include "Poco/RandomStream.h"
#include <openssl/err.h>
#include <openssl/evp.h>
namespace Poco {
namespace Crypto {
CipherKeyImpl::CipherKeyImpl(const std::string& name,
const std::string& passphrase,
const std::string& salt,
int iterationCount,
const std::string& digest):
_pCipher(0),
_pDigest(0),
_name(name),
_key(),
_iv()
{
// dummy access to Cipherfactory so that the EVP lib is initilaized
CipherFactory::defaultFactory();
_pCipher = EVP_get_cipherbyname(name.c_str());
if (!_pCipher)
throw Poco::NotFoundException("Cipher " + name + " was not found");
_pDigest = EVP_get_digestbyname(digest.c_str());
if (!_pDigest)
throw Poco::NotFoundException("Digest " + name + " was not found");
_key = ByteVec(keySize());
_iv = ByteVec(ivSize());
generateKey(passphrase, salt, iterationCount);
}
CipherKeyImpl::CipherKeyImpl(const std::string& name,
const ByteVec& key,
const ByteVec& iv):
_pCipher(0),
_pDigest(0),
_name(name),
_key(key),
_iv(iv)
{
// dummy access to Cipherfactory so that the EVP lib is initialized
CipherFactory::defaultFactory();
_pCipher = EVP_get_cipherbyname(name.c_str());
if (!_pCipher)
throw Poco::NotFoundException("Cipher " + name + " was not found");
}
CipherKeyImpl::CipherKeyImpl(const std::string& name):
_pCipher(0),
_pDigest(0),
_name(name),
_key(),
_iv()
{
// dummy access to Cipherfactory so that the EVP lib is initilaized
CipherFactory::defaultFactory();
_pCipher = EVP_get_cipherbyname(name.c_str());
if (!_pCipher)
throw Poco::NotFoundException("Cipher " + name + " was not found");
_key = ByteVec(keySize());
_iv = ByteVec(ivSize());
generateKey();
}
CipherKeyImpl::~CipherKeyImpl()
{
}
CipherKeyImpl::Mode CipherKeyImpl::mode() const
{
switch (EVP_CIPHER_mode(_pCipher))
{
case EVP_CIPH_STREAM_CIPHER:
return MODE_STREAM_CIPHER;
case EVP_CIPH_ECB_MODE:
return MODE_ECB;
case EVP_CIPH_CBC_MODE:
return MODE_CBC;
case EVP_CIPH_CFB_MODE:
return MODE_CFB;
case EVP_CIPH_OFB_MODE:
return MODE_OFB;
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
case EVP_CIPH_CTR_MODE:
return MODE_CTR;
case EVP_CIPH_GCM_MODE:
return MODE_GCM;
#endif
}
throw Poco::IllegalStateException("Unexpected value of EVP_CIPHER_mode()");
}
void CipherKeyImpl::generateKey()
{
ByteVec vec;
getRandomBytes(vec, keySize());
setKey(vec);
getRandomBytes(vec, ivSize());
setIV(vec);
}
void CipherKeyImpl::getRandomBytes(ByteVec& vec, std::size_t count)
{
Poco::RandomInputStream random;
vec.clear();
vec.reserve(count);
for (int i = 0; i < count; ++i)
vec.push_back(static_cast<unsigned char>(random.get()));
}
void CipherKeyImpl::generateKey(
const std::string& password,
const std::string& salt,
int iterationCount)
{
unsigned char keyBytes[EVP_MAX_KEY_LENGTH];
unsigned char ivBytes[EVP_MAX_IV_LENGTH];
// OpenSSL documentation specifies that the salt must be an 8-byte array.
unsigned char saltBytes[8];
if (!salt.empty())
{
int len = static_cast<int>(salt.size());
// Create the salt array from the salt string
for (int i = 0; i < 8; ++i)
saltBytes[i] = salt.at(i % len);
for (int i = 8; i < len; ++i)
saltBytes[i % 8] ^= salt.at(i);
}
// Now create the key and IV, using the MD5 digest algorithm.
int keySize = EVP_BytesToKey(
_pCipher,
_pDigest ? _pDigest : EVP_md5(),
(salt.empty() ? 0 : saltBytes),
reinterpret_cast<const unsigned char*>(password.data()),
static_cast<int>(password.size()),
iterationCount,
keyBytes,
ivBytes);
// Copy the buffers to our member byte vectors.
_key.assign(keyBytes, keyBytes + keySize);
if (ivSize() == 0)
_iv.clear();
else
_iv.assign(ivBytes, ivBytes + ivSize());
}
int CipherKeyImpl::keySize() const
{
return EVP_CIPHER_key_length(_pCipher);
}
int CipherKeyImpl::blockSize() const
{
return EVP_CIPHER_block_size(_pCipher);
}
int CipherKeyImpl::ivSize() const
{
return EVP_CIPHER_iv_length(_pCipher);
}
void CipherKeyImpl::setIV(const ByteVec& iv)
{
poco_assert(mode() == MODE_GCM || iv.size() == static_cast<ByteVec::size_type>(ivSize()));
_iv = iv;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,108 @@
//
// CryptoException.cpp
//
//
// Library: Crypto
// Package: Crypto
// Module: CryptoException
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CryptoException.h"
#include "Poco/NumberFormatter.h"
#include <typeinfo>
#include <openssl/err.h>
namespace Poco {
namespace Crypto {
POCO_IMPLEMENT_EXCEPTION(CryptoException, Exception, "Crypto Exception")
OpenSSLException::OpenSSLException(int otherCode): CryptoException(otherCode)
{
setExtMessage();
}
OpenSSLException::OpenSSLException(const std::string& msg, int otherCode): CryptoException(msg, otherCode)
{
setExtMessage();
}
OpenSSLException::OpenSSLException(const std::string& msg, const std::string& arg, int otherCode): CryptoException(msg, arg, otherCode)
{
setExtMessage();
}
OpenSSLException::OpenSSLException(const std::string& msg, const Poco::Exception& exc, int otherCode): CryptoException(msg, exc, otherCode)
{
setExtMessage();
}
OpenSSLException::OpenSSLException(const OpenSSLException& exc): CryptoException(exc)
{
setExtMessage();
}
OpenSSLException::~OpenSSLException() throw()
{
}
OpenSSLException& OpenSSLException::operator = (const OpenSSLException& exc)
{
CryptoException::operator = (exc);
return *this;
}
const char* OpenSSLException::name() const throw()
{
return "OpenSSLException";
}
const char* OpenSSLException::className() const throw()
{
return typeid(*this).name();
}
Poco::Exception* OpenSSLException::clone() const
{
return new OpenSSLException(*this);
}
void OpenSSLException::setExtMessage()
{
Poco::UInt64 e = static_cast<Poco::UInt64>(ERR_get_error());
char buf[128] = { 0 };
char* pErr = ERR_error_string(static_cast<unsigned long>(e), buf);
std::string err;
if (pErr) err = pErr;
else err = NumberFormatter::format(e);
extendedMessage(err);
}
void OpenSSLException::rethrow() const
{
throw *this;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,355 @@
//
// CryptoStream.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CryptoStream
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CryptoStream.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Crypto/Cipher.h"
#include "Poco/Exception.h"
#include <algorithm>
#undef min
#undef max
namespace Poco {
namespace Crypto {
//
// CryptoStreamBuf
//
CryptoStreamBuf::CryptoStreamBuf(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
Poco::BufferedStreamBuf(bufferSize, std::ios::in),
_pTransform(pTransform),
_pIstr(&istr),
_pOstr(0),
_eof(false),
_buffer(static_cast<std::size_t>(bufferSize))
{
poco_check_ptr (pTransform);
poco_assert (bufferSize > 2 * pTransform->blockSize());
}
CryptoStreamBuf::CryptoStreamBuf(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
Poco::BufferedStreamBuf(bufferSize, std::ios::out),
_pTransform(pTransform),
_pIstr(0),
_pOstr(&ostr),
_eof(false),
_buffer(static_cast<std::size_t>(bufferSize))
{
poco_check_ptr (pTransform);
poco_assert (bufferSize > 2 * pTransform->blockSize());
}
CryptoStreamBuf::~CryptoStreamBuf()
{
try
{
close();
}
catch (...)
{
}
delete _pTransform;
}
void CryptoStreamBuf::close()
{
sync();
if (_pIstr)
{
_pIstr = 0;
}
else if (_pOstr)
{
// Close can be called multiple times. By zeroing the pointer we make
// sure that we call finalize() only once, even if an exception is
// thrown.
std::ostream* pOstr = _pOstr;
_pOstr = 0;
// Finalize transformation.
std::streamsize n = _pTransform->finalize(_buffer.begin(), static_cast<std::streamsize>(_buffer.size()));
if (n > 0)
{
pOstr->write(reinterpret_cast<char*>(_buffer.begin()), n);
if (!pOstr->good())
throw Poco::IOException("Output stream failure");
}
}
}
int CryptoStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
if (!_pIstr)
return 0;
int count = 0;
while (!_eof)
{
int m = (static_cast<int>(length) - count)/2 - static_cast<int>(_pTransform->blockSize());
// Make sure we can read at least one more block. Explicitly check
// for m < 0 since blockSize() returns an unsigned int and the
// comparison might give false results for m < 0.
if (m <= 0)
break;
int n = 0;
if (_pIstr->good())
{
_pIstr->read(reinterpret_cast<char*>(_buffer.begin()), m);
n = static_cast<int>(_pIstr->gcount());
}
if (n == 0)
{
_eof = true;
// No more data, finalize transformation
count += static_cast<int>(_pTransform->finalize(
reinterpret_cast<unsigned char*>(buffer + count),
static_cast<int>(length) - count));
}
else
{
// Transform next chunk of data
count += static_cast<int>(_pTransform->transform(
_buffer.begin(),
n,
reinterpret_cast<unsigned char*>(buffer + count),
static_cast<int>(length) - count));
}
}
return count;
}
int CryptoStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
if (!_pOstr)
return 0;
std::size_t maxChunkSize = _buffer.size()/2;
std::size_t count = 0;
while (count < length)
{
// Truncate chunk size so that the maximum output fits into _buffer.
std::size_t n = static_cast<std::size_t>(length) - count;
if (n > maxChunkSize)
n = maxChunkSize;
// Transform next chunk of data
std::streamsize k = _pTransform->transform(
reinterpret_cast<const unsigned char*>(buffer + count),
static_cast<std::streamsize>(n),
_buffer.begin(),
static_cast<std::streamsize>(_buffer.size()));
// Attention: (n != k) might be true. In count, we have to track how
// many bytes from buffer have been consumed, not how many bytes have
// been written to _pOstr!
count += n;
if (k > 0)
{
_pOstr->write(reinterpret_cast<const char*>(_buffer.begin()), k);
if (!_pOstr->good())
throw Poco::IOException("Output stream failure");
}
}
return static_cast<int>(count);
}
//
// CryptoIOS
//
CryptoIOS::CryptoIOS(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
_buf(istr, pTransform, bufferSize)
{
poco_ios_init(&_buf);
}
CryptoIOS::CryptoIOS(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
_buf(ostr, pTransform, bufferSize)
{
poco_ios_init(&_buf);
}
CryptoIOS::~CryptoIOS()
{
}
CryptoStreamBuf* CryptoIOS::rdbuf()
{
return &_buf;
}
//
// CryptoInputStream
//
CryptoInputStream::CryptoInputStream(std::istream& istr, CryptoTransform* pTransform, std::streamsize bufferSize):
CryptoIOS(istr, pTransform, bufferSize),
std::istream(&_buf)
{
}
CryptoInputStream::CryptoInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
std::istream(&_buf)
{
}
CryptoInputStream::~CryptoInputStream()
{
}
//
// CryptoOutputStream
//
CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, CryptoTransform* pTransform, std::streamsize bufferSize):
CryptoIOS(ostr, pTransform, bufferSize),
std::ostream(&_buf)
{
}
CryptoOutputStream::CryptoOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
std::ostream(&_buf)
{
}
CryptoOutputStream::~CryptoOutputStream()
{
}
void CryptoOutputStream::close()
{
_buf.close();
}
//
// EncryptingInputStream
//
EncryptingInputStream::EncryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(istr, cipher.createEncryptor(), bufferSize),
std::istream(&_buf)
{
}
EncryptingInputStream::~EncryptingInputStream()
{
}
//
// EncryptingOuputStream
//
EncryptingOutputStream::EncryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(ostr, cipher.createEncryptor(), bufferSize),
std::ostream(&_buf)
{
}
EncryptingOutputStream::~EncryptingOutputStream()
{
}
void EncryptingOutputStream::close()
{
_buf.close();
}
//
// DecryptingInputStream
//
DecryptingInputStream::DecryptingInputStream(std::istream& istr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(istr, cipher.createDecryptor(), bufferSize),
std::istream(&_buf)
{
}
DecryptingInputStream::~DecryptingInputStream()
{
}
//
// DecryptingOuputStream
//
DecryptingOutputStream::DecryptingOutputStream(std::ostream& ostr, Cipher& cipher, std::streamsize bufferSize):
CryptoIOS(ostr, cipher.createDecryptor(), bufferSize),
std::ostream(&_buf)
{
}
DecryptingOutputStream::~DecryptingOutputStream()
{
}
void DecryptingOutputStream::close()
{
_buf.close();
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,38 @@
//
// CryptoTransform.cpp
//
// Library: Crypto
// Package: Cipher
// Module: CryptoTransform
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/CryptoTransform.h"
namespace Poco {
namespace Crypto {
CryptoTransform::CryptoTransform()
{
}
CryptoTransform::~CryptoTransform()
{
}
int CryptoTransform::setPadding(int padding)
{
return 1;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,80 @@
//
// DigestEngine.cpp
//
// Library: Crypto
// Package: Digest
// Module: DigestEngine
//
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/DigestEngine.h"
#include "Poco/Exception.h"
namespace Poco {
namespace Crypto {
DigestEngine::DigestEngine(const std::string& name):
_name(name),
_pContext(EVP_MD_CTX_create())
{
const EVP_MD* md = EVP_get_digestbyname(_name.c_str());
if (!md) throw Poco::NotFoundException(_name);
EVP_DigestInit_ex(_pContext, md, NULL);
}
DigestEngine::~DigestEngine()
{
EVP_MD_CTX_destroy(_pContext);
}
int DigestEngine::nid() const
{
return EVP_MD_type(EVP_MD_CTX_md(_pContext));
}
std::size_t DigestEngine::digestLength() const
{
return EVP_MD_CTX_size(_pContext);
}
void DigestEngine::reset()
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
EVP_MD_CTX_free(_pContext);
_pContext = EVP_MD_CTX_create();
#else
EVP_MD_CTX_cleanup(_pContext);
#endif
const EVP_MD* md = EVP_get_digestbyname(_name.c_str());
if (!md) throw Poco::NotFoundException(_name);
EVP_DigestInit_ex(_pContext, md, NULL);
}
const Poco::DigestEngine::Digest& DigestEngine::digest()
{
_digest.clear();
unsigned len = EVP_MD_CTX_size(_pContext);
_digest.resize(len);
EVP_DigestFinal_ex(_pContext, &_digest[0], &len);
reset();
return _digest;
}
void DigestEngine::updateImpl(const void* data, std::size_t length)
{
EVP_DigestUpdate(_pContext, data, length);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,100 @@
//
// ECDSADigestEngine.cpp
//
//
// Library: Crypto
// Package: ECDSA
// Module: ECDSADigestEngine
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/ECDSADigestEngine.h"
#include <openssl/ecdsa.h>
namespace Poco {
namespace Crypto {
ECDSADigestEngine::ECDSADigestEngine(const ECKey& key, const std::string &name):
_key(key),
_engine(name)
{
}
ECDSADigestEngine::~ECDSADigestEngine()
{
}
std::size_t ECDSADigestEngine::digestLength() const
{
return _engine.digestLength();
}
void ECDSADigestEngine::reset()
{
_engine.reset();
_digest.clear();
_signature.clear();
}
const DigestEngine::Digest& ECDSADigestEngine::digest()
{
if (_digest.empty())
{
_digest = _engine.digest();
}
return _digest;
}
const DigestEngine::Digest& ECDSADigestEngine::signature()
{
if (_signature.empty())
{
digest();
_signature.resize(_key.size());
unsigned sigLen = static_cast<unsigned>(_signature.size());
if (!ECDSA_sign(0, &_digest[0], static_cast<unsigned>(_digest.size()),
&_signature[0], &sigLen, _key.impl()->getECKey()))
{
throw OpenSSLException();
}
if (sigLen < _signature.size()) _signature.resize(sigLen);
}
return _signature;
}
bool ECDSADigestEngine::verify(const DigestEngine::Digest& sig)
{
digest();
EC_KEY* pKey = _key.impl()->getECKey();
if (pKey)
{
int ret = ECDSA_verify(0, &_digest[0], static_cast<unsigned>(_digest.size()),
&sig[0], static_cast<unsigned>(sig.size()),
pKey);
if (1 == ret) return true;
else if (0 == ret) return false;
}
throw OpenSSLException();
}
void ECDSADigestEngine::updateImpl(const void* data, std::size_t length)
{
_engine.update(data, length);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,75 @@
//
// ECKey.cpp
//
//
// Library: Crypto
// Package: EC
// Module: ECKey
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/ECKey.h"
#include <openssl/rsa.h>
namespace Poco {
namespace Crypto {
ECKey::ECKey(const EVPPKey& key):
KeyPair(new ECKeyImpl(key)),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::ECKey(const X509Certificate& cert):
KeyPair(new ECKeyImpl(cert)),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::ECKey(const PKCS12Container& cont):
KeyPair(new ECKeyImpl(cont)),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::ECKey(const std::string& eccGroup):
KeyPair(new ECKeyImpl(OBJ_txt2nid(eccGroup.c_str()))),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::ECKey(const std::string& publicKeyFile,
const std::string& privateKeyFile,
const std::string& privateKeyPassphrase):
KeyPair(new ECKeyImpl(publicKeyFile, privateKeyFile, privateKeyPassphrase)),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::ECKey(std::istream* pPublicKeyStream,
std::istream* pPrivateKeyStream,
const std::string& privateKeyPassphrase):
KeyPair(new ECKeyImpl(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase)),
_pImpl(KeyPair::impl().cast<ECKeyImpl>())
{
}
ECKey::~ECKey()
{
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,258 @@
//
// ECKeyImpl.cpp
//
//
// Library: Crypto
// Package: EC
// Module: ECKeyImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/ECKeyImpl.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/PKCS12Container.h"
#include "Poco/FileStream.h"
#include "Poco/Format.h"
#include "Poco/StreamCopier.h"
#include <sstream>
#include <openssl/evp.h>
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
#include <openssl/bn.h>
#endif
namespace Poco {
namespace Crypto {
ECKeyImpl::ECKeyImpl(const EVPPKey& key):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
{
checkEC("ECKeyImpl(const EVPPKey&)", "EVP_PKEY_get1_EC_KEY()");
}
ECKeyImpl::ECKeyImpl(const X509Certificate& cert):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(0)
{
const X509* pCert = cert.certificate();
if (pCert)
{
EVP_PKEY* pKey = X509_get_pubkey(const_cast<X509*>(pCert));
if (pKey)
{
_pEC = EVP_PKEY_get1_EC_KEY(pKey);
EVP_PKEY_free(pKey);
checkEC("ECKeyImpl(const const X509Certificate&)", "EVP_PKEY_get1_EC_KEY()");
return;
}
}
throw OpenSSLException("ECKeyImpl(const X509Certificate&)");
}
ECKeyImpl::ECKeyImpl(const PKCS12Container& cont):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EVP_PKEY_get1_EC_KEY(cont.getKey()))
{
checkEC("ECKeyImpl(const PKCS12Container&)", "EVP_PKEY_get1_EC_KEY()");
}
ECKeyImpl::ECKeyImpl(int curve):
KeyPairImpl("ec", KT_EC_IMPL),
_pEC(EC_KEY_new_by_curve_name(curve))
{
poco_check_ptr(_pEC);
EC_KEY_set_asn1_flag(_pEC, OPENSSL_EC_NAMED_CURVE);
if (!(EC_KEY_generate_key(_pEC)))
throw OpenSSLException("ECKeyImpl(int curve): EC_KEY_generate_key()");
checkEC("ECKeyImpl(int curve)", "EC_KEY_generate_key()");
}
ECKeyImpl::ECKeyImpl(const std::string& publicKeyFile,
const std::string& privateKeyFile,
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
{
if (EVPPKey::loadKey(&_pEC, PEM_read_PrivateKey, EVP_PKEY_get1_EC_KEY, privateKeyFile, privateKeyPassphrase))
{
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!EVPPKey::loadKey(&_pEC, PEM_read_PUBKEY, EVP_PKEY_get1_EC_KEY, publicKeyFile))
{
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
}
checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
ECKeyImpl::ECKeyImpl(std::istream* pPublicKeyStream,
std::istream* pPrivateKeyStream,
const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
{
if (EVPPKey::loadKey(&_pEC, PEM_read_bio_PrivateKey, EVP_PKEY_get1_EC_KEY, pPrivateKeyStream, privateKeyPassphrase))
{
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_bio_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!EVPPKey::loadKey(&_pEC, PEM_read_bio_PUBKEY, EVP_PKEY_get1_EC_KEY, pPublicKeyStream))
{
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
}
checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
"PEM_read_bio_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
}
ECKeyImpl::~ECKeyImpl()
{
freeEC();
}
void ECKeyImpl::checkEC(const std::string& method, const std::string& func) const
{
if (!_pEC) throw OpenSSLException(Poco::format("%s: %s", method, func));
if (!EC_KEY_check_key(_pEC))
throw OpenSSLException(Poco::format("%s: EC_KEY_check_key()", method));
}
void ECKeyImpl::freeEC()
{
if (_pEC)
{
EC_KEY_free(_pEC);
_pEC = 0;
}
}
int ECKeyImpl::size() const
{
int sz = -1;
EVP_PKEY* pKey = EVP_PKEY_new();
if (pKey && EVP_PKEY_set1_EC_KEY(pKey, _pEC))
{
sz = EVP_PKEY_bits(pKey);
EVP_PKEY_free(pKey);
return sz;
}
throw OpenSSLException("ECKeyImpl::size()");
}
int ECKeyImpl::groupId() const
{
if (_pEC)
{
const EC_GROUP* ecGroup = EC_KEY_get0_group(_pEC);
if (ecGroup)
{
return EC_GROUP_get_curve_name(ecGroup);
}
else
{
throw OpenSSLException("ECKeyImpl::groupName()");
}
}
throw NullPointerException("ECKeyImpl::groupName() => _pEC");
}
std::string ECKeyImpl::getCurveName(int nid)
{
std::string curveName;
size_t len = EC_get_builtin_curves(NULL, 0);
EC_builtin_curve* pCurves =
(EC_builtin_curve*) OPENSSL_malloc(sizeof(EC_builtin_curve) * len);
if (!pCurves) return curveName;
if (!EC_get_builtin_curves(pCurves, len))
{
OPENSSL_free(pCurves);
return curveName;
}
if (-1 == nid) nid = pCurves[0].nid;
const int bufLen = 128;
char buf[bufLen];
std::memset(buf, 0, bufLen);
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
curveName = buf;
OPENSSL_free(pCurves);
return curveName;
}
int ECKeyImpl::getCurveNID(std::string& name)
{
std::string curveName;
size_t len = EC_get_builtin_curves(NULL, 0);
EC_builtin_curve* pCurves =
(EC_builtin_curve*)OPENSSL_malloc(static_cast<int>(sizeof(EC_builtin_curve) * len));
if (!pCurves) return -1;
if (!EC_get_builtin_curves(pCurves, len))
{
OPENSSL_free(pCurves);
return -1;
}
int nid = -1;
const int bufLen = 128;
char buf[bufLen];
if (name.empty())
{
std::memset(buf, 0, bufLen);
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
name = buf;
nid = pCurves[0].nid;
}
else
{
for (int i = 0; i < len; ++i)
{
std::memset(buf, 0, bufLen);
OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(pCurves[i].nid), 0);
if (strncmp(name.c_str(), buf, name.size() > bufLen ? bufLen : name.size()) == 0)
{
nid = pCurves[i].nid;
break;
}
}
}
OPENSSL_free(pCurves);
return nid;
}
bool ECKeyImpl::hasCurve(const std::string& name)
{
std::string tmp(name);
return (-1 != getCurveNID(tmp));
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,321 @@
//
// EVPPKey.cpp
//
//
// Library: Crypto
// Package: CryptoCore
// Module: EVPPKey
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/EVPPKey.h"
#include "Poco/Crypto/ECKey.h"
#include "Poco/Crypto/RSAKey.h"
#include "Poco/NumberFormatter.h"
namespace Poco {
namespace Crypto {
EVPPKey::EVPPKey(const std::string& ecCurveName): _pEVPPKey(0)
{
newECKey(ecCurveName.c_str());
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(const char* ecCurveName): _pEVPPKey(0)
{
newECKey(ecCurveName);
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(EVP_PKEY* pEVPPKey): _pEVPPKey(0)
{
duplicate(pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(const std::string& publicKeyFile,
const std::string& privateKeyFile,
const std::string& privateKeyPassphrase): _pEVPPKey(0)
{
if (loadKey(&_pEVPPKey, PEM_read_PrivateKey, (EVP_PKEY_get_Key_fn)0, privateKeyFile, privateKeyPassphrase))
{
poco_check_ptr(_pEVPPKey);
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!loadKey(&_pEVPPKey, PEM_read_PUBKEY, (EVP_PKEY_get_Key_fn)0, publicKeyFile))
{
throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
}
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(std::istream* pPublicKeyStream,
std::istream* pPrivateKeyStream,
const std::string& privateKeyPassphrase): _pEVPPKey(0)
{
if (loadKey(&_pEVPPKey, PEM_read_bio_PrivateKey, (EVP_PKEY_get_Key_fn)0, pPrivateKeyStream, privateKeyPassphrase))
{
poco_check_ptr(_pEVPPKey);
return; // private key is enough
}
// no private key, this must be public key only, otherwise throw
if (!loadKey(&_pEVPPKey, PEM_read_bio_PUBKEY, (EVP_PKEY_get_Key_fn)0, pPublicKeyStream))
{
throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
}
poco_check_ptr(_pEVPPKey);
}
EVPPKey::EVPPKey(const EVPPKey& other)
{
duplicate(other._pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
}
EVPPKey& EVPPKey::operator=(const EVPPKey& other)
{
duplicate(other._pEVPPKey, &_pEVPPKey);
poco_check_ptr(_pEVPPKey);
return *this;
}
#ifdef POCO_ENABLE_CPP11
EVPPKey::EVPPKey(EVPPKey&& other): _pEVPPKey(other._pEVPPKey)
{
other._pEVPPKey = nullptr;
poco_check_ptr(_pEVPPKey);
}
EVPPKey& EVPPKey::operator=(EVPPKey&& other)
{
_pEVPPKey = other._pEVPPKey;
other._pEVPPKey = nullptr;
poco_check_ptr(_pEVPPKey);
return *this;
}
#endif // POCO_ENABLE_CPP11
EVPPKey::~EVPPKey()
{
if (_pEVPPKey) EVP_PKEY_free(_pEVPPKey);
}
void EVPPKey::save(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase) const
{
if (!publicKeyFile.empty() && (publicKeyFile != privateKeyFile))
{
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_PUBKEY(bio, _pEVPPKey))
{
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_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
}
else
{
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 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 EVPPKey::save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream, const std::string& privateKeyPassphrase) const
{
if (pPublicKeyStream && (pPublicKeyStream != pPrivateKeyStream))
{
BIO* bio = BIO_new(BIO_s_mem());
if (!bio) throw Poco::IOException("Cannot create BIO for writing public key");
if (!PEM_write_bio_PUBKEY(bio, _pEVPPKey))
{
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_PrivateKey(bio, _pEVPPKey, 0, 0, 0, 0, 0);
else
rc = PEM_write_bio_PrivateKey(bio, _pEVPPKey, 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);
}
}
EVP_PKEY* EVPPKey::duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey)
{
if (!pFromKey) throw NullPointerException("EVPPKey::duplicate(): "
"provided key pointer is null.");
*pToKey = EVP_PKEY_new();
if (!*pToKey) throw NullPointerException("EVPPKey::duplicate(): "
"EVP_PKEY_new() returned null.");
int keyType = type(pFromKey);
switch (keyType)
{
case EVP_PKEY_RSA:
{
RSA* pRSA = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pFromKey));
if (pRSA)
{
EVP_PKEY_set1_RSA(*pToKey, pRSA);
RSA_free(pRSA);
}
else throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_get1_RSA()");
break;
}
case EVP_PKEY_EC:
{
EC_KEY* pEC = EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>(pFromKey));
if (pEC)
{
EVP_PKEY_set1_EC_KEY(*pToKey, pEC);
EC_KEY_free(pEC);
int cmp = EVP_PKEY_cmp_parameters(*pToKey, pFromKey);
if (cmp < 0)
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_cmp_parameters()");
if (0 == cmp)
{
if(!EVP_PKEY_copy_parameters(*pToKey, pFromKey))
throw OpenSSLException("EVPPKey::duplicate(): EVP_PKEY_copy_parameters()");
}
}
else throw OpenSSLException();
break;
}
default:
throw NotImplementedException("EVPPKey:duplicate(); Key type: " +
NumberFormatter::format(keyType));
}
return *pToKey;
}
void EVPPKey::newECKey(const char* ecCurveName)
{
int curveID = OBJ_txt2nid(ecCurveName);
EC_KEY* pEC = EC_KEY_new_by_curve_name(curveID);
if (!pEC) goto err;
if (!EC_KEY_generate_key(pEC)) goto err;
_pEVPPKey = EVP_PKEY_new();
if (!_pEVPPKey) goto err;
if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pEC)) goto err;
EC_KEY_free(pEC);
return;
err:
throw OpenSSLException("EVPPKey:newECKey()");
}
void EVPPKey::setKey(ECKey* pKey)
{
poco_check_ptr(pKey);
poco_check_ptr(pKey->impl());
setKey(pKey->impl()->getECKey());
}
void EVPPKey::setKey(RSAKey* pKey)
{
poco_check_ptr(pKey);
poco_check_ptr(pKey->impl());
setKey(pKey->impl()->getRSA());
}
int EVPPKey::passCB(char* buf, int size, int, void* pass)
{
if (pass)
{
int len = (int)std::strlen((char*)pass);
if(len > size) len = size;
std::memcpy(buf, pass, len);
return len;
}
return 0;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,34 @@
//
// KeyPair.cpp
//
//
// Library: Crypto
// Package: CryptoCore
// Module: KeyPair
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/KeyPair.h"
#include <openssl/rsa.h>
namespace Poco {
namespace Crypto {
KeyPair::KeyPair(KeyPairImpl::Ptr pKeyPairImpl): _pImpl(pKeyPairImpl)
{
}
KeyPair::~KeyPair()
{
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,35 @@
//
// KeyPairImpl.cpp
//
//
// Library: Crypto
// Package: CryptoCore
// Module: KeyPairImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/KeyPairImpl.h"
namespace Poco {
namespace Crypto {
KeyPairImpl::KeyPairImpl(const std::string& name, Type type):
_name(name),
_type(type)
{
}
KeyPairImpl::~KeyPairImpl()
{
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,162 @@
//
// OpenSSLInitializer.cpp
//
// Library: Crypto
// Package: CryptoCore
// Module: OpenSSLInitializer
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/OpenSSLInitializer.h"
#include "Poco/RandomStream.h"
#include "Poco/Thread.h"
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
#include <openssl/conf.h>
#endif
using Poco::RandomInputStream;
using Poco::Thread;
namespace Poco {
namespace Crypto {
Poco::FastMutex* OpenSSLInitializer::_mutexes(0);
Poco::AtomicCounter OpenSSLInitializer::_rc;
OpenSSLInitializer::OpenSSLInitializer()
{
initialize();
}
OpenSSLInitializer::~OpenSSLInitializer()
{
try
{
uninitialize();
}
catch (...)
{
poco_unexpected();
}
}
void OpenSSLInitializer::initialize()
{
if (++_rc == 1)
{
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
OPENSSL_config(NULL);
#endif
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
char seed[SEEDSIZE];
RandomInputStream rnd;
rnd.read(seed, sizeof(seed));
RAND_seed(seed, SEEDSIZE);
int nMutexes = CRYPTO_num_locks();
_mutexes = new Poco::FastMutex[nMutexes];
CRYPTO_set_locking_callback(&OpenSSLInitializer::lock);
// Not needed on Windows (see SF #110: random unhandled exceptions when linking with ssl).
// https://sourceforge.net/p/poco/bugs/110/
//
// From http://www.openssl.org/docs/crypto/threads.html :
// "If the application does not register such a callback using CRYPTO_THREADID_set_callback(),
// then a default implementation is used - on Windows and BeOS this uses the system's
// default thread identifying APIs"
CRYPTO_set_id_callback(&OpenSSLInitializer::id);
CRYPTO_set_dynlock_create_callback(&OpenSSLInitializer::dynlockCreate);
CRYPTO_set_dynlock_lock_callback(&OpenSSLInitializer::dynlock);
CRYPTO_set_dynlock_destroy_callback(&OpenSSLInitializer::dynlockDestroy);
}
}
void OpenSSLInitializer::uninitialize()
{
if (--_rc == 0)
{
EVP_cleanup();
ERR_free_strings();
CRYPTO_set_locking_callback(0);
CRYPTO_set_id_callback(0);
delete [] _mutexes;
CONF_modules_free();
}
}
void OpenSSLInitializer::lock(int mode, int n, const char* file, int line)
{
if (mode & CRYPTO_LOCK)
_mutexes[n].lock();
else
_mutexes[n].unlock();
}
unsigned long OpenSSLInitializer::id()
{
// Note: we use an old-style C cast here because
// neither static_cast<> nor reinterpret_cast<>
// work uniformly across all platforms.
return (unsigned long) Poco::Thread::currentTid();
}
struct CRYPTO_dynlock_value* OpenSSLInitializer::dynlockCreate(const char* file, int line)
{
return new CRYPTO_dynlock_value;
}
void OpenSSLInitializer::dynlock(int mode, struct CRYPTO_dynlock_value* lock, const char* file, int line)
{
poco_check_ptr (lock);
if (mode & CRYPTO_LOCK)
lock->_mutex.lock();
else
lock->_mutex.unlock();
}
void OpenSSLInitializer::dynlockDestroy(struct CRYPTO_dynlock_value* lock, const char* file, int line)
{
delete lock;
}
void initializeCrypto()
{
OpenSSLInitializer::initialize();
}
void uninitializeCrypto()
{
OpenSSLInitializer::uninitialize();
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,191 @@
//
// PKCS12Container.cpp
//
//
// Library: Crypto
// Package: Certificate
// Module: PKCS12Container
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/PKCS12Container.h"
#include "Poco/NumberFormatter.h"
#include "Poco/StreamCopier.h"
#include <sstream>
#include <openssl/err.h>
namespace Poco {
namespace Crypto {
PKCS12Container::PKCS12Container(std::istream& istr, const std::string& password): _pKey(0)
{
std::ostringstream ostr;
Poco::StreamCopier::copyStream(istr, ostr);
const std::string& cont = ostr.str();
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(cont.data()), static_cast<int>(cont.size()));
if (pBIO)
{
PKCS12* pPKCS12 = 0;
d2i_PKCS12_bio(pBIO, &pPKCS12);
BIO_free(pBIO);
if (!pPKCS12) throw OpenSSLException("PKCS12Container(istream&, const string&)");
load(pPKCS12, password);
}
else
{
throw Poco::NullPointerException("PKCS12Container(istream&, const string&)");
}
}
PKCS12Container::PKCS12Container(const std::string& path, const std::string& password): _pKey(0)
{
FILE* pFile = fopen(path.c_str(), "rb");
if (pFile)
{
PKCS12* pPKCS12 = d2i_PKCS12_fp(pFile, NULL);
fclose (pFile);
if (!pPKCS12) throw OpenSSLException("PKCS12Container(const string&, const string&)");
load(pPKCS12, password);
}
else
{
throw Poco::OpenFileException("PKCS12Container: " + path);
}
}
PKCS12Container::PKCS12Container(const PKCS12Container& other):
_pKey(EVPPKey::duplicate(other._pKey, &_pKey)),
_pX509Cert(new X509Certificate(*other._pX509Cert)),
_caCertList(other._caCertList),
_caCertNames(other._caCertNames),
_pkcsFriendlyName(other._pkcsFriendlyName)
{
}
PKCS12Container& PKCS12Container::operator = (const PKCS12Container& other)
{
if (&other != this)
{
if (_pKey) EVP_PKEY_free(_pKey);
_pKey = EVPPKey::duplicate(other._pKey, &_pKey);
_pX509Cert.reset(new X509Certificate(*other._pX509Cert));
_caCertList = other._caCertList;
_caCertNames = other._caCertNames;
_pkcsFriendlyName = other._pkcsFriendlyName;
}
return *this;
}
#ifdef POCO_ENABLE_CPP11
PKCS12Container::PKCS12Container(PKCS12Container&& other):
_pKey(other._pKey),
_pX509Cert(std::move(other._pX509Cert)),
_caCertList(std::move(other._caCertList)),
_caCertNames(std::move(other._caCertNames)),
_pkcsFriendlyName(std::move(other._pkcsFriendlyName))
{
other._pKey = 0;
}
PKCS12Container& PKCS12Container::operator = (PKCS12Container&& other)
{
if (&other != this)
{
if (_pKey) EVP_PKEY_free(_pKey);
_pKey = other._pKey; other._pKey = 0;
_pX509Cert = std::move(other._pX509Cert);
_caCertList = std::move(other._caCertList);
_caCertNames = std::move(other._caCertNames);
_pkcsFriendlyName = std::move(other._pkcsFriendlyName);
}
return *this;
}
#endif // POCO_ENABLE_CPP11
PKCS12Container::~PKCS12Container()
{
if (_pKey) EVP_PKEY_free(_pKey);
}
std::string PKCS12Container::extractFriendlyName(X509* pCert)
{
std::string friendlyName;
if(!pCert) throw NullPointerException("PKCS12Container::extractFriendlyName(X509)");
// This is how PKCS12_add_cert() sets friendlyName (via PKCS12_add_friendlyname())
int namelen = 0;
char *name = (char *)X509_alias_get0(pCert, &namelen);
friendlyName = std::string(name, namelen);
return friendlyName;
}
void PKCS12Container::load(PKCS12* pPKCS12, const std::string& password)
{
if (pPKCS12)
{
X509* pCert = 0;
STACK_OF(X509)* pCA = 0;
if (PKCS12_parse(pPKCS12, password.c_str(), &_pKey, &pCert, &pCA))
{
if (pCert)
{
_pX509Cert.reset(new X509Certificate(pCert, true));
_pkcsFriendlyName = extractFriendlyName(pCert);
}
else _pX509Cert.reset();
_caCertList.clear();
_caCertNames.clear();
if (pCA)
{
int certCount = sk_X509_num(pCA);
for (int i = 0; i < certCount; ++i)
{
X509* pX509 = sk_X509_value(pCA, i);
if (pX509)
{
_caCertList.push_back(X509Certificate(pX509, true));
_caCertNames.push_back(extractFriendlyName(pX509));
}
else throw OpenSSLException("PKCS12Container::load()");
}
}
}
else
{
throw OpenSSLException();
}
PKCS12_free(pPKCS12);
sk_X509_pop_free(pCA, X509_free);
if (pCert) X509_free(pCert);
poco_assert_dbg (_caCertList.size() == _caCertNames.size());
}
else
{
throw NullPointerException("PKCS12Container: struct PKCS12");
}
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,342 @@
//
// RSACipherImpl.cpp
//
// Library: Crypto
// Package: RSA
// Module: RSACipherImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/RSACipherImpl.h"
#include "Poco/Crypto/CryptoTransform.h"
#include "Poco/Exception.h"
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <cstring>
namespace Poco {
namespace Crypto {
namespace
{
void throwError()
{
unsigned long err;
std::string msg;
while ((err = ERR_get_error()))
{
if (!msg.empty())
msg.append("; ");
msg.append(ERR_error_string(err, 0));
}
throw Poco::IOException(msg);
}
int mapPaddingMode(RSAPaddingMode paddingMode)
{
switch (paddingMode)
{
case RSA_PADDING_PKCS1:
return RSA_PKCS1_PADDING;
case RSA_PADDING_PKCS1_OAEP:
return RSA_PKCS1_OAEP_PADDING;
case RSA_PADDING_NONE:
return RSA_NO_PADDING;
default:
poco_bugcheck();
return RSA_NO_PADDING;
}
}
class RSAEncryptImpl: public CryptoTransform
{
public:
RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
~RSAEncryptImpl();
std::size_t blockSize() const;
std::size_t maxDataSize() const;
std::string getTag(std::size_t);
void setTag(const std::string&);
std::streamsize transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength);
std::streamsize finalize(unsigned char* output, std::streamsize length);
private:
const RSA* _pRSA;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
};
RSAEncryptImpl::RSAEncryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
_pRSA(pRSA),
_paddingMode(paddingMode),
_pos(0),
_pBuf(0)
{
_pBuf = new unsigned char[blockSize()];
}
RSAEncryptImpl::~RSAEncryptImpl()
{
delete [] _pBuf;
}
std::size_t RSAEncryptImpl::blockSize() const
{
return RSA_size(_pRSA);
}
std::size_t RSAEncryptImpl::maxDataSize() const
{
std::size_t size = blockSize();
switch (_paddingMode)
{
case RSA_PADDING_PKCS1:
case RSA_PADDING_SSLV23:
size -= 11;
break;
case RSA_PADDING_PKCS1_OAEP:
size -= 41;
break;
default:
break;
}
return size;
}
std::string RSAEncryptImpl::getTag(std::size_t)
{
return std::string();
}
void RSAEncryptImpl::setTag(const std::string&)
{
}
std::streamsize RSAEncryptImpl::transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength)
{
// always fill up the buffer before writing!
std::streamsize maxSize = static_cast<std::streamsize>(maxDataSize());
std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
poco_assert_dbg(_pos <= maxSize);
poco_assert (outputLength >= rsaSize);
int rc = 0;
while (inputLength > 0)
{
// check how many data bytes we are missing to get the buffer full
poco_assert_dbg (maxSize >= _pos);
std::streamsize missing = maxSize - _pos;
if (missing == 0)
{
poco_assert (outputLength >= rsaSize);
int n = RSA_public_encrypt(static_cast<int>(maxSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (n == -1)
throwError();
rc += n;
output += n;
outputLength -= n;
_pos = 0;
}
else
{
if (missing > inputLength)
missing = inputLength;
std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
input += missing;
_pos += missing;
inputLength -= missing;
}
}
return rc;
}
std::streamsize RSAEncryptImpl::finalize(unsigned char* output, std::streamsize length)
{
poco_assert (length >= blockSize());
poco_assert (_pos <= maxDataSize());
int rc = 0;
if (_pos > 0)
{
rc = RSA_public_encrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (rc == -1) throwError();
}
return rc;
}
class RSADecryptImpl: public CryptoTransform
{
public:
RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode);
~RSADecryptImpl();
std::size_t blockSize() const;
std::string getTag(std::size_t);
void setTag(const std::string&);
std::streamsize transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength);
std::streamsize finalize(
unsigned char* output,
std::streamsize length);
private:
const RSA* _pRSA;
RSAPaddingMode _paddingMode;
std::streamsize _pos;
unsigned char* _pBuf;
};
RSADecryptImpl::RSADecryptImpl(const RSA* pRSA, RSAPaddingMode paddingMode):
_pRSA(pRSA),
_paddingMode(paddingMode),
_pos(0),
_pBuf(0)
{
_pBuf = new unsigned char[blockSize()];
}
RSADecryptImpl::~RSADecryptImpl()
{
delete [] _pBuf;
}
std::size_t RSADecryptImpl::blockSize() const
{
return RSA_size(_pRSA);
}
std::string RSADecryptImpl::getTag(std::size_t)
{
return std::string();
}
void RSADecryptImpl::setTag(const std::string&)
{
}
std::streamsize RSADecryptImpl::transform(
const unsigned char* input,
std::streamsize inputLength,
unsigned char* output,
std::streamsize outputLength)
{
// always fill up the buffer before decrypting!
std::streamsize rsaSize = static_cast<std::streamsize>(blockSize());
poco_assert_dbg(_pos <= rsaSize);
poco_assert (outputLength >= rsaSize);
int rc = 0;
while (inputLength > 0)
{
// check how many data bytes we are missing to get the buffer full
poco_assert_dbg (rsaSize >= _pos);
std::streamsize missing = rsaSize - _pos;
if (missing == 0)
{
int tmp = RSA_private_decrypt(static_cast<int>(rsaSize), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (tmp == -1)
throwError();
rc += tmp;
output += tmp;
outputLength -= tmp;
_pos = 0;
}
else
{
if (missing > inputLength)
missing = inputLength;
std::memcpy(_pBuf + _pos, input, static_cast<std::size_t>(missing));
input += missing;
_pos += missing;
inputLength -= missing;
}
}
return rc;
}
std::streamsize RSADecryptImpl::finalize(unsigned char* output, std::streamsize length)
{
poco_assert (length >= blockSize());
int rc = 0;
if (_pos > 0)
{
rc = RSA_private_decrypt(static_cast<int>(_pos), _pBuf, output, const_cast<RSA*>(_pRSA), mapPaddingMode(_paddingMode));
if (rc == -1)
throwError();
}
return rc;
}
}
RSACipherImpl::RSACipherImpl(const RSAKey& key, RSAPaddingMode paddingMode):
_key(key),
_paddingMode(paddingMode)
{
}
RSACipherImpl::~RSACipherImpl()
{
}
CryptoTransform* RSACipherImpl::createEncryptor()
{
return new RSAEncryptImpl(_key.impl()->getRSA(), _paddingMode);
}
CryptoTransform* RSACipherImpl::createDecryptor()
{
return new RSADecryptImpl(_key.impl()->getRSA(), _paddingMode);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,96 @@
//
// RSADigestEngine.cpp
//
// Library: Crypto
// Package: RSA
// Module: RSADigestEngine
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/RSADigestEngine.h"
#include <openssl/rsa.h>
namespace Poco {
namespace Crypto {
RSADigestEngine::RSADigestEngine(const RSAKey& key, DigestType digestType):
_key(key),
_engine(digestType == DIGEST_MD5 ? "MD5" : "SHA1")
{
}
RSADigestEngine::RSADigestEngine(const RSAKey& key, const std::string &name):
_key(key),
_engine(name)
{
}
RSADigestEngine::~RSADigestEngine()
{
}
std::size_t RSADigestEngine::digestLength() const
{
return _engine.digestLength();
}
void RSADigestEngine::reset()
{
_engine.reset();
_digest.clear();
_signature.clear();
}
const DigestEngine::Digest& RSADigestEngine::digest()
{
if (_digest.empty())
{
_digest = _engine.digest();
}
return _digest;
}
const DigestEngine::Digest& RSADigestEngine::signature()
{
if (_signature.empty())
{
digest();
_signature.resize(_key.size());
unsigned sigLen = static_cast<unsigned>(_signature.size());
RSA_sign(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &_signature[0], &sigLen, _key.impl()->getRSA());
// truncate _sig to sigLen
if (sigLen < _signature.size())
_signature.resize(sigLen);
}
return _signature;
}
bool RSADigestEngine::verify(const DigestEngine::Digest& sig)
{
digest();
DigestEngine::Digest sigCpy = sig; // copy becausse RSA_verify can modify sigCpy
int ret = RSA_verify(_engine.nid(), &_digest[0], static_cast<unsigned>(_digest.size()), &sigCpy[0], static_cast<unsigned>(sigCpy.size()), _key.impl()->getRSA());
return ret != 0;
}
void RSADigestEngine::updateImpl(const void* data, std::size_t length)
{
_engine.update(data, length);
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,87 @@
//
// RSAKey.cpp
//
// Library: Crypto
// Package: RSA
// Module: RSAKey
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/RSAKey.h"
#include <openssl/rsa.h>
namespace Poco {
namespace Crypto {
RSAKey::RSAKey(const EVPPKey& key):
KeyPair(new RSAKeyImpl(key)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::RSAKey(const X509Certificate& cert):
KeyPair(new RSAKeyImpl(cert)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::RSAKey(const PKCS12Container& cont):
KeyPair(new RSAKeyImpl(cont)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::RSAKey(KeyLength keyLength, Exponent exp):
KeyPair(new RSAKeyImpl(keyLength, (exp == EXP_LARGE) ? RSA_F4 : RSA_3)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::RSAKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase):
KeyPair(new RSAKeyImpl(publicKeyFile, privateKeyFile, privateKeyPassphrase)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::RSAKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase):
KeyPair(new RSAKeyImpl(pPublicKeyStream, pPrivateKeyStream, privateKeyPassphrase)),
_pImpl(KeyPair::impl().cast<RSAKeyImpl>())
{
}
RSAKey::~RSAKey()
{
}
RSAKeyImpl::ByteVec RSAKey::modulus() const
{
return _pImpl->modulus();
}
RSAKeyImpl::ByteVec RSAKey::encryptionExponent() const
{
return _pImpl->encryptionExponent();
}
RSAKeyImpl::ByteVec RSAKey::decryptionExponent() const
{
return _pImpl->decryptionExponent();
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,386 @@
//
// RSAKeyImpl.cpp
//
// Library: Crypto
// Package: RSA
// Module: RSAKeyImpl
//
// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/RSAKeyImpl.h"
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/PKCS12Container.h"
#include "Poco/FileStream.h"
#include "Poco/StreamCopier.h"
#include <sstream>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
#include <openssl/bn.h>
#endif
namespace Poco {
namespace Crypto {
RSAKeyImpl::RSAKeyImpl(const EVPPKey& key):
KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
{
if (!_pRSA) throw OpenSSLException();
}
RSAKeyImpl::RSAKeyImpl(const X509Certificate& cert):
KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(0)
{
const X509* pCert = cert.certificate();
EVP_PKEY* pKey = X509_get_pubkey(const_cast<X509*>(pCert));
if (pKey)
{
_pRSA = EVP_PKEY_get1_RSA(pKey);
EVP_PKEY_free(pKey);
}
else
throw OpenSSLException("RSAKeyImpl(const X509Certificate&)");
}
RSAKeyImpl::RSAKeyImpl(const PKCS12Container& cont):
KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(0)
{
EVPPKey key = cont.getKey();
_pRSA = EVP_PKEY_get1_RSA(key);
}
RSAKeyImpl::RSAKeyImpl(int keyLength, unsigned long exponent): KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(0)
{
#if OPENSSL_VERSION_NUMBER >= 0x00908000L
_pRSA = RSA_new();
int ret = 0;
BIGNUM* bn = 0;
try
{
bn = BN_new();
BN_set_word(bn, exponent);
ret = RSA_generate_key_ex(_pRSA, keyLength, bn, 0);
BN_free(bn);
}
catch (...)
{
BN_free(bn);
throw;
}
if (!ret) throw Poco::InvalidArgumentException("Failed to create RSA context");
#else
_pRSA = RSA_generate_key(keyLength, exponent, 0, 0);
if (!_pRSA) throw Poco::InvalidArgumentException("Failed to create RSA context");
#endif
}
RSAKeyImpl::RSAKeyImpl(const std::string& publicKeyFile,
const std::string& privateKeyFile,
const std::string& privateKeyPassphrase): KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(0)
{
poco_assert_dbg(_pRSA == 0);
_pRSA = RSA_new();
if (!publicKeyFile.empty())
{
BIO* bio = BIO_new(BIO_s_file());
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key", publicKeyFile);
int rc = BIO_read_filename(bio, const_cast<char *>(publicKeyFile.c_str()));
if (rc)
{
RSA* pubKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
if (!pubKey)
{
int rc = BIO_reset(bio);
// BIO_reset() normally returns 1 for success and 0 or -1 for failure.
// File BIOs are an exception, they return 0 for success and -1 for failure.
if (rc != 0) throw Poco::FileException("Failed to load public key", publicKeyFile);
pubKey = PEM_read_bio_RSA_PUBKEY(bio, &_pRSA, 0, 0);
}
BIO_free(bio);
if (!pubKey)
{
freeRSA();
throw Poco::FileException("Failed to load public key", publicKeyFile);
}
}
else
{
freeRSA();
throw Poco::FileNotFoundException("Public key file", publicKeyFile);
}
}
if (!privateKeyFile.empty())
{
BIO* bio = BIO_new(BIO_s_file());
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key", privateKeyFile);
int rc = BIO_read_filename(bio, const_cast<char *>(privateKeyFile.c_str()));
if (rc)
{
RSA* privKey = 0;
if (privateKeyPassphrase.empty())
privKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, 0);
else
privKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, const_cast<char*>(privateKeyPassphrase.c_str()));
BIO_free(bio);
if (!privKey)
{
freeRSA();
throw Poco::FileException("Failed to load private key", privateKeyFile);
}
}
else
{
freeRSA();
throw Poco::FileNotFoundException("Private key file", privateKeyFile);
}
}
}
RSAKeyImpl::RSAKeyImpl(std::istream* pPublicKeyStream,
std::istream* pPrivateKeyStream,
const std::string& privateKeyPassphrase): KeyPairImpl("rsa", KT_RSA_IMPL),
_pRSA(0)
{
poco_assert_dbg(_pRSA == 0);
_pRSA = RSA_new();
if (pPublicKeyStream)
{
std::string publicKeyData;
Poco::StreamCopier::copyToString(*pPublicKeyStream, publicKeyData);
BIO* bio = BIO_new_mem_buf(const_cast<char*>(publicKeyData.data()), static_cast<int>(publicKeyData.size()));
if (!bio) throw Poco::IOException("Cannot create BIO for reading public key");
RSA* publicKey = PEM_read_bio_RSAPublicKey(bio, &_pRSA, 0, 0);
if (!publicKey)
{
int rc = BIO_reset(bio);
// BIO_reset() normally returns 1 for success and 0 or -1 for failure.
// File BIOs are an exception, they return 0 for success and -1 for failure.
if (rc != 1) throw Poco::FileException("Failed to load public key");
publicKey = PEM_read_bio_RSA_PUBKEY(bio, &_pRSA, 0, 0);
}
BIO_free(bio);
if (!publicKey)
{
freeRSA();
throw Poco::FileException("Failed to load public key");
}
}
if (pPrivateKeyStream)
{
std::string privateKeyData;
Poco::StreamCopier::copyToString(*pPrivateKeyStream, privateKeyData);
BIO* bio = BIO_new_mem_buf(const_cast<char*>(privateKeyData.data()), static_cast<int>(privateKeyData.size()));
if (!bio) throw Poco::IOException("Cannot create BIO for reading private key");
RSA* privateKey = 0;
if (privateKeyPassphrase.empty())
privateKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, 0);
else
privateKey = PEM_read_bio_RSAPrivateKey(bio, &_pRSA, 0, const_cast<char*>(privateKeyPassphrase.c_str()));
BIO_free(bio);
if (!privateKey)
{
freeRSA();
throw Poco::FileException("Failed to load private key");
}
}
}
RSAKeyImpl::~RSAKeyImpl()
{
freeRSA();
}
void RSAKeyImpl::freeRSA()
{
if (_pRSA) RSA_free(_pRSA);
_pRSA = 0;
}
int RSAKeyImpl::size() const
{
return RSA_size(_pRSA);
}
RSAKeyImpl::ByteVec RSAKeyImpl::modulus() const
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
const BIGNUM* n = 0;
const BIGNUM* e = 0;
const BIGNUM* d = 0;
RSA_get0_key(_pRSA, &n, &e, &d);
return convertToByteVec(n);
#else
return convertToByteVec(_pRSA->n);
#endif
}
RSAKeyImpl::ByteVec RSAKeyImpl::encryptionExponent() const
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
const BIGNUM* n = 0;
const BIGNUM* e = 0;
const BIGNUM* d = 0;
RSA_get0_key(_pRSA, &n, &e, &d);
return convertToByteVec(e);
#else
return convertToByteVec(_pRSA->e);
#endif
}
RSAKeyImpl::ByteVec RSAKeyImpl::decryptionExponent() const
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
const BIGNUM* n = 0;
const BIGNUM* e = 0;
const BIGNUM* d = 0;
RSA_get0_key(_pRSA, &n, &e, &d);
return convertToByteVec(d);
#else
return convertToByteVec(_pRSA->d);
#endif
}
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)
{
int numBytes = BN_num_bytes(bn);
ByteVec byteVector(numBytes);
ByteVec::value_type* buffer = new ByteVec::value_type[numBytes];
BN_bn2bin(bn, buffer);
for (int i = 0; i < numBytes; ++i)
byteVector[i] = buffer[i];
delete [] buffer;
return byteVector;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,382 @@
//
// X509Certificate.cpp
//
// Library: Crypto
// Package: Certificate
// Module: X509Certificate
//
// Copyright (c) 2006-2009, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Crypto/X509Certificate.h"
#include "Poco/Crypto/CryptoException.h"
#include "Poco/StreamCopier.h"
#include "Poco/String.h"
#include "Poco/DateTimeParser.h"
#include "Poco/Format.h"
#include <sstream>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/evp.h>
namespace Poco {
namespace Crypto {
X509Certificate::X509Certificate(std::istream& istr):
_pCert(0)
{
load(istr);
}
X509Certificate::X509Certificate(const std::string& path):
_pCert(0)
{
load(path);
}
X509Certificate::X509Certificate(X509* pCert):
_pCert(pCert)
{
poco_check_ptr(_pCert);
init();
}
X509Certificate::X509Certificate(X509* pCert, bool shared):
_pCert(pCert)
{
poco_check_ptr(_pCert);
if (shared)
{
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
X509_up_ref(_pCert);
#else
_pCert->references++;
#endif
}
init();
}
X509Certificate::X509Certificate(const X509Certificate& cert):
_issuerName(cert._issuerName),
_subjectName(cert._subjectName),
_serialNumber(cert._serialNumber),
_pCert(cert._pCert)
{
_pCert = X509_dup(_pCert);
}
X509Certificate& X509Certificate::operator = (const X509Certificate& cert)
{
X509Certificate tmp(cert);
swap(tmp);
return *this;
}
void X509Certificate::swap(X509Certificate& cert)
{
using std::swap;
swap(cert._issuerName, _issuerName);
swap(cert._subjectName, _subjectName);
swap(cert._serialNumber, _serialNumber);
swap(cert._pCert, _pCert);
}
X509Certificate::~X509Certificate()
{
X509_free(_pCert);
}
void X509Certificate::load(std::istream& istr)
{
poco_assert (!_pCert);
std::stringstream certStream;
Poco::StreamCopier::copyStream(istr, certStream);
std::string cert = certStream.str();
BIO *pBIO = BIO_new_mem_buf(const_cast<char*>(cert.data()), static_cast<int>(cert.size()));
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate");
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
BIO_free(pBIO);
if (!_pCert) throw Poco::IOException("Failed to load certificate from stream");
init();
}
void X509Certificate::load(const std::string& path)
{
poco_assert (!_pCert);
BIO *pBIO = BIO_new(BIO_s_file());
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
if (!BIO_read_filename(pBIO, const_cast<char *>(path.c_str())))
{
BIO_free(pBIO);
throw Poco::OpenFileException("Cannot open certificate file for reading", path);
}
_pCert = PEM_read_bio_X509(pBIO, 0, 0, 0);
BIO_free(pBIO);
if (!_pCert) throw Poco::ReadFileException("Failed to load certificate from", path);
init();
}
void X509Certificate::save(std::ostream& stream) const
{
BIO *pBIO = BIO_new(BIO_s_mem());
if (!pBIO) throw Poco::IOException("Cannot create BIO for writing certificate");
try
{
if (!PEM_write_bio_X509(pBIO, _pCert))
throw Poco::IOException("Failed to write certificate to stream");
char *pData;
long size;
size = BIO_get_mem_data(pBIO, &pData);
stream.write(pData, size);
}
catch (...)
{
BIO_free(pBIO);
throw;
}
BIO_free(pBIO);
}
void X509Certificate::save(const std::string& path) const
{
BIO *pBIO = BIO_new(BIO_s_file());
if (!pBIO) throw Poco::IOException("Cannot create BIO for reading certificate file", path);
if (!BIO_write_filename(pBIO, const_cast<char*>(path.c_str())))
{
BIO_free(pBIO);
throw Poco::CreateFileException("Cannot create certificate file", path);
}
try
{
if (!PEM_write_bio_X509(pBIO, _pCert))
throw Poco::WriteFileException("Failed to write certificate to file", path);
}
catch (...)
{
BIO_free(pBIO);
throw;
}
BIO_free(pBIO);
}
void X509Certificate::init()
{
char buffer[NAME_BUFFER_SIZE];
X509_NAME_oneline(X509_get_issuer_name(_pCert), buffer, sizeof(buffer));
_issuerName = buffer;
X509_NAME_oneline(X509_get_subject_name(_pCert), buffer, sizeof(buffer));
_subjectName = buffer;
BIGNUM* pBN = ASN1_INTEGER_to_BN(X509_get_serialNumber(const_cast<X509*>(_pCert)), 0);
if (pBN)
{
char* pSN = BN_bn2hex(pBN);
if (pSN)
{
_serialNumber = pSN;
OPENSSL_free(pSN);
}
BN_free(pBN);
}
}
std::string X509Certificate::commonName() const
{
return subjectName(NID_COMMON_NAME);
}
std::string X509Certificate::issuerName(NID nid) const
{
if (X509_NAME* issuer = X509_get_issuer_name(_pCert))
{
char buffer[NAME_BUFFER_SIZE];
if (X509_NAME_get_text_by_NID(issuer, nid, buffer, sizeof(buffer)) >= 0)
return std::string(buffer);
}
return std::string();
}
std::string X509Certificate::subjectName(NID nid) const
{
if (X509_NAME* subj = X509_get_subject_name(_pCert))
{
char buffer[NAME_BUFFER_SIZE];
if (X509_NAME_get_text_by_NID(subj, nid, buffer, sizeof(buffer)) >= 0)
return std::string(buffer);
}
return std::string();
}
void X509Certificate::extractNames(std::string& cmnName, std::set<std::string>& domainNames) const
{
domainNames.clear();
if (STACK_OF(GENERAL_NAME)* names = static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(_pCert, NID_subject_alt_name, 0, 0)))
{
for (int i = 0; i < sk_GENERAL_NAME_num(names); ++i)
{
const GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i);
if (name->type == GEN_DNS)
{
const char* data = reinterpret_cast<char*>(ASN1_STRING_data(name->d.ia5));
std::size_t len = ASN1_STRING_length(name->d.ia5);
domainNames.insert(std::string(data, len));
}
}
GENERAL_NAMES_free(names);
}
cmnName = commonName();
if (!cmnName.empty() && domainNames.empty())
{
domainNames.insert(cmnName);
}
}
Poco::DateTime X509Certificate::validFrom() const
{
ASN1_TIME* certTime = X509_get_notBefore(_pCert);
std::string dateTime(reinterpret_cast<char*>(certTime->data));
int tzd;
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
}
Poco::DateTime X509Certificate::expiresOn() const
{
ASN1_TIME* certTime = X509_get_notAfter(_pCert);
std::string dateTime(reinterpret_cast<char*>(certTime->data));
int tzd;
return DateTimeParser::parse("%y%m%d%H%M%S", dateTime, tzd);
}
bool X509Certificate::issuedBy(const X509Certificate& issuerCertificate) const
{
X509* pCert = const_cast<X509*>(_pCert);
X509* pIssuerCert = const_cast<X509*>(issuerCertificate.certificate());
EVP_PKEY* pIssuerPublicKey = X509_get_pubkey(pIssuerCert);
if (!pIssuerPublicKey) throw Poco::InvalidArgumentException("Issuer certificate has no public key");
int rc = X509_verify(pCert, pIssuerPublicKey);
EVP_PKEY_free(pIssuerPublicKey);
return rc == 1;
}
bool X509Certificate::equals(const X509Certificate& otherCertificate) const
{
X509* pCert = const_cast<X509*>(_pCert);
X509* pOtherCert = const_cast<X509*>(otherCertificate.certificate());
return X509_cmp(pCert, pOtherCert) == 0;
}
std::string X509Certificate::signatureAlgorithm() const
{
int sigNID = NID_undef;
#if (OPENSSL_VERSION_NUMBER >= 0x1010000fL) && !defined(LIBRESSL_VERSION_NUMBER)
sigNID = X509_get_signature_nid(_pCert);
#else
poco_check_ptr(_pCert->sig_alg);
sigNID = OBJ_obj2nid(_pCert->sig_alg->algorithm);
#endif
if (sigNID != NID_undef)
{
const char* pAlgName = OBJ_nid2ln(sigNID);
if (pAlgName) return std::string(pAlgName);
else throw OpenSSLException(Poco::format("X509Certificate::"
"signatureAlgorithm(): OBJ_nid2ln(%d)", sigNID));
}
else
throw NotFoundException("X509Certificate::signatureAlgorithm()");
return "";
}
X509Certificate::List X509Certificate::readPEM(const std::string& pemFileName)
{
List caCertList;
BIO* pBIO = BIO_new_file(pemFileName.c_str(), "r");
if (pBIO == NULL) throw OpenFileException("X509Certificate::readPEM()");
X509* x = PEM_read_bio_X509(pBIO, NULL, 0, NULL);
if (!x) throw OpenSSLException(Poco::format("X509Certificate::readPEM(%s)", pemFileName));
while(x)
{
caCertList.push_back(X509Certificate(x));
x = PEM_read_bio_X509(pBIO, NULL, 0, NULL);
}
BIO_free(pBIO);
return caCertList;
}
void X509Certificate::writePEM(const std::string& pemFileName, const List& list)
{
BIO* pBIO = BIO_new_file(pemFileName.c_str(), "a");
if (pBIO == NULL) throw OpenFileException("X509Certificate::writePEM()");
List::const_iterator it = list.begin();
List::const_iterator end = list.end();
for (; it != end; ++it)
{
if (!PEM_write_bio_X509(pBIO, const_cast<X509*>(it->certificate())))
{
throw OpenSSLException("X509Certificate::writePEM()");
}
}
BIO_free(pBIO);
}
void X509Certificate::print(std::ostream& out) const
{
out << "subjectName: " << subjectName() << std::endl;
out << "issuerName: " << issuerName() << std::endl;
out << "commonName: " << commonName() << std::endl;
out << "country: " << subjectName(X509Certificate::NID_COUNTRY) << std::endl;
out << "localityName: " << subjectName(X509Certificate::NID_LOCALITY_NAME) << std::endl;
out << "stateOrProvince: " << subjectName(X509Certificate::NID_STATE_OR_PROVINCE) << std::endl;
out << "organizationName: " << subjectName(X509Certificate::NID_ORGANIZATION_NAME) << std::endl;
out << "organizationUnitName: " << subjectName(X509Certificate::NID_ORGANIZATION_UNIT_NAME) << std::endl;
out << "emailAddress: " << subjectName(X509Certificate::NID_PKCS9_EMAIL_ADDRESS) << std::endl;
out << "serialNumber: " << subjectName(X509Certificate::NID_SERIAL_NUMBER) << std::endl;
}
} } // namespace Poco::Crypto

View File

@ -0,0 +1,20 @@
file (GLOB SRCS src/*.cpp)
add_library (_poco_data ${SRCS})
add_library (Poco::Data ALIAS _poco_data)
# TODO: remove these warning exclusions
target_compile_options (_poco_data
PRIVATE
-Wno-comma
-Wno-covered-switch-default
-Wno-deprecated-dynamic-exception-spec
-Wno-extra-semi-stmt
-Wno-old-style-cast
-Wno-shorten-64-to-32
-Wno-sign-compare
-Wno-unused-parameter
-Wno-zero-as-null-pointer-constant
)
target_include_directories (_poco_data SYSTEM PUBLIC "include")
target_link_libraries (_poco_data PUBLIC Poco::Foundation)

View File

@ -0,0 +1,52 @@
if (ENABLE_ODBC)
if (NOT TARGET ch_contrib::unixodbc)
message(FATAL_ERROR "Configuration error: unixodbc is not a target")
endif()
set (SRCS
src/Binder.cpp
src/ConnectionHandle.cpp
src/Connector.cpp
src/EnvironmentHandle.cpp
src/Extractor.cpp
src/ODBCException.cpp
src/ODBCMetaColumn.cpp
src/ODBCStatementImpl.cpp
src/Parameter.cpp
src/Preparator.cpp
src/SessionImpl.cpp
src/TypeInfo.cpp
src/Unicode.cpp
src/Utility.cpp
)
add_library (_poco_data_odbc ${SRCS})
add_library (Poco::Data::ODBC ALIAS _poco_data_odbc)
# TODO: remove these warning exclusions
target_compile_options (_poco_data_odbc
PRIVATE
-Wno-cast-qual
-Wno-deprecated-dynamic-exception-spec
-Wno-extra-semi-stmt
-Wno-old-style-cast
-Wno-sign-compare
-Wno-tautological-constant-out-of-range-compare
-Wno-tautological-unsigned-zero-compare
-Wno-unused-parameter
-Wno-unused-variable
-Wno-zero-as-null-pointer-constant
)
target_include_directories (_poco_data_odbc SYSTEM PUBLIC "include")
target_link_libraries (_poco_data_odbc PUBLIC Poco::Data ch_contrib::unixodbc)
message (STATUS "Using Poco::Data::ODBC")
else ()
add_library (_poco_data_odbc INTERFACE)
add_library (Poco::Data::ODBC ALIAS _poco_data_odbc)
if (TARGET ch_contrib::unixodbc)
target_link_libraries (_poco_data_odbc INTERFACE ch_contrib::unixodbc)
endif()
message (STATUS "Not using Poco::Data::ODBC")
endif ()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
//
// ConnectionHandle.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: ConnectionHandle
//
// Definition of ConnectionHandle.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_ConnectionHandle_INCLUDED
#define Data_ODBC_ConnectionHandle_INCLUDED
#include "Poco/Data/ODBC/EnvironmentHandle.h"
#include "Poco/Data/ODBC/ODBC.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
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
#endif

View File

@ -0,0 +1,101 @@
//
// Connector.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Connector
//
// Definition of the Connector class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Connector_INCLUDED
#define Data_ODBC_Connector_INCLUDED
#include "Poco/Data/Connector.h"
#include "Poco/Data/ODBC/ODBC.h"
namespace Poco
{
namespace Data
{
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
#endif // Data_ODBC_Connector_INCLUDED

View File

@ -0,0 +1,217 @@
//
// Diagnostics.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Diagnostics
//
// Definition of Diagnostics.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Diagnostics_INCLUDED
#define Data_ODBC_Diagnostics_INCLUDED
#include <cstring>
#include <vector>
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Utility.h"
#include <sqlext.h>
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:
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;
};
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

View File

@ -0,0 +1,96 @@
//
// EnvironmentHandle.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: EnvironmentHandle
//
// Definition of EnvironmentHandle.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_EnvironmentHandle_INCLUDED
#define Data_ODBC_EnvironmentHandle_INCLUDED
#include "Poco/Data/ODBC/ODBC.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
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
#endif

View File

@ -0,0 +1,124 @@
//
// Error.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Error
//
// Definition of Error.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef 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/Utility.h"
#include "Poco/Format.h"
#include <sqlext.h>
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:
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;
};
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

View File

@ -0,0 +1,748 @@
//
// Extractor.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Extractor
//
// Definition of the Extractor class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Extractor_INCLUDED
#define Data_ODBC_Extractor_INCLUDED
#include <map>
#include "Poco/Any.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/Constants.h"
#include "Poco/Data/Date.h"
#include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/ODBCMetaColumn.h"
#include "Poco/Data/ODBC/Preparator.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/Time.h"
#include "Poco/DateTime.h"
#include "Poco/Dynamic/Var.h"
#include "Poco/Exception.h"
#include "Poco/Nullable.h"
#include "Poco/UTFString.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
namespace ODBC
{
class ODBC_API Extractor : public Poco::Data::AbstractExtractor
/// Extracts and converts data values from the result row returned by ODBC.
/// If NULL is received, the incoming val value is not changed and false is returned
{
public:
typedef Preparator::Ptr PreparatorPtr;
Extractor(const StatementHandle & rStmt, Preparator::Ptr pPreparator);
/// Creates the Extractor.
~Extractor();
/// Destroys the Extractor.
bool extract(std::size_t pos, Poco::Int8 & val);
/// Extracts an Int8.
bool extract(std::size_t pos, std::vector<Poco::Int8> & val);
/// Extracts an Int8 vector.
bool extract(std::size_t pos, std::deque<Poco::Int8> & val);
/// Extracts an Int8 deque.
bool extract(std::size_t pos, std::list<Poco::Int8> & val);
/// Extracts an Int8 list.
bool extract(std::size_t pos, Poco::UInt8 & val);
/// Extracts an UInt8.
bool extract(std::size_t pos, std::vector<Poco::UInt8> & val);
/// Extracts an UInt8 vector.
bool extract(std::size_t pos, std::deque<Poco::UInt8> & val);
/// Extracts an UInt8 deque.
bool extract(std::size_t pos, std::list<Poco::UInt8> & val);
/// Extracts an UInt8 list.
bool extract(std::size_t pos, Poco::Int16 & val);
/// Extracts an Int16.
bool extract(std::size_t pos, std::vector<Poco::Int16> & val);
/// Extracts an Int16 vector.
bool extract(std::size_t pos, std::deque<Poco::Int16> & val);
/// Extracts an Int16 deque.
bool extract(std::size_t pos, std::list<Poco::Int16> & val);
/// Extracts an Int16 list.
bool extract(std::size_t pos, Poco::UInt16 & val);
/// Extracts an UInt16.
bool extract(std::size_t pos, std::vector<Poco::UInt16> & val);
/// Extracts an UInt16 vector.
bool extract(std::size_t pos, std::deque<Poco::UInt16> & val);
/// Extracts an UInt16 deque.
bool extract(std::size_t pos, std::list<Poco::UInt16> & val);
/// Extracts an UInt16 list.
bool extract(std::size_t pos, Poco::Int32 & val);
/// Extracts an Int32.
bool extract(std::size_t pos, std::vector<Poco::Int32> & val);
/// Extracts an Int32 vector.
bool extract(std::size_t pos, std::deque<Poco::Int32> & val);
/// Extracts an Int32 deque.
bool extract(std::size_t pos, std::list<Poco::Int32> & val);
/// Extracts an Int32 list.
bool extract(std::size_t pos, Poco::UInt32 & val);
/// Extracts an UInt32.
bool extract(std::size_t pos, std::vector<Poco::UInt32> & val);
/// Extracts an UInt32 vector.
bool extract(std::size_t pos, std::deque<Poco::UInt32> & val);
/// Extracts an UInt32 deque.
bool extract(std::size_t pos, std::list<Poco::UInt32> & val);
/// Extracts an UInt32 list.
bool extract(std::size_t pos, Poco::Int64 & val);
/// Extracts an Int64.
bool extract(std::size_t pos, std::vector<Poco::Int64> & val);
/// Extracts an Int64 vector.
bool extract(std::size_t pos, std::deque<Poco::Int64> & val);
/// Extracts an Int64 deque.
bool extract(std::size_t pos, std::list<Poco::Int64> & val);
/// Extracts an Int64 list.
bool extract(std::size_t pos, Poco::UInt64 & val);
/// Extracts an UInt64.
bool extract(std::size_t pos, std::vector<Poco::UInt64> & val);
/// Extracts an UInt64 vector.
bool extract(std::size_t pos, std::deque<Poco::UInt64> & val);
/// Extracts an UInt64 deque.
bool extract(std::size_t pos, std::list<Poco::UInt64> & val);
/// Extracts an UInt64 list.
#ifndef POCO_LONG_IS_64_BIT
bool extract(std::size_t pos, long & val);
/// Extracts a long.
bool extract(std::size_t pos, unsigned long & val);
/// Extracts an unsigned long.
bool extract(std::size_t pos, std::vector<long> & val);
/// Extracts a long vector.
bool extract(std::size_t pos, std::deque<long> & val);
/// Extracts a long deque.
bool extract(std::size_t pos, std::list<long> & val);
/// Extracts a long list.
#endif
bool extract(std::size_t pos, bool & val);
/// Extracts a boolean.
bool extract(std::size_t pos, std::vector<bool> & val);
/// Extracts a boolean vector.
bool extract(std::size_t pos, std::deque<bool> & val);
/// Extracts a boolean deque.
bool extract(std::size_t pos, std::list<bool> & val);
/// Extracts a boolean list.
bool extract(std::size_t pos, float & val);
/// Extracts a float.
bool extract(std::size_t pos, std::vector<float> & val);
/// Extracts a float vector.
bool extract(std::size_t pos, std::deque<float> & val);
/// Extracts a float deque.
bool extract(std::size_t pos, std::list<float> & val);
/// Extracts a float list.
bool extract(std::size_t pos, double & val);
/// Extracts a double.
bool extract(std::size_t pos, std::vector<double> & val);
/// Extracts a double vector.
bool extract(std::size_t pos, std::deque<double> & val);
/// Extracts a double deque.
bool extract(std::size_t pos, std::list<double> & val);
/// Extracts a double list.
bool extract(std::size_t pos, char & val);
/// Extracts a single character.
bool extract(std::size_t pos, std::vector<char> & val);
/// Extracts a single character vector.
bool extract(std::size_t pos, std::deque<char> & val);
/// Extracts a single character deque.
bool extract(std::size_t pos, std::list<char> & val);
/// Extracts a single character list.
bool extract(std::size_t pos, std::string & val);
/// Extracts a string.
bool extract(std::size_t pos, std::vector<std::string> & val);
/// Extracts a string vector.
bool extract(std::size_t pos, std::deque<std::string> & val);
/// Extracts a string deque.
bool extract(std::size_t pos, std::list<std::string> & val);
/// Extracts a string list.
/// Extracts a single character list.
bool extract(std::size_t pos, UTF16String & val);
/// Extracts a string.
bool extract(std::size_t pos, std::vector<UTF16String> & val);
/// Extracts a string vector.
bool extract(std::size_t pos, std::deque<UTF16String> & val);
/// Extracts a string deque.
bool extract(std::size_t pos, std::list<UTF16String> & val);
/// Extracts a string list.
bool extract(std::size_t pos, Poco::Data::BLOB & val);
/// Extracts a BLOB.
bool extract(std::size_t pos, Poco::Data::CLOB & val);
/// Extracts a CLOB.
bool extract(std::size_t pos, std::vector<Poco::Data::BLOB> & val);
/// Extracts a BLOB vector.
bool extract(std::size_t pos, std::deque<Poco::Data::BLOB> & val);
/// Extracts a BLOB deque.
bool extract(std::size_t pos, std::list<Poco::Data::BLOB> & val);
/// Extracts a BLOB list.
bool extract(std::size_t pos, std::vector<Poco::Data::CLOB> & val);
/// Extracts a CLOB vector.
bool extract(std::size_t pos, std::deque<Poco::Data::CLOB> & val);
/// Extracts a CLOB deque.
bool extract(std::size_t pos, std::list<Poco::Data::CLOB> & val);
/// Extracts a CLOB list.
bool extract(std::size_t pos, Poco::Data::Date & val);
/// Extracts a Date.
bool extract(std::size_t pos, std::vector<Poco::Data::Date> & val);
/// Extracts a Date vector.
bool extract(std::size_t pos, std::deque<Poco::Data::Date> & val);
/// Extracts a Date deque.
bool extract(std::size_t pos, std::list<Poco::Data::Date> & val);
/// Extracts a Date list.
bool extract(std::size_t pos, Poco::Data::Time & val);
/// Extracts a Time.
bool extract(std::size_t pos, std::vector<Poco::Data::Time> & val);
/// Extracts a Time vector.
bool extract(std::size_t pos, std::deque<Poco::Data::Time> & val);
/// Extracts a Time deque.
bool extract(std::size_t pos, std::list<Poco::Data::Time> & val);
/// Extracts a Time list.
bool extract(std::size_t pos, Poco::DateTime & val);
/// Extracts a DateTime.
bool extract(std::size_t pos, std::vector<Poco::DateTime> & val);
/// Extracts a DateTime vector.
bool extract(std::size_t pos, std::deque<Poco::DateTime> & val);
/// Extracts a DateTime deque.
bool extract(std::size_t pos, std::list<Poco::DateTime> & val);
/// Extracts a DateTime list.
bool extract(std::size_t pos, Poco::Any & val);
/// Extracts an Any.
bool extract(std::size_t pos, std::vector<Poco::Any> & val);
/// Extracts an Any vector.
bool extract(std::size_t pos, std::deque<Poco::Any> & val);
/// Extracts an Any deque.
bool extract(std::size_t pos, std::list<Poco::Any> & val);
/// Extracts an Any list.
bool extract(std::size_t pos, Poco::DynamicAny & val);
/// Extracts a DynamicAny.
bool extract(std::size_t pos, std::vector<Poco::DynamicAny> & val);
/// Extracts a DynamicAny vector.
bool extract(std::size_t pos, std::deque<Poco::DynamicAny> & val);
/// Extracts a DynamicAny deque.
bool extract(std::size_t pos, std::list<Poco::DynamicAny> & val);
/// Extracts a DynamicAny list.
void setDataExtraction(Preparator::DataExtraction ext);
/// Set data extraction mode.
Preparator::DataExtraction getDataExtraction() const;
/// Returns data extraction mode.
bool isNull(std::size_t col, std::size_t row = POCO_DATA_INVALID_ROW);
/// Returns true if the value at [col,row] is null.
void reset();
/// Resets the internally cached length indicators.
private:
static const int CHUNK_SIZE = 1024;
/// Amount of data retrieved in one SQLGetData() request when doing manual extract.
static const std::string FLD_SIZE_EXCEEDED_FMT;
/// String format for the exception message when the field size is exceeded.
void checkDataSize(std::size_t size);
/// This check is only performed for bound data
/// retrieval from variable length columns.
/// The reason for this check is to ensure we can
/// accept the value ODBC driver is supplying
/// (i.e. the bound buffer is large enough to receive
/// the returned value)
void resizeLengths(std::size_t pos);
/// Resizes the vector holding extracted data lengths to the
/// appropriate size.
template <typename T>
bool extractBoundImpl(std::size_t pos, T & val)
{
if (isNull(pos))
return false;
poco_assert_dbg(typeid(T) == _pPreparator->at(pos).type());
val = *AnyCast<T>(&_pPreparator->at(pos));
return true;
}
bool extractBoundImpl(std::size_t pos, Poco::Data::BLOB & val);
bool extractBoundImpl(std::size_t pos, Poco::Data::CLOB & val);
template <typename C>
bool extractBoundImplContainer(std::size_t pos, C & val)
{
typedef typename C::value_type Type;
poco_assert_dbg(typeid(std::vector<Type>) == _pPreparator->at(pos).type());
std::vector<Type> & v = RefAnyCast<std::vector<Type>>(_pPreparator->at(pos));
val.assign(v.begin(), v.end());
return true;
}
bool extractBoundImplContainer(std::size_t pos, std::vector<std::string> & values);
bool extractBoundImplContainer(std::size_t pos, std::deque<std::string> & values);
bool extractBoundImplContainer(std::size_t pos, std::list<std::string> & values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String> & values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String> & values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String> & values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::CLOB> & values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::CLOB> & values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::CLOB> & values);
bool extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::BLOB> & values);
bool extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::BLOB> & values);
bool extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::BLOB> & values);
template <typename C>
bool extractBoundImplContainerString(std::size_t pos, C & values)
{
typedef typename C::value_type StringType;
typedef typename C::iterator ItType;
typedef typename StringType::value_type CharType;
CharType ** pc = AnyCast<CharType *>(&(_pPreparator->at(pos)));
poco_assert_dbg(pc);
poco_assert_dbg(_pPreparator->bulkSize() == values.size());
std::size_t colWidth = columnSize(pos);
ItType it = values.begin();
ItType end = values.end();
for (int row = 0; it != end; ++it, ++row)
{
it->assign(*pc + row * colWidth / sizeof(CharType), _pPreparator->actualDataSize(pos, row));
// clean up superfluous null chars returned by some drivers
typename StringType::size_type trimLen = 0;
typename StringType::reverse_iterator sIt = it->rbegin();
typename StringType::reverse_iterator sEnd = it->rend();
for (; sIt != sEnd; ++sIt)
{
if (*sIt == '\0')
++trimLen;
else
break;
}
if (trimLen)
it->assign(it->begin(), it->begin() + it->length() - trimLen);
}
return true;
}
template <typename C>
bool extractBoundImplContainerLOB(std::size_t pos, C & values)
{
typedef typename C::value_type LOBType;
typedef typename LOBType::ValueType CharType;
typedef typename C::iterator ItType;
CharType ** pc = AnyCast<CharType *>(&(_pPreparator->at(pos)));
poco_assert_dbg(pc);
poco_assert_dbg(_pPreparator->bulkSize() == values.size());
std::size_t colWidth = _pPreparator->maxDataSize(pos);
ItType it = values.begin();
ItType end = values.end();
for (int row = 0; it != end; ++it, ++row)
it->assignRaw(*pc + row * colWidth, _pPreparator->actualDataSize(pos, row));
return true;
}
template <typename T>
bool extractBoundImplLOB(std::size_t pos, Poco::Data::LOB<T> & val)
{
if (isNull(pos))
return false;
std::size_t dataSize = _pPreparator->actualDataSize(pos);
checkDataSize(dataSize);
T * sp = AnyCast<T *>(_pPreparator->at(pos));
val.assignRaw(sp, dataSize);
return true;
}
template <typename T>
bool extractManualImpl(std::size_t pos, T & val, SQLSMALLINT cType)
{
SQLRETURN rc = 0;
T value = (T)0;
resizeLengths(pos);
rc = SQLGetData(
_rStmt,
(SQLUSMALLINT)pos + 1,
cType, //C data type
&value, //returned value
0, //buffer length (ignored)
&_lengths[pos]); //length indicator
if (Utility::isError(rc))
throw StatementException(_rStmt, "SQLGetData()");
if (isNullLengthIndicator(_lengths[pos]))
return false;
else
{
//for fixed-length data, buffer must be large enough
//otherwise, driver may write past the end
poco_assert_dbg(_lengths[pos] <= sizeof(T));
val = value;
}
return true;
}
template <typename T, typename NT>
bool extAny(std::size_t pos, T & val)
{
NT i;
if (extract(pos, i))
{
val = i;
return true;
}
else
{
val = Nullable<NT>();
return false;
}
}
template <typename T>
bool extractImpl(std::size_t pos, T & val)
/// Utility function for extraction of Any and DynamicAny.
{
ODBCMetaColumn column(_rStmt, pos);
switch (column.type())
{
case MetaColumn::FDT_INT8: {
return extAny<T, Poco::Int8>(pos, val);
}
case MetaColumn::FDT_UINT8: {
return extAny<T, Poco::UInt8>(pos, val);
}
case MetaColumn::FDT_INT16: {
return extAny<T, Poco::Int16>(pos, val);
}
case MetaColumn::FDT_UINT16: {
return extAny<T, Poco::UInt16>(pos, val);
}
case MetaColumn::FDT_INT32: {
return extAny<T, Poco::Int32>(pos, val);
}
case MetaColumn::FDT_UINT32: {
return extAny<T, Poco::UInt32>(pos, val);
}
case MetaColumn::FDT_INT64: {
return extAny<T, Poco::Int64>(pos, val);
}
case MetaColumn::FDT_UINT64: {
return extAny<T, Poco::UInt64>(pos, val);
}
case MetaColumn::FDT_BOOL: {
return extAny<T, bool>(pos, val);
}
case MetaColumn::FDT_FLOAT: {
return extAny<T, float>(pos, val);
}
case MetaColumn::FDT_DOUBLE: {
return extAny<T, double>(pos, val);
}
case MetaColumn::FDT_STRING: {
return extAny<T, std::string>(pos, val);
}
case MetaColumn::FDT_WSTRING: {
return extAny<T, Poco::UTF16String>(pos, val);
}
case MetaColumn::FDT_BLOB: {
return extAny<T, Poco::Data::BLOB>(pos, val);
}
case MetaColumn::FDT_CLOB: {
return extAny<T, Poco::Data::CLOB>(pos, val);
}
case MetaColumn::FDT_DATE: {
return extAny<T, Poco::Data::Date>(pos, val);
}
case MetaColumn::FDT_TIME: {
return extAny<T, Poco::Data::Time>(pos, val);
}
case MetaColumn::FDT_TIMESTAMP: {
return extAny<T, Poco::DateTime>(pos, val);
}
default:
throw DataFormatException("Unsupported data type.");
}
return false;
}
bool isNullLengthIndicator(SQLLEN val) const;
/// The reason for this utility wrapper are platforms where
/// SQLLEN macro (a.k.a. SQLINTEGER) yields 64-bit value,
/// while SQL_NULL_DATA (#define'd as -1 literal) remains 32-bit.
SQLINTEGER columnSize(std::size_t pos) const;
const StatementHandle & _rStmt;
PreparatorPtr _pPreparator;
Preparator::DataExtraction _dataExtraction;
std::vector<SQLLEN> _lengths;
};
///
/// inlines
///
inline bool Extractor::extractBoundImpl(std::size_t pos, Poco::Data::BLOB & val)
{
return extractBoundImplLOB<BLOB::ValueType>(pos, val);
}
inline bool Extractor::extractBoundImpl(std::size_t pos, Poco::Data::CLOB & val)
{
return extractBoundImplLOB<CLOB::ValueType>(pos, val);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<std::string> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<std::string> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<std::string> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<Poco::UTF16String> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<Poco::UTF16String> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco::UTF16String> & values)
{
return extractBoundImplContainerString(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::CLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::CLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::CLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::vector<Poco::Data::BLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::deque<Poco::Data::BLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline bool Extractor::extractBoundImplContainer(std::size_t pos, std::list<Poco::Data::BLOB> & values)
{
return extractBoundImplContainerLOB(pos, values);
}
inline void Extractor::setDataExtraction(Preparator::DataExtraction ext)
{
_pPreparator->setDataExtraction(_dataExtraction = ext);
}
inline Preparator::DataExtraction Extractor::getDataExtraction() const
{
return _dataExtraction;
}
inline void Extractor::reset()
{
_lengths.clear();
}
inline void Extractor::resizeLengths(std::size_t pos)
{
if (pos >= _lengths.size())
_lengths.resize(pos + 1, (SQLLEN)0);
}
inline bool Extractor::isNullLengthIndicator(SQLLEN val) const
{
return SQL_NULL_DATA == (int)val;
}
inline SQLINTEGER Extractor::columnSize(std::size_t pos) const
{
std::size_t size = ODBCMetaColumn(_rStmt, pos).length();
std::size_t maxSize = _pPreparator->maxDataSize(pos);
if (size > maxSize)
size = maxSize;
return (SQLINTEGER)size;
}
}
}
} // namespace Poco::Data::ODBC
#endif // Data_ODBC_Extractor_INCLUDED

View File

@ -0,0 +1,111 @@
//
// Handle.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Handle
//
// Definition of Handle.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Handle_INCLUDED
#define Data_ODBC_Handle_INCLUDED
#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/Utility.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
namespace ODBC
{
template <typename H, SQLSMALLINT handleType>
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;
};
typedef Handle<SQLHSTMT, SQL_HANDLE_STMT> StatementHandle;
typedef Handle<SQLHDESC, SQL_HANDLE_DESC> DescriptorHandle;
}
}
} // namespace Poco::Data::ODBC
#endif

View File

@ -0,0 +1,53 @@
//
// ODBC.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: ODBC
//
// Basic definitions for the Poco ODBC library.
// This file must be the first file included by every other ODBC
// header file.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_ODBC_INCLUDED
#define Data_ODBC_ODBC_INCLUDED
#include "Poco/Foundation.h"
//
// The following block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the ODBC_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// ODBC_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
//
#if !defined(ODBC_API)
# if !defined(POCO_NO_GCC_API_ATTRIBUTE) && defined(__GNUC__) && (__GNUC__ >= 4)
# define ODBC_API __attribute__((visibility("default")))
# else
# define ODBC_API
# endif
#endif
#include "Poco/Data/ODBC/Unicode.h"
//
// Automatically link Data library.
//
#endif // ODBC_ODBC_INCLUDED

View File

@ -0,0 +1,147 @@
//
// ODBCException.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: ODBCException
//
// Definition of ODBCException.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_ODBCException_INCLUDED
#define Data_ODBC_ODBCException_INCLUDED
#include "Poco/Data/DataException.h"
#include "Poco/Data/ODBC/Diagnostics.h"
#include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Format.h"
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:
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

View File

@ -0,0 +1,94 @@
//
// ODBCMetaColumn.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: ODBCMetaColumn
//
// Definition of ODBCMetaColumn.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_ODBCColumn_INCLUDED
#define Data_ODBC_ODBCColumn_INCLUDED
#include "Poco/Data/MetaColumn.h"
#include "Poco/Data/ODBC/Error.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include <sqlext.h>
namespace Poco
{
namespace Data
{
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
#endif

View File

@ -0,0 +1,208 @@
//
// ODBCStatementImpl.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: ODBCStatementImpl
//
// Definition of the ODBCStatementImpl class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_ODBCStatementImpl_INCLUDED
#define Data_ODBC_ODBCStatementImpl_INCLUDED
#include <sstream>
#include "Poco/Data/Column.h"
#include "Poco/Data/ODBC/Binder.h"
#include "Poco/Data/ODBC/Extractor.h"
#include "Poco/Data/ODBC/ODBC.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/Format.h"
#include "Poco/SharedPtr.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
namespace ODBC
{
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
#endif // Data_ODBC_ODBCStatementImpl_INCLUDED

View File

@ -0,0 +1,113 @@
//
// Parameter.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Parameter
//
// Definition of Parameter.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Parameter_INCLUDED
#define Data_ODBC_Parameter_INCLUDED
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBC.h"
#include <sqlext.h>
namespace Poco
{
namespace Data
{
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
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,294 @@
//
// SessionImpl.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: SessionImpl
//
// Definition of the SessionImpl class.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_SessionImpl_INCLUDED
#define Data_ODBC_SessionImpl_INCLUDED
#include "Poco/Data/AbstractSessionImpl.h"
#include "Poco/Data/ODBC/Binder.h"
#include "Poco/Data/ODBC/Connector.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/Mutex.h"
#include "Poco/SharedPtr.h"
#include <sqltypes.h>
namespace Poco
{
namespace Data
{
namespace ODBC
{
class ODBC_API SessionImpl : public Poco::Data::AbstractSessionImpl<SessionImpl>
/// Implements SessionImpl interface
{
public:
static const std::size_t ODBC_MAX_FIELD_SIZE = 1024u;
enum TransactionCapability
{
ODBC_TXN_CAPABILITY_UNKNOWN = -1,
ODBC_TXN_CAPABILITY_FALSE = 0,
ODBC_TXN_CAPABILITY_TRUE = 1
};
SessionImpl(
const std::string & connect,
std::size_t loginTimeout,
std::size_t maxFieldSize = ODBC_MAX_FIELD_SIZE,
bool autoBind = true,
bool autoExtract = true);
/// Creates the SessionImpl. Opens a connection to the database.
/// Throws NotConnectedException if connection was not successful.
//@ deprecated
SessionImpl(
const std::string & connect,
Poco::Any maxFieldSize = ODBC_MAX_FIELD_SIZE,
bool enforceCapability = false,
bool autoBind = true,
bool autoExtract = true);
/// Creates the SessionImpl. Opens a connection to the database.
~SessionImpl();
/// Destroys the SessionImpl.
Poco::Data::StatementImpl * createStatementImpl();
/// Returns an ODBC StatementImpl
void open(const std::string & connect = "");
/// Opens a connection to the Database
void close();
/// Closes the connection
bool isConnected();
/// Returns true if session is connected
void setConnectionTimeout(std::size_t timeout);
/// Sets the session connection timeout value.
std::size_t getConnectionTimeout();
/// Returns the session connection timeout value.
void begin();
/// Starts a transaction
void commit();
/// Commits and ends a transaction
void rollback();
/// Aborts a transaction
bool isTransaction();
/// Returns true iff a transaction is in progress.
const std::string & connectorName() const;
/// Returns the name of the connector.
bool canTransact();
/// Returns true if connection is transaction-capable.
void setTransactionIsolation(Poco::UInt32 ti);
/// Sets the transaction isolation level.
Poco::UInt32 getTransactionIsolation();
/// Returns the transaction isolation level.
bool hasTransactionIsolation(Poco::UInt32);
/// Returns true iff the transaction isolation level corresponding
/// to the supplied bitmask is supported.
bool isTransactionIsolation(Poco::UInt32);
/// Returns true iff the transaction isolation level corresponds
/// to the supplied bitmask.
void autoCommit(const std::string &, bool val);
/// Sets autocommit property for the session.
bool isAutoCommit(const std::string & name = "");
/// Returns autocommit property value.
void autoBind(const std::string &, bool val);
/// Sets automatic binding for the session.
bool isAutoBind(const std::string & name = "");
/// Returns true if binding is automatic for this session.
void autoExtract(const std::string &, bool val);
/// Sets automatic extraction for the session.
bool isAutoExtract(const std::string & name = "");
/// Returns true if extraction is automatic for this session.
void setMaxFieldSize(const std::string & rName, const Poco::Any & rValue);
/// Sets the max field size (the default used when column size is unknown).
Poco::Any getMaxFieldSize(const std::string & rName = "");
/// Returns the max field size (the default used when column size is unknown).
int maxStatementLength();
/// Returns maximum length of SQL statement allowed by driver.
void setQueryTimeout(const std::string &, const Poco::Any & value);
/// Sets the timeout (in seconds) for queries.
/// Value must be of type int.
Poco::Any getQueryTimeout(const std::string &);
/// Returns the timeout (in seconds) for queries,
/// or -1 if no timeout has been set.
int queryTimeout() const;
/// Returns the timeout (in seconds) for queries,
/// or -1 if no timeout has been set.
const ConnectionHandle & dbc() const;
/// Returns the connection handle.
Poco::Any dataTypeInfo(const std::string & rName = "");
/// Returns the data types information.
private:
void setDataTypeInfo(const std::string & rName, const Poco::Any & rValue);
/// No-op. Throws InvalidAccessException.
static const int FUNCTIONS = SQL_API_ODBC3_ALL_FUNCTIONS_SIZE;
void checkError(SQLRETURN rc, const std::string & msg = "");
Poco::UInt32 getDefaultTransactionIsolation();
Poco::UInt32 transactionIsolation(SQLULEN isolation);
std::string _connector;
const ConnectionHandle _db;
Poco::Any _maxFieldSize;
bool _autoBind;
bool _autoExtract;
TypeInfo _dataTypes;
char _canTransact;
bool _inTransaction;
int _queryTimeout;
Poco::FastMutex _mutex;
};
///
/// inlines
///
inline void SessionImpl::checkError(SQLRETURN rc, const std::string & msg)
{
if (Utility::isError(rc))
throw ConnectionException(_db, msg);
}
inline const ConnectionHandle & SessionImpl::dbc() const
{
return _db;
}
inline void SessionImpl::setMaxFieldSize(const std::string & rName, const Poco::Any & rValue)
{
_maxFieldSize = rValue;
}
inline Poco::Any SessionImpl::getMaxFieldSize(const std::string & rName)
{
return _maxFieldSize;
}
inline void SessionImpl::setDataTypeInfo(const std::string & rName, const Poco::Any & rValue)
{
throw InvalidAccessException();
}
inline Poco::Any SessionImpl::dataTypeInfo(const std::string & rName)
{
return &_dataTypes;
}
inline void SessionImpl::autoBind(const std::string &, bool val)
{
_autoBind = val;
}
inline bool SessionImpl::isAutoBind(const std::string & name)
{
return _autoBind;
}
inline void SessionImpl::autoExtract(const std::string &, bool val)
{
_autoExtract = val;
}
inline bool SessionImpl::isAutoExtract(const std::string & name)
{
return _autoExtract;
}
inline const std::string & SessionImpl::connectorName() const
{
return _connector;
}
inline bool SessionImpl::isTransactionIsolation(Poco::UInt32 ti)
{
return 0 != (ti & getTransactionIsolation());
}
inline void SessionImpl::setQueryTimeout(const std::string &, const Poco::Any & value)
{
_queryTimeout = Poco::AnyCast<int>(value);
}
inline Poco::Any SessionImpl::getQueryTimeout(const std::string &)
{
return _queryTimeout;
}
inline int SessionImpl::queryTimeout() const
{
return _queryTimeout;
}
}
}
} // namespace Poco::Data::ODBC
#endif // Data_ODBC_SessionImpl_INCLUDED

View File

@ -0,0 +1,121 @@
//
// TypeInfo.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: TypeInfo
//
// Definition of TypeInfo.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_DataTypes_INCLUDED
#define Data_ODBC_DataTypes_INCLUDED
#include <map>
#include <vector>
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/DynamicAny.h"
#include "Poco/NamedTuple.h"
#include <sqlext.h>
namespace Poco
{
namespace Data
{
namespace ODBC
{
class ODBC_API TypeInfo
/// Datatypes mapping utility class.
///
/// This class provides mapping between C and SQL datatypes as well
/// as datatypes supported by the underlying database. In order for database
/// types to be available, a valid connection handle must be supplied at either
/// object construction time, or at a later point in time, through call to
/// fillTypeInfo member function.
///
/// Class also provides a convenient debugging function that prints
/// tabulated data to an output stream.
{
public:
typedef std::map<int, int> DataTypeMap;
typedef DataTypeMap::value_type ValueType;
typedef Poco::NamedTuple<
std::string,
SQLSMALLINT,
SQLINTEGER,
std::string,
std::string,
std::string,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
std::string,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLSMALLINT,
SQLINTEGER,
SQLSMALLINT>
TypeInfoTup;
typedef std::vector<TypeInfoTup> TypeInfoVec;
explicit TypeInfo(SQLHDBC * pHDBC = 0);
/// Creates the TypeInfo.
~TypeInfo();
/// Destroys the TypeInfo.
int cDataType(int sqlDataType) const;
/// Returns C data type corresponding to supplied SQL data type.
int sqlDataType(int cDataType) const;
/// Returns SQL data type corresponding to supplied C data type.
void fillTypeInfo(SQLHDBC pHDBC);
/// Fills the data type info structure for the database.
DynamicAny getInfo(SQLSMALLINT type, const std::string & param) const;
/// Returns information about specified data type as specified by parameter 'type'.
/// The requested information is specified by parameter 'param'.
/// Will fail with a Poco::NotFoundException thrown if the param is not found
bool tryGetInfo(SQLSMALLINT type, const std::string & param, DynamicAny & result) const;
/// Returns information about specified data type as specified by parameter 'type' in param result.
/// The requested information is specified by parameter 'param'.
/// Will return false if the param is not found. The value of result will be not changed in this case.
void print(std::ostream & ostr);
/// Prints all the types (as reported by the underlying database)
/// to the supplied output stream.
private:
void fillCTypes();
void fillSQLTypes();
DataTypeMap _cDataTypes;
DataTypeMap _sqlDataTypes;
TypeInfoVec _typeInfo;
SQLHDBC * _pHDBC;
};
}
}
} // namespace Poco::Data::ODBC
#endif

View File

@ -0,0 +1,791 @@
//
// Unicode.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Unicode
//
// Definition of Unicode.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Unicode_INCLUDED
#define Data_ODBC_Unicode_INCLUDED
#include <cstring>
#include "Poco/Buffer.h"
#include "Poco/Exception.h"
#include "Poco/UnicodeConverter.h"
#ifndef SQL_NOUNICODEMAP
# define SQL_NOUNICODEMAP
#endif
#include <sqlext.h>
#include <sqltypes.h>
#include <sqlucode.h>
#if defined(POCO_OS_FAMILY_UNIX) && defined(UNICODE)
# define POCO_ODBC_UNICODE
# ifdef POCO_UNIXODBC
# define POCO_ODBC_UNICODE_UNIXODBC
# elif defined(POCO_IODBC)
# error "iODBC Unicode not supported"
# endif
#endif
namespace Poco
{
namespace Data
{
namespace ODBC
{
#if defined(POCO_PTR_IS_64_BIT) \
|| defined(POCO_OS_FAMILY_UNIX) // mkrivos - POCO_OS_FAMILY_UNIX doesn't compile with SQLPOINTER & SQLColAttribute()
typedef SQLLEN * NumAttrPtrType;
#else
typedef SQLPOINTER NumAttrPtrType;
#endif
SQLRETURN ODBC_API SQLColAttribute(
SQLHSTMT hstmt,
SQLUSMALLINT iCol,
SQLUSMALLINT iField,
SQLPOINTER pCharAttr,
SQLSMALLINT cbCharAttrMax,
SQLSMALLINT * pcbCharAttr,
NumAttrPtrType pNumAttr);
SQLRETURN ODBC_API SQLColAttributes(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLUSMALLINT fDescType,
SQLPOINTER rgbDesc,
SQLSMALLINT cbDescMax,
SQLSMALLINT * pcbDesc,
SQLLEN * pfDesc);
SQLRETURN ODBC_API SQLConnect(
SQLHDBC hdbc,
SQLCHAR * szDSN,
SQLSMALLINT cbDSN,
SQLCHAR * szUID,
SQLSMALLINT cbUID,
SQLCHAR * szAuthStr,
SQLSMALLINT cbAuthStr);
SQLRETURN ODBC_API SQLDescribeCol(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLCHAR * szColName,
SQLSMALLINT cbColNameMax,
SQLSMALLINT * pcbColName,
SQLSMALLINT * pfSqlType,
SQLULEN * pcbColDef,
SQLSMALLINT * pibScale,
SQLSMALLINT * pfNullable);
SQLRETURN ODBC_API SQLError(
SQLHENV henv,
SQLHDBC hdbc,
SQLHSTMT hstmt,
SQLCHAR * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg);
SQLRETURN ODBC_API SQLExecDirect(SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr);
SQLRETURN ODBC_API
SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue);
SQLRETURN ODBC_API SQLGetCursorName(SQLHSTMT hstmt, SQLCHAR * szCursor, SQLSMALLINT cbCursorMax, SQLSMALLINT * pcbCursor);
SQLRETURN ODBC_API SQLSetDescField(
SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, SQLPOINTER Value, SQLINTEGER BufferLength);
SQLRETURN ODBC_API SQLGetDescField(
SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue);
SQLRETURN ODBC_API SQLGetDescRec(
SQLHDESC hdesc,
SQLSMALLINT iRecord,
SQLCHAR * szName,
SQLSMALLINT cbNameMax,
SQLSMALLINT * pcbName,
SQLSMALLINT * pfType,
SQLSMALLINT * pfSubType,
SQLLEN * pLength,
SQLSMALLINT * pPrecision,
SQLSMALLINT * pScale,
SQLSMALLINT * pNullable);
SQLRETURN ODBC_API SQLGetDiagField(
SQLSMALLINT fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
SQLSMALLINT fDiagField,
SQLPOINTER rgbDiagInfo,
SQLSMALLINT cbDiagInfoMax,
SQLSMALLINT * pcbDiagInfo);
SQLRETURN ODBC_API SQLGetDiagRec(
SQLSMALLINT fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
SQLCHAR * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg);
SQLRETURN ODBC_API SQLPrepare(SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr);
SQLRETURN ODBC_API SQLSetConnectAttr(SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValue);
SQLRETURN ODBC_API SQLSetCursorName(SQLHSTMT hstmt, SQLCHAR * szCursor, SQLSMALLINT cbCursor);
SQLRETURN ODBC_API SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax);
SQLRETURN ODBC_API
SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue);
SQLRETURN ODBC_API SQLColumns(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName);
SQLRETURN ODBC_API SQLGetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam);
SQLRETURN ODBC_API
SQLGetInfo(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue);
SQLRETURN ODBC_API SQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType);
SQLRETURN ODBC_API SQLSetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam);
SQLRETURN ODBC_API SQLSpecialColumns(
SQLHSTMT hstmt,
SQLUSMALLINT fColType,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLUSMALLINT fScope,
SQLUSMALLINT fNullable);
SQLRETURN ODBC_API SQLStatistics(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLUSMALLINT fUnique,
SQLUSMALLINT fAccuracy);
SQLRETURN ODBC_API SQLTables(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szTableType,
SQLSMALLINT cbTableType);
SQLRETURN ODBC_API SQLDataSources(
SQLHENV henv,
SQLUSMALLINT fDirection,
SQLCHAR * szDSN,
SQLSMALLINT cbDSNMax,
SQLSMALLINT * pcbDSN,
SQLCHAR * szDescription,
SQLSMALLINT cbDescriptionMax,
SQLSMALLINT * pcbDescription);
SQLRETURN ODBC_API SQLDriverConnect(
SQLHDBC hdbc,
SQLHWND hwnd,
SQLCHAR * szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR * szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT * pcbConnStrOut,
SQLUSMALLINT fDriverCompletion);
SQLRETURN ODBC_API SQLBrowseConnect(
SQLHDBC hdbc,
SQLCHAR * szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR * szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT * pcbConnStrOut);
SQLRETURN ODBC_API SQLColumnPrivileges(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName);
SQLRETURN ODBC_API SQLForeignKeys(
SQLHSTMT hstmt,
SQLCHAR * szPkCatalogName,
SQLSMALLINT cbPkCatalogName,
SQLCHAR * szPkSchemaName,
SQLSMALLINT cbPkSchemaName,
SQLCHAR * szPkTableName,
SQLSMALLINT cbPkTableName,
SQLCHAR * szFkCatalogName,
SQLSMALLINT cbFkCatalogName,
SQLCHAR * szFkSchemaName,
SQLSMALLINT cbFkSchemaName,
SQLCHAR * szFkTableName,
SQLSMALLINT cbFkTableName);
SQLRETURN ODBC_API SQLNativeSql(
SQLHDBC hdbc, SQLCHAR * szSqlStrIn, SQLINTEGER cbSqlStrIn, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStrMax, SQLINTEGER * pcbSqlStr);
SQLRETURN ODBC_API SQLPrimaryKeys(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName);
SQLRETURN ODBC_API SQLProcedureColumns(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szProcName,
SQLSMALLINT cbProcName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName);
SQLRETURN ODBC_API SQLProcedures(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szProcName,
SQLSMALLINT cbProcName);
SQLRETURN ODBC_API SQLTablePrivileges(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName);
SQLRETURN ODBC_API SQLDrivers(
SQLHENV henv,
SQLUSMALLINT fDirection,
SQLCHAR * szDriverDesc,
SQLSMALLINT cbDriverDescMax,
SQLSMALLINT * pcbDriverDesc,
SQLCHAR * szDriverAttributes,
SQLSMALLINT cbDrvrAttrMax,
SQLSMALLINT * pcbDrvrAttr);
///
/// inlines
///
inline bool isString(SQLPOINTER pValue, SQLINTEGER length)
{
return (SQL_NTS == length || length > 0) && pValue;
}
inline SQLINTEGER stringLength(SQLPOINTER pValue, SQLINTEGER length)
{
if (SQL_NTS != length)
return length;
return (SQLINTEGER)std::strlen((const char *)pValue);
}
#if !defined(POCO_ODBC_UNICODE)
///
/// inlines
///
inline SQLRETURN SQLColAttribute(
SQLHSTMT hstmt,
SQLUSMALLINT iCol,
SQLUSMALLINT iField,
SQLPOINTER pCharAttr,
SQLSMALLINT cbCharAttrMax,
SQLSMALLINT * pcbCharAttr,
NumAttrPtrType pNumAttr)
{
return ::SQLColAttributeA(hstmt, iCol, iField, pCharAttr, cbCharAttrMax, pcbCharAttr, pNumAttr);
}
inline SQLRETURN SQLColAttributes(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLUSMALLINT fDescType,
SQLPOINTER rgbDesc,
SQLSMALLINT cbDescMax,
SQLSMALLINT * pcbDesc,
SQLLEN * pfDesc)
{
return ::SQLColAttributesA(hstmt, icol, fDescType, rgbDesc, cbDescMax, pcbDesc, pfDesc);
}
inline SQLRETURN SQLConnect(
SQLHDBC hdbc,
SQLCHAR * szDSN,
SQLSMALLINT cbDSN,
SQLCHAR * szUID,
SQLSMALLINT cbUID,
SQLCHAR * szAuthStr,
SQLSMALLINT cbAuthStr)
{
return ::SQLConnectA(hdbc, szDSN, cbDSN, szUID, cbUID, szAuthStr, cbAuthStr);
}
inline SQLRETURN SQLDescribeCol(
SQLHSTMT hstmt,
SQLUSMALLINT icol,
SQLCHAR * szColName,
SQLSMALLINT cbColNameMax,
SQLSMALLINT * pcbColName,
SQLSMALLINT * pfSqlType,
SQLULEN * pcbColDef,
SQLSMALLINT * pibScale,
SQLSMALLINT * pfNullable)
{
return ::SQLDescribeColA(hstmt, icol, szColName, cbColNameMax, pcbColName, pfSqlType, pcbColDef, pibScale, pfNullable);
}
inline SQLRETURN SQLError(
SQLHENV henv,
SQLHDBC hdbc,
SQLHSTMT hstmt,
SQLCHAR * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg)
{
throw Poco::NotImplementedException("SQLError is obsolete. "
"Use SQLGetDiagRec instead.");
}
inline SQLRETURN SQLExecDirect(SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr)
{
return ::SQLExecDirectA(hstmt, szSqlStr, cbSqlStr);
}
inline SQLRETURN
SQLGetConnectAttr(SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue)
{
return ::SQLGetConnectAttrA(hdbc, fAttribute, rgbValue, cbValueMax, pcbValue);
}
inline SQLRETURN SQLGetCursorName(SQLHSTMT hstmt, SQLCHAR * szCursor, SQLSMALLINT cbCursorMax, SQLSMALLINT * pcbCursor)
{
throw Poco::NotImplementedException("Not implemented");
}
inline SQLRETURN SQLSetDescField(
SQLHDESC DescriptorHandle, SQLSMALLINT RecNumber, SQLSMALLINT FieldIdentifier, SQLPOINTER Value, SQLINTEGER BufferLength)
{
return ::SQLSetDescField(DescriptorHandle, RecNumber, FieldIdentifier, Value, BufferLength);
}
inline SQLRETURN SQLGetDescField(
SQLHDESC hdesc, SQLSMALLINT iRecord, SQLSMALLINT iField, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue)
{
return ::SQLGetDescFieldA(hdesc, iRecord, iField, rgbValue, cbValueMax, pcbValue);
}
inline SQLRETURN SQLGetDescRec(
SQLHDESC hdesc,
SQLSMALLINT iRecord,
SQLCHAR * szName,
SQLSMALLINT cbNameMax,
SQLSMALLINT * pcbName,
SQLSMALLINT * pfType,
SQLSMALLINT * pfSubType,
SQLLEN * pLength,
SQLSMALLINT * pPrecision,
SQLSMALLINT * pScale,
SQLSMALLINT * pNullable)
{
return ::SQLGetDescRecA(hdesc, iRecord, szName, cbNameMax, pcbName, pfType, pfSubType, pLength, pPrecision, pScale, pNullable);
}
inline SQLRETURN SQLGetDiagField(
SQLSMALLINT fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
SQLSMALLINT fDiagField,
SQLPOINTER rgbDiagInfo,
SQLSMALLINT cbDiagInfoMax,
SQLSMALLINT * pcbDiagInfo)
{
return ::SQLGetDiagFieldA(fHandleType, handle, iRecord, fDiagField, rgbDiagInfo, cbDiagInfoMax, pcbDiagInfo);
}
inline SQLRETURN SQLGetDiagRec(
SQLSMALLINT fHandleType,
SQLHANDLE handle,
SQLSMALLINT iRecord,
SQLCHAR * szSqlState,
SQLINTEGER * pfNativeError,
SQLCHAR * szErrorMsg,
SQLSMALLINT cbErrorMsgMax,
SQLSMALLINT * pcbErrorMsg)
{
return ::SQLGetDiagRecA(fHandleType, handle, iRecord, szSqlState, pfNativeError, szErrorMsg, cbErrorMsgMax, pcbErrorMsg);
}
inline SQLRETURN SQLPrepare(SQLHSTMT hstmt, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStr)
{
return ::SQLPrepareA(hstmt, szSqlStr, cbSqlStr);
}
inline SQLRETURN SQLSetConnectAttr(SQLHDBC hdbc, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValue)
{
return ::SQLSetConnectAttrA(hdbc, fAttribute, rgbValue, cbValue);
}
inline SQLRETURN SQLSetCursorName(SQLHSTMT hstmt, SQLCHAR * szCursor, SQLSMALLINT cbCursor)
{
throw Poco::NotImplementedException("Not implemented");
}
inline SQLRETURN SQLSetStmtAttr(SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax)
{
return ::SQLSetStmtAttr(hstmt, fAttribute, rgbValue, cbValueMax);
}
inline SQLRETURN
SQLGetStmtAttr(SQLHSTMT hstmt, SQLINTEGER fAttribute, SQLPOINTER rgbValue, SQLINTEGER cbValueMax, SQLINTEGER * pcbValue)
{
return ::SQLGetStmtAttrA(hstmt, fAttribute, rgbValue, cbValueMax, pcbValue);
}
inline SQLRETURN SQLColumns(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName)
{
return ::SQLColumnsA(
hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, szColumnName, cbColumnName);
}
inline SQLRETURN SQLGetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLPOINTER pvParam)
{
return ::SQLGetConnectOptionA(hdbc, fOption, pvParam);
}
inline SQLRETURN
SQLGetInfo(SQLHDBC hdbc, SQLUSMALLINT fInfoType, SQLPOINTER rgbInfoValue, SQLSMALLINT cbInfoValueMax, SQLSMALLINT * pcbInfoValue)
{
return ::SQLGetInfoA(hdbc, fInfoType, rgbInfoValue, cbInfoValueMax, pcbInfoValue);
}
inline SQLRETURN SQLGetTypeInfo(SQLHSTMT StatementHandle, SQLSMALLINT DataType)
{
return ::SQLGetTypeInfoA(StatementHandle, DataType);
}
inline SQLRETURN SQLSetConnectOption(SQLHDBC hdbc, SQLUSMALLINT fOption, SQLULEN vParam)
{
return ::SQLSetConnectOptionA(hdbc, fOption, vParam);
}
inline SQLRETURN SQLSpecialColumns(
SQLHSTMT hstmt,
SQLUSMALLINT fColType,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLUSMALLINT fScope,
SQLUSMALLINT fNullable)
{
return ::SQLSpecialColumnsA(
hstmt, fColType, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, fScope, fNullable);
}
inline SQLRETURN SQLStatistics(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLUSMALLINT fUnique,
SQLUSMALLINT fAccuracy)
{
return ::SQLStatisticsA(
hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, fUnique, fAccuracy);
}
inline SQLRETURN SQLTables(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szTableType,
SQLSMALLINT cbTableType)
{
return ::SQLTablesA(
hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, szTableType, cbTableType);
}
inline SQLRETURN SQLDataSources(
SQLHENV henv,
SQLUSMALLINT fDirection,
SQLCHAR * szDSN,
SQLSMALLINT cbDSNMax,
SQLSMALLINT * pcbDSN,
SQLCHAR * szDescription,
SQLSMALLINT cbDescriptionMax,
SQLSMALLINT * pcbDescription)
{
return ::SQLDataSourcesA(henv, fDirection, szDSN, cbDSNMax, pcbDSN, szDescription, cbDescriptionMax, pcbDescription);
}
inline SQLRETURN SQLDriverConnect(
SQLHDBC hdbc,
SQLHWND hwnd,
SQLCHAR * szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR * szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT * pcbConnStrOut,
SQLUSMALLINT fDriverCompletion)
{
return ::SQLDriverConnectA(
hdbc, hwnd, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut, fDriverCompletion);
}
inline SQLRETURN SQLBrowseConnect(
SQLHDBC hdbc,
SQLCHAR * szConnStrIn,
SQLSMALLINT cbConnStrIn,
SQLCHAR * szConnStrOut,
SQLSMALLINT cbConnStrOutMax,
SQLSMALLINT * pcbConnStrOut)
{
return ::SQLBrowseConnectA(hdbc, szConnStrIn, cbConnStrIn, szConnStrOut, cbConnStrOutMax, pcbConnStrOut);
}
inline SQLRETURN SQLColumnPrivileges(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName)
{
return ::SQLColumnPrivilegesA(
hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName, szColumnName, cbColumnName);
}
inline SQLRETURN SQLForeignKeys(
SQLHSTMT hstmt,
SQLCHAR * szPkCatalogName,
SQLSMALLINT cbPkCatalogName,
SQLCHAR * szPkSchemaName,
SQLSMALLINT cbPkSchemaName,
SQLCHAR * szPkTableName,
SQLSMALLINT cbPkTableName,
SQLCHAR * szFkCatalogName,
SQLSMALLINT cbFkCatalogName,
SQLCHAR * szFkSchemaName,
SQLSMALLINT cbFkSchemaName,
SQLCHAR * szFkTableName,
SQLSMALLINT cbFkTableName)
{
return ::SQLForeignKeysA(
hstmt,
szPkCatalogName,
cbPkCatalogName,
szPkSchemaName,
cbPkSchemaName,
szPkTableName,
cbPkTableName,
szFkCatalogName,
cbFkCatalogName,
szFkSchemaName,
cbFkSchemaName,
szFkTableName,
cbFkTableName);
}
inline SQLRETURN SQLNativeSql(
SQLHDBC hdbc, SQLCHAR * szSqlStrIn, SQLINTEGER cbSqlStrIn, SQLCHAR * szSqlStr, SQLINTEGER cbSqlStrMax, SQLINTEGER * pcbSqlStr)
{
return ::SQLNativeSqlA(hdbc, szSqlStrIn, cbSqlStrIn, szSqlStr, cbSqlStrMax, pcbSqlStr);
}
inline SQLRETURN SQLPrimaryKeys(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName)
{
return ::SQLPrimaryKeysA(hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName);
}
inline SQLRETURN SQLProcedureColumns(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szProcName,
SQLSMALLINT cbProcName,
SQLCHAR * szColumnName,
SQLSMALLINT cbColumnName)
{
return ::SQLProcedureColumnsA(
hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szProcName, cbProcName, szColumnName, cbColumnName);
}
inline SQLRETURN SQLProcedures(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szProcName,
SQLSMALLINT cbProcName)
{
return ::SQLProceduresA(hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szProcName, cbProcName);
}
inline SQLRETURN SQLTablePrivileges(
SQLHSTMT hstmt,
SQLCHAR * szCatalogName,
SQLSMALLINT cbCatalogName,
SQLCHAR * szSchemaName,
SQLSMALLINT cbSchemaName,
SQLCHAR * szTableName,
SQLSMALLINT cbTableName)
{
return ::SQLTablePrivilegesA(hstmt, szCatalogName, cbCatalogName, szSchemaName, cbSchemaName, szTableName, cbTableName);
}
inline SQLRETURN SQLDrivers(
SQLHENV henv,
SQLUSMALLINT fDirection,
SQLCHAR * szDriverDesc,
SQLSMALLINT cbDriverDescMax,
SQLSMALLINT * pcbDriverDesc,
SQLCHAR * szDriverAttributes,
SQLSMALLINT cbDrvrAttrMax,
SQLSMALLINT * pcbDrvrAttr)
{
return ::SQLDriversA(
henv, fDirection, szDriverDesc, cbDriverDescMax, pcbDriverDesc, szDriverAttributes, cbDrvrAttrMax, pcbDrvrAttr);
}
#endif // POCO_ODBC_UNICODE
}
}
} // namespace Poco::Data::ODBC
#endif // ODBC_Unicode_INCLUDED

View File

@ -0,0 +1,56 @@
//
// Unicode.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Unicode
//
// Definition of Unicode_UNIX.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Unicode_UNIX_INCLUDED
#define Data_ODBC_Unicode_UNIX_INCLUDED
namespace Poco
{
namespace Data
{
namespace ODBC
{
void makeUTF16(SQLCHAR * pSQLChar, SQLINTEGER length, std::string & target);
/// Utility function for conversion from UTF-8 to UTF-16
inline void makeUTF16(SQLCHAR * pSQLChar, SQLSMALLINT length, std::string & target)
/// Utility function for conversion from UTF-8 to UTF-16.
{
makeUTF16(pSQLChar, (SQLINTEGER)length, target);
}
void makeUTF8(Poco::Buffer<SQLWCHAR> & buffer, SQLINTEGER length, SQLPOINTER pTarget, SQLINTEGER targetLength);
/// Utility function for conversion from UTF-16 to UTF-8.
inline void makeUTF8(Poco::Buffer<SQLWCHAR> & buffer, int length, SQLPOINTER pTarget, SQLSMALLINT targetLength)
/// Utility function for conversion from UTF-16 to UTF-8.
{
makeUTF8(buffer, length, pTarget, (SQLINTEGER)targetLength);
}
}
}
} // namespace Poco::Data::ODBC
#endif // Data_ODBC_Unicode_UNIX_INCLUDED

View File

@ -0,0 +1,62 @@
//
// Unicode.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Unicode
//
// Definition of Unicode_WIN32.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Unicode_WIN32_INCLUDED
#define Data_ODBC_Unicode_WIN32_INCLUDED
namespace Poco
{
namespace Data
{
namespace ODBC
{
inline void makeUTF16(SQLCHAR * pSQLChar, SQLINTEGER length, std::wstring & target)
/// Utility function for conversion from UTF-8 to UTF-16
{
int len = length;
if (SQL_NTS == len)
len = (int)std::strlen((const char *)pSQLChar);
UnicodeConverter::toUTF16((const char *)pSQLChar, len, target);
}
inline void makeUTF8(Poco::Buffer<wchar_t> & buffer, SQLINTEGER length, SQLPOINTER pTarget, SQLINTEGER targetLength)
/// Utility function for conversion from UTF-16 to UTF-8. Length is in bytes.
{
if (buffer.sizeBytes() < length)
throw InvalidArgumentException("Specified length exceeds available length.");
else if ((length % 2) != 0)
throw InvalidArgumentException("Length must be an even number.");
length /= sizeof(wchar_t);
std::string result;
UnicodeConverter::toUTF8(buffer.begin(), length, result);
std::memset(pTarget, 0, targetLength);
std::strncpy((char *)pTarget, result.c_str(), result.size() < targetLength ? result.size() : targetLength);
}
}
}
} // namespace Poco::Data::ODBC
#endif // Data_ODBC_Unicode_WIN32_INCLUDED

View File

@ -0,0 +1,224 @@
//
// Utility.h
//
// Library: Data/ODBC
// Package: ODBC
// Module: Utility
//
// Definition of Utility.
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#ifndef Data_ODBC_Utility_INCLUDED
#define Data_ODBC_Utility_INCLUDED
#include <map>
#include <sstream>
#include <sqltypes.h>
#include "Poco/Data/Date.h"
#include "Poco/Data/ODBC/ODBC.h"
#include "Poco/Data/ODBC/TypeInfo.h"
#include "Poco/Data/Time.h"
#include "Poco/DateTime.h"
namespace Poco
{
namespace Data
{
namespace ODBC
{
class ODBC_API Utility
/// Various utility functions
{
public:
typedef std::map<std::string, std::string> DSNMap;
typedef DSNMap DriverMap;
static bool isError(SQLRETURN rc);
/// Returns true if return code is error
static DriverMap & drivers(DriverMap & driverMap);
/// Returns driver-attributes map of available ODBC drivers.
static DSNMap & dataSources(DSNMap & dsnMap);
/// Returns DSN-description map of available ODBC data sources.
template <typename MapType, typename KeyArgType, typename ValueArgType>
static typename MapType::iterator mapInsert(MapType & m, const KeyArgType & k, const ValueArgType & v)
/// Utility map "insert or replace" function (from S. Meyers: Effective STL, Item 24)
{
typename MapType::iterator lb = m.lower_bound(k);
if (lb != m.end() && !(m.key_comp()(k, lb->first)))
{
lb->second = v;
return lb;
}
else
{
typedef typename MapType::value_type MVT;
return m.insert(lb, MVT(k, v));
}
}
static int cDataType(int sqlDataType);
/// Returns C data type corresponding to supplied SQL data type.
static int sqlDataType(int cDataType);
/// Returns SQL data type corresponding to supplied C data type.
static void dateSync(Date & dt, const SQL_DATE_STRUCT & ts);
/// Transfers data from ODBC SQL_DATE_STRUCT to Poco::DateTime.
template <typename T, typename F>
static void dateSync(T & d, const F & ds)
/// Transfers data from ODBC SQL_DATE_STRUCT container to Poco::DateTime container.
{
std::size_t size = ds.size();
if (d.size() != size)
d.resize(size);
typename T::iterator dIt = d.begin();
typename F::const_iterator it = ds.begin();
typename F::const_iterator end = ds.end();
for (; it != end; ++it, ++dIt)
dateSync(*dIt, *it);
}
static void timeSync(Time & dt, const SQL_TIME_STRUCT & ts);
/// Transfers data from ODBC SQL_TIME_STRUCT to Poco::DateTime.
template <typename T, typename F>
static void timeSync(T & t, const F & ts)
/// Transfers data from ODBC SQL_TIME_STRUCT container to Poco::DateTime container.
{
std::size_t size = ts.size();
if (t.size() != size)
t.resize(size);
typename T::iterator dIt = t.begin();
typename F::const_iterator it = ts.begin();
typename F::const_iterator end = ts.end();
for (; it != end; ++it, ++dIt)
timeSync(*dIt, *it);
}
static void dateTimeSync(Poco::DateTime & dt, const SQL_TIMESTAMP_STRUCT & ts);
/// Transfers data from ODBC SQL_TIMESTAMP_STRUCT to Poco::DateTime.
template <typename T, typename F>
static void dateTimeSync(T & dt, const F & ts)
/// Transfers data from ODBC SQL_TIMESTAMP_STRUCT container to Poco::DateTime container.
{
std::size_t size = ts.size();
if (dt.size() != size)
dt.resize(size);
typename T::iterator dIt = dt.begin();
typename F::const_iterator it = ts.begin();
typename F::const_iterator end = ts.end();
for (; it != end; ++it, ++dIt)
dateTimeSync(*dIt, *it);
}
static void dateSync(SQL_DATE_STRUCT & ts, const Date & dt);
/// Transfers data from Poco::Data::Date to ODBC SQL_DATE_STRUCT.
template <typename C>
static void dateSync(std::vector<SQL_DATE_STRUCT> & ds, const C & d)
/// Transfers data from Poco::Data::Date vector to ODBC SQL_DATE_STRUCT container.
{
std::size_t size = d.size();
if (ds.size() != size)
ds.resize(size);
std::vector<SQL_DATE_STRUCT>::iterator dIt = ds.begin();
typename C::const_iterator it = d.begin();
typename C::const_iterator end = d.end();
for (; it != end; ++it, ++dIt)
dateSync(*dIt, *it);
}
static void timeSync(SQL_TIME_STRUCT & ts, const Time & dt);
/// Transfers data from Poco::Data::Time to ODBC SQL_TIME_STRUCT.
template <typename C>
static void timeSync(std::vector<SQL_TIME_STRUCT> & ts, const C & t)
/// Transfers data from Poco::Data::Time container to ODBC SQL_TIME_STRUCT vector.
{
std::size_t size = t.size();
if (ts.size() != size)
ts.resize(size);
std::vector<SQL_TIME_STRUCT>::iterator tIt = ts.begin();
typename C::const_iterator it = t.begin();
typename C::const_iterator end = t.end();
for (; it != end; ++it, ++tIt)
timeSync(*tIt, *it);
}
static void dateTimeSync(SQL_TIMESTAMP_STRUCT & ts, const Poco::DateTime & dt);
/// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT.
template <typename C>
static void dateTimeSync(std::vector<SQL_TIMESTAMP_STRUCT> & ts, const C & dt)
/// Transfers data from Poco::DateTime to ODBC SQL_TIMESTAMP_STRUCT.
{
std::size_t size = dt.size();
if (ts.size() != size)
ts.resize(size);
std::vector<SQL_TIMESTAMP_STRUCT>::iterator tIt = ts.begin();
typename C::const_iterator it = dt.begin();
typename C::const_iterator end = dt.end();
for (; it != end; ++it, ++tIt)
dateTimeSync(*tIt, *it);
}
private:
static const TypeInfo _dataTypes;
/// C <==> SQL data type mapping
};
///
/// inlines
///
inline bool Utility::isError(SQLRETURN rc)
{
return (0 != (rc & (~1)));
}
inline int Utility::cDataType(int sqlDataType)
{
return _dataTypes.cDataType(sqlDataType);
}
inline int Utility::sqlDataType(int cDataType)
{
return _dataTypes.sqlDataType(cDataType);
}
inline void Utility::dateSync(Date & d, const SQL_DATE_STRUCT & ts)
{
d.assign(ts.year, ts.month, ts.day);
}
inline void Utility::timeSync(Time & t, const SQL_TIME_STRUCT & ts)
{
t.assign(ts.hour, ts.minute, ts.second);
}
}
}
} // namespace Poco::Data::ODBC
#endif

View File

@ -0,0 +1,529 @@
//
// Binder.cpp
//
// Library: Data/ODBC
// Package: ODBC
// Module: Binder
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Data/ODBC/Binder.h"
#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/Connector.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/DateTime.h"
#include "Poco/Exception.h"
#include <sql.h>
namespace Poco {
namespace Data {
namespace ODBC {
Binder::Binder(const StatementHandle& rStmt,
std::size_t maxFieldSize,
Binder::ParameterBinding dataBinding,
TypeInfo* pDataTypes):
_rStmt(rStmt),
_paramBinding(dataBinding),
_pTypeInfo(pDataTypes),
_paramSetSize(0),
_maxFieldSize(maxFieldSize)
{
}
Binder::~Binder()
{
freeMemory();
}
void Binder::freeMemory()
{
LengthPtrVec::iterator itLen = _lengthIndicator.begin();
LengthPtrVec::iterator itLenEnd = _lengthIndicator.end();
for(; itLen != itLenEnd; ++itLen) delete *itLen;
LengthVecVec::iterator itVecLen = _vecLengthIndicator.begin();
LengthVecVec::iterator itVecLenEnd = _vecLengthIndicator.end();
for (; itVecLen != itVecLenEnd; ++itVecLen) delete *itVecLen;
TimeMap::iterator itT = _times.begin();
TimeMap::iterator itTEnd = _times.end();
for(; itT != itTEnd; ++itT) delete itT->first;
DateMap::iterator itD = _dates.begin();
DateMap::iterator itDEnd = _dates.end();
for(; itD != itDEnd; ++itD) delete itD->first;
TimestampMap::iterator itTS = _timestamps.begin();
TimestampMap::iterator itTSEnd = _timestamps.end();
for(; itTS != itTSEnd; ++itTS) delete itTS->first;
StringMap::iterator itStr = _strings.begin();
StringMap::iterator itStrEnd = _strings.end();
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
CharPtrVec::iterator itChr = _charPtrs.begin();
CharPtrVec::iterator endChr = _charPtrs.end();
for (; itChr != endChr; ++itChr) std::free(*itChr);
UTF16CharPtrVec::iterator itUTF16Chr = _utf16CharPtrs.begin();
UTF16CharPtrVec::iterator endUTF16Chr = _utf16CharPtrs.end();
for (; itUTF16Chr != endUTF16Chr; ++itUTF16Chr) std::free(*itUTF16Chr);
BoolPtrVec::iterator itBool = _boolPtrs.begin();
BoolPtrVec::iterator endBool = _boolPtrs.end();
for (; itBool != endBool; ++itBool) delete [] *itBool;
DateVecVec::iterator itDateVec = _dateVecVec.begin();
DateVecVec::iterator itDateVecEnd = _dateVecVec.end();
for (; itDateVec != itDateVecEnd; ++itDateVec) delete *itDateVec;
TimeVecVec::iterator itTimeVec = _timeVecVec.begin();
TimeVecVec::iterator itTimeVecEnd = _timeVecVec.end();
for (; itTimeVec != itTimeVecEnd; ++itTimeVec) delete *itTimeVec;
DateTimeVecVec::iterator itDateTimeVec = _dateTimeVecVec.begin();
DateTimeVecVec::iterator itDateTimeVecEnd = _dateTimeVecVec.end();
for (; itDateTimeVec != itDateTimeVecEnd; ++itDateTimeVec) delete *itDateTimeVec;
}
void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
{
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER) val.size();
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits, val.size());
if (isOutBound(dir))
{
getColumnOrParameterSize(pos, size);
char* pChar = (char*) std::calloc(size, sizeof(char));
pVal = (SQLPOINTER) pChar;
_outParams.insert(ParamMap::value_type(pVal, size));
_strings.insert(StringMap::value_type(pChar, const_cast<std::string*>(&val)));
}
else if (isInBound(dir))
{
pVal = (SQLPOINTER) val.c_str();
_inParams.insert(ParamMap::value_type(pVal, size));
}
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);
if (PB_AT_EXEC == _paramBinding)
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
_lengthIndicator.push_back(pLenIn);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_CHAR,
Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR,
(SQLUINTEGER) colSize,
0,
pVal,
(SQLINTEGER) size,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
}
}
void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir)
{
typedef UTF16String::value_type CharT;
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits);
if (isOutBound(dir))
{
getColumnOrParameterSize(pos, size);
CharT* pChar = (CharT*)std::calloc(size, 1);
pVal = (SQLPOINTER)pChar;
_outParams.insert(ParamMap::value_type(pVal, size));
_utf16Strings.insert(UTF16StringMap::value_type(pChar, const_cast<UTF16String*>(&val)));
}
else if (isInBound(dir))
{
pVal = (SQLPOINTER)val.c_str();
_inParams.insert(ParamMap::value_type(pVal, size));
}
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);
if (PB_AT_EXEC == _paramBinding)
{
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
}
_lengthIndicator.push_back(pLenIn);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT)pos + 1,
toODBCDirection(dir),
SQL_C_WCHAR,
SQL_WLONGVARCHAR,
(SQLUINTEGER)colSize,
0,
pVal,
(SQLINTEGER)size,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(std::string)");
}
}
void Binder::bind(std::size_t pos, const Date& val, Direction dir)
{
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT);
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
_lengthIndicator.push_back(pLenIn);
SQL_DATE_STRUCT* pDS = new SQL_DATE_STRUCT;
Utility::dateSync(*pDS, val);
_dates.insert(DateMap::value_type(pDS, const_cast<Date*>(&val)));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_TYPE_DATE, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_DATE,
SQL_TYPE_DATE,
colSize,
decDigits,
(SQLPOINTER) pDS,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(Date)");
}
}
void Binder::bind(std::size_t pos, const Time& val, Direction dir)
{
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIME_STRUCT);
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
_lengthIndicator.push_back(pLenIn);
SQL_TIME_STRUCT* pTS = new SQL_TIME_STRUCT;
Utility::timeSync(*pTS, val);
_times.insert(TimeMap::value_type(pTS, const_cast<Time*>(&val)));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_TYPE_TIME, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIME,
SQL_TYPE_TIME,
colSize,
decDigits,
(SQLPOINTER) pTS,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(Time)");
}
}
void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
{
SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT);
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = size;
_lengthIndicator.push_back(pLenIn);
SQL_TIMESTAMP_STRUCT* pTS = new SQL_TIMESTAMP_STRUCT;
Utility::dateTimeSync(*pTS, val);
_timestamps.insert(TimestampMap::value_type(pTS, const_cast<DateTime*>(&val)));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_TYPE_TIMESTAMP, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
toODBCDirection(dir),
SQL_C_TYPE_TIMESTAMP,
SQL_TYPE_TIMESTAMP,
colSize,
decDigits,
(SQLPOINTER) pTS,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter(DateTime)");
}
}
void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
{
if (isOutBound(dir) || !isInBound(dir))
throw NotImplementedException("NULL parameter type can only be inbound.");
_inParams.insert(ParamMap::value_type(SQLPOINTER(0), SQLINTEGER(0)));
SQLLEN* pLenIn = new SQLLEN;
*pLenIn = SQL_NULL_DATA;
_lengthIndicator.push_back(pLenIn);
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
SQL_PARAM_INPUT,
SQL_C_STINYINT,
Utility::sqlDataType(SQL_C_STINYINT),
colSize,
decDigits,
0,
0,
_lengthIndicator.back())))
{
throw StatementException(_rStmt, "SQLBindParameter()");
}
}
std::size_t Binder::parameterSize(SQLPOINTER pAddr) const
{
ParamMap::const_iterator it = _inParams.find(pAddr);
if (it != _inParams.end()) return it->second;
it = _outParams.find(pAddr);
if (it != _outParams.end()) return it->second;
throw NotFoundException("Requested data size not found.");
}
void Binder::bind(std::size_t pos, const char* const &pVal, Direction dir)
{
throw NotImplementedException("char* binding not implemented, Use std::string instead.");
}
SQLSMALLINT Binder::toODBCDirection(Direction dir) const
{
bool in = isInBound(dir);
bool out = isOutBound(dir);
SQLSMALLINT ioType = SQL_PARAM_TYPE_UNKNOWN;
if (in && out) ioType = SQL_PARAM_INPUT_OUTPUT;
else if(in) ioType = SQL_PARAM_INPUT;
else if(out) ioType = SQL_PARAM_OUTPUT;
else throw Poco::IllegalStateException("Binder not bound (must be [in] OR [out]).");
return ioType;
}
void Binder::synchronize()
{
if (_dates.size())
{
DateMap::iterator it = _dates.begin();
DateMap::iterator end = _dates.end();
for(; it != end; ++it)
Utility::dateSync(*it->second, *it->first);
}
if (_times.size())
{
TimeMap::iterator it = _times.begin();
TimeMap::iterator end = _times.end();
for(; it != end; ++it)
Utility::timeSync(*it->second, *it->first);
}
if (_timestamps.size())
{
TimestampMap::iterator it = _timestamps.begin();
TimestampMap::iterator end = _timestamps.end();
for(; it != end; ++it)
Utility::dateTimeSync(*it->second, *it->first);
}
if (_strings.size())
{
StringMap::iterator it = _strings.begin();
StringMap::iterator end = _strings.end();
for(; it != end; ++it)
it->second->assign(it->first, std::strlen(it->first));
}
}
void Binder::reset()
{
freeMemory();
LengthPtrVec().swap(_lengthIndicator);
_inParams.clear();
_outParams.clear();
_dates.clear();
_times.clear();
_timestamps.clear();
_strings.clear();
_dateVecVec.clear();
_timeVecVec.clear();
_dateTimeVecVec.clear();
_charPtrs.clear();
_boolPtrs.clear();
_containers.clear();
_paramSetSize = 0;
}
void Binder::getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
SQLSMALLINT& decDigits,
std::size_t actualSize)
{
// Not all drivers are equally willing to cooperate in this matter.
// Hence the funky flow control.
DynamicAny tmp;
bool found(false);
if (_pTypeInfo)
{
found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp);
if (found) colSize = tmp;
if (actualSize > colSize)
{
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
pos, actualSize, static_cast<long>(colSize)));
}
found = _pTypeInfo->tryGetInfo(cDataType, "MINIMUM_SCALE", tmp);
if (found)
{
decDigits = tmp;
return;
}
}
try
{
Parameter p(_rStmt, pos);
colSize = (SQLINTEGER) p.columnSize();
decDigits = (SQLSMALLINT) p.decimalDigits();
return;
}
catch (StatementException&)
{
}
try
{
ODBCMetaColumn c(_rStmt, pos);
colSize = (SQLINTEGER) c.length();
decDigits = (SQLSMALLINT) c.precision();
return;
}
catch (StatementException&)
{
}
// last check, just in case
if ((0 != colSize) && (actualSize > colSize))
{
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
pos, actualSize, static_cast<long>(colSize)));
}
// no success, set to zero and hope for the best
// (most drivers do not require these most of the times anyway)
colSize = 0;
decDigits = 0;
return;
}
void Binder::getColumnOrParameterSize(std::size_t pos, SQLINTEGER& size)
{
std::size_t colSize = 0;
std::size_t paramSize = 0;
try
{
ODBCMetaColumn col(_rStmt, pos);
colSize = col.length();
}
catch (StatementException&) { }
try
{
Parameter p(_rStmt, pos);
paramSize = p.columnSize();
}
catch (StatementException&)
{
size = DEFAULT_PARAM_SIZE;
//On Linux, PostgreSQL driver segfaults on SQLGetDescField, so this is disabled for now
}
if (colSize > 0 && paramSize > 0)
size = colSize < paramSize ? static_cast<SQLINTEGER>(colSize) : static_cast<SQLINTEGER>(paramSize);
else if (colSize > 0)
size = static_cast<SQLINTEGER>(colSize);
else if (paramSize > 0)
size = static_cast<SQLINTEGER>(paramSize);
if (size > _maxFieldSize) size = static_cast<SQLINTEGER>(_maxFieldSize);
}
void Binder::setParamSetSize(std::size_t length)
{
if (0 == _paramSetSize)
{
if (Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, SQL_IS_UINTEGER)) ||
Utility::isError(Poco::Data::ODBC::SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
throw StatementException(_rStmt, "SQLSetStmtAttr()");
_paramSetSize = static_cast<SQLINTEGER>(length);
}
}
} } } // namespace Poco::Data::ODBC

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