diff --git a/.editorconfig b/.editorconfig index ba49e3c2349..9edd602a17e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,7 @@ root = true [*] indent_style = tab indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.github/actions/adjust-snapshot-buildno/action.yml b/.github/actions/adjust-snapshot-buildno/action.yml new file mode 100644 index 00000000000..fba61ec7704 --- /dev/null +++ b/.github/actions/adjust-snapshot-buildno/action.yml @@ -0,0 +1,20 @@ +name: Adjust snapshot build number +description: Adjust snapshot build number + +runs: + using: composite + steps: + - id: adjust-snapshot-buildno + if: + github.repository == 'FirebirdSQL/firebird' && + (github.ref_type == 'branch' && + (github.ref_name == 'master' || + (startsWith(github.ref_name, 'v') && endsWith(github.ref_name, '-release')) + ) + ) || + false + shell: bash + run: | + sed -i'' -e "s/SuffixKind=\(.*\)/SuffixKind=\"$(echo ${{ github.sha }} | cut -c 1-7)\"/" src/misc/writeBuildNum.sh + mkdir gen + src/misc/writeBuildNum.sh rebuildHeader diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 236b53fe80f..32f01d8e77d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,169 +3,385 @@ name: CI on: [push, pull_request] jobs: - build: + + build-linux-ubuntu-x64-clang: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Adjust snapshot build number + uses: ./.github/actions/adjust-snapshot-buildno + + - name: Prepare + run: | + sudo apt-get install libtool-bin libtomcrypt1 libtomcrypt-dev libtommath1 libtommath-dev libicu-dev zlib1g-dev + + - name: Build + run: | + CC=clang CXX=clang++ ./autogen.sh --enable-binreloc --prefix=/opt/firebird + make -j4 + make dist + tar xzvf gen/Firebird-[0-9]*.tar.gz + (cd Firebird-[0-9]*; sudo ./install.sh -silent) + + - name: Upload installer + uses: actions/upload-artifact@main + with: + name: firebird-ubuntu-20.04-clang-x64 + path: gen/Firebird-[0-9]*.tar.gz + + build-linux-chroot: + name: build-linux-chroot-${{ matrix.arch }} + runs-on: ubuntu-22.04 + env: + ARCH_SUFFIX: ${{ (matrix.arch == 'x64' && 'amd64' || (matrix.arch == 'x86' && 'i686' || '')) }} + ARCH_BITS: ${{ (matrix.arch == 'x64' && '64' || (matrix.arch == 'x86' && '32' || '')) }} + + strategy: + fail-fast: false + matrix: + arch: + - x64 + - x86 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Adjust snapshot build number + uses: ./.github/actions/adjust-snapshot-buildno + + - name: Download and extract chroot environment + run: | + wget --no-verbose -O - https://github.com/FirebirdSQL/snapshots/releases/download/tools/chroot-${ARCH_BITS}-gcc.6.4.tar.xz | sudo tar -xJ + + - name: Build + run: | + sudo mkdir -p ${ARCH_BITS}-gcc.6.4/firebird + sudo ./start_chroot.sh <<"EOF" + cd /firebird + ./autogen.sh --prefix=/opt/firebird --enable-binreloc --with-builtin-tomcrypt --with-termlib=:libncurses.a + make -j4 + make dist + EOF + + - name: Upload installer + uses: actions/upload-artifact@main + with: + name: firebird-linux-${{ matrix.arch }} + path: gen/Firebird-[0-9]*.${{ env.ARCH_SUFFIX }}.tar.gz + + - name: Snapshot - prepare + id: snapshot_prepare + if: | + github.repository == 'FirebirdSQL/firebird' && + github.event.head_commit.message == 'increment build number' && + github.ref_name == 'v4.0-release' + run: | + echo "snapshot_name=v4.0" >> $GITHUB_OUTPUT + + - name: Snapshot - delete old assets + uses: mknejp/delete-release-assets@v1 + if: steps.snapshot_prepare.outputs.snapshot_name + with: + repository: FirebirdSQL/snapshots + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + tag: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + fail-if-no-release: false + fail-if-no-assets: false + assets: | + Firebird-*.${{ env.ARCH_SUFFIX }}.tar.gz + + - name: Snapshot - release + id: snapshot_release_try1 + uses: softprops/action-gh-release@v1 + if: steps.snapshot_prepare.outputs.snapshot_name + continue-on-error: true + with: + repository: FirebirdSQL/snapshots + name: Latest snapshots for ${{ steps.snapshot_prepare.outputs.snapshot_name }} + tag_name: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + prerelease: true + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + files: | + gen/Firebird-*.${{ env.ARCH_SUFFIX }}.tar.gz + + - name: Snapshot - release (retry) + uses: softprops/action-gh-release@v1 + if: | + steps.snapshot_prepare.outputs.snapshot_name && + steps.snapshot_release_try1.outcome == 'failure' + with: + repository: FirebirdSQL/snapshots + name: Latest snapshots for ${{ steps.snapshot_prepare.outputs.snapshot_name }} + tag_name: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + prerelease: true + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + files: | + gen/Firebird-*.${{ env.ARCH_SUFFIX }}.tar.gz + + build-alpine-x64: + runs-on: ubuntu-22.04 + container: alpine:3.14 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Prepare + run: apk update && apk --no-cache --update add build-base libtool git autoconf automake zlib-dev icu-dev ncurses-dev libedit-dev linux-headers tar sed + + - name: Adjust snapshot build number + uses: ./.github/actions/adjust-snapshot-buildno + + - name: Build + run: | + ./autogen.sh --enable-binreloc-threads --with-builtin-tommath --with-builtin-tomcrypt --prefix=/opt/firebird + make -j4 + make dist + tar xzvf gen/Firebird-[0-9]*.tar.gz + + - name: Upload installer + uses: actions/upload-artifact@main + with: + name: firebird-alpine-x64 + path: gen/Firebird-[0-9]*.tar.gz + + build-windows: runs-on: ${{ matrix.os }} - container: ${{ matrix.container }} + env: + VS_VERSION: ${{ (matrix.os == 'windows-2019' && '2019' || (matrix.os == 'windows-2022' && '2022' || '')) }} strategy: fail-fast: false matrix: - os: [macOS-latest, windows-2016, ubuntu-20.04] + os: + - windows-2022 + - windows-2019 platform: [x64, x86] - include: - - os: ubuntu-18.04 - platform: x64 - container: alpine - exclude: - - os: macOS-latest - platform: x86 - - os: ubuntu-20.04 - platform: x86 steps: - - uses: actions/checkout@v1 - with: - fetch-depth: 10 - - - name: Prepare (Linux) - if: matrix.os == 'ubuntu-20.04' && matrix.container != 'alpine' - run: | - sudo apt-get install libtool-bin libtomcrypt1 libtomcrypt-dev libtommath1 libtommath-dev libicu-dev zlib1g-dev - - - name: Build (Linux) - if: matrix.os == 'ubuntu-20.04' && matrix.container != 'alpine' - run: | - CC=clang CXX=clang++ ./autogen.sh --enable-binreloc --prefix=/opt/firebird - make -j4 - make dist - tar xzvf gen/Firebird-[0-9]*.tar.gz - (cd Firebird-[0-9]*; sudo ./install.sh -silent) - - - name: Prepare (Linux, Alpine) - if: matrix.os == 'ubuntu-18.04' && matrix.container == 'alpine' - run: apk update && apk --no-cache --update add build-base libtool git autoconf automake zlib-dev icu-dev ncurses-dev libedit-dev linux-headers tar - - - name: Build (Linux, Alpine) - if: matrix.os == 'ubuntu-18.04' && matrix.container == 'alpine' - run: | - ./autogen.sh --enable-binreloc-threads --with-builtin-tommath --with-builtin-tomcrypt --prefix=/opt/firebird - make -j4 - make dist - tar xzvf gen/Firebird-[0-9]*.tar.gz - - - name: Prepare (MacOS) - if: matrix.os == 'macOS-latest' - run: | - brew install automake libtool - export LIBTOOLIZE=glibtoolize - export LIBTOOL=glibtool - - mkdir extern/icu-macos - pushd extern/icu-macos - curl -OL https://github.com/unicode-org/icu/releases/download/release-63-2/icu4c-63_2-src.tgz - curl -OL https://github.com/unicode-org/icu/commit/24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch - tar xzf icu4c-63_2-src.tgz - ICU_INSTALL_PATH=`pwd`/install - cd icu/source - patch -p3 < ../../24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch - ./runConfigureICU MacOSX --prefix=$ICU_INSTALL_PATH - make -j4 - make install - install_name_tool -id @rpath/lib/libicuuc.dylib $ICU_INSTALL_PATH/lib/libicuuc.dylib - install_name_tool -id @rpath/lib/libicui18n.dylib $ICU_INSTALL_PATH/lib/libicui18n.dylib - install_name_tool -id @rpath/lib/libicudata.dylib $ICU_INSTALL_PATH/lib/libicudata.dylib - install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $ICU_INSTALL_PATH/lib/libicuuc.63.dylib - install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $ICU_INSTALL_PATH/lib/libicui18n.63.dylib - install_name_tool -change libicuuc.63.dylib @loader_path/libicuuc.63.dylib $ICU_INSTALL_PATH/lib/libicui18n.63.dylib - popd - mkdir -p gen/Release/firebird/lib - mkdir -p gen/Debug/firebird/lib - cp $ICU_INSTALL_PATH/lib/libicu{data,i18n,uc}.*dylib gen/Release/firebird/lib/ - cp $ICU_INSTALL_PATH/lib/libicu{data,i18n,uc}.*dylib gen/Debug/firebird/lib/ - - - name: Build (MacOS) - if: matrix.os == 'macOS-latest' - run: | - export LIBTOOLIZE=glibtoolize - export LIBTOOL=glibtool - - ICU_INSTALL_PATH=`pwd`/extern/icu-macos/install - - export C_INCLUDE_PATH="$ICU_INSTALL_PATH/include:$C_INCLUDE_PATH" - export CPLUS_INCLUDE_PATH="$ICU_INSTALL_PATH/include:$CPLUS_INCLUDE_PATH" - - LIBRARY_PATH="$ICU_INSTALL_PATH/lib:$LIBRARY_PATH" ./autogen.sh --with-builtin-tommath --with-builtin-tomcrypt - make -j4 - - (cd gen; make -B -f make.platform.postfix ICU_LOC="$ICU_INSTALL_PATH/lib/") - (cd gen; make -B -f Makefile.install) - - # Rename directory to make sure the build is relocatable. - mv gen gen2 - sudo installer -pkg gen2/Release/*.pkg -verbose -target / - - export FIREBIRD_LOCK=`pwd`/temp - echo "create database 't.fdb'; select '1' from rdb\$database; select _win1252 '2' from rdb\$database; select _utf8 '3' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql - - echo "create database 'localhost:/tmp/t.fdb' user sysdba password 'masterkey'; select '11' from rdb\$database; select _win1252 '22' from rdb\$database; select _utf8 '33' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql - - mv gen2 gen - mkdir gen/artifacts - mv gen/Release/*.pkg gen/artifacts - - - name: Prepare (Windows) - if: matrix.os == 'windows-2016' - shell: cmd - run: | - for /r %%i in (*.bat) do unix2dos "%%i" - - - name: Build (Windows) - if: matrix.os == 'windows-2016' - shell: cmd - env: - PLATFORM: ${{ matrix.platform }} - run: | - if "%PLATFORM%" == "x64" set FB_VS_ARCH=amd64 - if "%PLATFORM%" == "x64" set FB_PROCESSOR_ARCHITECTURE=AMD64 - if "%PLATFORM%" == "x64" set FB_OUTPUT_SUFFIX=x64 - if "%PLATFORM%" == "x86" set FB_VS_ARCH=x86 - if "%PLATFORM%" == "x86" set FB_PROCESSOR_ARCHITECTURE=x86 - if "%PLATFORM%" == "x86" set FB_OUTPUT_SUFFIX=win32 - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=%FB_VS_ARCH% - cd builds\win32 - run_all.bat JUSTBUILD - - - name: Upload (Linux) - if: matrix.os == 'ubuntu-20.04' && matrix.container != 'alpine' - uses: actions/upload-artifact@main - with: - name: firebird-linux-${{ matrix.platform }} - path: gen/Firebird-[0-9]*.tar.gz - - - name: Upload (Linux, Alpine) - if: matrix.os == 'ubuntu-18.04' && matrix.container == 'alpine' - uses: actions/upload-artifact@master - with: - name: firebird-linux-alpine - path: gen/Firebird-[0-9]*.tar.gz - - - name: Upload (MacOS) - if: matrix.os == 'macOS-latest' - uses: actions/upload-artifact@main - with: - name: firebird-macos - path: gen/artifacts - - - name: Upload (Windows x64) - if: matrix.os == 'windows-2016' && matrix.platform == 'x64' - uses: actions/upload-artifact@main - with: - name: firebird-windows-x64 - path: output_x64 - - - name: Upload (Windows x86) - if: matrix.os == 'windows-2016' && matrix.platform == 'x86' - uses: actions/upload-artifact@main - with: - name: firebird-windows-x86 - path: output_win32 + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Adjust snapshot build number + uses: ./.github/actions/adjust-snapshot-buildno + + - name: Prepare + shell: cmd + run: | + for /r %%i in (*.bat) do unix2dos "%%i" + + - name: Build + shell: cmd + env: + PLATFORM: ${{ matrix.platform }} + VS_SCRIPT: ${{ matrix.os == 'windows-2022' && 'C:\Program Files\Microsoft Visual Studio\%VS_VERSION%\Enterprise\Common7\Tools\VsDevCmd.bat' || 'C:\Program Files (x86)\Microsoft Visual Studio\%VS_VERSION%\Enterprise\Common7\Tools\VsDevCmd.bat' }} + run: | + if "%PLATFORM%" == "x64" set FB_VS_ARCH=amd64 + if "%PLATFORM%" == "x64" set FB_PROCESSOR_ARCHITECTURE=AMD64 + if "%PLATFORM%" == "x64" set FB_ARTIFACTS_DIR=output_x64 + if "%PLATFORM%" == "x86" set FB_VS_ARCH=x86 + if "%PLATFORM%" == "x86" set FB_PROCESSOR_ARCHITECTURE=x86 + if "%PLATFORM%" == "x86" set FB_ARTIFACTS_DIR=output_win32 + echo FB_ARTIFACTS_DIR=%FB_ARTIFACTS_DIR% >> %GITHUB_ENV% + call "%VS_SCRIPT%" -arch=%FB_VS_ARCH% + cd builds\win32 + call run_all.bat JUSTBUILD + + - name: Upload zip + uses: actions/upload-artifact@main + with: + name: firebird-windows-${{ matrix.platform }}-vs-${{ env.VS_VERSION }} + path: ${{ env.FB_ARTIFACTS_DIR }} + + build-macos: + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 10 + + - name: Adjust snapshot build number + uses: ./.github/actions/adjust-snapshot-buildno + + - name: Prepare - Install tools + run: | + brew install automake libtool ninja python-setuptools + + - name: Cache - libc++ install + id: cache-libcxx-install-macos + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-libcxx-install-13.0.1 + path: | + extern/libcxx-macos-install + + - name: Download libc++ sources + if: steps.cache-libcxx-install-macos.outputs.cache-hit != 'true' + run: | + mkdir extern/libcxx-macos + pushd extern/libcxx-macos + curl -OL https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.1/llvm-project-13.0.1.src.tar.xz + tar xJf llvm-project-13.0.1.src.tar.xz + popd + + - name: Build libc++ + if: steps.cache-libcxx-install-macos.outputs.cache-hit != 'true' + run: | + LIBCXX_BUILD_PATH=`pwd`/extern/libcxx-macos-build + LIBCXX_INSTALL_PATH=`pwd`/extern/libcxx-macos-install + mkdir $LIBCXX_BUILD_PATH + pushd extern/libcxx-macos/llvm-project-13.0.1.src + export MACOSX_DEPLOYMENT_TARGET=10.9 + cmake -G Ninja -S llvm -B $LIBCXX_BUILD_PATH \ + -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" \ + -DCMAKE_INSTALL_PREFIX=$LIBCXX_INSTALL_PATH \ + -DCMAKE_BUILD_TYPE=Release \ + -DLIBCXX_ENABLE_SHARED=false \ + -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=true + ninja -C $LIBCXX_BUILD_PATH cxx cxxabi + ninja -C $LIBCXX_BUILD_PATH install-cxx install-cxxabi + popd + + - name: Cache - libicu install + id: cache-libicu-install-macos + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-libicu-install-63.2 + path: | + extern/libicu-macos-install + + - name: Download and patch libicu sources + if: steps.cache-libicu-install-macos.outputs.cache-hit != 'true' + run: | + mkdir extern/libicu-macos + pushd extern/libicu-macos + curl -OL https://github.com/unicode-org/icu/releases/download/release-63-2/icu4c-63_2-src.tgz + curl -OL https://github.com/unicode-org/icu/commit/24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch + tar xzf icu4c-63_2-src.tgz + cd icu/source + patch -p3 < ../../24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch + popd + + - name: Build libicu + if: steps.cache-libicu-install-macos.outputs.cache-hit != 'true' + run: | + export LIBTOOLIZE=glibtoolize + export LIBTOOL=glibtool + export PATH="$(brew --prefix python@3.11)/bin:$PATH" + + LIBICU_INSTALL_PATH=`pwd`/extern/libicu-macos-install + pushd extern/libicu-macos/icu/source + ./runConfigureICU MacOSX --prefix=$LIBICU_INSTALL_PATH + make -j4 + make install + install_name_tool -id @rpath/lib/libicuuc.dylib $LIBICU_INSTALL_PATH/lib/libicuuc.dylib + install_name_tool -id @rpath/lib/libicui18n.dylib $LIBICU_INSTALL_PATH/lib/libicui18n.dylib + install_name_tool -id @rpath/lib/libicudata.dylib $LIBICU_INSTALL_PATH/lib/libicudata.dylib + install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $LIBICU_INSTALL_PATH/lib/libicuuc.63.dylib + install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $LIBICU_INSTALL_PATH/lib/libicui18n.63.dylib + install_name_tool -change libicuuc.63.dylib @loader_path/libicuuc.63.dylib $LIBICU_INSTALL_PATH/lib/libicui18n.63.dylib + popd + + - name: Build + run: | + export LIBTOOLIZE=glibtoolize + export LIBTOOL=glibtool + export PATH="$(brew --prefix python@3.11)/bin:$PATH" + + LIBCXX_INSTALL_PATH=`pwd`/extern/libcxx-macos-install + LIBICU_INSTALL_PATH=`pwd`/extern/libicu-macos-install + + mkdir -p gen/Release/firebird/lib + cp -R $LIBICU_INSTALL_PATH/lib/libicu{data,i18n,uc}.*dylib gen/Release/firebird/lib/ + + export C_INCLUDE_PATH="$LIBICU_INSTALL_PATH/include:`xcrun --show-sdk-path`/usr/include" + export CPLUS_INCLUDE_PATH="$LIBCXX_INSTALL_PATH/include/c++/v1:$LIBICU_INSTALL_PATH/include:`xcrun --show-sdk-path`/usr/include" + export LIBRARY_PATH="$LIBCXX_INSTALL_PATH/lib:$LIBICU_INSTALL_PATH/lib:$LIBRARY_PATH" + + ./autogen.sh --with-builtin-tommath --with-builtin-tomcrypt + make -j4 + + (cd gen; make -B -f make.platform.postfix ICU_LOC="$LIBICU_INSTALL_PATH/lib/") + (cd gen; make -B -f Makefile.install) + + # Rename directory to make sure the build is relocatable. + mv gen gen2 + sudo installer -pkg gen2/Release/*.pkg -verbose -target / + + export FIREBIRD_LOCK=`pwd`/temp + echo "create database 't.fdb'; select '1' from rdb\$database; select _win1252 '2' from rdb\$database; select _utf8 '3' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql + + echo "create database 'localhost:/tmp/t.fdb' user sysdba password 'masterkey'; select '11' from rdb\$database; select _win1252 '22' from rdb\$database; select _utf8 '33' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql + + mv gen2 gen + mkdir gen/artifacts + mv gen/Release/*.pkg gen/artifacts + + - name: Upload installer + uses: actions/upload-artifact@main + with: + name: firebird-macos + path: gen/artifacts + + - name: Snapshot - prepare + id: snapshot_prepare + if: | + github.repository == 'FirebirdSQL/firebird' && + github.event.head_commit.message == 'increment build number' && + github.ref_name == 'v4.0-release' + run: | + echo "snapshot_name=v4.0" >> $GITHUB_OUTPUT + + - name: Snapshot - delete old assets + uses: mknejp/delete-release-assets@v1 + if: steps.snapshot_prepare.outputs.snapshot_name + with: + repository: FirebirdSQL/snapshots + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + tag: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + fail-if-no-release: false + fail-if-no-assets: false + assets: | + Firebird-[0-9]*-x86_64.pkg + + - name: Snapshot - release + id: snapshot_release_try1 + uses: softprops/action-gh-release@v1 + if: steps.snapshot_prepare.outputs.snapshot_name + continue-on-error: true + with: + repository: FirebirdSQL/snapshots + name: Latest snapshots for ${{ steps.snapshot_prepare.outputs.snapshot_name }} + tag_name: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + prerelease: true + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + files: | + gen/artifacts/Firebird-[0-9]*-x86_64.pkg + + - name: Snapshot - release (retry) + uses: softprops/action-gh-release@v1 + if: | + steps.snapshot_prepare.outputs.snapshot_name && + steps.snapshot_release_try1.outcome == 'failure' + with: + repository: FirebirdSQL/snapshots + name: Latest snapshots for ${{ steps.snapshot_prepare.outputs.snapshot_name }} + tag_name: snapshot-${{ steps.snapshot_prepare.outputs.snapshot_name }} + prerelease: true + token: ${{ secrets.SNAPSHOT_RELEASE_TOKEN }} + files: | + gen/artifacts/Firebird-[0-9]*-x86_64.pkg diff --git a/.github/workflows/tzdata-update.yml b/.github/workflows/tzdata-update.yml index efe1e9b5ab2..fd253e1de41 100644 --- a/.github/workflows/tzdata-update.yml +++ b/.github/workflows/tzdata-update.yml @@ -9,8 +9,17 @@ jobs: if: github.repository == 'FirebirdSQL/firebird' runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + branch: + - master + - v4.0-release + steps: - uses: actions/checkout@v2 + with: + ref: ${{ matrix.branch }} - name: Checkout ICU run: git clone --depth 1 https://github.com/unicode-org/icu-data.git -b main /tmp/icu-checkout @@ -27,12 +36,16 @@ jobs: echo $VERSION > extern/icu/tzdata/version.txt extern/icu/tzdata/update.sh + echo "VERSION=$VERSION" >> $GITHUB_ENV - name: Create Pull Request uses: peter-evans/create-pull-request@v3.5.0 with: token: ${{ secrets.GITHUB_TOKEN }} - commit-message: Update tzdata. - title: Update tzdata. + commit-message: Update tzdata to version ${{ env.VERSION }}. + title: Update tzdata to version ${{ env.VERSION }}. assignees: asfernandes - branch: work/tzdata-update + branch: work/tzdata-update-${{ matrix.branch }} + base: ${{ matrix.branch }} + labels: | + type: task diff --git a/.gitignore b/.gitignore index 15acad6dab1..d930bd8d759 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ libtool src/dsql/parse.cpp .vscode/.browse.VC.db extern/decNumber/libdecFloat*.a +extern/int128/absl/numeric/libi128*.a /Makefile /src/include/gen/parse.h /src/include/gen/autoconfig.auto diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f62c5cf3a91..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,78 +0,0 @@ -matrix: - include: - # - os: osx - # osx_image: xcode9.2 # macOS 10.12 Sierra - # - os: osx - # osx_image: xcode11.2 # macOS 10.14 Mojave - - os: linux - -language: cpp - -notifications: - email: false - -sudo: required -dist: xenial - -install: - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sudo apt-get update - sudo apt-get install -y libtool-bin libtommath0 libtommath-dev libicu-dev zlib1g-dev - fi - -script: - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - ./autogen.sh --enable-binreloc --with-builtin-tomcrypt --prefix=/opt/firebird - make -j4 - make dist - tar xzvf gen/Firebird-[0-9]*.tar.gz - (cd Firebird-[0-9]*; sudo ./install.sh -silent) - fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - export LIBTOOLIZE=glibtoolize - export LIBTOOL=glibtool - - mkdir extern/icu-macos - pushd extern/icu-macos - curl -OL https://github.com/unicode-org/icu/releases/download/release-63-2/icu4c-63_2-src.tgz - curl -OL https://github.com/unicode-org/icu/commit/24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch - tar xzf icu4c-63_2-src.tgz - ICU_INSTALL_PATH=`pwd`/install - cd icu/source - patch -p3 < ../../24aeb9a5a5874f4ce5db912e30670ac3ae236971.patch - ./runConfigureICU MacOSX --prefix=$ICU_INSTALL_PATH - make -j4 - make install - install_name_tool -id @rpath/lib/libicuuc.dylib $ICU_INSTALL_PATH/lib/libicuuc.dylib - install_name_tool -id @rpath/lib/libicui18n.dylib $ICU_INSTALL_PATH/lib/libicui18n.dylib - install_name_tool -id @rpath/lib/libicudata.dylib $ICU_INSTALL_PATH/lib/libicudata.dylib - install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $ICU_INSTALL_PATH/lib/libicuuc.63.dylib - install_name_tool -change libicudata.63.dylib @loader_path/libicudata.63.dylib $ICU_INSTALL_PATH/lib/libicui18n.63.dylib - install_name_tool -change libicuuc.63.dylib @loader_path/libicuuc.63.dylib $ICU_INSTALL_PATH/lib/libicui18n.63.dylib - popd - mkdir -p gen/Release/firebird/lib - mkdir -p gen/Debug/firebird/lib - cp $ICU_INSTALL_PATH/lib/libicu{data,i18n,uc}.*dylib gen/Release/firebird/lib/ - cp $ICU_INSTALL_PATH/lib/libicu{data,i18n,uc}.*dylib gen/Debug/firebird/lib/ - - export C_INCLUDE_PATH="$ICU_INSTALL_PATH/include:$C_INCLUDE_PATH" - export CPLUS_INCLUDE_PATH="$ICU_INSTALL_PATH/include:$CPLUS_INCLUDE_PATH" - - LIBRARY_PATH="$ICU_INSTALL_PATH/lib:$LIBRARY_PATH" ./autogen.sh --with-builtin-tommath --with-builtin-tomcrypt - make -j4 - - (cd gen; make -B -f make.platform.postfix ICU_LOC="$ICU_INSTALL_PATH/lib/") - (cd gen; make -B -f Makefile.install) - - # Rename directory to make sure the build is relocatable. - mv gen gen2 - sudo installer -pkg gen2/Release/*.pkg -verbose -target / - - export FIREBIRD_LOCK=`pwd`/temp - echo "create database 't.fdb'; select '1' from rdb\$database; select _win1252 '2' from rdb\$database; select _utf8 '3' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql - - echo "create database 'localhost:/tmp/t.fdb' user sysdba password 'masterkey'; select '11' from rdb\$database; select _win1252 '22' from rdb\$database; select _utf8 '33' collate unicode from rdb\$database;" | /Library/Frameworks/Firebird.framework/Resources/bin/isql - fi diff --git a/.vscode/tasks.json b/.vscode/tasks.json index af551682d22..b22ca1fc747 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,13 +1,19 @@ { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format - "version": "0.1.0", - "command": "make", - "isShellCommand": true, - "args": [ - "TARGET=Debug", - "engine", - "-j9" - ], - "showOutput": "always" + "version": "2.0.0", + "tasks": [ + { + "label": "make", + "type": "shell", + "command": "make", + "args": [ + "TARGET=Debug", + "engine", + "-j7" + ], + "problemMatcher": [], + "group": "build" + } + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ce04515fc4..d00614d4ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,1211 @@ -# v4.0 Release Candidate 1 (planned) +# v4.0.6 + +## Improvements + +* [#8433](https://github.com/FirebirdSQL/firebird/pull/8433): Improve code of class `BePlusTree` + Contributor(s): Vlad Khorsun + +* [#8353](https://github.com/FirebirdSQL/firebird/issues/8353): Report unique usernames for `isc_info_user_names` + Contributor(s): Vlad Khorsun + +* [#8256](https://github.com/FirebirdSQL/firebird/issues/8256): `Win_sspi` plugin uses NTLM + Contributor(s): Vlad Khorsun + +* [#8161](https://github.com/FirebirdSQL/firebird/issues/8161): Cardinality estimation should use primary record versions only + Contributor(s): Vlad Khorsun + +## Bugfixes + +* [#8554](https://github.com/FirebirdSQL/firebird/issues/8554): Vulnerability GHSA-7qp6-hqxj-pjjp / ZDI-CAN-26486 + Contributor(s): Alexander Peshkov + +* [#8520](https://github.com/FirebirdSQL/firebird/issues/8520): Error in `iTransaction.getInfo()` on embedded connection + Contributor(s): Alexander Peshkov + +* [#8509](https://github.com/FirebirdSQL/firebird/issues/8509): "Error creating private namespace" message in _firebird.log_ + Contributor(s): Vlad Khorsun + +* [#8485](https://github.com/FirebirdSQL/firebird/issues/8485): Segfault on incorrect _databases.conf_ starting with sub-config (without line `alias=database_path`) + Contributor(s): Alexander Peshkov + +* [#8477](https://github.com/FirebirdSQL/firebird/issues/8477): Inheritance of `WINDOW` does not work + Contributor(s): Adriano dos Santos Fernandes + +* [#8449](https://github.com/FirebirdSQL/firebird/issues/8449): Races when server is closed during forced database shutdown + Contributor(s): Alexander Peshkov + +* [#8440](https://github.com/FirebirdSQL/firebird/issues/8440): Wrong result for `MINVALUE/MAXVALUE` with string arguments + Contributor(s): Dmitry Yemanov + +* [#8437](https://github.com/FirebirdSQL/firebird/issues/8437): Segfault when running query with `PARTITION BY` and subquery + Contributor(s): Adriano dos Santos Fernandes + +* [#8431](https://github.com/FirebirdSQL/firebird/pull/8431): Make sure only one error will be sent to not-started service + Contributor(s): Alexander Peshkov + +* [#8430](https://github.com/FirebirdSQL/firebird/issues/8430): Unstable error messages in services with trace enabled + Contributor(s): Artyom Abakumov + +* [#8429](https://github.com/FirebirdSQL/firebird/issues/8429): Segfault when already destroyed callback interface is used + Contributor(s): Alexander Peshkov + +* [#8417](https://github.com/FirebirdSQL/firebird/issues/8417): Negative statement ID in trace output + Contributor(s): Dmitry Yemanov + +* [#8403](https://github.com/FirebirdSQL/firebird/pull/8403): Fix potential deadlock when starting the encryption thread + Contributor(s): Alexander Peshkov + +* [#8389](https://github.com/FirebirdSQL/firebird/issues/8389): Unnecessary reload of the encryption plugin in the _SuperServer_ architecture + Contributor(s): Alexey Mochalov + +* [#8350](https://github.com/FirebirdSQL/firebird/issues/8350): Missing records inside a replicated database + Contributor(s): Vlad Khorsun + +* [#8336](https://github.com/FirebirdSQL/firebird/issues/8336): Error: "Invalid clumplet buffer structure: buffer end before end of clumplet - clumplet too long (77779)" when using trusted auth + Contributor(s): Vlad Khorsun + +* [#8324](https://github.com/FirebirdSQL/firebird/pull/8324): Make asynchronous replica re-initialization reliable + Contributor(s): Dmitry Yemanov + +* [#8304](https://github.com/FirebirdSQL/firebird/issues/8304): Wrong results using `MINVALUE/MAXVALUE` in join condition + Contributor(s): Adriano dos Santos Fernandes + +* [#8283](https://github.com/FirebirdSQL/firebird/issues/8283): Assert in `~thread_db()` due to not released page buffer + Contributor(s): Vlad Khorsun + +* [#8268](https://github.com/FirebirdSQL/firebird/pull/8268): Fix refetch header data from delta when database in backup lock + Contributor(s): Andrey Kravchenko + +* [#8255](https://github.com/FirebirdSQL/firebird/pull/8255): Catch possible stack overflow when preparing and compiling user statements + Contributor(s): Vlad Khorsun + +* [#8253](https://github.com/FirebirdSQL/firebird/issues/8253): Incorrect handling of non-ASCII object names in `CREATE MAPPING` statement + Contributor(s): Vlad Khorsun + +* [#8243](https://github.com/FirebirdSQL/firebird/pull/8243): Fix a bug where the shutdown handler could be called again + Contributor(s): Alexander Zhdanov + +* [#8238](https://github.com/FirebirdSQL/firebird/pull/8238): Fix using macro with regex in path parameter in _fbtrace.conf_ + Contributor(s): Alexander Peshkov, Artyom Ivanov + +* [#8237](https://github.com/FirebirdSQL/firebird/issues/8237): Database access error when _nbackup_ is starting + Contributor(s): Alexander Peshkov + +* [#8236](https://github.com/FirebirdSQL/firebird/issues/8236): Avoid "hangs" in `clock_gettime()` in tomcrypt's PRNG + Contributor(s): Alexander Peshkov + +* [#8222](https://github.com/FirebirdSQL/firebird/pull/8222): Fix a case of deleted memory modification + Contributor(s): Ilya Eremin + +* [#8221](https://github.com/FirebirdSQL/firebird/issues/8221): Crash when `MAKE_DBKEY()` is called with 0 or 1 arguments + Contributor(s): Vlad Khorsun + +* [#8219](https://github.com/FirebirdSQL/firebird/issues/8219): Database creation in 3.0.12, 4.0.5 and 5.0.1 is slower than in previous releases + Contributor(s): Adriano dos Santos Fernandes + +* [#8215](https://github.com/FirebirdSQL/firebird/issues/8215): Rare sporadic segfaults in test for core-6142 on Windows + Contributor(s): Alexander Peshkov + +* [#8069](https://github.com/FirebirdSQL/firebird/pull/8069): Add missing synchronization to cached vectors of known pages + Contributor(s): Dmitry Yemanov, Vlad Khorsun + + +# v4.0.5 + +## Improvements + +* [#8181](https://github.com/FirebirdSQL/firebird/pull/8181): Ensure the standalone CS listener on Linux uses the _SO_REUSEADDR_ socket option + Contributor(s): Dmitry Yemanov + +* [#8165](https://github.com/FirebirdSQL/firebird/pull/8165): Added shutdown handler for _Classic Server_ + Contributor(s): Alexander Zhdanov + +* [#8104](https://github.com/FirebirdSQL/firebird/issues/8104): More efficient evaluation of expressions like `RDB$DB_KEY <= ?` after mass delete + Contributor(s): Vlad Khorsun + +* [#8066](https://github.com/FirebirdSQL/firebird/issues/8066): Make protocol schemes case-insensitive + Contributor(s): Vlad Khorsun + +* [#8042](https://github.com/FirebirdSQL/firebird/issues/8042): Improve conflict resolution on replica when table have both primary and unique keys + Contributor(s): Vlad Khorsun + +* [#8030](https://github.com/FirebirdSQL/firebird/issues/8030): Better cardinality estimation when empty data pages exist + Contributor(s): Vlad Khorsun + +* [#8010](https://github.com/FirebirdSQL/firebird/issues/8010): Remove `gfix -cache` option + Contributor(s): Vlad Khorsun + +* [#7978](https://github.com/FirebirdSQL/firebird/issues/7978): Update Windows distributions with _zlib_ version 1.3.1 + Contributor(s): Vlad Khorsun + +* [#7928](https://github.com/FirebirdSQL/firebird/issues/7928): Make `TempCacheLimit` setting to be per-database, (not per-attachment) for _SuperClassic_ + Contributor(s): Vlad Khorsun + +* [#7854](https://github.com/FirebirdSQL/firebird/issues/7854): Performance issue with time zones + Contributor(s): Adriano dos Santos Fernandes, Vlad Khorsun + +## Bugfixes + +* [#8189](https://github.com/FirebirdSQL/firebird/issues/8189): Slow connection times with a lot of simultaneous connections and active trace session present + Contributor(s): Alexander Peshkov, Vlad Khorsun + +* [#8180](https://github.com/FirebirdSQL/firebird/issues/8180): Sometimes a system trace session is terminated spontaneously + Contributor(s): Artyom Abakumov + +* [#8178](https://github.com/FirebirdSQL/firebird/pull/8178): Fix boolean conversion to string inside `DataTypeUtil::makeFromList()` + Contributor(s): Dmitry Yemanov + +* [#8171](https://github.com/FirebirdSQL/firebird/issues/8171): Trace plugin unloaded if called method is not implemented + Contributor(s): Vlad Khorsun + +* [#8156](https://github.com/FirebirdSQL/firebird/issues/8156): Can not specify concrete IPv6 address in ES/EDS connection string + Contributor(s): Vlad Khorsun + +* [#8151](https://github.com/FirebirdSQL/firebird/issues/8151): Deadlock happens when run 'List Trace Sessions' service and there are many active trace sessions + Contributor(s): Vlad Khorsun + +* [#8150](https://github.com/FirebirdSQL/firebird/issues/8150): Process could attach to the deleted instance of shared memory + Contributor(s): Alexander Peshkov, Vlad Khorsun + +* [#8149](https://github.com/FirebirdSQL/firebird/issues/8149): The hung or crash could happen when connection fires _TRACE_EVENT_DETACH_ event and new trace session created concurrently + Contributor(s): Vlad Khorsun + +* [#8138](https://github.com/FirebirdSQL/firebird/issues/8138): Bugcheck when replicator state is changed concurrently + Contributor(s): Vlad Khorsun + +* [#8120](https://github.com/FirebirdSQL/firebird/issues/8120): `CAST` dies with numeric value is out of range error + Contributor(s): Vlad Khorsun + +* [#8114](https://github.com/FirebirdSQL/firebird/issues/8114): Segfault in connections pool during server shutdown + Contributor(s): Vlad Khorsun + +* [#8110](https://github.com/FirebirdSQL/firebird/issues/8110): Firebird crashes on Android API level 34 + Contributor(s): Vlad Khorsun + +* [#8108](https://github.com/FirebirdSQL/firebird/issues/8108): ICU 63.1 suppresses conversion errors + Contributor(s): Dmitry Kovalenko + +* [#8101](https://github.com/FirebirdSQL/firebird/issues/8101): Firebird crashes if a plugin factory returns _nullptr_ and no error in status + Contributor(s): Vlad Khorsun, Dimitry Sibiryakov + +* [#8089](https://github.com/FirebirdSQL/firebird/issues/8089): AV when attaching database while low of free memory + Contributor(s): Vlad Khorsun + +* [#8085](https://github.com/FirebirdSQL/firebird/issues/8085): Memory leak when executing a lot of different queries and `StatementTimeout > 0` + Contributor(s): Vlad Khorsun + +* [#8083](https://github.com/FirebirdSQL/firebird/issues/8083): AV when writting into internal trace log + Contributor(s): Vlad Khorsun + +* [#8079](https://github.com/FirebirdSQL/firebird/issues/8079): Engine could crash when executing some trigger(s) while another attachment modifies them + Contributor(s): Vlad Khorsun + +* [#8077](https://github.com/FirebirdSQL/firebird/issues/8077): Error "Too many recursion levels" does not stop execution of code that uses `ON DISCONNECT` trigger + Contributor(s): Alexander Peshkov, Vlad Khorsun + +* [#8058](https://github.com/FirebirdSQL/firebird/issues/8058): Replicated DDL changes do not set the correct grantor + Contributor(s): Dmitry Yemanov + +* [#8056](https://github.com/FirebirdSQL/firebird/issues/8056): Error "Too many temporary blobs" with blob_append when select a stored procedue using rows-clause + Contributor(s): Vlad Khorsun + +* [#8040](https://github.com/FirebirdSQL/firebird/issues/8040): Bugcheck 183 (wrong record length) could happen on replica database after UK violation on insert + Contributor(s): Vlad Khorsun + +* [#8039](https://github.com/FirebirdSQL/firebird/issues/8039): Segfault when opening damaged (last TIP is missing in `RDB$PAGES`, user's FW was OFF) database + Contributor(s): Alexander Peshkov + +* [#8027](https://github.com/FirebirdSQL/firebird/issues/8027): Broken _gbak_ statistics + Contributor(s): Alexander Peshkov + +* [#8011](https://github.com/FirebirdSQL/firebird/issues/8011): DECFLOAT error working with `INT128` in UDR + Contributor(s): Alexander Peshkov + +* [#8006](https://github.com/FirebirdSQL/firebird/issues/8006): Int128 datatype not supported in FB_MESSAGE macro + Contributor(s): Alexander Peshkov + +* [#8003](https://github.com/FirebirdSQL/firebird/issues/8003): _gbak_ v4 can't backup database in _ODS < 13_ + Contributor(s): Vlad Khorsun + +* [#7997](https://github.com/FirebirdSQL/firebird/issues/7997): Unexpected results when comparing integer with string containing value out of range of that integer datatype + Contributor(s): Alexander Peshkov + +* [#7993](https://github.com/FirebirdSQL/firebird/issues/7993): Unexpected results when using `CASE WHEN` with `RIGHT JOIN` + Contributor(s): Dmitry Yemanov + +* [#7985](https://github.com/FirebirdSQL/firebird/issues/7985): Hang in case of error when sweep thread is attaching to database (_Classic Server_) + Contributor(s): Alexander Peshkov + +* [#7979](https://github.com/FirebirdSQL/firebird/issues/7979): Hang when database with disconnect trigger using `MON$` tables is shutting down + Contributor(s): Alexander Peshkov + +* [#7969](https://github.com/FirebirdSQL/firebird/issues/7969): Characters are garbled when replicating fields with type `BLOB SUB_TYPE TEXT` if the character set of the connection and the field are different + Contributor(s): Dmitry Yemanov + +* [#7950](https://github.com/FirebirdSQL/firebird/issues/7950): Unable to restore database when .fbk was created on host with other ICU + Contributor(s): Alexander Peshkov + +* [#7927](https://github.com/FirebirdSQL/firebird/issues/7927): Some default values is set incorrectly for SC/CS architectures + Contributor(s): Vlad Khorsun + +* [#7917](https://github.com/FirebirdSQL/firebird/issues/7917): Hang in case of error when sweep thread is attaching to database + Contributor(s): Alexander Peshkov + +* [#7905](https://github.com/FirebirdSQL/firebird/issues/7905): Segfault during TPC initialization + Contributor(s): Alexander Peshkov + +* [#7899](https://github.com/FirebirdSQL/firebird/issues/7899): Inconsistent state of master-detail occurs after RE-connect + 'SET AUTODDL OFF' + 'drop ' which is ROLLED BACK + Contributor(s): Vlad Khorsun + +* [#7896](https://github.com/FirebirdSQL/firebird/issues/7896): _replication.log_ remains empty (and without any error in firebird.log) until concurrent FB instance is running under different account and generates segments on its master. Significant delay required after stop concurrent FB it in order allow first one to write in its replication log. + Contributor(s): Vlad Khorsun + +* [#7885](https://github.com/FirebirdSQL/firebird/issues/7885): Unstable error messages in services due to races related with service status vector + Contributor(s): Alexander Peshkov + +* [#7873](https://github.com/FirebirdSQL/firebird/issues/7873): Wrong memory buffer alignment and I/O buffer size when working in direct I/O mode + Contributor(s): Vlad Khorsun + +* [#7869](https://github.com/FirebirdSQL/firebird/issues/7869): _gbak_ can write uninitialized data into `RDB$RETURN_ARGUMENT` and `RDB$ARGUMENT_POSITION` fields + Contributor(s): Dmitry Kovalenko + +* [#7867](https://github.com/FirebirdSQL/firebird/issues/7867): Error "wrong page type" during garbage collection on v4.0.4 + Contributor(s): Ilya Eremin + +* [#7860](https://github.com/FirebirdSQL/firebird/issues/7860): Crash potentially caused by `BETWEEN` operator + Contributor(s): Vlad Khorsun + +* [#7851](https://github.com/FirebirdSQL/firebird/issues/7851): The skip of `att_functionarg_field_precision` does not check `RESTORE_format` + Contributor(s): Dmitry Kovalenko + +* [#7846](https://github.com/FirebirdSQL/firebird/issues/7846): FB4 can't backup/restore `INT128`-array + Contributor(s): Dmitry Kovalenko + +* [#7844](https://github.com/FirebirdSQL/firebird/issues/7844): Removing first column with `SET WIDTH` crashes _isql_ + Contributor(s): Adriano dos Santos Fernandes + +* [#7839](https://github.com/FirebirdSQL/firebird/issues/7839): Potential bug in `BETWEEN` operator + Contributor(s): Vlad Khorsun + +* [#7831](https://github.com/FirebirdSQL/firebird/issues/7831): Incorrect type of UDF-argument with array + Contributor(s): Dmitry Kovalenko + +* [#7827](https://github.com/FirebirdSQL/firebird/issues/7827): Problem using Python _firebird-driver_ with either Intel or M1 Mac builds with version 4.0.3 or 5.0+ + Contributor(s): Adriano dos Santos Fernandes + +* [#7809](https://github.com/FirebirdSQL/firebird/issues/7809): Crash "Fatal lock manager error: Process disappeared in LockManager::acquire_shmem" + Contributor(s): Alexander Peshkov + +* [#7800](https://github.com/FirebirdSQL/firebird/issues/7800): Default publication status is not preserved after backup/restore + Contributor(s): Dmitry Yemanov + +* [#7461](https://github.com/FirebirdSQL/firebird/issues/7461): Differences in field metadata descriptions between Firebird 2.5 and Firebird 4 + Contributor(s): Dmitry Yemanov + + +# v4.0.4 + +## Improvements + +* [#7818](https://github.com/FirebirdSQL/firebird/issues/7818): Extend `RDB$GET_CONTEXT('SYSTEM', '***')` with other info from `MON$ATTACHMENTS` + Contributor(s): Vlad Khorsun + +* [#7755](https://github.com/FirebirdSQL/firebird/issues/7755): Update Windows distribution with new _zlib_ version 1.3 (released 2023-08-18) + Contributor(s): Vlad Khorsun + +## Bugfixes + +* [#7817](https://github.com/FirebirdSQL/firebird/issues/7817): Memory leak is possible for UDF array arguments + Contributor(s): Dmitry Yemanov + +* [#7812](https://github.com/FirebirdSQL/firebird/issues/7812): Service backup does not work in multiple engines configuration + Contributor(s): Alexander Peshkov + +* [#7779](https://github.com/FirebirdSQL/firebird/issues/7779): Firebird 4.0.3 is constantly crashing with the same symptoms (fbclient.dll) + Contributor(s): Vlad Khorsun + +* [#7772](https://github.com/FirebirdSQL/firebird/issues/7772): Blob corruption in FB4.0.3 (embedded) + Contributor(s): Vlad Khorsun + +* [#7770](https://github.com/FirebirdSQL/firebird/issues/7770): Restore takes 25% more time vs 4.0.0 + Contributor(s): Vlad Khorsun + +* [#7766](https://github.com/FirebirdSQL/firebird/issues/7766): Firebird 4 Windows Installer omits DLLs during custom installation mode + Contributor(s): Paul Reeves + +* [#7762](https://github.com/FirebirdSQL/firebird/issues/7762): Crash on "Operating system call pthread_mutex_destroy failed. Error code 16" in log + Contributor(s): Alexander Peshkov + +* [#7761](https://github.com/FirebirdSQL/firebird/issues/7761): Regression when displaying line number of errors in _ISQL_ scripts + Contributor(s): Adriano dos Santos Fernandes + +* [#7759](https://github.com/FirebirdSQL/firebird/issues/7759): Routine calling overhead increased by factor 6 vs Firebird 4.0.0 + Contributor(s): Adriano dos Santos Fernandes + +* [#7747](https://github.com/FirebirdSQL/firebird/pull/7747): Fix an issue where the garbage collection in indexes and blobs is not performed in _VIO_backout_ + Contributor(s): Ilya Eremin + +* [#7745](https://github.com/FirebirdSQL/firebird/issues/7745): Error restoring database which has system domains in user table with BLOBs using embedded connection + Contributor(s): Alexander Peshkov + +* [#7738](https://github.com/FirebirdSQL/firebird/issues/7738): Crash on multiple connections/disconnections + Contributor(s): Alexander Peshkov + +* [#7737](https://github.com/FirebirdSQL/firebird/pull/7737): Fix cases where the precedence relationship between a record page and a blob page is not set + Contributor(s): Ilya Eremin + +* [#7731](https://github.com/FirebirdSQL/firebird/issues/7731): Display length of `TIMESTAMP WITH TIME ZONE` is wrong in dialect 1 + Contributor(s): Alexander Peshkov + +* [#7730](https://github.com/FirebirdSQL/firebird/issues/7730): Server ignores the size of `VARCHAR` when performing `SET BIND ... TO VARCHAR(N)` + Contributor(s): Alexander Peshkov + +* [#7729](https://github.com/FirebirdSQL/firebird/issues/7729): `SET BIND OF TS WITH TZ TO VARCHAR(128)` uses the date format of dialect 1 + Contributor(s): Alexander Peshkov + +* [#7727](https://github.com/FirebirdSQL/firebird/issues/7727): Index for integer column cannot be used when `INT128/DECFLOAT` value is being searched + Contributor(s): Dmitry Yemanov + +* [#7723](https://github.com/FirebirdSQL/firebird/issues/7723): Wrong error message on login if the user doesn't exist and _WireCrypt_ is disabled + Contributor(s): Alexander Peshkov + +* [#7713](https://github.com/FirebirdSQL/firebird/issues/7713): `FOR SELECT` statement can not see any changes made inside the `DO` block + Contributor(s): Vlad Khorsun + +* [#7691](https://github.com/FirebirdSQL/firebird/issues/7691): `WITH CALLER PRIVILEGES` has no effect in triggers + Contributor(s): Alexander Peshkov + +* [#7480](https://github.com/FirebirdSQL/firebird/issues/7480): Firebird server stops accepting new connections after some time + Contributor(s): Alexander Peshkov + + +# v4.0.3 + +## Improvements + +* [#7542](https://github.com/FirebirdSQL/firebird/issues/7542): Compiler warnings raise when build cloop-generated _Firebird.pas_ in RAD Studio 11.3 + Contributor(s): Vlad Khorsun + +* [#7539](https://github.com/FirebirdSQL/firebird/issues/7539): `RDB$GET/SET_CONTEXT()`: enclosing in apostrophes or double quotes of a missed namespace/variable will made output more readable + Contributor(s): Vlad Khorsun + +* [#7494](https://github.com/FirebirdSQL/firebird/issues/7494): Avoid non necessary index reads + Contributor(s): Vlad Khorsun + +* [#7468](https://github.com/FirebirdSQL/firebird/issues/7468): Add switch to control in guardian timeout before killing firebird server process + Contributor(s): Alex Peshkoff + +* [#7437](https://github.com/FirebirdSQL/firebird/issues/7437): Updated _zlib_ to version 1.2.13 (released 2022-10-13) + Contributor(s): Vlad Khorsun + +* [#7425](https://github.com/FirebirdSQL/firebird/issues/7425): Add REPLICA MODE to the output of the _isql_ `SHOW DATABASE` command + Contributor(s): Dmitry Yemanov + +* [#7418](https://github.com/FirebirdSQL/firebird/issues/7418): Improve reliability of plugin manager + Contributor(s): Alex Peshkoff + +* [#7294](https://github.com/FirebirdSQL/firebird/issues/7294): Allow FB-known macros in replication.conf + Contributor(s): Dmitry Yemanov + +* [#7259](https://github.com/FirebirdSQL/firebird/issues/7259): Remove TcpLoopbackFastPath and use of SIO_LOOPBACK_FAST_PATH + Contributor(s): Vlad Khorsun + +* [#7186](https://github.com/FirebirdSQL/firebird/issues/7186): _Nbackup_ `RDB$BACKUP_HISTORY` cleanup + Contributor(s): Vlad Khorsun + +## Bugfixes + +* [#7683](https://github.com/FirebirdSQL/firebird/issues/7683): `rdb$time_zone_util.transitions` returns an infinite result set + Contributor(s): Adriano dos Santos Fernandes + +* [#7670](https://github.com/FirebirdSQL/firebird/issues/7670): Cursor name can duplicate parameter and variable names in procedures and functions + Contributor(s): Adriano dos Santos Fernandes + +* [#7665](https://github.com/FirebirdSQL/firebird/issues/7665): Wrong result ordering in `LEFT JOIN` query + Contributor(s): Dmitry Yemanov + +* [#7664](https://github.com/FirebirdSQL/firebird/issues/7664): `DROP TABLE` executed for a table with big records may lead to "wrong page type" or "end of file" error + Contributor(s): Ilya Eremin + +* [#7662](https://github.com/FirebirdSQL/firebird/pull/7662): Peformance issues in prepare_update() + Contributor(s): Ilya Eremin + +* [#7661](https://github.com/FirebirdSQL/firebird/issues/7661): FB CS rejects new connections + Contributor(s): Vlad Khorsun + +* [#7651](https://github.com/FirebirdSQL/firebird/issues/7651): Unable to find savepoint in insert with nested query and returning clause in FB4 + Contributor(s): Dmitry Yemanov + +* [#7638](https://github.com/FirebirdSQL/firebird/issues/7638): `OVERRIDING USER VALUE` should be allowed for `GENERATED ALWAYS AS IDENTITY` + Contributor(s): Adriano dos Santos Fernandes + +* [#7627](https://github.com/FirebirdSQL/firebird/issues/7627): The size of the database with big records becomes bigger after backup/restore + Contributor(s): Ilya Eremin + +* [#7626](https://github.com/FirebirdSQL/firebird/issues/7626): Segfault when new attachment is done to shutting down database + Contributor(s): Alex Peshkoff + +* [#7611](https://github.com/FirebirdSQL/firebird/issues/7611): Can't backup/restore database from v3 to v4 with `SEC$USER_NAME` field longer than 10 characters + Contributor(s): Adriano dos Santos Fernandes + +* [#7610](https://github.com/FirebirdSQL/firebird/issues/7610): Uninitialized/random value assigned to `RDB$ROLES.RDB$SYSTEM PRIVILEGES` when restoring from FB3 backup + Contributor(s): Adriano dos Santos Fernandes + +* [#7605](https://github.com/FirebirdSQL/firebird/issues/7605): Disallow replication of `RDB$BACKUP_HISTORY` + Contributor(s): Dmitry Yemanov + +* [#7604](https://github.com/FirebirdSQL/firebird/issues/7604): PSQL functions do not convert the output BLOB to the connection character set + Contributor(s): Adriano dos Santos Fernandes + +* [#7603](https://github.com/FirebirdSQL/firebird/issues/7603): `BIN_SHR` on `INT128` does not apply sign extension + Contributor(s): Alex Peshkoff + +* [#7599](https://github.com/FirebirdSQL/firebird/issues/7599): Conversion of text with '\0' to `DECFLOAT` without errors + Contributor(s): Alex Peshkoff + +* [#7591](https://github.com/FirebirdSQL/firebird/issues/7591): `RELEASE SAVEPOINT ONLY` works incorrectly + Contributor(s): Dmitry Yemanov + +* [#7582](https://github.com/FirebirdSQL/firebird/issues/7582): Missing _isc_info_end_ in _Firebird.pas_ + Contributor(s): Alex Peshkoff + +* [#7579](https://github.com/FirebirdSQL/firebird/issues/7579): Cannot _nbackup_ a Firebird 3.0 database in Firebird 4.0 service with _engine12_ setup in _Providers_ + Contributor(s): Alex Peshkoff + +* [#7556](https://github.com/FirebirdSQL/firebird/issues/7556): FB Classic can hang attempting to attach DB while it is starting to encrypt/decrypt + Contributor(s): Alex Peshkoff + +* [#7555](https://github.com/FirebirdSQL/firebird/issues/7555): Invalid configuration for random fresh created database may be used after drop of another one with alias in _databases.conf_ + Contributor(s): Alex Peshkoff + +* [#7548](https://github.com/FirebirdSQL/firebird/issues/7548): `SET BIND OF TIMESTAMP WITH TIME ZONE TO CHAR` is not working with UTF8 connection charset + Contributor(s): Adriano dos Santos Fernandes + +* [#7537](https://github.com/FirebirdSQL/firebird/issues/7537): Wrong name in error message when unknown namespace is passed into `RDB$SET_CONTEXT` + Contributor(s): Vlad Khorsun + +* [#7535](https://github.com/FirebirdSQL/firebird/issues/7535): High CPU usage connect to Firebird 3 database using Firebird 4 Classic and SuperClassic service + Contributor(s): Vlad Khorsun + +* [#7517](https://github.com/FirebirdSQL/firebird/issues/7517): Successful compiling of procedure with wrong PLAN(s) used by some of its statement(s) + Contributor(s): Dmitry Yemanov + +* [#7514](https://github.com/FirebirdSQL/firebird/issues/7514): Segfault when detaching after deleting shadow on Classic + Contributor(s): Alex Peshkoff + +* [#7510](https://github.com/FirebirdSQL/firebird/issues/7510): Firebird regularly crashes soon after unload of _udr_engine_ plugin + Contributor(s): Alex Peshkoff + +* [#7501](https://github.com/FirebirdSQL/firebird/issues/7501): Precision of a standalone unit may differ from a packaged one in SQL dialect 1 + Contributor(s): Vlad Khorsun + +* [#7499](https://github.com/FirebirdSQL/firebird/issues/7499): Problem with restore (error: index cannot be used in the specified plan) + Contributor(s): Vlad Khorsun + +* [#7488](https://github.com/FirebirdSQL/firebird/issues/7488): Invalid real to string cast + Contributor(s): Artyom Abakumov, Alex Peshkoff + +* [#7484](https://github.com/FirebirdSQL/firebird/issues/7484): External engine `SYSTEM` not found + Contributor(s): Adriano dos Santos Fernandes + +* [#7482](https://github.com/FirebirdSQL/firebird/issues/7482): Result of `blob_append(null, null) (literal '')` is not shown + Contributor(s): Vlad Khorsun, Adriano dos Santos Fernandes + +* [#7473](https://github.com/FirebirdSQL/firebird/issues/7473): Client application crash when processing callback requests from server during _attachDatabase_ + Contributor(s): Alex Peshkoff + +* [#7472](https://github.com/FirebirdSQL/firebird/issues/7472): Window functions may lead to crash interacting with others exceptions + Contributor(s): Adriano dos Santos Fernandes + +* [#7467](https://github.com/FirebirdSQL/firebird/issues/7467): Simple SQL crashes Firebird: `select cast(rdb$db_key as integer) from rdb$database` + Contributor(s): Alex Peshkoff + +* [#7465](https://github.com/FirebirdSQL/firebird/issues/7465): Restore success illegally reported when _gbak_ was unable to activate all indices + Contributor(s): Alex Peshkoff + +* [#7456](https://github.com/FirebirdSQL/firebird/issues/7456): Impossible drop function in package with name of PSQL-function + Contributor(s): Adriano dos Santos Fernandes + +* [#7446](https://github.com/FirebirdSQL/firebird/issues/7446): Attempt to use data in destroyed transaction pool + Contributor(s): Alex Peshkoff + +* [#7444](https://github.com/FirebirdSQL/firebird/issues/7444): _isql_ crashes while executing test from QA suite + Contributor(s): Alex Peshkoff + +* [#7415](https://github.com/FirebirdSQL/firebird/issues/7415): _DbCrypt/KeyHolder_ plugins key changing issues on running server + Contributor(s): Alexey Mochalov + +* [#7402](https://github.com/FirebirdSQL/firebird/issues/7402): Server crashes on startup error + Contributor(s): Alex Peshkoff + +* [#7398](https://github.com/FirebirdSQL/firebird/issues/7398): Worst plan sort created to execute an indexed tables + Contributor(s): Dmitry Yemanov + +* [#7393](https://github.com/FirebirdSQL/firebird/issues/7393): Access violation after double fault in _attachDatabase()_ + Contributor(s): Alex Peshkoff + +* [#7387](https://github.com/FirebirdSQL/firebird/issues/7387): Unreliable replication behaviour in Linux Classic + Contributor(s): Dmitry Yemanov + +* [#7380](https://github.com/FirebirdSQL/firebird/issues/7380): Aliased blob variable with less restrictions makes text blob accept malformed string through `BLOB_APPEND` + Contributor(s): Vlad Khorsun + +* [#7379](https://github.com/FirebirdSQL/firebird/issues/7379): `BLOB_APPEND` with existing blob accepts malformed string + Contributor(s): Vlad Khorsun, Adriano dos Santos Fernandes + +* [#7371](https://github.com/FirebirdSQL/firebird/issues/7371): Various errors (fatal lock manager error, pthread_mutex_destroy failed) caused by races when opening/closing database + Contributor(s): Alex Peshkoff + +* [#7370](https://github.com/FirebirdSQL/firebird/issues/7370): Segfault under OOM conditions + Contributor(s): Alex Peshkoff + +* [#7369](https://github.com/FirebirdSQL/firebird/issues/7369): Build fails against _re2_ 20220601 + Contributor(s): Adriano dos Santos Fernandes + +* [#7365](https://github.com/FirebirdSQL/firebird/issues/7365): Client side aliases do not work in _databases.conf_ + Contributor(s): Alex Peshkoff + +* [#7361](https://github.com/FirebirdSQL/firebird/issues/7361): Broken compacting of trace config storage + Contributor(s): Alex Peshkoff + +* [#7359](https://github.com/FirebirdSQL/firebird/issues/7359): Querying to list the running trace sessions can fail if two service API calls was done before it for a short time (Linux specifics) + Contributor(s): Alex Peshkoff + +* [#7357](https://github.com/FirebirdSQL/firebird/issues/7357): Lock manager error when connect a Firebird 3.0 database more than once using SuperClassic Firebird 4.0 service + Contributor(s): Alex Peshkoff + +* [#7349](https://github.com/FirebirdSQL/firebird/issues/7349): Contradictory licensing/distribution statements in several charset-support files + Contributor(s): Mark Rotteveel + +* [#7314](https://github.com/FirebirdSQL/firebird/issues/7314): Multitreaded activating indices restarts server process + Contributor(s): Vlad Khorsun + +* [#7298](https://github.com/FirebirdSQL/firebird/issues/7298): Unreliable info result parsing + Contributor(s): Alex Peshkoff + +* [#7296](https://github.com/FirebirdSQL/firebird/issues/7296): During shutdown _op_disconnect_ may be sent to invalid handle + Contributor(s): Alex Peshkoff + +* [#7295](https://github.com/FirebirdSQL/firebird/issues/7295): Unexpected message 'Error reading data from the connection' when _fbtracemgr_ is closed using Ctrl-C + Contributor(s): Alex Peshkoff + +* [#7283](https://github.com/FirebirdSQL/firebird/issues/7283): Suspicious error message during install + Contributor(s): Alex Peshkoff + +* [#7276](https://github.com/FirebirdSQL/firebird/issues/7276): Firebird 4 literal with `CONTAINING` crashes server + Contributor(s): Vlad Khorsun + +* [#7271](https://github.com/FirebirdSQL/firebird/issues/7271): Sporadic server crash + Contributor(s): Vlad Khorsun + +* [#7262](https://github.com/FirebirdSQL/firebird/issues/7262): Repeated _op_batch_create_ leaks the batch + Contributor(s): Alex Peshkoff + +* [#7256](https://github.com/FirebirdSQL/firebird/issues/7256): Inconsistent conversion of non-TEXT blobs in `BLOB_APPEND` + Contributor(s): Vlad Khorsun + +* [#7255](https://github.com/FirebirdSQL/firebird/issues/7255): `READ COMMITTED READ CONSISTENCY` mode is broken in Classic / SuperClassic on Linux + Contributor(s): Alex Peshkoff + +* [#7233](https://github.com/FirebirdSQL/firebird/pull/7233): Slow database restore when Classic server mode is used + Contributor(s): Ilya Eremin + +* [#7241](https://github.com/FirebirdSQL/firebird/issues/7241): MacOS installer - firebird user is not created correctly if group already exists + Contributor(s): Jonathan Frutos + +* [#7239](https://github.com/FirebirdSQL/firebird/issues/7239): Connect using XNET protocol shows different exception (comparing to INET) if database is in the shutdown state + Contributor(s): Vlad Khorsun + +* [#6941](https://github.com/FirebirdSQL/firebird/issues/6941): Dummy (always true) conditions may change the join order + Contributor(s): Dmitry Yemanov + +* [#4729](https://github.com/FirebirdSQL/firebird/issues/4729): `GRANT` and `REVOKE UPDATE` (field) + Contributor(s): Alex Peshkoff + + +# v4.0.2 + +## New features + +* [#6983](https://github.com/FirebirdSQL/firebird/pull/6983): New built-in function BLOB_APPEND + Reference(s): [/doc/sql.extensions/README.blob_append.md](https://github.com/FirebirdSQL/firebird/raw/v4.0-release/doc/sql.extensions/README.blob_append.md) + Contributor(s): Vlad Khorsun + +## Improvements + +* [#7208](https://github.com/FirebirdSQL/firebird/issues/7208): Trace: provide performance statistics for DDL statement + Contributor(s): Vlad Khorsun + +* [#7194](https://github.com/FirebirdSQL/firebird/issues/7194): Make it possible to avoid _fbclient_ dependency in Pascal programs using _firebird.pas_ + Contributor(s): Alex Peshkoff + +* [#7168](https://github.com/FirebirdSQL/firebird/issues/7168): Ignore missing UDR libraries during restore + Contributor(s): Adriano dos Santos Fernandes + +* [#7161](https://github.com/FirebirdSQL/firebird/issues/7161): Update _zlib_ to version 1.2.12 + Contributor(s): Vlad Khorsun + +* [#7093](https://github.com/FirebirdSQL/firebird/issues/7093): Improve indexed lookup speed of strings when the last keys characters are part of collated contractions + Contributor(s): Adriano dos Santos Fernandes + +* [#7092](https://github.com/FirebirdSQL/firebird/issues/7092): Improve performance of `CURRENT_TIME` + Contributor(s): Adriano dos Santos Fernandes + +* [#7042](https://github.com/FirebirdSQL/firebird/issues/7042): `ON DISCONNECT` triggers are not executed during forced attachment shutdown + Contributor(s): Ilya Eremin + +* [#7041](https://github.com/FirebirdSQL/firebird/issues/7041): Firebird port for Apple M1 architecture + Contributor(s): Jonathan Frutos, Alex Peshkoff, Adriano dos Santos Fernandes + +* [#7038](https://github.com/FirebirdSQL/firebird/issues/7038): Improve performance of `STARTING WITH` with insensitive collations + Contributor(s): Adriano dos Santos Fernandes + +* [#6730](https://github.com/FirebirdSQL/firebird/issues/6730): Trace: provide ability to see `STATEMENT RESTART` events (or their count) + Contributor(s): Vlad Khorsun + +## Bugfixes + +* [#7243](https://github.com/FirebirdSQL/firebird/issues/7243): Some _UNICODE_ characters can lead to wrong `CONTAINING` evaluation when lower/upper uses different number of bytes in its encoding + Contributor(s): Adriano dos Santos Fernandes + +* [#7229](https://github.com/FirebirdSQL/firebird/issues/7229): `ALTER COLUMN DROP IDENTITY` does not reset generator name in metadata cache + Contributor(s): Adriano dos Santos Fernandes + +* [#7222](https://github.com/FirebirdSQL/firebird/issues/7222): Dependencies of packaged functions are not tracked + Contributor(s): Adriano dos Santos Fernandes + +* [#7217](https://github.com/FirebirdSQL/firebird/pull/7217): It's not allowed to execute DROP PACKAGE BODY for a package with a procedure even if a user has DROP ANY PACKAGE privilege + Contributor(s): Ilya Eremin + +* [#7204](https://github.com/FirebirdSQL/firebird/issues/7204): Segfault in _GBAK_ when restoring a broken backup file over the wire + Contributor(s): Alex Peshkoff + +* [#7202](https://github.com/FirebirdSQL/firebird/issues/7202): _ISQL -ch utf8_ (Windows only): either silently quits to OS or issues non-expected 'malformed string' when non-ASCII character occurs in the typed command + Contributor(s): Adriano dos Santos Fernandes + +* [#7200](https://github.com/FirebirdSQL/firebird/issues/7200): `DROP DATABASE` leads to hang if it is issued while database encrypting/decrypting is in progress + Contributor(s): Alex Peshkoff + +* [#7199](https://github.com/FirebirdSQL/firebird/issues/7199): Various errors (strange messages in firebird.log, segfaults) with high rate of attach/detach database operations + Contributor(s): Alex Peshkoff + +* [#7197](https://github.com/FirebirdSQL/firebird/issues/7197): Segfault in Linux CS after successful detach from database + Contributor(s): Alex Peshkoff + +* [#7194](https://github.com/FirebirdSQL/firebird/issues/7194): _GSTAT_ fails but returns 0 as error code if incorrect _databases.conf_ is used + Contributor(s): Alexey Mochalov + +* [#7188](https://github.com/FirebirdSQL/firebird/issues/7188): Memory leak in _fbclient_ when a multi-database transaction is used + Contributor(s): Alex Peshkoff + +* [#7184](https://github.com/FirebirdSQL/firebird/issues/7184): _GBAK_ output is not being flushed to disk + Contributor(s): Alex Peshkoff + +* [#7179](https://github.com/FirebirdSQL/firebird/issues/7179): Wrong error message - "string right truncation. expected length 30, actual 30." + Contributor(s): Adriano dos Santos Fernandes + +* [#7178](https://github.com/FirebirdSQL/firebird/issues/7178): DEFAULTed grants to PUBLIC must act as DEFAULTed to every user + Contributor(s): Roman Simakov + +* [#7176](https://github.com/FirebirdSQL/firebird/issues/7176): Incorrect error "Invalid token. Malformed string." with UNION + blob + non-UTF8 varchar + Contributor(s): Adriano dos Santos Fernandes + +* [#7167](https://github.com/FirebirdSQL/firebird/issues/7167): Incorrect transliteration of field names in constraint violation errors + Contributor(s): Adriano dos Santos Fernandes + +* [#7160](https://github.com/FirebirdSQL/firebird/issues/7160): Missing checkout in the trace manager when performing user mapping may cause server hang + Contributor(s): Alex Peshkoff + +* [#7150](https://github.com/FirebirdSQL/firebird/issues/7150): Replication not restarting after network failure + Contributor(s): Dmitry Yemanov + +* [#7147](https://github.com/FirebirdSQL/firebird/issues/7147): Problems with use of big timeout (or no timeout at all) in the trace service + Contributor(s): Alex Peshkoff + +* [#7141](https://github.com/FirebirdSQL/firebird/issues/7141): Services manager breaks long lines into 1023 bytes portions when using _isc_info_svc_line_ in _Service::query()_ + Contributor(s): Adriano dos Santos Fernandes + +* [#7140](https://github.com/FirebirdSQL/firebird/issues/7140): Wrong select result in case of special sort character + Contributor(s): Adriano dos Santos Fernandes + +* [#7139](https://github.com/FirebirdSQL/firebird/issues/7139): With multiple trace sessions user may receive trace events related to engine's requests + Contributor(s): Alex Peshkoff + +* [#7138](https://github.com/FirebirdSQL/firebird/issues/7138): Problems accessing FB4 database, copied from another host + Contributor(s): Alex Peshkoff + +* [#7135](https://github.com/FirebirdSQL/firebird/issues/7135): Firebird engine randomly fails when delivering mapping clear signal to other processes + Contributor(s): Alex Peshkoff + +* [#7134](https://github.com/FirebirdSQL/firebird/issues/7134): Database page errors directly after _GBAK_, dissappearing after some calls of _GFIX_ + Contributor(s): Vlad Khorsun + +* [#7129](https://github.com/FirebirdSQL/firebird/issues/7129): Cannot alter SQL SECURITY on package + Contributor(s): Alexey Mochalov + +* [#7128](https://github.com/FirebirdSQL/firebird/issues/7128): Incorrect error message with _isc_sql_interprete()_ + Contributor(s): Vlad Khorsun + +* [#7124](https://github.com/FirebirdSQL/firebird/issues/7124): Inconsistent _RDB$USER_PRIVILEGES_ after dropping identity + Contributor(s): Adriano dos Santos Fernandes + +* [#7123](https://github.com/FirebirdSQL/firebird/issues/7123): ISQL does not extract `INCREMENT BY` for IDENTITY column + Contributor(s): Adriano dos Santos Fernandes + +* [#7122](https://github.com/FirebirdSQL/firebird/issues/7122): Invalid state of mapping cache after replacement of database + Contributor(s): Alex Peshkoff + +* [#7121](https://github.com/FirebirdSQL/firebird/issues/7121): Mapping error when server tries to use mapping rules from database in full shutdown mode + Contributor(s): Alex Peshkoff + +* [#7119](https://github.com/FirebirdSQL/firebird/issues/7119): Database statistics service could not find existing table(s) + Contributor(s): Vlad Khorsun + +* [#7118](https://github.com/FirebirdSQL/firebird/issues/7118): Chained `JOIN .. USING` across the same column names may be optimized badly + Contributor(s): Dmitry Yemanov + +* [#7113](https://github.com/FirebirdSQL/firebird/issues/7113): Wrong path in Object Pascal's readme.md + Contributor(s): Alex Peshkoff + +* [#7112](https://github.com/FirebirdSQL/firebird/issues/7112): Avoid unload of plugins in MacOS due to problematic reload of them + Contributor(s): Adriano dos Santos Fernandes + +* [#7108](https://github.com/FirebirdSQL/firebird/issues/7108): Firebird does not find an record when adding a foreign key + Contributor(s): Adriano dos Santos Fernandes + +* [#7106](https://github.com/FirebirdSQL/firebird/issues/7106): Wrong detection of must-be-delimited user names + Contributor(s): Alex Peshkoff + +* [#7103](https://github.com/FirebirdSQL/firebird/issues/7103): FB service hangs after several `DELETE FROM MON$STATEMENTS` being issued in order to stop ES/EDS which waits record for updating + Contributor(s): Vlad Khorsun + +* [#7099](https://github.com/FirebirdSQL/firebird/issues/7099): Incomplete _op_batch_cs_ response with _TAG_MULTIERROR_ + Contributor(s): Alex Peshkoff + +* [#7096](https://github.com/FirebirdSQL/firebird/issues/7096): Client install on Windows is missing some files + Contributor(s): Paul Reeves + +* [#7094](https://github.com/FirebirdSQL/firebird/issues/7094): Incorrect indexed lookup of strings when the last keys characters are part of collated contractions and there is multi-segment insensitive descending index + Contributor(s): Adriano dos Santos Fernandes + +* [#7090](https://github.com/FirebirdSQL/firebird/issues/7090): Performance degradation with `CURRENT_DATE`, `LOCALTIME` and `LOCALTIMESTAMP` + Contributor(s): Adriano dos Santos Fernandes + +* [#7088](https://github.com/FirebirdSQL/firebird/pull/7088): MacOS UDR and Legacy_UserManager plugins not working due to not exported entry point + Contributor(s): Adriano dos Santos Fernandes + +* [#7084](https://github.com/FirebirdSQL/firebird/issues/7084): Creating unique constraints on MacOS fails on larger tables + Contributor(s): Adriano dos Santos Fernandes + +* [#7080](https://github.com/FirebirdSQL/firebird/issues/7080): Executing batch crashes the server + Contributor(s): Alex Peshkoff + +* [#6947](https://github.com/FirebirdSQL/firebird/issues/6947): Query to MON$ tables does not return data when database encryption/decryption is in progress + Contributor(s): Alex Peshkoff + +* [#4085](https://github.com/FirebirdSQL/firebird/issues/4085): _RDB$INDICES_ information stored inconsistently after a `CREATE INDEX` + Contributor(s): Dmitry Yemanov + +* [#3357](https://github.com/FirebirdSQL/firebird/issues/3357): Bad execution plan if some stream depends on multiple streams via a function + Contributor(s): Dmitry Yemanov + + +# v4.0.1 + +## New features + +* [#6910](https://github.com/FirebirdSQL/firebird/issues/6910): Add way to retrieve statement BLR with Statement::getInfo and ISQL's SET EXEC_PATH_DISPLAY BLR + Contributor(s): Adriano dos Santos Fernandes + +## Improvements + +* [#6959](https://github.com/FirebirdSQL/firebird/issues/6959): Add IBatch::getInfo() method to the API + Contributor(s): Alex Peshkoff + +* [#6954](https://github.com/FirebirdSQL/firebird/issues/6954): fb_info_protocol_version support + Contributor(s): Alex Peshkoff + +* [#6929](https://github.com/FirebirdSQL/firebird/issues/6929): Add support of PKCS v.1.5 padding to RSA functions, needed for backward compatibility with old systems + Contributor(s): Alex Peshkoff + +* [#6915](https://github.com/FirebirdSQL/firebird/issues/6915): Allow attribute DISABLE-COMPRESSIONS in UNICODE collations + Contributor(s): Adriano dos Santos Fernandes + +* [#6903](https://github.com/FirebirdSQL/firebird/issues/6903): Make it possible to create ICU-based collations with locales keywords + Contributor(s): tkeinz, Adriano dos Santos Fernandes + +* [#6872](https://github.com/FirebirdSQL/firebird/issues/6872): Faster indexed STARTING WITH execution with UNICODE collations + Contributor(s): Adriano dos Santos Fernandes + +* [#6810](https://github.com/FirebirdSQL/firebird/issues/6810): Use precise limit of salt length when signing messages and verifying the sign + Contributor(s): Alex Peshkoff + +* [#6809](https://github.com/FirebirdSQL/firebird/issues/6809): Integer hex-literal support for INT128 + Contributor(s): Alex Peshkoff + +## Bugfixes + +* [#7070](https://github.com/FirebirdSQL/firebird/issues/7070): Error "BLOB is not found" while replication converts INSERT into UPDATE for a conflicting record + Contributor(s): Dmitry Yemanov + +* [#7068](https://github.com/FirebirdSQL/firebird/issues/7068): Errors in the ChaCha plugin are displayed incorrectly + Contributor(s): Alex Peshkoff + +* [#7067](https://github.com/FirebirdSQL/firebird/issues/7067): Deadlock when using not initialized security database + Contributor(s): Alex Peshkoff + +* [#7066](https://github.com/FirebirdSQL/firebird/issues/7066): Server may send incorrect specific data to client when establishing encrypted connection + Contributor(s): Alex Peshkoff + +* [#7065](https://github.com/FirebirdSQL/firebird/issues/7065): Connection hangs after delivery of 256GB of data + Contributor(s): Alex Peshkoff + +* [#7064](https://github.com/FirebirdSQL/firebird/issues/7064): Linear regression functions aren't implemented correctly + Contributor(s): Adriano dos Santos Fernandes + +* [#7062](https://github.com/FirebirdSQL/firebird/issues/7062): Creation of expression index does not release its statement correctly + Contributor(s): Adriano dos Santos Fernandes + +* [#7060](https://github.com/FirebirdSQL/firebird/issues/7060): Deadlock when execute test for CORE-4337 + Contributor(s): Alex Peshkoff + +* [#7057](https://github.com/FirebirdSQL/firebird/issues/7057): Client-side positioned updates work wrongly with scrollable cursors + Contributor(s): Dmitry Yemanov + +* [#7056](https://github.com/FirebirdSQL/firebird/issues/7056): Fetching from a scrollable cursor may overwrite user-specified buffer and corrupt memory + Contributor(s): Dmitry Yemanov + +* [#7052](https://github.com/FirebirdSQL/firebird/issues/7052): Races between transactions on the primary side may cause update conflicts while applying journals to the replica + Contributor(s): Dmitry Yemanov + +* [#7048](https://github.com/FirebirdSQL/firebird/issues/7048): Incorrect releasing of user savepoint (older savepoints become inaccessible) + Contributor(s): Dmitry Yemanov + +* [#7043](https://github.com/FirebirdSQL/firebird/issues/7043): Wrong message when user has no access to /tmp/firebird + Contributor(s): Alex Peshkoff + +* [#7037](https://github.com/FirebirdSQL/firebird/issues/7037): Build problem when using both --with-builtin-tommath and --with-builtin-tomcrypt + Contributor(s): Adriano dos Santos Fernandes + +* [#7034](https://github.com/FirebirdSQL/firebird/issues/7034): Server crashes while fetching from a scrollable cursor in PSQL + Contributor(s): Dmitry Yemanov + +* [#7033](https://github.com/FirebirdSQL/firebird/issues/7033): Replicator is missing sanity checks for user-supplied blocks + Contributor(s): Dmitry Yemanov + +* [#7018](https://github.com/FirebirdSQL/firebird/issues/7018): Problems with windows frames + Contributor(s): Adriano dos Santos Fernandes + +* [#7015](https://github.com/FirebirdSQL/firebird/issues/7015): Replication applier code may crash if the specified block contains no savepoint operations + Contributor(s): Dmitry Yemanov + +* [#6998](https://github.com/FirebirdSQL/firebird/issues/6998): Problems with access to RDB$CONFIG table for non-privileged user when he has grant on execution of SP which has necessary access rights (created by SYSDBA with SQL DEFINER clause) + Contributor(s): Roman Simakov + +* [#6995](https://github.com/FirebirdSQL/firebird/issues/6995): "String truncation error" is raised while restoring the database from a v2.5 backup + Contributor(s): Dmitry Yemanov + +* [#6989](https://github.com/FirebirdSQL/firebird/issues/6989): Invalid message in replication.log (and possibly crash in the case of synchronous replication) when the target DB has no "replica" flag set + Contributor(s): Dmitry Yemanov + +* [#6985](https://github.com/FirebirdSQL/firebird/issues/6985): Application could hang when using new Batch API with blobs over XNET + Contributor(s): Vlad Khorsun + +* [#6979](https://github.com/FirebirdSQL/firebird/issues/6979): Windows x64 server installer installs an incomplete x86 client + Contributor(s): Paul Reeves + +* [#6978](https://github.com/FirebirdSQL/firebird/issues/6978): Firebird 4 fails to build on big endian platforms + Contributor(s): Alex Peshkoff + +* [#6976](https://github.com/FirebirdSQL/firebird/issues/6976): Lack of proper clean up after failure to initialize shared memory + Contributor(s): Vlad Khorsun + +* [#6975](https://github.com/FirebirdSQL/firebird/issues/6975): Crash or hang while shutting down the replica database if segments are being applied + Contributor(s): Dmitry Yemanov + +* [#6968](https://github.com/FirebirdSQL/firebird/issues/6968): On Windows, engine may hang when works with corrupted database and read after the end of file + Contributor(s): Vlad Khorsun + +* [#6966](https://github.com/FirebirdSQL/firebird/issues/6966): Status vector for ES() is unstable if another execute block with correct statement was executed before. Affects only LINUX builds in Classic mode + Contributor(s): Alex Peshkoff + +* [#6963](https://github.com/FirebirdSQL/firebird/issues/6963): The REFERENCES permission does not work + Contributor(s): Alex Peshkoff + +* [#6955](https://github.com/FirebirdSQL/firebird/issues/6955): fb_info_creation_timestamp_tz returns a corrupted buffer + Contributor(s): Vlad Khorsun + +* [#6945](https://github.com/FirebirdSQL/firebird/issues/6945): Segfault in the batch interface when gbak restores a database with many blobs over the wire + Contributor(s): Alex Peshkoff + +* [#6943](https://github.com/FirebirdSQL/firebird/issues/6943): Windows client install is missing some DLLs + Contributor(s): Paul Reeves + +* [#6935](https://github.com/FirebirdSQL/firebird/issues/6935): SQL SECURITY DEFINER has inconsistent behaviour if the object owner is non-privileged + Contributor(s): Dmitry Yemanov + +* [#6935](https://github.com/FirebirdSQL/firebird/issues/6935): SQL SECURITY DEFINER does not affect the ownership of created DDL objects + Contributor(s): Dmitry Yemanov + +* [#6930](https://github.com/FirebirdSQL/firebird/issues/6930): Segfault when calling cryptographic functions + Contributor(s): Alex Peshkoff + +* [#6917](https://github.com/FirebirdSQL/firebird/issues/6917): Firebird 4 installer asks for SYSDBA password when doing client installation + Contributor(s): Paul Reeves + +* [#6913](https://github.com/FirebirdSQL/firebird/issues/6913): Buffer overflows in getInfo APIs + Contributor(s): Adriano dos Santos Fernandes + +* [#6909](https://github.com/FirebirdSQL/firebird/issues/6909): Some updates may crash Firebird server on the replica side + Contributor(s): Dmitry Yemanov + +* [#6907](https://github.com/FirebirdSQL/firebird/issues/6907): Failed DDL commands can be replicated + Contributor(s): Dmitry Yemanov + +* [#6900](https://github.com/FirebirdSQL/firebird/issues/6900): IBatch::add() method fails silently when a memory limit is exceeded + Contributor(s): Alex Peshkoff + +* [#6893](https://github.com/FirebirdSQL/firebird/issues/6893): Problem with replication of BLOB segments longer than 32KB + Contributor(s): Dmitry Yemanov + +* [#6887](https://github.com/FirebirdSQL/firebird/issues/6887): Invalid SIMILAR TO patterns may lead memory read beyond string limits + Contributor(s): Adriano dos Santos Fernandes + +* [#6886](https://github.com/FirebirdSQL/firebird/issues/6886): Differerent interfaces behaviour depending upon source of interface + Contributor(s): Alex Peshkoff + +* [#6887](https://github.com/FirebirdSQL/firebird/issues/6887): Significant performance regression of SIMILAR TO and SUBSTRING(SIMILAR) when pattern is taken from a variable + Contributor(s): Adriano dos Santos Fernandes + +* [#6874](https://github.com/FirebirdSQL/firebird/issues/6874): Literal 65536 (interpreted as int) cannot be multiplied by itself w/o cast if result is more than 2^63-1 + Contributor(s): Alex Peshkoff + +* [#6860](https://github.com/FirebirdSQL/firebird/issues/6860): Create user statement fails with SQLSTATE = HY000 when using DataTypeCompatibility + Contributor(s): Alex Peshkoff + +* [#6856](https://github.com/FirebirdSQL/firebird/issues/6856): Permission error after replication of DDL commands + Contributor(s): Dmitry Yemanov + +* [#6853](https://github.com/FirebirdSQL/firebird/issues/6853): Asynchronous replication leaks file handles + Contributor(s): Dmitry Yemanov + +* [#6850](https://github.com/FirebirdSQL/firebird/issues/6850): Database-level and DDL triggers are executed at the replica side + Contributor(s): Dmitry Yemanov + +* [#6849](https://github.com/FirebirdSQL/firebird/issues/6849): Conflicting INSERT propagated into a read-write replica may cause duplicate records to appear (and PK/UK violation to happen) + Contributor(s): Dmitry Yemanov + +* [#6848](https://github.com/FirebirdSQL/firebird/issues/6848): Generator values may not replicate after commit + Contributor(s): Dmitry Yemanov + +* [#6845](https://github.com/FirebirdSQL/firebird/issues/6845): Result type of AVG over BIGINT column results in type INT128 + Contributor(s): Alex Peshkoff + +* [#6838](https://github.com/FirebirdSQL/firebird/issues/6838): Deleting multiple rows from a view with triggers may cause triggers to fire just once + Contributor(s): Dmitry Yemanov + +* [#6832](https://github.com/FirebirdSQL/firebird/issues/6832): Segfault when using COMMIT RETAINING with Global Temporary Tables + Contributor(s): Alex Peshkoff + +* [#6801](https://github.com/FirebirdSQL/firebird/issues/6801): Error recompiling a package with some combination of nested functions + Contributor(s): Adriano dos Santos Fernandes + + +# v4.0 Release (01-Jun-2021) + +## Improvements + +* [#6806](https://github.com/FirebirdSQL/firebird/issues/6806): Rename RSA_SIGN and RSA_VERIFY + Reference(s): [/doc/sql.extensions/README.builtin_functions.txt](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.builtin_functions.txt), [/doc/sql.extensions/README.keywords](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.keywords) + Contributor(s): Alex Peshkoff + +* [#6786](https://github.com/FirebirdSQL/firebird/issues/6786): Add session time zone to system context + Reference(s): [/doc/sql.extensions/README.time_zone.md](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.time_zone.md), [/doc/sql.extensions/README.context_variables2](https://github.com/FirebirdSQL/firebird/raw/master/doc/sql.extensions/README.context_variables2) + Contributor(s): Adriano dos Santos Fernandes + +* [#6769](https://github.com/FirebirdSQL/firebird/issues/6769): More efficient implementation of SUBSTRING for UTF8 character set + Contributor(s): Adriano dos Santos Fernandes + +* [#6767](https://github.com/FirebirdSQL/firebird/issues/6767): Add ability for a replication plugin to refuse attachment + Contributor(s): Dmitry Yemanov + +* [#6748](https://github.com/FirebirdSQL/firebird/issues/6748): Freeing a statement using DSQL_drop or DSQL_unprepare should send free packet immediately + Contributor(s): Vlad Khorsun + +* [#6715](https://github.com/FirebirdSQL/firebird/issues/6715): Provide time zone ID constants in public headers + Contributor(s): Adriano dos Santos Fernandes + +* [#6253](https://github.com/FirebirdSQL/firebird/issues/6253): RDB$GET_TRANSACTION_CN should work the same way in Super and Classic + Contributor(s): Vlad Khorsun + +## Bugfixes + +* [#6816](https://github.com/FirebirdSQL/firebird/issues/6816): Illegal output length in base64/hex encode/decode functions + Contributor(s): Alex Peshkoff + +* [#6812](https://github.com/FirebirdSQL/firebird/issues/6812): BASE64_ENCODE and HEX_ENCODE can exceed maximum widths for VARCHAR + Contributor(s): Alex Peshkoff + +* [#6808](https://github.com/FirebirdSQL/firebird/issues/6808): Segfault in encrypt/decrypt functions when their first argument is NULL + Contributor(s): Alex Peshkoff + +* [#6805](https://github.com/FirebirdSQL/firebird/issues/6805): RDB$TYPES has incorrect entries for RDB$TYPE 28 and 29 in RDB$TYPE_NAME column + Contributor(s): Alex Peshkoff + +* [#6804](https://github.com/FirebirdSQL/firebird/issues/6804): Assertion in tomcrypt when key length for RC4 is too small + Contributor(s): Alex Peshkoff + +* [#6802](https://github.com/FirebirdSQL/firebird/issues/6802): When the statement timeout is set, it causes the lock manager to delay reporting deadlocks until timeout is expired + Contributor(s): Vlad Khorsun + +* [#6800](https://github.com/FirebirdSQL/firebird/issues/6800): Client config DefaultTimeZone is not passed to server when isc_dpb_session_time_zone is not set + Contributor(s): Adriano dos Santos Fernandes + +* [#6797](https://github.com/FirebirdSQL/firebird/issues/6797): Functions DECRYPT and RSA_DECRYPT return VARCHAR CHARACTER SET NONE instead of VARBINARY (VARCHAR CHARACTER SET OCTETS) + Contributor(s): Alex Peshkoff + +* [#6796](https://github.com/FirebirdSQL/firebird/issues/6796): Buffer overflow when padding line with national characters causes ISQL to crash + Contributor(s): Adriano dos Santos Fernandes + +* [#6795](https://github.com/FirebirdSQL/firebird/issues/6795): Replication gets stuck due to "Blob xxx.xx is not found for table xxx" error + Contributor(s): Dmitry Yemanov + +* [#6790](https://github.com/FirebirdSQL/firebird/issues/6790): MON$ATTACHMENTS.MON$TIMESTAMP is incorrect when DefaultTimeZone is configured with time zone different from the server's default + Contributor(s): Adriano dos Santos Fernandes + +* [#6787](https://github.com/FirebirdSQL/firebird/issues/6787): MON$ATTACHMENTS.MON$TIMESTAMP should use its session original time zone + Contributor(s): Adriano dos Santos Fernandes + +* [#6785](https://github.com/FirebirdSQL/firebird/issues/6785): Problem when restoring the database on Firebird 4 RC1 + Contributor(s): Vlad Khorsun + +* [#6782](https://github.com/FirebirdSQL/firebird/issues/6782): Cannot get "records fetched" for selectable procedures in trace + Contributor(s): Vlad Khorsun + +* [#6781](https://github.com/FirebirdSQL/firebird/issues/6781): Crashing (due to UDF exception) process hangs + Contributor(s): Vlad Khorsun + +* [#6780](https://github.com/FirebirdSQL/firebird/issues/6780): firebird.msg is missing in Firebird Android builds + Contributor(s): Alex Peshkoff + +* [#6778](https://github.com/FirebirdSQL/firebird/issues/6778): Inconsistent cursor-driven deletion + Contributor(s): Dmitry Yemanov + +* [#6777](https://github.com/FirebirdSQL/firebird/issues/6777): AV when the engine shuts down and cancels an attachment waiting in the lock manager + Contributor(s): Vlad Khorsun + +* [#6768](https://github.com/FirebirdSQL/firebird/issues/6768): Restore backup on RawDevice (error during "open O_CREAT" operation for file "/dev/sda1") + Contributor(s): Alex Peshkoff + +* [#6766](https://github.com/FirebirdSQL/firebird/issues/6766): Replication plugin can crash engine returning nullptr from startTransaction() method + Contributor(s): Dmitry Yemanov + +* [#6761](https://github.com/FirebirdSQL/firebird/issues/6761): Hash join cannot match records using some TIME ZONE / DECFLOAT keys + Contributor(s): Dmitry Yemanov + +* [#6759](https://github.com/FirebirdSQL/firebird/issues/6759): Results of concatenation with blob has no info about collation of source columns (which are declared with such info) + Contributor(s): Vlad Khorsun + +* [#6758](https://github.com/FirebirdSQL/firebird/issues/6758): COMPUTED BY column looses charset and collate of source field when is either of type BLOB or VARCHAR casted to BLOB + Contributor(s): Vlad Khorsun + +* [#6756](https://github.com/FirebirdSQL/firebird/issues/6756): Error "no current record for fetch operation" when sorting by a international string + Contributor(s): Dmitry Yemanov + +* [#6754](https://github.com/FirebirdSQL/firebird/issues/6754): Connect to database that contains broken pages can lead to FB crash + Contributor(s): Alex Peshkoff + +* [#6753](https://github.com/FirebirdSQL/firebird/issues/6753): AV in the engine when StatementTimeout is active for user statement and some internal DSQL statement was executed as part of overall execution process + Contributor(s): Vlad Khorsun + +* [#6752](https://github.com/FirebirdSQL/firebird/issues/6752): Segfaults in fbclient when receiving invalid / unexpected data from server + Contributor(s): Alex Peshkoff + +* [#6751](https://github.com/FirebirdSQL/firebird/issues/6751): Various segfaults in fbclient + Contributor(s): Alex Peshkoff + +* [#6750](https://github.com/FirebirdSQL/firebird/issues/6750): CAST of Infinity values to FLOAT doesn't work + Contributor(s): Alex Peshkoff + +* [#6749](https://github.com/FirebirdSQL/firebird/issues/6749): Error "Invalid time zone (+08). Falling back to displacement" in firebird.log + Contributor(s): Adriano dos Santos Fernandes + +* [#6747](https://github.com/FirebirdSQL/firebird/issues/6747): Wrong message when connecting to tiny trash database file + Contributor(s): Alex Peshkoff + +* [#6746](https://github.com/FirebirdSQL/firebird/issues/6746): Regression: CREATE DATABASE fails with 'Token unknown' error when DB name is enclosed in double quotes and 'DEFAULT CHARACTER SET' is specified after DB name + Contributor(s): Adriano dos Santos Fernandes + +* [#6745](https://github.com/FirebirdSQL/firebird/issues/6745): Protect included tomcrypt library from being overwritten by a system package + Contributor(s): Alex Peshkoff + +* [#6738](https://github.com/FirebirdSQL/firebird/issues/6738): Segfault when GFIX requests for database page buffer more memory than available from OS + Contributor(s): Alex Peshkoff + +* [#6734](https://github.com/FirebirdSQL/firebird/issues/6734): Provide same results for date arithmetics when date is changed by values near +/-max(bigint) + Contributor(s): Alex Peshkoff + +* [#6733](https://github.com/FirebirdSQL/firebird/issues/6733): Attempt to create database with page_size >= 65536 makes DB with actual page size = 4KB or 8KB, but not 32KB as it should + Contributor(s): Alex Peshkoff + +* [#6731](https://github.com/FirebirdSQL/firebird/issues/6731): Segfault when shutting down database which got encrypted by another process + Contributor(s): Alex Peshkoff + +* [#6729](https://github.com/FirebirdSQL/firebird/issues/6729): Regression: GSTAT with switch -t executed via services fails with "found unknown switch" error + Contributor(s): Alex Peshkoff + +* [#6727](https://github.com/FirebirdSQL/firebird/issues/6727): Synchronous replication to localhost hangs on disconnect + Contributor(s): Dmitry Yemanov + +* [#6724](https://github.com/FirebirdSQL/firebird/issues/6724): Inconsistent translation "string->timestamp->string->timestamp" in Dialect 1 + Contributor(s): Adriano dos Santos Fernandes + +* [#6719](https://github.com/FirebirdSQL/firebird/issues/6719): User without ALTER ANY ROLE privilege can use COMMENT ON ROLE + Contributor(s): Alex Peshkoff + +* [#6718](https://github.com/FirebirdSQL/firebird/issues/6718): Event delivery could be missed when local (XNET) protocol is used + Contributor(s): Vlad Khorsun + +* [#6717](https://github.com/FirebirdSQL/firebird/issues/6717): FETCH ABSOLUTE and RELATIVE beyond bounds of cursor should always position immediately before-first or after-last + Contributor(s): Dmitry Yemanov + +* [#6716](https://github.com/FirebirdSQL/firebird/issues/6716): FETCH RELATIVE has an off by one error for the first row + Contributor(s): Dmitry Yemanov + +* [#6710](https://github.com/FirebirdSQL/firebird/issues/6710): COMMENT ON USER can only apply comment on user defined by the default user manager plugin + Contributor(s): Alex Peshkoff + +* [#6709](https://github.com/FirebirdSQL/firebird/issues/6709): GBAK discards replica mode during backup/restore + Contributor(s): Dmitry Yemanov + +* [#6708](https://github.com/FirebirdSQL/firebird/issues/6708): Rare race condition in Plugin Manager could lead to the server crash + Contributor(s): Vlad Khorsun + +* [#6700](https://github.com/FirebirdSQL/firebird/issues/6700): Wire compression causes sporadic "Error reading data from the connection" errors + Contributor(s): Alex Peshkoff + +* [#6698](https://github.com/FirebirdSQL/firebird/issues/6698): Comments before the first line of code are removed + Contributor(s): Adriano dos Santos Fernandes + +* [#6679](https://github.com/FirebirdSQL/firebird/issues/6679): CLOOP envelopes are wrong regarding IStatus + Contributor(s): Alex Peshkoff + +* [#6265](https://github.com/FirebirdSQL/firebird/issues/6265): Segfault when using expression index with complex expression + Contributor(s): Vlad Khorsun + +* [#5784](https://github.com/FirebirdSQL/firebird/issues/5784): When 32-bit and 64-bit Firebird 3 servers run on a single Windows machine concurrently, Firebird services freeze several minutes after first disconnect + Contributor(s): Vlad Khorsun + +* [#3810](https://github.com/FirebirdSQL/firebird/issues/3810): Wrong or missing IS NULL optimization (regression) + Contributor(s): Vlad Khorsun + +* [#3106](https://github.com/FirebirdSQL/firebird/issues/3106): Many indexed reads in a compound index with NULLs + Contributor(s): Vlad Khorsun + +* [#2469](https://github.com/FirebirdSQL/firebird/issues/2469): Stored procedure recursively called by calculated field fails after reconnect + Contributor(s): Vlad Khorsun + +# v4.0 Release Candidate 1 (01-Feb-2021) ## New features diff --git a/README.md b/README.md index 2ffb53eb892..7588b338794 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://travis-ci.com/FirebirdSQL/firebird.svg?branch=master)](https://travis-ci.com/FirebirdSQL/firebird) -[![Build Status](https://ci.appveyor.com/api/projects/status/github/FirebirdSQL/firebird?branch=master&svg=true)](https://ci.appveyor.com/project/FirebirdSQL/firebird) +[![Build Status (GitHub)](https://github.com/FirebirdSQL/firebird/actions/workflows/main.yml/badge.svg?branch=v4.0-release)](https://github.com/FirebirdSQL/firebird/actions/workflows/main.yml?query=branch%3Av4.0-release) +[![Build Status (AppVeyor)](https://ci.appveyor.com/api/projects/status/github/FirebirdSQL/firebird?branch=master&svg=true)](https://ci.appveyor.com/project/FirebirdSQL/firebird) # Firebird README diff --git a/appveyor.yml b/appveyor.yml index ec259323de8..14f98f81c86 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -44,6 +44,7 @@ install: - sh: if [ $PLATFORM = "x86" ]; then export BUILD_FLAG=--build=i386-pc-linux-gnu; fi - sh: sudo apt-get -y update - sh: sudo apt-get -y install $APT_PACKAGES + - sh: sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 80 --slave /usr/bin/g++ g++ /usr/bin/g++-7 - sh: find . -type f -iname "*.sh" -exec chmod +x {} \; - sh: ./autogen.sh --enable-binreloc --with-builtin-tomcrypt --prefix=/opt/firebird $BUILD_FLAG - sh: make -j4 diff --git a/builds/install/arch-specific/android/BuildPackage.sh b/builds/install/arch-specific/android/BuildPackage.sh index beb8406da0d..f7f5caa8f73 100644 --- a/builds/install/arch-specific/android/BuildPackage.sh +++ b/builds/install/arch-specific/android/BuildPackage.sh @@ -1,10 +1,18 @@ +bits=${1} +[ -z "$bits" ] && bits=32 +[ "$bits" = "32" ] && cross=arm-linux-androideabi +[ "$bits" = "64" ] && cross=aarch64-linux-android +[ -z "$cross" ] && echo "Invalid bits passed" && exit 1 +arm="" +[ "$bits" = "64" ] && arm=64 + MakeVersion=gen/Make.Version Build=`grep ^BuildNum ${MakeVersion}|awk '{print $3;}'` Version=`grep ^FirebirdVersion ${MakeVersion}|awk '{print $3;}'` -Release="Firebird-${Version}.${Build}-0.arm.tar.gz" -Debug="Firebird-withDebugInfo-${Version}.${Build}-0.arm.tar.gz" +Release="Firebird-${Version}.${Build}-0.arm${arm}.tar.gz" +Debug="Firebird-withDebugInfo-${Version}.${Build}-0.arm${arm}.tar.gz" Stripped=strip -aStrip=${NDK}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-strip +aStrip=${NDK}/toolchains/${cross}-4.9/prebuilt/linux-x86_64/bin/${cross}-strip fbRootDir=`pwd` cd gen/Release diff --git a/builds/install/arch-specific/darwin/install-script b/builds/install/arch-specific/darwin/install-script index df9709e0e9c..2d59ea763fc 100644 --- a/builds/install/arch-specific/darwin/install-script +++ b/builds/install/arch-specific/darwin/install-script @@ -23,7 +23,8 @@ FB_RES="$FB_FW/Versions/A/Resources" # Now create the firebird group echo "Create the Firebird group 10.7+" if dscl localhost -read /Local/Default/Groups/firebird 2&>1 /dev/null; then - echo "Group Found" + gid=$(dscl localhost -read /Local/Default/Groups/firebird PrimaryGroupID | awk '($1 == "PrimaryGroupID:") { print $2 }') + echo "Group Found $gid" else gid=501 dscl localhost -search /Local/Default/Groups PrimaryGroupID $gid | grep $gid diff --git a/builds/install/arch-specific/linux/firebird.service.in b/builds/install/arch-specific/linux/firebird.service.in index 5babad3a87a..28954fab51f 100644 --- a/builds/install/arch-specific/linux/firebird.service.in +++ b/builds/install/arch-specific/linux/firebird.service.in @@ -1,13 +1,13 @@ [Unit] Description=Firebird Database Server After=syslog.target network.target +Documentation=https://firebirdsql.org/en/firebird-rdbms/ [Service] User=firebird Group=firebird Type=forking ExecStart=@FB_SBINDIR@/fbguard -daemon -forever -StandardError=syslog [Install] WantedBy=multi-user.target diff --git a/builds/install/arch-specific/linux/makeInstallImage.sh.in b/builds/install/arch-specific/linux/makeInstallImage.sh.in index 519662815f5..1c570f66638 100644 --- a/builds/install/arch-specific/linux/makeInstallImage.sh.in +++ b/builds/install/arch-specific/linux/makeInstallImage.sh.in @@ -57,8 +57,8 @@ addLibs() { LIB=`objdump -p $libSdir/firebird|grep NEEDED|grep tomcrypt|awk '{print $2;}'` [ "$LIB" ] && echo "export LIBTOMCRYPT=$LIB" >>$libTarget - LIB=`objdump -p $libSdir/isql|grep NEEDED|egrep "(curses|termcap|tinfo)"|awk '{print $2;}'` - [ "$LIB" ] && echo "export LIBCURSES=$LIB" >>$libTarget + LIB=$(echo `objdump -p $libSdir/isql|grep NEEDED|egrep "(curses|termcap|tinfo)"|awk '{print $2;}'`) + [ "$LIB" ] && echo "export LIBCURSES='$LIB'" >>$libTarget echo >>$libTarget for i in posixLibrary.sh linuxLibrary.sh diff --git a/builds/install/arch-specific/win32/.gitignore b/builds/install/arch-specific/win32/.gitignore new file mode 100644 index 00000000000..99cf5ff7dc5 --- /dev/null +++ b/builds/install/arch-specific/win32/.gitignore @@ -0,0 +1 @@ +*.*~ diff --git a/builds/install/arch-specific/win32/BuildExecutableInstall.bat b/builds/install/arch-specific/win32/BuildExecutableInstall.bat index 8c2c66e180d..8867cb4c7de 100644 --- a/builds/install/arch-specific/win32/BuildExecutableInstall.bat +++ b/builds/install/arch-specific/win32/BuildExecutableInstall.bat @@ -26,9 +26,11 @@ @echo off :: reset ERRLEV to clear error from last run in same cmd shell -set ERRLEV=0 +set ERRLEV= + :: Assume we are preparing a production build set FBBUILD_BUILDTYPE=release + :: Don't ship pdb files by default set FBBUILD_SHIP_PDB=no_pdb :: Reset "make" vars to zero @@ -40,7 +42,7 @@ if not defined FB2_SNAPSHOT (set FB2_SNAPSHOT=0) :: See what we have on the command line -for %%v in ( %* ) do ( +@for %%v in ( %* ) do ( ( if /I "%%v"=="DEBUG" (set FBBUILD_BUILDTYPE=debug) ) ( if /I "%%v"=="PDB" (set FBBUILD_SHIP_PDB=ship_pdb) ) ( if /I "%%v"=="ZIP" (set FBBUILD_ZIP_PACK=1) ) @@ -48,9 +50,9 @@ for %%v in ( %* ) do ( ( if /I "%%v"=="ALL" ( (set FBBUILD_ZIP_PACK=1) & (set FBBUILD_ISX_PACK=1) ) ) ) -::Are we doing a snapshot build? If so we always do less work. +:: Are we doing a snapshot build? If so we always do less work. if "%FB2_SNAPSHOT%"=="1" ( - (set FBBUILD_ISX_PACK=0) + ( set FBBUILD_ISX_PACK=0 ) ) @@ -65,65 +67,62 @@ if "%FB2_SNAPSHOT%"=="1" ( :: let's bail out now. @echo o Checking for sed... -(cmd /c "sed.exe --version 2>&1 | findstr version > nul ") || ( call :ERROR Could not locate sed && @goto :EOF ) +@(cmd /c "sed.exe --version 2>&1 | findstr version > nul ") || ( call :ERROR Could not locate sed & goto :EOF ) @echo o Checking for unix2dos... -(cmd /c "unix2dos.exe --version 2>&1 | findstr version > nul" ) || ( call :ERROR Could not locate unix2dos && @goto :EOF ) - -@for /f "usebackq tokens=*" %%c in (`where /f touch 2^>nul`) do set TOUCH_COMMAND=%%c -if defined TOUCH_COMMAND ( - @%TOUCH_COMMAND% --version nul 2>nul - if not errorlevel 1 ( - @echo o POSIX touch utility found at %TOUCH_COMMAND% - ) else ( @set TOUCH_COMMAND= ) -) +@( cmd /c "unix2dos.exe --version 2>&1 | findstr version > nul" ) || ( call :ERROR Could not locate unix2dos & goto :EOF ) -@for /f "usebackq tokens=*" %%c in (`where /f md5sum 2^>nul`) do set MD5_COMMAND=%%c +@for /f "usebackq tokens=*" %%c in ( `where /f md5sum 2^>nul` ) do set MD5_COMMAND=%%c if defined MD5_COMMAND ( - @echo o POSIX md5sum utility found at %MD5_COMMAND% + echo o POSIX md5sum utility found at %MD5_COMMAND% ) -if %FBBUILD_ZIP_PACK% EQU 1 ( +@if %FBBUILD_ZIP_PACK% EQU 1 ( + if not defined SEVENZIP ( + if exist "%ProgramW6432%\7-Zip\7z.exe" set SEVENZIP=%ProgramW6432%\7-Zip + ) if not defined SEVENZIP ( call :ERROR SEVENZIP environment variable is not defined. - @goto :EOF - ) else (@echo o Compression utility found.) + goto :EOF + ) else ( + echo o Compression utility found. + ) ) -if %FBBUILD_ISX_PACK% NEQ 1 goto :SKIP_INNO +@if %FBBUILD_ISX_PACK% NEQ 1 goto :SKIP_INNO -if defined INNO6_SETUP_PATH ( +@if defined INNO6_SETUP_PATH ( set ISCC_COMMAND=%INNO6_SETUP_PATH%\iscc.exe ) :: If the environment variable is not set let's search in PATH -if not defined ISCC_COMMAND ( - @for /f "usebackq tokens=*" %%c in (`where /f iscc 2^>nul`) do set ISCC_COMMAND=%%c +@if not defined ISCC_COMMAND ( + for /f "usebackq tokens=*" %%c in ( `where /f iscc 2^>nul` ) do set ISCC_COMMAND=%%c ) -if not defined ISCC_COMMAND ( - @echo Required Inno Setup compiler not found - @exit /b 1 +@if not defined ISCC_COMMAND ( + echo Required Inno Setup compiler not found + exit /b 1 ) @echo o Inno Setup found as %ISCC_COMMAND%. :SKIP_INNO -if not defined WIX ( - @echo. - @echo The WIX environment var not defined. - @echo WiX is needed to build the MSI kits of the CRT runtimes. - @echo. +@if not defined WIX ( + echo. + echo The WIX environment var not defined. + echo WiX is needed to build the MSI kits of the CRT runtimes. + echo. ) else ( - @echo o WiX found at "%WIX%". + echo o WiX found at "%WIX%". ) -if not defined FB_EXTERNAL_DOCS ( - @echo. - @echo The FB_EXTERNAL_DOCS environment var is not defined - @echo It should point to the directory containing the relevant release notes - @echo in adobe pdf format. - @echo. +@if not defined FB_EXTERNAL_DOCS ( + echo. + echo The FB_EXTERNAL_DOCS environment var is not defined + echo It should point to the directory containing the relevant release notes + echo in adobe pdf format. + echo. ) else ( - @echo o Package will include documentation from "%FB_EXTERNAL_DOCS%". + echo o Package will include documentation from "%FB_EXTERNAL_DOCS%". ) @@ -136,64 +135,67 @@ if not defined FB_EXTERNAL_DOCS ( ::========== :: Cut off everything that is not #define to let Inno Setup use it -findstr /B /L "#define" "%FB_ROOT_PATH%\src\jrd\build_no.h" >"%FB_ROOT_PATH%\gen\jrd\build_no.h" +@findstr /B /L "#define" "%FB_ROOT_PATH%\src\jrd\build_no.h" > "%FB_ROOT_PATH%\gen\jrd\build_no.h" :: Read version parameters from build_no.h -for /F "tokens=2*" %%a in (%FB_ROOT_PATH%\gen\jrd\build_no.h) do ( -@echo Setting %%a to %%~b -SET %%a=%%~b +@for /F "tokens=2*" %%a in ( %FB_ROOT_PATH%\gen\jrd\build_no.h ) do ( + echo Setting %%a to %%~b + SET %%a=%%~b ) :: Set our package number at 0 and increment every :: time we rebuild in a single session -if not defined FBBUILD_PACKAGE_NUMBER ( -set FBBUILD_PACKAGE_NUMBER=0 +@if not defined FBBUILD_PACKAGE_NUMBER ( + set FBBUILD_PACKAGE_NUMBER=0 ) else ( -set /A FBBUILD_PACKAGE_NUMBER+=1 + set /A FBBUILD_PACKAGE_NUMBER+=1 ) @echo Setting FBBUILD_PACKAGE_NUMBER to %FBBUILD_PACKAGE_NUMBER% :: If a suffix is defined (usually for an RC) ensure it is prefixed correctly. -if defined FBBUILD_FILENAME_SUFFIX ( -if not "%FBBUILD_FILENAME_SUFFIX:~0,1%"=="_" ( -(set FBBUILD_FILENAME_SUFFIX=_%FBBUILD_FILENAME_SUFFIX%) -) +@if defined FBBUILD_FILENAME_SUFFIX ( + if not "%FBBUILD_FILENAME_SUFFIX:~0,1%"=="-" ( + set FBBUILD_FILENAME_SUFFIX=-%FBBUILD_FILENAME_SUFFIX% + ) ) :: Set up our final destination -set FBBUILD_INSTALL_IMAGES=%FB_ROOT_PATH%\builds\install_images -if not exist "%FBBUILD_INSTALL_IMAGES%" (mkdir "%FBBUILD_INSTALL_IMAGES%") +@set FBBUILD_INSTALL_IMAGES=%FB_ROOT_PATH%\builds\install_images +@if not exist "%FBBUILD_INSTALL_IMAGES%" ( mkdir "%FBBUILD_INSTALL_IMAGES%" ) :: Determine Product Status -if %FB_BUILD_TYPE%==V ( -set FBBUILD_PROD_STATUS=PROD +@if %FB_BUILD_TYPE%==V ( + set FBBUILD_PROD_STATUS=PROD ) else ( -set FBBUILD_PROD_STATUS=DEV + set FBBUILD_PROD_STATUS=DEV ) -set FBBUILD_FILE_ID=%PRODUCT_VER_STRING%_%FBBUILD_PACKAGE_NUMBER%_%FB_TARGET_PLATFORM% +@set FBBUILD_FILE_ID=%PRODUCT_VER_STRING%-%FBBUILD_PACKAGE_NUMBER%-%FB_TARGET_PLATFORM% @setlocal @echo. -@if not exist %FB_GEN_DIR%\readmes (@mkdir %FB_GEN_DIR%\readmes) -set SED_COMMAND=sed -e s/\$MAJOR/%FB_MAJOR_VER%/g ^ +@if not exist %FB_GEN_DIR%\readmes ( mkdir %FB_GEN_DIR%\readmes ) +@set SED_COMMAND=sed -e s/\$MAJOR/%FB_MAJOR_VER%/g ^ -e s/\$MINOR/%FB_MINOR_VER%/g ^ -e s/\$RELEASE/%FB_REV_NO%/g @echo Processing version strings in Readme_%FBBUILD_PROD_STATUS%.txt @%SED_COMMAND% Readme_%FBBUILD_PROD_STATUS%.txt > %FB_GEN_DIR%\readmes\Readme.txt -@for %%f in (installation_readme.txt) do ( - @echo Processing version strings in %%f - @%SED_COMMAND% %%f > %FB_GEN_DIR%\readmes\%%f +@for %%f in ( installation_readme.txt installation_scripted.txt ) do ( + echo Processing version strings in %%f + %SED_COMMAND% %%f > %FB_GEN_DIR%\readmes\%%f ) @for %%d in (ba cz de es fr hu it pl pt ru si ) do ( - @if not exist %FB_GEN_DIR%\readmes\%%d (@mkdir %FB_GEN_DIR%\readmes\%%d) - @for %%f in ( %%d\*.txt ) do ( - @echo Processing version strings in %%f - @%SED_COMMAND% %%f > %FB_GEN_DIR%\readmes\%%f + if not exist %FB_GEN_DIR%\readmes\%%d ( mkdir %FB_GEN_DIR%\readmes\%%d ) + for %%f in ( %%d\*.txt ) do ( + echo Processing version strings in %%f + %SED_COMMAND% %%f > %FB_GEN_DIR%\readmes\%%f ) ) @endlocal +:: Dump env vars to file for later testing. +@set > %FB_ROOT_PATH%\builds\install\arch-specific\win32\test_installer\fb_build_vars_%PROCESSOR_ARCHITECTURE%.txt + ::End of SET_VERSION ::---------------- @goto :EOF @@ -207,126 +209,113 @@ set SED_COMMAND=sed -e s/\$MAJOR/%FB_MAJOR_VER%/g ^ :: We are forced to set this because the runtime library now (MSVC15) :: has a different version to the compiler. And sometimes they use 141 :: and sometimes 140. -if %MSVC_VERSION% EQU 15 ( - @set MSVC_RUNTIME_MAJOR_VERSION=14 - @set MSVC_RUNTIME_MINOR_VERSION_0=0 - @set MSVC_RUNTIME_MINOR_VERSION_1=1 +@if %MSVC_VERSION% EQU 15 ( + set MSVC_RUNTIME_MAJOR_VERSION=14 + set MSVC_RUNTIME_MINOR_VERSION_0=0 + set MSVC_RUNTIME_MINOR_VERSION_1=1 ) else ( - @set MSVC_RUNTIME_VERSION=%MSVC_VERSION%0 + set MSVC_RUNTIME_VERSION=%MSVC_VERSION%0 ) @echo Copying MSVC runtime libraries... @if not exist %FB_OUTPUT_DIR%\system32 ( - @mkdir %FB_OUTPUT_DIR%\system32 + mkdir %FB_OUTPUT_DIR%\system32 ) -for %%f in ( msvcp%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_0%.dll vcruntime%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_0%.dll ) do ( +@for %%f in ( msvcp%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_0%.dll vcruntime%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_0%.dll ) do ( echo Copying "%VCToolsRedistDir%\%VSCMD_ARG_TGT_ARCH%\Microsoft.VC%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%.CRT\%%f" - copy "%VCToolsRedistDir%\%VSCMD_ARG_TGT_ARCH%\Microsoft.VC%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%.CRT\%%f" %FB_OUTPUT_DIR%\ >nul - if %ERRORLEVEL% GEQ 1 ( - call :ERROR Copying "%VCToolsRedistDir%\%VSCMD_ARG_TGT_ARCH%\Microsoft.VC%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%.CRT\%%f" failed with error %ERRORLEVEL% ) && (goto :EOF) + copy "%VCToolsRedistDir%\%VSCMD_ARG_TGT_ARCH%\Microsoft.VC%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%.CRT\%%f" %FB_OUTPUT_DIR%\ >nul + if ERRORLEVEL 1 ( + call :ERROR Copying "%VCToolsRedistDir%\%VSCMD_ARG_TGT_ARCH%\Microsoft.VC%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%.CRT\%%f" failed with error %ERRORLEVEL% & goto :EOF ) ) -@where /Q implib.exe -@if not errorlevel 1 ( -if "%VSCMD_ARG_TGT_ARCH%"=="x86" ( - @echo Generating fbclient_bor.lib - @implib %FB_OUTPUT_DIR%\lib\fbclient_bor.lib %FB_OUTPUT_DIR%\fbclient.dll > nul -) +@if "%VSCMD_ARG_TGT_ARCH%"=="x86" ( + echo Generating fbclient_bor.lib + where /Q implib.exe + if not ERRORLEVEL 1 ( + implib %FB_OUTPUT_DIR%\lib\fbclient_bor.lib %FB_OUTPUT_DIR%\fbclient.dll > nul + ) else ( + call :WARNING implib not found + ) ) @if "%FBBUILD_SHIP_PDB%"=="ship_pdb" ( - @echo Copying pdb files... - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\fbserver\firebird.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\yvalve\fbclient.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\engine\engine*.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\fbtrace\fbtrace.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\legacy_auth\legacy_auth.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\legacy_usermanager\legacy_usermanager.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\srp\srp.pdb %FB_OUTPUT_DIR%\ > nul - @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\udr_engine\udr_engine.pdb %FB_OUTPUT_DIR%\ > nul -) -:: Maybe include these and other executables, one day ? -:: @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\gbak\gbak.pdb %FB_OUTPUT_DIR%\ > nul -:: @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\gfix\gfix.pdb %FB_OUTPUT_DIR%\ > nul -:: @copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\isql\isql.pdb %FB_OUTPUT_DIR%\ > nul - + echo Copying pdb files... + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\fbserver\firebird.pdb %FB_OUTPUT_DIR%\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\burp\burp.pdb %FB_OUTPUT_DIR%\gbak.pdb > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\gfix\gfix.pdb %FB_OUTPUT_DIR%\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\isql\isql.pdb %FB_OUTPUT_DIR%\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\yvalve\fbclient.pdb %FB_OUTPUT_DIR%\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\engine\engine*.pdb %FB_OUTPUT_DIR%\plugins\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\fbtrace\fbtrace.pdb %FB_OUTPUT_DIR%\plugins\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\legacy_auth\legacy_auth.pdb %FB_OUTPUT_DIR%\plugins\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\legacy_usermanager\legacy_usermanager.pdb %FB_OUTPUT_DIR%\plugins\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\srp\srp.pdb %FB_OUTPUT_DIR%\plugins\ > nul + copy %FB_TEMP_DIR%\%FBBUILD_BUILDTYPE%\udr_engine\udr_engine.pdb %FB_OUTPUT_DIR%\plugins\ > nul +) @echo Started copying docs... @rmdir /S /Q %FB_OUTPUT_DIR%\doc 2>nul @mkdir %FB_OUTPUT_DIR%\doc @copy %FB_ROOT_PATH%\*.md %FB_OUTPUT_DIR%\doc\ > nul @copy %FB_ROOT_PATH%\doc\*.* %FB_OUTPUT_DIR%\doc\ > nul -@if %ERRORLEVEL% GEQ 1 ( - call :ERROR COPY of main documentation tree failed with error %ERRORLEVEL% +@if ERRORLEVEL 1 ( + call :ERROR COPY of main documentation tree failed. goto :EOF ) -:: Various upgrade scripts and docs -for %%d in ( v3.0 v4.0 ) do ( +@echo Copy various upgrade scripts and docs +@for %%d in ( v3.0 v4.0 ) do ( mkdir %FB_OUTPUT_DIR%\misc\upgrade\%%d 2>nul - @copy %FB_ROOT_PATH%\src\misc\upgrade\%%d\*.* %FB_OUTPUT_DIR%\misc\upgrade\%%d > nul - @if %ERRORLEVEL% GEQ 1 ( - call :ERROR copy %FB_ROOT_PATH%\src\misc\upgrade\%%d\*.* %FB_OUTPUT_DIR%\misc\upgrade\%%d failed with error %ERRORLEVEL%. + copy %FB_ROOT_PATH%\src\misc\upgrade\%%d\*.* %FB_OUTPUT_DIR%\misc\upgrade\%%d > nul + if ERRORLEVEL 1 ( + call :ERROR copy %FB_ROOT_PATH%\src\misc\upgrade\%%d\*.* %FB_OUTPUT_DIR%\misc\upgrade\%%d failed. goto :EOF ) ) -:: INTL script +@echo Copy INTL script @copy %FB_ROOT_PATH%\src\misc\intl.sql %FB_OUTPUT_DIR%\misc\ > nul -@if %ERRORLEVEL% GEQ 1 ( - call :ERROR copy %FB_ROOT_PATH%\src\misc\intl.sql %FB_OUTPUT_DIR%\misc failed with error %ERRORLEVEL%. +@if ERRORLEVEL 1 ( + call :ERROR copy %FB_ROOT_PATH%\src\misc\intl.sql %FB_OUTPUT_DIR%\misc failed. goto :EOF ) @echo Copying other documentation... @copy %FB_GEN_DIR%\readmes\installation_readme.txt %FB_OUTPUT_DIR%\doc\installation_readme.txt > nul -:: FIX ME - we now have some .md files and ChangeLog is no longer a monster. -:: Maybe we can just do nothing here. -:: If we are not doing a final release then include stuff that is -:: likely to be of use to testers, especially as our release notes -:: may be incomplete or non-existent -::@if /I "%FBBUILD_PROD_STATUS%"=="DEV" ( -:: @copy %FB_ROOT_PATH%\ChangeLog %FB_OUTPUT_DIR%\doc\ChangeLog.txt > nul -::) - @mkdir %FB_OUTPUT_DIR%\doc\sql.extensions 2>nul -@if %ERRORLEVEL% GEQ 2 ( (call :ERROR MKDIR for doc\sql.extensions dir failed) & (@goto :EOF)) +@if ERRORLEVEL 2 ( ( call :ERROR MKDIR for doc\sql.extensions dir failed) & ( goto :EOF ) ) @copy %FB_ROOT_PATH%\doc\sql.extensions\*.* %FB_OUTPUT_DIR%\doc\sql.extensions\ > nul -@if %ERRORLEVEL% GEQ 1 ( (call :ERROR Copying doc\sql.extensions failed ) & (goto :EOF)) +@if ERRORLEVEL 1 ( ( call :ERROR Copying doc\sql.extensions failed ) & ( goto :EOF ) ) :: External docs aren't necessary for a snapshot build, so we don't throw :: an error if FB_EXTERNAL_DOCS is not defined. On the other hand, -:: if the docs are available then we can include them. -if defined FB_EXTERNAL_DOCS ( - @echo Copying pdf docs... - @for %%v in ( Firebird_v%FB_MAJOR_VER%.%FB_MINOR_VER%.%FB_REV_NO%.ReleaseNotes.pdf ) do ( - @echo ... %%v - @copy /Y %FB_EXTERNAL_DOCS%\%%v %FB_OUTPUT_DIR%\doc\%%v > nul - if %ERRORLEVEL% GEQ 1 (call :ERROR Copying %FB_EXTERNAL_DOCS%\%%v failed.) +:: if the docs are available then we must include them. +@if defined FB_EXTERNAL_DOCS ( + echo Copying essential pdf docs... + for %%v in ( Firebird_v%FB_MAJOR_VER%.%FB_MINOR_VER%.%FB_REV_NO%.ReleaseNotes.pdf ) do ( + echo ... %FB_EXTERNAL_DOCS%\%%v to %FB_OUTPUT_DIR%\doc\%%v + copy /Y %FB_EXTERNAL_DOCS%\%%v %FB_OUTPUT_DIR%\doc\%%v > nul + if ERRORLEVEL 1 ( + call :ERROR Copying %FB_EXTERNAL_DOCS%\%%v to %FB_OUTPUT_DIR%\doc\%%v FAILED. & goto :EOF + ) ) - @for %%v in ( Firebird-%FB_MAJOR_VER%.%FB_MINOR_VER%-QuickStart.pdf ) do ( - @echo ... %%v - @copy /Y %FB_EXTERNAL_DOCS%\%%v %FB_OUTPUT_DIR%\doc\%%v > nul - if %ERRORLEVEL% GEQ 1 ( - REM - As of RC1 there is no quick start guide so we do not want - REM the packaging to fail for something that doesn't exist - if "%FBBUILD_FILENAME_SUFFIX%" == "_RC1" ( - echo Copying %FB_EXTERNAL_DOCS%\%%v failed. - ) else ( - call :ERROR Copying %FB_EXTERNAL_DOCS%\%%v failed. - ) + echo Copying optional pdf docs... + for %%v in ( Firebird-%FB_MAJOR_VER%.%FB_MINOR_VER%-QuickStart.pdf ) do ( + echo ... %%v + copy /Y %FB_EXTERNAL_DOCS%\%%v %FB_OUTPUT_DIR%\doc\%%v > nul + if ERRORLEVEL 1 ( + call :WARNING Copying %FB_EXTERNAL_DOCS%\%%v to %FB_OUTPUT_DIR%\doc\%%v FAILED. ) ) - -@echo Finished copying pdf docs... -@echo. + echo Finished copying pdf docs... + echo. ) @echo Cleaning irrelevant files... @@ -343,11 +332,11 @@ for %%v in (IPLicense.txt IDPLicense.txt ) do ( ) :: And readme -@copy %FB_GEN_DIR%\readmes\Readme.txt %FB_OUTPUT_DIR%\ > nul +@copy %FB_GEN_DIR%\readmes\Readme.txt %FB_OUTPUT_DIR%\ > nul :: Walk through all docs and transform any that are not .txt, .pdf or .html to .txt @echo Setting .txt filetype to ascii docs. -for /R %FB_OUTPUT_DIR%\doc %%v in ( * ) do ( +@for /R %FB_OUTPUT_DIR%\doc %%v in ( * ) do ( if /I not "%%~xv" == ".md" ( if /I not "%%~xv" == ".txt" ( if /I not "%%~xv" == ".pdf" ( @@ -361,8 +350,8 @@ for /R %FB_OUTPUT_DIR%\doc %%v in ( * ) do ( ) ) -if %FB2_SNAPSHOT% EQU 1 ( - @copy %FB_ROOT_PATH%\builds\install\arch-specific\win32\readme_snapshot.txt %FB_OUTPUT_DIR%\readme_snapshot.txt > nul +@if %FB2_SNAPSHOT% EQU 1 ( + copy %FB_ROOT_PATH%\builds\install\arch-specific\win32\readme_snapshot.txt %FB_OUTPUT_DIR%\readme_snapshot.txt > nul ) @echo Completed copying docs. @@ -378,17 +367,17 @@ if %FB2_SNAPSHOT% EQU 1 ( :: Generate runtimes as an MSI file. :: This requires WiX 3.0 to be installed ::============ -if %MSVC_VERSION% EQU 15 ( +@if %MSVC_VERSION% EQU 15 ( if not exist %FB_OUTPUT_DIR%\system32\vccrt%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%_%FB_TARGET_PLATFORM%.msi ( "%WIX%\bin\candle.exe" -v -sw1091 %FB_ROOT_PATH%\builds\win32\msvc%MSVC_VERSION%\VCCRT_%FB_TARGET_PLATFORM%.wxs -out %FB_GEN_DIR%\vccrt_%FB_TARGET_PLATFORM%.wixobj - @if %ERRORLEVEL% GEQ 1 ( - ( call :ERROR Could not generate wixobj for MSVC Runtime MSI ) & (goto :EOF) + if ERRORLEVEL 1 ( + ( call :ERROR Could not generate wixobj for MSVC Runtime MSI ) & ( goto :EOF ) ) else ( "%WIX%\bin\light.exe" -sw1076 %FB_GEN_DIR%\vccrt_%FB_TARGET_PLATFORM%.wixobj -out %FB_OUTPUT_DIR%\system32\vccrt%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%_%FB_TARGET_PLATFORM%.msi - @if %ERRORLEVEL% GEQ 1 ( (call :ERROR Could not generate MSVCC Runtime MSI ) & (goto :EOF)) + if ERRORLEVEL 1 ( (call :ERROR Could not generate MSVCC Runtime MSI ) & (goto :EOF)) ) ) else ( - @echo Using an existing build of %FB_OUTPUT_DIR%\system32\vccrt%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%_%FB_TARGET_PLATFORM%.msi + echo Using an existing build of %FB_OUTPUT_DIR%\system32\vccrt%MSVC_RUNTIME_MAJOR_VERSION%%MSVC_RUNTIME_MINOR_VERSION_1%_%FB_TARGET_PLATFORM%.msi ) ) @@ -400,22 +389,20 @@ if %MSVC_VERSION% EQU 15 ( :INCLUDE_DIR ::========== :: Prepare other files needed for deployment to /include dir -setlocal +@setlocal :: grab some missing bits'n'pieces from different parts of the source tree ::========================================================================= @echo Copying ib_util etc -@copy %FB_ROOT_PATH%\src\extlib\ib_util.h %FB_OUTPUT_DIR%\include > nul || (call :WARNING Copying ib_util.h failed. && @goto :EOF ) -@copy %FB_ROOT_PATH%\lang_helpers\ib_util.pas %FB_OUTPUT_DIR%\include > nul || (call :WARNING Copying ib_util.pas failed. && @goto :EOF ) +@copy %FB_ROOT_PATH%\src\extlib\ib_util.h %FB_OUTPUT_DIR%\include > nul || (call :ERROR Copying ib_util.h failed. & goto :EOF ) +@copy %FB_ROOT_PATH%\lang_helpers\ib_util.pas %FB_OUTPUT_DIR%\include > nul || (call :ERROR Copying ib_util.pas failed. & goto :EOF ) @echo Copying other include files required for development... -set OUTPATH=%FB_OUTPUT_DIR%\include +@set OUTPATH=%FB_OUTPUT_DIR%\include @copy %FB_ROOT_PATH%\src\yvalve\perf.h %OUTPATH%\ > nul @copy %FB_ROOT_PATH%\src\include\gen\firebird.pas %OUTPATH%\firebird\ > nul || (@call :ERROR Failure executing copy %FB_ROOT_PATH%\src\include\gen\firebird.pas %OUTPATH%\firebird\ ) -@if %ERRLEV% GEQ 1 goto :END -@xcopy /e /i /y %FB_ROOT_PATH%\src\include\firebird\impl %OUTPATH%\firebird\ > nul || (@call :ERROR Failure executing @xcopy /e /i /y %FB_ROOT_PATH%\src\include\firebird\* %OUTPATH%\firebird\ ) -@if %ERRLEV% GEQ 1 goto :END +@if ERRORLEVEL 1 goto :END -endlocal +@endlocal ::End of INCLUDE_DIR ::------------------ @@ -426,7 +413,7 @@ endlocal :: Generate sample databases file ::=============================== @echo Creating sample databases.conf -copy %FB_ROOT_PATH%\builds\install\misc\databases.conf %FB_OUTPUT_DIR%\databases.conf > nul +@copy %FB_ROOT_PATH%\builds\install\misc\databases.conf %FB_OUTPUT_DIR%\databases.conf > nul ::End of DB_CONF ::----------------- @@ -455,8 +442,8 @@ copy %FB_ROOT_PATH%\builds\install\misc\databases.conf %FB_OUTPUT_DIR%\databases :: in builds\win32 by build_msg.bat. Copying from there to output dir ::================================================================= @if not exist %FB_OUTPUT_DIR%\firebird.msg ( - (@copy %FB_GEN_DIR%\firebird.msg %FB_OUTPUT_DIR%\firebird.msg > nul) - (@if %ERRORLEVEL% GEQ 1 ( (call :ERROR Could not copy firebird.msg ) & (goto :EOF))) + copy %FB_GEN_DIR%\firebird.msg %FB_OUTPUT_DIR%\firebird.msg > nul + if ERRORLEVEL 1 ( call :ERROR Could not copy firebird.msg & goto :EOF ) ) ::End of FB_MSG @@ -468,8 +455,8 @@ copy %FB_ROOT_PATH%\builds\install\misc\databases.conf %FB_OUTPUT_DIR%\databases :: Get a list of all files in the tree make sure :: that and they all have windows EOL ::=============================================== -for /R %FB_OUTPUT_DIR% %%W in ( *.txt *.conf *.sql *.c *.cpp *.hpp *.h *.bat *.pas *.e *.def *.rc *.md *.html ) do ( - unix2dos -q --safe %%W || exit /b 1 +@for /R %FB_OUTPUT_DIR% %%W in ( *.txt *.conf *.sql *.c *.cpp *.hpp *.h *.bat *.pas *.e *.def *.rc *.md *.html ) do ( + unix2dos --safe %%W > nul 2>&1 || exit /b 1 ) ::End of SET_CRLF @@ -480,63 +467,33 @@ for /R %FB_OUTPUT_DIR% %%W in ( *.txt *.conf *.sql *.c *.cpp *.hpp *.h *.bat *.p :ZIP_PACK ::======= :: Forcefully disable delayed expansion because of exclamation marks in 7z switches -setlocal DisableDelayedExpansion +@setlocal DisableDelayedExpansion -set SKIP_FILES=-x!installation_readme.txt +@set SKIP_FILES=-x!installation_readme.txt -if "%FBBUILD_SHIP_PDB%" == "ship_pdb" ( - set FBBUILD_ZIPFILE=%FBBUILD_INSTALL_IMAGES%\Firebird-%FBBUILD_FILE_ID%_pdb%FBBUILD_FILENAME_SUFFIX%.zip +@if "%FBBUILD_SHIP_PDB%" == "ship_pdb" ( + set FBBUILD_ZIPFILE=%FBBUILD_INSTALL_IMAGES%\Firebird-%FBBUILD_FILE_ID%-pdb%FBBUILD_FILENAME_SUFFIX%.zip ) else ( set FBBUILD_ZIPFILE=%FBBUILD_INSTALL_IMAGES%\Firebird-%FBBUILD_FILE_ID%%FBBUILD_FILENAME_SUFFIX%.zip set SKIP_FILES=%SKIP_FILES% -x!*.pdb ) :: No need to ship this file with the msi runtime -set SKIP_FILES=%SKIP_FILES% -x!*.wixpdb +@set SKIP_FILES=%SKIP_FILES% -x!*.wixpdb -if "%FB2_EXAMPLES%" == "0" set SKIP_FILES=%SKIP_FILES% -xr-!examples +@if "%FB2_EXAMPLES%" == "0" set SKIP_FILES=%SKIP_FILES% -xr-!examples -if exist %FBBUILD_ZIPFILE% ( - @del %FBBUILD_ZIPFILE% -) +@if exist %FBBUILD_ZIPFILE% del %FBBUILD_ZIPFILE% -%SEVENZIP%\7z.exe a -r -tzip -mx9 %SKIP_FILES% %FBBUILD_ZIPFILE% %FB_OUTPUT_DIR%\* +@%SEVENZIP%\7z.exe a -r -tzip -mx9 %SKIP_FILES% %FBBUILD_ZIPFILE% %FB_OUTPUT_DIR%\* -endlocal +@endlocal ::End of ZIP_PACK ::---------------- @goto :EOF -:TOUCH_ALL -::======== -::Set file timestamp to something meaningful. -::While building and testing this feature might be annoying, so we don't do it. -::========================================================== -setlocal - -if /I not "%FBBUILD_BUILDTYPE%"=="release" goto :EOF -if not defined TOUCH_COMMAND echo POSIX touch utility not found && exit /b 1 - -set TIMESTRING=0%FB_MAJOR_VER%:0%FB_MINOR_VER%:0%FB_REV_NO% - -:: Perhaps here we should touch directories as well -:: Here and there XXX_COMMAND is "call"-ed in case if it is a batch file - -@echo Touching release build files with %TIMESTRING% timestamp - -@for /R %FB_OUTPUT_DIR% %%F in ( * ) do ( - call %TOUCH_COMMAND% -c -d %TIMESTRING% %%F || exit /b 1 -) - -endlocal - -::End of TOUCH_ALL -::---------------- -@goto :EOF - - :ISX_PACK ::======= :: Now let's go and build the installable .exe @@ -546,7 +503,7 @@ endlocal :: ::================================================= @echo. -call %ISCC_COMMAND% %FB_ROOT_PATH%\builds\install\arch-specific\win32\FirebirdInstall.iss +@call %ISCC_COMMAND% %FB_ROOT_PATH%\builds\install\arch-specific\win32\FirebirdInstall.iss @echo. ::End of ISX_PACK @@ -558,22 +515,24 @@ call %ISCC_COMMAND% %FB_ROOT_PATH%\builds\install\arch-specific\win32\FirebirdIn ::========= :: Generate the md5sum checksum file ::================================== -if not defined MD5_COMMAND ( +@if not defined MD5_COMMAND ( call :WARNING md5sum utility not found. Cannot generate md5 sums. - @goto :EOF + goto :EOF ) @echo Generating md5sums for Firebird-%PRODUCT_VER_STRING%-%FBBUILD_PACKAGE_NUMBER% :: write sums into temporary file to avoid including it into the process -pushd %FBBUILD_INSTALL_IMAGES% -call %MD5_COMMAND% Firebird-%PRODUCT_VER_STRING%?%FBBUILD_PACKAGE_NUMBER%*.* >md5sum.tmp +@pushd %FBBUILD_INSTALL_IMAGES% +@call %MD5_COMMAND% Firebird-%PRODUCT_VER_STRING%?%FBBUILD_PACKAGE_NUMBER%*.* > md5sum.tmp :: then rename it to the proper name -if not errorlevel 1 ( +@if not ERRORLEVEL 1 ( del Firebird-%PRODUCT_VER_STRING%-%FBBUILD_PACKAGE_NUMBER%.md5sum >nul 2>nul ren md5sum.tmp Firebird-%PRODUCT_VER_STRING%-%FBBUILD_PACKAGE_NUMBER%.md5sum +) else ( + echo Error calling %0 & popd & @goto :END ) -popd +@popd ::End of DO_MD5SUMS ::----------------- @@ -637,46 +596,50 @@ popd :ERROR ::==== :: errorlevel gets reset automatically so capture it before we lose it. -set ERRLEV=%errorlevel% +@set ERRLEV=%ERRORLEVEL% @echo. @echo Error %ERRLEV% in BuildExecutableInstall @echo %* @echo. ::End of ERROR ::------------ -@goto :EOF +@goto :END :WARNING ::====== -set ERRLEV=%errorlevel% +@set ERRLEV=%ERRORLEVEL% @echo. @echo **** WARNING - Execution of a non-critical component failed with error level %ERRLEV%. **** @echo %* @echo. -if "%FBBUILD_PROD_STATUS%"=="PROD" ( -@echo. -@echo Production status is Final or Release Candidate -@echo Error %ERRLEV% must be fixed before continuing -@echo. +@if "%FBBUILD_PROD_STATUS%" == "PROD" ( + echo. + echo Production status is Final or Release Candidate + echo Error %ERRLEV% must be fixed before continuing + echo. ) else ( -set ERRLEV=0 + set ERRLEV= + ver > nul ) +::End of WARNING +::-------------- @goto :EOF :MAIN ::==== ::Check if on-line help is required -for %%v in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do ( - ( @if /I "%%v"=="-h" (goto :HELP & goto :EOF) ) - ( @if /I "%%v"=="/h" (goto :HELP & goto :EOF) ) - ( @if /I "%%v"=="HELP" (goto :HELP & goto :EOF) ) +@for %%v in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do ( + if /I "%%v"=="-h" ( goto :HELP & goto :EOF ) + if /I "%%v"=="/h" ( goto :HELP & goto :EOF ) + if /I "%%v"=="HELP" ( goto :HELP & goto :EOF ) ) pushd ..\..\..\win32 ::This must be called from the directory it resides in. @call setenvvar.bat +@if ERRORLEVEL 1 ( popd & ( call :ERROR Failure after calling setenvvar.bat ) & goto :END ) popd @if errorlevel 1 (goto :END) @@ -684,76 +647,71 @@ popd @echo. @echo Reading command-line parameters... -@(@call :SET_PARAMS %* ) -@if "%ERRLEV%"=="1" (@goto :ERROR %errorlevel% calling SET_PARAMS && @goto :END) +@(call :SET_PARAMS %* ) +@if ERRORLEVEL 1 (call :ERROR Calling SET_PARAMS & goto :END) @echo. @echo Checking that all required components are available... -@(@call :CHECK_ENVIRONMENT ) || (@echo Error calling CHECK_ENVIRONMENT && @goto :END) +@( call :CHECK_ENVIRONMENT ) || ( echo Error calling CHECK_ENVIRONMENT & goto :END ) @echo. @echo Setting version number... -@(@call :SET_VERSION ) || (@echo Error calling SET_VERSION && @goto :END) +@( call :SET_VERSION ) || ( echo Error calling SET_VERSION & goto :END ) @echo. @echo Copying additional files needed for installation, documentation etc. -@(@call :COPY_XTRA ) || (@echo Error calling COPY_XTRA && @goto :END ) +@( call :COPY_XTRA ) || ( echo Error calling COPY_XTRA & goto :END ) @echo. :: WIX is not necessary for a snapshot build, so we don't throw :: an error if WIX is not defined. On the other hand, :: if it is there anyway, use it. -if defined WIX ( -@echo Building MSI runtimes -@(@call :BUILD_CRT_MSI ) || (@echo Error calling BUILD_CRT_MSI && @goto :END) -@echo. +@if defined WIX ( + echo Building MSI runtimes + ( call :BUILD_CRT_MSI ) || ( echo Error calling BUILD_CRT_MSI & goto :END ) + echo. ) @echo Prepare include directory -@(@call :INCLUDE_DIR ) || (@echo Error calling INCLUDE_DIR && @goto :END) +@( call :INCLUDE_DIR ) || ( echo Error calling INCLUDE_DIR & goto :END ) @echo. @echo Writing databases conf -@(@call :DB_CONF ) || (@echo Error calling DB_CONF && @goto :END) +@( call :DB_CONF ) || ( echo Error calling DB_CONF & goto :END ) @echo. @echo Copying miscellany such as the QLI help database -@(@call :MISC ) || (@echo Error calling MISC & @goto :END) +@( call :MISC ) || ( echo Error calling MISC & goto :END) @echo. @echo Copying firebird.msg -@(@call :FB_MSG ) || (@echo Error calling FB_MSG && @goto :END) +@( call :FB_MSG ) || ( echo Error calling FB_MSG & goto :END ) @echo. @echo Fix up line endings... -@(@call :SET_CRLF ) || (@echo Error calling SET_CRLF && @goto :EOF) -@echo. - -::@echo Creating .local files for libraries -::@(@call :TOUCH_LOCAL ) || (@echo Error calling TOUCH_LOCAL & @goto :END) -::@echo. - -@(@call :TOUCH_ALL ) || (@echo Error calling TOUCH_ALL && @goto :END) +@( call :SET_CRLF ) || ( echo Error calling SET_CRLF & goto :EOF ) @echo. -if %FBBUILD_ZIP_PACK% EQU 1 ( -@echo Zipping files for zip pack -@(@call :ZIP_PACK ) || (@echo Error calling ZIP_PACK && @goto :END) -@echo. +@if %FBBUILD_ZIP_PACK% EQU 1 ( + echo Zipping files for zip pack + ( call :ZIP_PACK ) || ( echo Error calling ZIP_PACK & goto :END ) + echo. ) -if %FBBUILD_ISX_PACK% EQU 1 ( -@echo Now let's compile the InnoSetup scripts -@(@call :ISX_PACK ) || (@echo Error calling ISX_PACK && @goto :END) -@echo. +@if %FBBUILD_ISX_PACK% EQU 1 ( + echo Now let's compile the InnoSetup scripts + ( call :ISX_PACK ) || ( echo Error calling ISX_PACK & goto :END ) + echo. ) -@(@call :DO_MD5SUMS ) || (@echo Error calling DO_MD5SUMS && @goto :END) - +@( call :DO_MD5SUMS ) || ( echo Error calling DO_MD5SUMS & goto :END) @echo. @echo Completed building installation kit(s) @echo. -::@if %FB2_ISS_DEBUG% equ 0 (ENDLOCAL) +:: If we got this far then be sure to reset ERRLEV +:: because run_all.bat will check for ERRLEV +@set ERRLEV= + ::End of MAIN ::----------- @goto :END diff --git a/builds/install/arch-specific/win32/FirebirdInstall.iss b/builds/install/arch-specific/win32/FirebirdInstall.iss index 5f39455bd66..25e8b6edb86 100644 --- a/builds/install/arch-specific/win32/FirebirdInstall.iss +++ b/builds/install/arch-specific/win32/FirebirdInstall.iss @@ -8,7 +8,7 @@ ; for the specific language governing rights and limitations under the ; License. ; -; The Original Code is copyright 2001-2021 Paul Reeves for IBPhoenix. +; The Original Code is copyright 2001-2024 Paul Reeves for IBPhoenix. ; ; The Initial Developer of the Original Code is Paul Reeves for IBPhoenix. ; @@ -23,9 +23,9 @@ ; Usage Notes: ; -; This script has been designed to work with Inno Setup v6.1.2 +; This script has been designed to work with Inno Setup v6.2.1 ; It is available as a quick start pack from here: -; http://www.jrsoftware.org/isdl.php +; https://www.jrsoftware.org/isdl.php ; ; ; Known bugs and problems etc etc. @@ -77,8 +77,8 @@ #define PackageNumber "0" #endif #define FilenameSuffix GetEnv("FBBUILD_FILENAME_SUFFIX") -#if FilenameSuffix != "" && pos('_',FilenameSuffix) == 0 -#define FilenameSuffix "_" + FilenameSuffix +#if FilenameSuffix != "" && pos('-',FilenameSuffix) == 0 +#define FilenameSuffix "-" + FilenameSuffix #endif ;-------Start of Innosetup script debug flags section @@ -138,7 +138,7 @@ ; even Windows 7 are now deprecated and hopefully no production install of ; W2K8 R2 is unpatched. If necessary we can define 'support_legacy_windows' to ; roll back this new feature but users who need to deploy to what are now -; ancient versions of windows are advised to manually install Firebird 4.0 with +; ancient versions of windows are advised to manually install Firebird with ; the zip package. #ifdef support_legacy_windows #define MINVER "6.0" @@ -208,13 +208,6 @@ #endif #endif -#if FB_BUILD_TYPE == "T" -;If we are still under development we can ignore some missing files. -#define SkipFileIfDevStatus " skipifsourcedoesntexist " -#else -#define SkipFileIfDevStatus " " -#endif - ;This location is relative to SourceDir (declared below) #define FilesDir="output_" + PlatformTarget #if PlatformTarget == "x64" @@ -242,14 +235,17 @@ ;#endif -;Some more strings to distinguish the name of final executable +; Some more strings to distinguish the name of final executable +; shipping with debug symbols should not be confused with actual debug builds #ifdef ship_pdb -#define pdb_str="_pdb" +#define pdb_str="-pdb" #else #define pdb_str="" #endif +; This is intended for builds that have been built with the debug flag +; So far we have never actually released such a build. #if GetEnv("FBBUILD_BUILDTYPE") == "debug" -#define debug_str="_debug" +#define debug_str="-debug" #else #define debug_str="" #endif @@ -273,8 +269,8 @@ AppVersion={#MyAppVerString} VersionInfoVersion={#MyAppVerString} SourceDir={#Root} -OutputBaseFilename={#MyAppName}-{#MyAppVerString}_{#PackageNumber}_{#PlatformTarget}{#debug_str}{#pdb_str}{#FilenameSuffix} -;OutputManifestFile={#MyAppName}-{#MyAppVerString}_{#PackageNumber}_{#PlatformTarget}{#debug_str}{#pdb_str}{#FilenameSuffix}_Setup-Manifest.txt +OutputBaseFilename={#MyAppName}-{#MyAppVerString}-{#PackageNumber}-{#PlatformTarget}{#debug_str}{#pdb_str}{#FilenameSuffix} +;OutputManifestFile={#MyAppName}-{#MyAppVerString}-{#PackageNumber}-{#PlatformTarget}{#debug_str}{#pdb_str}{#FilenameSuffix}-Setup-Manifest.txt OutputDir=builds\install_images ;!!! These directories are as seen from SourceDir !!! #define ScriptsDir "builds\install\arch-specific\win32" @@ -377,14 +373,14 @@ Name: CopyFbClientAsGds32Task; Description: {cm:CopyFbClientAsGds32Task}; Compon [Run] ; due to the changes required to support MSVC15 support for earlier versions is now broken. #if Int(msvc_runtime_major_version,14) >= 14 -Filename: msiexec.exe; Parameters: "/qn /norestart /i ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi"" /L*v ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.log"" "; StatusMsg: "Installing MSVC 32-bit runtime libraries to system directory"; Check: HasWI30; Components: ClientComponent; +Filename: msiexec.exe; Parameters: "/qn /norestart /i ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi"" /L*v ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.log"" "; StatusMsg: {cm:InstallingMSVC32runtimes}; Check: HasWI30; Components: ClientComponent; #if PlatformTarget == "x64" -Filename: msiexec.exe; Parameters: "/qn /norestart /i ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.msi"" /L*v ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.log"" "; StatusMsg: "Installing MSVC 64-bit runtime libraries to system directory"; Check: HasWI30; Components: ClientComponent; +Filename: msiexec.exe; Parameters: "/qn /norestart /i ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.msi"" /L*v ""{tmp}\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.log"" "; StatusMsg: {cm:InstallingMSVC64runtimes}; Check: HasWI30; Components: ClientComponent; #endif #endif ;Only register Firebird if we are installing AND configuring -Filename: {app}\instreg.exe; Parameters: "install "; StatusMsg: {cm:instreg}; MinVersion: {#MinVer}; Components: ClientComponent; Flags: runminimized; Check: ConfigureFirebird; +Filename: {app}\instreg.exe; Parameters: "install "; StatusMsg: {cm:instreg}; MinVersion: {#MinVer}; Components: ServerComponent; Flags: runminimized; Check: ConfigureFirebird; Filename: {app}\instclient.exe; Parameters: "install fbclient"; StatusMsg: {cm:instclientCopyFbClient}; MinVersion: {#MinVer}; Components: ClientComponent; Flags: runminimized; Check: CopyFBClientLib; Filename: {app}\instclient.exe; Parameters: "install gds32"; StatusMsg: {cm:instclientGenGds32}; MinVersion: {#MinVer}; Components: ClientComponent; Flags: runminimized; Check: CopyGds32 @@ -410,7 +406,7 @@ Filename: "{#MyAppURL}/afterinstall"; Description: "After installation - What Ne Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: Firebird; ValueData: ; Flags: uninsdeletevalue; Tasks: UseApplicationTask; Check: ConfigureFirebird; ;This doesn't seem to get cleared automatically by instreg on uninstall, so lets make sure of it -Root: HKLM; Subkey: "SOFTWARE\Firebird Project"; Flags: uninsdeletekeyifempty; Components: ClientComponent DevAdminComponent ServerComponent +Root: HKLM; Subkey: "SOFTWARE\Firebird Project"; Flags: uninsdeletekeyifempty; Components: ServerComponent ;Clean up Invalid registry entries from previous installs. Root: HKLM; Subkey: "SOFTWARE\FirebirdSQL"; ValueType: none; Flags: deletekey; @@ -460,8 +456,8 @@ Source: {#FilesDir}\fbtrace.conf; DestDir: {app}; DestName: fbtrace.conf; Compon Source: {#FilesDir}\databases.conf; DestDir: {app}; Components: ClientComponent; Flags: uninsneveruninstall onlyifdoesntexist Source: {#FilesDir}\replication.conf; DestDir: {app}; DestName: replication.conf.default; Components: ServerComponent; Source: {#FilesDir}\replication.conf; DestDir: {app}; Components: ServerComponent; Flags: uninsneveruninstall onlyifdoesntexist; check: NoReplicationConfExists; -Source: {#FilesDir}\security4.fdb; DestDir: {app}; Destname: security4.fdb.empty; Components: ServerComponent; -Source: {#FilesDir}\security4.fdb; DestDir: {app}; Components: ServerComponent; Flags: uninsneveruninstall onlyifdoesntexist +Source: {#FilesDir}\security{#FB_MAJOR_VER}.fdb; DestDir: {app}; Destname: security{#FB_MAJOR_VER}.fdb.empty; Components: ServerComponent; +Source: {#FilesDir}\security{#FB_MAJOR_VER}.fdb; DestDir: {app}; Components: ServerComponent; Check: ConfigureAuthentication; Flags: uninsneveruninstall onlyifdoesntexist Source: {#FilesDir}\firebird.msg; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion Source: {#FilesDir}\firebird.log; DestDir: {app}; Components: ServerComponent; Flags: uninsneveruninstall skipifsourcedoesntexist external dontcopy @@ -476,7 +472,7 @@ Source: {#FilesDir}\firebird.exe; DestDir: {app}; Components: ServerComponent; F Source: {#FilesDir}\fb_lock_print.exe; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion Source: {#FilesDir}\ib_util.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion Source: {#FilesDir}\instclient.exe; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion -Source: {#FilesDir}\instreg.exe; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#FilesDir}\instreg.exe; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion Source: {#FilesDir}\instsvc.exe; DestDir: {app}; Components: ServerComponent; MinVersion: {#MinVer}; Flags: sharedfile ignoreversion Source: {#FilesDir}\isql.exe; DestDir: {app}; Components: DevAdminComponent; Flags: ignoreversion Source: {#FilesDir}\nbackup.exe; DestDir: {app}; Components: DevAdminComponent; Flags: ignoreversion @@ -485,17 +481,28 @@ Source: {#FilesDir}\fbsvcmgr.exe; DestDir: {app}; Components: DevAdminComponent; Source: {#FilesDir}\fbtracemgr.exe; DestDir: {app}; Components: DevAdminComponent; Flags: ignoreversion Source: {#FilesDir}\fbclient.dll; DestDir: {app}; Components: ClientComponent; Flags: overwritereadonly sharedfile promptifolder #if PlatformTarget == "x64" -Source: {#WOW64Dir}\fbclient.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: overwritereadonly sharedfile promptifolder {#SkipFileIfDevStatus} -Source: {#WOW64Dir}\instclient.exe; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion {#SkipFileIfDevStatus} +Source: {#WOW64Dir}\fbclient.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: overwritereadonly sharedfile promptifolder +Source: {#WOW64Dir}\instclient.exe; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion #endif -Source: {#FilesDir}\icuuc??.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion -Source: {#FilesDir}\icuin??.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion -Source: {#FilesDir}\icudt??.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion -Source: {#FilesDir}\icudt*.dat; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion +Source: {#FilesDir}\icuuc??.dll; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#FilesDir}\icuin??.dll; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#FilesDir}\icudt??.dll; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#FilesDir}\icudt*.dat; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +#if PlatformTarget == "x64" +Source: {#WOW64Dir}\icuuc??.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#WOW64Dir}\icuin??.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#WOW64Dir}\icudt??.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion +Source: {#WOW64Dir}\icudt*.dat; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion +#endif + #if PlatformTarget =="Win32" Source: {#FilesDir}\fbrmclib.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion #endif -Source: {#FilesDir}\zlib1.dll; DestDir: {app}; Components: ServerComponent; Flags: sharedfile ignoreversion + +Source: {#FilesDir}\zlib1.dll; DestDir: {app}; Components: ClientComponent; Flags: sharedfile ignoreversion +#if PlatformTarget == "x64" +Source: {#WOW64Dir}\zlib1.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile ignoreversion +#endif ;Rules for installation of MS runtimes are simplified with MSVC10 ;We just install the runtimes into the install dir. @@ -505,8 +512,8 @@ Source: {#FilesDir}\{#msvcr_filename}{#msvc_runtime_major_version}{#msvc_runtime Source: {#FilesDir}\msvcp{#msvc_runtime_major_version}{#msvc_runtime_minor_version_0}.dll; DestDir: {app}; Components: ClientComponent; Flags: sharedfile; #if PlatformTarget == "x64" ;If we are installing on x64 we need some 32-bit libraries for compatibility with 32-bit applications -Source: {#WOW64Dir}\{#msvcr_filename}{#msvc_runtime_major_version}{#msvc_runtime_minor_version_0}.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile {#SkipFileIfDevStatus}; -Source: {#WOW64Dir}\msvcp{#msvc_runtime_major_version}{#msvc_runtime_minor_version_0}.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile {#SkipFileIfDevStatus}; +Source: {#WOW64Dir}\{#msvcr_filename}{#msvc_runtime_major_version}{#msvc_runtime_minor_version_0}.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile; +Source: {#WOW64Dir}\msvcp{#msvc_runtime_major_version}{#msvc_runtime_minor_version_0}.dll; DestDir: {app}\WOW64; Components: ClientComponent; Flags: sharedfile; #endif #endif /* #if Int(msvc_runtime_major_version,14) >= 10 */ @@ -514,10 +521,10 @@ Source: {#WOW64Dir}\msvcp{#msvc_runtime_major_version}{#msvc_runtime_minor_versi #if PlatformTarget == "x64" ;MinVersion 0,5.0 means no version of Win9x and at least Win2k if NT O/S ;In addition, O/S must have Windows Installer 3.0. -Source: {#FilesDir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; Flags: {#SkipFileIfDevStatus} -Source: {#WOW64Dir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; Flags: {#SkipFileIfDevStatus} +Source: {#FilesDir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_x64.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; +Source: {#WOW64Dir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; #else -Source: {#FilesDir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; Flags: {#SkipFileIfDevStatus} +Source: {#FilesDir}\system32\vccrt{#msvc_runtime_major_version}{#msvc_runtime_minor_version_1}_Win32.msi; DestDir: {tmp}; Check: HasWI30; MinVersion: {#MinVer}; Components: ClientComponent; #endif #endif @@ -534,7 +541,7 @@ Source: {#FilesDir}\intl\fbintl.dll; DestDir: {app}\intl; Components: ServerComp Source: {#FilesDir}\intl\fbintl.conf; DestDir: {app}\intl; Components: ServerComponent; Flags: onlyifdoesntexist Source: {#FilesDir}\lib\*.*; DestDir: {app}\lib; Components: DevAdminComponent; Flags: ignoreversion; #if PlatformTarget == "x64" -Source: {#WOW64Dir}\lib\*.lib; DestDir: {app}\WOW64\lib; Components: DevAdminComponent; Flags: ignoreversion {#SkipFileIfDevStatus} +Source: {#WOW64Dir}\lib\*.lib; DestDir: {app}\WOW64\lib; Components: DevAdminComponent; Flags: ignoreversion #endif ;deprecated in FB4.0 @@ -544,25 +551,31 @@ Source: {#WOW64Dir}\lib\*.lib; DestDir: {app}\WOW64\lib; Components: DevAdminCom ;Source: {#FilesDir}\UDF\*.txt; DestDir: {app}\UDF; Components: ServerComponent; Flags: ignoreversion; Source: {#FilesDir}\plugins.conf; DestDir: {app}; Components: ServerComponent; Flags: ignoreversion; -Source: {#FilesDir}\plugins\*.dll; DestDir: {app}\plugins; Components: ServerComponent; Flags: ignoreversion; +Source: {#FilesDir}\plugins\*.dll; DestDir: {app}\plugins; Components: ServerComponent; Flags: ignoreversion; Check: IsServerInstall; +Source: {#FilesDir}\plugins\chacha.dll; DestDir: {app}\plugins; Components: ClientComponent; Flags: ignoreversion; Check: IsNotServerInstall; Source: {#FilesDir}\plugins\*.conf; DestDir: {app}\plugins; Components: ServerComponent; Flags: ignoreversion; Source: {#FilesDir}\plugins\udr\*.*; DestDir: {app}\plugins\udr; Components: ServerComponent; Flags: ignoreversion; +#if PlatformTarget == "x64" +Source: {#WOW64Dir}\plugins\chacha*.dll; DestDir: {app}\WOW64\plugins; Components: ClientComponent; Flags: ignoreversion; +#endif Source: {#FilesDir}\misc\*.*; DestDir: {app}\misc; Components: ServerComponent; Flags: ignoreversion createallsubdirs recursesubdirs ; Source: {#FilesDir}\tzdata\*.*; DestDir: {app}\tzdata; Components: ClientComponent; Flags: ignoreversion; -;Source: {#FilesDir}\system32\Firebird2Control.cpl; DestDir: {sys}; Components: ServerComponent; MinVersion: {#MinVer}; Flags: sharedfile ignoreversion promptifolder restartreplace uninsrestartdelete; Check: InstallCPLApplet #endif /* files */ #ifdef examples -Source: {#FilesDir}\examples\*.*; DestDir: {app}\examples; Components: DevAdminComponent; Flags: ignoreversion createallsubdirs recursesubdirs {#SkipFileIfDevStatus}; +Source: {#FilesDir}\examples\*.*; DestDir: {app}\examples; Components: DevAdminComponent; Flags: ignoreversion createallsubdirs recursesubdirs; #endif #ifdef ship_pdb Source: {#FilesDir}\fbclient.pdb; DestDir: {app}; Components: ClientComponent; Source: {#FilesDir}\firebird.pdb; DestDir: {app}; Components: ServerComponent; -;Source: {#FilesDir}\fbembed.pdb; DestDir: {app}; Components: ClientComponent; +Source: {#FilesDir}\gbak.pdb; DestDir: {app}; Components: DevAdminComponent; +Source: {#FilesDir}\gfix.pdb; DestDir: {app}; Components: DevAdminComponent; +Source: {#FilesDir}\isql.pdb; DestDir: {app}; Components: ClientComponent; +Source: {#FilesDir}\plugins\*.pdb; DestDir: {app}\plugins; Components: ServerComponent; #if PlatformTarget == "x64" Source: {#WOW64Dir}\fbclient.pdb; DestDir: {app}\WOW64; Components: ClientComponent; #endif @@ -577,7 +590,7 @@ Filename: {app}\instclient.exe; Parameters: " remove fbclient"; StatusMsg: {cm:i Filename: {app}\wow64\instclient.exe; Parameters: " remove gds32"; StatusMsg: {cm:instclientDecLibCountGds32}; MinVersion: {#MinVer}; Flags: runminimized 32bit; RunOnceId: RemoveGDS32x86 Filename: {app}\wow64\instclient.exe; Parameters: " remove fbclient"; StatusMsg: {cm:instclientDecLibCountFbClient}; MinVersion: {#MinVer}; Flags: runminimized 32bit; RunOnceId: RemoveFbClientx86 #endif -Filename: {app}\instreg.exe; Parameters: " remove"; StatusMsg: {cm:instreg}; MinVersion: {#MinVer}; Flags: runminimized; RunOnceId: RemoveRegistryEntry +Filename: {app}\instreg.exe; Parameters: " remove"; StatusMsg: {cm:instreg}; MinVersion: {#MinVer}; Components: ServerComponent; Flags: runminimized; RunOnceId: RemoveRegistryEntry [UninstallDelete] Type: files; Name: "{app}\*.lck" @@ -594,10 +607,14 @@ program Setup; // Some global variables are also in FirebirdInstallEnvironmentChecks.inc // This is not ideal, but then this scripting environment is not ideal, either. // The basic point of the include files is to isolate chunks of code that are -// a) Form a module or have common functionality +// a) From a module or have common functionality // b) Debugged. // This hopefully keeps the main script simpler to follow. + +const + UNDEFINED = -1; + Var InstallRootDir: String; FirebirdConfSaved: String; @@ -613,6 +630,8 @@ Var SYSDBAPassword: String; // SYSDBA password + init_secdb: integer; // Is set to UNDEFINED by default in InitializeSetup + #ifdef setuplogging // Not yet implemented - leave log in %TEMP% // OkToCopyLog : Boolean; // Set when installation is complete. @@ -663,7 +682,7 @@ begin // or // (pos('/?',Uppercase(CommandLine)) > 0) or // InnoSetup displays its own help if these switches are passed. // (pos('/H',Uppercase(CommandLine)) > 0) ) // Note also that our help scren only appears after the Choose Language dialogue :-( - then begin + then begin ShowHelpDlg; result := False; Exit; @@ -695,7 +714,7 @@ begin exit; end; - //By default we want to install and confugure, + //By default we want to install and configure, //unless subsequent analysis suggests otherwise. InstallAndConfigure := Install + Configure; @@ -704,6 +723,7 @@ begin InitExistingInstallRecords; AnalyzeEnvironment; result := AnalysisAssessment; + init_secdb := UNDEFINED; end; @@ -833,26 +853,42 @@ begin end; - - function InitSecurityDB: Boolean; var AStringList: TStringList; TempDir: String; - ResultCode: Integer; - CmdStr: string; + ResultCode: Integer; + CmdStr: string; + InputStr: string; + OutputStr: string; begin - TempDir := ExpandConstant( '{tmp}' ); - CmdStr := ExpandConstant( '{app}\isql.exe' ); - AStringList := TStringList.create; - with AStringList do begin - Add( 'create user ' + GetAdminUserName + ' password ''' + GetAdminUserPassword + ''' using plugin Srp;' ); - Add( 'commit;' ); //Technically exit implies a commit so this not necessary. OTOH, explicitly committing makes for more readable code. - Add( 'exit;' ); - SaveToFile( Tempdir +'\temp.sql' ); - end; - Result := Exec( CmdStr , ' -m -m2 -user SYSDBA -i ' + TempDir + '\temp.sql -o ' + TempDir + '\temp.sql.txt employee ' , TempDir, SW_HIDE, ewWaitUntilTerminated, ResultCode ); - DeleteFile( TempDir + +'\temp.sql '); + TempDir := ExpandConstant( '{tmp}' ); + CmdStr := ExpandConstant( '{app}\isql.exe' ); + InputStr := TempDir + '\' + 'temp.sql'; + OutputStr := InputStr + '.txt'; + + // Ensure these files do not already exist. + if FileExists( InputStr ) then DeleteFile( InputStr ); + if FileExists( OutputStr ) then DeleteFile( OutputStr ); + + AStringList := TStringList.create; + with AStringList do begin + Add( 'create or alter user ' + GetAdminUserName + ' password ''' + GetAdminUserPassword + ''' using plugin Srp;' ); + Add( 'exit;' ); + SaveToFile( InputStr ); + end; + Result := Exec( CmdStr , ' -m -m2 -user SYSDBA -i ' + InputStr + ' -o ' + OutputStr + ' employee ' , TempDir, SW_HIDE, ewWaitUntilTerminated, ResultCode ); + if ResultCode <> 0 then begin + Result := False; + Log( 'In function InitSecurityDB Exec isql returned ' + IntToStr(ResultCode) + ' executing ' + InputStr ); + end; + if FindInFile( OutputStr, 'error' ) then begin + Result := False; + Log( 'In function InitSecurityDB FindInFile found an error in ' + OutputStr ); + end; + + DeleteFile( InputStr ); + DeleteFile( OutputStr ); end; @@ -936,16 +972,16 @@ begin // These attempts to modify firebird.conf may not survice repeated installs. - if WizardIsTaskSelected('UseClassicServerTask') then - ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Classic','#'); + if WizardIsTaskSelected('UseClassicServerTask') then + ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Classic','#'); if WizardIsTaskSelected('UseSuperClassicTask') then - ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = SuperClassic','#'); + ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = SuperClassic','#'); - if WizardIsTaskSelected('UseSuperServerTask') then - ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Super','#'); + if WizardIsTaskSelected('UseSuperServerTask') then + ReplaceLine(GetAppPath+'\firebird.conf','ServerMode = ','ServerMode = Super','#'); - end; + end; end; end; @@ -968,16 +1004,16 @@ var begin //Do resize only once! if wizardform.height = initWizardHeight then begin - AHeight := HEIGHT_INCREASE; - AWidth := WIDTH_INCREASE; + AHeight := HEIGHT_INCREASE; + AWidth := WIDTH_INCREASE; - if not Increase then begin - AHeight := (AHeight * (-1)); - AWidth := (AWidth * (-1)); - end; + if not Increase then begin + AHeight := (AHeight * (-1)); + AWidth := (AWidth * (-1)); + end; - SetupWizardFormComponentsArrays; - ResizeWizardFormHeight(AHeight); + SetupWizardFormComponentsArrays; + ResizeWizardFormHeight(AHeight); // ResizeWizardFormWidth(AWidth); end; end; @@ -1001,9 +1037,8 @@ var AppStr: String; ReadMeFileStr: String; begin - case CurStep of + case CurStep of ssInstall: begin -// RenamePreFB3RC1Files; SetupSharedFilesArray; GetSharedLibCountBeforeCopy; end; @@ -1014,10 +1049,11 @@ begin IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\firebird.log', false); IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\databases.conf', false); IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\fbtrace.conf', false); - IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\security4.fdb', false); + IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\security{#FB_MAJOR_VER}.fdb', false); IncrementSharedCount(Is64BitInstallMode, GetAppPath+'\replication.conf', false); - InitSecurityDB; + if init_secdb = 1 then + InitSecurityDB; //Fix up conf file UpdateFirebirdConf; @@ -1062,7 +1098,7 @@ end; // # FIXME - we can probably remove this function function ChooseUninstallIcon(Default: String): String; begin - result := GetAppPath+'\firebird.exe'; + result := GetAppPath+'\firebird.exe'; end; //InnoSetup has a Check Parameter that allows installation if the function returns true. @@ -1140,8 +1176,8 @@ begin aStringList.add(appPath+'\firebird.log'); aStringList.add(appPath+'\databases.conf'); aStringList.add(appPath+'\fbtrace.conf'); - aStringList.add(appPath+'\security4.fdb'); - aStringList.add(appPath+'\security4.fdb.old'); + aStringList.add(appPath+'\security{#FB_MAJOR_VER}.fdb'); + aStringList.add(appPath+'\security{#FB_MAJOR_VER}.fdb.old'); aStringList.add(appPath+'\replication.conf'); for count := 0 to aStringList.count - 1 do begin @@ -1185,12 +1221,12 @@ end; function NextButtonClick(CurPageID: Integer): Boolean; var - i: integer; + i: integer; begin Result := True; case CurPageID of AdminUserPage.ID : begin - { check user has entered new sysdba password correctly. } + { check user has entered new sysdba password correctly. } i := CompareStr(AdminUserPage.Values[0],AdminUserPage.Values[1]); If not (i = 0) then begin Result := False; @@ -1204,3 +1240,5 @@ end; begin end. + +; kate: replace-tabs on; indent-width 2; tab-width 2; replace-tabs-save on; syntax Pascal; diff --git a/builds/install/arch-specific/win32/FirebirdInstallEnvironmentChecks.inc b/builds/install/arch-specific/win32/FirebirdInstallEnvironmentChecks.inc index 7472d1500e8..6f959bd7e4c 100644 --- a/builds/install/arch-specific/win32/FirebirdInstallEnvironmentChecks.inc +++ b/builds/install/arch-specific/win32/FirebirdInstallEnvironmentChecks.inc @@ -106,31 +106,56 @@ Const FB25_x64_Install = 14; FB30Install = 15; FB30_x64_Install = 16; - Current32Install = FB30Install; - Current64Install = FB30_x64_Install; + FB40Install = 17; + FB40_x64_Install = 18; + FB50Install = 19; + FB50_x64_Install = 20; + FB60Install = 21; + FB60_x64_Install = 22; + FB70Install = 23; + FB70_x64_Install = 24; + FB80Install = 25; + FB80_x64_Install = 26; + FB90Install = 27; + FB90_x64_Install = 28; + MaxProdInstalled = FB90_x64_Install; + + Current32Install = FB{#FB_MAJOR_VER}0Install; + Current64Install = FB{#FB_MAJOR_VER}0_x64_Install; - MaxProdInstalled = FB30_x64_Install; //ProductsInstalled - IB4 = $00001; - IB5 = $00002; - IB6 = $00004; - IB65 = $00008; - IB70 = $00010; - FB1 = $00020; - FB15RC = $00040; - FB15 = $00080; - FB20 = $00100; - IB80 = $00200; - IB81 = $00400; - FB21 = $00800; - FB25 = $01000; - FB30 = $02000; - FB21_x64 = $04000; - FB25_x64 = $08000; - FB30_x64 = $10000; - CurFB32 = FB30; - CurFB64 = FB30_x64; + IB4 = 0; + IB5 = 1; + IB6 = 2; + IB65 = 3; + IB70 = 4; + FB1 = 5; + FB15RC = 6; + FB15 = 7; + FB20 = 8; + IB80 = 9; + IB81 = 10; + FB21 = 11; + FB21_x64 = 12; + FB25 = 13; + FB25_x64 = 14; + FB30 = 15; + FB30_x64 = 16; + FB40 = 17; + FB40_x64 = 18; + FB50 = 19; + FB50_x64 = 20; + FB60 = 21; + FB60_x64 = 22; + FB70 = 23; + FB70_x64 = 24; + FB80 = 25; + FB80_x64 = 26; + FB90 = 27; + FB90_x64 = 28; + CurFB32 = FB{#FB_MAJOR_VER}0; + CurFB64 = FB{#FB_MAJOR_VER}0_x64; // Likely gds32 version strings for installed versions of Firebird or InterBase are: // [6,0,n,n] InterBase 6.0 @@ -373,6 +398,138 @@ begin ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; end; + FB40Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB40_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB50Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB50_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB60Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB60_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB70Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB70_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB80Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB80_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB90Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (Win32) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM32; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + + FB90_x64_Install: begin + ProductsInstalledArray[product].Description := FBDesc + ' (x64) '; + ProductsInstalledArray[product].RegKey := FB2RegKey; + ProductsInstalledArray[product].RegEntry := FBRegPathEntry; + ProductsInstalledArray[product].MessageFile := FBMessageFile; + ProductsInstalledArray[product].RootKey := HKLM64; + ProductsInstalledArray[product].Path := GetRegistryEntry(ProductsInstalledArray[product].RootKey, + ProductsInstalledArray[product].RegKey, ProductsInstalledArray[product].RegEntry); + ProductsInstalledArray[product].BinPath := ProductsInstalledArray[product].Path; + end; + end; //case ProductsInstalledArray[product].RegVersion := GetRegistryEntry( @@ -387,11 +544,9 @@ var product: Integer; gds32VersionString: String; VerInt: Array of Integer; -// BoolOne, BoolTwo, BoolEval: Boolean; -// EvalOne, EvalTwo: Integer; + dbg_ProductPath, dbg_BinPath, dbg_ClientVersion, dbg_GBAKVersion, dbg_Server: String; dbg_InstallType : Integer; -// eval_bool: boolean; begin @@ -707,6 +862,150 @@ begin ProductsInstalledArray[product].InstallType := NotInstalled; end; + FB40Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '4.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB40_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '4.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + + FB50Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '5.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB50_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '5.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + + FB60Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '6.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB60_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '6.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + + FB70Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '7.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB70_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '7.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + + FB80Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '8.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB80_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '8.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + + FB90Install: begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '9.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40; + ProductsInstalledCount := ProductsInstalledCount + 1; + end; + end; + + FB90_x64_Install: begin + if iswin64 then begin + if (CompareVersion(ProductsInstalledArray[product].ClientVersion, '9.0.0.0',2) <> 0) then + ProductsInstalledArray[product].InstallType := NotInstalled + else + if ((ProductsInstalledArray[product].InstallType AND ClientInstall) = ClientInstall) then begin + ProductsInstalled := ProductsInstalled + FB40_x64; + ProductsInstalledCount := ProductsInstalledCount + 1; + end + end + else + ProductsInstalledArray[product].InstallType := NotInstalled; + end; + end;//case @@ -795,7 +1094,7 @@ else SharedFileArray[27].Filename := ExpandConstant('{app}')+'databases.conf'; SharedFileArray[28].Filename := ExpandConstant('{app}')+'firebird.conf'; SharedFileArray[29].Filename := ExpandConstant('{app}')+'firebird.log'; -SharedFileArray[30].Filename := ExpandConstant('{app}')+'security4.fdb'; +SharedFileArray[30].Filename := ExpandConstant('{app}')+'security{#FB_MAJOR_VER}.fdb'; SharedFileArray[31].Filename := ExpandConstant('{app}')+'fbtrace.conf'; SharedFileArray[32].Filename := ExpandConstant('{app}')+'fbsvcmgr.exe'; SharedFileArray[33].Filename := ExpandConstant('{app}')+'fbrmclib.dll'; @@ -803,7 +1102,7 @@ SharedFileArray[34].Filename := ExpandConstant('{app}')+'fbtracemgr.exe'; SharedFileArray[35].Filename := ExpandConstant('{app}')+'zlib1.dll'; SharedFileArray[36].Filename := ExpandConstant('{app}')+'replication.conf'; -// FIXME +// FIXME // Add in WOW64 here. end; @@ -890,9 +1189,27 @@ begin end; +function IsServerInstall: Boolean; +begin + if WizardIsComponentSelected('ServerComponent') then + Result := true + else + Result := False; +end; + + +function IsNotServerInstall: Boolean; +begin + if IsServerInstall then + Result := False + else + Result := True; +end; + + function ConfigureFirebird: boolean; begin - result := (InstallAndConfigure AND Configure) = Configure; + Result := (InstallAndConfigure AND Configure) = Configure; end; @@ -1006,7 +1323,7 @@ begin result := False; if (ConfigureFirebird) then result := WizardIsTaskSelected('UseSuperServerTask\UseGuardianTask') - or WizardIsTaskSelected('UseSuperClassicTask\UseGuardianTask'); + or WizardIsTaskSelected('UseSuperClassicTask\UseGuardianTask'); end; @@ -1135,12 +1452,11 @@ begin //If existing install of the same majorver.minorver is //found then we can upgrade it. -//// **** FIX ME **** Don't use hardcoded constants here. They get overlooked. if ( (ProductsInstalledCount = 1) AND #if PlatformTarget == "x64" - ((ProductsInstalled AND FB30_x64 ) = FB30_x64 ) ) then begin + ((ProductsInstalled AND FB{#FB_MAJOR_VER}0_x64 ) = FB{#FB_MAJOR_VER}0_x64 ) ) then begin #else - ((ProductsInstalled AND FB30 ) = FB30 ) ) then begin + ((ProductsInstalled AND FB{#FB_MAJOR_VER}0 ) = FB{#FB_MAJOR_VER}0 ) ) then begin #endif result := true; exit; @@ -1163,28 +1479,28 @@ begin end; -{ procedure RenamePreFB3RC1Files; -//The method of specifying the architecture used changed after Beta 2 -//Detect this old config and rename it. -var - FirebirdConfStr: AnsiString; +function ConfigureAuthentication: boolean; +// This function should only be called once - when the innosetup installer tries to +// install the secdb. If it is called a second time it will always find the secdb +// exists, even if it hasn't been configured. The only real way to test whether we +// should configure authentication is to actually _open_ a database and read the +// sec$users table. Except we cannot do that as we need this information before we +// install the files needed to read the database. begin - if FileExists(GetAppPath+'\firebird.conf') then begin - LoadStringFromFile( GetAppPath+'\firebird.conf', FirebirdConfStr ); - if pos('SharedDatabase', FirebirdConfStr) > 0 then begin - RenameFile(GetAppPath+'\firebird.conf', GetAppPath+'\firebird.conf.preRC1'); - RenameFile(GetAppPath+'\security4.fdb', GetAppPath+'\security4.fdb.preRC1'); + // if it is the first time we are called test for existence of the security db + if init_secdb = UNDEFINED then begin + if FileExists(WizardDirValue + '\security{#FB_MAJOR_VER}.fdb') then + Result := false + else + Result := true end - end -end; -} + else + // else the result is the current setting of init_secdb + Result := Boolean(init_secdb); + + // Whatever the result, cast it to an integer and update init_secdb + init_secdb := Integer(Result); -function ConfigureAuthentication: boolean; -begin - if FileExists(WizardDirValue + '\security4.fdb') then - Result := false - else - Result := true; end; @@ -1209,3 +1525,5 @@ begin result := NOT HasWI30; end; +// kate: replace-tabs on; indent-width 2; tab-width 2; replace-tabs-save on; syntax Pascal; + diff --git a/builds/install/arch-specific/win32/FirebirdInstallGUIFunctions.inc b/builds/install/arch-specific/win32/FirebirdInstallGUIFunctions.inc index 2159dcdc928..ced599ae419 100644 --- a/builds/install/arch-specific/win32/FirebirdInstallGUIFunctions.inc +++ b/builds/install/arch-specific/win32/FirebirdInstallGUIFunctions.inc @@ -30,15 +30,15 @@ o EnumerateObjectList; - Simple demonstration of object enumeration. - o Show Help - - CreateHelpDlg; - - ShowHelpDlg: Integer; - - CloseHelpDlg; - - o Show some debug info for debugging inno setup script - - CreateDebugDlg - - CloseDebugDlg; - - ShowDebugDlg + o Show Help + - CreateHelpDlg; + - ShowHelpDlg: Integer; + - CloseHelpDlg; + + o Show some debug info for debugging inno setup script + - CreateDebugDlg + - CloseDebugDlg; + - ShowDebugDlg *) @@ -49,9 +49,9 @@ var CompGroupButtonsArray: array of string; CompGroup1, CompGroup2, CompGroup3, CompGroupButtons: TStringList; -// This is a non-exhaustive list of components that need to be repositioned -// and/or resized if the form size is changed. Use EnumerateObjectList to -// get a full list of components. +// This is a non-exhaustive list of components that need to be repositioned +// and/or resized if the form size is changed. Use EnumerateObjectList to +// get a full list of components. procedure SetupWizardFormComponentsArrays; var i: integer; @@ -85,93 +85,93 @@ begin CompGroup1Array[23]:='OuterNotebook'; CompGroup1 := TStringList.create; - + for i := 0 to GetArrayLength( CompGroup1Array )-1 do begin - CompGroup1.add( CompGroup1Array[i] ); + CompGroup1.add( CompGroup1Array[i] ); CompGroup1.objects[i] := (WizardForm.FindComponent(CompGroup1Array[i])); end; - - SetArrayLength(CompGroup2Array,8); - CompGroup2Array[0] := 'Bevel'; - CompGroup2Array[1] := 'BeveledLabel'; - CompGroup2Array[2] := 'LicenseAcceptedRadio'; - CompGroup2Array[3] := 'LicenseNotAcceptedRadio'; - CompGroup2Array[4] := 'DiskSpaceLabel'; - CompGroup2Array[5] := 'ComponentsDiskSpaceLabel'; - CompGroup2Array[6] := 'NoIconsCheck'; - CompGroup2Array[7] := 'RunList'; + + SetArrayLength(CompGroup2Array,8); + CompGroup2Array[0] := 'Bevel'; + CompGroup2Array[1] := 'BeveledLabel'; + CompGroup2Array[2] := 'LicenseAcceptedRadio'; + CompGroup2Array[3] := 'LicenseNotAcceptedRadio'; + CompGroup2Array[4] := 'DiskSpaceLabel'; + CompGroup2Array[5] := 'ComponentsDiskSpaceLabel'; + CompGroup2Array[6] := 'NoIconsCheck'; + CompGroup2Array[7] := 'RunList'; CompGroup2 := TStringList.create; for i := 0 to GetArrayLength( CompGroup2Array )-1 do begin - CompGroup2.add(CompGroup2Array[i]); + CompGroup2.add(CompGroup2Array[i]); CompGroup2.objects[i] := (WizardForm.FindComponent(CompGroup2Array[i])); end; SetArrayLength(CompGroup3Array,1); - CompGroup3Array[0] := 'WizardBitmapImage'; + CompGroup3Array[0] := 'WizardBitmapImage'; CompGroup3 := TStringList.create; for i:=0 to GetArrayLength(CompGroup3Array)-1 do begin - CompGroup3.add(CompGroup3Array[i]); + CompGroup3.add(CompGroup3Array[i]); CompGroup3.objects[i] := (WizardForm.FindComponent(CompGroup3Array[i])); end; - SetArrayLength(CompGroupButtonsArray,3); - CompGroupButtonsArray[0] := 'BackButton'; - CompGroupButtonsArray[1] := 'NextButton'; - CompGroupButtonsArray[2] := 'CancelButton'; - CompGroupButtons := TStringList.create; + SetArrayLength(CompGroupButtonsArray,3); + CompGroupButtonsArray[0] := 'BackButton'; + CompGroupButtonsArray[1] := 'NextButton'; + CompGroupButtonsArray[2] := 'CancelButton'; + CompGroupButtons := TStringList.create; for i:=0 to GetArrayLength(CompGroupButtonsArray)-1 do begin - CompGroupButtons.add(CompGroupButtonsArray[i]); + CompGroupButtons.add(CompGroupButtonsArray[i]); CompGroupButtons.objects[i] := (WizardForm.FindComponent(CompGroupButtonsArray[i])); end; end; - + procedure ResizeWizardFormHeight(AValue: Integer); var - i: integer; + i: integer; begin wizardform.height := wizardform.height+AValue; wizardform.top := wizardform.top - (AValue div 2); // Group 1 - reset height of components - for i:=0 to GetArrayLength(CompGroup1Array)-1 do - TControl(CompGroup1.objects[i]).height := TControl(CompGroup1.objects[i]).height + Avalue; + for i:=0 to GetArrayLength(CompGroup1Array)-1 do + TControl(CompGroup1.objects[i]).height := TControl(CompGroup1.objects[i]).height + Avalue; - // Group 2 - reset top of components - for i:=0 to GetArrayLength(CompGroup2Array)-1 do - TControl(CompGroup2.objects[i]).top := TControl(CompGroup2.objects[i]).top + AValue; + // Group 2 - reset top of components + for i:=0 to GetArrayLength(CompGroup2Array)-1 do + TControl(CompGroup2.objects[i]).top := TControl(CompGroup2.objects[i]).top + AValue; // Group 3 - reset top of components but keep 'centered' vertically. - for i:=0 to GetArrayLength(CompGroup3Array)-1 do - TControl( CompGroup3.objects[i]).top := TControl(CompGroup3.objects[i]).top + (AValue div 2); - - // Group Buttons - reset top of components - for i:=0 to GetArrayLength(CompGroupButtonsArray)-1 do - TControl(CompGroupButtons.objects[i]).top := TControl(CompGroupButtons.objects[i]).top + AValue; - + for i:=0 to GetArrayLength(CompGroup3Array)-1 do + TControl( CompGroup3.objects[i]).top := TControl(CompGroup3.objects[i]).top + (AValue div 2); + + // Group Buttons - reset top of components + for i:=0 to GetArrayLength(CompGroupButtonsArray)-1 do + TControl(CompGroupButtons.objects[i]).top := TControl(CompGroupButtons.objects[i]).top + AValue; + end; // This needs more work. for now it is not used by the installer. procedure ResizeWizardFormWidth(AValue: Integer); var - i: integer; + i: integer; begin wizardform.width := wizardform.width + AValue; - wizardform.left := wizardform.left - (AValue div 2); - + wizardform.left := wizardform.left - (AValue div 2); + // Group 1 - reset width of components - for i:=0 to GetArrayLength(CompGroup1Array)-1 do begin - TControl(CompGroup1.objects[i]).width := TControl(CompGroup1.objects[i]).width + Avalue; -// TControl(CompGroup1.objects[i]).left := TControl(CompGroup1.objects[i]).left + (Avalue div 2); - end; + for i:=0 to GetArrayLength(CompGroup1Array)-1 do begin + TControl(CompGroup1.objects[i]).width := TControl(CompGroup1.objects[i]).width + Avalue; +// TControl(CompGroup1.objects[i]).left := TControl(CompGroup1.objects[i]).left + (Avalue div 2); + end; - // Group 2 - reset left of components - for i:=0 to GetArrayLength(CompGroup2Array)-1 do begin - TControl(CompGroup2.objects[i]).left := TControl(CompGroup2.objects[i]).left + AValue; - TControl(CompGroup2.objects[i]).width := TControl(CompGroup2.objects[i]).width + (AValue div 2); - end; + // Group 2 - reset left of components + for i:=0 to GetArrayLength(CompGroup2Array)-1 do begin + TControl(CompGroup2.objects[i]).left := TControl(CompGroup2.objects[i]).left + AValue; + TControl(CompGroup2.objects[i]).width := TControl(CompGroup2.objects[i]).width + (AValue div 2); + end; // Group 3 - reset left of components but keep 'centered' horizontally. // for i:=0 to GetArrayLength(CompGroup3Array)-1 do @@ -284,20 +284,20 @@ end; function ShowHelpDlg: Integer; begin - CreateHelpDlg; + CreateHelpDlg; result := HelpDlg.ShowModal; - CloseHelpDlg; + CloseHelpDlg; end; // Add a simple debug dialogue -var - DebugDlg: TForm; - +var + DebugDlg: TForm; + procedure CreateDebugDlg(aString: String; ADescription: String); var DebugText: TMemo; -// DebugDescription: TLabel; +// DebugDescription: TLabel; OKButton: TButton; begin DebugDlg := TForm.create(nil); @@ -328,8 +328,8 @@ begin DebugDlg.ActiveControl := OKButton; end; - - + + procedure CloseDebugDlg; begin with DebugDlg do begin @@ -341,8 +341,8 @@ end; function ShowDebugDlg(aString: String; aDescription: String): Integer; begin - CreateDebugDlg(aString,aDescription); + CreateDebugDlg(aString,aDescription); result := DebugDlg.ShowModal; - CloseDebugDlg; + CloseDebugDlg; end; diff --git a/builds/install/arch-specific/win32/FirebirdInstallSupportFunctions.inc b/builds/install/arch-specific/win32/FirebirdInstallSupportFunctions.inc index 7bfefac4496..f1ccbecb1a4 100644 --- a/builds/install/arch-specific/win32/FirebirdInstallSupportFunctions.inc +++ b/builds/install/arch-specific/win32/FirebirdInstallSupportFunctions.inc @@ -27,15 +27,15 @@ Function Prototypes function IsWin32: boolean; function Is32BitInstallMode: boolean; - function IsWinTen: boolean; - function IsWinEightOne: boolean; - function IsWinEight: boolean; - function IsW2K12: boolean; + function IsWinTen: boolean; + function IsWinEightOne: boolean; + function IsWinEight: boolean; + function IsW2K12: boolean; function IsVista: boolean; - function IsVistaSP1: boolean; - function IsWin2K8R1: boolean; - function IsWinSeven: boolean; - function IsWin2K8R2: boolean; + function IsVistaSP1: boolean; + function IsWin2K8R1: boolean; + function IsWinSeven: boolean; + function IsWin2K8R2: boolean; function IsWin2k3: boolean; function IsWinXP: boolean; function IsWin2K: boolean; @@ -53,7 +53,7 @@ Function Prototypes function GetInstalledVersion(BinaryFile: String): Array of Integer; function ConvertIBVerStrToFbVerStr( VerStr: String) : String; function GetRegistryEntry(RegKey, RegEntry: string): String; - + *) (* @@ -68,21 +68,21 @@ InnoSetup Help Extract on Windows version strings: Windows NT versions: 4.0.1381 Windows NT 4.0 5.0.2195 Windows 2000 -5.01.2600 Windows XP - or Windows XP 64-Bit Edition Version 2002 (Itanium) -5.02.3790 Windows Server 2003 - or Windows XP x64 Edition (AMD64/EM64T) - or Windows XP 64-Bit Edition Version 2003 (Itanium) -6.0.6000 Windows Vista -6.0.6001 Windows Vista with Service Pack 1 - or Windows Server 2008 -6.0.6002 Windows Vista with Service Pack 2 -6.1.7600 Windows 7 - or Windows Server 2008 R2 -6.2.9200 Windows 8 or Windows Server 2012 -6.3.9200 Windows 8.1 or Windows Server 2012 R2 -6.3.9600 Windows 8.1 with Update 1 -10.0.10240 Windows 10 +5.01.2600 Windows XP + or Windows XP 64-Bit Edition Version 2002 (Itanium) +5.02.3790 Windows Server 2003 + or Windows XP x64 Edition (AMD64/EM64T) + or Windows XP 64-Bit Edition Version 2003 (Itanium) +6.0.6000 Windows Vista +6.0.6001 Windows Vista with Service Pack 1 + or Windows Server 2008 +6.0.6002 Windows Vista with Service Pack 2 +6.1.7600 Windows 7 + or Windows Server 2008 R2 +6.2.9200 Windows 8 or Windows Server 2012 +6.3.9200 Windows 8.1 or Windows Server 2012 R2 +6.3.9600 Windows 8.1 with Update 1 +10.0.10240 Windows 10 *) @@ -356,6 +356,20 @@ begin end; +function FindInFile( Filename, StringToFind: String): Boolean; +var + i: Integer; + AString: AnsiString; +begin + Result := False; + LoadStringFromFile( Filename, Astring ); + i := Length( Astring ); + if i <> 0 then + i := Pos ( StringToFind, Astring ); + if i <> 0 then Result := True; +end; + + procedure DecodeVersion( VerStr: String; var VerInt: array of Integer ); var i,p: Integer; s: string; diff --git a/builds/install/arch-specific/win32/ba/Instalacija_ProcitajMe.txt b/builds/install/arch-specific/win32/ba/Instalacija_ProcitajMe.txt index bd0c4519db1..7a84353325e 100644 --- a/builds/install/arch-specific/win32/ba/Instalacija_ProcitajMe.txt +++ b/builds/install/arch-specific/win32/ba/Instalacija_ProcitajMe.txt @@ -38,7 +38,7 @@ Pogledajte UNINSTALL sekciju ispod za vise informacija o ovome. Ako ste instalirali beta ili alpha verziju firebird-a, instalacija ce preimenovati firebird.conf i -security4.fdb jer ove datoteke vise nisu kompatibilne. +security$MAJOR.fdb jer ove datoteke vise nisu kompatibilne. Deployment gds32.dll @@ -69,7 +69,7 @@ Re-instalacija Firebird-a Instalacioni program radi sve sto moze da detektuje i sacuva prethodnu instalaciju. Ako instalacija detektuje -firebird.conf ili security4.fdb onda nece ponuditi +firebird.conf ili security$MAJOR.fdb onda nece ponuditi opciju da instalira legacy_auth. Niti ce ponuditi opciju da postavi SYSDBA username i password. @@ -128,7 +128,7 @@ o Deinstalacija ostavlja 6 datoteka u install - fbtrace.conf - replication.conf - firebird.log - - security4.fdb + - security$MAJOR.fdb Ovo je uradjeno namjerno. Ove datoteke su sve potencijalno modifikovane od strane korisnika i mogu diff --git a/builds/install/arch-specific/win32/custom_messages.inc b/builds/install/arch-specific/win32/custom_messages.inc index d4187ae68e2..e3a809c7136 100644 --- a/builds/install/arch-specific/win32/custom_messages.inc +++ b/builds/install/arch-specific/win32/custom_messages.inc @@ -82,7 +82,7 @@ en.SYSDBAPasswordEmpty=Password is empty. You must enter a password for SYSDBA. en.EnableLegacyClientAuth=Enable a&uthorization for legacy Firebird clients? en.CreateSYSDBAPassword=Create a password for the Database System Administrator en.ClickThroughPWCreation=Or click through to use the default password of masterkey. -en.PasswordNote=*** Note - in Firebird 3 masterkey and masterke are different passwords. *** +en.PasswordNote=*** Note - since Firebird 3 masterkey and masterke are different passwords. *** en.SYSDBAPassword=SYSDBA Password: en.RetypeSYSDBAPassword=Retype SYSDBA Password: en.InstallingMSVC32runtimes=Installing MSVC 32-bit runtime libraries to system directory diff --git a/builds/install/arch-specific/win32/cz/instalace_ctime.txt b/builds/install/arch-specific/win32/cz/instalace_ctime.txt index c4560172870..744d6364a36 100644 --- a/builds/install/arch-specific/win32/cz/instalace_ctime.txt +++ b/builds/install/arch-specific/win32/cz/instalace_ctime.txt @@ -38,7 +38,7 @@ viz část ODINSTALACE níže. Máte-li nainstalovanou beta či alpha verzi Firebirdu $MAJOR.$MINOR, instalátor přejmenuje firebird.conf -a security3.fdb, jelikož tyto soubory již nejsou kompatibilní. +a security$MAJOR.fdb, jelikož tyto soubory již nejsou kompatibilní. Instalace gds32.dll @@ -63,7 +63,7 @@ Reinstalace of Firebird $MAJOR.$MINOR --------------------------- Instalační program dělá vše pro detekci a zachování předchozí instalace. -Jestliže instalátor rozpozná firebird.conf či security3.fdb, nebude +Jestliže instalátor rozpozná firebird.conf či security$MAJOR.fdb, nebude nabízet možnost instalace legacy_auth. Rovněž nebude nabízet volbu pro nastavení hesla pro SYSDBA. @@ -123,7 +123,7 @@ o Odinstalace v instalační složce zanechá - fbtrace.conf - replication.conf - firebird.log - - security3.fdb + - security$MAJOR.fdb To je záměr. Všechny tyto soubory jsou potencionálně pozměnitelné uživatelem a diff --git a/builds/install/arch-specific/win32/fr/installation_lisezmoi.txt b/builds/install/arch-specific/win32/fr/installation_lisezmoi.txt index 4a7ad0e9e34..981fa4bbf06 100644 --- a/builds/install/arch-specific/win32/fr/installation_lisezmoi.txt +++ b/builds/install/arch-specific/win32/fr/installation_lisezmoi.txt @@ -28,7 +28,7 @@ Contenu o Avant l'installation o Déployement de gds32.dll o Installation du Guardian -o Réinstallation de Firebird +o Réinstallation de Firebird $MAJOR o Problèmes connus d'installation o Desinstallation o Installation depuis un fichier batch @@ -44,7 +44,7 @@ Il est particulièrement important de vérifier que fbclient.dll et gds32.dll ont été retirés de . Si vous avez installé une version beta ou alpha de Firebird $MAJOR.$MINOR, -l'installeur va renommer firebird.conf et security4.fdb, car ces +l'installeur va renommer firebird.conf et security$MAJOR.fdb, car ces fichiers ne sont plus compatibles avec la version actuelle. @@ -132,7 +132,7 @@ o La désinstallation laisse six fichiers dans le - fbtrace.conf - replication.conf - firebird.log - - security4.fdb + - security$MAJOR.fdb Ceci est intentionnel. Ces fichiers sont tous potentiellement modifiables par les utilisateurs et peuvent diff --git a/builds/install/arch-specific/win32/install_service.bat b/builds/install/arch-specific/win32/install_service.bat index 0953547a4ad..960765ddc5a 100644 --- a/builds/install/arch-specific/win32/install_service.bat +++ b/builds/install/arch-specific/win32/install_service.bat @@ -1,11 +1,11 @@ @echo off -if "%1"=="" ( +if "%~1"=="" ( instreg install -z ) setlocal set INSTALL_SERVICE=install -z set START_SERVICE=start -if not "%1"=="" ( +if not "%~1"=="" ( set INSTALL_SERVICE=%INSTALL_SERVICE% -n %1 set START_SERVICE=%START_SERVICE% -n %1 ) @@ -13,7 +13,7 @@ instsvc %INSTALL_SERVICE% instsvc %START_SERVICE% endlocal @echo. -@echo Firebird installed and started as a service using +@echo Firebird installed and started as a service using @echo architecture specified in firebird.conf. @echo. diff --git a/builds/install/arch-specific/win32/installation_readme.txt b/builds/install/arch-specific/win32/installation_readme.txt index 660f5260a8a..7f687bd3eae 100644 --- a/builds/install/arch-specific/win32/installation_readme.txt +++ b/builds/install/arch-specific/win32/installation_readme.txt @@ -19,6 +19,7 @@ Contents -------- o Before installation +o Deployment to older versions of Windows o Deployment of gds32.dll o Installation of the Guardian o Re-installation of Firebird $MAJOR.$MINOR @@ -37,13 +38,39 @@ fbclient.dll and gds32.dll are removed from . See the UNINSTALL section below for more info on this. +Deployment to older versions of Windows +--------------------------------------- + +The binary installer no longer supports older versions +of windows. As per the innosetup documentation: + + "Change in default behavior: [Setup] section + directive MinVersion now defaults to 6.1sp1, so by + default Setup will not run on Windows Vista or on + versions of Windows 7 and Windows Server 2008 R2 + which have not been updated." + +These earlier versions do not support some of the +security measures against potential DLL preloading +attacks so deployment to these is now blocked by the +installer. + +This change _may_ be a problem for users of W2K8 R2. +In any case Windows Vista and even Windows 7 are now +deprecated by Microsoft and hopefully no production +install of W2K8 R2 is unpatched. Users who need to +deploy to what are now ancient versions of windows are +advised to manually install Firebird 4.0 with the zip +package. + + Installation of the Guardian ---------------------------- -We are hoping to phase out the Guardian. It doesn't -work with the Classic server and the binary installer -does not offer it at install time if Classic is -chosen. If SuperServer or SuperClassic are chosen +We are hoping to phase out the Guardian. It doesn't +work with the Classic server and the binary installer +does not offer it at install time if Classic is +chosen. If SuperServer or SuperClassic are chosen it is offered but not selected by default. @@ -52,7 +79,7 @@ Re-installation of Firebird The binary installer does its best to detect and preserve a previous install. If the installer detects -firebird.conf or security4.fdb it will not offer the +firebird.conf or security$MAJOR.fdb it will not offer the option to set the SYSDBA username and password. @@ -74,14 +101,14 @@ o The service installer (instsvc) uses the same installations. This is by design. Services exist in a single name space. -o Be sure to install as an administrator. ie, if - using the binary installer right click and choose - 'Run as administrator'. Otherwise the installer +o Be sure to install as an administrator. ie, if + using the binary installer right click and choose + 'Run as administrator'. Otherwise the installer may be unable to start the Firebird service at the end of installation. o Libraries deployed by instclient may fail to load if - the MS runtime libraries have not been installed. + the MS runtime libraries have not been installed. This may be a problem if installing on older Windows platforms. @@ -112,7 +139,7 @@ o Uninstallation leaves six files in the install - fbtrace.conf - replication.conf - firebird.log - - security4.fdb + - security$MAJOR.fdb This is intentional. These files are all potentially modifiable by users and may be required diff --git a/builds/install/arch-specific/win32/installation_scripted.txt b/builds/install/arch-specific/win32/installation_scripted.txt index 5ca49954d15..5c1a8e621e4 100644 --- a/builds/install/arch-specific/win32/installation_scripted.txt +++ b/builds/install/arch-specific/win32/installation_scripted.txt @@ -14,14 +14,15 @@ General notes on preparing a scripted install --------------------------------------------- These notes only document the firebird specific options for a scripted -installation. Developers should refer to the full InnoSetup documentation -for a description of the other options available for a scripted install. +installation. Developers should refer to the full InnoSetup documentation +for a description of the other options available for a scripted install. This can be found here: + http://www.jrsoftware.org/ishelp/ -It is highly recommended that a scripted install is tested thoroughly -before deployment. The easiest way to test is to run the script without -the /SILENT parameter. This will present a standard installer with the +It is highly recommended that a scripted install is tested thoroughly +before deployment. The easiest way to test is to run the script without +the /SILENT parameter. This will present a standard installer with the scripted options preselected. NOTE that the /TASKS parameter clears all the default task settings. If @@ -44,7 +45,7 @@ HELP Setup parameters specific to the Firebird Uninstaller /CLEAN -For general parameters available to all InnoSetup based installers see the +For general parameters available to all InnoSetup based installers see the documentation for innosetup. A summary is available via /? or /HELP @@ -53,10 +54,10 @@ Parameters specific to Firebird installs HELP Invoke this file as a help screen at installation time. - Note no / is prefixed !! Because /? and /HELP are now - used by innosetup itself to dispaly innosetup specific help. + Note no / is prefixed !! Because /? and /HELP are now + used by innosetup itself to display innosetup specific help. + - /COMPONENTS="comma separated list of component names" Choose from - ServerComponent, @@ -67,31 +68,31 @@ HELP parameter causes Setup to automatically select a custom type. A full install requires combining components. For example: - /COMPONENTS="ClientComponent" + /COMPONENTS="ClientComponent" would be required for a client only install. - - NOTE - If a full server instal is required there is no need to + + NOTE - If a full server install is required there is no need to specify /COMPONENTS. All three are chosen by default. - + /TASKS="comma separated list of task names" Specifies a list of tasks that should be initially selected or deselected. To deselect a task, prefix its name with a "!" character. - Choose from - UseSuperServerTask + Choose from - UseSuperServerTask UseSuperServerTask\UseGuardianTask (optional) - or - UseSuperClassicTask + or + UseSuperClassicTask UseSuperClassicTask\UseGuardianTask (optional) or UseClassicServerTask - - UseApplicationTask - or + + UseApplicationTask + or UseServiceTask - + AutoStartTask CopyFbClientToSysTask CopyFbClientAsGds32Task @@ -103,7 +104,8 @@ HELP By default the following tasks are run: - UseSuperServerTask,UseServiceTask,AutoStartTask,CopyFbClientToSysTask + UseSuperServerTask,UseServiceTask,AutoStartTask,CopyFbClientToSysTask + /MERGETASKS="comma separated list of task names" @@ -118,8 +120,8 @@ HELP /SYSDBAPASSWORD="mypassword" If supplied this will override the default SYSDBA password "masterkey". - - NOTE: If an existing Security database is found this parameter will be + + NOTE: If an existing Security database is found this parameter will be ignored. @@ -134,8 +136,8 @@ HELP users by breaking a perfectly good working install of Firebird or InterBase. Its your choice. - - + + Parameters specific to Firebird uninstalls ------------------------------------------ @@ -147,7 +149,7 @@ Parameters specific to Firebird uninstalls firebird.conf databases.conf firebird.log - security3.fdb + security$MAJOR.fdb fbtrace.conf replication.conf @@ -159,26 +161,26 @@ Parameters specific to Firebird uninstalls Examples -------- -These examples are just for firebird related options. In practice you -they will probably be combined with options such as /SILENT, /LOG, +These examples are just for firebird related options. In practice you +they will probably be combined with options such as /SILENT, /LOG, /RESTARTEXITCODE etc. 1/ Full server install of super server architecture - o Change SYSDBA password from default masterkey, + o Change SYSDBA password from default masterkey, o deploy gds32 to /MERGETASKS="CopyFbClientAsGds32Task" /SYSDBAPASSWORD="mypassword" - + 2/ Deploy Classic Server and keep other default tasks - /MERGETASKS="UseClassicServerTask" + /MERGETASKS="UseClassicServerTask" -3/ Really mess things up by accidentally deselecting the defaults and +3/ Really mess things up by accidentally deselecting the defaults and letting InnoSetup guess: - /TASKS="CopyFbClientAsGds32Task" + /TASKS="CopyFbClientAsGds32Task" Be careful when using the /TASKS parameter ! - + diff --git a/builds/install/arch-specific/win32/ru/installation_readme.txt b/builds/install/arch-specific/win32/ru/installation_readme.txt index 6c073022887..b23dae6ce3d 100644 --- a/builds/install/arch-specific/win32/ru/installation_readme.txt +++ b/builds/install/arch-specific/win32/ru/installation_readme.txt @@ -36,7 +36,7 @@ o Установка из пакетного (bat) файла каталога . Если у вас установлена Альфа или Бета версия Firebird $MAJOR.$MINOR, -то программа установки переименует файлы firebird.conf и security4.fdb +то программа установки переименует файлы firebird.conf и security$MAJOR.fdb из-за их несовместимости с устанавливаемой версией. @@ -67,7 +67,7 @@ MS VC runtime версии 10.0 установлены в системе. Программа установки пытается обнаружить и сохранить ранее установленную версию Firebird. Если программа установки обнаруживает файлы firebird.conf -или security4.fdb, то некоторые настройки авторизации могут быть недоступны, +или security$MAJOR.fdb, то некоторые настройки авторизации могут быть недоступны, в частности возможность установить пароль пользователя SYSDBA. @@ -124,7 +124,7 @@ o Деинсталлятор оставляет следующие файлы в - fbtrace.conf - replication.conf - firebird.log - - security4.fdb + - security$MAJOR.fdb Это происходит намеренно. Эти файлы потенциально могут быть изменены пользователем и могут diff --git a/builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.txt b/builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.md similarity index 80% rename from builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.txt rename to builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.md index c216ccd934a..46cfe2c99ef 100644 --- a/builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.txt +++ b/builds/install/arch-specific/win32/test_installer/Innosetup-command-line-reference.md @@ -1,116 +1,147 @@ -Setup Command Line Parameters +# Setup Command Line Parameters (Taken from InnoSetup Help v. 6.1.2 Deember 2020) The Setup program accepts optional command line parameters. These can be useful to system administrators, and to other programs calling the Setup program. -/HELP, /? + +**/HELP, /?** + Shows a summary of this information. Ignored if the UseSetupLdr [Setup] section directive was set to no. -/SP- + +**/SP-** + Disables the This will install... Do you wish to continue? prompt at the beginning of Setup. Of course, this will have no effect if the DisableStartupPrompt [Setup] section directive was set to yes. -/SILENT, /VERYSILENT + +**/SILENT, /VERYSILENT** + Instructs Setup to be silent or very silent. When Setup is silent the wizard and the background window are not displayed but the installation progress window is. When a setup is very silent this installation progress window is not displayed. Everything else is normal so for example error messages during installation are displayed and the startup prompt is (if you haven't disabled it with DisableStartupPrompt or the '/SP-' command line option explained above). If a restart is necessary and the '/NORESTART' command isn't used (see below) and Setup is silent, it will display a Reboot now? message box. If it's very silent it will reboot without asking. -/SUPPRESSMSGBOXES + +**/SUPPRESSMSGBOXES** + Instructs Setup to suppress message boxes. Only has an effect when combined with '/SILENT' or '/VERYSILENT'. The default response in situations where there's a choice is: -•Yes in a 'Keep newer file?' situation. -•No in a 'File exists, confirm overwrite.' situation. -•Abort in Abort/Retry situations. -•Cancel in Retry/Cancel situations. -•Yes (=continue) in a DiskSpaceWarning/DirExists/DirDoesntExist/NoUninstallWarning/ExitSetupMessage/ConfirmUninstall situation. -•Yes (=restart) in a FinishedRestartMessage/UninstalledAndNeedsRestart situation. -•The recommended choice in a PrivilegesRequiredOverridesAllowed=dialog situation. +- Yes in a 'Keep newer file?' situation. +- No in a 'File exists, confirm overwrite.' situation. +- Abort in Abort/Retry situations. +- Cancel in Retry/Cancel situations. +- Yes (=continue) in a DiskSpaceWarning/DirExists/DirDoesntExist/NoUninstallWarning/ExitSetupMessage/ConfirmUninstall situation. +- Yes (=restart) in a FinishedRestartMessage/UninstalledAndNeedsRestart situation. +- The recommended choice in a PrivilegesRequiredOverridesAllowed=dialog situation. + 5 message boxes are not suppressible: -•The About Setup message box. -•The Exit Setup? message box. -•The FileNotInDir2 message box displayed when Setup requires a new disk to be inserted and the disk was not found. -•Any (error) message box displayed before Setup (or Uninstall) could read the command line parameters. -•Any task dialog or message box displayed by [Code] support functions TaskDialogMsgBox and MsgBox. +- The About Setup message box. +- The Exit Setup? message box. +- The FileNotInDir2 message box displayed when Setup requires a new disk to be inserted and the disk was not found. +- Any (error) message box displayed before Setup (or Uninstall) could read the command line parameters. +- Any task dialog or message box displayed by [Code] support functions TaskDialogMsgBox and MsgBox. + +**/ALLUSERS** -/ALLUSERS Instructs Setup to install in administrative install mode. Only has an effect when the [Setup] section directive PrivilegesRequiredOverridesAllowed allows the commandline override. -/CURRENTUSER +**/CURRENTUSER** + Instructs Setup to install in non administrative install mode. Only has an effect when the [Setup] section directive PrivilegesRequiredOverridesAllowed allows the commandline override. -/LOG +**/LOG** + Causes Setup to create a log file in the user's TEMP directory detailing file installation and [Run] actions taken during the installation process. This can be a helpful debugging aid. For example, if you suspect a file isn't being replaced when you believe it should be (or vice versa), the log file will tell you if the file was really skipped, and why. The log file is created with a unique name based on the current date. (It will not overwrite or append to existing files.) The information contained in the log file is technical in nature and therefore not intended to be understandable by end users. Nor is it designed to be machine-parsable; the format of the file is subject to change without notice. -/LOG="filename" +**/LOG="filename"** + Same as /LOG, except it allows you to specify a fixed path/filename to use for the log file. If a file with the specified name already exists it will be overwritten. If the file cannot be created, Setup will abort with an error message. -/NOCANCEL +**/NOCANCEL** + Prevents the user from cancelling during the installation process, by disabling the Cancel button and ignoring clicks on the close button. Useful along with '/SILENT' or '/VERYSILENT'. -/NORESTART +**/NORESTART** + Prevents Setup from restarting the system following a successful installation, or after a Preparing to Install failure that requests a restart. Typically used along with /SILENT or /VERYSILENT. -/RESTARTEXITCODE=exit code +**/RESTARTEXITCODE=exit code** + Specifies a custom exit code that Setup is to return when the system needs to be restarted following a successful installation. (By default, 0 is returned in this case.) Typically used along with /NORESTART. See also: Setup Exit Codes -/CLOSEAPPLICATIONS +**/CLOSEAPPLICATIONS** + Instructs Setup to close applications using files that need to be updated by Setup if possible. -/NOCLOSEAPPLICATIONS +**/NOCLOSEAPPLICATIONS** + Prevents Setup from closing applications using files that need to be updated by Setup. If /CLOSEAPPLICATIONS was also used, this command line parameter is ignored. -/FORCECLOSEAPPLICATIONS +**/FORCECLOSEAPPLICATIONS** + Instructs Setup to force close when closing applications. -/NOFORCECLOSEAPPLICATIONS +**/NOFORCECLOSEAPPLICATIONS** + Prevents Setup from force closing when closing applications. If /FORCECLOSEAPPLICATIONS was also used, this command line parameter is ignored. -/LOGCLOSEAPPLICATIONS +**/LOGCLOSEAPPLICATIONS** + Instructs Setup to create extra logging when closing applications for debugging purposes. -/RESTARTAPPLICATIONS +**/RESTARTAPPLICATIONS** + Instructs Setup to restart applications if possible. -/NORESTARTAPPLICATIONS +**/NORESTARTAPPLICATIONS** + Prevents Setup from restarting applications. If /RESTARTAPPLICATIONS was also used, this command line parameter is ignored. -/LOADINF="filename" +**/LOADINF="filename"** + Instructs Setup to load the settings from the specified file after having checked the command line. This file can be prepared using the '/SAVEINF=' command as explained below. Don't forget to use quotes if the filename contains spaces. -/SAVEINF="filename" +**/SAVEINF="filename"** + Instructs Setup to save installation settings to the specified file. Don't forget to use quotes if the filename contains spaces. -/LANG=language +**/LANG=language** + Specifies the language to use. language specifies the internal name of the language as specified in a [Languages] section entry. When a valid /LANG parameter is used, the Select Language dialog will be suppressed. -/DIR="x:\dirname" +**/DIR="x:\dirname"** + Overrides the default directory name displayed on the Select Destination Location wizard page. A fully qualified pathname must be specified. May include an "expand:" prefix which instructs Setup to expand any constants in the name. For example: '/DIR=expand:{autopf}\My Program'. -/GROUP="folder name" +**/GROUP="folder name"** + Overrides the default folder name displayed on the Select Start Menu Folder wizard page. May include an "expand:" prefix, see '/DIR='. If the [Setup] section directive DisableProgramGroupPage was set to yes, this command line parameter is ignored. -/NOICONS +**/NOICONS** + Instructs Setup to initially check the Don't create a Start Menu folder check box on the Select Start Menu Folder wizard page. -/TYPE=type name +**/TYPE=type name** + Overrides the default setup type. If the specified type exists and isn't a custom type, then any /COMPONENTS parameter will be ignored. -/COMPONENTS="comma separated list of component names" +**/COMPONENTS="comma separated list of component names"** + Overrides the default component settings. Using this command line parameter causes Setup to automatically select a custom type. If no custom type is defined, this parameter is ignored. Only the specified components will be selected; the rest will be deselected. @@ -120,11 +151,21 @@ If a component name is prefixed with a "*" character, any child components will This parameter does not change the state of components that include the fixed flag. Example: + Deselect all components, then select the "help" and "plugins" components: -/COMPONENTS="help,plugins" Example: + +``` +/COMPONENTS="help,plugins" +``` + +Example: + Deselect all components, then select a parent component and all of its children with the exception of one: -/COMPONENTS="*parent,!parent\child" -/TASKS="comma separated list of task names" + +``` +/COMPONENTS="*parent,!parent\child" /TASKS="comma separated list of task names" +``` + Specifies a list of tasks that should be initially selected. Only the specified tasks will be selected; the rest will be deselected. Use the /MERGETASKS parameter instead if you want to keep the default set of tasks and only select/deselect some of them. @@ -132,21 +173,41 @@ Only the specified tasks will be selected; the rest will be deselected. Use the If a task name is prefixed with a "*" character, any child tasks will be selected as well (except for those that include the dontinheritcheck flag). If a task name is prefixed with a "!" character, the task will be deselected. Example: + Deselect all tasks, then select the "desktopicon" and "fileassoc" tasks: -/TASKS="desktopicon,fileassoc" Example: + +``` +/TASKS="desktopicon,fileassoc" +``` + +Example: + Deselect all tasks, then select a parent task and all of its children with the exception of one: -/TASKS="*parent,!parent\child" -/MERGETASKS="comma separated list of task names" + +``` +/TASKS="*parent,!parent\child" /MERGETASKS="comma separated list of task names" +``` + Like the /TASKS parameter, except the specified tasks will be merged with the set of tasks that would have otherwise been selected by default. If UsePreviousTasks is set to yes, the specified tasks will be selected/deselected after any previous tasks are restored. Example: + Keep the default set of selected tasks, but additionally select the "desktopicon" and "fileassoc" tasks: -/MERGETASKS="desktopicon,fileassoc" Example: + +``` +/MERGETASKS="desktopicon,fileassoc" +``` + +Example: + Keep the default set of selected tasks, but deselect the "desktopicon" task: -/MERGETASKS="!desktopicon" -/PASSWORD=password + +``` +/MERGETASKS="!desktopicon" /PASSWORD=password +``` + Specifies the password to use. If the [Setup] section directive Password was not set, this command line parameter is ignored. When an invalid password is specified, this command line parameter is also ignored. diff --git a/builds/install/arch-specific/win32/test_installer/fbit-functions.psm1 b/builds/install/arch-specific/win32/test_installer/fbit-functions.psm1 new file mode 100644 index 00000000000..180d20305db --- /dev/null +++ b/builds/install/arch-specific/win32/test_installer/fbit-functions.psm1 @@ -0,0 +1,264 @@ +#region Helper functions ############# + +function spacer() { + param ( [string]$message ) + if ( $message ) { + Write-Output '' + Write-Output "=================== $message ===================" + Write-Output '' + } else { + Write-Output '------------------------------------------------------------------------------------------' + } +} + + +function Pause( [string] $_msg = "Press any key to continue..." ) { + Set-PSDebug -Trace 2 + + $null = Read-Host $_msg + +} + + +function RunTimeStamp() { + Get-Date -UFormat '%Y-%m-%d_%H-%M-%S' +} + + +<# +.SYNOPSIS +Shorten the prompt + +.DESCRIPTION +The path to the test installer script can get too long + +.PARAMETER reset +Restore the full path + +#> +function prompt( [switch]$reset ) { + + + $local:identity = [Security.Principal.WindowsIdentity]::GetCurrent() + $local:principal = [Security.Principal.WindowsPrincipal] $local:identity + $local:adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator + + $( if (Test-Path variable:/PSDebugContext) { '[DBG]: ' } + elseif ($principal.IsInRole($adminRole)) { '[ADMIN]: ' } + else { '' } + ) + $( if ( $reset -eq $true ) { + 'PS ' + $(Get-Location) + $( if ( $NestedPromptLevel -ge 1 ) { '>>' } ) + '> ' + } else { + 'FBIT ' + '> ' + } ) + +} + + +function check_file_exists( [string]$_apath, [switch]$_isdir ) { + if ( $_isdir ) { + return ( (Test-Path -Path $_apath ) -ne "" ) + } else { + return ( ( Test-Path -Path $_apath -PathType Leaf ) -ne "" ) + } +} + + +function Invoke-Command ($_commandPath, $_commandArguments, $_commandTitle, $_outfile ) { + Try { + $local:pinfo = New-Object System.Diagnostics.ProcessStartInfo + $local:pinfo.FileName = "$_commandPath" + $local:pinfo.RedirectStandardError = $true + $local:pinfo.RedirectStandardOutput = $true + $local:pinfo.UseShellExecute = $false + $local:pinfo.Arguments = "$_commandArguments" + $global:p = New-Object System.Diagnostics.Process + $global:p.StartInfo = $pinfo + $global:p.Start() | Out-Null + $local:result_object = [pscustomobject]@{ + commandTitle = $_commandTitle + stdout = $p.StandardOutput.ReadToEnd() + stderr = $p.StandardError.ReadToEnd() + ExitCode = $p.ExitCode + } + $global:p.WaitForExit() + if ( "$_outfile" -ne '' ) { + $local:result_object.stdout > $_outfile + } else { + Write-Verbose $local:result_object.stdout + } + return $local:result_object.ExitCode + } catch { + Write-Output $local:result_object.stderr + return $local:result_object.ExitCode + + } + + # Write-Verbose "stdout: $stdout" + # Write-Verbose "stderr: $stderr" + # Write-Verbose "exit code: $p.ExitCode" + +} + + +#endregion end of helper functions ############# + + +<# +.SYNOPSIS +Indicate if the (non-)existence of a file is a good or a bad thing. +.DESCRIPTION +When installing Firebird we expect certain files to exist. +When uninstalling we do not expect files to exist. + +.PARAMETER afile +The file to check for + +.PARAMETER str_if_true +The string to output if file exists. Defaults to 'good' + +.PARAMETER str_if_false +The string to output if the file does not exist + +.PARAMETER status_true_is_fail +When installing set status_true_is_fail to false. +When uninstalling set status_true_is_fail to true. + +.PARAMETER isdir +Set isdir if testing for a directory. + +.EXAMPLE +An example + +.NOTES +General notes +#> +function check_file_status( $afile, [boolean]$status_true_is_fail, [boolean]$isdir + , [string]$str_if_true = 'good', [string]$str_if_false = 'bad' +) { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + $local:retval = check_file_exists $afile $isdir + if ( $local:retval -eq $true ) { + Write-Output "$TAB $afile exists - $str_if_true" + } else { + Write-Output "$TAB $afile not found - $str_if_false" + } + + if ( $status_true_is_fail -eq $true -and $local:retval -eq $true ) { + Write-Verbose "$TAB $status_true_is_fail -eq $true -and $local:retval -eq $true " + $ErrorCount += 1 + } + + if ( $status_true_is_fail -eq $false -and $local:retval -eq $false ) { + Write-Verbose "$TAB $status_true_is_fail -eq $true -and $local:retval -eq $true " + $ErrorCount += 1 + } + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" +} + + +function check_server_arch_configured() { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + if ( $global:classicserver ) { $local:str_to_test = 'servermode = classic' } + if ( $global:superclassic ) { $local:str_to_test = 'servermode = superclassic' } + if ( $global:superserver ) { $local:str_to_test = 'servermode = super' } + + # FIXME What if the fb.conf does not exist? + $local:found = (Select-String -Path "$FIREBIRD/firebird.conf" -Pattern ^$local:str_to_test) + + if ( ! $local:found.Length -gt 0 ) { + $ErrorCount += 1 + Write-Verbose $TAB $local:str_to_test not set in $FIREBIRD/firebird.conf + + } + + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" +} + + + +<# +.SYNOPSIS +Compare two strings + +.DESCRIPTION +Long description + +.PARAMETER expected +The result expected + +.PARAMETER actual +The actual result + +.PARAMETER equals_is_true +Set True if the actual result should equal the expected result +Or Set True if actualt result should not equal the expected result + +.NOTES +General notes +#> +function check_result ( [string]$expected, [string]$actual, [boolean]$equals_is_true) { + + # Write-Verbose "if ( ($expected -eq $actual ) -and $equals_is_true ){ return $true }" + if ( ( "$expected" -eq "$actual" ) -and $equals_is_true ) { return $true } + + # Write-Verbose "if ( ($expected -eq $actual ) -and !$equals_is_true ){ return $false }" + if ( ( "$expected" -eq "$actual" ) -and ! $equals_is_true ) { return $false } + + # Write-Verbose "if ( ($expected -ne $actual ) -and $equals_is_true ){ return $false }" + if ( ( "$expected" -ne "$actual" ) -and $equals_is_true ) { return $false } + + # Write-Verbose "if ( ($expected -ne $actual ) -and !$equals_is_true ){ return $true }" + if ( ( "$expected" -ne "$actual" ) -and ! $equals_is_true ) { return $true } +} + +function check_file_output( $afile, $apattern ) { + $local:aretval = Select-String -Path $afile -Pattern $apattern -SimpleMatch -Quiet + return $local:aretval + +} + +function print_output( $astring, [boolean]$found, [boolean]$found_is_fail + , [string]$str_if_true = "GOOD", [string]$str_if_false = "BAD" ) { + + # If we find the string (ie result is not empty) + if ( $found ) { + if ( $found_is_fail ) { + Write-Host -ForegroundColor Red "${TAB}$astring - $str_if_false" + $global:ErrorCount += 1 + } else { + Write-Host -ForegroundColor Green "${TAB}$astring - $str_if_true" + } + # We did not find the string + } else { + if ( $found_is_fail ) { + Write-Host -ForegroundColor Green "${TAB}$astring - $str_if_true" + } else { + Write-Host -ForegroundColor Red "${TAB}$astring - $str_if_false" + $global:ErrorCount += 1 + } + } + +} + + + +<# +.SYNOPSIS +Execute SQL via isql.exe + +.NOTES +This function assumes that the script to execute exists in $env:Temp\infile.txt +and the output will be stored in $env:Temp\outfile.txt +#> +function Exec_SQL( [string]$db = "localhost:employee", + [string]$username = "sysdba", [string]$pw = "masterkey" ) { + + # Always reset outfile otherwise output is appended. + Write-Output "" > $env:Temp\outfile.txt + + $local:retval = Invoke-Command "$global:FIREBIRD\isql.exe" " -user $username -password $pw -z ` + -i $env:Temp/infile.txt -o $env:Temp/outfile.txt -m -m2 $db" + +} diff --git a/builds/install/arch-specific/win32/test_installer/fbit-help.txt b/builds/install/arch-specific/win32/test_installer/fbit-help.txt deleted file mode 100644 index 67919143c3a..00000000000 --- a/builds/install/arch-specific/win32/test_installer/fbit-help.txt +++ /dev/null @@ -1,88 +0,0 @@ - - - Firebird Binary Installer Test Harness HELP (Designed with TABS=4 and console width=120) - - fbit {PARAM [...]] - - Parameters may be passed in any order except for one special case: - - fbit CLEAN - - will clean up from previous broken installs. CLEAN must the first parameter - and subsequent parameters are ignored. Note: - It will run silently. - - - By default fbit installs Firebird according to the parameters passed and then - immediately uninstalls it. A copy of the install is made, along with the install and uninstall logs. - - - FBIT Specific Parameters - ======================== - Param Name Value Passed Comment - ---------- ------------ ------- - HELP - Displays this screen - DRYRUN - Show what will be done. No changes are made - NOARCHIVE - Disables copying of install dir to %USERPROFILE%\fbit - Logs and inf files are always saved. - NOUNINSTALL - Disable automatic uninstall for this test run - SCRIPTED - Sets VERYSILENT, SP and NOMSG - TESTNAME NameOfTestRun Optional. No spaces allowed. Used for storing test run details. - - -The following parameters are set by default. They are unset automatically when a conflicting parameter is passed. - - Default Param Value Unset by - ------------- ------------- ---------- - INTERACTIVE True SCRIPTED - INSTALLTYPE ServerInstall CLIENT or DEVINST - SERVICE_TASK True APPTASK - SUPERSERVER True CLASSICSERVER or SUPERCLASSIC - - - Firebird Installer specific Parameters - ====================================== - Param Name Value passed Action when set - ---------- ------------------------- --------------- - COPYGDSLIB CopyFbClientAsGds32Task Copy fbclient to and rename to gds32 - FORCE FORCE Force installation - NOAUTOSTART NULL Does not set AutoStartTask - NOCOPYFBLIB CopyFbClientToSysTask Does not copy fbclient to - PASSWORD /SYSDBAPASSWORD=%ISC_PASSWORD% Changes SYSDBA password from masterkey - See :SET_GLOBAL_ENV - - Installation Tasks - ================== - Param Name Value passed Comment - ------------- ------------ --------------- - APPTASK UseApplicationTask Will not install as a service - CLASSICSERVER UseClassicServerTask Will configure classic server - SUPERCLASSIC UseSuperClassicTask Will configure super classic - - - Installation Types - ================== - Param Name Value passed Comment - ------------ ------------ ------- - CLIENT ClientInstall Minimal working client install - DEVINST DeveloperInstall Everything but the server. - - - Uninstallation - ============== - Param Name Value passed Comment - -------------- ------------ ------- - CLEAN CLEAN Completely remove the firebird install - Reset list of shared dll's in the registry - - - Generic InnoSetup parameters - ============================ - Param Name Value passed Comment - ---------- ------------ ------- - NOMSG SUPPRESSMSGBOXES Suppress message boxes - NOCANCEL NOCANCEL Prevents user cancelling install - SILENT SILENT - SP SP- Disables the This will install... prompt - VERYSILENT VERYSILENT - --------------------------- End of Fbit Help Screen ---------------------------------------- diff --git a/builds/install/arch-specific/win32/test_installer/fbit.bat b/builds/install/arch-specific/win32/test_installer/fbit.bat deleted file mode 100644 index 92878a5a8e3..00000000000 --- a/builds/install/arch-specific/win32/test_installer/fbit.bat +++ /dev/null @@ -1,749 +0,0 @@ -@setlocal enabledelayedexpansion - -:: DEBUG is intended for setting echo on globally. Each sub-routine tests -:: for DEBUG and if set VERBOSE is set. As each sub-routine exits VERBOSE -:: unset. -:: Uncomment 'call SET_VERBOSE' where needed to turn on VERBOSE -:: NOTE - DEBUG and VERBOSE still need some work around the use of the @ prefix. -@set DEBUG= -@if not defined DEBUG @echo off - -:: Use this to check UAC status -:: - 0x1 means UAC is on and user will be asked for permission -:: - 0x0 means that UAC is off and install/uninstall will run without asking for permission -:: - User with Admin rights is still recommended. -::reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA | grep REG | cut -d" " -f 13 - -:: NOTE - This script is not intended as an example of best practice for a -:: scripted install of Firebird. It is designed to test almost all possible -:: scriptable combinations and is thus far more complicated than a typical -:: install script need be. However, it can be used for testing. Note that chosen -:: settings :: used for each test run are saved into an .inf file, along with a -:: log of the install run. - -@goto :MAIN %* -@goto :EOF - -::======================================================= -:SET_GLOBAL_ENV -@call :SET_VERBOSE_IF_DEBUG_ON -@if defined DEBUG @echo Entering %0 - - -:: FBINST_EXEC must point to the package we want to test... -if not defined FBINST_EXEC ( - rem - if we have just built firebird we can test the install immediately - if defined FBBUILD_FILE_ID ( - if defined FBBUILD_FILENAME_SUFFIX ( - @set FBINST_EXEC=%FBBUILD_INSTALL_IMAGES%\Firebird-%FBBUILD_FILE_ID%%FBBUILD_FILENAME_SUFFIX%.exe - ) else ( - @set FBINST_EXEC=%FBBUILD_INSTALL_IMAGES%\Firebird-%FBBUILD_FILE_ID%.exe - ) - ) -) else ( - rem Set the actual path and filename here - or set it in the environment before running fbit. - @set FBINST_EXEC=%USERPROFILE%\Desktop\Firebird-4.0.0.2311_0_x64_RC1.exe -) - -:: This should be set dynamically, perhaps. But for now it is hard-coded. -@set FIREBIRD_BASE_VER=Firebird_4_0 - -:: It is possible that successive installs into the same directory may -:: generate different uninstallers but for now we hard code the default. -@set UNINSTALLEXE=unins000.exe - -:: The log dir should probably be under %TEMP% (or something like that) -:: In any case we try to create it if it doesn't exist -@set FBINSTALLLOGDIR=%USERPROFILE%\fbit-tests\logs - -:: We use this dir to store copies of each install for future comparison -:: Perhaps this should be under the User's dir? -@set FBINSTALLCOPYDIR=%USERPROFILE%\fbit-tests\install_archive - -:: This is just the default root directory for all versions of firebird -@set FIREBIRDROOTDIR="%ProgramFiles%\Firebird" - -:: This is the default click through install dir. -:: It is created by the installer if it does not exist. -@set FIREBIRD=%FIREBIRDROOTDIR%\%FIREBIRD_BASE_VER% - -:: Set this to 1 if you want to see the generated final command in the screen -:: output. Innosetup stores it automatically in the log file so this is not -:: necessary in normal use. Displaying it also makes the screen output harder -:: to read. -@set SHOW_FINAL_CMD= - -:: change as reqd, or comment out if ISC_PASSWORD is already set in your env -@set ISC_PASSWORD="secret" - -@set TAB= & - -@if not defined DRYRUN ( - if not exist %FBINSTALLLOGDIR% @mkdir %FBINSTALLLOGDIR% >nul 2>nul - if not exist %FBINSTALLCOPYDIR% @mkdir %FBINSTALLCOPYDIR% >nul 2>nul -) - -@if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::====SET_GLOBAL_ENV============================================ - - -::======================================================= -:GET_OPTS -@call :SET_VERBOSE_IF_DEBUG_ON -if defined DEBUG @echo Entering %0 - -:: Automatically parse the commandline and place all valid options into ENV VARS -:: Courtesy of this link: -:: https://stackoverflow.com/questions/3973824/windows-bat-file-optional-argument-parsing -::@setlocal enabledelayedexpansion - -:: NOTE 1: These variable names are case insensitive - we can pass CLEAN or -:: clean, for example. -:: NOTE 2: Variables with defaults are impossible to undefine via passing -:: parameters. They must be undefined in code. -:: NOTE 3: Most variables are flags. If a flag has a default it will take the -:: value of the next flag on the command line. For example -:: flag: flagwithdefault:1 -:: and this order of params: -:: flagwithdefault flag -:: will end up as -:: flagwithdefault=flag -:: Basically all this means that these variables should not be passed to runtime: -:: INTERACTIVE INSTALL INSTALLTYPE SERVER SERVICE_TASK SUPERSERVER - -set "options=APPTASK: CLASSICSERVER: CLEAN: CLIENT: CMD_PARAMS: COMPONENTS: COPYGDSLIB: DEVINST: DRYRUN: FINALCMD: FULL_CMD: FORCE: HELP: INTERACTIVE:1 INSTALL:1 INSTALLTYPE:ServerInstall NOARCHIVE: NOAUTOSTART: NOCANCEL: NOCOPYFBLIB: NOMSG: NOUNINSTALL: PASSWORD: RUN_TIMESTAMP: SCRIPTED: SERVER:1 SILENT: SP: SERVICE_TASK:1 SUPERCLASSIC: SUPERSERVER:1 TASK_LIST:UseSuperServerTask TESTNAME:"" UNINSTALL: VERYSILENT: XRESULT:0" -if defined VERBOSE @echo on -for %%O in (%options%) do ( - for /f "tokens=1,* delims=:" %%A in ("%%O") do ( - set "%%A=%%~B" - ) -) -if defined VERBOSE ( - call :PRINT_VARS - if NOT defined DEBUG pause -) - -:loop -if not "%~1"=="" ( - set "test=!options:*%~1:=! " - if "!test!"=="!options! " ( - echo Error: Invalid option %~1 - ) else if "!test:~0,1!"==" " ( - set "%~1=1" - ) else ( - set "%~1=%~2" - shift - ) - @if defined VERBOSE ( - @set %1 - if NOT defined DEBUG pause -) - shift - goto :loop -) - -if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::======================================================= - -::======================================================= -:SET_PARAMS -@call :SET_VERBOSE_IF_DEBUG_ON -@if defined DEBUG @echo Entering %0 -::@call :SET_VERBOSE - -:: Current possible install options (FB4 RC1) -:: [Types] - ServerInstall DeveloperInstall ClientInstall CustomInstall -:: [Components] - ServerComponent DevAdminComponent ClientComponent -:: [Tasks] - UseClassicServerTask UseSuperClassicTask UseSuperClassicTask\UseGuardianTask ^ -:: UseSuperServerTask UseSuperServerTask\UseGuardianTask UseApplicationTask UseServiceTask ^ -:: AutoStartTask CopyFbClientToSysTask CopyFbClientAsGds32Task - -:: Defaults are -:: SetupType=serverinstall -:: Components=servercomponent,devadmincomponent,clientcomponent -:: Tasks=usesuperservertask,useservicetask,autostarttask,copyfbclienttosystask - -:: InnoSetup can use MERGETASKS to add non-exclusive tasks to the default list. -:: For example: -:: MERGETASKS="UseSuperServerTask\UseGuardianTask,CopyFbClientAsGds32Task" -:: UNFORTUNATELY we can't negate tasks with ! if delayed variable expansion is -:: used so this option is not very useful to us. -:: -:: Instead we use TASKS to entirely redefine the task list. For example: -:: TASKS="UseClassicServerTask,UseApplicationTask,CopyFbClientAsGds32Task" - -:: There are other things we could test, maybe one day. See the installer help -:: dialogue or innosetup help for setup commandline params. - -:: FBIT uses SCRIPTED to automatically set /SP- /VERYSILENT /SUPPRESSMSGBOXES -:: INTERACTIVE and SCRIPTED are incompatible. INTERACTIVE is default but the -:: variable is never tested. - - -@if defined SCRIPTED ( - set VERYSILENT=VERYSILENT - set SP=SP- - set NOMSG=SUPPRESSMSGBOXES - set INTERACTIVE= -) - -@if defined UNINSTALL ( - set INSTALL= - @if defined CLEAN ( set CMD_PARAMS=!CMD_PARAMS! /CLEAN ) -rem We now have everything we need for uninstall so jump to the end - goto :SET_CMD_PARAMS -) - -:: Fix up any incompatible assignments - -@if defined CLASSICSERVER ( set SUPERSERVER=& set SUPERCLASSIC=) -@if defined SUPERCLASSIC ( set SUPERSERVER=& set CLASSICSERVER=) -:: Theoretically this next line is redundant -@if defined SUPERSERVER ( set SUPERCLASSIC=& set CLASSICSERVER=) - -@if defined CLIENT ( set INSTALLTYPE=ClientInstall & set DEVINST=& set SERVER=) -@if defined DEVINST (set INSTALLTYPE=DeveloperInstall & set SERVER=) -:: Theoretically this next line is redundant -@if defined SERVER (set INSTALLTYPE=ServerInstall ) - - -:: Now build our task list - -@if defined CLASSICSERVER ( set TASK_LIST=UseClassicServerTask) -@if defined SUPERCLASSIC ( set TASK_LIST=UseSuperClassicTask) -:: Theoretically this next line is redundant -@if defined SUPERSERVER ( set TASK_LIST=UseSuperServerTask) - -@if defined APPTASK ( - set TASK_LIST=!TASK_LIST!,UseApplicationTask -) else ( - set TASK_LIST=!TASK_LIST!,UseServiceTask -) - -@if NOT defined NOAUTOSTART ( - set TASK_LIST=!TASK_LIST!,AutoStartTask - set INSTALLTYPE=CustomInstall -) - -if NOT defined NOCOPYFBLIB ( - set TASK_LIST=!TASK_LIST!,CopyFbClientToSysTask - set INSTALLTYPE=CustomInstall -) - -@if defined COPYGDSLIB ( - set TASK_LIST=!TASK_LIST!,CopyFbClientAsGds32Task - set INSTALLTYPE=CustomInstall -) - -:SET_CMD_PARAMS -:: set up the CMD_PARAMS variable we will use - -@if defined FORCE (set CMD_PARAMS=!CMD_PARAMS! /FORCE ) - -@if defined NOCANCEL (set CMD_PARAMS=!CMD_PARAMS! /NOCANCEL ) - -:: Setting PASSWORD is only relevant for a server install -@if defined PASSWORD ( - @if defined SERVER ( - set SYSDBAPASSWORD=%ISC_PASSWORD% - set CMD_PARAMS=!CMD_PARAMS! /SYSDBAPASSWORD=%SYSDBAPASSWORD% - set INSTALLTYPE=CustomInstall - ) -) - -if defined NOMSG set CMD_PARAMS=!CMD_PARAMS! /SUPPRESSMSGBOXES -if defined SILENT set CMD_PARAMS=!CMD_PARAMS! /SILENT -if defined SP set CMD_PARAMS=!CMD_PARAMS! /SP- -if defined VERYSILENT set CMD_PARAMS=!CMD_PARAMS! /VERYSILENT - -:: Setting CustomInstall clears the default COMPONENTS list so we -:: must define it manually -@if /I %INSTALLTYPE% == "CustomInstall" ( - @if defined CLIENT ( set COMPONENTS=ClientComponent) - @if defined DEVINST ( set COMPONENTS=DevAdminComponent,ClientComponent) -) else ( - set COMPONENTS=ServerComponent,DevAdminComponent,ClientComponent -) - -if defined INSTALL ( - set FULL_CMD=/TYPE=!INSTALLTYPE! /TASKS="!TASK_LIST!" /COMPONENTS="!COMPONENTS!" !CMD_PARAMS! -) else ( - set FULL_CMD=!CMD_PARAMS! -) - -@if defined VERBOSE ( - @call :PRINT_VARS - if NOT defined DEBUG pause -) -@if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::===SET_PARAMS========================================== - -::======================================================= -:PRINT_VARS -:: if a variable is not defined we don't print it, except for critical -:: variables such as FINALCMD that MUST be defined. -@echo Variables set during script execution are: -@set ADIRNAME -@set APPTASK 2>nul -@set CLASSICSERVER 2>nul -@set CLEAN 2>nul -@set CLIENT 2>nul -@set CMD_PARAMS 2>nul -@set COMPONENTS 2>nul -@set COPYGDSLIB 2>nul -@set DEVINST 2>nul -@set DRYRUN 2>nul -@set FBINST_EXEC -@set FINALCMD 2>nul -@set FULL_CMD -@set FORCE 2>nul -@set INTERACTIVE 2>nul -@set INSTALL 2>nul -@set MERGE_TASKS 2>nul -@set NOARCHIVE= 2>nul -@set NOAUTOSTART 2>nul -@set NOCANCEL 2>nul -@set NOCOPYFBLIB 2>nul -@set NOMSG 2>nul -@set NOUNINSTALL 2>nul -@set PASSWORD 2>nul -@set RUN_TIMESTAMP 2>nul -@set SCRIPTED 2>nul -@set SERVICE_TASK 2>nul -@set SERVER 2>nul -@set SERVICE_TASK 2>nul -@set SILENT 2>nul -@set SP 2>nul -@set SUPERCLASSIC 2>nul -@set SUPERSERVER 2>nul -@set TASK_LIST 2>nul -@set TESTNAME 2>nul -@set UNINSTALL 2>nul -@set VERYSILENT 2>nul -@echo. - -@goto :EOF -::======================================================= - -::======================================================= -:RUN_INSTALLER -@echo. -@echo. -@call :SET_VERBOSE_IF_DEBUG_ON -if defined DEBUG @echo Entering %0 %* -::@call :CHECK_ENV || (@echo Check the values in SET_ENV & goto :EOF ) -@call :CHECK_ENV -::@call :RESET_INSTALL_ENV -@call :GET_OPTS %* -@call :SET_PARAMS %* -::@call :SET_VERBOSE -@if defined VERBOSE @echo on -@if defined VERBOSE @echo FULL_CMD is %FULL_CMD% -@if defined VERBOSE ( if NOT defined DEBUG pause ) -@call :TIMESTAMP -@set RUN_TIMESTAMP=%TIMESTAMP% -@set INSTALL_TIMESTAMP=%TIMESTAMP% - -set FINALCMD=%FBINST_EXEC% %FULL_CMD% /DIR=%FIREBIRD% /LOG=%FBINSTALLLOGDIR%\install%RUN_TIMESTAMP%.log /SAVEINF=%FBINSTALLLOGDIR%\install%RUN_TIMESTAMP%-saved.inf -if defined DRYRUN ( - @echo DRYRUN - Not executing call %FINALCMD% -) else ( - @if defined SHOW_FINAL_CMD @echo Executing %FINALCMD% - call %FINALCMD% - - @if errorlevel 1 ( - rem @echo Calling %FBINST_EXEC% failed with %ERRORLEVEL% - set _err=%ERRORLEVEL% - call :ISS_ERROR %_err% %FBINST_EXEC% %FULL_CMD% - set /A XRESULT+=1 - ) else ( - @echo Calling %FBINST_EXEC%......................SUCCESS! - ) - - @echo. - @echo Now checking system state... - if not defined NOCOPYFBLIB ( - call :CHECKFILEEXISTS c:\windows\system32\fbclient.dll good bad err_is_fail - ) else ( - call :CHECKFILEEXISTS c:\windows\system32\fbclient.dll bad good no_err_is_fail - ) - - if not defined COPYGDSLIB ( - call :CHECKFILEEXISTS c:\windows\system32\gds32.dll bad good no_err_is_fail - ) else ( - call :CHECKFILEEXISTS c:\windows\system32\gds32.dll good bad err_is_fail - ) - @echo. - @call :COPY_INSTALL - @echo. -) - @echo. -@echo %0 completed with %XRESULT% errors -@set XRESULT=0 -@if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@echo. -@echo. -@goto :EOF -::===RUN_INSTALLER================================= - - -::========================================================= -:RUN_UNINSTALLER -@echo. -@echo. -@call :SET_VERBOSE_IF_DEBUG_ON -::@call :SET_VERBOSE -@if defined DEBUG @echo Entering %0 %* -::@call :RESET_INSTALL_ENV -@call :GET_OPTS %* UNINSTALL -@call :SET_PARAMS -::@call :SET_VERBOSE -@if defined VERBOSE @echo on -@if defined VERBOSE call :PRINT_VARS -@if defined VERBOSE @echo FULL_CMD is %FULL_CMD% -@if defined NOUNINSTALL ( - @echo NOUNINSTALL was passed. Exiting %0. - @goto :EOF -) -@call :TIMESTAMP -@set RUN_TIMESTAMP=%TIMESTAMP% -@set FINALCMD=%FIREBIRD%\%UNINSTALLEXE% %FULL_CMD% /log=%FBINSTALLLOGDIR%\uninstall%RUN_TIMESTAMP%.log -@if defined VERBOSE ( if NOT defined DEBUG (pause) ) -@if defined DRYRUN ( - echo DRYRUN - Not executing call %FINALCMD% - if defined DEBUG @echo Leaving %0 - @call :UNSET_VERBOSE - @echo. - @echo. - goto :EOF -) - @if defined SHOW_FINAL_CMD @echo Executing %FINALCMD% - call %FINALCMD% 2>nul - if errorlevel 1 ( - set _err=%ERRORLEVEL% - ) else ( - set _err=0 - ) - if %_err% GEQ 1 ( - set _err=%ERRORLEVEL% - call :ISS_ERROR %_err% %UNINSTALLEXE% %FULL_CMD% - set /A XRESULT+=1 - ) else ( - echo Calling %FIREBIRD%\%UNINSTALLEXE% ................SUCCESS! - ) - - rem We need to give time to the uninstaller to clean up - rem If the install is interactive we need to close the final msg box first - rem If the install is scripted we need to pause a few seconds. - rem Change as required for your system. - if INTERACTIVE equ 1 ( - echo Close the uninstaller dialog now!!! - timeout /t 10 - ) else ( - timeout /t 3 - ) - - echo. - echo Now checking system state... - call :CHECKFILEEXISTS c:\windows\system32\fbclient.dll bad good no_err_is_fail - call :CHECKFILEEXISTS c:\windows\system32\gds32.dll bad good no_err_is_fail - - if defined CLEAN ( - call :CHECKSHAREDDLLS - call :CHECKFILEEXISTS %FIREBIRD% bad good no_err_is_fail - ) - echo. - call :COPY_INSTALL - echo. -) -echo. - -echo %0 completed with %XRESULT% errors -set XRESULT=0 -if defined DEBUG @echo Leaving %0 -call :UNSET_VERBOSE -@echo. -@echo. -@goto :EOF -::====CLICK_THROUGH_UNINSTALL======================== - - -::===================================== -:CHECKFILEEXISTS -if defined DEBUG @echo Entering %0 -@call :SET_VERBOSE_IF_DEBUG_ON - -:: DIR returns an error if file not found and zero if file is returned so we -:: have to turn things around a bit if we want to test for a file that SHOULD -:: be removed. In that case no error is a bad sign! -:: -:: This sub-routine takes four params -:: - %1 filename or dirname to verify -:: - %2 - string for no error from dir. ie if we expect the file to exist -:: then pass GOOD. If we don't expect it then we pass BAD. -:: - %3 - string to output if DIR throws an error -:: - %4 - flag to indicate if 0 is an error or not -::@call :SET_VERBOSE -if defined VERBOSE @echo on -if defined VERBOSE @echo %* -dir %1 >nul 2>nul -if errorlevel 1 ( - set _err=%ERRORLEVEL% -) else ( - set _err=0 -) -if %_err% EQU 0 ( - @echo %TAB% %1 exists - %2 ! -) else ( - @echo %TAB% %1 not found - %3 ! -) - -if "%4"=="err_is_fail" ( - if %_err% GTR 0 ( - set /A XRESULT+=1 - @echo XRESULT++ - ) -) -if "%4"=="no_err_is_fail" ( - if %_err% EQU 0 ( - set /A XRESULT+=1 - @echo XRESULT++ - ) -) - -call :RESET_ERRORLEVEL -@call :UNSET_VERBOSE -if defined DEBUG @echo Leaving %0 -@goto :EOF -::===CHECKFILEEXISTS================================== - - -::===================================== -:CHECKSHAREDDLLS -if defined DEBUG @echo Entering %0 -@call :SET_VERBOSE_IF_DEBUG_ON -@reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs > %TEMP%\shareddlls.txt -@grep --ignore-case --count firebird %TEMP%\shareddlls.txt > %TEMP%\shareddllscount.txt -set /p SHAREDDLLSCOUNT= < %TEMP%\shareddllscount.txt -if NOT defined DEBUG del /q %TEMP%\shareddll*.txt -if %SHAREDDLLSCOUNT% GTR 0 ( - @echo %TAB% Oops - residue in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs - set /A XRESULT+=1 - @echo XRESULT++ -) -call :RESET_ERRORLEVEL -if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::===CHECKSHAREDDLLS=================== - - -::===================================== -:COPY_INSTALL -@call :SET_VERBOSE_IF_DEBUG_ON -if defined DEBUG @echo Entering %0 -::@call :SET_VERBOSE -if defined VERBOSE @echo on - -:: ADIRNAME should normally be set during install and persist for uninstall -@if not defined ADIRNAME ( - @if defined INSTALL_TIMESTAMP ( - @if defined TESTNAME ( - @set ADIRNAME=%FBINSTALLCOPYDIR%\%FIREBIRD_BASE_VER%_%INSTALLTYPE%_%TESTNAME%_%INSTALL_TIMESTAMP% - ) else ( - @set ADIRNAME=%FBINSTALLCOPYDIR%\%FIREBIRD_BASE_VER%_%INSTALLTYPE%_%INSTALL_TIMESTAMP% - ) - ) else ( - @set ADIRNAME=%FBINSTALLCOPYDIR%\%FIREBIRD_BASE_VER%_Uninstall_%RUN_TIMESTAMP% - ) -) -@if defined verbose @echo ADIRNAME is %ADIRNAME% -@mkdir %ADIRNAME% 2>nul - -@if defined INSTALL ( - @if not defined NOARCHIVE ( - @echo %TAB% Copying Install to %ADIRNAME% - @xcopy /e /i /y %FIREBIRD% %ADIRNAME% > nul - @if errorlevel 1 ( - @echo ERROR Failure executing xcopy /e /i /y %FIREBIRD% %ADIRNAME% - ) - ) - @copy %FBINSTALLLOGDIR%\install%RUN_TIMESTAMP%-saved.inf %ADIRNAME%\install-saved.inf > nul - @copy %FBINSTALLLOGDIR%\install%RUN_TIMESTAMP%.log %ADIRNAME%\install.log > nul -) else ( - @echo %TAB% Copying uninstall log to %ADIRNAME% - @copy %FBINSTALLLOGDIR%\uninstall%RUN_TIMESTAMP%.log %ADIRNAME%\uninstall.log > nul -) -@if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::===COPY_INSTALL====================== - -::===================================== -:CHECK_ENV -:: TODO - add more checks for the environment declared in SET_GLOBAL_ENV -if not exist %FBINST_EXEC% ( - echo Cannot find %FBINST_EXEC% - exit /b 1 -) -@goto :EOF -::===CHECK_ENV========================= - -::===================================== -:RESET_ERRORLEVEL -:: ERRORLEVEL is an internal variable. We can see its value with -:: 'echo %ERRORLEVEL%' but if we try to reset its value with -:: SET ERRORLEVEL=0 we just create an env var called ERRORLEVEL which will -:: not have the same value as the internal ERRORLEVEL. We have to execute an -:: arbitrary command that cannot fail if we want to really reset the internal -:: variable. -@ver > nul -@goto :EOF -::===RESET_ERRORLEVEL================== - -::===================================== -:SET_VERBOSE_IF_DEBUG_ON -:: The script is designed to allow turning VERBOSE on at the sub-routine level -:: If we set DEBUG globally then we should turn on VERBOSE automatically when -:: we enter a sub-routine -@if defined DEBUG ( - @set VERBOSE=1 - @echo on -) -@goto :EOF -::===SET_VERBOSE_IF_DEBUG_ON================ - -::===================================== -:SET_VERBOSE -@set VERBOSE=1 -@goto :EOF -::===SET_VERBOSE================ - -::===================================== -:UNSET_VERBOSE -:: Unset VERBOSE before exiting each sub-routine. -:: and force echo off -@if NOT defined DEBUG ( - @set VERBOSE= - @echo off -) -@goto :EOF -::===UNSET_VERBOSE================ - - -::===================================== -:HELP -@echo off -@echo. -@more /e /t4 %~d0%~p0fbit-help.txt -@echo. -goto :EOF -::===HELP============================== - -::===================================== -:ISS_ERROR -@echo. -@echo InnoSetup ErrorCode %1 from calling %~2 %~3 %~4 %~5 %~6 %~7 %~8 %~9 -@echo Definition of Innosetup errorcode %1 is to be added later -@echo. -@goto :EOF -::====================================== - -::================================================================================================================ -:: GENERIC SUPPORT ROUTINES FROM HERE TO END ====================================================================== -::================================================================================================================ - -::===================================== -:GET_DATE -if NOT defined DEBUG @echo off -echo. | date | FIND "(mm" > NUL -if errorlevel 1 ((set MD=0) & call :ParseDate DD MM) else ((set MD=1) & call :ParseDate MM DD) -@goto :EOF -:ParseDate -for /f "tokens=1-3 delims=/.- " %%a in ("%DATE%") do ( -set %1=%%a -set %2=%%b -set YYYY=%%c -@goto:EOF) -::===================================== - -::===================================== -:GET_TIME -if NOT defined DEBUG @echo off -for /f "tokens=1-4 delims=:. " %%a in ("%TIME%") do ( -set hh=%%a -set nn=%%b -set ss=%%c -set ms=%%d -@goto :EOF) -::===================================== - -::===================================== -:CLEAR_DT_VARS -if NOT defined DEBUG @echo off -set MM= -set DD= -set YYYY= -set hh= -set nn= -set ss= -set ms= -@goto :EOF -::===================================== - -::===================================== -:TIMESTAMP -@call :GET_DATE -@call :GET_TIME -@set TIMESTAMP=%YYYY%%MM%%DD%%hh%%nn%%ss% -if defined DEBUG (@echo Timestamp set to %TIMESTAMP%) -call :CLEAR_DT_VARS -@goto :EOF -::===================================== - -::============================================================================== -:: MAIN is always the last routine -::============================================================================== - -::===================================== -:MAIN -@if defined DEBUG @echo Entering %0 %* -@call :SET_GLOBAL_ENV - -@if /I "%1"=="help" ( - @call :HELP - @goto :EOF -) - -:: sometimes it is useful to just tidy up! -@if /I "%1"=="clean" ( - @call :RUN_UNINSTALLER SCRIPTED CLEAN - @goto :EOF -) - -@call :RUN_INSTALLER %* -@call :RUN_UNINSTALLER %* - -@if defined DEBUG @echo Leaving %0 -@call :UNSET_VERBOSE -@goto :EOF -::===MAIN============================== - -:: CONTINUE with -:: - look at setting up different test recipes and naming them. -:: - Integrate innosetup exit codes and look at error handling -:: - Tidy up the relationship between DEBUG and VERBOSE. -:: - DEBUG should turn on VERBOSE? -:: - VERBOSE should be routine specific.? -:: - DEBUG should persist for entire script run? - - -:: NOTHING BEYOND THIS POINT=========== -:EOF diff --git a/builds/install/arch-specific/win32/test_installer/fbit.ps1 b/builds/install/arch-specific/win32/test_installer/fbit.ps1 new file mode 100644 index 00000000000..2cf0eac41ca --- /dev/null +++ b/builds/install/arch-specific/win32/test_installer/fbit.ps1 @@ -0,0 +1,1199 @@ +<# +.SYNOPSIS + +fbit - test the firebird binary installer on windows + +.DESCRIPTION + +fbit {PARAM [...]] + + Parameters may be passed in any order except for one special case: + + fbit -realclean + + will clean up from previous broken installs. -realclean must the first + parameter and subsequent parameters are ignored. Note: - It will run + silently and will force cleanup, even if the uninstaller no longer exists. + + By default fbit installs Firebird according to the parameters passed and then immediately + uninstalls it. A copy of the install is made, along with the install and uninstall logs. + + REQUIREMENTS + ============ + + Some knowledge of InnoSetup will be useful. See $FIREBIRD/doc/installation_scripted.txt + for more info. + + FBIT Specific Parameters + ======================== + Param Name Value Passed to fbit Comment + ---------- -------------------- ------- + -help - Displays this screen + -dryrun - Show what will be done. No changes are made + -noarchive - Disables copying of install dir to %USERPROFILE%\fbit + Logs and inf files are always saved. + -nouninstall - Disable automatic uninstall for this test run + -scripted - Sets VERYSILENT, SP and nomsg + -testname NameOfTestRun Optional. No spaces allowed. Used for storing test run details. + + -fbinst_exec Path and filename of Installer Will be dynamically determined if not set. + + -config A file name Pass parameters in a config file. + Overrides params passed on the command-line. + + The following parameters are set by default. They are unset + automatically when a conflicting parameter is passed: + + DefaultParam Default Value set by fbit Unset by + ------------- ------------------------- ---------- + -interactive True -scripted + -installtype ServerInstall -client or -devinst + -service_task True -apptask + -superserver True -classicserver or -superclassic + + Firebird Installer specific Parameters + ====================================== + Param Name Value passed to installer Action when set + ---------- ------------------------- --------------- + -copygdslib CopyFbClientAsGds32Task Copy fbclient to and rename to gds32 + -force FORCE Force installation + -noautostart - Does not set AutoStartTask + -nocopyfblib - Does not copy fbclient to + -password /SYSDBAPASSWORD=%PASSWORD% Changes SYSDBA password from masterkey + If -password is not passed on the command-line and + ISC_PASSWORD is set then ISC_PASSWORD will be used. + -legacy_auth EnableLegacyClientAuth Adds support for legacy authentication + + Installation Tasks + ================== + Param Name Value passed to /TASKS Comment + ------------- ---------------------- --------------- + -apptask UseApplicationTask Will not install as a service + -classicserver UseClassicServerTask Will configure classic server + -superclassic UseSuperClassicTask Will configure super classic + + Installation Types + ================== + Param Name Value passed to /TYPE Comment + ------------ --------------------- ------- + -client ClientInstall Minimal working client install + -devinst DeveloperInstall Everything but the server. + -server_install ServerInstall + + Uninstallation + ============== + Param Name Value passed to uninstaller Comment + -------------- --------------------------- ------- + -clean CLEAN Completely remove an existing firebird install. + Assumes installed version of Firebird matches + $firebirdrootdir\$firebird_base_ver set in fbit script. + + -realclean Calls uninstaller if it exists. + Deletes the $firebirdrootdir\$firebird_base_ver dir + Removes the list of firebird shared dll's in the registry. + BEWARE - this should only be used when normal CLEAN is no + longer working correctly. + + -realclean -force Do not prompt during clean up. (Currently not implemented.) + + Generic InnoSetup parameters + ============================ + Param Name Value passed to installer Comment + ---------- ------------------------- ------- + -nomsg SUPPRESSMSGBOXES Suppress message boxes + -nocancel NOCANCEL Prevents user cancelling install + -silent SILENT + -sp SP- Disables the 'This will install...' prompt + -verysilent VERYSILENT + + +.PARAMETER help +Outputs this help screen and quits. + +.INPUTS + +None. + +.OUTPUTS + +None. + +.EXAMPLE + + fbit -scripted + +(Run a scripted server install followed immediately by a scripted uninstall. + Adding -verbose is recommended.) + +.EXAMPLE + + fbit -realclean + + (Clean up previous firebird install) + +.EXAMPLE + + fbit -scripted -client + +(Test scripted install of firebird client) + +#> + + +[CmdletBinding(DefaultParameterSetName = "StandardParams" )] +param( + + # Load a configuration file + [string]$config, + + [Parameter(Mandatory = $true, ParameterSetName = "classic")] + [switch]$classicserver, + + [Parameter(Mandatory = $true, ParameterSetName = "superclassic")] + [switch]$superclassic, + + # is the default. No need to set. + [switch]$superserver, + # use scripted install instead of default interactive + [switch]$scripted, + # uninstall an existing install. (install is the default.) + [switch]$uninstall, + # Ignore errors as far as possible. Used for -realclean + [switch]$force, + # install firebird. This is the default. + [switch]$install, + # Remove as many traces of Firebird as possible from the system. + [switch]$realclean, + # Print generated command to screen before execution. + [switch]$show_final_command, + # Just install. Default behaviour is to install and uninstall. + [switch]$nouninstall, + # verify current install + [switch]$check_install, + # verify current install + [switch]$check_uninstall, + + # parameters specific to this script + [string]$inno_params_from_cmdline, + [string]$fbinst_exec, + [string]$testname = "fbit_test", + + # ### Params to control InnoSetup + + [switch]$apptask, + [switch]$clean, + [switch]$client_install, + [string]$components = "", + [switch]$copygdslib, + [switch]$dev_install, + [switch]$noarchive, + [switch]$noautostart, + [switch]$nocancel, + [switch]$nocopyfblib, + [switch]$nomsg, + [string]$password = "masterkey", + [switch]$server_install, + [switch]$silent, + [switch]$sp, + # install Firebird as a service. This is the default. See also apptask. + [switch]$service_task, + [string]$task_list = "", + [switch]$verysilent, + + # General parameters. Do not add anything after help + + [switch]$dryrun, + [switch]$help + + + +) + + +# Vars available to all functions in script +$TAB = ' ' +$ErrorCount = 0 +[string]$action = "" +# Full Install/Uninstall command that will be executed +[string]$finalcmd +# The actual list of commands that will be passed to the installer/uninstaller +[string]$full_cmdline = "" +# Override timestamp +[string]$run_timestamp + +[boolean]$IsVerbose = $false +[boolean]$IsDebug = $false + +[string]$uninst_cmdline = "" +[string]$inno_silent = "" + + +[System.ConsoleColor]$fgcol = "Black" +[System.ConsoleColor]$fgred = "Red" +[System.ConsoleColor]$fggreen = "Green" + +Import-Module .\fbit-functions.psm1 + +<# + TO DO list + +#> + + +<# +.SYNOPSIS +Load a simple config file and assign key-value pairs to $key variables + +.DESCRIPTION + + +.EXAMPLE +# Comment lines may start with # or // +# Variables are strings by default +avar="AValue" +# Booleans must be passed as 0 or 1 and are converted to boolean types +aboolean=$true +# Switches may be set by passing the switch name prefixed with a hyphen + -aswitch +# Or just passed 'as is' + aswitch + +.NOTES +General notes +#> +function LoadConfig( [string] $_conffile ) { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + Write-Debug "_conffile is $_conffile" + foreach ($i in $(Get-Content $_conffile)) { + # Trim any lead/trailing whitespace + # Include value in quotes if you need trailing whitespace! + $local:line = $i.trim() + if ($local:line -ne '') { + if ( -not ($line.startswith( '#' ) -or $line.startswith( '//' )) ) { + Write-Verbose "Processing $local:line" + + $local:avalue = $null + $local:akey = $null + + $local:akey = $i.split('=')[0] + if ( $null -ne $local:akey ) { $local:akey = $local:akey.trim() } + + # Check if key is a switch. + if ( $local:akey.StartsWith('-') ) { + Write-Debug "$local:akey is a switch" + Set-Variable -Scope global -Name $local:akey.TrimStart('-') -Value $true + Set-Variable -Scope Script -Name $local:akey.TrimStart('-') -Value $true + continue + } + + try { + $local:avalue = $i.split('=', 2)[1] + } catch { + Write-Debug "Setting $local:akey to true" + Set-Variable -Scope global -Name $local:akey -Value $true + Set-Variable -Scope Script -Name $local:akey -Value $true + continue + } + + if ( $null -ne $local:avalue ) { $local:avalue = $local:avalue.trim() } + Write-Debug "akey is $local:akey and avalue is $local:avalue" + # Test avalue and change type to boolean if necessary + switch ( $local:avalue ) { + { $_ -eq "1" } { + Write-Debug "Setting $local:akey to true" + Set-Variable -Scope Global -Name $local:akey -Value $true + Set-Variable -Scope Script -Name $local:akey -Value $true + } + { $_ -eq "0" } { + Write-Debug "Setting $local:akey to false" + Set-Variable -Scope Global -Name $local:akey -Value $false + Set-Variable -Scope Script -Name $local:akey -Value $false } + { $_ -eq $null } { + Write-Debug "Setting $local:akey to true" + Set-Variable -Scope Global -Name $local:akey -Value $true + Set-Variable -Scope Script -Name $local:akey -Value $true + } + Default { + Set-Variable -Scope global -Name $local:akey -Value $local:avalue + Set-Variable -Scope Script -Name $local:akey -Value $local:avalue + } + } + } else { + Write-Debug "NOT processing commented $local:line" + + } + } + } +# Set-PSDebug -Off +# Get-ChildItem Variable: +# Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber)" + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" +} + + +function print_vars( [string]$_action ) { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + $local:varfile = "$fbinstalllogdir/${testname}-${_action}-$run_timestamp.vars" + if ( $script:IsDebug ) { + Get-ChildItem Variable: + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber)" + } + if ( $script:IsVerbose ) { + spacer > $local:varfile + if ( check_file_exists "fb_build_vars_${env:PROCESSOR_ARCHITECTURE}.txt" ) { + spacer "Firebird Build Environment" >> $local:varfile + Get-Content fb_build_vars_${env:PROCESSOR_ARCHITECTURE}.txt >> $local:varfile + spacer "Firebird Build Environment END" >> $local:varfile + spacer >> $local:varfile + } + spacer 'Global Vars' >> $local:varfile + Get-Variable -Scope global >> $local:varfile + spacer 'Global Vars END' >> $local:varfile + spacer >> $local:varfile + spacer 'Env Vars' >> $local:varfile + env | grep '^FB' >> $local:varfile + env | grep '^ISC' >> $local:varfile + spacer 'Env Vars END' >> $local:varfile + spacer 'Script Vars' >> $local:varfile + Get-Variable -Scope script | Format-Table -AutoSize -Wrap >> $local:varfile + spacer 'Script Vars END' >> $local:varfile + spacer >> $local:varfile + spacer 'Local Vars' >> $local:varfile + Get-Variable -Scope local >> $local:varfile + spacer 'Local Vars END' >> $local:varfile + spacer >> $local:varfile + } + Write-Debug "Leaving $($MyInvocation.MyCommand.Name)" + +} + +function show-help() { + Get-Help $PSCommandPath -ShowWindow +} + + + + + +<# +.SYNOPSIS +Set defaults based on lack of supplied arguments +#> +function check_params() { + + if ( $(Test-Path variable:$script:MyInvocation.BoundParameters['Verbose'] ) ) { + $script:IsVerbose = $script:MyInvocation.BoundParameters['Verbose'].IsPresent + } + + if ( $(Test-Path variable:$script:MyInvocation.BoundParameters['Debug'] ) ){ + $script:IsDebug = $script:MyInvocation.BoundParameters['Debug'].IsPresent + } + + if ( $script:config ) { + Write-Output "script:config is $script:config" + LoadConfig $script:config + } else { + Write-Output "$($MyInvocation.MyCommand.Name) Not calling script:config $script:config" + } + + if ( $script:IsDebug ) { + Get-ChildItem Variable: + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber ) After testing script:config $script:config" + } + + # ### fbit related param checks. These control what gets executed. ### # + # By default the script is designed to install, check install and uninstall. + # Those defaults are over-ridden by "realclean", "uninstall", and "check_install" + + # If realclean is set then we must try to uninstall/cleanup. + # fbit will exit after "clean" or "realclean" has finished. + if ( $script:realclean ) { $script:uninstall = $true } + + # Default to install if uninstall not set. uninstall is run automatically after. + # Pass nouninstall if the intention is to keep the installation for further testing + $script:install = !$script:uninstall + + # By default we install unless uninstall has been set. + # If realclean has been set then we really clean up and then exit. + # If check_install has been set then we check the install and exit. + # If check_uninstall has been set then we check the install and exit. + if ( $script:install ) { $script:action = "install" } + if ( $script:uninstall ) { $script:action = "uninstall" } + if ( $script:realclean) { $script:action = "realclean" } + if ( $script:check_install -and !$realclean ) { $script:action = "check_install" } + if ( $script:check_uninstall ) { $script:action = "check_uninstall" } + + + # ### InnoSetup related param checks ### # + + $script:interactive = !$script:scripted + + + # default to superserver if neither of classic nor superclassic are set + $script:superserver = !($script:classicserver -or $script:superclassic) + + # default to server install if neither of dev nor client install are set + $script:server_install = !($script:dev_install -or $script:client_install ) + + # Install Firebird as a service if $apptask not set + $script:service_task = !($script:apptask) + + # If ISC_PASSWORD is set and password defaults to masterkey then set password + # to ISC_PASSWORD. + # If password != masterkey then we over-ride the value of $env:ISC_PASSWORD + if ( $env:ISC_PASSWORD -and ($script:password -eq "masterkey" ) ) { + $script:password = $env:ISC_PASSWORD + } + + # ### END of InnoSetup related param checks ### # + + if ( $script:IsDebug ) { + Get-ChildItem Variable: + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber ) Before leaving function." + } +} + + + +<# +.SYNOPSIS +Check registry for shared dlls + +.NOTES +Currently checks for all references to firebirdin the list of sharedDlls. +Perhaps this should be limited to include a firebird major version check. +#> +function check_shared_dlls() { + + $local:shareddlls = (reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs) + $local:count = (Select-String -InputObject "$local:shareddlls" -Pattern "firebird" -AllMatches).Matches.Count + + if ( $local:count -gt 0 ) { + $script:ErrorCount += 1 + Write-Output "$script:TAB Shared firebird dlls found in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs" + } else { + Write-Output "$script:TAB No shared firebird dlls found in registry" + } + +} + + +<# +.SYNOPSIS +Make a copy of the install +#> +function copy_install() { # ( [string]$_sourceFolder, [string]$_targetFolder ) { + + $_source_folder = $script:FIREBIRD + $_target_folder = $script:copy_install_target + + Write-Verbose "Saving Firebird Installation to $_target_folder" + + if ( ! ( Test-Path -Path $_target_folder ) ) { mkdir $_target_folder } + Copy-Item -Path $_source_folder\* -Destination $_target_folder -Recurse -Force | Out-Null + if ( Test-Path $script:install_log_file -PathType leaf ) { + Copy-Item -Path $script:install_log_file -Destination $_target_folder -Force | Out-Null + } + if ( Test-Path $script:install_inf_file -PathType leaf ) { + Copy-Item -Path $script:install_inf_file -Destination $_target_folder -Force | Out-Null + } + +} + +<# +.SYNOPSIS +Check that the sec db has been initialised +.DESCRIPTION +Check that the sec db has been initialised. +Also check if masterkey is used for the SYSDBA password. + +.NOTES + + if user has specified a password and it is not masterkey then + verify that + - the password works + - that masterkey does not work. + + +#> +function check_server_sec_db() { + + # Check that the security db exists + $local:retval = check_file_exists "$script:FIREBIRD\security${script:fbmajver}.fdb" + if ( !$local:retval ) { + $script:fgcol = ( $script:action | Select-String -Pattern "un" -NotMatch -Quiet ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}$script:FIREBIRD\security${script:fbmajver}.fdb not found." + return + } + + # Now check that isql is available + $local:retval = check_file_exists "$script:FIREBIRD/isql.exe" + if ( !$local:retval ) { + $script:fgcol = ( $script:action | Select-String -Pattern "un" -NotMatch -Quiet ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}$FIREBIRD\isql.exe does not exist. Cannot check security db" + return + } + + #Write-Output "${TAB}Test the password we used during the install..." + + Write-Output "exit;" > $env:Temp\infile.txt + + foreach ( $apw in "$script:password", "masterkey", "masterke" ) { + Exec_SQL "localhost:employee" "SYSDBA" "$apw" + if ( $apw -eq "$script:password") { + $local:found_str_is_fail = $true + } else { + $local:found_str_is_fail = $false + } + $local:teststr = "Your user name and password are not defined. Ask your database administrator to set up a Firebird login." + $local:retval = $(check_file_output "$env:Temp\outfile.txt" "$local:teststr") + + print_output "${TAB}Password test with $apw " $local:retval $local:found_str_is_fail "PASSED" "FAILED" + + } + +} + +<# +.SYNOPSIS +Use the $FIREBIRD variable to check the current firebird installation + +.DESCRIPTION +Long description + +.EXAMPLE +An example + +.NOTES +General notes +#> +function check_firebird_installed() { + + $local:retval = check_file_exists $script:FIREBIRD -_isdir + if ( ! $local:retval ) { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}$script:FIREBIRD directory does not exist." + return + } + + $local:retval = check_file_exists "${script:FIREBIRD}\firebird.exe" + if ( $local:retval ) { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fggreen : $script:fgred + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Server appears to be installed." + $script:server_installed = $true + } else { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Server does NOT appear to be installed." + } + + + $local:retval = check_file_exists "$script:FIREBIRD/isql.exe" + if ( $local:retval ) { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fggreen : $script:fgred + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Dev Tools appears to be installed." + $script:devtools_installed = $true + } else { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Dev Tools do NOT appear to be installed." + } + $local:retval = check_file_exists "$script:FIREBIRD/fbclient.dll" + if ( $local:retval ) { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fggreen : $script:fgred + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Client appears to be installed." + $script:client_installed = $true + } else { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fgred : $script:fggreen + Write-Host -ForegroundColor $script:fgcol "${TAB}Firebird Client does NOT appear to be installed." + } + +} + + +function check_service_installed( [string]$_servicename ) { + + $local:ExpectedServiceName = "FirebirdServerDefaultInstance" + + $local:ActualServiceName = Get-Service -ErrorAction ignore -Name $local:ExpectedServiceName | Select-Object -ExpandProperty Name + if (check_result $local:ExpectedServiceName $local:ActualServiceName $true ) { + $script:fgcol = ( $script:action -eq "check_install" ) ? $script:fggreen : $script:fgred + Write-Host -ForegroundColor $script:fgcol "${TAB}$local:ExpectedServiceName is installed. " + } else { + $script:fgcol = ( $script:action -eq "check_uninstall" ) ? $script:fggreen : $script:fgred + Write-Host -ForegroundColor $script:fgcol "${TAB}$local:ExpectedServiceName is NOT installed. " + } +} + + +function load_fb_build_env() { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + # Build_All.bat should generate fb_build_vars_${env:PROCESSOR_ARCHITECTURE}.txt + $local:fbbuild_vars_file = Get-Content "fb_build_vars_${env:PROCESSOR_ARCHITECTURE}.txt" + + $script:fbbuild_vars = @{} +# $local:fbbuild_vars_file | Sort-Object -Property key | ForEach-Object { + $local:fbbuild_vars_file | ForEach-Object { + $s = $_ -split "=" + $s[1] = $s[1].Trim() + $script:fbbuild_vars.Add($s[0], $s[1] ) + } + if ( $script:IsDebug ) { + Get-ChildItem Variable: + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber) " + } + + # Check that we have fbmajver and fix it if not. + # Normally this should not happen if we have just built firebird + if ( ! $script:fbbuild_vars.ContainsKey('FB_MAJOR_VER') ) { + # Try to locate build_no.h + $local:fb_root_path= $script:fbbuild_vars.'FB_ROOT_PATH' + if ( Test-Path "${local:fb_root_path}\src\jrd\build_no.h" -PathType Leaf ) { + + foreach ($aline in $(Get-Content Z:\FB30\FB3-dev\src\jrd\build_no.h | grep "#define FB_")) { + $s = $aline.split(" ") + $s[2] = $s[2].Trim('"') + $script:fbbuild_vars.Add($s[1], $s[2] ) + } + $script:fbmajver = $script:fbbuild_vars.'FB_MAJOR_VER' + $script:fbpackageNum = $script:fbbuild_vars.ContainsKey('FB_PACKAGE_NUMBER') ? $script:fbbuild_vars.'FB_PACKAGE_NUMBER' : 0 + + $script:fbbuild_vars.'FBBUILD_FILE_ID' = $script:fbbuild_vars.'FB_MAJOR_VER' + "." + + $script:fbbuild_vars.'FB_MINOR_VER' + "." + + $script:fbbuild_vars.'FB_REV_NO' + "." + + $script:fbbuild_vars.'FB_BUILD_NO' + "-" + + $script:fbpackageNum + "-" + + $script:fbbuild_vars.'FB_TARGET_PLATFORM' + } + } + + $script:fbbuild_vars = [System.Collections.SortedList] $script:fbbuild_vars + + $script:fbbuild_vars.GetEnumerator() | ForEach-Object { + Write-Verbose "$($_.Key): $($_.Value)" + } + + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" + +} + + +<# +.SYNOPSIS +Analyse the installation and environment. Set some variables. +#> +function check_environment() { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + # If passed via command line + if ( $script:fbinst_exec -ne "" ) { + Write-Debug "Determine build env from $script:fbinst_exec" +# Set-PSDebug -Trace 2 + $path_file = @{} + $path_file = $script:fbinst_exec -split "\\", -2 + $path_file = $path_file[1] -split ".exe" , 2 + $script:FirebirdInstallVer = $path_file[0] + $_astr = $script:FirebirdInstallVer -split "\." + $_astr = $_astr[0] -split "-" + $script:fbmajver = $_astr[1] +# Set-PSDebug -Trace 0 + } else { + Write-Debug "Determine build env dynamically" + load_fb_build_env + switch ( $script:fbmajver ) { + "3" { + $local:fb_file_id = $script:fbbuild_vars.'FBBUILD_FILE_ID' -replace "-", "_" + } + Default { + $local:fb_file_id = $script:fbbuild_vars.'FBBUILD_FILE_ID' + } + } + + if ( $local:fb_file_id -eq "" ) { + Write-Output "Unable to set fbinst_exec." + } else { + $script:FirebirdInstallVer = "Firebird-${local:fb_file_id}" + $script:fbinst_exec = -join ($script:fbbuild_vars.'FB_ROOT_PATH', "\builds\install_images\", $script:FirebirdInstallVer , '.exe' ) + Write-Verbose "Setting fbinst_exec to $script:fbinst_exec" + } + + } + if ( $script:IsDebug ) { + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber)" + } + +# Set-PSDebug -Trace 2 + $script:fbinstalllogdir = "$env:userprofile\fbit-tests\logs" + $script:fbinstallcopydir = "$env:userprofile\fbit-tests\install_archive" + + + #This is just the default root directory for all versions of firebird + $script:firebirdrootdir = "$env:ProgramFiles\Firebird" + $script:firebird_base_ver = "Firebird_" + $script:fbmajver + "_0" + + # ### FIXME - allow assigning a non-default dir + $script:FIREBIRD = "$script:firebirdrootdir\$script:firebird_base_ver" + + $script:uninstallexe = "${script:FIREBIRD}\unins000.exe" + + if ( ! $(Test-Path variable:run_timestamp) ) { + $script:run_timestamp = runtimestamp + } + + $script:install_inf_file = "${script:fbinstalllogdir}\${script:testname}-install-$script:FirebirdInstallVer-$script:run_timestamp-saved.inf" + $script:install_log_file = "$script:fbinstalllogdir\${script:testname}-install-$script:FirebirdInstallVer-$script:run_timestamp.log" + $script:uninstall_log_file = "$script:fbinstalllogdir\${script:testname}-uninstall-$script:FirebirdInstallVer-$script:run_timestamp.log" + $script:copy_install_target = "$script:fbinstallcopydir\$script:testname-install-$script:FirebirdInstallVer-$script:run_timestamp" + + $script:boiler_plate_install = " /DIR=`"$script:FIREBIRD`" /LOG=`"$script:install_log_file`" /SAVEINF=`"$script:install_inf_file`" " + $script:boiler_plate_uninstall = " /LOG=`"$script:uninstall_log_file`" " + + if ( $script:IsDebug ) { + # Set-PSDebug -Trace 0 + Get-ChildItem Variable: + Pause "In $($MyInvocation.MyCommand.Name) called from line $($MyInvocation.ScriptLineNumber)" + } + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" + +} + + +function check_innosetup_params() { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + if ( ! $script:dryrun ) { + $local:patharray = "$script:fbinstalllogdir", "$script:fbinstallcopydir" + foreach ($apath in $local:patharray) { + if ( check_file_exists "$apath" $true ) { + if ($? -eq $false) { mkdir -Path "$apath" } + } + } + } + + if ( $script:scripted ) { + $script:inno_verysilent = " /VERYSILENT " + $script:inno_sp = " /SP- " + $script:inno_nomsg = " /SUPPRESSMSGBOXES " + } + + + if ( $script:uninstall) { + if ( $script:realclean ) { $script:clean = $true } + } else { + + # check params for install + if ( $script:client_install) { + $script:task_list = "" + $script:inno_installtype = "ClientInstall" + $script:inno_devinst = "" + $script:inno_server_install = "" + $script:inno_classicserver = "" + $script:inno_superclassic = "" + $script:inno_superserver = "" + } + + if ( $script:dev_install) { + $script:task_list = "" + $script:inno_installtype = "DeveloperInstall" + $script:inno_client = "" + $script:inno_server_install = "" + $script:inno_classicserver = "" + $script:inno_superclassic = "" + $script:inno_superserver = "" + } + + # FIXME - CODE REVIEW REQUIRED + if ( $script:server_install ) { + + $script:inno_installtype = "ServerInstall" + $script:inno_client = "" + $script:inno_devinst = "" + + if ( $cscript:lassicserver ) { + $script:task_list = " UseClassicServerTask " + $script:inno_classicserver = 1 + $script:inno_superserver = "" + $script:inno_superclassic = "" + } else { + if ( $script:superclassic ) { + $script:task_list = " UseSuperClassicTask " + $script:inno_superserver = "" + $script:inno_classicserver = "" + $script:inno_superclassic = 1 + } else { + $script:task_list = " UseSuperServerTask " + $script:inno_superclassic = "" + $script:inno_classicserver = "" + $script:inno_superserver = 1 + } + } + + $script:inno_sysdbapassword = " /SYSDBAPASSWORD=`"$script:password`" " + + } # end if ( $server_install ) + + # Now start building our task list + + # At this stage, if task_list is not defined then we are not doing a server install + if ( $script:task_list ) { + if ( $script:apptask ) { + $script:task_list += ", UseApplicationTask " + $script:inno_installtype = "CustomInstall" + $script:inno_service_task = "" + } else { + $script:task_list += ", UseServiceTask " + } + + if ( ! $script:noautostart ) { + $script:task_list += ", AutoStartTask " + # $script:inno_installtype="CustomInstall" + } + + # ### FIXME - we need to integrate /MERGE_TASKS and use it here + if ( ! $script:nocopyfblib ) { + $script:task_list += ", CopyFbClientToSysTask " + # $script:inno_installtype="CustomInstall" + } + + if ( $script:copygdslib ) { + $script:task_list += ", CopyFbClientAsGds32Task" + $script:inno_installtype = "CustomInstall" + } + + if ( ! $(Test-Path variable:legacy_auth) ) { + $script:task_list += ", EnableLegacyClientAuth" + $script:inno_installtype = "CustomInstall" + } + } + + } # End check innosetup params for install + + spacer + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" +} + + +function clean_registry() { + + # Loop through HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall + # and search for "The Firebird Project" and uninstall all ms runtimes + + + return +} + + +function build_inno_cmd() { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + + # set up the command line variables we will use + + + + # ### Params shared by install and uninstall actions ### + + if ( $script:force ) { + $script:inno_params_from_cmdline += " /FORCE " + $script:uninst_cmdline += " /FORCE " + } + + if ( $script:inno_nomsg ) { + $script:inno_params_from_cmdline += $script:inno_nomsg + $script:uninst_cmdline += $script:inno_nomsg + } + + if ( $script:inno_sp ) { + $script:inno_params_from_cmdline += $script:inno_sp + $script:uninst_cmdline += $script:inno_sp + } + + if ( $script:inno_verysilent ) { + $script:inno_params_from_cmdline += $script:inno_verysilent + $script:uninst_cmdline += $script:inno_verysilent + } + + # ### Params used exclusively by the uninstall action ### + if ( $script:clean ) { + $script:uninst_cmdline += " /CLEAN " + } + + if ( $script:inno_silent ) { $script:inno_params_from_cmdline += " /SILENT " } + + if ( $script:nocancel ) { $script:inno_params_from_cmdline += " /NOCANCEL " } + + # ### Params used exclusively for install action ### + + if ( $script:install ) { + # Setting PASSWORD is only relevant for a server install + if ( $script:password -ne "masterkey" ) { + $script:inno_params_from_cmdline += " $script:inno_sysdbapassword " + $script:inno_installtype = "CustomInstall" + } + + if ( $script:inno_installtype -eq "CustomInstall" ) { + + if ( $script:client_install ) { $script:inno_components = "ClientComponent" } + if ( $script:dev_install ) { $script:inno_components = "DevAdminComponent,ClientComponent" } + if ( $script:server_install ) { $script:inno_components = "ServerComponent,DevAdminComponent,ClientComponent" } + + } else { + $script:inno_components = "ServerComponent,DevAdminComponent,ClientComponent" + } + + if ( $script:TASK_LIST ) { + $script:full_cmdline = " /TYPE=`"$script:inno_installtype`" /TASKS=`"$script:task_list`" /COMPONENTS=`"$script:inno_components`" $script:inno_params_from_cmdline " + } else { + $script:full_cmdline = "/TYPE=`"$script:inno_installtype`" /COMPONENTS=`"$script:inno_components`" $script:inno_params_from_cmdline " + } + } + + # Always add on the boiler plate log and inf output to the command + $script:full_cmdline += $script:boiler_plate_install + $script:uninst_cmdline += $script:boiler_plate_uninstall + + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" + +} + + +function dry_run( [string]$_action, [string]$_exec ) { + + Write-Output "Dry run - not executing $_action with $_exec" + +} + +function run_check_install() { + + + if ( $script:action | Select-String -Pattern "un" -SimpleMatch -Quiet ) { + $script:action = "check_uninstall" + Write-Output "Checking uninstallation..." + } else { + $script:action = "check_install" + Write-Output "Checking installation..." + } + # What is the most reliable way? + check_firebird_installed + + check_service_installed + check_server_sec_db + +} + +function run_installer() { + [OutputType([int])] + [cmdletbinding()] + Param() + begin { + Write-Debug "Entering function $($MyInvocation.MyCommand.Name)" + $local:retval = 0 + } + +# We use BEGIN..PROCESS..END here so that we can mask the output of copyinstall and +# allow the function to return an integer instean of an object. + process { + build_inno_cmd + print_vars "$script:action" + + if ( ! ( check_file_exists "$script:fbinst_exec" ) ) { + Write-Error "fbinst_exec does not exist. Quitting." + $local:retval = 1 + return + } + + Write-Verbose "Cmdline to execute is $script:fbinst_exec $script:full_cmdline" + + if ( $dryrun ) { + dry_run $script:action $script:fbinst_exec + } else { + + $errorActionPreference = "Stop" + $env:SEE_MASK_NOZONECHECKS = 1 + + $local:retval = Invoke-Command "$script:fbinst_exec" "$script:full_cmdline" "Running Firebird Installer" + + if ( $local:retval -ne 0 ) { + iss_error ( $local:retval ) + } else { + Write-Verbose "Completed Firebird Installation" + + if ( ! $script:noarchive ) { + # Assign output to null here or else returned $local:retval below becomes an object, not an int + $null = copy_install + + } + } + } + } + end { + Write-Debug "Leaving function $($MyInvocation.MyCommand.Name)" + return $local:retval + } +} + + +function run_uninstaller() { + + $script:action = "uninstall" + build_inno_cmd + print_vars "$script:action" + + Write-Verbose "uninst_cmdline is $script:uninst_cmdline" + + if ( $dryrun ) { + dry_run $script:action $script:uninstallexe + } else { + + $local:retval = check_file_exists "$script:uninstallexe" + if ( ! $local:retval ) { + Write-Output "$script:uninstallexe does not exist. Quitting." + Write-Output "" + return #$local:retval + } + + $errorActionPreference = "Stop" + $local:retval = Invoke-Command "$script:uninstallexe" "$script:uninst_cmdline" "UnInstalling Firebird" + if ( $local:retval -ne 0 ) { + iss_error ( $local:retval ) + } else { + Write-Verbose "Firebird should now be uninstalled" + + run_check_install + + } + + # Copy uninstall log to copy_install_target if it exists. + if ( Test-Path -Path $script:copy_install_target ) { + if ( Test-Path $script:uninstall_log_file -PathType leaf ) { + Copy-Item -Path $script:uninstall_log_file -Destination $script:copy_install_target | Out-Null + } + } + + } + + # return $local:retval + +} +function run_cleanup() { + + if ( $script:dryrun ) { + Write-Output "Dry run - not executing $($MyInvocation.MyCommand.Name )" + Write-Output "Not uninstalling Firebird" + Write-Output "Not deleting the $env:firebirdrootdir\$env:firebird_base_ver dir" + Write-Output "Not removing the list of firebird shared dll's in the registry." + Write-Output "" + } else { + Write-Verbose "Cleaning up existing Firebird installation" + run_uninstaller + + if ( $script:realclean ) { + $local:retval = check_file_exists $script:firebirdrootdir\$script:firebird_base_ver dir $true + if ( $local:retval ) { + Write-Verbose "Removing all files in $script:firebirdrootdir\$script:firebird_base_ver dir" + Remove-Item "$script:firebirdrootdir\$script:firebird_base_ver" -Recurse -Include "*.*" -Confirm + } + Write-Verbose "Removing fbclient and gds32 from $env:SystemRoot\System32" + Remove-Item "$env:SystemRoot\System32" -Include "fbclient.dll", "gds32.dll" -Confirm + Write-Verbose "Removing fbclient and gds32 from $env:SystemRoot\SysWOW64" + Remove-Item "$env:SystemRoot\SysWOW64" -Include "fbclient.dll", "gds32.dll" -Confirm + + Write-Verbose "Clean up listing of Shared DLLs in registry" + $RegKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs" + Remove-ItemProperty HKLM:$RegKey -Name "C:\Program\*.*" -Confirm + Remove-ItemProperty HKLM:$RegKey -Name "${script:firebirdrootdir}\${script:firebird_base_ver}\*.*" -Confirm + Remove-ItemProperty HKLM:$RegKey -Name "*\fbclient.dll" -Confirm + Remove-ItemProperty HKLM:$RegKey -Name "*\gds32.dll" -Confirm + } + Write-Verbose "Completed cleanup of Firebird installation" + } + +} + + +function iss_error( [Int32]$_err_code = 0 ) { + + switch ($_err_code) { + 1 { Write-Output "Setup failed to initialize." } + 2 { + Write-Output "The user clicked Cancel in the wizard before the actual installation + started, or chose 'No' on the opening 'This will install...' message box." + } + 3 { + Write-Output "A fatal error occurred while preparing to move to the next + installation phase (for example, from displaying the pre-installation + wizard pages to the actual installation process). This should never + happen except under the most unusual of circumstances, such as + running out of memory or Windows resources." + } + 4 { Write-Output "A fatal error occurred during the actual installation process." } + 5 { + Write-Output "The user clicked Cancel during the actual installation process, + or chose Abort at an Abort-Retry-Ignore box." + } + 6 { + Write-Output "The Setup process was forcefully terminated by the debugger + (Run | Terminate was used in the Compiler IDE)." + } + 7 { + Write-Output "The Preparing to Install stage determined that Setup cannot proceed + with installation. (First introduced in Inno Setup 5.4.1.)" + } + 8 { + Write-Output "The Preparing to Install stage determined that Setup cannot proceed + with installation, and that the system needs to be restarted in + order to correct the problem. (First introduced in Inno Setup 5.4.1.)" + } + Default {} + } + +} + +function main() { + begin{ +# $script:DebugPreference = 'Continue' +# $script:VerbosePreference = 'Continue' + + Set-StrictMode -Version 3.0 + } + + process { + if ( $script:help ) { + show-help + } else { + prompt + spacer + check_params + check_environment + check_innosetup_params + + switch ($script:action) { + "realclean" { run_cleanup } + "check_install" { run_check_install } + "uninstall" { run_uninstaller } + "check_uninstall" { run_check_install } + Default { + $local:retval = $( run_installer | Select-Object -Last 1 ) + if ( $local:retval -ne 0 ) { + Write-Error "run_installer returned $local:retval" + return + } + run_check_install + if ( ! $script:nouninstall ) { + run_uninstaller + } + } + } + } + } + + end{ + spacer " Finished " + + # this attempt to 'reset' the prompt fails :-( + #prompt -reset + + } +} + +main $args + diff --git a/builds/install/arch-specific/win32/uninstall_service.bat b/builds/install/arch-specific/win32/uninstall_service.bat index c9375ca8657..8e53d399dd7 100644 --- a/builds/install/arch-specific/win32/uninstall_service.bat +++ b/builds/install/arch-specific/win32/uninstall_service.bat @@ -2,7 +2,7 @@ setlocal set REMOVE_SERVICE=remove -z set STOP_SERVICE=stop -if not "%1"=="" ( +if not "%~1"=="" ( set STOP_SERVICE=%STOP_SERVICE% -n %1 set REMOVE_SERVICE=%REMOVE_SERVICE% -n %1 ) @@ -10,4 +10,4 @@ instsvc %STOP_SERVICE% instsvc %REMOVE_SERVICE% endlocal -if "%1"=="" (instreg remove -z) +if "%~1"=="" (instreg remove -z) diff --git a/builds/install/misc/firebird.conf b/builds/install/misc/firebird.conf index dd99340588b..a2746a47908 100644 --- a/builds/install/misc/firebird.conf +++ b/builds/install/misc/firebird.conf @@ -102,7 +102,7 @@ # provide ';'-separated trees list, where database files are stored. # Relative paths are treated relative to the root directory of firebird. # Default value 'Full' gives full access to all files on your site. -# To specify access to specific trees, enum all required paths +# To specify access to specific trees, enum all required paths # (for Windows this may be something like 'C:\DataBase;D:\Mirror', # for unix - '/db;/mnt/mirrordb'). If you choose 'None', then only # databases listed in databases.conf can be attached. @@ -149,7 +149,7 @@ # # ExternalFileAccess may be None, Full or Restrict. If you choose # Restrict, provide ';'-separated trees list, where external files -# are stored. Relative paths are treated relative to the root directory +# are stored. Relative paths are treated relative to the root directory # of firebird. Default value 'None' disables any use of external files # on your site. To specify access to specific trees, enum all required # paths (for Windows this may be something like 'C:\ExternalTables', @@ -173,7 +173,7 @@ # # UdfAccess may be None, Full or Restrict. If you choose # Restrict, provide ';'-separated trees list, where UDF libraries -# are stored. Relative paths are treated relative to the root directory +# are stored. Relative paths are treated relative to the root directory # of firebird. # # Since FB4.0 default value is None. Set it to 'Restrict UDF' to have @@ -196,8 +196,8 @@ # # Provide ';'-separated trees list, where temporary files are stored. # Relative paths are treated relative to the root directory of firebird. -# Default value is determined using FIREBIRD_TMP, TEMP or TMP -# environment options. Once the first specified directory has no +# Default value is determined using FIREBIRD_TMP, TEMP or TMP +# environment options. Once the first specified directory has no # available space, the engine will switch to the next one, and so on. # # E.g.: @@ -234,7 +234,7 @@ # ---------------------------- # Maximum summary size of each user trace session's log files in MB. -# When log files size reach this limit, trace session automatically +# When log files size reach this limit, trace session automatically # suspends until interactive user service read and delete some log files. # # Type: integer @@ -261,10 +261,10 @@ # Disk space preallocation # # Sets the amount of preallocated disk space in bytes. Disk space -# preallocation allows to reduce physical file fragmentation and to make +# preallocation allows to reduce physical file fragmentation and to make # database work in out of disk space condition. With preallocation enabled, -# engine allocates 1/16nth of already allocated disk space at a time but -# not less than 128KB and no more than DatabaseGrowthIncrement (128MB by +# engine allocates 1/16nth of already allocated disk space at a time but +# not less than 128KB and no more than DatabaseGrowthIncrement (128MB by # default). To disable preallocation set DatabaseGrowthIncrement to zero. # Shadow database files are not preallocated. # @@ -278,7 +278,7 @@ # File system cache usage # # Determines whether Firebird will use file system cache for database files or -# not. +# not. # # Type: boolean # @@ -290,21 +290,21 @@ # File system cache threshold # # The threshold value that determines whether Firebird will use file system -# cache or not. File system caching is used if database cache size in pages +# cache or not. File system caching is used if database cache size in pages # (configured explicitly in database header or via DefaultDbCachePages setting) # is less than FileSystemCacheThreshold value. # # To use file system cache always set FileSystemCacheThreshold to a large value. -# To bypass file system cache for all databases set FileSystemCacheThreshold to +# To bypass file system cache for all databases set FileSystemCacheThreshold to # zero. -# +# # CAUTION! # This setting is deprecated and will be removed in future Firebird versions. # Consider using "UseFileSystemCache" setting instead. -# If "UseFileSystemCache" is set, then value of "FileSystemCacheThreshold" is +# If "UseFileSystemCache" is set, then value of "FileSystemCacheThreshold" is # ignored. -# If "UseFileSystemCache" is not set, and "FileSystemCacheThreshold" is set -# then value of "FileSystemCacheThreshold" is in use and accounted by the +# If "UseFileSystemCache" is not set, and "FileSystemCacheThreshold" is set +# then value of "FileSystemCacheThreshold" is in use and accounted by the # engine. # # Type: integer, measured in database pages @@ -333,7 +333,7 @@ # Security note # To adjust the setting engine needs SeIncreaseQuotaPrivilege right. Built-in # service accounts and administrators have it by default. Installer grants this -# right to Firebird service account. If the engine fails to adjust the cache +# right to Firebird service account. If the engine fails to adjust the cache # size setting it will log warning message to the firebird.log and continue. # # Type: integer, measured in % of total physical RAM @@ -375,7 +375,7 @@ # # The situation for SMB/CIFS is quite similar to NFS with not all configurations # providing file locking mechanisms needed for safe operation. Using SuperServer -# engine with the database on NT file server may be considered relatively safe +# engine with the database on NT file server may be considered relatively safe # as file locking protects the database from being used by the several engines. # Network stack can still change order of writes so you may get a corrupted # database in case of network errors or power outage. @@ -500,7 +500,7 @@ # # UserManager sets plugin used to work with security database. If more than -# one plugin is given, first plugin from the list is used by default. If you +# one plugin is given, first plugin from the list is used by default. If you # need to manage legacy logins using legacy tools set it to Legacy_UserManager. # Other managers may be chosen in create/alter/drop user commands. # @@ -514,14 +514,14 @@ #TracePlugin = fbtrace # Wire crypt plugins are used to crypt data transferred over the wire. -# In default case wire is encrypted using ChaCha#20 or Alleged RC4. -# Key must be generated by auth plugin. +# In default case wire is encrypted using ChaCha#20 (32/64 bit counter variants) +# or Alleged RC4. Key must be generated by auth plugin. # For chacha we are using 16 or 32 bytes key (depends upon what is provided -# by auth plugin), 12 bytes nonce and 4 bytes counter, 20 (10 + 10) rounds are made. +# by auth plugin), 12 (8) bytes nonce and 4 (8) bytes counter, 20 (10 + 10) rounds are made. # # Per-connection configurable. # -#WireCryptPlugin = ChaCha, Arc4 +#WireCryptPlugin = ChaCha64, ChaCha, Arc4 # Key holder is a kind of temp storage for DB crypt keys. # There is no default for this kind of plugins. @@ -612,6 +612,18 @@ #ConnectionIdleTimeout = 0 +# ---------------------------- +# +# Set number of seconds after which ON DISCONNECT trigger execution will be +# automatically cancelled by the engine. Zero means no timeout is set. +# +# Per-database configurable. +# +# Type: integer +# +#OnDisconnectTriggerTimeout = 180 + + # ---------------------------- # # How often the pages are flushed on disk @@ -658,12 +670,12 @@ # ---------------------------- -# How COMMIT\ROLLBACK RETAINING handle GLOBAL TEMPORARY TABLE ON COMMIT DELETE ROWS +# How COMMIT\ROLLBACK RETAINING handle GLOBAL TEMPORARY TABLE ON COMMIT DELETE ROWS # # GLOBAL TEMPORARY TABLE ON COMMIT DELETE ROWS (GTT) data is cleared on "hard" -# commit (rollback) but should be preserved on commit(rollback) retaining. +# commit (rollback) but should be preserved on commit(rollback) retaining. # Due to bug in initial implementation in Firebird 2.1 that data is not visible -# for the application. This setting allows to preserve backward compatibility +# for the application. This setting allows to preserve backward compatibility # (i.e. clear GTT data on commit\rollback retaining). # Value of 0 makes engine to not clear GTT data on commit\rollback retaining and # let application to see it. @@ -682,20 +694,20 @@ # # Since Firebird 2.0, strict alias checking rules were implemented in the SQL # parser to accord with the SQL standard requirements. This setting allows -# these rules to be relaxed in order to allow legacy applications to run on +# these rules to be relaxed in order to allow legacy applications to run on # Firebird 2.0. -# A setting of 1 (true) allows the parser to resolve a qualified column reference +# A setting of 1 (true) allows the parser to resolve a qualified column reference # using the relation name, where an alias has been specified for that relation. # # For example, it allows a query such as: # SELECT TABLE.X FROM TABLE A # -# It is not recommended to enable this setting. It should be regarded as an -# interim workaround for porting untidy legacy code, until it is practicable to -# revise such code. -# +# It is not recommended to enable this setting. It should be regarded as an +# interim workaround for porting untidy legacy code, until it is practicable to +# revise such code. +# # CAUTION! -# There is no guarantee that this setting will be available in future Firebird +# There is no guarantee that this setting will be available in future Firebird # versions. # # Type: boolean @@ -741,7 +753,7 @@ # Should connection over the wire be encrypted? # Has 3 different values: Required, Enabled or Disabled. Enabled behavior # depends on the other side's requirements. If both sides are set to Enabled, -# the connection is encrypted when possible. Note that Wirecrypt should be set +# the connection is encrypted when possible. Note that Wirecrypt should be set # to Enabled when running a Firebird server with legacy authentication. # # Attention: default depends upon connection type: incoming (server) @@ -768,8 +780,8 @@ # Seconds to wait on a silent client connection before the server sends # dummy packets to request acknowledgment. # -# NOTE. This option may hang or crash Windows NT4 or Windows 2000 pre SP3 -# on the client side as explained here: +# NOTE. This option may hang or crash Windows NT4 or Windows 2000 pre SP3 +# on the client side as explained here: # http://support.microsoft.com/default.aspx?kbid=296265. # or may not prevent eventual inactive client disconnection for other OS. # @@ -801,7 +813,8 @@ # # If empty, the default is the OS time zone. # When set in the server, it defines the default session time zone for attachments. -# When set in the client, it defines the default time zone used with client-side API functions. +# When set in the client, it defines the default time zone used with client-side API functions and +# the default value of isc_dpb_session_time_zone. # # Type: string # @@ -830,7 +843,7 @@ # messages. The value of 0 (Zero) means that the server will choose # a port number randomly. # -# Per-connection configurable. +# Per-database configurable. # # Type: integer # @@ -862,9 +875,12 @@ # Either enables or disables the "TCP Loopback Fast Path" feature (SIO_LOOPBACK_FAST_PATH). # Applies to Windows (version 8/2012 or higher) only. # -# Type: Boolean, default 1 (true) +# Note: Microsoft has deprecated it and not recommended to use anymore. +# To be removed in future Firebird versions. +# +# Type: Boolean, default 0 (false) # -#TcpLoopbackFastPath = 1 +#TcpLoopbackFastPath = 0 # # Allows setting of IPV6_V6ONLY socket option. If enabled, IPv6 sockets @@ -959,7 +975,7 @@ # Bytes of shared memory allocated for each block of TIP cache. # The reason to reduce this value is if you have small TIP and # want to conserve some memory. The reason to increase this -# value is if you need very large cache and approach limits +# value is if you need very large cache and approach limits # on kernel objects allocated for each block (files, mutexes, etc). # Each cached transaction uses 8 bytes of memory. # @@ -1093,6 +1109,26 @@ # #RemotePipeName = interbas +# ---------------------------- +# The way of how to create names for named Windows kernel objects, such as +# events, memory mapped files, etc. Since v4.0.3 Firebird creates its named +# kernel objects in private namespace. It allows to interact processes within +# different Windows sessions, such as user session and system session. Also, +# it uses engine version in some shared event names - it allows single process +# to host Firebird engines of different versions. +# +# The legacy names is for backward compatibility only, it allows simultaneous +# run of Firebird processes of newly (>= v4.0.3) and older (< 4.0.3) +# subreleases of version 4. +# +# The setting is global. +# It is used for backward compatibility only and will not be present in the +# future Firebird versions. +# +# Type: boolean +# +#UseLegacyKernelObjectsNames = false + # ============================ # Settings for Unix/Linux platforms @@ -1147,7 +1183,7 @@ #ServerMode = Super # ============================ -# Settings of External Connections Pool +# Settings of External Connections Pool # ============================ # Set the maximum number of inactive (idle) external connections to retain at diff --git a/builds/install/misc/plugins.conf b/builds/install/misc/plugins.conf index aad0df450fb..95e9d8dd7b7 100644 --- a/builds/install/misc/plugins.conf +++ b/builds/install/misc/plugins.conf @@ -6,3 +6,7 @@ Plugin = UDR { Config = UDR_config { path = $(dir_plugins)/udr } + +Plugin = ChaCha64 { + Module = $(dir_plugins)/ChaCha +} diff --git a/builds/install/posix-common/posixLibrary.sh.in b/builds/install/posix-common/posixLibrary.sh.in index f499f93e5a8..d1f1e5ea9e8 100644 --- a/builds/install/posix-common/posixLibrary.sh.in +++ b/builds/install/posix-common/posixLibrary.sh.in @@ -211,8 +211,11 @@ missingLibrary() { # Check library presence, errorexit when missing checkLibrary() { - libName=${1} - haveLibrary $libName || missingLibrary $libName + libList=${1} + for libName in $libList + do + haveLibrary $libName || missingLibrary $libName + done } diff --git a/builds/make.new/config/install-sh b/builds/make.new/config/install-sh index 8175c640fe6..ec298b53740 100755 --- a/builds/make.new/config/install-sh +++ b/builds/make.new/config/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2018-03-11.20; # UTC +scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -69,6 +69,11 @@ posix_mkdir= # Desired mode of installed file. mode=0755 +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= @@ -99,18 +104,28 @@ Options: --version display version info and exit. -c (ignored) - -C install only if different (preserve the last data modification time) + -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do @@ -137,8 +152,13 @@ while test $# -ne 0; do -o) chowncmd="$chownprog $2" shift;; + -p) cpprog="$cpprog -p";; + -s) stripcmd=$stripprog;; + -S) backupsuffix="$2" + shift;; + -t) is_target_a_directory=always dst_arg=$2 @@ -255,6 +275,10 @@ do dstdir=$dst test -d "$dstdir" dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command @@ -301,22 +325,6 @@ do if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then @@ -326,52 +334,49 @@ do fi posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - # Note that $RANDOM variable is not portable (e.g. dash); Use it - # here however when possible just to lower collision chance. - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - - trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 - - # Because "mkdir -p" follows existing symlinks and we likely work - # directly in world-writeable /tmp, make sure that the '$tmpdir' - # directory is successfully created first before we actually test - # 'mkdir -p' feature. - if (umask $mkdir_umask && - $mkdirprog $mkdir_mode "$tmpdir" && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - test_tmpdir="$tmpdir/a" - ls_ld_tmpdir=`ls -ld "$test_tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null - fi - trap '' 0;; - esac;; + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null + fi + trap '' 0;; esac if @@ -382,7 +387,7 @@ do then : else - # The umask is ridiculous, or mkdir does not conform to POSIX, + # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. @@ -411,7 +416,7 @@ do prefixes= else if $posix_mkdir; then - (umask=$mkdir_umask && + (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 @@ -451,7 +456,18 @@ do trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # @@ -477,6 +493,13 @@ do then rm -f "$dsttmp" else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || @@ -491,9 +514,9 @@ do # file should still install successfully. { test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || + $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 diff --git a/builds/posix/Makefile.in b/builds/posix/Makefile.in index bb4ceb12fb8..3374981768c 100644 --- a/builds/posix/Makefile.in +++ b/builds/posix/Makefile.in @@ -75,7 +75,12 @@ ifndef GCC endif ifeq ($(TOMMATH_BUILD_FLG),Y) -TOM2TOM_FLAGS=-I../libtommath +TOM2TOM_CFLAGS=-I../libtommath +ifeq ($(PLATFORM),DARWIN) +LTC_LDFLAGS='-L$(LIB) $(call LINK_DARWIN_RPATH,..)' +else +LTC_LDFLAGS='-L$(LIB) $(subst $,$$$$,$(call LIB_LINK_RPATH,lib))' +endif endif .PHONY: master_process cross_process firebird Debug Release external @@ -110,6 +115,7 @@ PAS_ROOT=$(MISC)/pascal PASCAL_SOURCES=$(wildcard $(PAS_ROOT)/*) TMP_FUNCS=$(TMP_ROOT)/func.pas XPB_CONSTS=$(SRC_ROOT)/include/firebird/impl/consts_pub.h +INF_CONSTS=$(SRC_ROOT)/include/firebird/impl/inf_pub.h ERR_CONSTS=$(ROOT)/lang_helpers/gds_codes.pas RPL_AWK=$(GEN_ROOT)/def_awk RPL_AWK_SRC=$(MISC)/def_awk.c @@ -137,9 +143,10 @@ $(RPL_AWK): $(RPL_AWK_SRC) $(RPL_GREP): $(RPL_GREP_SRC) $(CC) -o $@ $^ -$(TMP_FUNCS): $(PASCAL_SOURCES) $(XPB_CONSTS) $(ERR_CONSTS) $(RPL_AWK) $(RPL_GREP) +$(TMP_FUNCS): $(PASCAL_SOURCES) $(XPB_CONSTS) $(INF_CONSTS) $(ERR_CONSTS) $(RPL_AWK) $(RPL_GREP) cp $(PAS_ROOT)/fb_get_master_interface.pas $(TMP_FUNCS) $(RPL_AWK) <$(XPB_CONSTS) >>$(TMP_FUNCS) + $(RPL_AWK) <$(INF_CONSTS) >>$(TMP_FUNCS) $(RPL_GREP) <$(ERR_CONSTS) >>$(TMP_FUNCS) $(API_PAS_FILE): $(IDL_FILE) $(PASCAL_SOURCES) $(TMP_FUNCS) @@ -170,8 +177,15 @@ external: $(MAKE) -C $(ROOT)/extern/decNumber ln -sf $(ROOT)/extern/decNumber/libdecFloat.a $(LIB) +ifeq ($(ABSEIL_BUILD_FLG),Y) + $(MAKE) -C $(ROOT)/extern/int128/absl/numeric + ln -sf $(ROOT)/extern/int128/absl/numeric/libi128.a $(LIB) +endif + +ifeq ($(RE2_BUILD_FLG),Y) CXXFLAGS="-O3 -g -fPIC" $(MAKE) -C $(ROOT)/extern/re2 ln -sf $(ROOT)/extern/re2/obj/libre2.a $(LIB) +endif ifeq ($(TOMMATH_BUILD_FLG),Y) CFLAGS="$(CFLAGS)" $(MAKE) -C $(ROOT)/extern/libtommath -f makefile.shared GCC=$(GCC) @@ -186,7 +200,7 @@ endif endif ifeq ($(TOMCRYPT_BUILD_FLG),Y) - CFLAGS="$(CFLAGS) $(TOM2TOM_FLAGS)" $(MAKE) -C $(ROOT)/extern/libtomcrypt -f makefile.shared GCC=$(GCC) + CFLAGS="$(CFLAGS) $(TOM2TOM_CFLAGS)" $(MAKE) -C $(ROOT)/extern/libtomcrypt -f makefile.shared GCC=$(GCC) LTC_LDFLAGS=$(LTC_LDFLAGS) ifeq ($(PLATFORM),DARWIN) install_name_tool -id "@rpath/lib/libtomcrypt.dylib" $(TOMCRYPT)/.libs/libtomcrypt.1.dylib @@ -328,6 +342,8 @@ cross2: $(MAKE) re2 $(MAKE) -C $(ROOT)/extern/decNumber ln -sf $(ROOT)/extern/decNumber/libdecFloat$(CROSS).a $(LIB) + $(MAKE) -C $(ROOT)/extern/int128/absl/numeric + ln -sf $(ROOT)/extern/int128/absl/numeric/libi128$(CROSS).a $(LIB) $(MAKE) yvalve $(MAKE) engine $(MAKE) fbintl @@ -410,7 +426,7 @@ $(LIBFBINTL_SO): $(INTL_Objects) $(COMMON_LIB) gpre: $(GPRE) databases $(GPRE): $(GPRE_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) HELP_FDB = $(FIREBIRD)/help/help.fdb SECURITY_FDB = $(FIREBIRD)/security4.fdb @@ -484,62 +500,62 @@ utilities: firebird_server fb_lock_print fbguard fbsvcmgr fbtracemgr gbak gfix g firebird_server: $(FB_DAEMON) $(FB_DAEMON): $(Remote_Server_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) fb_lock_print: $(LOCKPRINT) $(LOCKPRINT): $(LOCKPRINT_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) fbguard: $(FBGUARD) $(FBGUARD): $(FBGUARD_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) fbsvcmgr: $(FBSVCMGR) $(FBSVCMGR): $(FBSVCMGR_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) fbtracemgr: $(FBTRACEMGR) $(FBTRACEMGR): $(FBTRACEMGR_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gbak: $(GBAK) $(GBAK): $(GBAK_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gsplit: $(GSPLIT) $(GSPLIT): $(GSPLIT_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gfix: $(GFIX) $(GFIX): $(GFIX_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gsec: $(GSEC) $(GSEC): $(GSEC_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gstat: $(GSTAT) $(GSTAT): $(GSTAT_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) isql: $(ISQL) $(ISQL): $(ISQL_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LIBEDITLINE) $(TERMLIB) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LIBEDITLINE) $(TERMLIB) $(LINK_LIBS) nbackup: $(NBACKUP) $(NBACKUP): $(NBACKUP_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) #___________________________________________________________________________ @@ -630,7 +646,7 @@ gen_codes: $(CODES) msg.timestamp $(CODES) $(SRC_ROOT)/include/gen $(LNG_ROOT) $(CODES): $(CODES_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) #___________________________________________________________________________ # all the rest we need to build @@ -650,7 +666,7 @@ cross_rest: qli gbak_files qli: $(QLI) $(QLI): $(QLI_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) examples: include_generic $(MAKE) -f Makefile.examples -C $(GEN_ROOT)/examples/ @@ -664,13 +680,12 @@ $(FIREBIRD_MSG): $(BUILD_FILE) msg.timestamp tzdata: $(FIREBIRD)/tzdata -# FIXME: For big-endian, be.zip must be used. -$(FIREBIRD)/tzdata: $(ROOT)/extern/icu/tzdata/le.zip +$(FIREBIRD)/tzdata: $(ROOT)/extern/icu/tzdata/$(TZDATA_ZIP) mkdir -p $(FIREBIRD)/tzdata - unzip -o $(ROOT)/extern/icu/tzdata/le.zip -d $(FIREBIRD)/tzdata + unzip -o $(ROOT)/extern/icu/tzdata/$(TZDATA_ZIP) -d $(FIREBIRD)/tzdata $(BUILD_FILE): $(BUILD_Objects) $(COMMON_LIB) - $(EXE_LINK) $(EXE_LINK_OPTIONS) $(LSB_UNDEF) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) $(call LINK_DARWIN_RPATH,..) + $(EXE_LINK) $(EXE_LINK_OPTIONS) $(LSB_UNDEF) $^ -o $@ $(FIREBIRD_LIBRARY_LINK) $(LINK_LIBS) gbak_files: $(GBAK_FILES) @@ -738,12 +753,12 @@ install install-embedded silent_install package packages dist: # .PHONY: clean clean_objects clean_dependancies clean_extern_objects clean_build \ clean_gpre_gen clean_icu clean_dbs clean_examples clean_makefiles \ - clean_editline clean_all clean_decfloat clean_vers clean_misc + clean_editline clean_all clean_decfloat clean_int128 clean_vers clean_misc clean: clean_objects clean_dependancies clean_extern_objects clean_build \ clean_yacc_gen clean_gpre_gen clean_dbs clean_examples clean_tommath \ - clean_tomcrypt clean_decfloat clean_vers clean_misc + clean_tomcrypt clean_decfloat clean_int128 clean_vers clean_misc clean_vers: $(RM) *.vers @@ -797,6 +812,9 @@ clean_tomcrypt: clean_decfloat: -$(MAKE) -C $(ROOT)/extern/decNumber clean +clean_int128: + -$(MAKE) -C $(ROOT)/extern/int128/absl/numeric clean + clean_objects: $(RM) `find $(TMP_ROOT)/ -type f -name '*.o' -print` $(RM) `find $(TMP_ROOT)/ -type f -name '*.a' -print` diff --git a/builds/posix/Makefile.in.examples b/builds/posix/Makefile.in.examples index 8fb0b9e8410..228e238b6c3 100644 --- a/builds/posix/Makefile.in.examples +++ b/builds/posix/Makefile.in.examples @@ -60,6 +60,7 @@ export PATH GPRE_FLAGS= -m -z -n LIB_LINK_RPATH = $(call LIB_PLATFORM_RPATH,$(if $(subst intl,,$(1)),$(LIB),$(LIB)/../intl)) +LINK_DARWIN_RPATH = -Wl,-rpath,@loader_path/../$(TARGET)/firebird LIB_LINK_MAPFILE = EXAMPLES_DEST= $(GEN_ROOT)/examples @@ -115,6 +116,9 @@ $(EXAMPLES_FB)/README: $(CP) $(ROOT)/examples/stat/*.* $(EXAMPLES_FB)/stat/ $(CP) $(ROOT)/examples/udf/*.* $(EXAMPLES_FB)/udf/ $(CP) $(ROOT)/examples/udr/*.* $(EXAMPLES_FB)/udr/ + $(CP) $(ROOT)/examples/object_pascal/*.* $(EXAMPLES_FB)/object_pascal/ + $(CP) $(ROOT)/examples/object_pascal/[mM]ake* $(EXAMPLES_FB)/object_pascal/ + $(CP) $(ROOT)/examples/object_pascal/common/*.* $(EXAMPLES_FB)/object_pascal/common/ # $(CP) intlemp.fdb $(EXAMPLES_FB)/empbuild/ $(CP) $(ROOT)/examples/readme $(EXAMPLES_FB)/README $(CP) $(ROOT)/examples/empbuild/employe2.sql $(EXAMPLES_FB)/empbuild/ diff --git a/builds/posix/make.android.arm64 b/builds/posix/make.android.arm64 index 79fbb90c2e6..ff0d8d85ff4 100644 --- a/builds/posix/make.android.arm64 +++ b/builds/posix/make.android.arm64 @@ -41,7 +41,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) CROSS_CONFIG=android.arm64 LDFLAGS += --sysroot=$(CROSS_SYSROOT) -static-libstdc++ -DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) +DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) LINK_LIBS = $(DroidLibs) STATICLINK_LIBS = $(DroidLibs) diff --git a/builds/posix/make.android.arme b/builds/posix/make.android.arme index c7233d0191b..b6ae33587d6 100644 --- a/builds/posix/make.android.arme +++ b/builds/posix/make.android.arme @@ -40,7 +40,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS) CROSS_CONFIG=android.arme LDFLAGS += --sysroot=$(CROSS_PLATFORM) -static-libstdc++ -DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) +DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) UDR_SUPPORT_LIBS := LINK_LIBS = $(DroidLibs) diff --git a/builds/posix/make.defaults b/builds/posix/make.defaults index 6dfd3ab118d..7361efc5302 100755 --- a/builds/posix/make.defaults +++ b/builds/posix/make.defaults @@ -50,6 +50,7 @@ EXA_ROOT=$(ROOT)/examples IsCross=@IS_CROSS@ TOMMATH_BUILD_FLG=@TOMMATH_BUILD@ TOMCRYPT_BUILD_FLG=@TOMCRYPT_BUILD@ +RE2_BUILD_FLG=@RE2_BUILD@ FB_BUILD=$(GEN_ROOT)/$(TARGET)/firebird ifeq ($(IsCross), Y) @@ -102,14 +103,15 @@ GLOB_OPTIONS:= #____________________________________________________________________________ -# Global c++ flags: firebird needs no RTTI, choose build standard -PLUSPLUS_FLAGS:= -fno-rtti -std=c++11 +# Global c++ flags: firebird needs no RTTI, choose build standard, make it build with icu-76.1 +PLUSPLUS_FLAGS:= -fno-rtti -std=c++11 -DU_SHOW_CPLUSPLUS_API=0 -DU_SHOW_CPLUSPLUS_HEADER_API=0 # If this is defined then we use special rules useful for developers only IsDeveloper = @DEVEL_FLG@ CpuType=@CPU_TYPE@ PLATFORM=@PLATFORM@ +TZDATA_ZIP=@TZDATA_ZIP@ SFIO_EXAMPLES=@SFIO_EXAMPLES@ # link with readline libraries - set by configure @@ -131,10 +133,18 @@ ATOMIC_OPTIONS=@ATOMIC_OPTIONS@ # needed at least for solaris inline assembly routines CAS_OPTIONS=@CAS_OPTIONS@ +# BigEndian int128 support +ABSEIL_BUILD_FLG = @ABSEIL_BUILD_FLG@ + # multiple-precision integer library MATHLIB=@MATHLIB@ DECLIB=-ldecFloat$(CROSS) RE2LIB=-lre2 +ifeq ($(ABSEIL_BUILD_FLG), Y) + I128LIB=-li128$(CROSS) +else + I128LIB= +endif # crypt library CRYPTLIB=@CRYPTLIB@ @@ -190,8 +200,8 @@ endif STATICLIB_LINK = $(AR) crus STATICEXE_LINK = $(CXX) $(GLOB_OPTIONS) $(CXXFLAGS) -static-libstdc++ -LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) -SO_LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) +LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB) +SO_LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB) # Default extensions @@ -315,7 +325,7 @@ ifeq (@USE_RPATH@,1) ifeq ($(strip @BINRELOC_CFLAGS@),) LIB_LINK_RPATH = $(call LIB_PLATFORM_RPATH,$(if $(subst intl,,$(1)),@FB_LIBDIR@,@FB_INTLDIR@)) else - LIB_LINK_RPATH = $(call LIB_PLATFORM_RPATH,'$$ORIGIN/../$(1)') + LIB_LINK_RPATH = $(call LIB_PLATFORM_RPATH,\$$ORIGIN/../$(1)) endif else LIB_LINK_RPATH = @@ -335,7 +345,7 @@ LIB_LINK_SONAME= -Wl,-soname,$(1) LIB_LINK_MAPFILE= -Wl,--version-script,$(1) FIREBIRD_LIBRARY_LINK= -L$(LIB) -lfbclient $(MATHLIB) $(CRYPTLIB) -EXE_LINK_OPTIONS= $(LDFLAGS) $(THR_FLAGS) $(UNDEF_FLAGS) $(LIB_PATH_OPTS) $(LINK_EMPTY_SYMBOLS) +EXE_LINK_OPTIONS= $(LDFLAGS) $(THR_FLAGS) $(UNDEF_FLAGS) $(LIB_PATH_OPTS) $(call LINK_DARWIN_RPATH,..) $(LINK_EMPTY_SYMBOLS) LIB_LINK_OPTIONS= $(LDFLAGS) $(THR_FLAGS) -shared FB_DAEMON = $(BIN)/firebird$(EXEC_EXT) @@ -418,7 +428,6 @@ GPRE = $(BIN)/gpre$(EXEC_EXT) RUN_GPRE = $(RBIN)/gpre$(EXEC_EXT) GPRE_CURRENT = $(RBIN)/gpre_current$(EXEC_EXT) - # From msgs CHECK_MESSAGES = $(BIN)/check_messages$(EXEC_EXT) BUILD_FILE = $(BIN)/build_file$(EXEC_EXT) @@ -432,8 +441,8 @@ fr_FR_MSG = $(FIREBIRD)/fr_FR.msg de_DE_MSG = $(FIREBIRD)/de_DE.msg ja_JP_MSG = $(FIREBIRD)/ja_JP.msg - -#Platform Manager -#For want of a better suggestion we may as well default to posix +# Platform Manager +# For want of a better suggestion we may as well default to posix PLATFORM_PATH = os/posix TRACE_OS_Sources = + diff --git a/builds/posix/make.rules b/builds/posix/make.rules index 3afd8911412..6307e2cf70d 100644 --- a/builds/posix/make.rules +++ b/builds/posix/make.rules @@ -32,7 +32,7 @@ # Please don't use compiler/platform specific flags here - nmcc 02-Nov-2002 -WFLAGS =-I$(SRC_ROOT)/include/gen -I$(SRC_ROOT)/include -I$(ROOT)/extern/re2 $(CPPFLAGS) $(LTCSOURCE) +WFLAGS =-I$(SRC_ROOT)/include/gen -I$(SRC_ROOT)/include $(CPPFLAGS) $(LTCSOURCE) ifeq ($(TOMMATH_BUILD_FLG),Y) WFLAGS += -I$(TOMMATH_INC) @@ -42,6 +42,14 @@ ifeq ($(TOMCRYPT_BUILD_FLG),Y) WFLAGS += -I$(TOMCRYPT_INC) endif +ifeq ($(ABSEIL_BUILD_FLG),Y) + WFLAGS += -I$(ROOT)/extern/int128 +endif + +ifeq ($(RE2_BUILD_FLG),Y) + WFLAGS += -I$(ROOT)/extern/re2 +endif + ifeq ($(LSB_FLG),Y) WFLAGS += -DLSB_BUILD endif diff --git a/builds/posix/postfix.darwin b/builds/posix/postfix.darwin index 9c00191f65e..097f4ecd82c 100644 --- a/builds/posix/postfix.darwin +++ b/builds/posix/postfix.darwin @@ -30,8 +30,7 @@ framework: mkdir -p $(FB_FW)/Versions/A/Libraries cp $(ICU_LOC)*.dylib ../gen/$(TARGET)/firebird/lib/ - - ln -s Versions/Current/Firebird $(FB_FW)/Firebird + ln -s Versions/Current/Libraries/libfbclient.dylib $(FB_FW)/Firebird ln -s Versions/Current/Headers $(FB_FW)/Headers ln -s Versions/Current/Resources $(FB_FW)/Resources ln -s Versions/Current/Libraries $(FB_FW)/Libraries diff --git a/builds/posix/prefix.darwin_aarch64 b/builds/posix/prefix.darwin_aarch64 new file mode 100644 index 00000000000..897d120b6aa --- /dev/null +++ b/builds/posix/prefix.darwin_aarch64 @@ -0,0 +1,49 @@ +# The contents of this file are subject to the Interbase Public +# License Version 1.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy +# of the License at http://www.Inprise.com/IPL.html +# +# Software distributed under the License is distributed on an +# "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express +# or implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code was created by Inprise Corporation +# and its predecessors. Portions created by Inprise Corporation are +# +# Copyright (C) 2000 Inprise Corporation +# All Rights Reserved. +# Contributor(s): ______________________________________. +# Start of file prefix.darwin: $(VERSION) @PLATFORM@ +# 2 Oct 2002, Nickolay Samofatov - Major Cleanup +# +# Default build from 10.9 using Clang +# +# Build instructions +# set CFLAGS='-I (ICUDIR)/icu/source/common' (ucnv.h) +# set LDFLAGS='-L(ICUDIR)/icu/source/lib' (-licuuc) +# set CXXFLAGS='-I (ICUDIR)/icu/source/common -I ICUDIR/icu/source/i18n' +# where ICUDIR is where you installed ICU +# configure using --with-builtin-tommath +# or add the relevant -I, -L for an installed version of libtommath + +#DYLD_PRINT_ENV=1 +#export DYLD_PRINT_ENV + +#DYLD_PRINT_LIBRARIES=1 +#export DYLD_PRINT_LIBRARIES + +MACOSX_DEPLOYMENT_TARGET=11.0 +export MACOSX_DEPLOYMENT_TARGET + +PROD_FLAGS=-DDARWIN -DARM64 -pipe -O2 -MMD -fPIC -fno-common -mmacosx-version-min=11.0 +DEV_FLAGS=-ggdb -DDARWIN -DARM64 -pipe -MMD -fPIC -fno-omit-frame-pointer -fno-common -Wall -fno-optimize-sibling-calls -mmacosx-version-min=11.0 -Wno-non-virtual-dtor +CXXFLAGS:=$(CXXFLAGS) -fvisibility-inlines-hidden -fvisibility=hidden -stdlib=libc++ + +UNDEF_PLATFORM= + +LINK_LIBS+=-liconv +#MATHLIB=$(ROOT)/extern/libtommath/.libs/libtommath.a +SO_LINK_LIBS+=-liconv + +include $(ROOT)/gen/darwin.defaults diff --git a/builds/posix/prefix.darwin_i386 b/builds/posix/prefix.darwin_i386 index 39a37941caf..ff6069839d5 100644 --- a/builds/posix/prefix.darwin_i386 +++ b/builds/posix/prefix.darwin_i386 @@ -24,10 +24,7 @@ # 2. dnl the CPU_TYPE # 3. edit extern/icu/source/config and set the right 32bit flags (-arch i386) # 4. for CFLAGS, CXXFLAGS, LDFLAGS export '-m32 -arch i386' -# 5. export MACOSX_DEPLOYMENT_TARGET=10.7 - -DYLD_LIBRARY_PATH=$(FIREBIRD)/lib -export DYLD_LIBRARY_PATH +# 5. export MACOSX_DEPLOYMENT_TARGET=10.7 MACOSX_DEPLOYMENT_TARGET=10.7 export MACOSX_DEPLOYMENT_TARGET @@ -36,7 +33,7 @@ PROD_FLAGS=-O1 -DDARWIN -pipe -MMD -fPIC -fno-common -arch i386 -mmacosx-version DEV_FLAGS=-ggdb -DDARWIN -pipe -MMD -fPIC -fno-common -Wall -arch i386 -mmacosx-version-min=10.7 -Wno-non-virtual-dtor CXXFLAGS:=$(CXXFLAGS) -fvisibility-inlines-hidden -fvisibility=hidden -fno-weak -EXE_LINK_OPTIONS:=-m32 +EXE_LINK_OPTIONS+=-m32 LD_FLAGS+=-m32 -arch i386 include $(ROOT)/gen/darwin.defaults diff --git a/builds/posix/prefix.darwin_powerpc b/builds/posix/prefix.darwin_powerpc index f8816c6248e..c56b5feaede 100644 --- a/builds/posix/prefix.darwin_powerpc +++ b/builds/posix/prefix.darwin_powerpc @@ -17,9 +17,6 @@ # Start of file prefix.darwin: $(VERSION) @PLATFORM@ # 2 Oct 2002, Nickolay Samofatov - Major Cleanup -DYLD_LIBRARY_PATH=$(FIREBIRD)/lib -export DYLD_LIBRARY_PATH - MACOSX_DEPLOYMENT_TARGET=10.2 export MACOSX_DEPLOYMENT_TARGET @@ -27,6 +24,4 @@ PROD_FLAGS=-DDARWIN -pipe -p -MMD -fPIC -fno-common -arch ppc -mmacosx-version-m DEV_FLAGS=-ggdb -DDARWIN -pipe -p -MMD -fPIC -fno-common -Wall -arch ppc -mmacosx-version-min=10.2 -Wno-non-virtual-dtor CXXFLAGS:=$(CXXFLAGS) -fvisibility-inlines-hidden -fvisibility=hidden -fno-weak -EXE_LINK_OPTIONS:= - include $(ROOT)/gen/darwin.defaults diff --git a/builds/posix/prefix.darwin_ppc64 b/builds/posix/prefix.darwin_ppc64 index 9fbc89de2eb..a33ed454899 100644 --- a/builds/posix/prefix.darwin_ppc64 +++ b/builds/posix/prefix.darwin_ppc64 @@ -18,7 +18,7 @@ # 2 Oct 2002, Nickolay Samofatov - Major Cleanup # To use this file to build 64bit version of Firebird for MacOS 10.5 (Leopard) -# Can only be built on MacOSX 10.5 (Leopard) due to lack of 64bit support in +# Can only be built on MacOSX 10.5 (Leopard) due to lack of 64bit support in # Carbon in previous versions of MacOSX # 1. edit configure.in so that MAKEFILE_PREFIX=darwin_ppc64 # 2. uncomment the CPU_TYPE @@ -29,9 +29,6 @@ # 6. export LDFLAGS='-arch ppc_64' # 7. export MACOSX_DEPLOYMENT_TARGET=10.5 -DYLD_LIBRARY_PATH=$(FIREBIRD)/lib -export DYLD_LIBRARY_PATH - MACOSX_DEPLOYMENT_TARGET=10.5 export MACOSX_DEPLOYMENT_TARGET @@ -39,7 +36,7 @@ PROD_FLAGS=-O3 -DDARWIN -pipe -p -MMD -fPIC -fno-common -mmacosx-version-min=10. DEV_FLAGS=-ggdb -DDARWIN -pipe -p -MMD -fPIC -fno-common -Wall -mmacosx-version-min=10.5 -Wno-non-virtual-dtor CXXFLAGS:=$(CXXFLAGS) -fvisibility-inlines-hidden -fvisibility=hidden -EXE_LINK_OPTIONS:=-arch ppc64 +EXE_LINK_OPTIONS+=-arch ppc64 LD_FLAGS+=-arch ppc64 include $(ROOT)/gen/darwin.defaults diff --git a/builds/posix/prefix.darwin_x86_64 b/builds/posix/prefix.darwin_x86_64 index afd6a86b58f..cbadd3397fd 100644 --- a/builds/posix/prefix.darwin_x86_64 +++ b/builds/posix/prefix.darwin_x86_64 @@ -35,7 +35,6 @@ PROD_FLAGS=-O1 -DDARWIN -pipe -MMD -fPIC -fno-common -mmacosx-version-min=10.7 DEV_FLAGS=-ggdb -DDARWIN -pipe -MMD -fPIC -fno-omit-frame-pointer -fno-common -Wall -fno-optimize-sibling-calls -mmacosx-version-min=10.7 -Wno-non-virtual-dtor CXXFLAGS:=$(CXXFLAGS) -fvisibility-inlines-hidden -fvisibility=hidden -stdlib=libc++ -msse4 -EXE_LINK_OPTIONS:= LD_FLAGS+=-liconv FIREBIRD_LIBRARY_LINK+=-liconv UNDEF_PLATFORM= diff --git a/builds/posix/prefix.linux_amd64 b/builds/posix/prefix.linux_amd64 index 9a9067d2436..5d5fccdddb0 100644 --- a/builds/posix/prefix.linux_amd64 +++ b/builds/posix/prefix.linux_amd64 @@ -20,7 +20,8 @@ COMMON_FLAGS=-ggdb -DFB_SEND_FLAGS=MSG_NOSIGNAL -DLINUX -DAMD64 -pipe -MMD -fPIC -fmessage-length=0 OPTIMIZE_FLAGS=-O3 -fno-omit-frame-pointer -WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-variable -Wno-narrowing -Wno-unused-local-typedefs +WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-variable -Wno-narrowing \ + -Wno-unused-local-typedefs -Wno-template-id-cdtor PLATFORM_PLUSPLUS_FLAGS=-Wno-invalid-offsetof -Wno-class-memaccess PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS) diff --git a/builds/posix/prefix.linux_s390x b/builds/posix/prefix.linux_s390x index ccb2340123b..cb0992bb411 100644 --- a/builds/posix/prefix.linux_s390x +++ b/builds/posix/prefix.linux_s390x @@ -18,10 +18,10 @@ # # 2 Oct 2002, Nickolay Samofatov - Major cleanup -COMMON_FLAGS=-ggdb -DFB_SEND_FLAGS=MSG_NOSIGNAL -DLINUX -pipe -MMD -fPIC -fmessage-length=0 -fsigned-char +COMMON_FLAGS=-ggdb -DFB_SEND_FLAGS=MSG_NOSIGNAL -DLINUX -pipe -MMD -fPIC -fmessage-length=0 -fsigned-char -Wno-invalid-offsetof OPTIMIZE_FLAGS=-O3 -fno-omit-frame-pointer -fno-builtin WARN_FLAGS=-Wall -Wno-switch -Wno-parentheses -Wno-unknown-pragmas -Wno-unused-variable -Wno-non-virtual-dtor PROD_FLAGS=$(COMMON_FLAGS) $(OPTIMIZE_FLAGS) -DEV_FLAGS=-DUSE_VALGRIND -p $(COMMON_FLAGS) $(WARN_FLAGS) -#DEV_FLAGS=-p $(COMMON_FLAGS) $(WARN_FLAGS) +#DEV_FLAGS=-DUSE_VALGRIND -p $(COMMON_FLAGS) $(WARN_FLAGS) +DEV_FLAGS=-p $(COMMON_FLAGS) $(WARN_FLAGS) diff --git a/builds/win32/gen_helper.nmake b/builds/win32/gen_helper.nmake index 54d292de580..f9e143a8565 100644 --- a/builds/win32/gen_helper.nmake +++ b/builds/win32/gen_helper.nmake @@ -14,6 +14,7 @@ PAS_ROOT=$(MISC)\pascal PASCAL_SOURCES=$(PAS_ROOT)\Pascal.interface.pas $(PAS_ROOT)\Pascal.implementation.pas TMP_FUNCS=$(FB_GEN_DIR)\misc\func.pas XPB_CONSTS=$(FB_ROOT_PATH)\src\include\firebird\impl\consts_pub.h +INF_CONSTS=$(FB_ROOT_PATH)\src\include\firebird\impl\inf_pub.h ERR_CONSTS=$(FB_ROOT_PATH)\lang_helpers\gds_codes.pas RPL_AWK=$(FB_GEN_DIR)\def_awk.exe RPL_AWK_SRC=$(MISC)\def_awk.c @@ -50,6 +51,7 @@ $(RPL_GREP): $(RPL_GREP_SRC) $(TMP_FUNCS): $(PAS_ROOT)\fb_get_master_interface.pas $(XPB_CONSTS) $(ERR_CONSTS) $(RPL_AWK) $(RPL_GREP) copy $(PAS_ROOT)\fb_get_master_interface.pas $(TMP_FUNCS) $(RPL_AWK) <$(XPB_CONSTS) >>$(TMP_FUNCS) + $(RPL_AWK) <$(INF_CONSTS) >>$(TMP_FUNCS) $(RPL_GREP) <$(ERR_CONSTS) >>$(TMP_FUNCS) $(API_PAS_FILE): $(IDL_FILE) $(PASCAL_SOURCES) $(TMP_FUNCS) diff --git a/builds/win32/make_boot.bat b/builds/win32/make_boot.bat index 5c9445ea26b..b39e1c10214 100644 --- a/builds/win32/make_boot.bat +++ b/builds/win32/make_boot.bat @@ -187,7 +187,7 @@ goto :EOF @echo Building re2... @mkdir %FB_ROOT_PATH%\extern\re2\builds\%FB_TARGET_PLATFORM% 2>nul @pushd %FB_ROOT_PATH%\extern\re2\builds\%FB_TARGET_PLATFORM% -@cmake -G "Visual Studio %MSVC_VERSION%" -A %FB_TARGET_PLATFORM% -S %FB_ROOT_PATH%\extern\re2 +@cmake -G "%MSVC_CMAKE_GENERATOR%" -A %FB_TARGET_PLATFORM% -S %FB_ROOT_PATH%\extern\re2 if errorlevel 1 call :boot2 re2 @cmake --build %FB_ROOT_PATH%\extern\re2\builds\%FB_TARGET_PLATFORM% --target ALL_BUILD --config Release > re2_Release_%FB_TARGET_PLATFORM%.log @cmake --build %FB_ROOT_PATH%\extern\re2\builds\%FB_TARGET_PLATFORM% --target ALL_BUILD --config Debug > re2_Debug_%FB_TARGET_PLATFORM%.log diff --git a/builds/win32/msvc12/FirebirdCommon.props b/builds/win32/msvc12/FirebirdCommon.props index a3f24757cbc..e5619451e90 100644 --- a/builds/win32/msvc12/FirebirdCommon.props +++ b/builds/win32/msvc12/FirebirdCommon.props @@ -33,6 +33,7 @@ true $(IntDir)$(TargetName).pdb $(IntDir)$(TargetName).lib + psapi.lib;%(AdditionalDependencies) $(IntDir)$(TargetName).bsc diff --git a/builds/win32/msvc12/empbuild.vcxproj b/builds/win32/msvc12/empbuild.vcxproj index e52dc64bd58..c07748c347a 100644 --- a/builds/win32/msvc12/empbuild.vcxproj +++ b/builds/win32/msvc12/empbuild.vcxproj @@ -146,8 +146,9 @@ /MACHINE:I386 %(AdditionalOptions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console @@ -166,8 +167,9 @@ GPRE_FORTRAN;GPRE_PASCAL;GPRE_COBOL;GPRE_ADA;_DEBUG;_CONSOLE;SUPERCLIENT;WIN32;DEV_BUILD;%(PreprocessorDefinitions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console diff --git a/builds/win32/msvc14/FirebirdCommon.props b/builds/win32/msvc14/FirebirdCommon.props index 50faef634da..8bba5a105cc 100644 --- a/builds/win32/msvc14/FirebirdCommon.props +++ b/builds/win32/msvc14/FirebirdCommon.props @@ -33,6 +33,7 @@ true $(IntDir)$(TargetName).pdb $(IntDir)$(TargetName).lib + psapi.lib;%(AdditionalDependencies) $(IntDir)$(TargetName).bsc diff --git a/builds/win32/msvc14/empbuild.vcxproj b/builds/win32/msvc14/empbuild.vcxproj index b6bc0e0a4c6..c0119913e3f 100644 --- a/builds/win32/msvc14/empbuild.vcxproj +++ b/builds/win32/msvc14/empbuild.vcxproj @@ -146,8 +146,9 @@ /MACHINE:I386 %(AdditionalOptions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console @@ -166,8 +167,9 @@ GPRE_FORTRAN;GPRE_PASCAL;GPRE_COBOL;GPRE_ADA;_DEBUG;_CONSOLE;SUPERCLIENT;WIN32;DEV_BUILD;%(PreprocessorDefinitions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console diff --git a/builds/win32/msvc15/FirebirdCommon.props b/builds/win32/msvc15/FirebirdCommon.props index 50faef634da..ee42ff943a1 100644 --- a/builds/win32/msvc15/FirebirdCommon.props +++ b/builds/win32/msvc15/FirebirdCommon.props @@ -33,6 +33,7 @@ true $(IntDir)$(TargetName).pdb $(IntDir)$(TargetName).lib + psapi.lib;%(AdditionalDependencies) $(IntDir)$(TargetName).bsc @@ -41,4 +42,4 @@ RC_ARH_$(Platform);RC_TARGET_$(TargetName);RC_TARGET_NAME=$(TargetName);RC_TARGET_FILENAME=$(TargetFileName);%(PreprocessorDefinitions) - \ No newline at end of file + diff --git a/builds/win32/msvc15/alice.vcxproj b/builds/win32/msvc15/alice.vcxproj index 0aed0b4ec85..9a6814497b5 100644 --- a/builds/win32/msvc15/alice.vcxproj +++ b/builds/win32/msvc15/alice.vcxproj @@ -20,32 +20,42 @@ {0D616380-1A5A-4230-A80B-021360E4E669} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -147,4 +157,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/btyacc.vcxproj b/builds/win32/msvc15/btyacc.vcxproj index 8c31efd8b94..d4d616523da 100644 --- a/builds/win32/msvc15/btyacc.vcxproj +++ b/builds/win32/msvc15/btyacc.vcxproj @@ -22,32 +22,42 @@ {57CDBF51-F1FB-4227-8C03-6F4134A7E234} btyacc ManagedCProj - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application MultiByte false - v141_xp + v141_xp + v142 + v143 Application MultiByte false - v141_xp + v141_xp + v142 + v143 Application MultiByte false - v141 + v141 + v142 + v143 Application MultiByte false - v141 + v141 + v142 + v143 @@ -185,4 +195,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/build_msg.vcxproj b/builds/win32/msvc15/build_msg.vcxproj index 1451525e6ff..ecaefec7499 100644 --- a/builds/win32/msvc15/build_msg.vcxproj +++ b/builds/win32/msvc15/build_msg.vcxproj @@ -21,32 +21,42 @@ {99A84638-DF3A-417F-895D-5BD88FC29411} build_msg - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 diff --git a/builds/win32/msvc15/burp.vcxproj b/builds/win32/msvc15/burp.vcxproj index 0104a2949b9..bb4eeef340c 100644 --- a/builds/win32/msvc15/burp.vcxproj +++ b/builds/win32/msvc15/burp.vcxproj @@ -20,32 +20,42 @@ {D1507562-A363-4685-96AF-B036F5E5E47F} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -155,4 +165,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/chacha.vcxproj b/builds/win32/msvc15/chacha.vcxproj index 7dedf997d14..976f851c2e9 100644 --- a/builds/win32/msvc15/chacha.vcxproj +++ b/builds/win32/msvc15/chacha.vcxproj @@ -21,28 +21,38 @@ {F2E1A852-5A4B-4162-9DA8-0363805FCFD0} chacha - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 @@ -195,4 +205,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/codes.vcxproj b/builds/win32/msvc15/codes.vcxproj index 7a4e961251b..14e3cde11db 100644 --- a/builds/win32/msvc15/codes.vcxproj +++ b/builds/win32/msvc15/codes.vcxproj @@ -20,32 +20,42 @@ {5658573B-E79E-4C84-8B15-C910C4CDB9AD} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -194,4 +204,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/common.vcxproj b/builds/win32/msvc15/common.vcxproj index f7a2ed6dc35..4769c4ec366 100644 --- a/builds/win32/msvc15/common.vcxproj +++ b/builds/win32/msvc15/common.vcxproj @@ -222,33 +222,43 @@ {15605F44-BFFD-444F-AD4C-55DC9D704465} + 10.0.17763.0 + 10.0 + 10.0 common - 10.0.17763.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 diff --git a/builds/win32/msvc15/empbuild.vcxproj b/builds/win32/msvc15/empbuild.vcxproj index b18564a07a3..80014addd24 100644 --- a/builds/win32/msvc15/empbuild.vcxproj +++ b/builds/win32/msvc15/empbuild.vcxproj @@ -21,32 +21,42 @@ {FC2859B9-56DB-40B4-86C4-2DE31ECE9144} empbuild - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -147,8 +157,9 @@ /MACHINE:I386 %(AdditionalOptions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console @@ -167,8 +178,9 @@ GPRE_FORTRAN;GPRE_PASCAL;GPRE_COBOL;GPRE_ADA;_DEBUG;_CONSOLE;SUPERCLIENT;WIN32;DEV_BUILD;%(PreprocessorDefinitions) - odbc32.lib;odbccp32.lib;fbclient.lib;%(AdditionalDependencies) - ..\..\..\temp\$(Platform)\$(Configuration)\fbclient;%(AdditionalLibraryDirectories) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + Console diff --git a/builds/win32/msvc15/engine.vcxproj b/builds/win32/msvc15/engine.vcxproj index 274670ee27d..d43af6f459e 100644 --- a/builds/win32/msvc15/engine.vcxproj +++ b/builds/win32/msvc15/engine.vcxproj @@ -412,32 +412,42 @@ {F8798A49-9D20-451E-A7BD-FEB5237103B5} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 diff --git a/builds/win32/msvc15/fb2control.vcxproj b/builds/win32/msvc15/fb2control.vcxproj index 998654a506a..fb012b5d95c 100644 --- a/builds/win32/msvc15/fb2control.vcxproj +++ b/builds/win32/msvc15/fb2control.vcxproj @@ -20,7 +20,9 @@ {1AE02D41-7E24-43CC-9BCB-E4CEB6037D16} - 10.0.17134.0 + 10.0.17763.0 + 10.0 + 10.0 MFCProj @@ -28,25 +30,33 @@ DynamicLibrary Static MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary Static MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary Dynamic MultiByte - v141 + v141 + v142 + v143 DynamicLibrary Static MultiByte - v141 + v141 + v142 + v143 @@ -258,4 +268,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fb_lock_print.vcxproj b/builds/win32/msvc15/fb_lock_print.vcxproj index c193caa5483..4a67d26247b 100644 --- a/builds/win32/msvc15/fb_lock_print.vcxproj +++ b/builds/win32/msvc15/fb_lock_print.vcxproj @@ -20,32 +20,42 @@ {E8397148-0E9C-449B-9F45-7FB377A08242} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -192,4 +202,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbguard.vcxproj b/builds/win32/msvc15/fbguard.vcxproj index 09c33082441..a6c392774f4 100644 --- a/builds/win32/msvc15/fbguard.vcxproj +++ b/builds/win32/msvc15/fbguard.vcxproj @@ -20,32 +20,42 @@ {BBD83ED3-8A48-4FE8-B4B7-CB27730986B2} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -208,4 +218,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbrmclib.vcxproj b/builds/win32/msvc15/fbrmclib.vcxproj index 0ce4098d823..fb9c76449cb 100644 --- a/builds/win32/msvc15/fbrmclib.vcxproj +++ b/builds/win32/msvc15/fbrmclib.vcxproj @@ -12,20 +12,26 @@ {FAF9AD25-8238-49E9-9AC9-8C56E190440A} - 10.0.17134.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 @@ -129,4 +135,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbserver.vcxproj b/builds/win32/msvc15/fbserver.vcxproj index 0418db84c0f..51cdba3a057 100644 --- a/builds/win32/msvc15/fbserver.vcxproj +++ b/builds/win32/msvc15/fbserver.vcxproj @@ -20,32 +20,42 @@ {23EC8DAA-6718-4EF3-979F-89F611C7D504} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -233,4 +243,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbsvcmgr.vcxproj b/builds/win32/msvc15/fbsvcmgr.vcxproj index 292c68d26b8..f0359b09963 100644 --- a/builds/win32/msvc15/fbsvcmgr.vcxproj +++ b/builds/win32/msvc15/fbsvcmgr.vcxproj @@ -20,32 +20,42 @@ {EFB07DBC-36E3-4C54-B941-3CDAFAACF47B} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -188,4 +198,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbtrace.vcxproj b/builds/win32/msvc15/fbtrace.vcxproj index 4b46cccbe4c..b47e95904fe 100644 --- a/builds/win32/msvc15/fbtrace.vcxproj +++ b/builds/win32/msvc15/fbtrace.vcxproj @@ -20,28 +20,38 @@ {53F75437-15B8-4A5C-86BF-E238CC68FCBC} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 @@ -209,4 +219,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/fbtracemgr.vcxproj b/builds/win32/msvc15/fbtracemgr.vcxproj index 9681eb74000..9ee22a6ec3c 100644 --- a/builds/win32/msvc15/fbtracemgr.vcxproj +++ b/builds/win32/msvc15/fbtracemgr.vcxproj @@ -22,32 +22,42 @@ {58C7E370-0EDD-4F5E-8617-3F5071170205} fbtracemgr Win32Proj - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -191,4 +201,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gbak.vcxproj b/builds/win32/msvc15/gbak.vcxproj index 4e3bad3de5b..2ac340738db 100644 --- a/builds/win32/msvc15/gbak.vcxproj +++ b/builds/win32/msvc15/gbak.vcxproj @@ -20,32 +20,42 @@ {B732F5D2-B5D9-417F-B156-D790F466CB8E} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -211,4 +221,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gfix.vcxproj b/builds/win32/msvc15/gfix.vcxproj index dbf7c2584ca..1ccf23fee2d 100644 --- a/builds/win32/msvc15/gfix.vcxproj +++ b/builds/win32/msvc15/gfix.vcxproj @@ -21,32 +21,42 @@ {44A9E4AD-B932-4620-B319-431A153BB341} gfix - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -192,4 +202,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gpre.vcxproj b/builds/win32/msvc15/gpre.vcxproj index 8f729f36790..1b6c19fb421 100644 --- a/builds/win32/msvc15/gpre.vcxproj +++ b/builds/win32/msvc15/gpre.vcxproj @@ -21,32 +21,42 @@ {D84F0839-28A4-40B2-B5F4-F5E1E7F48FD0} gpre - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -206,4 +216,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gpre_boot.vcxproj b/builds/win32/msvc15/gpre_boot.vcxproj index 04d707d38bf..f7660a4d269 100644 --- a/builds/win32/msvc15/gpre_boot.vcxproj +++ b/builds/win32/msvc15/gpre_boot.vcxproj @@ -21,32 +21,42 @@ {8348521F-4480-4A1D-AE3B-E260235E9860} gpre_boot - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -201,4 +211,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gpre_common.vcxproj b/builds/win32/msvc15/gpre_common.vcxproj index 4c10444d245..f94a41f1923 100644 --- a/builds/win32/msvc15/gpre_common.vcxproj +++ b/builds/win32/msvc15/gpre_common.vcxproj @@ -21,32 +21,42 @@ {2925B855-5975-44AE-BB00-1217A2A4E511} gpre - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -222,4 +232,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gsec.vcxproj b/builds/win32/msvc15/gsec.vcxproj index 5f833a0b96d..1d647ba359a 100644 --- a/builds/win32/msvc15/gsec.vcxproj +++ b/builds/win32/msvc15/gsec.vcxproj @@ -20,32 +20,42 @@ {7043CC61-DEC1-4C6B-86B9-0E911D1094C9} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -192,4 +202,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gsplit.vcxproj b/builds/win32/msvc15/gsplit.vcxproj index aebab4136b2..56849087c09 100644 --- a/builds/win32/msvc15/gsplit.vcxproj +++ b/builds/win32/msvc15/gsplit.vcxproj @@ -21,32 +21,42 @@ {B7F22B7F-9937-4874-9A8B-6AB4E36E74A5} gsplit - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -204,4 +214,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/gstat.vcxproj b/builds/win32/msvc15/gstat.vcxproj index 677983308ca..82322a05d9e 100644 --- a/builds/win32/msvc15/gstat.vcxproj +++ b/builds/win32/msvc15/gstat.vcxproj @@ -20,32 +20,42 @@ {7E862973-37C4-4202-80E7-490ED4DEDA14} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -199,4 +209,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/ib_util.vcxproj b/builds/win32/msvc15/ib_util.vcxproj index 554cbf642fd..37f38a2a9c5 100644 --- a/builds/win32/msvc15/ib_util.vcxproj +++ b/builds/win32/msvc15/ib_util.vcxproj @@ -20,32 +20,42 @@ {EABA0FF3-1C4D-4FAB-8418-31C9061F3F0D} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -207,4 +217,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/instclient.vcxproj b/builds/win32/msvc15/instclient.vcxproj index 595fb86a7c8..56a56073f01 100644 --- a/builds/win32/msvc15/instclient.vcxproj +++ b/builds/win32/msvc15/instclient.vcxproj @@ -21,32 +21,42 @@ {C6A31374-178C-4680-A404-76BE24D0229B} instclient - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -191,4 +201,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/instreg.vcxproj b/builds/win32/msvc15/instreg.vcxproj index 75909d0aa8f..c94037af44b 100644 --- a/builds/win32/msvc15/instreg.vcxproj +++ b/builds/win32/msvc15/instreg.vcxproj @@ -21,32 +21,42 @@ {19470DE6-1975-4F9B-B1BE-E87A83240B15} instreg - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -190,4 +200,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/instsvc.vcxproj b/builds/win32/msvc15/instsvc.vcxproj index c8b864d2c9c..58091aeb622 100644 --- a/builds/win32/msvc15/instsvc.vcxproj +++ b/builds/win32/msvc15/instsvc.vcxproj @@ -21,32 +21,42 @@ {72894398-38CA-47A6-95FE-9647DE2BE968} instsvc - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -202,4 +212,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/intl.vcxproj b/builds/win32/msvc15/intl.vcxproj index 8f6a4c5dcd6..9ac780a85a2 100644 --- a/builds/win32/msvc15/intl.vcxproj +++ b/builds/win32/msvc15/intl.vcxproj @@ -20,32 +20,42 @@ {DFFA2117-E6A8-4806-BB69-94DAC8F8F42A} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -264,4 +274,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/intlbuild.vcxproj b/builds/win32/msvc15/intlbuild.vcxproj index e82c203efa1..8e4cfa974e5 100644 --- a/builds/win32/msvc15/intlbuild.vcxproj +++ b/builds/win32/msvc15/intlbuild.vcxproj @@ -20,32 +20,42 @@ {9546EF04-1326-464B-A6ED-395C60DD63CC} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -178,4 +188,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/isql.vcxproj b/builds/win32/msvc15/isql.vcxproj index af4b94877b0..7d7669cbf78 100644 --- a/builds/win32/msvc15/isql.vcxproj +++ b/builds/win32/msvc15/isql.vcxproj @@ -21,32 +21,42 @@ {DEE75AD5-F165-40E1-80B2-400E27725D5C} isql - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -217,4 +227,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/legacy_auth.vcxproj b/builds/win32/msvc15/legacy_auth.vcxproj index 66824c107ff..42a96026296 100644 --- a/builds/win32/msvc15/legacy_auth.vcxproj +++ b/builds/win32/msvc15/legacy_auth.vcxproj @@ -20,28 +20,38 @@ {062BD3C7-2D01-44F6-8D79-070F688C559F} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 @@ -195,4 +205,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/legacy_usermanager.vcxproj b/builds/win32/msvc15/legacy_usermanager.vcxproj index 7430adbbb3c..2eecaaff5a7 100644 --- a/builds/win32/msvc15/legacy_usermanager.vcxproj +++ b/builds/win32/msvc15/legacy_usermanager.vcxproj @@ -20,28 +20,38 @@ {D836FBF5-071E-4E04-8D63-C7EB6701B296} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 @@ -198,4 +208,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/nbackup.vcxproj b/builds/win32/msvc15/nbackup.vcxproj index f5db2a4f862..8d1ccd99701 100644 --- a/builds/win32/msvc15/nbackup.vcxproj +++ b/builds/win32/msvc15/nbackup.vcxproj @@ -20,32 +20,42 @@ {01A41DFA-8908-4576-A1F1-C8BC7EAE39A1} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -195,4 +205,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/qli.vcxproj b/builds/win32/msvc15/qli.vcxproj index ddc09151020..8f911ad013c 100644 --- a/builds/win32/msvc15/qli.vcxproj +++ b/builds/win32/msvc15/qli.vcxproj @@ -20,32 +20,42 @@ {EBB8361B-49D5-43A5-8771-940DF3E308EF} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141_xp + v141_xp + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 Application false MultiByte - v141 + v141 + v142 + v143 @@ -252,4 +262,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/remote.vcxproj b/builds/win32/msvc15/remote.vcxproj index 824f8f8c8bc..41d0aa0e9e5 100644 --- a/builds/win32/msvc15/remote.vcxproj +++ b/builds/win32/msvc15/remote.vcxproj @@ -20,32 +20,42 @@ {4BCC693D-1745-45ED-8302-E5E2F979549A} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -167,4 +177,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/srp.vcxproj b/builds/win32/msvc15/srp.vcxproj index c540213dbd9..665f9bdd2c1 100644 --- a/builds/win32/msvc15/srp.vcxproj +++ b/builds/win32/msvc15/srp.vcxproj @@ -21,28 +21,38 @@ {BD00D28E-6667-414E-A4B1-6BEFC07ADB42} srp - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 DynamicLibrary MultiByte - v141 + v141 + v142 + v143 @@ -198,4 +208,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/udf_compat.vcxproj b/builds/win32/msvc15/udf_compat.vcxproj index d3f63cb210c..445a0583b15 100644 --- a/builds/win32/msvc15/udf_compat.vcxproj +++ b/builds/win32/msvc15/udf_compat.vcxproj @@ -20,32 +20,42 @@ {6794EB8C-6425-422D-A3B0-14EED54C0E98} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -192,4 +202,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/udr_engine.vcxproj b/builds/win32/msvc15/udr_engine.vcxproj index 71102206d80..7ecaa80407c 100644 --- a/builds/win32/msvc15/udr_engine.vcxproj +++ b/builds/win32/msvc15/udr_engine.vcxproj @@ -20,32 +20,42 @@ {20DEBF08-EF0A-4C94-ADEB-FE9BBA14588B} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -217,4 +227,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/udrcpp_example.vcxproj b/builds/win32/msvc15/udrcpp_example.vcxproj index 503586897d5..83326c59d65 100644 --- a/builds/win32/msvc15/udrcpp_example.vcxproj +++ b/builds/win32/msvc15/udrcpp_example.vcxproj @@ -20,32 +20,42 @@ {FF0FD8DF-1E5C-486E-B395-A620376A4633} - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -230,4 +240,4 @@ - \ No newline at end of file + diff --git a/builds/win32/msvc15/yvalve.vcxproj b/builds/win32/msvc15/yvalve.vcxproj index 112d3f9d4b3..b73b2889c72 100644 --- a/builds/win32/msvc15/yvalve.vcxproj +++ b/builds/win32/msvc15/yvalve.vcxproj @@ -88,32 +88,42 @@ {4FE03933-98CD-4879-A135-FD9430087A6B} yvalve - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 DynamicLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -231,4 +241,4 @@ - \ No newline at end of file + diff --git a/builds/win32/run_all.bat b/builds/win32/run_all.bat index e13429ec729..788f4df059d 100644 --- a/builds/win32/run_all.bat +++ b/builds/win32/run_all.bat @@ -9,6 +9,8 @@ set FBBUILD_BUILDTYPE=release set FBBUILD_INCLUDE_PDB= set FBBUILD_MAKE_KITS_ONLY= set FBBUILD_BUILD_ONLY=0 +set FBBUILD_TEST_ONLY= +set FB2_SNAPSHOT= ::Check if on-line help is required for %%v in ( %1 %2 %3 %4 %5 %6 %7 %8 %9 ) do ( @@ -26,10 +28,15 @@ for %%v in ( %* ) do ( ( if /I "%%v"=="PDB" (set FBBUILD_INCLUDE_PDB=1) ) ( if /I "%%v"=="REPACK" (set FBBUILD_MAKE_KITS_ONLY=1) ) ( if /I "%%v"=="JUSTBUILD" (set FBBUILD_BUILD_ONLY=1) ) +( if /I "%%v"=="TESTENV" (set FBBUILD_TEST_ONLY=1) ) +( if /I "%%v"=="SNAPSHOT" (set FB2_SNAPSHOT=1) ) +( if /I "%%v"=="NO_RN" set FB_EXTERNAL_DOCS=) ) call :SETVCENV +if defined FBBUILD_TEST_ONLY ( goto TEST_ENV & goto :EOF ) + if defined FBBUILD_MAKE_KITS_ONLY (goto :MAKE_KITS & goto :EOF) @@ -51,10 +58,12 @@ if "%FBBUILD_BUILD_ONLY%"=="1" goto :END :: Package everything up pushd ..\install\arch-specific\win32 call BuildExecutableInstall ISX ZIP EMB %FBBUILD_BUILDTYPE% -if "%ERRLEV%"=="1" ( @echo Oops - some sort of error & popd & goto :END) +if "%ERRLEV%"=="1" ( + @echo Oops - some sort of error during packaging & popd & goto :END +) if defined FBBUILD_INCLUDE_PDB ( -set /A FBBUILD_PACKAGE_NUMBER-=1 -call BuildExecutableInstall ISX ZIP EMB %FBBUILD_BUILDTYPE% PDB + set /A FBBUILD_PACKAGE_NUMBER-=1 + call BuildExecutableInstall ISX ZIP EMB %FBBUILD_BUILDTYPE% PDB ) popd @@ -67,9 +76,9 @@ goto :END @echo. @echo NOCLEAN - don't run CLEAN_ALL.BAT @echo. -@echo REALCLEAN - Run CLEAN_ALL.BAT REALCLEAN -@echo This will do a deeper clean. -@echo Recommended for multi-platform builds +@echo REALCLEAN - Run CLEAN_ALL.BAT REALCLEAN +@echo This will do a deeper clean. +@echo Recommended for multi-platform builds @echo. @echo DEBUG - Do a DEBUG build (for experienced developers only.) @echo This switch is not needed to debug Firebird. @@ -80,14 +89,43 @@ goto :END @echo. @echo JUSTBUILD - Just build - don't create packages. @echo. +@echo TESTENV - Sanity check - is Visual Studio available?. +@echo - print the build variables that will be used +@echo. +@echo SNAPSHOT - Build and create a zip kit. +@echo This is intended to produce a x64 test kit +@echo with no dependency on Win32 +@echo. +@echo NO_RN - Do not fail the packaging if release notes unavailable. +@echo Default is to fail if FB_EXTERNAL_DOCS is set and release notes not found. +@echo. @goto :EOF ::--------- +:TEST_ENV +::=============================== +:: Show variables +@call setenvvar.bat %* +if "%ERRLEV%"=="1" goto :END +set > %TEMP%\fb_build_vars_%PROCESSOR_ARCHITECTURE%.txt +type %TEMP%\fb_build_vars_%PROCESSOR_ARCHITECTURE%.txt +goto :END +::--------- + + :SETVCENV ::=============================== :: Set up the compiler environment +if DEFINED VS170COMNTOOLS ( +@devenv /? >nul 2>nul +@if errorlevel 9009 (call "%VS170COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE%) else ( echo The file: & @echo "%VS170COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% & echo has already been executed.) +) else ( +if DEFINED VS160COMNTOOLS ( +@devenv /? >nul 2>nul +@if errorlevel 9009 (call "%VS160COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE%) else ( echo The file: & @echo "%VS160COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% & echo has already been executed.) +) else ( if DEFINED VS150COMNTOOLS ( @devenv /? >nul 2>nul @if errorlevel 9009 (call "%VS150COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE%) else ( echo The file: & @echo "%VS150COMNTOOLS%\..\..\VC\Auxiliary\Build\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% & echo has already been executed.) @@ -100,15 +138,12 @@ if DEFINED VS120COMNTOOLS ( @devenv /? >nul 2>nul @if errorlevel 9009 (call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" %PROCESSOR_ARCHITECTURE%) else ( echo The file: & @echo "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% & echo has already been executed.) ) else ( -if DEFINED VS100COMNTOOLS ( -@devenv /? >nul 2>nul -@if errorlevel 9009 (call "%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat" %PROCESSOR_ARCHITECTURE%) else ( echo The file: & @echo "%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat" %PROCESSOR_ARCHITECTURE% & echo has already been executed.) -) else ( @goto :HELP ) ) ) ) +) goto :END ::--------- diff --git a/builds/win32/setenvvar.bat b/builds/win32/setenvvar.bat index 5ebe49eea7b..a2116dc836e 100644 --- a/builds/win32/setenvvar.bat +++ b/builds/win32/setenvvar.bat @@ -17,19 +17,32 @@ set FB_PROCESSOR_ARCHITECTURE=%PROCESSOR_ARCHITECTURE% ::================= :SET_MSVC_VER +if DEFINED VS170COMNTOOLS ( +@set MSVC_VERSION=15 +@set MSVC_CMAKE_GENERATOR=Visual Studio 17 2022 +) else ( +if DEFINED VS160COMNTOOLS ( +@set MSVC_VERSION=15 +@set MSVC_CMAKE_GENERATOR=Visual Studio 16 2019 +) else ( if DEFINED VS150COMNTOOLS ( @set MSVC_VERSION=15 +@set MSVC_CMAKE_GENERATOR=Visual Studio 15 ) else ( if DEFINED VS140COMNTOOLS ( @set MSVC_VERSION=14 +@set MSVC_CMAKE_GENERATOR=Visual Studio 14 ) else ( if DEFINED VS120COMNTOOLS ( @set MSVC_VERSION=12 +@set MSVC_CMAKE_GENERATOR=Visual Studio 12 ) else ( @goto :HELP ) ) ) +) +) set VS_VER=msvc%MSVC_VERSION% diff --git a/configure.ac b/configure.ac index 0a3de368ac6..e545f8c9ff4 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,20 @@ dnl Test for special ar options? AR_OPT_CHECK=false case "$build" in + aarch64-*-darwin*) + MAKEFILE_PREFIX=darwin_aarch64 + MAKEFILE_POSTFIX=darwin + PLATFORM=DARWIN + INSTALL_PREFIX=darwin + AC_DEFINE(DARWIN, 1, [Define this if OS is DARWIN]) + XE_APPEND(-framework CoreFoundation,LIBS) + EDITLINE_FLG=Y + SHRLIB_EXT=dylib + CPU_TYPE=ARM64 + EXPORT_SYMBOLS_STYLE=darwin + RAW_DEVICES_FLG=N + ;; + x*64-*-darwin*) MAKEFILE_PREFIX=darwin_x86_64 MAKEFILE_POSTFIX=darwin @@ -549,6 +563,17 @@ AC_ARG_WITH(builtin-tomcrypt, [TOMCRYPT_BUILD=Y]) AC_SUBST(TOMCRYPT_BUILD) +TERMLIB= +AC_ARG_WITH(termlib, + [ --with-termlib build with explicitly specified termcap support library], + [TERMLIB=${withval}]) + +RE2_BUILD=Y +AC_ARG_WITH(system-re2, + [ --with-system-re2 use system-wide re2 library instead of embedded copy], + [RE2_BUILD=N]) +AC_SUBST(RE2_BUILD) + dnl Avoid dumb '-g -O2' autoconf's default dnl Debugging information and optimization flags should be set in prefix.$platform file dnl Should be replaced with AC_PROG_GCC_DEFAULT_FLAGS() when available @@ -604,6 +629,7 @@ if test "$LSB_FLG" = "Y"; then CXXFLAGS="$CXXFLAGS --lsb-besteffort --lsb-shared-libs=fbclient:ib_util:tommath:tomcrypt --lsb-target-version=4.1" AC_SUBST(TOMMATH_BUILD, Y) AC_SUBST(TOMCRYPT_BUILD, Y) + AC_SUBST(RE2_BUILD, Y) AC_PATH_PROG(CC, lsbcc, "", [$PATH$PATH_SEPARATOR/opt/lsb/bin$PATH_SEPARATOR]) AC_PATH_PROG(CXX, lsbc++, "", [$PATH$PATH_SEPARATOR/opt/lsb/bin$PATH_SEPARATOR]) if test "x$CC" = "x" || test "x$CXX" = "x" ; then @@ -635,8 +661,9 @@ if test "$STD_EDITLINE" = "true"; then AC_CHECK_LIB(readline, readline, [READLINE=readline EDITLINE_FLG=Y], [STD_EDITLINE=false if test "$EDITLINE_FLG" = "Y"; then - AC_MSG_WARN([[[--with-system-editline specified, not found. Using bundled editline]]])]))) + AC_MSG_WARN([[[--with-system-editline specified, not found. Using bundled editline]]]) fi + ]))) fi XE_RESTORE_ENV() @@ -858,18 +885,32 @@ else fi AC_SUBST(CRYPTLIB) -dnl Check for libraries -AC_SEARCH_LIBS(dlopen, dl) -AC_CHECK_LIB(m, main) +dnl Check for termcap support if test "$EDITLINE_FLG" = "Y"; then - AC_CHECK_LIB(curses, tgetent, TERMLIB=curses, \ - AC_CHECK_LIB(ncurses, tgetent, TERMLIB=ncurses, \ - AC_CHECK_LIB(termcap, tgetent, TERMLIB=termcap, \ - AC_CHECK_LIB(tinfo, tgetent, TERMLIB=tinfo, \ - AC_MSG_ERROR(termcap support not found))))) + if test -z "$TERMLIB"; then + AC_CHECK_LIB(curses, tgetent, TERMLIB=curses, \ + AC_CHECK_LIB(ncurses, tgetent, TERMLIB=ncurses, \ + AC_CHECK_LIB(termcap, tgetent, TERMLIB=termcap, \ + AC_CHECK_LIB(tinfo, tgetent, TERMLIB=tinfo, \ + AC_MSG_ERROR(termcap support not found))))) + fi AC_SUBST(TERMLIB) fi +dnl check for re2 presence +if test "$RE2_BUILD" != "Y"; then + XE_SAVE_ENV() + AC_LANG_PUSH(C++) + AC_CHECK_HEADER(re2/re2.h, RE2LIB=-lre2, + AC_MSG_ERROR(Include file for re2 not found - please install development re2 package or drop --with-system-re2)) + AC_LANG_POP(C++) + XE_RESTORE_ENV() +fi +AC_SUBST(RE2LIB) + +dnl Check for libraries +AC_SEARCH_LIBS(dlopen, dl) +AC_CHECK_LIB(m, main) AC_SEARCH_LIBS(inet_aton, resolv) AC_CHECK_LIB(atomic, main) @@ -975,6 +1016,18 @@ case $host in ;; esac AC_CHECK_FUNCS(poll) +AC_CHECK_FUNCS(dlinfo) +if test "$ac_cv_func_dlinfo" = "yes"; then + AC_MSG_CHECKING(if dlinfo supports RTLD_DI_LINKMAP) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _GNU_SOURCE +#include +#include ]], [[struct link_map info; dlinfo(0, RTLD_DI_LINKMAP, &info);]])],[AC_DEFINE(HAVE_RTLD_DI_LINKMAP, [1], [Linkmap info support]) AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) + + AC_MSG_CHECKING(if dlinfo supports RTLD_DI_ORIGIN) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _GNU_SOURCE +#include +#include ]], [[char info[256]; dlinfo(0, RTLD_DI_ORIGIN, info);]])],[AC_DEFINE(HAVE_RTLD_DI_ORIGIN, [1], [Origin info support]) AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)]) +fi dnl Check for time function AC_SEARCH_LIBS(clock_gettime, rt) @@ -1003,9 +1056,9 @@ AC_CHECK_FUNCS(sem_init) if test "$ac_cv_func_sem_init" = "yes"; then AC_MSG_CHECKING(for working sem_init()) AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - main () { + int main () { sem_t s; - exit(sem_init(&s,0,0)); + return sem_init(&s,0,0); } ]])],[AC_DEFINE(WORKING_SEM_INIT,1,[Define this if sem_init() works on the platform]) AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no) @@ -1027,7 +1080,15 @@ AC_LINK_IFELSE( AC_LANG_POP(C++) dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_BIGENDIAN +AC_C_BIGENDIAN( + [ + AC_DEFINE(WORDS_BIGENDIAN,1,[Words have most significant byte first]) + AC_SUBST(TZDATA_ZIP,be.zip) + ], + [ + AC_SUBST(TZDATA_ZIP,le.zip) + ] +) AC_C_VOLATILE AC_TYPE_OFF_T AC_TYPE_SIZE_T @@ -1036,12 +1097,21 @@ AC_SYS_LARGEFILE if test "$ac_cv_sys_file_offset_bits" = "no"; then AC_MSG_CHECKING(for native large file support) AC_RUN_IFELSE([AC_LANG_SOURCE([[#include - main () { - exit(!(sizeof(off_t) == 8)); + int main () { + return !(sizeof(off_t) == 8); }]])],[ac_cv_sys_file_offset_bits=64; AC_DEFINE(_FILE_OFFSET_BITS,64) AC_MSG_RESULT(yes)],[AC_MSG_RESULT(no)],[]) fi +dnl Use int128 support for big endians +if test "$ac_cv_c_bigendian" = "yes"; then + ABSEIL_BUILD_FLG=Y + AC_DEFINE(FB_USE_ABSEIL_INT128, 1, [Use Abseil's class int128]) +else + ABSEIL_BUILD_FLG=N +fi +AC_SUBST(ABSEIL_BUILD_FLG) + AC_CHECK_SIZEOF(void *) VOID_PTR_SIZE=$ac_cv_sizeof_void_p AC_SUBST(VOID_PTR_SIZE) @@ -1074,23 +1144,23 @@ dnl EKU: try to determine the alignment of long and double dnl replaces FB_ALIGNMENT and FB_DOUBLE_ALIGN in src/jrd/common.h AC_MSG_CHECKING(alignment of long) AC_RUN_IFELSE([AC_LANG_SOURCE([[#include -main () { +int main () { struct s { char a; union { long long x; sem_t y; } b; }; - exit((int)&((struct s*)0)->b); + return (int)&((struct s*)0)->b; }]])],[ac_cv_c_alignment=$ac_status],[ac_cv_c_alignment=$ac_status],[]) AC_MSG_RESULT($ac_cv_c_alignment) AC_DEFINE_UNQUOTED(FB_ALIGNMENT, $ac_cv_c_alignment, [Alignment of long]) AC_MSG_CHECKING(alignment of double) -AC_RUN_IFELSE([AC_LANG_SOURCE([[main () { +AC_RUN_IFELSE([AC_LANG_SOURCE([[int main () { struct s { char a; double b; }; - exit((int)&((struct s*)0)->b); + return (int)&((struct s*)0)->b; }]])],[ac_cv_c_double_align=$ac_status],[ac_cv_c_double_align=$ac_status],[]) AC_MSG_RESULT($ac_cv_c_double_align) AC_DEFINE_UNQUOTED(FB_DOUBLE_ALIGN, $ac_cv_c_double_align, [Alignment of double]) @@ -1107,7 +1177,7 @@ static int abs64Compare(SINT64 n1, SINT64 n2) { return n1 == n2 ? 0 : n1 < n2 ? 1 : -1; } int main() { - exit (abs64Compare(-9223372036854775808, 3652058) == 1 ? 0 : 1); + return abs64Compare(-9223372036854775808, 3652058) == 1 ? 0 : 1; }]])],[ac_cv_compare_failed=0 ac_cv_compare_result=success]) CFLAGS="$savedflags" @@ -1233,6 +1303,8 @@ dnl # output mkdir -p gen/\$fb_tgt/firebird/examples/extauth mkdir -p gen/\$fb_tgt/firebird/examples/include mkdir -p gen/\$fb_tgt/firebird/examples/interfaces + mkdir -p gen/\$fb_tgt/firebird/examples/object_pascal + mkdir -p gen/\$fb_tgt/firebird/examples/object_pascal/common mkdir -p gen/\$fb_tgt/firebird/examples/package mkdir -p gen/\$fb_tgt/firebird/examples/stat mkdir -p gen/\$fb_tgt/firebird/examples/udf diff --git a/doc/README.isql_enhancements.txt b/doc/README.isql_enhancements.txt index cdff772a86f..d3e4378114a 100644 --- a/doc/README.isql_enhancements.txt +++ b/doc/README.isql_enhancements.txt @@ -163,13 +163,13 @@ Isql enhancements in Firebird v3. Author: Vladyslav Khorsun -When set to ON, isql keeps text of following successful SET TRANSACTION statement and -new DML transactions is started using the same SQL text (instead of defaul CONCURRENCY +When set to ON, isql keeps text of following successful SET TRANSACTION statement and +new DML transactions is started using the same SQL text (instead of defaul CONCURRENCY WAIT mode). When set to OFF, isql start new DML transaction as usual. Name KEEP_TRAN_PARAMS could be cut down to the KEEP_TRAN. -In Firebird 3 KEEP_TRAN_PARAMS value is OFF by default, preserving backward compatibility +In Firebird 3 KEEP_TRAN_PARAMS value is OFF by default, preserving backward compatibility with old behaviour. In Firebird 4 KEEP_TRAN_PARAMS is ON by default to make isql behaviour more logical. @@ -191,7 +191,7 @@ SET TRANSACTION SQL>commit; --- start new transaction, check KEEP_TRAN value and actual transaction's +-- start new transaction, check KEEP_TRAN value and actual transaction's -- parameters SQL>SET TRANSACTION READ COMMITTED WAIT; SQL>SET; @@ -237,4 +237,19 @@ SNAPSHOT SQL> SET; ... Keep transaction params: OFF -SQL> +SQL> + + + +Isql enhancements in Firebird v4.0.1. +--------------------------------- + +10) SET EXEC_PATH_DISPLAY BLR/OFF + +Retrieves the execution path of a DML statement formatted as BLR text. + +It requires server v4.0.1 or greater to work. + +Warning: this feature is very tied to engine internals and its usage is discouraged +if you do not understand very well how these internals are subject to change between +versions. diff --git a/doc/README.replication.md b/doc/README.replication.md index f0f13ec3896..07c157059a9 100644 --- a/doc/README.replication.md +++ b/doc/README.replication.md @@ -115,6 +115,10 @@ In the Beta 1 release, any physical copying method can be used: * nbackup -l + file-level copy + nbackup -n * nbackup -b 0 +If _nbackup_ was used, restore or fixup operation should be performed to complete the replica creation. Note that if you're recreating a priorly working replica, then `-seq[uence]` option of _nbackup_ must be used during restore/fixup to preserve the replication sequence counter inside the database, so that replication could continue from the moment when the primary database was copied: + +* nbackup -f <database> -seq + Then the replica mode must be activated for the database copy. Two options are possible: * gfix -replica read\_only <database> -- set up database as read-only replica diff --git a/doc/README.services_extension b/doc/README.services_extension index a103fe035a3..148b4621972 100644 --- a/doc/README.services_extension +++ b/doc/README.services_extension @@ -265,3 +265,20 @@ Samples of use of new parameter in fbsvcmgr utility (supposing login and password are set using some other method): fbsvcmgr - action_nfix dbname /tmp/ecopy.fdb + +9) Services API extension - support of new nbackup feature to clean history table. +(Khorsun Vlad, hvlad@users.sourceforge.net, 2022) + +Action isc_action_svc_nbak get new parameter tags + isc_spb_nbk_clean_history : tell nbackup to clean RDB$HISTORY table + isc_spb_nbk_keep_days : specify how many recent rows should be kept in the history + isc_spb_nbk_keep_rows : specify how days back from today should be kept in the history + +Examples: +- make backup of level 1, clean RDB$HISTORY table and keep 1 recent row in it: + + fbsvcmgr action_nbak dbfile db.fdb nbk_file db.nbk nbk_level 1 nbk_clean_history nbk_keep_rows 1 + +- make backup of level 2, clean RDB$HISTORY table and keep rows for the last 7 days in it: + + fbsvcmgr action_nbak dbfile db.fdb nbk_file db.nbk nbk_level 2 nbk_clean_history nbk_keep_days 7 diff --git a/doc/README.trace_services b/doc/README.trace_services index a398cc70592..86155a4124d 100644 --- a/doc/README.trace_services +++ b/doc/README.trace_services @@ -98,7 +98,8 @@ I. Sample configuration files for user trace sessions: a) Trace prepare, free and execution of all statements within connection 12345 - +database +{ enabled true connection_id 12345 log_statement_prepare true @@ -106,13 +107,14 @@ a) Trace prepare, free and execution of all statements within connection 12345 log_statement_start true log_statement_finish true time_threshold 0 - +} b) Trace all connections of given user to database mydatabase.fdb Log executed INSERT, UPDATE and DELETE statements, nested calls to procedures and triggers and show corresponding PLAN's and performance statistics. - +database = %[\\/]mydatabase.fdb +{ enabled true include_filter (%)(INSERT|UPDATE|DELETE)(%) log_statement_finish true @@ -121,19 +123,21 @@ b) Trace all connections of given user to database mydatabase.fdb print_plan true print_perf true time_threshold 0 - +} c) Trace connections and transactions in all databases except of security database - +database +{ enabled true log_connections true log_transactions true - +} - +database = security.db +{ enabled false - +} diff --git a/doc/Using_OO_API.html b/doc/Using_OO_API.html index 24bfd723b9e..47afb4da500 100644 --- a/doc/Using_OO_API.html +++ b/doc/Using_OO_API.html @@ -6,7 +6,7 @@ - + @@ -36,19 +36,19 @@ in C++, interface may be defined using any language able to call functions using C calling conventions and having concepts of array and pointer to -procedure/function. Next interfaces are versioned +procedure/function. Next interfaces are versionedi.e. we support different versions of same interface. Binary layout of interfaces is designed to support that features very efficient (there is no need in -additional virtual calls like in OLE2/COM with it's QueryInterface) -but -it's not convenient for direct use from most languages. Therefore +additional virtual calls like in OLE2/COM with it's QueryInterface) +but it's not +convenient for direct use from most languages. Therefore language-specific wrappers should better be designed for different languages making use of API easier. Currently we have wrappers for C++ and Pascal, Java is coming soon. From end-user POV calls from C++ and Pascal have absolutely no difference, though some additional language-specific features present in C++ (like ability to turn off -automatic status check after API calls) are missing in Pascal.

+automatic status check after API calls) are missing in Pascal.


@@ -69,17 +69,16 @@


-

Firebird +

Firebird installation package contains a number of live samples of use of OO API – they are in examples/interfaces (database access) and -examples/dbcrypt (plugin performing fictitious -database encryption) +examples/dbcrypt (plugin performing fictitious database encryption) directories. It's supposed that the reader is familiar with ISC API -used in Firebird since interbase times.

+used in Firebird since interbase times.


-

This +

This document does not pretend to be a full Firebird 3 documentation – it just describes new object oriented API, and a reader should be familiar with main Firebird concepts, knowledge about ISC API is also @@ -92,7 +91,7 @@ (except one present in firebird public headers), etc. Primary goal is to make this text usable not only to C++ people because our API is oriented to support not only C++ but other, more simple languages -too.

+too.


@@ -934,49 +933,67 @@

IBatchCompletionState* cs = batch->execute(&status, tra);

-

We +

We requested accounting of the number of modified (inserted, updated or deleted) records per message. To print it we must use BatchCompletionState interface. Determine total number of messages processed by batch (it can be less than the number of messages passed to the batch if error happened and an option enabling multiple errors during batch processing was not -turned on):

-

unsigned -total = cs->getSize(&status);

+turned on):

+

unsigned total = +cs->getSize(&status);

Now print the state of each message:

-

for -(unsigned p = 0; p < total; ++p) printf(“Msg %u state %d\n”, -p, cs->getState(&status, p));

-

When -finished analyzing completion state don’t forget to dispose it:

-

cs->dispose();

-

Full -sample of printing contents -of BatchCompletionState -is in print_cs() function in sample 11.batch.cpp.

-

If +

for (unsigned p = 0; p < +total; ++p) printf(“Msg %u state %d\n”, p, cs->getState(&status, +p));

+

When +finished analyzing completion state don’t forget to dispose it:

+

cs->dispose();

+

Full +sample of printing contents of +BatchCompletionState +is in print_cs() function in sample 11.batch.cpp.

+

If for some reason you want to make batch buffers empty not executing it (i.e. prepare for new portion of messages to process) use cancel() -method:

-

batch->cancel(&status);

+method:

+

batch->cancel(&status);

-Like -the rest of our data access interfaces Batch has special method to -close it:

-

batch->close(&status);

+Like the rest of our data +access interfaces Batch has special method to close it:

+

batch->close(&status);

-Standard -release() call may be used instead if one does not care about errors:

-

batch->release();

+Standard release() call may be +used instead if one does not care about errors:

+

batch->release();

-Described -methods help to implement all what one needs for JDBC-style prepared -statement batch operations. +Described methods help to +implement all what one needs for JDBC-style prepared statement batch +operations.

-


-
+


+ +

+

Notice: +JDBC does not recommend to use too large batches, for example “Oracle +recommends you to keep the batch sizes in the general range of 50 to +100”. Firebird supports bigger batches but it anyway has to +limit maximum batch size – see TAG_BUFFER_BYTES_SIZE. +If total size of messages exceeds that limit isc_batch_too_big error +is returned. Pay attention that due to deep buffering of batch data +when sending it over the wire you will not get this error at once but +only when buffers are flashed from client to server. This may happen +in both add() and execute() methods – execute() performs final +flash. If you still wish to execute the batch with the messages that +fit in a buffer you may do it (when error was returned by execute() +just repeat it). An actual number of processed messages will be +returned in BatchCompletionState. +An optimal batch size should be found for each particular case but +sooner of all having it >1000 hardly gives you serious performance +increase.

+


One can add more than @@ -1001,19 +1018,18 @@

Blobs -in general are not compatible with batches – batch is efficient -when one needs to pass a lot of small data to the server in single -step, blobs are treated as large objects and therefore in general it -makes no sense to use them in batches. But on practice it often -happens that blobs are not too big – and in this case use of -traditional blob API (create blob, pass segments to the server, close -blob, pass blobs ID in the message) kills performance, specially when -used over WAN. Therefore in firebird batch supports passing blobs to -server inline, together with other messages. To use that feature -first of all blob usage policy for a -batch to be created should be set (as an option in parameters -block):

+

Blobs in general are not +compatible with batches – batch is efficient when one needs to pass +a lot of small data to the server in single step, blobs are treated +as large objects and therefore in general it makes no sense to use +them in batches. But on practice it often happens that blobs are not +too big – and in this case use of traditional blob API (create +blob, pass segments to the server, close blob, pass blobs ID in the +message) kills performance, specially when used over WAN. Therefore +in firebird batch supports passing blobs to server inline, together +with other messages. To use that feature first of all blob +usage policy for a batch to be created should be set (as an +option in parameters block):

pb->insertInt(&status, IBatch::BLOB_IDS, IBatch::BLOB_IDS_ENGINE);

In @@ -1052,14 +1068,14 @@

batch->appendBlobData(&status, descriptionSize, descriptionText);

-

This -may be done in a loop but take care not to overflow internal batch -buffers – it’s size is controlled by BUFFER_BYTES_SIZE -option when creating batch interface but can’t exceed 40Mb (default -is 10Mb). If you need to process such big blob (for example on the +

This may be done in a loop +but take care not to overflow internal batch buffers – it’s size +is controlled by BUFFER_BYTES_SIZE option +when creating batch interface but can’t exceed 256Mb (default is +16Mb). If you need to process such big blob (for example on the background of a lot of small one – this can explain use of batch) just use standard blob API and registerBlob -method of Batch interface.

+method of Batch interface.

One more possible choice of blob policy is BLOB_IDS_USER. Usage at the first look does not change much – before calling addBlob() correct @@ -1071,17 +1087,16 @@

Please -take into an account – unlike blobs created using regular -createBlob() blobs created by Batch -interface are by default stream, not segmented. Segmented blobs -provide nothing interesting compared with stream one and therefore -not recommended to be used in new development, we support that format -only for backward compatibility reasons. If you really need segmented -blobs this default may be overridden by calling:

-

batch->setDefaultBpb(&status, -bpbLength, -bpb);

+

Please take into an account +– unlike blobs created using regular createBlob() +blobs created by Batch interface are by default +stream, not segmented. Segmented blobs provide nothing interesting +compared with stream one and therefore not recommended to be used in +new development, we support that format only for backward +compatibility reasons. If you really need segmented blobs this +default may be overridden by calling:

+

batch->setDefaultBpb(&status, +bpbLength, bpb);

Certainly passed BPB may contain any other blob creation parameters too. As you may have already noticed you may also pass BPB directly to addBlob() @@ -1091,13 +1106,12 @@

Next -step when working with existing blob streams is use of -addBlobStream() method. Using it one can add more than one blob to -the batch per single call. Blob stream is a sequence of blobs, each -starts with blob header. Header should be appropriately aligned - -Batch interface provides special call for this -purpose:

+

Next step when working with +existing blob streams is use of addBlobStream() method. Using it one +can add more than one blob to the batch per single call. Blob stream +is a sequence of blobs, each starts with blob header. Header should +be appropriately aligned - Batch interface +provides special call for this purpose:

unsigned alignment = batch->getBlobAlignment(&status);

It’s @@ -1126,15 +1140,14 @@

Last +

Last method used to work with blobs stands alone from the first three that -pass blob data inline with the rest of batch data – -it’s +pass blob data inline with the rest of batch data it’s needed to register in a batch ID of a blob created using standard blob API. This may be unavoidable if one needs to pass to a batch really big blob. Do not use ID of such blob in batch directly – that will cause invalid blob ID error during batch execution. Instead -do:

+do:

batch->registerBlob(&status, &realId, &msg->desc);

@@ -1319,6 +1332,16 @@

Using services.

svc->detach(&status);


+

+

+IService interface also +contains method cancel(). It’s needed to cancel wait in a query() +and is used internally by network server. Current implementation is +restricted – IService::cancel() is not supported by remote +redirector, only engine provider supports it. That means one can use +it only in embedded connections.

+


+

Writing @@ -1363,7 +1386,7 @@

Implementation of plugin loaded and must be notified if operating system tries to unload one of that modules without explicit plugin manager command (this may happen first of all when using embedded access – when exit() is -called in a program or main firebird library fbclient +called in a program or main firebird library fbclient is unloaded). Primary task of IPluginModule interface is that notification. First of all one must decide - how to detect that module is going to be unloaded? When @@ -1660,7 +1683,7 @@

Plugin module minimum case the function should register module and all factories in plugin manager:

extern -"C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* +"C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master)

{

IPluginManager* @@ -1821,8 +1844,8 @@

Generic interfaces.

add(StatusType* status, unsigned count, const void* inBuffer) – adds count messages from inBuffer to the batch. Total size of messages that can be added to the batch is - limited by BUFFER_BYTES_SIZE parameter of - batch creation.

+ limited by TAG_BUFFER_BYTES_SIZE parameter + of batch creation.

  • void addBlob(StatusType* status, unsigned length, const void* inBuffer, ISC_QUAD* blobId, unsigned bpbLength, const @@ -1832,7 +1855,7 @@

    Generic interfaces.

    passed (format matches one used in Attachment::createBlob).Total size of inline blobs that can be added to the batch (including optional BPBs, blob headers, segment sizes and taking into an - accoount alignment) is limited by BUFFER_BYTES_SIZE parameter + accoount alignment) is limited by TAG_BUFFER_BYTES_SIZE parameter of batch creation (affects all blob-oriented methods except registerBlob()).

    @@ -1887,33 +1910,49 @@

    Generic interfaces.

    char* par) – sets BPB which will be used for all blobs missing non-default BPB. Must be called before adding any message or blob to batch.

    +
  • void + getInfo(StatusType* status, unsigned itemsLength, const unsigned + char* items, unsigned bufferLength, unsigned char* buffer) – + requests information about batch.

    Tag for parameters block:

    VERSION1

    Tags for clumplets in parameters block:

    -

    MULTIERROR +

    TAG_MULTIERROR (0/1) – can have >1 message with errors

    -

    RECORD_COUNTS +

    TAG_RECORD_COUNTS (0/1) - per-message modified records accounting

    -

    BUFFER_BYTES_SIZE -(integer) - maximum possible buffer size (default 10Mb, maximum 40Mb)

    -

    BLOB_IDS +

    TAG_BUFFER_BYTES_SIZE +(integer) - maximum possible buffer size on server (default 16Mb, +maximum 256Mb)

    +

    TAG_BLOB_POLICY - policy used to store blobs

    -

    DETAILED_ERRORS +

    TAG_DETAILED_ERRORS (integer) - how many vectors with detailed error info are stored in completion state (default 64, maximum 256)

    Policies used to store blobs:

    -

    BLOB_IDS_NONE +

    BLOB_NONE – inline blobs can't be used (registerBlob() works anyway)

    -

    BLOB_IDS_ENGINE +

    BLOB_ID_ENGINE - blobs are added one by one, IDs are generated by firebird engine

    -

    BLOB_IDS_USER +

    BLOB_ID_USER - blobs are added one by one, IDs are generated by user

    -

    BLOB_IDS_STREAM -- blobs are added in a stream, IDs are generated by user

    +

    BLOB_STREAM +- blobs are added in a stream

    +

    Items +accepted in getInfo() call:

    +

    INF_BUFFER_BYTES_SIZE +– actual maximum +possible buffer size (one set by TAG_BUFFER_BYTES_SIZE)

    +

    INF_DATA_BYTES_SIZE +- already added messages size

    +

    INF_BLOBS_BYTES_SIZE +- already added blobs size

    +

    INF_BLOB_ALIGNMENT +- required alignment for the BLOB data (duplicates getBlobAlignment)


    @@ -2350,9 +2389,9 @@

    Generic interfaces.

  • unsigned getMessageLength(StatusType* status) - returns length of message buffer (use it to allocate memory for the buffer).

    -
  • unsigned +

  • unsigned getAlignment(StatusType* status) – returns alignment required for - message buffer.

    + message buffer.

  • unsigned getAlignedLength(StatusType* status) – returns length of message buffer taking into an account @@ -2670,6 +2709,9 @@

    Generic interfaces.

    start(StatusType* status, unsigned spbLength, const unsigned char* spb) – start utility in services manager. Replaces isc_service_start().

    +
  • void + cancel(StatusType* status) – cancel wait of current query() call. + Supported only for embedded connections.


    @@ -3021,8 +3063,8 @@

    Generic interfaces.

    decodeTimeTz(StatusType* status, const ISC_TIME_TZ* timeTz, unsigned* hours, unsigned* minutes, unsigned* seconds, unsigned*

    fractions, - unsigned timeZoneBufferLength, char* timeZoneBuffer) - – decode time taking time zone into an account.

    + unsigned timeZoneBufferLength, char* timeZoneBuffer) – decode time + taking time zone into an account.

  • void decodeTimeStampTz(StatusType* status, const ISC_TIMESTAMP_TZ* timeStampTz, unsigned* year, unsigned* month, unsigned* day, @@ -3564,13 +3606,24 @@

    Database encryption is passed in both directions. The source of a key receives dataLength bytes of data and may send up to bufferLength bytes into buffer returning actual number of bytes placed into buffer.

    +
  • + int getHashLength(StatusType* status) - returns length of hash of the keys provided by interface. + Hash is needed to let caller compare interfaces for equality. Empty (no keys) + interface should return hash length equal to zero. +

    +
  • + void getHashData(StatusType* status, void* hash) - places hash of the keys provided by interface + into memory location defined by parameter hash. Should copy exact number of bytes + returned by getHashLength() call. Hash algorithm is chosen by plugin author + (in year 2024 SHA256 appears reasonable choice). +


    DbCryptInfo interface is passed to DbCryptPlugin by engine. Plugin may save this -interface and use when needed to obtain additional informatio about +interface and use when needed to obtain additional information about database.

    1. const @@ -3766,4 +3819,4 @@

      Non-interface objects used

      - \ No newline at end of file + diff --git a/doc/sql.extensions/README.blob_append.md b/doc/sql.extensions/README.blob_append.md new file mode 100644 index 00000000000..e4a1140fef5 --- /dev/null +++ b/doc/sql.extensions/README.blob_append.md @@ -0,0 +1,132 @@ +-------------------- +BLOB_APPEND function +-------------------- + +Regular operator `||` (concatenation) with BLOB arguments creates temporary BLOB per every pair of arguments +with BLOB. This could lead to the excessive memory consumption and growth of database file. The `BLOB_APPEND` function is designed to concatenate BLOBs without creating intermediate BLOBs. + +In order to achieve this, the resulting BLOB is left open for writing instead of been closed immediately after it is filled with data. I.e. such blob could be appended as many times as required. Engine marks such blob with new internal flag `BLB_close_on_read` and closes it automatically when necessary. + +*Available in*: DSQL, PSQL. + +Syntax: + +`BLOB_APPEND( , ... )` + + +*Return type*: BLOB, temporary, not closed (i.e. open for writing), marked by flag `BLB_close_on_read`. + + +Input Arguments: + +- For the first argument, depending on its value, the following function behavior is defined: + + - NULL: a new empty non-closed BLOB will be created + - permanent BLOB (from table) or temporary already closed BLOB: + a new empty non-closed BLOB will be created and the contents the first BLOB will be added to it + - temporary non-closed BLOB: it will be used later + - other data types are converted to a string, a temporary non-closed BLOB will be created with the contents of this string + +- Other arguments can be of any type. The following behavior is defined for them: + - NULLs are ignored + - non-BLOBs are converted to string (as usual) and appended to the content of the result + - BLOBs, if necessary, are transliterated to the character set of the first argument and their contents are appended to the result + +The `BLOB_APPEND` function returns a temporary non-closed BLOB as output. +This is either a new BLOB or the same one that was in the first argument. Thus, a series of operations of the form +`blob = BLOB_APPEND(blob, ...)` will result in at most one BLOB being created (unless trying to append the BLOB to itself). +This BLOB will be automatically closed by the engine when it is attempted to be read by a client, written to a table, or used in other expressions that require the content to be read. + +Note: + +Testing a BLOB for a NULL value with the `IS [NOT] NULL` operator does not read it, and therefore a temporary open BLOB will not be closed by such tests. + +``` +execute block +returns (b blob sub_type text) +as +begin + -- will create a new temporary not closed BLOB + -- and will write to it the string from the 2nd argument + b = blob_append(null, 'Hello '); + -- adds two strings to the temporary BLOB without closing it + b = blob_append(b, 'World', '!'); + -- comparing a BLOB with a string will close it, because for this you need to read the BLOB + if (b = 'Hello World!') then + begin + -- ... + end + -- will create a temporary closed BLOB by adding a string to it + b = b || 'Close'; + suspend; +end +``` + +Tip: + +Use the `LIST` and` BLOB_APPEND` functions to concatenate BLOBs. This will save memory consumption, disk I/O, +and prevent database growth due to the creation of many temporary BLOBs when using concatenation operators. + +Example: + +Let's say you need to build JSON on the server side. We have a PSQL package JSON_UTILS with a set of functions for converting primitive data types to JSON notation. +Then the JSON building using the `BLOB_APPEND` function will look like this: + +``` +EXECUTE BLOCK +RETURNS ( + JSON_STR BLOB SUB_TYPE TEXT CHARACTER SET UTF8) +AS + DECLARE JSON_M BLOB SUB_TYPE TEXT CHARACTER SET UTF8; +BEGIN + FOR + SELECT + HORSE.CODE_HORSE, + HORSE.NAME, + HORSE.BIRTHDAY + FROM HORSE + WHERE HORSE.CODE_DEPARTURE = 15 + FETCH FIRST 1000 ROW ONLY + AS CURSOR C + DO + BEGIN + SELECT + LIST( + '{' || + JSON_UTILS.NUMERIC_PAIR('age', MEASURE.AGE) || + ',' || + JSON_UTILS.NUMERIC_PAIR('height', MEASURE.HEIGHT_HORSE) || + ',' || + JSON_UTILS.NUMERIC_PAIR('length', MEASURE.LENGTH_HORSE) || + ',' || + JSON_UTILS.NUMERIC_PAIR('chestaround', MEASURE.CHESTAROUND) || + ',' || + JSON_UTILS.NUMERIC_PAIR('wristaround', MEASURE.WRISTAROUND) || + ',' || + JSON_UTILS.NUMERIC_PAIR('weight', MEASURE.WEIGHT_HORSE) || + '}' + ) AS JSON_M + FROM MEASURE + WHERE MEASURE.CODE_HORSE = :C.CODE_HORSE + INTO JSON_M; + + JSON_STR = BLOB_APPEND( + JSON_STR, + IIF(JSON_STR IS NULL, '[', ',' || ascii_char(13)), + '{', + JSON_UTILS.INTEGER_PAIR('code_horse', C.CODE_HORSE), + ',', + JSON_UTILS.STRING_PAIR('name', C.NAME), + ',', + JSON_UTILS.TIMESTAMP_PAIR('birthday', C.BIRTHDAY), + ',', + JSON_UTILS.STRING_VALUE('measures') || ':[', JSON_M, ']', + '}' + ); + END + JSON_STR = BLOB_APPEND(JSON_STR, ']'); + SUSPEND; +END +``` + +A similar example using the usual concatenation operator `||` is an order of magnitude slower and does 1000 times more disk writes. diff --git a/doc/sql.extensions/README.builtin_functions.txt b/doc/sql.extensions/README.builtin_functions.txt index 4e69d59184d..9ddca3f2c6f 100644 --- a/doc/sql.extensions/README.builtin_functions.txt +++ b/doc/sql.extensions/README.builtin_functions.txt @@ -485,7 +485,7 @@ Important: Example: select encrypt('897897' using sober128 key 'AbcdAbcdAbcdAbcd' iv '01234567') from rdb$database; - select decrypt(x'0154090759DF' using sober128 key 'AbcdAbcdAbcdAbcd' iv '01234567') from rdb$database; + select cast(decrypt(x'0154090759DF' using sober128 key 'AbcdAbcdAbcdAbcd' iv '01234567') as varchar(128)) from rdb$database; select decrypt(secret_field using aes mode ofb key '0123456701234567' iv init_vector) from secure_table; @@ -1069,11 +1069,13 @@ Function: short symmetric keys which are then used in block ciphers to encrypt a message. Format: - RSA_ENCRYPT ( KEY [LPARAM ] [HASH ] ) + RSA_ENCRYPT ( KEY [LPARAM ] [HASH ] [PKCS_1_5] ) KEY should be a value, returhed by RSA_PUBLIC function. LPARAM is an additional system specific tag that can be applied to identify which system encoded the message. Default value is NULL. hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256. + PKCS_1_5 makes engine use old padding, needed for backward compatibility. + Due to security reasons should NOT be used in new projects. Example: (tip - start running samples one by one from RSA_PRIVATE function) @@ -1089,57 +1091,61 @@ Function: Decrypts using RSA private key and OAEP de-pads the resulting data. Format: - RSA_DECRYPT ( KEY [LPARAM ] [HASH ] ) + RSA_DECRYPT ( KEY [LPARAM ] [HASH ] [PKCS_1_5] ) KEY should be a value, returhed by RSA_PRIVATE function. LPARAM is the same variable passed to RSA_ENCRYPT. If it does not match what was used during encoding this function will not decrypt the packet. hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256. + PKCS_1_5 makes engine use old padding, needed for backward compatibility. + Due to security reasons should NOT be used in new projects. Example: (tip - start running samples one by one from RSA_PRIVATE function) - select rsa_decrypt(rdb$get_context('USER_SESSION', 'msg') - key rdb$get_context('USER_SESSION', 'private_key')) from rdb$database; + select cast(rsa_decrypt(rdb$get_context('USER_SESSION', 'msg') + key rdb$get_context('USER_SESSION', 'private_key')) as varchar(128)) from rdb$database; --------- -RSA_SIGN --------- +------------- +RSA_SIGN_HASH +------------- Function: Performs PSS encoding of message digest to be signed and signs using RSA private key. Format: - RSA_SIGN ( KEY [HASH ] [SALT_LENGTH ] ) + RSA_SIGN_HASH ( KEY [HASH ] [SALT_LENGTH ] [PKCS_1_5] ) KEY should be a value, returhed by RSA_PRIVATE function. hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256. SALT_LENGTH indicates the length of the desired salt, and should typically be small. A good value is between 8 and 16. + PKCS_1_5 makes engine use old padding, needed for backward compatibility. Example: (tip - start running samples one by one from RSA_PRIVATE function) - select rdb$set_context('USER_SESSION', 'msg', rsa_sign(hash('Test message' using sha256) + select rdb$set_context('USER_SESSION', 'msg', rsa_sign_hash(crypt_hash('Test message' using sha256) key rdb$get_context('USER_SESSION', 'private_key'))) from rdb$database; ----------- -RSA_VERIFY ----------- +--------------- +RSA_VERIFY_HASH +--------------- Function: Performs PSS encoding of message digest to be signed and verifies it's digital signature using RSA public key. Format: - RSA_VERIFY ( SIGNATURE KEY [HASH ] [SALT_LENGTH ] ) + RSA_VERIFY_HASH ( SIGNATURE KEY [HASH ] [SALT_LENGTH ] [PKCS_1_5] ) SIGNATURE should be a value, returhed by RSA_SIGN function. KEY should be a value, returhed by RSA_PUBLIC function. hash ::= { MD5 | SHA1 | SHA256 | SHA512 } Default is SHA256. SALT_LENGTH indicates the length of the desired salt, and should typically be small. A good value is between 8 and 16. + PKCS_1_5 makes engine use old padding, needed for backward compatibility. Example: (tip - start running samples one by one from RSA_PRIVATE function) - select rsa_verify(hash('Test message' using sha256) signature rdb$get_context('USER_SESSION', 'msg') + select rsa_verify_hash(crypt_hash('Test message' using sha256) signature rdb$get_context('USER_SESSION', 'msg') key rdb$get_context('USER_SESSION', 'public_key')) from rdb$database; diff --git a/doc/sql.extensions/README.context_variables2 b/doc/sql.extensions/README.context_variables2 index 5ef0fff719a..9d0892d370a 100644 --- a/doc/sql.extensions/README.context_variables2 +++ b/doc/sql.extensions/README.context_variables2 @@ -70,10 +70,14 @@ Usage: CLIENT_HOST | The wire protocol host name of remote client. Value is | returned for all supported protocols. | + CLIENT_OS_USER | Remote OS user name + | CLIENT_PID | Process ID of remote client application | CLIENT_PROCESS | Process name of remote client application | + CLIENT_VERSION | Version of the client library used by client application + | DB_NAME | Canonical name of current database. It is either alias | name if connectivity via file names is not allowed or | fully expanded database file name otherwise. diff --git a/doc/sql.extensions/README.ddl.txt b/doc/sql.extensions/README.ddl.txt index 48ded29b416..e57c2f50594 100644 --- a/doc/sql.extensions/README.ddl.txt +++ b/doc/sql.extensions/README.ddl.txt @@ -557,6 +557,7 @@ GRANT_REVOKE_ANY_DDL_RIGHT GRANT and REVOKE any DDL rights CREATE_PRIVILEGED_ROLES Use SET SYSTEM PRIVILEGES in roles MODIFY_EXT_CONN_POOL Manage properties of pool of external connections REPLICATE_INTO_DATABASE Use replication API to load changesets into database +GET_DBCRYPT_INFO Use getInfo() items, related with DB encryption 22) New grantee type in GRANT and REVOKE operators - SYSTEM PRIVILEGE. diff --git a/doc/sql.extensions/README.identity_columns.txt b/doc/sql.extensions/README.identity_columns.txt index 1f68eb16615..8bce9143028 100644 --- a/doc/sql.extensions/README.identity_columns.txt +++ b/doc/sql.extensions/README.identity_columns.txt @@ -100,7 +100,6 @@ following: insert into objects (id, name) overriding system value values (11, 'Laptop'); -OVERRIDING also supports a subclause to be used with BY DEFAULT columns, to ignore the value passed in INSERT and use -the defined sequence: +OVERRIDING also supports a subclause to ignore the value passed in INSERT and use the defined sequence: insert into objects (id, name) overriding user value values (12, 'Laptop'); -- 12 is not used diff --git a/doc/sql.extensions/README.keywords b/doc/sql.extensions/README.keywords index 6dae3f5b21f..570bdb6f588 100644 --- a/doc/sql.extensions/README.keywords +++ b/doc/sql.extensions/README.keywords @@ -363,8 +363,8 @@ Firebird 4.0 RSA_ENCRYPT * RSA_PRIVATE * RSA_PUBLIC * - RSA_SIGN * - RSA_VERIFY * + RSA_SIGN_HASH * + RSA_VERIFY_HASH * SALT_LENGTH * SECURITY SESSION diff --git a/doc/sql.extensions/README.time_zone.md b/doc/sql.extensions/README.time_zone.md index 5480cb1536f..9ed01fdb8c2 100644 --- a/doc/sql.extensions/README.time_zone.md +++ b/doc/sql.extensions/README.time_zone.md @@ -8,11 +8,13 @@ data types are defined to use the session time zone when converting from or to a `TIME` and `TIMESTAMP` are synonymous to theirs respectively `WITHOUT TIME ZONE` data types. The session time zone, as the name implies, can be a different one for each database attachment. -It can be set with the isc_dpb_session_time_zone DPB, and if not, it starts by default defined to be the -`firebird.conf` parameter `DefaultTimeZone` or the same time zone used by the Firebird OS process when the parameter is not defined. +It can be set (with this priority) using `isc_dpb_session_time_zone` DPB, the client's `firebird.conf` +parameter `DefaultTimeZone` and the server's `firebird.conf` parameter `DefaultTimeZone`. If none of these are set, +it starts using the same time zone used by the Firebird engine OS process. A change in `DefaultTimeZone` configuration or the OS time zone does not changes the default of a running Firebird process. -It can then be changed with `SET TIME ZONE` statement to a given time zone or reset to its original value with `SET TIME ZONE LOCAL`. +The session time zone can be changed with `SET TIME ZONE` statement to a given time zone or reset to its original value +with `SET TIME ZONE LOCAL`. The original time zone value is initially defined equal to the current time zone in session initialization and cannot be changed manually. But the original time zone is internally changed when a routine (function, procedure or trigger) @@ -57,7 +59,7 @@ But Firebird also supports region-based time zones in `TIME WITH TIME ZONE` valu When constructing a `TIME WITH TIME ZONE` value from a literal or conversion its UTC value must be computed and cannot be changed, so the current date may not be used. In this case the fixed date `2020-01-01` is used. So when comparing `TIME WITH TIME ZONE` with different time zones the -comparation is done is a manner similar to they being `TIMESTAMP WITH TIME ZONE` values in the +comparation is done in a manner similar to they being `TIMESTAMP WITH TIME ZONE` values in the given date. However when converting between `TIMESTAMP` types to `TIME WITH TIME ZONE` that fixed date is diff --git a/examples/dbcrypt/CryptApplication.cpp b/examples/dbcrypt/CryptApplication.cpp index 6d29215bf0c..f1418601839 100644 --- a/examples/dbcrypt/CryptApplication.cpp +++ b/examples/dbcrypt/CryptApplication.cpp @@ -36,14 +36,28 @@ class CryptKey : public ICryptKeyCallbackImpl { if (length > 0 && buffer) { - char k = 0x5a; memcpy(buffer, &k, 1); fprintf(stderr, "\nTransfered key to server\n"); } return 1; } + + int getHashLength(Firebird::CheckStatusWrapper* status) override + { + return 1; + } + + void getHashData(Firebird::CheckStatusWrapper* status, void* h) override + { + memcpy(h, &k, 1); + } + +private: + static const char k; }; +const char CryptKey::k = 0x5a; + class App { public: diff --git a/examples/dbcrypt/CryptKeyHolder.cpp b/examples/dbcrypt/CryptKeyHolder.cpp index bc79942238b..cdb396788e0 100644 --- a/examples/dbcrypt/CryptKeyHolder.cpp +++ b/examples/dbcrypt/CryptKeyHolder.cpp @@ -69,7 +69,7 @@ class CryptKeyHolder : public IKeyHolderPluginImplgetStatus()), - config(cnf), key(0), owner(NULL) + config(cnf), key(0), init(false), owner(NULL) { config->addRef(); } @@ -110,10 +110,13 @@ class CryptKeyHolder : public IKeyHolderPluginImplgetKey(); + const ISC_UCHAR& k = holder->getKey(); if (!k) { return 0; @@ -152,6 +155,36 @@ class CryptKeyHolder : public IKeyHolderPluginImplgetKey(); + if (!k) + { + ISC_STATUS err[] = {isc_arg_gds, isc_wish_list}; + status->setErrors2(2, err); + + return -1; + } + + return 1; + } + + void getHashData(Firebird::CheckStatusWrapper* status, void* h) override + { + // here key value is returned by hash function as is + // do not do it in production - use some hash function + const ISC_UCHAR& k = holder->getKey(); + if (!k) + { + ISC_STATUS err[] = {isc_arg_gds, isc_wish_list}; + status->setErrors2(2, err); + + return; + } + + memcpy(h, &k, 1); + } + private: CryptKeyHolder* holder; }; @@ -172,6 +205,18 @@ class CryptKeyHolder : public IKeyHolderPluginImplgetPluginManager(); diff --git a/examples/dbcrypt/DbCrypt.cpp b/examples/dbcrypt/DbCrypt.cpp index fcfc1ba3f44..6b0260eb276 100644 --- a/examples/dbcrypt/DbCrypt.cpp +++ b/examples/dbcrypt/DbCrypt.cpp @@ -266,7 +266,7 @@ Factory factory; } // anonymous namespace -extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master) { IPluginManager* pluginManager = master->getPluginManager(); diff --git a/examples/dbcrypt/fbSampleKeyHolder.conf b/examples/dbcrypt/fbSampleKeyHolder.conf index d1eac947e72..7daa82b95a1 100644 --- a/examples/dbcrypt/fbSampleKeyHolder.conf +++ b/examples/dbcrypt/fbSampleKeyHolder.conf @@ -7,7 +7,7 @@ # Key - integer value, a key used to "encrypt" database (i.e. when one issues "ALTER DATABASE ENCRYPT ..." # without KEY clause configuration parameter Key is used). This key can be passed from client to server -by the chain of sample key holders. +# by the chain of sample key holders. #Key = 90 diff --git a/examples/dbcrypt/msvc/DbCryptApp_MSVC15.vcxproj b/examples/dbcrypt/msvc/DbCryptApp_MSVC15.vcxproj index 4b3d413230e..e5007f05b31 100644 --- a/examples/dbcrypt/msvc/DbCryptApp_MSVC15.vcxproj +++ b/examples/dbcrypt/msvc/DbCryptApp_MSVC15.vcxproj @@ -22,32 +22,42 @@ 15.0 {D702CB26-9FB9-4A6F-B2F8-EF9961578B70} DbCrypt - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 Application true - v141_xp + v141_xp + v142 + v143 MultiByte Application false - v141_xp + v141_xp + v142 + v143 true MultiByte Application true - v141 + v141 + v142 + v143 MultiByte Application false - v141 + v141 + v142 + v143 true MultiByte @@ -163,4 +173,4 @@ - \ No newline at end of file + diff --git a/examples/dbcrypt/msvc/DbCrypt_MSVC15.vcxproj b/examples/dbcrypt/msvc/DbCrypt_MSVC15.vcxproj index eecf3f9301c..8292726697f 100644 --- a/examples/dbcrypt/msvc/DbCrypt_MSVC15.vcxproj +++ b/examples/dbcrypt/msvc/DbCrypt_MSVC15.vcxproj @@ -22,32 +22,42 @@ 15.0 {7F94BDD8-ED23-437E-9890-485052F14166} DbCrypt - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary true - v141_xp + v141_xp + v142 + v143 MultiByte DynamicLibrary false - v141_xp + v141_xp + v142 + v143 true MultiByte DynamicLibrary true - v141 + v141 + v142 + v143 MultiByte DynamicLibrary false - v141 + v141 + v142 + v143 true MultiByte @@ -158,4 +168,4 @@ - \ No newline at end of file + diff --git a/examples/dbcrypt/msvc/KeyHolder_MSVC15.vcxproj b/examples/dbcrypt/msvc/KeyHolder_MSVC15.vcxproj index 9a4bad94259..c5817df397e 100644 --- a/examples/dbcrypt/msvc/KeyHolder_MSVC15.vcxproj +++ b/examples/dbcrypt/msvc/KeyHolder_MSVC15.vcxproj @@ -22,32 +22,42 @@ 15.0 {17D033E3-0764-4E6D-859E-FA42977A84CA} DbCrypt - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary true - v141_xp + v141_xp + v142 + v143 MultiByte DynamicLibrary false - v141_xp + v141_xp + v142 + v143 true MultiByte DynamicLibrary true - v141 + v141 + v142 + v143 MultiByte DynamicLibrary false - v141 + v141 + v142 + v143 true MultiByte @@ -158,4 +168,4 @@ - \ No newline at end of file + diff --git a/examples/extauth/ExtAuth.cpp b/examples/extauth/ExtAuth.cpp index 5c3c5efd4d5..56926575f6e 100644 --- a/examples/extauth/ExtAuth.cpp +++ b/examples/extauth/ExtAuth.cpp @@ -435,13 +435,7 @@ Factory serverFactory; } // anonymous namespace -#if defined(_WIN32) -#define FB_DLL_EXPORT __declspec(dllexport) -#else -#define FB_DLL_EXPORT -#endif - -extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* m) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* m) { master = m; IPluginManager* pluginManager = master->getPluginManager(); diff --git a/examples/extauth/msvc/ExtAuth_MSVC15.vcxproj b/examples/extauth/msvc/ExtAuth_MSVC15.vcxproj index b738dc4e06a..d63b18cfa20 100644 --- a/examples/extauth/msvc/ExtAuth_MSVC15.vcxproj +++ b/examples/extauth/msvc/ExtAuth_MSVC15.vcxproj @@ -22,33 +22,43 @@ 15.0 {6DAB6DFA-D754-4698-876E-40ECF688AA07} ExtAuth - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 ExtAuth DynamicLibrary true - v141_xp + v141_xp + v142 + v143 MultiByte DynamicLibrary false - v141_xp + v141_xp + v142 + v143 true MultiByte DynamicLibrary true - v141 + v141 + v142 + v143 MultiByte DynamicLibrary false - v141 + v141 + v142 + v143 true MultiByte @@ -95,9 +105,9 @@ Level3 Disabled true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -111,9 +121,9 @@ Level3 Disabled true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -129,9 +139,9 @@ true true true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -149,9 +159,9 @@ true true true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console diff --git a/examples/extauth/msvc/KeyGen_MSVC15.vcxproj b/examples/extauth/msvc/KeyGen_MSVC15.vcxproj index 5f8cbc908ce..6439e904a51 100644 --- a/examples/extauth/msvc/KeyGen_MSVC15.vcxproj +++ b/examples/extauth/msvc/KeyGen_MSVC15.vcxproj @@ -22,33 +22,43 @@ 15.0 {A3AB86E1-D9E1-4B6B-B5E7-59524CB2602A} KeyGen - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 KeyGen Application true - v141_xp + v141_xp + v142 + v143 MultiByte Application false - v141_xp + v141_xp + v142 + v143 true MultiByte Application true - v141 + v141 + v142 + v143 MultiByte Application false - v141 + v141 + v142 + v143 true MultiByte @@ -73,31 +83,31 @@ ..\..\prebuilt\$(Platform)\$(Configuration)\bin\ ..\..\..\temp\$(PlatformName)\$(Configuration)\examples\$(ProjectName)\ - fbSampleExtAuthKeygen + fbSampleExtAuthKeygen ..\..\prebuilt\$(Platform)\$(Configuration)\bin\ ..\..\..\temp\$(PlatformName)\$(Configuration)\examples\$(ProjectName)\ - fbSampleExtAuthKeygen + fbSampleExtAuthKeygen ..\..\prebuilt\$(Platform)\$(Configuration)\bin\ ..\..\..\temp\$(PlatformName)\$(Configuration)\examples\$(ProjectName)\ - fbSampleExtAuthKeygen + fbSampleExtAuthKeygen ..\..\prebuilt\$(Platform)\$(Configuration)\bin\ ..\..\..\temp\$(PlatformName)\$(Configuration)\examples\$(ProjectName)\ - fbSampleExtAuthKeygen + fbSampleExtAuthKeygen Level3 Disabled true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -110,9 +120,9 @@ Level3 Disabled true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -127,9 +137,9 @@ true true true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -146,9 +156,9 @@ true true true - true + false ..\..\..\src\include\;..\..\..\extern\libtomcrypt\src\headers\ - _CRT_SECURE_NO_WARNINGS;LTM_DESC + _CRT_SECURE_NO_WARNINGS;LTM_DESC;WIN32 Console @@ -168,4 +178,4 @@ - \ No newline at end of file + diff --git a/examples/interfaces/06.fb_message.cpp b/examples/interfaces/06.fb_message.cpp index cc6b4c7e563..24ce32d02f1 100644 --- a/examples/interfaces/06.fb_message.cpp +++ b/examples/interfaces/06.fb_message.cpp @@ -36,6 +36,7 @@ static IMaster* master = fb_get_master_interface(); static IDecFloat16* idf16 = NULL; +static IInt128* ii128 = NULL; int main() { @@ -56,6 +57,7 @@ int main() try { idf16 = master->getUtilInterface()->getDecFloat16(&status); + ii128 = master->getUtilInterface()->getInt128(&status); att = prov->attachDatabase(&status, dbName, 0, NULL); tra = att->startTransaction(&status, 0, NULL); @@ -79,6 +81,7 @@ int main() (FB_VARCHAR(31), relationName) (FB_VARCHAR(100), description) (FB_DECFLOAT16, df16) + (FB_INT128, iHuge) ) output(&status, master); input.clear(); @@ -86,25 +89,28 @@ int main() rs = att->openCursor(&status, tra, 0, "select rdb$relation_id, rdb$relation_name, rdb$description," - " cast (rdb$relation_id as decfloat(16)) * 0.05 as df16" + " cast (rdb$relation_id as decfloat(16)) * 0.05 as df16," + " cast (rdb$relation_id as int128) * 212778764464767 as iHuge" " from rdb$relations" " where rdb$system_flag = ?" " order by rdb$relation_id", SAMPLES_DIALECT, input.getMetadata(), input.getData(), output.getMetadata(), NULL, 0); - printf(" ID Name/comment\n"); + printf(" ID Name datatype-tests (perform some arithmetics) /comment\n"); while (rs->fetchNext(&status, output.getData()) == IStatus::RESULT_OK) { unsigned lRelName = output->relationNameNull ? 0 : output->relationName.length; unsigned lDesc = output->descriptionNull ? 0 : output->description.length; char t16[IDecFloat16::STRING_SIZE]; idf16->toString(&status, &output->df16, sizeof(t16), t16); + char huge[IInt128::STRING_SIZE]; + ii128->toString(&status, &output->iHuge, -3, sizeof(huge), huge); - printf("%4d %*.*s%c%*.*s (%s)\n", output->relationId, + printf("%4d %*.*s [Decfloat16:%s Int128:%s] %c%*.*s\n", output->relationId, lRelName, lRelName, output->relationName.str, + t16, huge, lDesc ? '/' : ' ', - lDesc, lDesc, output->description.str, - t16); + lDesc, lDesc, output->description.str); } rs->close(&status); diff --git a/examples/interfaces/11.batch.cpp b/examples/interfaces/11.batch.cpp index d4925975e1a..85180376832 100644 --- a/examples/interfaces/11.batch.cpp +++ b/examples/interfaces/11.batch.cpp @@ -114,6 +114,53 @@ unsigned putSegment(unsigned char*& ptr, const char* testData) return align(l + sizeof l, IBatch::BLOB_SEGHDR_ALIGN); } +// batch info printer - prints what we know about batch + +static void printInfo(ThrowStatusWrapper& status, const char* hdr, IBatch* b, IUtil* utl) +{ + printf("\n%s\n", hdr); + + const unsigned char items[] = {IBatch::INF_BLOB_ALIGNMENT, IBatch::INF_BUFFER_BYTES_SIZE, + IBatch::INF_DATA_BYTES_SIZE, IBatch::INF_BLOBS_BYTES_SIZE}; + unsigned char buffer[29]; + b->getInfo(&status, sizeof items, items, sizeof buffer, buffer); + + IXpbBuilder* pb = utl->getXpbBuilder(&status, IXpbBuilder::INFO_RESPONSE, buffer, sizeof buffer); + for (pb->rewind(&status); !pb->isEof(&status); pb->moveNext(&status)) + { + int val = pb->getInt(&status); + const char* text = "Unknown tag"; + switch (pb->getTag(&status)) + { + case IBatch::INF_BLOB_ALIGNMENT: + text = "Blob alignment"; + break; + case IBatch::INF_BUFFER_BYTES_SIZE: + text = "Buffer size"; + break; + case IBatch::INF_DATA_BYTES_SIZE: + text = "Messages size"; + break; + case IBatch::INF_BLOBS_BYTES_SIZE: + text = "Blobs size"; + break; + case isc_info_truncated: + printf(" truncated\n"); + // fall down... + case isc_info_end: + pb->dispose(); + return; + default: + printf("Unexpected item %d\n", pb->getTag(&status)); + pb->dispose(); + return; + } + + printf("%s = %d\n", text, val); + } + pb->dispose(); +} + // BatchCompletionState printer - prints all what we know about completed batch static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUtil* utl) @@ -134,7 +181,7 @@ static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUti case IBatchCompletionState::EXECUTE_FAILED: if (!pr1) { - printf("Message Status\n", p); + printf("Message Status\n"); pr1 = true; } printf("%5u Execute failed\n", p); @@ -147,7 +194,7 @@ static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUti default: if (!pr1) { - printf("Message Status\n", p); + printf("Message Status\n"); pr1 = true; } printf("%5u Updated %d record(s)\n", p, s); @@ -157,7 +204,7 @@ static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUti } printf("Summary: total=%u success=%u success(but no update info)=%u\n", upcount, succ, unk); - // 2. Print detailed errors (if exist) for messages + // 2. Print detailed errors (if exist) for messages s2 = master->getStatus(); for(p = 0; (p = cs->findError(&status, p)) != IBatchCompletionState::NO_MORE_ERRORS; ++p) @@ -171,7 +218,7 @@ static void print_cs(ThrowStatusWrapper& status, IBatchCompletionState* cs, IUti text[sizeof(text) - 1] = 0; if (!pr2) { - printf("\nDetailed errors status:\n", p); + printf("\nDetailed errors status:\n"); pr2 = true; } printf("Message %u: %s\n", p, text); @@ -270,6 +317,9 @@ int main() batch->add(&status, 1, project1.getData()); } + // check batch state + printInfo(status, "Info when added many records", batch, utl); + // ... and cancel that records batch->cancel(&status); @@ -347,6 +397,8 @@ int main() batch->appendBlobData(&status, strlen(sqlStmt1), sqlStmt1); batch->add(&status, 1, project2.getData()); + printInfo(status, "Info with blob", batch, utl); + // execute it cs = batch->execute(&status, tra); print_cs(status, cs, utl); diff --git a/examples/interfaces/14.restore.cpp b/examples/interfaces/14.restore.cpp new file mode 100644 index 00000000000..1ab67bccd91 --- /dev/null +++ b/examples/interfaces/14.restore.cpp @@ -0,0 +1,172 @@ +/* + * PROGRAM: Object oriented API samples. + * MODULE: 14.restore.cpp + * DESCRIPTION: A sample of making restore of database using service manager. + * + * Example for the following interfaces: + * IService - interface to work with service manager. + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Alexander Peshkoff + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2016 Alexander Peshkoff + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + */ + +#include "ifaceExamples.h" + +static IMaster* master = fb_get_master_interface(); + +// print information, returned by isc_svc_query() call + +bool printLine(const unsigned char*& p) +{ + const ISC_USHORT length = (ISC_USHORT) isc_vax_integer((char*) p, sizeof(ISC_USHORT)); + p += sizeof(ISC_USHORT); + if (length > 0) + printf("%*.*s\n", length, length, p); + p += length; + return length > 0; +} + +bool printInfo(const unsigned char* p, size_t pSize) +{ + bool ret = false; + bool ignoreTruncation = false; + const unsigned char* const end = p + pSize; + + while (p < end && *p != isc_info_end) + { + switch (*p++) + { + case isc_info_svc_line: + ret = printLine(p); + break; + + case isc_info_truncated: + if (!ignoreTruncation) + printf("\n<<< truncated >>>\n"); + + fflush(stdout); + ret = true; + break; + + case isc_info_svc_timeout: + case isc_info_data_not_ready: + ret = true; + break; + + default: + printf("Unknown item 0x%x in received buffer\n", p[-1]); + } + } + + fflush(stdout); + return ret; +} + + +int main() +{ + int rc = 0; + + // Status wrapper + ThrowStatusWrapper status(master->getStatus()); + + // Declare pointers to required interfaces + IProvider* prov = master->getDispatcher(); + IUtil* utl = master->getUtilInterface(); + IService* svc = NULL; + IXpbBuilder* spb1 = NULL; + IXpbBuilder* spb2 = NULL; + + try + { + printf("** Attaching to service manager...\n"); + + // Prepare SPB to attach to service manager + spb1 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_ATTACH, NULL, 0); + spb1->insertString(&status, isc_spb_user_name, "sysdba"); + spb1->insertString(&status, isc_spb_password, "masterkey"); + + // Attach to service manager + svc = prov->attachServiceManager(&status, "service_mgr", spb1->getBufferLength(&status), + spb1->getBuffer(&status)); + + // In the simplest case sendItems parameter may be NULL + // Building receiveItems is mostly trivial + //const unsigned char receiveItems[] = {isc_info_svc_server_version}; + + // Output buffer + unsigned char results[1024]; + + printf("** Demo of making restore using service manager...\n"); + + // Build service start SPB + spb2 = utl->getXpbBuilder(&status, IXpbBuilder::SPB_START, NULL, 0); + spb2->insertTag(&status, isc_action_svc_restore); + spb2->insertString(&status, isc_spb_dbname, "employee-restored.fdb"); + spb2->insertString(&status, isc_spb_bkp_file, "employee.fbk"); + spb2->insertInt(&status, isc_spb_options, isc_spb_res_create); + + // Start service + svc->start(&status, spb2->getBufferLength(&status), spb2->getBuffer(&status)); + + // Prepare receiveItems block + const unsigned char receiveItems2[] = {isc_info_svc_line}; + + // Query service output + do + { + svc->query(&status, 0, NULL, sizeof(receiveItems2), receiveItems2, sizeof(results), results); + } while (printInfo(results, sizeof(results))); + + printf("** Detaching from service manager...\n"); + + // Detach from service manager + svc->detach(&status); + svc = NULL; + + printf("** Done.\n"); + } + catch (const FbException& error) + { + // handle error + rc = 1; + + char buf[256]; + master->getUtilInterface()->formatStatus(buf, sizeof(buf), error.getStatus()); + fprintf(stderr, "%s\n", buf); + } + + // release interfaces after error caught + if (svc) + svc->release(); + + // generic cleanup + prov->release(); + status.dispose(); + + if (spb1) + spb1->dispose(); + + if (spb2) + spb2->dispose(); + + return rc; +} diff --git a/examples/interfaces/ifaceExamples.h b/examples/interfaces/ifaceExamples.h index da349264dc9..cfcb1f9dca3 100644 --- a/examples/interfaces/ifaceExamples.h +++ b/examples/interfaces/ifaceExamples.h @@ -37,14 +37,6 @@ typedef int FbSampleAtomic; #include -#if defined(_WIN32) -#define FB_DLL_EXPORT __declspec(dllexport) -#elif defined(__APPLE__) -#define FB_DLL_EXPORT __attribute__((visibility("default"))) -#else -#define FB_DLL_EXPORT -#endif - using namespace Firebird; #define SAMPLES_DIALECT SQL_DIALECT_V6 diff --git a/examples/interfaces/makefile b/examples/interfaces/makefile index 153c3d558dc..a4e4f05454e 100644 --- a/examples/interfaces/makefile +++ b/examples/interfaces/makefile @@ -72,6 +72,7 @@ all: $(OUTBIN) 11.batch.o: 11.batch.cpp 12.batch_isc.o: 12.batch_isc.cpp 13.null_pk.o: 13.null_pk.cpp +14.restore.o: 14.restore.cpp # clean up clean: diff --git a/examples/object_pascal/Readme.md b/examples/object_pascal/Readme.md index 6c30083d98d..8d8cbf73c07 100644 --- a/examples/object_pascal/Readme.md +++ b/examples/object_pascal/Readme.md @@ -40,9 +40,10 @@ you would do the following to create a project from 03.select.pas: - Open select.lpr as a project - When prompted choose 'Simple Program' as the project template - Go into Project options and add the following paths: - /opt/firebird/include/Firebird +``` + /usr/include/Firebird common - +``` You can then compile and run the example through the debugger. diff --git a/examples/readme b/examples/readme index c0b19612f83..592c7cf480f 100644 --- a/examples/readme +++ b/examples/readme @@ -172,6 +172,7 @@ Program Description 12.batch_isc.cpp Working with batch interface from ISC API. +14.restore.cpp Using services: restore database. FbSampleAtomic typedef required in many examples. diff --git a/examples/replication/fbSampleReplicator.cpp b/examples/replication/fbSampleReplicator.cpp index fa8f63232b7..fcf59537b20 100644 --- a/examples/replication/fbSampleReplicator.cpp +++ b/examples/replication/fbSampleReplicator.cpp @@ -100,14 +100,7 @@ class Factory : public IPluginFactoryImpl extern "C" { -#if defined(__WIN32__) - void __declspec(dllexport) FB_PLUGIN_ENTRY_POINT(IMaster* m); -#else - void FB_PLUGIN_ENTRY_POINT(IMaster* m) - __attribute__((visibility("default"))); -#endif // __WIN32__ - - void FB_PLUGIN_ENTRY_POINT(IMaster* m) + FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* m) { master = m; IPluginManager* pm = m->getPluginManager(); diff --git a/extern/cloop/Makefile b/extern/cloop/Makefile index 08516c27cd5..c5a2b52628c 100644 --- a/extern/cloop/Makefile +++ b/extern/cloop/Makefile @@ -28,8 +28,8 @@ OBJS_C := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(SRCS_C)) OBJS_CPP := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRCS_CPP)) C_FLAGS := -ggdb -fPIC -MMD -MP -W -Wall -Wno-unused-parameter -CXX_FLAGS := $(C_FLAGS) -FPC_FLAGS := -Mdelphi +CXX_FLAGS := $(C_FLAGS) -std=c++11 +FPC_FLAGS := -Mdelphi -Cg ifeq ($(shell uname),FreeBSD) DL_LIB := @@ -47,16 +47,17 @@ endif ifeq ($(TARGET),debug) FPC_FLAGS += -g + LD_FLAGS += -ggdb endif vpath %.c $(SRC_DIRS) vpath %.cpp $(SRC_DIRS) define compile -$1/%.o: %.c +$1/%.o: %.c | $1 $(CC) -c $$(C_FLAGS) $$< -o $$@ -$1/%.o: %.cpp +$1/%.o: %.cpp | $1 $(CXX) -c $$(CXX_FLAGS) $$< -o $$@ endef @@ -85,6 +86,7 @@ $(foreach bdir,$(OBJ_DIRS),$(eval $(call compile,$(bdir)))) -include $(addsuffix .d,$(basename $(OBJS_CPP))) $(BIN_DIR)/cloop: \ + $(OBJ_DIR)/cloop/Action.o \ $(OBJ_DIR)/cloop/Expr.o \ $(OBJ_DIR)/cloop/Generator.o \ $(OBJ_DIR)/cloop/Lexer.o \ diff --git a/extern/cloop/src/cloop/Action.cpp b/extern/cloop/src/cloop/Action.cpp new file mode 100644 index 00000000000..bba8b6379e9 --- /dev/null +++ b/extern/cloop/src/cloop/Action.cpp @@ -0,0 +1,178 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Alexander Peshkov. + * + * Copyright (c) 2021 Alexander Peshkov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "Action.h" +#include "Parser.h" +#include "Generator.h" + +#include + +using std::string; + + +inline void identify(const ActionParametersBlock& apb, unsigned ident) +{ + identify(apb.out, ident); +} + + +void IfThenElseAction::generate(const ActionParametersBlock& apb, unsigned ident) +{ + switch(apb.language) + { + case LANGUAGE_C: + case LANGUAGE_CPP: + identify(apb, ident); + fprintf(apb.out, "if (%s) {\n", exprIf->generate(apb.language, apb.prefix).c_str()); + actThen->generate(apb, ident + 1); + identify(apb, ident); + fprintf(apb.out, "}\n"); + if (actElse) + { + identify(apb, ident); + fprintf(apb.out, "else {\n"); + actElse->generate(apb, ident + 1); + identify(apb, ident); + fprintf(apb.out, "}\n"); + } + break; + + case LANGUAGE_PASCAL: + identify(apb, ident); + fprintf(apb.out, "if %s then begin\n", exprIf->generate(apb.language, apb.prefix).c_str()); + actThen->generate(apb, ident + 1); + identify(apb, ident); + fprintf(apb.out, "end\n"); + if (actElse) + { + identify(apb, ident); + fprintf(apb.out, "else begin\n"); + actElse->generate(apb, ident + 1); + identify(apb, ident); + fprintf(apb.out, "end\n"); + } + break; + } +} + + +void CallAction::generate(const ActionParametersBlock& apb, unsigned ident) +{ + identify(apb, ident); + fprintf(apb.out, "%s(", name.c_str()); + for (auto itr = parameters.begin(); itr != parameters.end(); ++itr) + { + fprintf(apb.out, "%s%s", itr == parameters.begin() ? "" : ", ", itr->c_str()); + } + fprintf(apb.out, ");\n"); +} + + +void DefAction::generate(const ActionParametersBlock& apb, unsigned ident) +{ + switch(defType) + { + case DEF_NOT_IMPLEMENTED: + switch(apb.language) + { + case LANGUAGE_C: + if (!apb.method->statusName.empty()) + { + identify(apb, ident); + fprintf(apb.out, "CLOOP_setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n", + apb.method->statusName.c_str(), apb.prefix.c_str(), + apb.interface->name.c_str(), apb.method->version); + } + break; + + case LANGUAGE_CPP: + if (!apb.method->statusName.empty()) + { + identify(apb, ident); + fprintf(apb.out, "%s::setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n", + apb.exceptionClass.c_str(), apb.method->statusName.c_str(), apb.prefix.c_str(), + apb.interface->name.c_str(), apb.method->version); + identify(apb, ident); + fprintf(apb.out, "%s::checkException(%s);\n", + apb.exceptionClass.c_str(), apb.method->statusName.c_str()); + } + break; + + case LANGUAGE_PASCAL: + if (!apb.method->statusName.empty() && !apb.exceptionClass.empty()) + { + identify(apb, ident); + fprintf(apb.out, "%s.setVersionError(%s, \'%s%s\', vTable.version, %d);\n", + apb.exceptionClass.c_str(), apb.method->statusName.c_str(), apb.prefix.c_str(), + apb.interface->name.c_str(), apb.method->version); + } + break; + } + break; + + case DEF_IGNORE: + if (apb.method->returnTypeRef.token.type != Token::TYPE_VOID || + apb.method->returnTypeRef.isPointer) + { + identify(apb, ident); + + switch(apb.language) + { + case LANGUAGE_C: + case LANGUAGE_CPP: + fprintf(apb.out, "return 0;\n"); + break; + + case LANGUAGE_PASCAL: + { + const char* sResult = "nil"; + if (!apb.method->returnTypeRef.isPointer) + { + switch (apb.method->returnTypeRef.token.type) + { + case Token::TYPE_STRING: + break; + + case Token::TYPE_BOOLEAN: + sResult = "false"; + break; + + case Token::TYPE_IDENTIFIER: + if (apb.method->returnTypeRef.type == BaseType::TYPE_INTERFACE) + break; + + // fallthru + default: + sResult = "0"; + break; + } + } + + fprintf(apb.out, "Result := %s;\n", sResult); + } + break; + } + } + break; + } +} + + diff --git a/extern/cloop/src/cloop/Action.h b/extern/cloop/src/cloop/Action.h new file mode 100644 index 00000000000..99157ec3bbc --- /dev/null +++ b/extern/cloop/src/cloop/Action.h @@ -0,0 +1,104 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Alexander Peshkov. + * + * Copyright (c) 2021 Alexander Peshkov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef CLOOP_ACTION_H +#define CLOOP_ACTION_H + +#include "Expr.h" + +#include +#include +#include + +class Method; +class Interface; + +struct ActionParametersBlock +{ + FILE* out; + Language language; + const std::string& prefix; + const std::string& exceptionClass; + Interface* interface; + Method* method; +}; + +class Action +{ +public: + virtual ~Action() + { } + + virtual void generate(const ActionParametersBlock& apb, unsigned ident) = 0; +}; + + +class IfThenElseAction : public Action +{ +public: + IfThenElseAction() + : exprIf(nullptr), actThen(nullptr), actElse(nullptr) + { } + + IfThenElseAction(const IfThenElseAction&) = default; + + void generate(const ActionParametersBlock& apb, unsigned ident) override; + + Expr* exprIf; + Action* actThen; + Action* actElse; +}; + + +class CallAction : public Action +{ +public: + CallAction() = default; + + CallAction(const CallAction&) = default; + + void generate(const ActionParametersBlock& apb, unsigned ident) override; + + void addParam(const std::string& parName) + { + parameters.push_back(parName); + } + + std::string name; + std::vector parameters; +}; + + +class DefAction : public Action +{ +public: + enum DefType { DEF_NOT_IMPLEMENTED, DEF_IGNORE }; + + DefAction(DefType dt) + : defType(dt) + { } + + void generate(const ActionParametersBlock& apb, unsigned ident) override; + + DefType defType; +}; + +#endif //CLOOP_ACTION_H diff --git a/extern/cloop/src/cloop/Expr.cpp b/extern/cloop/src/cloop/Expr.cpp index 778a13b479a..13e97eb4084 100644 --- a/extern/cloop/src/cloop/Expr.cpp +++ b/extern/cloop/src/cloop/Expr.cpp @@ -86,19 +86,22 @@ string ConstantExpr::generate(Language language, const string& prefix) { string retPrefix; - switch (language) + if (interface) { - case LANGUAGE_C: - retPrefix = prefix + interface->name + "_"; - break; - - case LANGUAGE_CPP: - retPrefix = prefix + interface->name + "::"; - break; - - case LANGUAGE_PASCAL: - retPrefix = prefix + interface->name + "."; - break; + switch (language) + { + case LANGUAGE_C: + retPrefix = prefix + interface->name + "_"; + break; + + case LANGUAGE_CPP: + retPrefix = prefix + interface->name + "::"; + break; + + case LANGUAGE_PASCAL: + retPrefix = prefix + interface->name + "."; + break; + } } return retPrefix + name; diff --git a/extern/cloop/src/cloop/Generator.cpp b/extern/cloop/src/cloop/Generator.cpp index 22b9f85ecf8..35b48ded393 100644 --- a/extern/cloop/src/cloop/Generator.cpp +++ b/extern/cloop/src/cloop/Generator.cpp @@ -44,6 +44,16 @@ const char* const Generator::AUTOGEN_MSG = //-------------------------------------- +static const char* tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; +void identify(FILE* out, unsigned ident) +{ + fprintf(out, "%.*s", ident, tabs); +} + + +//-------------------------------------- + + FileGenerator::FileGenerator(const string& filename, const string& prefix) : prefix(prefix) { @@ -294,15 +304,8 @@ void CppGenerator::generate() fprintf(out, "\n\t\t"); - string statusName; - - if (!method->parameters.empty() && - parser->exceptionInterface && - method->parameters.front()->typeRef.token.text == parser->exceptionInterface->name) - { - statusName = method->parameters.front()->name; + if (!method->statusName.empty()) fprintf(out, "template "); - } fprintf(out, "%s %s(", convertType(method->returnTypeRef).c_str(), method->name.c_str()); @@ -316,7 +319,7 @@ void CppGenerator::generate() if (k != method->parameters.begin()) fprintf(out, ", "); - if (k == method->parameters.begin() && !statusName.empty()) + if (k == method->parameters.begin() && !method->statusName.empty()) fprintf(out, "StatusType* %s", parameter->name.c_str()); else { @@ -333,17 +336,13 @@ void CppGenerator::generate() fprintf(out, "\t\t\tif (cloopVTable->version < %d)\n", method->version); fprintf(out, "\t\t\t{\n"); - if (!statusName.empty()) - { - fprintf(out, - "\t\t\t\tStatusType::setVersionError(%s, \"%s%s\", cloopVTable->version, %d);\n", - statusName.c_str(), - prefix.c_str(), - interface->name.c_str(), - method->version); - - fprintf(out, "\t\t\t\tStatusType::checkException(%s);\n", statusName.c_str()); - } + const string exceptionClass("StatusType"); + ActionParametersBlock apb = {out, LANGUAGE_CPP, prefix, exceptionClass, interface, method}; + + if (method->notImplementedAction) + method->notImplementedAction->generate(apb, 4); + else + DefAction(DefAction::DEF_NOT_IMPLEMENTED).generate(apb, 4); fprintf(out, "\t\t\t\treturn"); @@ -360,11 +359,11 @@ void CppGenerator::generate() fprintf(out, "\t\t\t}\n"); } - if (!statusName.empty()) + if (!method->statusName.empty()) { fprintf(out, "\t\t\t"); - fprintf(out, "StatusType::clearException(%s)", statusName.c_str()); + fprintf(out, "StatusType::clearException(%s)", method->statusName.c_str()); fprintf(out, ";\n"); } @@ -635,7 +634,19 @@ void CppGenerator::generate() } } - fprintf(out, ")%s = 0;\n", (method->isConst ? " const" : "")); + fprintf(out, ")%s", (method->isConst ? " const" : "")); + + if (method->stubAction) + { + const string exceptionClass("StatusType"); + ActionParametersBlock apb = {out, LANGUAGE_CPP, prefix, exceptionClass, interface, method}; + + fprintf(out, "\n\t\t{\n"); + method->stubAction->generate(apb, 3); + fprintf(out, "\t\t}\n"); + } + else + fprintf(out, " = 0;\n"); } fprintf(out, "\t};\n"); @@ -1077,6 +1088,12 @@ void PascalGenerator::generate() if (!isProcedure) fprintf(out, ": %s", convertType(method->returnTypeRef).c_str()); + // Methods that present in TObject should be "reintroduce"d. + // So far there is just one case. For more cases better solution required. + + if (method->name == "toString") + fprintf(out, "; reintroduce"); + fprintf(out, ";\n"); } @@ -1119,7 +1136,10 @@ void PascalGenerator::generate() if (!isProcedure) fprintf(out, ": %s", convertType(method->returnTypeRef).c_str()); - fprintf(out, "; virtual; abstract;\n"); + fprintf(out, "; virtual;"); + if (!method->stubAction) + fprintf(out, " abstract;"); + fprintf(out, "\n"); } fprintf(out, "\tend;\n\n"); @@ -1168,10 +1188,34 @@ void PascalGenerator::generate() fprintf(out, ";\n"); fprintf(out, "begin\n"); - fprintf(out, "\t"); - //// TODO: checkVersion + unsigned ident = 1; + if (method->version - (interface->super ? interface->super->version : 0) != 1) + { + fprintf(out, "\tif (vTable.version < %d) then begin\n", method->version); + + ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method}; + if (method->notImplementedAction) + method->notImplementedAction->generate(apb, 2); + else + DefAction(DefAction::DEF_NOT_IMPLEMENTED).generate(apb, 2); + + if (method->returnTypeRef.token.type != Token::TYPE_VOID || + method->returnTypeRef.isPointer) + { + fprintf(out, "\t\tResult := %s;\n", + method->notImplementedExpr ? + method->notImplementedExpr->generate(LANGUAGE_PASCAL, prefix).c_str() : + method->returnTypeRef.valueIsPointer() ? "nil" : + method->returnTypeRef.token.type == Token::TYPE_BOOLEAN ? "false" : "0"); + } + + fprintf(out, "\tend\n\telse begin\n"); + ident = 2; + } + + identify(out, ident); if (!isProcedure) fprintf(out, "Result := "); @@ -1188,14 +1232,11 @@ void PascalGenerator::generate() fprintf(out, ");\n"); - if (!method->parameters.empty() && - parser->exceptionInterface && - method->parameters.front()->typeRef.token.text == parser->exceptionInterface->name && - !exceptionClass.empty()) - { - fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), - escapeName(method->parameters.front()->name).c_str()); - } + if (ident > 1) + fprintf(out, "\tend;\n"); + + if (!method->statusName.empty() && !exceptionClass.empty()) + fprintf(out, "\t%s.checkException(%s);\n", exceptionClass.c_str(), escapeName(method->statusName).c_str()); fprintf(out, "end;\n\n"); } @@ -1219,6 +1260,8 @@ void PascalGenerator::generate() bool isProcedure = method->returnTypeRef.token.type == Token::TYPE_VOID && !method->returnTypeRef.isPointer; + ActionParametersBlock apb = {out, LANGUAGE_PASCAL, prefix, exceptionClass, interface, method}; + fprintf(out, "%s %sImpl_%sDispatcher(this: %s", (isProcedure ? "procedure" : "function"), escapeName(interface->name, true).c_str(), @@ -1241,6 +1284,7 @@ void PascalGenerator::generate() fprintf(out, "; cdecl;\n"); fprintf(out, "begin\n"); + DefAction(DefAction::DEF_IGNORE).generate(apb, 1); if (!exceptionClass.empty()) fprintf(out, "\ttry\n\t"); @@ -1282,8 +1326,35 @@ void PascalGenerator::generate() fprintf(out, "\tend\n"); } - fprintf(out, "end;\n\n"); + + if (method->stubAction) + { + fprintf(out, "%s %sImpl.%s(", + (isProcedure ? "procedure" : "function"), + escapeName(interface->name, true).c_str(), + escapeName(method->name).c_str()); + + for (vector::iterator k = method->parameters.begin(); + k != method->parameters.end(); + ++k) + { + Parameter* parameter = *k; + + fprintf(out, "%s%s", + k == method->parameters.begin() ? "" : "; ", + convertParameter(*parameter).c_str()); + } + + fprintf(out, ")"); + if (!isProcedure) + fprintf(out, ": %s", convertType(method->returnTypeRef).c_str()); + fprintf(out, ";\n"); + + fprintf(out, "begin\n"); + method->stubAction->generate(apb, 1); + fprintf(out, "end;\n\n"); + } } fprintf(out, "var\n"); diff --git a/extern/cloop/src/cloop/Generator.h b/extern/cloop/src/cloop/Generator.h index 1854d4d71a5..399ffa81bfe 100644 --- a/extern/cloop/src/cloop/Generator.h +++ b/extern/cloop/src/cloop/Generator.h @@ -146,4 +146,7 @@ class PascalGenerator : public FileGenerator }; +void identify(FILE* out, unsigned ident); + + #endif // CLOOP_GENERATOR_H diff --git a/extern/cloop/src/cloop/Lexer.cpp b/extern/cloop/src/cloop/Lexer.cpp index 2c686ec858f..3d399950cb5 100644 --- a/extern/cloop/src/cloop/Lexer.cpp +++ b/extern/cloop/src/cloop/Lexer.cpp @@ -90,6 +90,8 @@ Token& Lexer::getToken(Token& token) token.type = Token::TYPE_INTERFACE; else if (token.text == "notImplemented") token.type = Token::TYPE_NOT_IMPLEMENTED; + else if (token.text == "notImplementedAction") + token.type = Token::TYPE_NOT_IMPLEMENTED_ACTION; else if (token.text == "struct") token.type = Token::TYPE_STRUCT; else if (token.text == "typedef") @@ -98,6 +100,20 @@ Token& Lexer::getToken(Token& token) token.type = Token::TYPE_VERSION; else if (token.text == "onError") token.type = Token::TYPE_ON_ERROR; + else if (token.text == "if") + token.type = Token::TYPE_IF; + else if (token.text == "then") + token.type = Token::TYPE_THEN; + else if (token.text == "else") + token.type = Token::TYPE_ELSE; + else if (token.text == "endif") + token.type = Token::TYPE_ENDIF; + else if (token.text == "call") + token.type = Token::TYPE_CALL; + else if (token.text == "defaultAction") + token.type = Token::TYPE_DEFAULT_ACTION; + else if (token.text == "stub") + token.type = Token::TYPE_STUB; // types else if (token.text == "void") token.type = Token::TYPE_VOID; diff --git a/extern/cloop/src/cloop/Lexer.h b/extern/cloop/src/cloop/Lexer.h index 6371ecd75ac..3a72a9dc12f 100644 --- a/extern/cloop/src/cloop/Lexer.h +++ b/extern/cloop/src/cloop/Lexer.h @@ -46,10 +46,18 @@ struct Token TYPE_EXCEPTION, TYPE_INTERFACE, TYPE_NOT_IMPLEMENTED, + TYPE_NOT_IMPLEMENTED_ACTION, + TYPE_STUB, TYPE_STRUCT, TYPE_TYPEDEF, TYPE_VERSION, TYPE_ON_ERROR, + TYPE_IF, + TYPE_THEN, + TYPE_ELSE, + TYPE_ENDIF, + TYPE_CALL, + TYPE_DEFAULT_ACTION, // types TYPE_VOID, TYPE_BOOLEAN, diff --git a/extern/cloop/src/cloop/Parser.cpp b/extern/cloop/src/cloop/Parser.cpp index 4061a57ec42..1330331a714 100644 --- a/extern/cloop/src/cloop/Parser.cpp +++ b/extern/cloop/src/cloop/Parser.cpp @@ -82,13 +82,19 @@ void Parser::parse() parseTypedef(); break; + case Token::TYPE_BOOLEAN: + if (exception) + error(token, "Cannot use attribute exception in boolean."); + parseBoolean(); + break; + default: syntaxError(token); break; } } - // Check types. + // Check types, assign statusName to methods. for (vector::iterator i = interfaces.begin(); i != interfaces.end(); ++i) { @@ -109,6 +115,13 @@ void Parser::parse() Parameter* parameter = *k; checkType(parameter->typeRef); } + + if (!method->parameters.empty() && + exceptionInterface && + method->parameters.front()->typeRef.token.text == exceptionInterface->name) + { + method->statusName = method->parameters.front()->name; + } } } } @@ -164,6 +177,16 @@ void Parser::parseStruct() getToken(token, TOKEN(';')); } +void Parser::parseBoolean() +{ + Boolean* b = new Boolean(); + + b->name = getToken(token, Token::TYPE_IDENTIFIER).text; + typesByName.insert(pair(b->name, b)); + + getToken(token, TOKEN(';')); +} + void Parser::parseTypedef() { Typedef* typeDef = new Typedef(); @@ -176,7 +199,9 @@ void Parser::parseTypedef() void Parser::parseItem() { - Expr* notImplementedExpr = NULL; + Expr* notImplementedExpr = nullptr; + Action* notImplementedAction = nullptr; + Action* stubAction = nullptr; std::string onError; while (lexer->getToken(token).type == TOKEN('[')) @@ -190,7 +215,6 @@ void Parser::parseItem() getToken(token, TOKEN('(')); notImplementedExpr = parseExpr(); getToken(token, TOKEN(')')); - getToken(token, TOKEN(']')); break; case Token::TYPE_ON_ERROR: @@ -200,13 +224,25 @@ void Parser::parseItem() if (token.type != Token::TYPE_IDENTIFIER) syntaxError(token); onError = token.text; - getToken(token, TOKEN(']')); + break; + + case Token::TYPE_NOT_IMPLEMENTED_ACTION: + if (notImplementedAction) + syntaxError(token); + notImplementedAction = parseAction(DefAction::DEF_NOT_IMPLEMENTED); + break; + + case Token::TYPE_STUB: + if (stubAction) + syntaxError(token); + stubAction = parseAction(DefAction::DEF_IGNORE); break; default: syntaxError(token); break; } + getToken(token, TOKEN(']')); } lexer->pushToken(token); @@ -226,7 +262,7 @@ void Parser::parseItem() } getToken(token, TOKEN('(')); - parseMethod(typeRef, name, notImplementedExpr, onError); + parseMethod(typeRef, name, notImplementedExpr, onError, notImplementedAction, stubAction); } void Parser::parseConstant(const TypeRef& typeRef, const string& name) @@ -241,7 +277,70 @@ void Parser::parseConstant(const TypeRef& typeRef, const string& name) getToken(token, TOKEN(';')); } -void Parser::parseMethod(const TypeRef& returnTypeRef, const string& name, Expr* notImplementedExpr, const string& onError) +Action* Parser::parseAction(DefAction::DefType dt) +{ + switch (lexer->getToken(token).type) + { + case Token::TYPE_IF: + return parseIfThenElseAction(dt); + + case Token::TYPE_CALL: + return parseCallAction(); + + case Token::TYPE_DEFAULT_ACTION: + return parseDefAction(dt); + + default: + break; + } + + syntaxError(token); +} + +Action* Parser::parseIfThenElseAction(DefAction::DefType dt) +{ + IfThenElseAction act; + + act.exprIf = parseLogicalExpr(); + + getToken(token, Token::TYPE_THEN); + act.actThen = parseAction(dt); + + lexer->getToken(token); + if (token.type == Token::TYPE_ELSE) + act.actElse = parseAction(dt); + else + lexer->pushToken(token); + + getToken(token, Token::TYPE_ENDIF); + return new IfThenElseAction(act); +} + +Action* Parser::parseCallAction() +{ + CallAction act; + + act.name = getToken(token, Token::TYPE_IDENTIFIER).text; + + getToken(token, TOKEN('(')); + do + { + act.addParam(getToken(token, Token::TYPE_IDENTIFIER).text); + } while(lexer->getToken(token).type == ','); + + if (token.type == ')') + return new CallAction(act); + + syntaxError(token); +} + +Action* Parser::parseDefAction(DefAction::DefType dt) +{ + return new DefAction(dt); +} + +void Parser::parseMethod(const TypeRef& returnTypeRef, const string& name, Expr* notImplementedExpr, + const string& onError, Action* notImplementedAction, Action* stubAction) { Method* method = new Method(); interface->methods.push_back(method); @@ -250,6 +349,8 @@ void Parser::parseMethod(const TypeRef& returnTypeRef, const string& name, Expr* method->name = name; method->version = interface->version; method->notImplementedExpr = notImplementedExpr; + method->notImplementedAction = notImplementedAction; + method->stubAction = stubAction; method->onErrorFunction = onError; if (lexer->getToken(token).type != TOKEN(')')) @@ -354,6 +455,10 @@ Expr* Parser::parsePrimaryExpr() } } + case Token::TYPE_DOUBLE_COLON: + getToken(token, Token::TYPE_IDENTIFIER); + return new ConstantExpr(nullptr, token.text); + default: syntaxError(token); return NULL; // warning @@ -436,3 +541,26 @@ void Parser::error(const Token& token, const string& msg) lexer->filename.c_str(), token.line, token.column, msg.c_str()); throw runtime_error(buffer); } + +bool TypeRef::valueIsPointer() +{ + if (isPointer) + return true; + + switch (token.type) + { + case Token::TYPE_STRING: + return true; + + case Token::TYPE_IDENTIFIER: + if (type == BaseType::TYPE_INTERFACE) + return true; + break; + + default: + break; + } + + return false; +} + diff --git a/extern/cloop/src/cloop/Parser.h b/extern/cloop/src/cloop/Parser.h index 89c5fdc25fb..82f98a12d70 100644 --- a/extern/cloop/src/cloop/Parser.h +++ b/extern/cloop/src/cloop/Parser.h @@ -23,6 +23,7 @@ #define CLOOP_PARSER_H #include "Lexer.h" +#include "Action.h" #include #include #include @@ -38,7 +39,8 @@ class BaseType { TYPE_INTERFACE, TYPE_STRUCT, - TYPE_TYPEDEF + TYPE_TYPEDEF, + TYPE_BOOLEAN }; protected: @@ -71,6 +73,8 @@ class TypeRef bool isConst; bool isPointer; BaseType::Type type; + + bool valueIsPointer(); }; @@ -96,6 +100,8 @@ class Method public: Method() : notImplementedExpr(NULL), + notImplementedAction(NULL), + stubAction(NULL), version(0), isConst(false) { @@ -105,9 +111,12 @@ class Method TypeRef returnTypeRef; std::vector parameters; Expr* notImplementedExpr; + Action* notImplementedAction; + Action* stubAction; unsigned version; bool isConst; std::string onErrorFunction; + std::string statusName; }; @@ -139,6 +148,16 @@ class Struct : public BaseType }; +class Boolean : public BaseType +{ +public: + Boolean() + : BaseType(TYPE_BOOLEAN) + { + } +}; + + class Typedef : public BaseType { public: @@ -158,15 +177,22 @@ class Parser void parseInterface(bool exception); void parseStruct(); void parseTypedef(); + void parseBoolean(); void parseItem(); void parseConstant(const TypeRef& typeRef, const std::string& name); - void parseMethod(const TypeRef& returnTypeRef, const std::string& name, Expr* notImplementedExpr, const std::string& onErrorFunction); + void parseMethod(const TypeRef& returnTypeRef, const std::string& name, Expr* notImplementedExpr, + const std::string& onErrorFunction, Action* notImplementedAction, Action* stubAction); Expr* parseExpr(); Expr* parseLogicalExpr(); Expr* parseUnaryExpr(); Expr* parsePrimaryExpr(); + Action* parseAction(DefAction::DefType dt); + Action* parseIfThenElseAction(DefAction::DefType dt); + Action* parseCallAction(); + Action* parseDefAction(DefAction::DefType dt); + private: void checkType(TypeRef& typeRef); @@ -174,8 +200,8 @@ class Parser TypeRef parseTypeRef(); - void syntaxError(const Token& token); - void error(const Token& token, const std::string& msg); + [[noreturn]] void syntaxError(const Token& token); + [[noreturn]] void error(const Token& token, const std::string& msg); public: std::vector interfaces; diff --git a/extern/cloop/src/cloop/cloop.vcxproj b/extern/cloop/src/cloop/cloop.vcxproj index f73e1195992..7630f9294d6 100644 --- a/extern/cloop/src/cloop/cloop.vcxproj +++ b/extern/cloop/src/cloop/cloop.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -20,23 +20,39 @@ Win32Proj + {7A639C01-BE0D-4BEE-D2D4-17CA5AB54E57} + 10.0.17763.0 + 10.0 + 10.0 Application true + v141 + v142 + v143 Application true + v141 + v142 + v143 Application false + v141 + v142 + v143 Application false + v141 + v142 + v143 @@ -131,6 +147,7 @@ + @@ -146,4 +163,4 @@ - \ No newline at end of file + diff --git a/extern/cloop/src/cloop/cloop.vcxproj.filters b/extern/cloop/src/cloop/cloop.vcxproj.filters index ddc53560612..66c8c78c7a9 100644 --- a/extern/cloop/src/cloop/cloop.vcxproj.filters +++ b/extern/cloop/src/cloop/cloop.vcxproj.filters @@ -30,6 +30,9 @@ Source Files + + Source Files + diff --git a/extern/cloop/src/tests/test1/CalcPascalApi.implementation.pas b/extern/cloop/src/tests/test1/CalcPascalApi.implementation.pas index 2179609804b..e44c8ad5f16 100644 --- a/extern/cloop/src/tests/test1/CalcPascalApi.implementation.pas +++ b/extern/cloop/src/tests/test1/CalcPascalApi.implementation.pas @@ -25,3 +25,9 @@ class procedure CalcException.catchException(status: Status; e: Exception); else status.setCode(-1); end; + +class procedure CalcException.setVersionError(status: Status; interfaceName: string; + currentVersion, expectedVersion: NativeInt); +begin + status.setCode(Status.ERROR_1); +end; diff --git a/extern/cloop/src/tests/test1/CalcPascalApi.interface.pas b/extern/cloop/src/tests/test1/CalcPascalApi.interface.pas index 2f758aed0f2..f7e71f5f91e 100644 --- a/extern/cloop/src/tests/test1/CalcPascalApi.interface.pas +++ b/extern/cloop/src/tests/test1/CalcPascalApi.interface.pas @@ -6,6 +6,8 @@ CalcException = class(Exception) class procedure checkException(status: Status); class procedure catchException(status: Status; e: Exception); + class procedure setVersionError(status: Status; interfaceName: string; + currentVersion, expectedVersion: NativeInt); private code: Integer; diff --git a/extern/cloop/src/tests/test1/CalcPascalApi.pas b/extern/cloop/src/tests/test1/CalcPascalApi.pas index d929e51cc91..28b8a583fba 100644 --- a/extern/cloop/src/tests/test1/CalcPascalApi.pas +++ b/extern/cloop/src/tests/test1/CalcPascalApi.pas @@ -30,6 +30,8 @@ CalcException = class(Exception) class procedure checkException(status: Status); class procedure catchException(status: Status; e: Exception); + class procedure setVersionError(status: Status; interfaceName: string; + currentVersion, expectedVersion: NativeInt); private code: Integer; @@ -221,17 +223,31 @@ function Calculator.sum(status: Status; n1: Integer; n2: Integer): Integer; function Calculator.getMemory(): Integer; begin - Result := CalculatorVTable(vTable).getMemory(Self); + if (vTable.version < 3) then begin + Result := Status.ERROR_1; + end + else begin + Result := CalculatorVTable(vTable).getMemory(Self); + end; end; procedure Calculator.setMemory(n: Integer); begin - CalculatorVTable(vTable).setMemory(Self, n); + if (vTable.version < 3) then begin + end + else begin + CalculatorVTable(vTable).setMemory(Self, n); + end; end; procedure Calculator.sumAndStore(status: Status; n1: Integer; n2: Integer); begin - CalculatorVTable(vTable).sumAndStore(Self, status, n1, n2); + if (vTable.version < 4) then begin + CalcException.setVersionError(status, 'Calculator', vTable.version, 4); + end + else begin + CalculatorVTable(vTable).sumAndStore(Self, status, n1, n2); + end; CalcException.checkException(status); end; @@ -248,7 +264,11 @@ procedure Calculator2.copyMemory(calculator: Calculator); procedure Calculator2.copyMemory2(address: IntegerPtr); begin - Calculator2VTable(vTable).copyMemory2(Self, address); + if (vTable.version < 6) then begin + end + else begin + Calculator2VTable(vTable).copyMemory2(Self, address); + end; end; procedure DisposableImpl_disposeDispatcher(this: Disposable); cdecl; @@ -279,6 +299,7 @@ procedure StatusImpl_disposeDispatcher(this: Status); cdecl; function StatusImpl_getCodeDispatcher(this: Status): Integer; cdecl; begin + Result := 0; try Result := StatusImpl(this).getCode(); except @@ -314,6 +335,7 @@ procedure FactoryImpl_disposeDispatcher(this: Factory); cdecl; function FactoryImpl_createStatusDispatcher(this: Factory): Status; cdecl; begin + Result := nil; try Result := FactoryImpl(this).createStatus(); except @@ -323,6 +345,7 @@ function FactoryImpl_createStatusDispatcher(this: Factory): Status; cdecl; function FactoryImpl_createCalculatorDispatcher(this: Factory; status: Status): Calculator; cdecl; begin + Result := nil; try Result := FactoryImpl(this).createCalculator(status); except @@ -332,6 +355,7 @@ function FactoryImpl_createCalculatorDispatcher(this: Factory; status: Status): function FactoryImpl_createCalculator2Dispatcher(this: Factory; status: Status): Calculator2; cdecl; begin + Result := nil; try Result := FactoryImpl(this).createCalculator2(status); except @@ -341,6 +365,7 @@ function FactoryImpl_createCalculator2Dispatcher(this: Factory; status: Status): function FactoryImpl_createBrokenCalculatorDispatcher(this: Factory; status: Status): Calculator; cdecl; begin + Result := nil; try Result := FactoryImpl(this).createBrokenCalculator(status); except @@ -367,6 +392,7 @@ procedure CalculatorImpl_disposeDispatcher(this: Calculator); cdecl; function CalculatorImpl_sumDispatcher(this: Calculator; status: Status; n1: Integer; n2: Integer): Integer; cdecl; begin + Result := 0; try Result := CalculatorImpl(this).sum(status, n1, n2); except @@ -376,6 +402,7 @@ function CalculatorImpl_sumDispatcher(this: Calculator; status: Status; n1: Inte function CalculatorImpl_getMemoryDispatcher(this: Calculator): Integer; cdecl; begin + Result := 0; try Result := CalculatorImpl(this).getMemory(); except @@ -420,6 +447,7 @@ procedure Calculator2Impl_disposeDispatcher(this: Calculator2); cdecl; function Calculator2Impl_sumDispatcher(this: Calculator2; status: Status; n1: Integer; n2: Integer): Integer; cdecl; begin + Result := 0; try Result := Calculator2Impl(this).sum(status, n1, n2); except @@ -429,6 +457,7 @@ function Calculator2Impl_sumDispatcher(this: Calculator2; status: Status; n1: In function Calculator2Impl_getMemoryDispatcher(this: Calculator2): Integer; cdecl; begin + Result := 0; try Result := Calculator2Impl(this).getMemory(); except @@ -456,6 +485,7 @@ procedure Calculator2Impl_sumAndStoreDispatcher(this: Calculator2; status: Statu function Calculator2Impl_multiplyDispatcher(this: Calculator2; status: Status; n1: Integer; n2: Integer): Integer; cdecl; begin + Result := 0; try Result := Calculator2Impl(this).multiply(status, n1, n2); except @@ -516,6 +546,12 @@ class procedure CalcException.catchException(status: Status; e: Exception); else status.setCode(-1); end; + +class procedure CalcException.setVersionError(status: Status; interfaceName: string; + currentVersion, expectedVersion: NativeInt); +begin + status.setCode(Status.ERROR_1); +end; initialization DisposableImpl_vTable := DisposableVTable.create; DisposableImpl_vTable.version := 1; diff --git a/extern/cloop/src/tests/test1/test1-c-dll.vcxproj b/extern/cloop/src/tests/test1/test1-c-dll.vcxproj index d1ae5e48cf9..8d7c06b149b 100644 --- a/extern/cloop/src/tests/test1/test1-c-dll.vcxproj +++ b/extern/cloop/src/tests/test1/test1-c-dll.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -21,27 +21,43 @@ Win32Proj test1-c-dll + {087FC91A-451C-853D-7439-51BF770E2380} + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary true NotSet + v141 + v142 + v143 DynamicLibrary true NotSet + v141 + v142 + v143 DynamicLibrary false NotSet + v141 + v142 + v143 DynamicLibrary false NotSet + v141 + v142 + v143 @@ -153,4 +169,4 @@ - \ No newline at end of file + diff --git a/extern/cloop/src/tests/test1/test1-c-exe.vcxproj b/extern/cloop/src/tests/test1/test1-c-exe.vcxproj index 01ba2892ae4..d69e724cbe9 100644 --- a/extern/cloop/src/tests/test1/test1-c-exe.vcxproj +++ b/extern/cloop/src/tests/test1/test1-c-exe.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -29,29 +29,44 @@ {4495AE41-C12E-446C-AE2F-5CECF5F80B17} Win32Proj test1cexe + 10.0.17763.0 + 10.0 + 10.0 Application true NotSet + v141 + v142 + v143 Application true NotSet + v141 + v142 + v143 Application false true NotSet + v141 + v142 + v143 Application false true NotSet + v141 + v142 + v143 @@ -156,4 +171,4 @@ - \ No newline at end of file + diff --git a/extern/cloop/src/tests/test1/test1-cpp-dll.vcxproj b/extern/cloop/src/tests/test1/test1-cpp-dll.vcxproj index a718512cc1c..9285779e7e1 100644 --- a/extern/cloop/src/tests/test1/test1-cpp-dll.vcxproj +++ b/extern/cloop/src/tests/test1/test1-cpp-dll.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -21,27 +21,43 @@ Win32Proj test1-cpp-dll + {A97C1858-7DFA-8FEB-FEAE-2E9F1491692F} + 10.0.17763.0 + 10.0 + 10.0 DynamicLibrary true NotSet + v141 + v142 + v143 DynamicLibrary true NotSet + v141 + v142 + v143 DynamicLibrary false NotSet + v141 + v142 + v143 DynamicLibrary false NotSet + v141 + v142 + v143 @@ -152,4 +168,4 @@ - \ No newline at end of file + diff --git a/extern/cloop/src/tests/test1/test1-cpp-exe.vcxproj b/extern/cloop/src/tests/test1/test1-cpp-exe.vcxproj index bc2b7dff8dc..de9326e178c 100644 --- a/extern/cloop/src/tests/test1/test1-cpp-exe.vcxproj +++ b/extern/cloop/src/tests/test1/test1-cpp-exe.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -22,29 +22,44 @@ {096EBD8E-C0FC-4286-A01D-89D562F3AE12} Win32Proj test1cppexe + 10.0.17763.0 + 10.0 + 10.0 Application true NotSet + v141 + v142 + v143 Application true NotSet + v141 + v142 + v143 Application false true NotSet + v141 + v142 + v143 Application false true NotSet + v141 + v142 + v143 @@ -155,4 +170,4 @@ - \ No newline at end of file + diff --git a/extern/decNumber/decCommon.c b/extern/decNumber/decCommon.c index 6a0c112c88c..e16d6ee2d1d 100644 --- a/extern/decNumber/decCommon.c +++ b/extern/decNumber/decCommon.c @@ -236,6 +236,7 @@ static decFloat * decFinalize(decFloat *df, bcdnum *num, uByte *ulsd=num->lsd; // .. uInt encode; // encoding accumulator Int length; // coefficient length + uByte buffer[ROUNDUP(DECPMAX+3, 4)]; // [+3 allows uInt padding] #if DECCHECK Int clen=ulsd-umsd+1; @@ -456,7 +457,6 @@ static decFloat * decFinalize(decFloat *df, bcdnum *num, // fold down needed; must copy to buffer in order to pad // with zeros safely; fortunately this is not the worst case // path because cannot have had a round - uByte buffer[ROUNDUP(DECPMAX+3, 4)]; // [+3 allows uInt padding] uByte *s=umsd; // source uByte *t=buffer; // safe target uByte *tlsd=buffer+(ulsd-umsd)+shift; // target LSD @@ -905,16 +905,20 @@ decFloat * decFloatFromString(decFloat *result, const char *string, else { // too long for buffer // [This is a rare and unusual case; arbitrary-length input] // strip leading zeros [but leave final 0 if all 0's] - if (*cfirst=='.') cfirst++; // step past dot at start - if (*cfirst=='0') { // [cfirst always -> digit] - for (; cfirstdecNumber {BE4D2DDC-59A0-4CD7-848E-231E13785335} decNumber - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -269,4 +279,4 @@ - \ No newline at end of file + diff --git a/extern/icu/tzdata/be.zip b/extern/icu/tzdata/be.zip index ffc05a389b2..d6963395b50 100644 Binary files a/extern/icu/tzdata/be.zip and b/extern/icu/tzdata/be.zip differ diff --git a/extern/icu/tzdata/le.zip b/extern/icu/tzdata/le.zip index 51508b03d63..b6edd9e0a0b 100644 Binary files a/extern/icu/tzdata/le.zip and b/extern/icu/tzdata/le.zip differ diff --git a/extern/icu/tzdata/update.sh b/extern/icu/tzdata/update.sh index c5b5e85a64a..018b370a22a 100755 --- a/extern/icu/tzdata/update.sh +++ b/extern/icu/tzdata/update.sh @@ -7,7 +7,7 @@ THIS_DIR=`dirname $THIS_DIR` TMP_DIR=`mktemp -d` VERSION=`cat $THIS_DIR/version.txt` -BASE_URL=https://github.com/unicode-org/icu-data/raw/master/tzdata/icunew/$VERSION/44 +BASE_URL=https://github.com/unicode-org/icu-data/raw/main/tzdata/icunew/$VERSION/44 echo Building update-ids... cd $THIS_DIR diff --git a/extern/icu/tzdata/version.txt b/extern/icu/tzdata/version.txt index 1d590958afd..ef468adcecf 100644 --- a/extern/icu/tzdata/version.txt +++ b/extern/icu/tzdata/version.txt @@ -1 +1 @@ -2021a +2025b diff --git a/extern/int128/absl/base/attributes.h b/extern/int128/absl/base/attributes.h new file mode 100644 index 00000000000..52139556f2a --- /dev/null +++ b/extern/int128/absl/base/attributes.h @@ -0,0 +1,721 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This header file defines macros for declaring attributes for functions, +// types, and variables. +// +// These macros are used within Abseil and allow the compiler to optimize, where +// applicable, certain function calls. +// +// Most macros here are exposing GCC or Clang features, and are stubbed out for +// other compilers. +// +// GCC attributes documentation: +// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html +// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html +// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html +// +// Most attributes in this file are already supported by GCC 4.7. However, some +// of them are not supported in older version of Clang. Thus, we check +// `__has_attribute()` first. If the check fails, we check if we are on GCC and +// assume the attribute exists on GCC (which is verified on GCC 4.7). + +#ifndef ABSL_BASE_ATTRIBUTES_H_ +#define ABSL_BASE_ATTRIBUTES_H_ + +#include "absl/base/config.h" + +// ABSL_HAVE_ATTRIBUTE +// +// A function-like feature checking macro that is a wrapper around +// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a +// nonzero constant integer if the attribute is supported or 0 if not. +// +// It evaluates to zero if `__has_attribute` is not defined by the compiler. +// +// GCC: https://gcc.gnu.org/gcc-5/changes.html +// Clang: https://clang.llvm.org/docs/LanguageExtensions.html +#ifdef __has_attribute +#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x) +#else +#define ABSL_HAVE_ATTRIBUTE(x) 0 +#endif + +// ABSL_HAVE_CPP_ATTRIBUTE +// +// A function-like feature checking macro that accepts C++11 style attributes. +// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6 +// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't +// find `__has_cpp_attribute`, will evaluate to 0. +#if defined(__cplusplus) && defined(__has_cpp_attribute) +// NOTE: requiring __cplusplus above should not be necessary, but +// works around https://bugs.llvm.org/show_bug.cgi?id=23435. +#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0 +#endif + +// ----------------------------------------------------------------------------- +// Function Attributes +// ----------------------------------------------------------------------------- +// +// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html +// Clang: https://clang.llvm.org/docs/AttributeReference.html + +// ABSL_PRINTF_ATTRIBUTE +// ABSL_SCANF_ATTRIBUTE +// +// Tells the compiler to perform `printf` format string checking if the +// compiler supports it; see the 'format' attribute in +// . +// +// Note: As the GCC manual states, "[s]ince non-static C++ methods +// have an implicit 'this' argument, the arguments of such methods +// should be counted from two, not one." +#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \ + __attribute__((__format__(__scanf__, string_index, first_to_check))) +#else +#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) +#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) +#endif + +// ABSL_ATTRIBUTE_ALWAYS_INLINE +// ABSL_ATTRIBUTE_NOINLINE +// +// Forces functions to either inline or not inline. Introduced in gcc 3.1. +#if ABSL_HAVE_ATTRIBUTE(always_inline) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) +#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 +#else +#define ABSL_ATTRIBUTE_ALWAYS_INLINE +#endif + +#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline)) +#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 +#else +#define ABSL_ATTRIBUTE_NOINLINE +#endif + +// ABSL_ATTRIBUTE_NO_TAIL_CALL +// +// Prevents the compiler from optimizing away stack frames for functions which +// end in a call to another function. +#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls) +#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 +#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls)) +#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__) +#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 +#define ABSL_ATTRIBUTE_NO_TAIL_CALL \ + __attribute__((optimize("no-optimize-sibling-calls"))) +#else +#define ABSL_ATTRIBUTE_NO_TAIL_CALL +#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0 +#endif + +// ABSL_ATTRIBUTE_WEAK +// +// Tags a function as weak for the purposes of compilation and linking. +// Weak attributes did not work properly in LLVM's Windows backend before +// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 +// for further information. +// The MinGW compiler doesn't complain about the weak attribute until the link +// step, presumably because Windows doesn't use ELF binaries. +#if (ABSL_HAVE_ATTRIBUTE(weak) || \ + (defined(__GNUC__) && !defined(__clang__))) && \ + (!defined(_WIN32) || __clang_major__ < 9) && !defined(__MINGW32__) +#undef ABSL_ATTRIBUTE_WEAK +#define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) +#define ABSL_HAVE_ATTRIBUTE_WEAK 1 +#else +#define ABSL_ATTRIBUTE_WEAK +#define ABSL_HAVE_ATTRIBUTE_WEAK 0 +#endif + +// ABSL_ATTRIBUTE_NONNULL +// +// Tells the compiler either (a) that a particular function parameter +// should be a non-null pointer, or (b) that all pointer arguments should +// be non-null. +// +// Note: As the GCC manual states, "[s]ince non-static C++ methods +// have an implicit 'this' argument, the arguments of such methods +// should be counted from two, not one." +// +// Args are indexed starting at 1. +// +// For non-static class member functions, the implicit `this` argument +// is arg 1, and the first explicit argument is arg 2. For static class member +// functions, there is no implicit `this`, and the first explicit argument is +// arg 1. +// +// Example: +// +// /* arg_a cannot be null, but arg_b can */ +// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1); +// +// class C { +// /* arg_a cannot be null, but arg_b can */ +// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2); +// +// /* arg_a cannot be null, but arg_b can */ +// static void StaticMethod(void* arg_a, void* arg_b) +// ABSL_ATTRIBUTE_NONNULL(1); +// }; +// +// If no arguments are provided, then all pointer arguments should be non-null. +// +// /* No pointer arguments may be null. */ +// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL(); +// +// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but +// ABSL_ATTRIBUTE_NONNULL does not. +#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index))) +#else +#define ABSL_ATTRIBUTE_NONNULL(...) +#endif + +// ABSL_ATTRIBUTE_NORETURN +// +// Tells the compiler that a given function never returns. +#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define ABSL_ATTRIBUTE_NORETURN +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS +// +// Tells the AddressSanitizer (or other memory testing tools) to ignore a given +// function. Useful for cases when a function reads random locations on stack, +// calls _exit from a cloned subprocess, deliberately accesses buffer +// out of bounds or does other scary things with memory. +// NOTE: GCC supports AddressSanitizer(asan) since 4.8. +// https://gcc.gnu.org/gcc-4.8/changes.html +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address) +#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY +// +// Tells the MemorySanitizer to relax the handling of a given function. All "Use +// of uninitialized value" warnings from such functions will be suppressed, and +// all values loaded from memory will be considered fully initialized. This +// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute +// above, but deals with initialized-ness rather than addressability issues. +// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC. +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory) +#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD +// +// Tells the ThreadSanitizer to not instrument a given function. +// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8. +// https://gcc.gnu.org/gcc-4.8/changes.html +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread) +#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED +// +// Tells the UndefinedSanitizer to ignore a given function. Useful for cases +// where certain behavior (eg. division by zero) is being used intentionally. +// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9. +// https://gcc.gnu.org/gcc-4.9/changes.html +#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined) +#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ + __attribute__((no_sanitize_undefined)) +#elif ABSL_HAVE_ATTRIBUTE(no_sanitize) +#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ + __attribute__((no_sanitize("undefined"))) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_CFI +// +// Tells the ControlFlowIntegrity sanitizer to not instrument a given function. +// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) +#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI +#endif + +// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +// +// Tells the SafeStack to not instrument a given function. +// See https://clang.llvm.org/docs/SafeStack.html for details. +#if ABSL_HAVE_ATTRIBUTE(no_sanitize) +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ + __attribute__((no_sanitize("safe-stack"))) +#else +#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK +#endif + +// ABSL_ATTRIBUTE_RETURNS_NONNULL +// +// Tells the compiler that a particular function never returns a null pointer. +#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) +#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) +#else +#define ABSL_ATTRIBUTE_RETURNS_NONNULL +#endif + +// ABSL_HAVE_ATTRIBUTE_SECTION +// +// Indicates whether labeled sections are supported. Weak symbol support is +// a prerequisite. Labeled sections are not supported on Darwin/iOS. +#ifdef ABSL_HAVE_ATTRIBUTE_SECTION +#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set +#elif (ABSL_HAVE_ATTRIBUTE(section) || \ + (defined(__GNUC__) && !defined(__clang__))) && \ + !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK +#define ABSL_HAVE_ATTRIBUTE_SECTION 1 + +// ABSL_ATTRIBUTE_SECTION +// +// Tells the compiler/linker to put a given function into a section and define +// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. +// This functionality is supported by GNU linker. Any function annotated with +// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into +// whatever section its caller is placed into. +// +#ifndef ABSL_ATTRIBUTE_SECTION +#define ABSL_ATTRIBUTE_SECTION(name) \ + __attribute__((section(#name))) __attribute__((noinline)) +#endif + + +// ABSL_ATTRIBUTE_SECTION_VARIABLE +// +// Tells the compiler/linker to put a given variable into a section and define +// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. +// This functionality is supported by GNU linker. +#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE +#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name))) +#endif + +// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS +// +// A weak section declaration to be used as a global declaration +// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link +// even without functions with ABSL_ATTRIBUTE_SECTION(name). +// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's +// a no-op on ELF but not on Mach-O. +// +#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS +#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \ + extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \ + extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK +#endif +#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS +#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) +#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) +#endif + +// ABSL_ATTRIBUTE_SECTION_START +// +// Returns `void*` pointers to start/end of a section of code with +// functions having ABSL_ATTRIBUTE_SECTION(name). +// Returns 0 if no such functions exist. +// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and +// link. +// +#define ABSL_ATTRIBUTE_SECTION_START(name) \ + (reinterpret_cast(__start_##name)) +#define ABSL_ATTRIBUTE_SECTION_STOP(name) \ + (reinterpret_cast(__stop_##name)) + +#else // !ABSL_HAVE_ATTRIBUTE_SECTION + +#define ABSL_HAVE_ATTRIBUTE_SECTION 0 + +// provide dummy definitions +#define ABSL_ATTRIBUTE_SECTION(name) +#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) +#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) +#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) +#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) +#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast(0)) +#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast(0)) + +#endif // ABSL_ATTRIBUTE_SECTION + +// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC +// +// Support for aligning the stack on 32-bit x86. +#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \ + (defined(__GNUC__) && !defined(__clang__)) +#if defined(__i386__) +#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \ + __attribute__((force_align_arg_pointer)) +#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) +#elif defined(__x86_64__) +#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1) +#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC +#else // !__i386__ && !__x86_64 +#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) +#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC +#endif // __i386__ +#else +#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC +#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) +#endif + +// ABSL_MUST_USE_RESULT +// +// Tells the compiler to warn about unused results. +// +// When annotating a function, it must appear as the first part of the +// declaration or definition. The compiler will warn if the return value from +// such a function is unused: +// +// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); +// AllocateSprocket(); // Triggers a warning. +// +// When annotating a class, it is equivalent to annotating every function which +// returns an instance. +// +// class ABSL_MUST_USE_RESULT Sprocket {}; +// Sprocket(); // Triggers a warning. +// +// Sprocket MakeSprocket(); +// MakeSprocket(); // Triggers a warning. +// +// Note that references and pointers are not instances: +// +// Sprocket* SprocketPointer(); +// SprocketPointer(); // Does *not* trigger a warning. +// +// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result +// warning. For that, warn_unused_result is used only for clang but not for gcc. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 +// +// Note: past advice was to place the macro after the argument list. +#if ABSL_HAVE_ATTRIBUTE(nodiscard) +#define ABSL_MUST_USE_RESULT [[nodiscard]] +#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) +#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) +#else +#define ABSL_MUST_USE_RESULT +#endif + +// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD +// +// Tells GCC that a function is hot or cold. GCC can use this information to +// improve static analysis, i.e. a conditional branch to a cold function +// is likely to be not-taken. +// This annotation is used for function declarations. +// +// Example: +// +// int foo() ABSL_ATTRIBUTE_HOT; +#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_HOT __attribute__((hot)) +#else +#define ABSL_ATTRIBUTE_HOT +#endif + +#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_COLD __attribute__((cold)) +#else +#define ABSL_ATTRIBUTE_COLD +#endif + +// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS +// +// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT +// macro used as an attribute to mark functions that must always or never be +// instrumented by XRay. Currently, this is only supported in Clang/LLVM. +// +// For reference on the LLVM XRay instrumentation, see +// http://llvm.org/docs/XRay.html. +// +// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration +// will always get the XRay instrumentation sleds. These sleds may introduce +// some binary size and runtime overhead and must be used sparingly. +// +// These attributes only take effect when the following conditions are met: +// +// * The file/target is built in at least C++11 mode, with a Clang compiler +// that supports XRay attributes. +// * The file/target is built with the -fxray-instrument flag set for the +// Clang/LLVM compiler. +// * The function is defined in the translation unit (the compiler honors the +// attribute in either the definition or the declaration, and must match). +// +// There are cases when, even when building with XRay instrumentation, users +// might want to control specifically which functions are instrumented for a +// particular build using special-case lists provided to the compiler. These +// special case lists are provided to Clang via the +// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The +// attributes in source take precedence over these special-case lists. +// +// To disable the XRay attributes at build-time, users may define +// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific +// packages/targets, as this may lead to conflicting definitions of functions at +// link-time. +// +// XRay isn't currently supported on Android: +// https://github.com/android/ndk/issues/368 +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \ + !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__) +#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] +#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args) +#define ABSL_XRAY_LOG_ARGS(N) \ + [[clang::xray_always_instrument, clang::xray_log_args(N)]] +#else +#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]] +#endif +#else +#define ABSL_XRAY_ALWAYS_INSTRUMENT +#define ABSL_XRAY_NEVER_INSTRUMENT +#define ABSL_XRAY_LOG_ARGS(N) +#endif + +// ABSL_ATTRIBUTE_REINITIALIZES +// +// Indicates that a member function reinitializes the entire object to a known +// state, independent of the previous state of the object. +// +// The clang-tidy check bugprone-use-after-move allows member functions marked +// with this attribute to be called on objects that have been moved from; +// without the attribute, this would result in a use-after-move warning. +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes) +#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define ABSL_ATTRIBUTE_REINITIALIZES +#endif + +// ----------------------------------------------------------------------------- +// Variable Attributes +// ----------------------------------------------------------------------------- + +// ABSL_ATTRIBUTE_UNUSED +// +// Prevents the compiler from complaining about variables that appear unused. +// +// For code or headers that are assured to only build with C++17 and up, prefer +// just using the standard '[[maybe_unused]]' directly over this macro. +// +// Due to differences in positioning requirements between the old, compiler +// specific __attribute__ syntax and the now standard [[maybe_unused]], this +// macro does not attempt to take advantage of '[[maybe_unused]]'. +#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) +#undef ABSL_ATTRIBUTE_UNUSED +#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#else +#define ABSL_ATTRIBUTE_UNUSED +#endif + +// ABSL_ATTRIBUTE_INITIAL_EXEC +// +// Tells the compiler to use "initial-exec" mode for a thread-local variable. +// See http://people.redhat.com/drepper/tls.pdf for the gory details. +#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec"))) +#else +#define ABSL_ATTRIBUTE_INITIAL_EXEC +#endif + +// ABSL_ATTRIBUTE_PACKED +// +// Instructs the compiler not to use natural alignment for a tagged data +// structure, but instead to reduce its alignment to 1. This attribute can +// either be applied to members of a structure or to a structure in its +// entirety. Applying this attribute (judiciously) to a structure in its +// entirety to optimize the memory footprint of very commonly-used structs is +// fine. Do not apply this attribute to a structure in its entirety if the +// purpose is to control the offsets of the members in the structure. Instead, +// apply this attribute only to structure members that need it. +// +// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the +// natural alignment of structure members not annotated is preserved. Aligned +// member accesses are faster than non-aligned member accesses even if the +// targeted microprocessor supports non-aligned accesses. +#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__)) +#else +#define ABSL_ATTRIBUTE_PACKED +#endif + +// ABSL_ATTRIBUTE_FUNC_ALIGN +// +// Tells the compiler to align the function start at least to certain +// alignment boundary +#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes))) +#else +#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) +#endif + +// ABSL_FALLTHROUGH_INTENDED +// +// Annotates implicit fall-through between switch labels, allowing a case to +// indicate intentional fallthrough and turn off warnings about any lack of a +// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by +// a semicolon and can be used in most places where `break` can, provided that +// no statements exist between it and the next switch label. +// +// Example: +// +// switch (x) { +// case 40: +// case 41: +// if (truth_is_out_there) { +// ++x; +// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations +// // in comments +// } else { +// return x; +// } +// case 42: +// ... +// +// Notes: When supported, GCC and Clang can issue a warning on switch labels +// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See +// clang documentation on language extensions for details: +// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough +// +// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has +// no effect on diagnostics. In any case this macro has no effect on runtime +// behavior and performance of code. + +#ifdef ABSL_FALLTHROUGH_INTENDED +#error "ABSL_FALLTHROUGH_INTENDED should not be defined." +#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]] +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] +#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough) +#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] +#else +#define ABSL_FALLTHROUGH_INTENDED \ + do { \ + } while (0) +#endif + +// ABSL_DEPRECATED() +// +// Marks a deprecated class, struct, enum, function, method and variable +// declarations. The macro argument is used as a custom diagnostic message (e.g. +// suggestion of a better alternative). +// +// Examples: +// +// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; +// +// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...} +// +// template +// ABSL_DEPRECATED("Use DoThat() instead") +// void DoThis(); +// +// Every usage of a deprecated entity will trigger a warning when compiled with +// clang's `-Wdeprecated-declarations` option. This option is turned off by +// default, but the warnings will be reported by clang-tidy. +#if defined(__clang__) && defined(__cplusplus) && __cplusplus >= 201103L +#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) +#endif + +#ifndef ABSL_DEPRECATED +#define ABSL_DEPRECATED(message) +#endif + +// ABSL_CONST_INIT +// +// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will +// not compile (on supported platforms) unless the variable has a constant +// initializer. This is useful for variables with static and thread storage +// duration, because it guarantees that they will not suffer from the so-called +// "static init order fiasco". Prefer to put this attribute on the most visible +// declaration of the variable, if there's more than one, because code that +// accesses the variable can then use the attribute for optimization. +// +// Example: +// +// class MyClass { +// public: +// ABSL_CONST_INIT static MyType my_var; +// }; +// +// MyType MyClass::my_var = MakeMyType(...); +// +// Note that this attribute is redundant if the variable is declared constexpr. +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) +#define ABSL_CONST_INIT [[clang::require_constant_initialization]] +#else +#define ABSL_CONST_INIT +#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) + +// ABSL_ATTRIBUTE_PURE_FUNCTION +// +// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure" +// functions. A function is pure if its return value is only a function of its +// arguments. The pure attribute prohibits a function from modifying the state +// of the program that is observable by means other than inspecting the +// function's return value. Declaring such functions with the pure attribute +// allows the compiler to avoid emitting some calls in repeated invocations of +// the function with the same argument values. +// +// Example: +// +// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d); +#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure) +#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]] +#elif ABSL_HAVE_ATTRIBUTE(pure) +#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure)) +#else +#define ABSL_ATTRIBUTE_PURE_FUNCTION +#endif + +// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function +// parameter or implicit object parameter is retained by the return value of the +// annotated function (or, for a parameter of a constructor, in the value of the +// constructed object). This attribute causes warnings to be produced if a +// temporary object does not live long enough. +// +// When applied to a reference parameter, the referenced object is assumed to be +// retained by the return value of the function. When applied to a non-reference +// parameter (for example, a pointer or a class type), all temporaries +// referenced by the parameter are assumed to be retained by the return value of +// the function. +// +// See also the upstream documentation: +// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound) +#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]] +#elif ABSL_HAVE_ATTRIBUTE(lifetimebound) +#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound)) +#else +#define ABSL_ATTRIBUTE_LIFETIME_BOUND +#endif + +#endif // ABSL_BASE_ATTRIBUTES_H_ diff --git a/extern/int128/absl/base/config.h b/extern/int128/absl/base/config.h new file mode 100644 index 00000000000..a6e7c86a0c9 --- /dev/null +++ b/extern/int128/absl/base/config.h @@ -0,0 +1,745 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: config.h +// ----------------------------------------------------------------------------- +// +// This header file defines a set of macros for checking the presence of +// important compiler and platform features. Such macros can be used to +// produce portable code by parameterizing compilation based on the presence or +// lack of a given feature. +// +// We define a "feature" as some interface we wish to program to: for example, +// a library function or system call. A value of `1` indicates support for +// that feature; any other value indicates the feature support is undefined. +// +// Example: +// +// Suppose a programmer wants to write a program that uses the 'mmap()' system +// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to +// selectively include the `mmap.h` header and bracket code using that feature +// in the macro: +// +// #include "absl/base/config.h" +// +// #ifdef ABSL_HAVE_MMAP +// #include "sys/mman.h" +// #endif //ABSL_HAVE_MMAP +// +// ... +// #ifdef ABSL_HAVE_MMAP +// void *ptr = mmap(...); +// ... +// #endif // ABSL_HAVE_MMAP + +#ifndef ABSL_BASE_CONFIG_H_ +#define ABSL_BASE_CONFIG_H_ + +// Included for the __GLIBC__ macro (or similar macros on other systems). +#include + +#ifdef __cplusplus +// Included for __GLIBCXX__, _LIBCPP_VERSION +#include +#endif // __cplusplus + +#if defined(__APPLE__) +// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED, +// __IPHONE_8_0. +#include +#include +#endif + +#include "absl/base/options.h" +#include "absl/base/policy_checks.h" + +// Helper macro to convert a CPP variable to a string literal. +#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x +#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x) + +// ----------------------------------------------------------------------------- +// Abseil namespace annotations +// ----------------------------------------------------------------------------- + +// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END +// +// An annotation placed at the beginning/end of each `namespace absl` scope. +// This is used to inject an inline namespace. +// +// The proper way to write Abseil code in the `absl` namespace is: +// +// namespace absl { +// ABSL_NAMESPACE_BEGIN +// +// void Foo(); // absl::Foo(). +// +// ABSL_NAMESPACE_END +// } // namespace absl +// +// Users of Abseil should not use these macros, because users of Abseil should +// not write `namespace absl {` in their own code for any reason. (Abseil does +// not support forward declarations of its own types, nor does it support +// user-provided specialization of Abseil templates. Code that violates these +// rules may be broken without warning.) +#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \ + !defined(ABSL_OPTION_INLINE_NAMESPACE_NAME) +#error options.h is misconfigured. +#endif + +// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor "" +#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1 + +#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \ + ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) + +static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0', + "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must " + "not be empty."); +static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || + ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' || + ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' || + ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' || + ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0', + "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must " + "be changed to a new, unique identifier name."); + +#endif + +#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 +#define ABSL_NAMESPACE_BEGIN +#define ABSL_NAMESPACE_END +#define ABSL_INTERNAL_C_SYMBOL(x) x +#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1 +#define ABSL_NAMESPACE_BEGIN \ + inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME { +#define ABSL_NAMESPACE_END } +#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v +#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \ + ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) +#define ABSL_INTERNAL_C_SYMBOL(x) \ + ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME) +#else +#error options.h is misconfigured. +#endif + +// ----------------------------------------------------------------------------- +// Compiler Feature Checks +// ----------------------------------------------------------------------------- + +// ABSL_HAVE_BUILTIN() +// +// Checks whether the compiler supports a Clang Feature Checking Macro, and if +// so, checks whether it supports the provided builtin function "x" where x +// is one of the functions noted in +// https://clang.llvm.org/docs/LanguageExtensions.html +// +// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check. +// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html +#ifdef __has_builtin +#define ABSL_HAVE_BUILTIN(x) __has_builtin(x) +#else +#define ABSL_HAVE_BUILTIN(x) 0 +#endif + +#if defined(__is_identifier) +#define ABSL_INTERNAL_HAS_KEYWORD(x) !(__is_identifier(x)) +#else +#define ABSL_INTERNAL_HAS_KEYWORD(x) 0 +#endif + +#ifdef __has_feature +#define ABSL_HAVE_FEATURE(f) __has_feature(f) +#else +#define ABSL_HAVE_FEATURE(f) 0 +#endif + +// Portable check for GCC minimum version: +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \ + (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +#else +#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0 +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \ + (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) +#else +#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0 +#endif + +// ABSL_HAVE_TLS is defined to 1 when __thread should be supported. +// We assume __thread is supported on Linux when compiled with Clang or compiled +// against libstdc++ with _GLIBCXX_HAVE_TLS defined. +#ifdef ABSL_HAVE_TLS +#error ABSL_HAVE_TLS cannot be directly set +#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS)) +#define ABSL_HAVE_TLS 1 +#endif + +// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE +// +// Checks whether `std::is_trivially_destructible` is supported. +// +// Notes: All supported compilers using libc++ support this feature, as does +// gcc >= 4.8.1 using libstdc++, and Visual Studio. +#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE +#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set +#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \ + (!defined(__clang__) && defined(__GLIBCXX__) && \ + ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8)) +#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1 +#endif + +// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE +// +// Checks whether `std::is_trivially_default_constructible` and +// `std::is_trivially_copy_constructible` are supported. + +// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE +// +// Checks whether `std::is_trivially_copy_assignable` is supported. + +// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with +// either libc++ or libstdc++, and Visual Studio (but not NVCC). +#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) +#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set +#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE) +#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set +#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \ + (!defined(__clang__) && ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && \ + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ + (defined(_MSC_VER) && !defined(__NVCC__)) +#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 +#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 +#endif + +// ABSL_HAVE_SOURCE_LOCATION_CURRENT +// +// Indicates whether `absl::SourceLocation::current()` will return useful +// information in some contexts. +#ifndef ABSL_HAVE_SOURCE_LOCATION_CURRENT +#if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \ + ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE) +#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1 +#elif ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) +#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1 +#endif +#endif + +// ABSL_HAVE_THREAD_LOCAL +// +// Checks whether C++11's `thread_local` storage duration specifier is +// supported. +#ifdef ABSL_HAVE_THREAD_LOCAL +#error ABSL_HAVE_THREAD_LOCAL cannot be directly set +#elif defined(__APPLE__) +// Notes: +// * Xcode's clang did not support `thread_local` until version 8, and +// even then not for all iOS < 9.0. +// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator +// targeting iOS 9.x. +// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time +// making ABSL_HAVE_FEATURE unreliable there. +// +#if ABSL_HAVE_FEATURE(cxx_thread_local) && \ + !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) +#define ABSL_HAVE_THREAD_LOCAL 1 +#endif +#else // !defined(__APPLE__) +#define ABSL_HAVE_THREAD_LOCAL 1 +#endif + +// There are platforms for which TLS should not be used even though the compiler +// makes it seem like it's supported (Android NDK < r12b for example). +// This is primarily because of linker problems and toolchain misconfiguration: +// Abseil does not intend to support this indefinitely. Currently, the newest +// toolchain that we intend to support that requires this behavior is the +// r11 NDK - allowing for a 5 year support window on that means this option +// is likely to be removed around June of 2021. +// TLS isn't supported until NDK r12b per +// https://developer.android.com/ndk/downloads/revision_history.html +// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in +// . For NDK < r16, users should define these macros, +// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11. +#if defined(__ANDROID__) && defined(__clang__) +#if __has_include() +#include +#endif // __has_include() +#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \ + defined(__NDK_MINOR__) && \ + ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1))) +#undef ABSL_HAVE_TLS +#undef ABSL_HAVE_THREAD_LOCAL +#endif +#endif // defined(__ANDROID__) && defined(__clang__) + +// ABSL_HAVE_INTRINSIC_INT128 +// +// Checks whether the __int128 compiler extension for a 128-bit integral type is +// supported. +// +// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is +// supported, but we avoid using it in certain cases: +// * On Clang: +// * Building using Clang for Windows, where the Clang runtime library has +// 128-bit support only on LP64 architectures, but Windows is LLP64. +// * On Nvidia's nvcc: +// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions +// actually support __int128. + +/* Unfortunately FB does not support alignment requirements (16) in ODS + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set +#elif defined(__SIZEOF_INT128__) +#if (defined(__clang__) && !defined(_WIN32)) || \ + (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ + (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) +#define ABSL_HAVE_INTRINSIC_INT128 1 +#elif defined(__CUDACC__) +// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a +// string explaining that it has been removed starting with CUDA 9. We use +// nested #ifs because there is no short-circuiting in the preprocessor. +// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined. +#if __CUDACC_VER__ >= 70000 +#define ABSL_HAVE_INTRINSIC_INT128 1 +#endif // __CUDACC_VER__ >= 70000 +#endif // defined(__CUDACC__) +#endif // ABSL_HAVE_INTRINSIC_INT128 + */ +#undef ABSL_HAVE_INTRINSIC_INT128 + +// ABSL_HAVE_EXCEPTIONS +// +// Checks whether the compiler both supports and enables exceptions. Many +// compilers support a "no exceptions" mode that disables exceptions. +// +// Generally, when ABSL_HAVE_EXCEPTIONS is not defined: +// +// * Code using `throw` and `try` may not compile. +// * The `noexcept` specifier will still compile and behave as normal. +// * The `noexcept` operator may still return `false`. +// +// For further details, consult the compiler's documentation. +#ifdef ABSL_HAVE_EXCEPTIONS +#error ABSL_HAVE_EXCEPTIONS cannot be directly set. +#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6) +// Clang >= 3.6 +#if ABSL_HAVE_FEATURE(cxx_exceptions) +#define ABSL_HAVE_EXCEPTIONS 1 +#endif // ABSL_HAVE_FEATURE(cxx_exceptions) +#elif defined(__clang__) +// Clang < 3.6 +// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro +#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) +#define ABSL_HAVE_EXCEPTIONS 1 +#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) +// Handle remaining special cases and default to exceptions being supported. +#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \ + !(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) && \ + !defined(__cpp_exceptions)) && \ + !(defined(_MSC_VER) && !defined(_CPPUNWIND)) +#define ABSL_HAVE_EXCEPTIONS 1 +#endif + +// ----------------------------------------------------------------------------- +// Platform Feature Checks +// ----------------------------------------------------------------------------- + +// Currently supported operating systems and associated preprocessor +// symbols: +// +// Linux and Linux-derived __linux__ +// Android __ANDROID__ (implies __linux__) +// Linux (non-Android) __linux__ && !__ANDROID__ +// Darwin (macOS and iOS) __APPLE__ +// Akaros (http://akaros.org) __ros__ +// Windows _WIN32 +// NaCL __native_client__ +// AsmJS __asmjs__ +// WebAssembly __wasm__ +// Fuchsia __Fuchsia__ +// +// Note that since Android defines both __ANDROID__ and __linux__, one +// may probe for either Linux or Android by simply testing for __linux__. + +// ABSL_HAVE_MMAP +// +// Checks whether the platform has an mmap(2) implementation as defined in +// POSIX.1-2001. +#ifdef ABSL_HAVE_MMAP +#error ABSL_HAVE_MMAP cannot be directly set +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ + defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \ + defined(__ASYLO__) || defined(__myriad2__) +#define ABSL_HAVE_MMAP 1 +#endif + +// ABSL_HAVE_PTHREAD_GETSCHEDPARAM +// +// Checks whether the platform implements the pthread_(get|set)schedparam(3) +// functions as defined in POSIX.1-2001. +#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM +#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set +#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ + defined(__ros__) +#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 +#endif + +// ABSL_HAVE_SCHED_GETCPU +// +// Checks whether sched_getcpu is available. +#ifdef ABSL_HAVE_SCHED_GETCPU +#error ABSL_HAVE_SCHED_GETCPU cannot be directly set +#elif defined(__linux__) +#define ABSL_HAVE_SCHED_GETCPU 1 +#endif + +// ABSL_HAVE_SCHED_YIELD +// +// Checks whether the platform implements sched_yield(2) as defined in +// POSIX.1-2001. +#ifdef ABSL_HAVE_SCHED_YIELD +#error ABSL_HAVE_SCHED_YIELD cannot be directly set +#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) +#define ABSL_HAVE_SCHED_YIELD 1 +#endif + +// ABSL_HAVE_SEMAPHORE_H +// +// Checks whether the platform supports the header and sem_init(3) +// family of functions as standardized in POSIX.1-2001. +// +// Note: While Apple provides for both iOS and macOS, it is +// explicitly deprecated and will cause build failures if enabled for those +// platforms. We side-step the issue by not defining it here for Apple +// platforms. +#ifdef ABSL_HAVE_SEMAPHORE_H +#error ABSL_HAVE_SEMAPHORE_H cannot be directly set +#elif defined(__linux__) || defined(__ros__) +#define ABSL_HAVE_SEMAPHORE_H 1 +#endif + +// ABSL_HAVE_ALARM +// +// Checks whether the platform supports the header and alarm(2) +// function as standardized in POSIX.1-2001. +#ifdef ABSL_HAVE_ALARM +#error ABSL_HAVE_ALARM cannot be directly set +#elif defined(__GOOGLE_GRTE_VERSION__) +// feature tests for Google's GRTE +#define ABSL_HAVE_ALARM 1 +#elif defined(__GLIBC__) +// feature test for glibc +#define ABSL_HAVE_ALARM 1 +#elif defined(_MSC_VER) +// feature tests for Microsoft's library +#elif defined(__MINGW32__) +// mingw32 doesn't provide alarm(2): +// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h +// mingw-w64 provides a no-op implementation: +// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c +#elif defined(__EMSCRIPTEN__) +// emscripten doesn't support signals +#elif defined(__Fuchsia__) +// Signals don't exist on fuchsia. +#elif defined(__native_client__) +#else +// other standard libraries +#define ABSL_HAVE_ALARM 1 +#endif + +// ABSL_IS_LITTLE_ENDIAN +// ABSL_IS_BIG_ENDIAN +// +// Checks the endianness of the platform. +// +// Notes: uses the built in endian macros provided by GCC (since 4.6) and +// Clang (since 3.2); see +// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html. +// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error. +#if defined(ABSL_IS_BIG_ENDIAN) +#error "ABSL_IS_BIG_ENDIAN cannot be directly set." +#endif +#if defined(ABSL_IS_LITTLE_ENDIAN) +#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set." +#endif + +#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define ABSL_IS_LITTLE_ENDIAN 1 +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define ABSL_IS_BIG_ENDIAN 1 +#elif defined(_WIN32) +#define ABSL_IS_LITTLE_ENDIAN 1 +#else +#error "absl endian detection needs to be set up for your compiler" +#endif + +// macOS 10.13 and iOS 10.11 don't let you use , , or +// even though the headers exist and are publicly noted to work. See +// https://github.com/abseil/abseil-cpp/issues/207 and +// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes +// libc++ spells out the availability requirements in the file +// llvm-project/libcxx/include/__config via the #define +// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. +#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ + ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) +#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 +#else +#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 +#endif + +// ABSL_HAVE_STD_ANY +// +// Checks whether C++17 std::any is available by checking whether exists. +#ifdef ABSL_HAVE_STD_ANY +#error "ABSL_HAVE_STD_ANY cannot be directly set." +#endif + +#ifdef __has_include +#if __has_include() && defined(__cplusplus) && __cplusplus >= 201703L && \ + !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE +#define ABSL_HAVE_STD_ANY 1 +#endif +#endif + +// ABSL_HAVE_STD_OPTIONAL +// +// Checks whether C++17 std::optional is available. +#ifdef ABSL_HAVE_STD_OPTIONAL +#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set." +#endif + +#ifdef __has_include +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE +#define ABSL_HAVE_STD_OPTIONAL 1 +#endif +#endif + +// ABSL_HAVE_STD_VARIANT +// +// Checks whether C++17 std::variant is available. +#ifdef ABSL_HAVE_STD_VARIANT +#error "ABSL_HAVE_STD_VARIANT cannot be directly set." +#endif + +#ifdef __has_include +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE +#define ABSL_HAVE_STD_VARIANT 1 +#endif +#endif + +// ABSL_HAVE_STD_STRING_VIEW +// +// Checks whether C++17 std::string_view is available. +#ifdef ABSL_HAVE_STD_STRING_VIEW +#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." +#endif + +#ifdef __has_include +#if __has_include() && defined(__cplusplus) && \ + __cplusplus >= 201703L +#define ABSL_HAVE_STD_STRING_VIEW 1 +#endif +#endif + +// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than +// the support for , , , . So we use +// _MSC_VER to check whether we have VS 2017 RTM (when , , +// , is implemented) or higher. Also, `__cplusplus` is +// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language +// version. +// TODO(zhangxy): fix tests before enabling aliasing for `std::any`. +#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ + ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \ + (defined(__cplusplus) && __cplusplus > 201402)) +// #define ABSL_HAVE_STD_ANY 1 +#define ABSL_HAVE_STD_OPTIONAL 1 +#define ABSL_HAVE_STD_VARIANT 1 +#define ABSL_HAVE_STD_STRING_VIEW 1 +#endif + +// ABSL_USES_STD_ANY +// +// Indicates whether absl::any is an alias for std::any. +#if !defined(ABSL_OPTION_USE_STD_ANY) +#error options.h is misconfigured. +#elif ABSL_OPTION_USE_STD_ANY == 0 || \ + (ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY)) +#undef ABSL_USES_STD_ANY +#elif ABSL_OPTION_USE_STD_ANY == 1 || \ + (ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY)) +#define ABSL_USES_STD_ANY 1 +#else +#error options.h is misconfigured. +#endif + +// ABSL_USES_STD_OPTIONAL +// +// Indicates whether absl::optional is an alias for std::optional. +#if !defined(ABSL_OPTION_USE_STD_OPTIONAL) +#error options.h is misconfigured. +#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \ + (ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL)) +#undef ABSL_USES_STD_OPTIONAL +#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \ + (ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL)) +#define ABSL_USES_STD_OPTIONAL 1 +#else +#error options.h is misconfigured. +#endif + +// ABSL_USES_STD_VARIANT +// +// Indicates whether absl::variant is an alias for std::variant. +#if !defined(ABSL_OPTION_USE_STD_VARIANT) +#error options.h is misconfigured. +#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \ + (ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT)) +#undef ABSL_USES_STD_VARIANT +#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \ + (ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT)) +#define ABSL_USES_STD_VARIANT 1 +#else +#error options.h is misconfigured. +#endif + +// ABSL_USES_STD_STRING_VIEW +// +// Indicates whether absl::string_view is an alias for std::string_view. +#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW) +#error options.h is misconfigured. +#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \ + (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \ + !defined(ABSL_HAVE_STD_STRING_VIEW)) +#undef ABSL_USES_STD_STRING_VIEW +#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \ + (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \ + defined(ABSL_HAVE_STD_STRING_VIEW)) +#define ABSL_USES_STD_STRING_VIEW 1 +#else +#error options.h is misconfigured. +#endif + +// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION +// SEH exception from emplace for variant when constructing the +// struct can throw. This defeats some of variant_test and +// variant_exception_safety_test. +#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG) +#define ABSL_INTERNAL_MSVC_2017_DBG_MODE +#endif + +// ABSL_INTERNAL_MANGLED_NS +// ABSL_INTERNAL_MANGLED_BACKREFERENCE +// +// Internal macros for building up mangled names in our internal fork of CCTZ. +// This implementation detail is only needed and provided for the MSVC build. +// +// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is +// the mangled spelling of the `absl` namespace, and +// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing +// the proper count to skip past the CCTZ fork namespace names. (This number +// is one larger when there is an inline namespace name to skip.) +#if defined(_MSC_VER) +#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 +#define ABSL_INTERNAL_MANGLED_NS "absl" +#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5" +#else +#define ABSL_INTERNAL_MANGLED_NS \ + ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl" +#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6" +#endif +#endif + +#undef ABSL_INTERNAL_HAS_KEYWORD + +// ABSL_DLL +// +// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)` +// so we can annotate symbols appropriately as being exported. When used in +// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so +// that consumers know the symbol is defined inside the DLL. In all other cases, +// the macro expands to nothing. +#if defined(_MSC_VER) +#if defined(ABSL_BUILD_DLL) +#define ABSL_DLL __declspec(dllexport) +#elif defined(ABSL_CONSUME_DLL) +#define ABSL_DLL __declspec(dllimport) +#else +#define ABSL_DLL +#endif +#else +#define ABSL_DLL +#endif // defined(_MSC_VER) + +// ABSL_HAVE_MEMORY_SANITIZER +// +// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of +// a compiler instrumentation module and a run-time library. +#ifdef ABSL_HAVE_MEMORY_SANITIZER +#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_MEMORY__) +#define ABSL_HAVE_MEMORY_SANITIZER 1 +#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer) +#define ABSL_HAVE_MEMORY_SANITIZER 1 +#endif + +// ABSL_HAVE_THREAD_SANITIZER +// +// ThreadSanitizer (TSan) is a fast data race detector. +#ifdef ABSL_HAVE_THREAD_SANITIZER +#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_THREAD__) +#define ABSL_HAVE_THREAD_SANITIZER 1 +#elif ABSL_HAVE_FEATURE(thread_sanitizer) +#define ABSL_HAVE_THREAD_SANITIZER 1 +#endif + +// ABSL_HAVE_ADDRESS_SANITIZER +// +// AddressSanitizer (ASan) is a fast memory error detector. +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set." +#elif defined(__SANITIZE_ADDRESS__) +#define ABSL_HAVE_ADDRESS_SANITIZER 1 +#elif ABSL_HAVE_FEATURE(address_sanitizer) +#define ABSL_HAVE_ADDRESS_SANITIZER 1 +#endif + +// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION +// +// Class template argument deduction is a language feature added in C++17. +#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION +#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set." +#elif defined(__cpp_deduction_guides) +#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1 +#endif + +#endif // ABSL_BASE_CONFIG_H_ diff --git a/extern/int128/absl/base/macros.h b/extern/int128/absl/base/macros.h new file mode 100644 index 00000000000..3e085a916bb --- /dev/null +++ b/extern/int128/absl/base/macros.h @@ -0,0 +1,158 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: macros.h +// ----------------------------------------------------------------------------- +// +// This header file defines the set of language macros used within Abseil code. +// For the set of macros used to determine supported compilers and platforms, +// see absl/base/config.h instead. +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. + +#ifndef ABSL_BASE_MACROS_H_ +#define ABSL_BASE_MACROS_H_ + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/optimization.h" +#include "absl/base/port.h" + +// ABSL_ARRAYSIZE() +// +// Returns the number of elements in an array as a compile-time constant, which +// can be used in defining new arrays. If you use this macro on a pointer by +// mistake, you will get a compile-time error. +#define ABSL_ARRAYSIZE(array) \ + (sizeof(::absl::macros_internal::ArraySizeHelper(array))) + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace macros_internal { +// Note: this internal template function declaration is used by ABSL_ARRAYSIZE. +// The function doesn't need a definition, as we only use its type. +template +auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; +} // namespace macros_internal +ABSL_NAMESPACE_END +} // namespace absl + +// ABSL_BAD_CALL_IF() +// +// Used on a function overload to trap bad calls: any call that matches the +// overload will cause a compile-time error. This macro uses a clang-specific +// "enable_if" attribute, as described at +// https://clang.llvm.org/docs/AttributeReference.html#enable-if +// +// Overloads which use this macro should be bracketed by +// `#ifdef ABSL_BAD_CALL_IF`. +// +// Example: +// +// int isdigit(int c); +// #ifdef ABSL_BAD_CALL_IF +// int isdigit(int c) +// ABSL_BAD_CALL_IF(c <= -1 || c > 255, +// "'c' must have the value of an unsigned char or EOF"); +// #endif // ABSL_BAD_CALL_IF +#if ABSL_HAVE_ATTRIBUTE(enable_if) +#define ABSL_BAD_CALL_IF(expr, msg) \ + __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg))) +#endif + +// ABSL_ASSERT() +// +// In C++11, `assert` can't be used portably within constexpr functions. +// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr +// functions. Example: +// +// constexpr double Divide(double a, double b) { +// return ABSL_ASSERT(b != 0), a / b; +// } +// +// This macro is inspired by +// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/ +#if defined(NDEBUG) +#define ABSL_ASSERT(expr) \ + (false ? static_cast(expr) : static_cast(0)) +#else +#define ABSL_ASSERT(expr) \ + (ABSL_PREDICT_TRUE((expr)) ? static_cast(0) \ + : [] { assert(false && #expr); }()) // NOLINT +#endif + +// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()` +// aborts the program in release mode (when NDEBUG is defined). The +// implementation should abort the program as quickly as possible and ideally it +// should not be possible to ignore the abort request. +#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \ + ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_INTERNAL_HARDENING_ABORT() \ + do { \ + __builtin_trap(); \ + __builtin_unreachable(); \ + } while (false) +#else +#define ABSL_INTERNAL_HARDENING_ABORT() abort() +#endif + +// ABSL_HARDENING_ASSERT() +// +// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement +// runtime assertions that should be enabled in hardened builds even when +// `NDEBUG` is defined. +// +// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to +// `ABSL_ASSERT()`. +// +// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on +// hardened mode. +#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG) +#define ABSL_HARDENING_ASSERT(expr) \ + (ABSL_PREDICT_TRUE((expr)) ? static_cast(0) \ + : [] { ABSL_INTERNAL_HARDENING_ABORT(); }()) +#else +#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr) +#endif + +#ifdef ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY try +#define ABSL_INTERNAL_CATCH_ANY catch (...) +#define ABSL_INTERNAL_RETHROW do { throw; } while (false) +#else // ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY if (true) +#define ABSL_INTERNAL_CATCH_ANY else if (false) +#define ABSL_INTERNAL_RETHROW do {} while (false) +#endif // ABSL_HAVE_EXCEPTIONS + +// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which +// reaches one has undefined behavior, and the compiler may optimize +// accordingly. +#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_UNREACHABLE __assume(0) +#else +#define ABSL_INTERNAL_UNREACHABLE +#endif + +#endif // ABSL_BASE_MACROS_H_ diff --git a/extern/int128/absl/base/optimization.h b/extern/int128/absl/base/optimization.h new file mode 100644 index 00000000000..d090be12868 --- /dev/null +++ b/extern/int128/absl/base/optimization.h @@ -0,0 +1,244 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: optimization.h +// ----------------------------------------------------------------------------- +// +// This header file defines portable macros for performance optimization. + +#ifndef ABSL_BASE_OPTIMIZATION_H_ +#define ABSL_BASE_OPTIMIZATION_H_ + +#include + +#include "absl/base/config.h" + +// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION +// +// Instructs the compiler to avoid optimizing tail-call recursion. This macro is +// useful when you wish to preserve the existing function order within a stack +// trace for logging, debugging, or profiling purposes. +// +// Example: +// +// int f() { +// int result = g(); +// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); +// return result; +// } +#if defined(__pnacl__) +#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } +#elif defined(__clang__) +// Clang will not tail call given inline volatile assembly. +#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") +#elif defined(__GNUC__) +// GCC will not tail call given inline volatile assembly. +#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") +#elif defined(_MSC_VER) +#include +// The __nop() intrinsic blocks the optimisation. +#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop() +#else +#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } +#endif + +// ABSL_CACHELINE_SIZE +// +// Explicitly defines the size of the L1 cache for purposes of alignment. +// Setting the cacheline size allows you to specify that certain objects be +// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations. +// (See below.) +// +// NOTE: this macro should be replaced with the following C++17 features, when +// those are generally available: +// +// * `std::hardware_constructive_interference_size` +// * `std::hardware_destructive_interference_size` +// +// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html +// for more information. +#if defined(__GNUC__) +// Cache line alignment +#if defined(__i386__) || defined(__x86_64__) +#define ABSL_CACHELINE_SIZE 64 +#elif defined(__powerpc64__) +#define ABSL_CACHELINE_SIZE 128 +#elif defined(__aarch64__) +// We would need to read special register ctr_el0 to find out L1 dcache size. +// This value is a good estimate based on a real aarch64 machine. +#define ABSL_CACHELINE_SIZE 64 +#elif defined(__arm__) +// Cache line sizes for ARM: These values are not strictly correct since +// cache line sizes depend on implementations, not architectures. There +// are even implementations with cache line sizes configurable at boot +// time. +#if defined(__ARM_ARCH_5T__) +#define ABSL_CACHELINE_SIZE 32 +#elif defined(__ARM_ARCH_7A__) +#define ABSL_CACHELINE_SIZE 64 +#endif +#endif + +#ifndef ABSL_CACHELINE_SIZE +// A reasonable default guess. Note that overestimates tend to waste more +// space, while underestimates tend to waste more time. +#define ABSL_CACHELINE_SIZE 64 +#endif + +// ABSL_CACHELINE_ALIGNED +// +// Indicates that the declared object be cache aligned using +// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to +// load a set of related objects in the L1 cache for performance improvements. +// Cacheline aligning objects properly allows constructive memory sharing and +// prevents destructive (or "false") memory sharing. +// +// NOTE: callers should replace uses of this macro with `alignas()` using +// `std::hardware_constructive_interference_size` and/or +// `std::hardware_destructive_interference_size` when C++17 becomes available to +// them. +// +// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html +// for more information. +// +// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__` +// or `__declspec` attribute. For compilers where this is not known to work, +// the macro expands to nothing. +// +// No further guarantees are made here. The result of applying the macro +// to variables and types is always implementation-defined. +// +// WARNING: It is easy to use this attribute incorrectly, even to the point +// of causing bugs that are difficult to diagnose, crash, etc. It does not +// of itself guarantee that objects are aligned to a cache line. +// +// NOTE: Some compilers are picky about the locations of annotations such as +// this attribute, so prefer to put it at the beginning of your declaration. +// For example, +// +// ABSL_CACHELINE_ALIGNED static Foo* foo = ... +// +// class ABSL_CACHELINE_ALIGNED Bar { ... +// +// Recommendations: +// +// 1) Consult compiler documentation; this comment is not kept in sync as +// toolchains evolve. +// 2) Verify your use has the intended effect. This often requires inspecting +// the generated machine code. +// 3) Prefer applying this attribute to individual variables. Avoid +// applying it to types. This tends to localize the effect. +#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE))) +#elif defined(_MSC_VER) +#define ABSL_CACHELINE_SIZE 64 +#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE)) +#else +#define ABSL_CACHELINE_SIZE 64 +#define ABSL_CACHELINE_ALIGNED +#endif + +// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE +// +// Enables the compiler to prioritize compilation using static analysis for +// likely paths within a boolean branch. +// +// Example: +// +// if (ABSL_PREDICT_TRUE(expression)) { +// return result; // Faster if more likely +// } else { +// return 0; +// } +// +// Compilers can use the information that a certain branch is not likely to be +// taken (for instance, a CHECK failure) to optimize for the common case in +// the absence of better information (ie. compiling gcc with `-fprofile-arcs`). +// +// Recommendation: Modern CPUs dynamically predict branch execution paths, +// typically with accuracy greater than 97%. As a result, annotating every +// branch in a codebase is likely counterproductive; however, annotating +// specific branches that are both hot and consistently mispredicted is likely +// to yield performance improvements. +#if ABSL_HAVE_BUILTIN(__builtin_expect) || \ + (defined(__GNUC__) && !defined(__clang__)) +#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false)) +#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true)) +#else +#define ABSL_PREDICT_FALSE(x) (x) +#define ABSL_PREDICT_TRUE(x) (x) +#endif + +// ABSL_INTERNAL_ASSUME(cond) +// Informs the compiler that a condition is always true and that it can assume +// it to be true for optimization purposes. The call has undefined behavior if +// the condition is false. +// In !NDEBUG mode, the condition is checked with an assert(). +// NOTE: The expression must not have side effects, as it will only be evaluated +// in some compilation modes and not others. +// +// Example: +// +// int x = ...; +// ABSL_INTERNAL_ASSUME(x >= 0); +// // The compiler can optimize the division to a simple right shift using the +// // assumption specified above. +// int y = x / 16; +// +#if !defined(NDEBUG) +#define ABSL_INTERNAL_ASSUME(cond) assert(cond) +#elif ABSL_HAVE_BUILTIN(__builtin_assume) +#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond) +#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + if (!(cond)) __builtin_unreachable(); \ + } while (0) +#elif defined(_MSC_VER) +#define ABSL_INTERNAL_ASSUME(cond) __assume(cond) +#else +#define ABSL_INTERNAL_ASSUME(cond) \ + do { \ + static_cast(false && (cond)); \ + } while (0) +#endif + +// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond) +// This macro forces small unique name on a static file level symbols like +// static local variables or static functions. This is intended to be used in +// macro definitions to optimize the cost of generated code. Do NOT use it on +// symbols exported from translation unit since it may cause a link time +// conflict. +// +// Example: +// +// #define MY_MACRO(txt) +// namespace { +// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt; +// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME(); +// const char* VeryVeryLongFuncName() { return txt; } +// } +// + +#if defined(__GNUC__) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \ + asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__)) +#else +#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() +#endif + +#endif // ABSL_BASE_OPTIMIZATION_H_ diff --git a/extern/int128/absl/base/options.h b/extern/int128/absl/base/options.h new file mode 100644 index 00000000000..230bf1eecc4 --- /dev/null +++ b/extern/int128/absl/base/options.h @@ -0,0 +1,238 @@ +// Copyright 2019 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: options.h +// ----------------------------------------------------------------------------- +// +// This file contains Abseil configuration options for setting specific +// implementations instead of letting Abseil determine which implementation to +// use at compile-time. Setting these options may be useful for package or build +// managers who wish to guarantee ABI stability within binary builds (which are +// otherwise difficult to enforce). +// +// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that +// maintainers of package managers who wish to package Abseil read and +// understand this file! *** +// +// Abseil contains a number of possible configuration endpoints, based on +// parameters such as the detected platform, language version, or command-line +// flags used to invoke the underlying binary. As is the case with all +// libraries, binaries which contain Abseil code must ensure that separate +// packages use the same compiled copy of Abseil to avoid a diamond dependency +// problem, which can occur if two packages built with different Abseil +// configuration settings are linked together. Diamond dependency problems in +// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in +// linker errors), or undefined behavior (resulting in crashes). +// +// Diamond dependency problems can be avoided if all packages utilize the same +// exact version of Abseil. Building from source code with the same compilation +// parameters is the easiest way to avoid such dependency problems. However, for +// package managers who cannot control such compilation parameters, we are +// providing the file to allow you to inject ABI (Application Binary Interface) +// stability across builds. Settings options in this file will neither change +// API nor ABI, providing a stable copy of Abseil between packages. +// +// Care must be taken to keep options within these configurations isolated +// from any other dynamic settings, such as command-line flags which could alter +// these options. This file is provided specifically to help build and package +// managers provide a stable copy of Abseil within their libraries and binaries; +// other developers should not have need to alter the contents of this file. +// +// ----------------------------------------------------------------------------- +// Usage +// ----------------------------------------------------------------------------- +// +// For any particular package release, set the appropriate definitions within +// this file to whatever value makes the most sense for your package(s). Note +// that, by default, most of these options, at the moment, affect the +// implementation of types; future options may affect other implementation +// details. +// +// NOTE: the defaults within this file all assume that Abseil can select the +// proper Abseil implementation at compile-time, which will not be sufficient +// to guarantee ABI stability to package managers. + +#ifndef ABSL_BASE_OPTIONS_H_ +#define ABSL_BASE_OPTIONS_H_ + +// Include a standard library header to allow configuration based on the +// standard library in use. +#ifdef __cplusplus +#include +#endif + +// ----------------------------------------------------------------------------- +// Type Compatibility Options +// ----------------------------------------------------------------------------- +// +// ABSL_OPTION_USE_STD_ANY +// +// This option controls whether absl::any is implemented as an alias to +// std::any, or as an independent implementation. +// +// A value of 0 means to use Abseil's implementation. This requires only C++11 +// support, and is expected to work on every toolchain we support. +// +// A value of 1 means to use an alias to std::any. This requires that all code +// using Abseil is built in C++17 mode or later. +// +// A value of 2 means to detect the C++ version being used to compile Abseil, +// and use an alias only if a working std::any is available. This option is +// useful when you are building your entire program, including all of its +// dependencies, from source. It should not be used otherwise -- for example, +// if you are distributing Abseil in a binary package manager -- since in +// mode 2, absl::any will name a different type, with a different mangled name +// and binary layout, depending on the compiler flags passed by the end user. +// For more info, see https://abseil.io/about/design/dropin-types. +// +// User code should not inspect this macro. To check in the preprocessor if +// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY. + +#define ABSL_OPTION_USE_STD_ANY 2 + + +// ABSL_OPTION_USE_STD_OPTIONAL +// +// This option controls whether absl::optional is implemented as an alias to +// std::optional, or as an independent implementation. +// +// A value of 0 means to use Abseil's implementation. This requires only C++11 +// support, and is expected to work on every toolchain we support. +// +// A value of 1 means to use an alias to std::optional. This requires that all +// code using Abseil is built in C++17 mode or later. +// +// A value of 2 means to detect the C++ version being used to compile Abseil, +// and use an alias only if a working std::optional is available. This option +// is useful when you are building your program from source. It should not be +// used otherwise -- for example, if you are distributing Abseil in a binary +// package manager -- since in mode 2, absl::optional will name a different +// type, with a different mangled name and binary layout, depending on the +// compiler flags passed by the end user. For more info, see +// https://abseil.io/about/design/dropin-types. + +// User code should not inspect this macro. To check in the preprocessor if +// absl::optional is a typedef of std::optional, use the feature macro +// ABSL_USES_STD_OPTIONAL. + +#define ABSL_OPTION_USE_STD_OPTIONAL 2 + + +// ABSL_OPTION_USE_STD_STRING_VIEW +// +// This option controls whether absl::string_view is implemented as an alias to +// std::string_view, or as an independent implementation. +// +// A value of 0 means to use Abseil's implementation. This requires only C++11 +// support, and is expected to work on every toolchain we support. +// +// A value of 1 means to use an alias to std::string_view. This requires that +// all code using Abseil is built in C++17 mode or later. +// +// A value of 2 means to detect the C++ version being used to compile Abseil, +// and use an alias only if a working std::string_view is available. This +// option is useful when you are building your program from source. It should +// not be used otherwise -- for example, if you are distributing Abseil in a +// binary package manager -- since in mode 2, absl::string_view will name a +// different type, with a different mangled name and binary layout, depending on +// the compiler flags passed by the end user. For more info, see +// https://abseil.io/about/design/dropin-types. +// +// User code should not inspect this macro. To check in the preprocessor if +// absl::string_view is a typedef of std::string_view, use the feature macro +// ABSL_USES_STD_STRING_VIEW. + +#define ABSL_OPTION_USE_STD_STRING_VIEW 2 + +// ABSL_OPTION_USE_STD_VARIANT +// +// This option controls whether absl::variant is implemented as an alias to +// std::variant, or as an independent implementation. +// +// A value of 0 means to use Abseil's implementation. This requires only C++11 +// support, and is expected to work on every toolchain we support. +// +// A value of 1 means to use an alias to std::variant. This requires that all +// code using Abseil is built in C++17 mode or later. +// +// A value of 2 means to detect the C++ version being used to compile Abseil, +// and use an alias only if a working std::variant is available. This option +// is useful when you are building your program from source. It should not be +// used otherwise -- for example, if you are distributing Abseil in a binary +// package manager -- since in mode 2, absl::variant will name a different +// type, with a different mangled name and binary layout, depending on the +// compiler flags passed by the end user. For more info, see +// https://abseil.io/about/design/dropin-types. +// +// User code should not inspect this macro. To check in the preprocessor if +// absl::variant is a typedef of std::variant, use the feature macro +// ABSL_USES_STD_VARIANT. + +#define ABSL_OPTION_USE_STD_VARIANT 2 + + +// ABSL_OPTION_USE_INLINE_NAMESPACE +// ABSL_OPTION_INLINE_NAMESPACE_NAME +// +// These options controls whether all entities in the absl namespace are +// contained within an inner inline namespace. This does not affect the +// user-visible API of Abseil, but it changes the mangled names of all symbols. +// +// This can be useful as a version tag if you are distributing Abseil in +// precompiled form. This will prevent a binary library build of Abseil with +// one inline namespace being used with headers configured with a different +// inline namespace name. Binary packagers are reminded that Abseil does not +// guarantee any ABI stability in Abseil, so any update of Abseil or +// configuration change in such a binary package should be combined with a +// new, unique value for the inline namespace name. +// +// A value of 0 means not to use inline namespaces. +// +// A value of 1 means to use an inline namespace with the given name inside +// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also +// be changed to a new, unique identifier name. In particular "head" is not +// allowed. + +#define ABSL_OPTION_USE_INLINE_NAMESPACE 0 +#define ABSL_OPTION_INLINE_NAMESPACE_NAME head + +// ABSL_OPTION_HARDENED +// +// This option enables a "hardened" build in release mode (in this context, +// release mode is defined as a build where the `NDEBUG` macro is defined). +// +// A value of 0 means that "hardened" mode is not enabled. +// +// A value of 1 means that "hardened" mode is enabled. +// +// Hardened builds have additional security checks enabled when `NDEBUG` is +// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a +// no-op, as well as disabling other bespoke program consistency checks. By +// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in +// release mode. These checks guard against programming errors that may lead to +// security vulnerabilities. In release mode, when one of these programming +// errors is encountered, the program will immediately abort, possibly without +// any attempt at logging. +// +// The checks enabled by this option are not free; they do incur runtime cost. +// +// The checks enabled by this option are always active when `NDEBUG` is not +// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The +// checks enabled by this option may abort the program in a different way and +// log additional information when `NDEBUG` is not defined. + +#define ABSL_OPTION_HARDENED 0 + +#endif // ABSL_BASE_OPTIONS_H_ diff --git a/extern/int128/absl/base/policy_checks.h b/extern/int128/absl/base/policy_checks.h new file mode 100644 index 00000000000..06b32439168 --- /dev/null +++ b/extern/int128/absl/base/policy_checks.h @@ -0,0 +1,111 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: policy_checks.h +// ----------------------------------------------------------------------------- +// +// This header enforces a minimum set of policies at build time, such as the +// supported compiler and library versions. Unsupported configurations are +// reported with `#error`. This enforcement is best effort, so successfully +// compiling this header does not guarantee a supported configuration. + +#ifndef ABSL_BASE_POLICY_CHECKS_H_ +#define ABSL_BASE_POLICY_CHECKS_H_ + +// Included for the __GLIBC_PREREQ macro used below. +#include + +// Included for the _STLPORT_VERSION macro used below. +#if defined(__cplusplus) +#include +#endif + +// ----------------------------------------------------------------------------- +// Operating System Check +// ----------------------------------------------------------------------------- + +#if defined(__CYGWIN__) +#error "Cygwin is not supported." +#endif + +// ----------------------------------------------------------------------------- +// Toolchain Check +// ----------------------------------------------------------------------------- + +// We support MSVC++ 14.0 update 2 and later. +// This minimum will go up. +#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__) +#error "This package requires Visual Studio 2015 Update 2 or higher." +#endif + +// We support gcc 4.7 and later. +// This minimum will go up. +#if defined(__GNUC__) && !defined(__clang__) +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) +#error "This package requires gcc 4.7 or higher." +#endif +#endif + +// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later. +// This corresponds to Apple Xcode version 4.5. +// This minimum will go up. +#if defined(__apple_build_version__) && __apple_build_version__ < 4211165 +#error "This package requires __apple_build_version__ of 4211165 or higher." +#endif + +// ----------------------------------------------------------------------------- +// C++ Version Check +// ----------------------------------------------------------------------------- + +// Enforce C++11 as the minimum. Note that Visual Studio has not +// advanced __cplusplus despite being good enough for our purposes, so +// so we exempt it from the check. +#if defined(__cplusplus) && !defined(_MSC_VER) +#if __cplusplus < 201103L +#error "C++ versions less than C++11 are not supported." +#endif +#endif + +// ----------------------------------------------------------------------------- +// Standard Library Check +// ----------------------------------------------------------------------------- + +#if defined(_STLPORT_VERSION) +#error "STLPort is not supported." +#endif + +// ----------------------------------------------------------------------------- +// `char` Size Check +// ----------------------------------------------------------------------------- + +// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a +// platform where this is not the case, please provide us with the details about +// your platform so we can consider relaxing this requirement. +#if CHAR_BIT != 8 +#error "Abseil assumes CHAR_BIT == 8." +#endif + +// ----------------------------------------------------------------------------- +// `int` Size Check +// ----------------------------------------------------------------------------- + +// Abseil currently assumes that an int is 4 bytes. If you would like to use +// Abseil on a platform where this is not the case, please provide us with the +// details about your platform so we can consider relaxing this requirement. +#if INT_MAX < 2147483647 +#error "Abseil assumes that int is at least 4 bytes. " +#endif + +#endif // ABSL_BASE_POLICY_CHECKS_H_ diff --git a/extern/int128/absl/base/port.h b/extern/int128/absl/base/port.h new file mode 100644 index 00000000000..5bc4d6cd95d --- /dev/null +++ b/extern/int128/absl/base/port.h @@ -0,0 +1,25 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This files is a forwarding header for other headers containing various +// portability macros and functions. + +#ifndef ABSL_BASE_PORT_H_ +#define ABSL_BASE_PORT_H_ + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/optimization.h" + +#endif // ABSL_BASE_PORT_H_ diff --git a/extern/int128/absl/numeric/Makefile b/extern/int128/absl/numeric/Makefile new file mode 100644 index 00000000000..396e95d0633 --- /dev/null +++ b/extern/int128/absl/numeric/Makefile @@ -0,0 +1,11 @@ +LIBRARY=libi128$(CROSS).a + +$(LIBRARY): $(wildcard *.cc) $(wildcard *.h) $(wildcard internal/*.h) $(wildcard ../base/*.h) $(wildcard *.inc) Makefile + $(RM) -f *.o + $(CXX) $(CROSS_FLAGS) -I../.. -c -O3 -fPIC int128.cc + $(AR) crs $(LIBRARY) *.o + $(RM) -f *.o + +.PHONY: clean +clean: + $(RM) -f *.o *.a diff --git a/extern/int128/absl/numeric/bits.h b/extern/int128/absl/numeric/bits.h new file mode 100644 index 00000000000..52013ad49bb --- /dev/null +++ b/extern/int128/absl/numeric/bits.h @@ -0,0 +1,177 @@ +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: bits.h +// ----------------------------------------------------------------------------- +// +// This file contains implementations of C++20's bitwise math functions, as +// defined by: +// +// P0553R4: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html +// P0556R3: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0556r3.html +// P1355R2: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html +// P1956R1: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf +// +// When using a standard library that implements these functions, we use the +// standard library's implementation. + +#ifndef ABSL_NUMERIC_BITS_H_ +#define ABSL_NUMERIC_BITS_H_ + +#include +#include +#include + +#if (defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) || \ + (defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) +#include +#endif + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/numeric/internal/bits.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +#if !(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) +// rotating +template +ABSL_MUST_USE_RESULT constexpr + typename std::enable_if::value, T>::type + rotl(T x, int s) noexcept { + return numeric_internal::RotateLeft(x, s); +} + +template +ABSL_MUST_USE_RESULT constexpr + typename std::enable_if::value, T>::type + rotr(T x, int s) noexcept { + return numeric_internal::RotateRight(x, s); +} + +// Counting functions +// +// While these functions are typically constexpr, on some platforms, they may +// not be marked as constexpr due to constraints of the compiler/available +// intrinsics. +template +ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, int>::type + countl_zero(T x) noexcept { + return numeric_internal::CountLeadingZeroes(x); +} + +template +ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, int>::type + countl_one(T x) noexcept { + // Avoid integer promotion to a wider type + return countl_zero(static_cast(~x)); +} + +template +ABSL_INTERNAL_CONSTEXPR_CTZ inline + typename std::enable_if::value, int>::type + countr_zero(T x) noexcept { + return numeric_internal::CountTrailingZeroes(x); +} + +template +ABSL_INTERNAL_CONSTEXPR_CTZ inline + typename std::enable_if::value, int>::type + countr_one(T x) noexcept { + // Avoid integer promotion to a wider type + return countr_zero(static_cast(~x)); +} + +template +ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline + typename std::enable_if::value, int>::type + popcount(T x) noexcept { + return numeric_internal::Popcount(x); +} +#else // defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L + +using std::countl_one; +using std::countl_zero; +using std::countr_one; +using std::countr_zero; +using std::popcount; +using std::rotl; +using std::rotr; + +#endif + +#if !(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) +// Returns: true if x is an integral power of two; false otherwise. +template +constexpr inline typename std::enable_if::value, bool>::type +has_single_bit(T x) noexcept { + return x != 0 && (x & (x - 1)) == 0; +} + +// Returns: If x == 0, 0; otherwise one plus the base-2 logarithm of x, with any +// fractional part discarded. +template +ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, T>::type + bit_width(T x) noexcept { + return std::numeric_limits::digits - countl_zero(x); +} + +// Returns: If x == 0, 0; otherwise the maximal value y such that +// has_single_bit(y) is true and y <= x. +template +ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, T>::type + bit_floor(T x) noexcept { + return x == 0 ? 0 : T{1} << (bit_width(x) - 1); +} + +// Returns: N, where N is the smallest power of 2 greater than or equal to x. +// +// Preconditions: N is representable as a value of type T. +template +ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, T>::type + bit_ceil(T x) { + // If T is narrower than unsigned, T{1} << bit_width will be promoted. We + // want to force it to wraparound so that bit_ceil of an invalid value are not + // core constant expressions. + // + // BitCeilNonPowerOf2 triggers an overflow in constexpr contexts if we would + // undergo promotion to unsigned but not fit the result into T without + // truncation. + return has_single_bit(x) ? T{1} << (bit_width(x) - 1) + : numeric_internal::BitCeilNonPowerOf2(x); +} +#else // defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L + +using std::bit_ceil; +using std::bit_floor; +using std::bit_width; +using std::has_single_bit; + +#endif + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_NUMERIC_BITS_H_ diff --git a/extern/int128/absl/numeric/int128.cc b/extern/int128/absl/numeric/int128.cc new file mode 100644 index 00000000000..17d88744ae1 --- /dev/null +++ b/extern/int128/absl/numeric/int128.cc @@ -0,0 +1,383 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/numeric/int128.h" + +#include + +#include +#include +#include // NOLINT(readability/streams) +#include +#include +#include + +#include "absl/base/optimization.h" +#include "absl/numeric/bits.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +ABSL_DLL const uint128 kuint128max = MakeUint128( + std::numeric_limits::max(), std::numeric_limits::max()); + +namespace { + +// Returns the 0-based position of the last set bit (i.e., most significant bit) +// in the given uint128. The argument is not 0. +// +// For example: +// Given: 5 (decimal) == 101 (binary) +// Returns: 2 +inline ABSL_ATTRIBUTE_ALWAYS_INLINE int Fls128(uint128 n) { + if (uint64_t hi = Uint128High64(n)) { + ABSL_INTERNAL_ASSUME(hi != 0); + return 127 - countl_zero(hi); + } + const uint64_t low = Uint128Low64(n); + ABSL_INTERNAL_ASSUME(low != 0); + return 63 - countl_zero(low); +} + +// Long division/modulo for uint128 implemented using the shift-subtract +// division algorithm adapted from: +// https://stackoverflow.com/questions/5386377/division-without-using +inline void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret, + uint128* remainder_ret) { + assert(divisor != 0); + + if (divisor > dividend) { + *quotient_ret = 0; + *remainder_ret = dividend; + return; + } + + if (divisor == dividend) { + *quotient_ret = 1; + *remainder_ret = 0; + return; + } + + uint128 denominator = divisor; + uint128 quotient = 0; + + // Left aligns the MSB of the denominator and the dividend. + const int shift = Fls128(dividend) - Fls128(denominator); + denominator <<= shift; + + // Uses shift-subtract algorithm to divide dividend by denominator. The + // remainder will be left in dividend. + for (int i = 0; i <= shift; ++i) { + quotient <<= 1; + if (dividend >= denominator) { + dividend -= denominator; + quotient |= 1; + } + denominator >>= 1; + } + + *quotient_ret = quotient; + *remainder_ret = dividend; +} + +template +uint128 MakeUint128FromFloat(T v) { + static_assert(std::is_floating_point::value, ""); + + // Rounding behavior is towards zero, same as for built-in types. + + // Undefined behavior if v is NaN or cannot fit into uint128. + assert(std::isfinite(v) && v > -1 && + (std::numeric_limits::max_exponent <= 128 || + v < std::ldexp(static_cast(1), 128))); + + if (v >= std::ldexp(static_cast(1), 64)) { + uint64_t hi = static_cast(std::ldexp(v, -64)); + uint64_t lo = static_cast(v - std::ldexp(static_cast(hi), 64)); + return MakeUint128(hi, lo); + } + + return MakeUint128(0, static_cast(v)); +} + +#if defined(__clang__) && !defined(__SSE3__) +// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 +// Casting from long double to uint64_t is miscompiled and drops bits. +// It is more work, so only use when we need the workaround. +uint128 MakeUint128FromFloat(long double v) { + // Go 50 bits at a time, that fits in a double + static_assert(std::numeric_limits::digits >= 50, ""); + static_assert(std::numeric_limits::digits <= 150, ""); + // Undefined behavior if v is not finite or cannot fit into uint128. + assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128)); + + v = std::ldexp(v, -100); + uint64_t w0 = static_cast(static_cast(std::trunc(v))); + v = std::ldexp(v - static_cast(w0), 50); + uint64_t w1 = static_cast(static_cast(std::trunc(v))); + v = std::ldexp(v - static_cast(w1), 50); + uint64_t w2 = static_cast(static_cast(std::trunc(v))); + return (static_cast(w0) << 100) | (static_cast(w1) << 50) | + static_cast(w2); +} +#endif // __clang__ && !__SSE3__ +} // namespace + +uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {} +uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {} +uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {} + +#if !defined(ABSL_HAVE_INTRINSIC_INT128) +uint128 operator/(uint128 lhs, uint128 rhs) { + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(lhs, rhs, "ient, &remainder); + return quotient; +} + +uint128 operator%(uint128 lhs, uint128 rhs) { + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(lhs, rhs, "ient, &remainder); + return remainder; +} +#endif // !defined(ABSL_HAVE_INTRINSIC_INT128) + +namespace { + +std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) { + // Select a divisor which is the largest power of the base < 2^64. + uint128 div; + int div_base_log; + switch (flags & std::ios::basefield) { + case std::ios::hex: + div = 0x1000000000000000; // 16^15 + div_base_log = 15; + break; + case std::ios::oct: + div = 01000000000000000000000; // 8^21 + div_base_log = 21; + break; + default: // std::ios::dec + div = 10000000000000000000u; // 10^19 + div_base_log = 19; + break; + } + + // Now piece together the uint128 representation from three chunks of the + // original value, each less than "div" and therefore representable as a + // uint64_t. + std::ostringstream os; + std::ios_base::fmtflags copy_mask = + std::ios::basefield | std::ios::showbase | std::ios::uppercase; + os.setf(flags & copy_mask, copy_mask); + uint128 high = v; + uint128 low; + DivModImpl(high, div, &high, &low); + uint128 mid; + DivModImpl(high, div, &high, &mid); + if (Uint128Low64(high) != 0) { + os << Uint128Low64(high); + os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); + os << Uint128Low64(mid); + os << std::setw(div_base_log); + } else if (Uint128Low64(mid) != 0) { + os << Uint128Low64(mid); + os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); + } + os << Uint128Low64(low); + return os.str(); +} + +} // namespace + +std::ostream& operator<<(std::ostream& os, uint128 v) { + std::ios_base::fmtflags flags = os.flags(); + std::string rep = Uint128ToFormattedString(v, flags); + + // Add the requisite padding. + std::streamsize width = os.width(0); + if (static_cast(width) > rep.size()) { + std::ios::fmtflags adjustfield = flags & std::ios::adjustfield; + if (adjustfield == std::ios::left) { + rep.append(width - rep.size(), os.fill()); + } else if (adjustfield == std::ios::internal && + (flags & std::ios::showbase) && + (flags & std::ios::basefield) == std::ios::hex && v != 0) { + rep.insert(2, width - rep.size(), os.fill()); + } else { + rep.insert(0, width - rep.size(), os.fill()); + } + } + + return os << rep; +} + +namespace { + +uint128 UnsignedAbsoluteValue(int128 v) { + // Cast to uint128 before possibly negating because -Int128Min() is undefined. + return Int128High64(v) < 0 ? -uint128(v) : uint128(v); +} + +} // namespace + +#if !defined(ABSL_HAVE_INTRINSIC_INT128) +namespace { + +template +int128 MakeInt128FromFloat(T v) { + // Conversion when v is NaN or cannot fit into int128 would be undefined + // behavior if using an intrinsic 128-bit integer. + assert(std::isfinite(v) && (std::numeric_limits::max_exponent <= 127 || + (v >= -std::ldexp(static_cast(1), 127) && + v < std::ldexp(static_cast(1), 127)))); + + // We must convert the absolute value and then negate as needed, because + // floating point types are typically sign-magnitude. Otherwise, the + // difference between the high and low 64 bits when interpreted as two's + // complement overwhelms the precision of the mantissa. + uint128 result = v < 0 ? -MakeUint128FromFloat(-v) : MakeUint128FromFloat(v); + return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)), + Uint128Low64(result)); +} + +} // namespace + +int128::int128(float v) : int128(MakeInt128FromFloat(v)) {} +int128::int128(double v) : int128(MakeInt128FromFloat(v)) {} +int128::int128(long double v) : int128(MakeInt128FromFloat(v)) {} + +int128 operator/(int128 lhs, int128 rhs) { + assert(lhs != Int128Min() || rhs != -1); // UB on two's complement. + + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs), + "ient, &remainder); + if ((Int128High64(lhs) < 0) != (Int128High64(rhs) < 0)) quotient = -quotient; + return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(quotient)), + Uint128Low64(quotient)); +} + +int128 operator%(int128 lhs, int128 rhs) { + assert(lhs != Int128Min() || rhs != -1); // UB on two's complement. + + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(UnsignedAbsoluteValue(lhs), UnsignedAbsoluteValue(rhs), + "ient, &remainder); + if (Int128High64(lhs) < 0) remainder = -remainder; + return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(remainder)), + Uint128Low64(remainder)); +} +#endif // ABSL_HAVE_INTRINSIC_INT128 + +std::ostream& operator<<(std::ostream& os, int128 v) { + std::ios_base::fmtflags flags = os.flags(); + std::string rep; + + // Add the sign if needed. + bool print_as_decimal = + (flags & std::ios::basefield) == std::ios::dec || + (flags & std::ios::basefield) == std::ios_base::fmtflags(); + if (print_as_decimal) { + if (Int128High64(v) < 0) { + rep = "-"; + } else if (flags & std::ios::showpos) { + rep = "+"; + } + } + + rep.append(Uint128ToFormattedString( + print_as_decimal ? UnsignedAbsoluteValue(v) : uint128(v), os.flags())); + + // Add the requisite padding. + std::streamsize width = os.width(0); + if (static_cast(width) > rep.size()) { + switch (flags & std::ios::adjustfield) { + case std::ios::left: + rep.append(width - rep.size(), os.fill()); + break; + case std::ios::internal: + if (print_as_decimal && (rep[0] == '+' || rep[0] == '-')) { + rep.insert(1, width - rep.size(), os.fill()); + } else if ((flags & std::ios::basefield) == std::ios::hex && + (flags & std::ios::showbase) && v != 0) { + rep.insert(2, width - rep.size(), os.fill()); + } else { + rep.insert(0, width - rep.size(), os.fill()); + } + break; + default: // std::ios::right + rep.insert(0, width - rep.size(), os.fill()); + break; + } + } + + return os << rep; +} + +ABSL_NAMESPACE_END +} // namespace absl + +namespace std { +constexpr bool numeric_limits::is_specialized; +constexpr bool numeric_limits::is_signed; +constexpr bool numeric_limits::is_integer; +constexpr bool numeric_limits::is_exact; +constexpr bool numeric_limits::has_infinity; +constexpr bool numeric_limits::has_quiet_NaN; +constexpr bool numeric_limits::has_signaling_NaN; +constexpr float_denorm_style numeric_limits::has_denorm; +constexpr bool numeric_limits::has_denorm_loss; +constexpr float_round_style numeric_limits::round_style; +constexpr bool numeric_limits::is_iec559; +constexpr bool numeric_limits::is_bounded; +constexpr bool numeric_limits::is_modulo; +constexpr int numeric_limits::digits; +constexpr int numeric_limits::digits10; +constexpr int numeric_limits::max_digits10; +constexpr int numeric_limits::radix; +constexpr int numeric_limits::min_exponent; +constexpr int numeric_limits::min_exponent10; +constexpr int numeric_limits::max_exponent; +constexpr int numeric_limits::max_exponent10; +constexpr bool numeric_limits::traps; +constexpr bool numeric_limits::tinyness_before; + +constexpr bool numeric_limits::is_specialized; +constexpr bool numeric_limits::is_signed; +constexpr bool numeric_limits::is_integer; +constexpr bool numeric_limits::is_exact; +constexpr bool numeric_limits::has_infinity; +constexpr bool numeric_limits::has_quiet_NaN; +constexpr bool numeric_limits::has_signaling_NaN; +constexpr float_denorm_style numeric_limits::has_denorm; +constexpr bool numeric_limits::has_denorm_loss; +constexpr float_round_style numeric_limits::round_style; +constexpr bool numeric_limits::is_iec559; +constexpr bool numeric_limits::is_bounded; +constexpr bool numeric_limits::is_modulo; +constexpr int numeric_limits::digits; +constexpr int numeric_limits::digits10; +constexpr int numeric_limits::max_digits10; +constexpr int numeric_limits::radix; +constexpr int numeric_limits::min_exponent; +constexpr int numeric_limits::min_exponent10; +constexpr int numeric_limits::max_exponent; +constexpr int numeric_limits::max_exponent10; +constexpr bool numeric_limits::traps; +constexpr bool numeric_limits::tinyness_before; +} // namespace std diff --git a/extern/int128/absl/numeric/int128.h b/extern/int128/absl/numeric/int128.h new file mode 100644 index 00000000000..a9cbe489dd1 --- /dev/null +++ b/extern/int128/absl/numeric/int128.h @@ -0,0 +1,1155 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: int128.h +// ----------------------------------------------------------------------------- +// +// This header file defines 128-bit integer types, `uint128` and `int128`. +// +// TODO(absl-team): This module is inconsistent as many inline `uint128` methods +// are defined in this file, while many inline `int128` methods are defined in +// the `int128_*_intrinsic.inc` files. + +#ifndef ABSL_NUMERIC_INT128_H_ +#define ABSL_NUMERIC_INT128_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/base/port.h" + +#if defined(_MSC_VER) +// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is +// a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t +// builtin type. We need to make sure not to define operator wchar_t() +// alongside operator unsigned short() in these instances. +#define ABSL_INTERNAL_WCHAR_T __wchar_t +#if defined(_M_X64) +#include +#pragma intrinsic(_umul128) +#endif // defined(_M_X64) +#else // defined(_MSC_VER) +#define ABSL_INTERNAL_WCHAR_T wchar_t +#endif // defined(_MSC_VER) + +namespace absl { +ABSL_NAMESPACE_BEGIN + +class int128; + +// uint128 +// +// An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type +// as closely as is practical, including exhibiting undefined behavior in +// analogous cases (e.g. division by zero). This type is intended to be a +// drop-in replacement once C++ supports an intrinsic `uint128_t` type; when +// that occurs, existing well-behaved uses of `uint128` will continue to work +// using that new type. +// +// Note: code written with this type will continue to compile once `uint128_t` +// is introduced, provided the replacement helper functions +// `Uint128(Low|High)64()` and `MakeUint128()` are made. +// +// A `uint128` supports the following: +// +// * Implicit construction from integral types +// * Explicit conversion to integral types +// +// Additionally, if your compiler supports `__int128`, `uint128` is +// interoperable with that type. (Abseil checks for this compatibility through +// the `ABSL_HAVE_INTRINSIC_INT128` macro.) +// +// However, a `uint128` differs from intrinsic integral types in the following +// ways: +// +// * Errors on implicit conversions that do not preserve value (such as +// loss of precision when converting to float values). +// * Requires explicit construction from and conversion to floating point +// types. +// * Conversion to integral types requires an explicit static_cast() to +// mimic use of the `-Wnarrowing` compiler flag. +// * The alignment requirement of `uint128` may differ from that of an +// intrinsic 128-bit integer type depending on platform and build +// configuration. +// +// Example: +// +// float y = absl::Uint128Max(); // Error. uint128 cannot be implicitly +// // converted to float. +// +// absl::uint128 v; +// uint64_t i = v; // Error +// uint64_t i = static_cast(v); // OK +// +class +#if defined(ABSL_HAVE_INTRINSIC_INT128) + alignas(unsigned __int128) +#endif // ABSL_HAVE_INTRINSIC_INT128 + uint128 { + public: + uint128() = default; + + // Constructors from arithmetic types + constexpr uint128(int v); // NOLINT(runtime/explicit) + constexpr uint128(unsigned int v); // NOLINT(runtime/explicit) + constexpr uint128(long v); // NOLINT(runtime/int) + constexpr uint128(unsigned long v); // NOLINT(runtime/int) + constexpr uint128(long long v); // NOLINT(runtime/int) + constexpr uint128(unsigned long long v); // NOLINT(runtime/int) +#ifdef ABSL_HAVE_INTRINSIC_INT128 + constexpr uint128(__int128 v); // NOLINT(runtime/explicit) + constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit) +#endif // ABSL_HAVE_INTRINSIC_INT128 + constexpr uint128(int128 v); // NOLINT(runtime/explicit) + explicit uint128(float v); + explicit uint128(double v); + explicit uint128(long double v); + + // Assignment operators from arithmetic types + uint128& operator=(int v); + uint128& operator=(unsigned int v); + uint128& operator=(long v); // NOLINT(runtime/int) + uint128& operator=(unsigned long v); // NOLINT(runtime/int) + uint128& operator=(long long v); // NOLINT(runtime/int) + uint128& operator=(unsigned long long v); // NOLINT(runtime/int) +#ifdef ABSL_HAVE_INTRINSIC_INT128 + uint128& operator=(__int128 v); + uint128& operator=(unsigned __int128 v); +#endif // ABSL_HAVE_INTRINSIC_INT128 + uint128& operator=(int128 v); + + // Conversion operators to other arithmetic types + constexpr explicit operator bool() const; + constexpr explicit operator char() const; + constexpr explicit operator signed char() const; + constexpr explicit operator unsigned char() const; + constexpr explicit operator char16_t() const; + constexpr explicit operator char32_t() const; + constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; + constexpr explicit operator short() const; // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned short() const; + constexpr explicit operator int() const; + constexpr explicit operator unsigned int() const; + constexpr explicit operator long() const; // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned long() const; + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator long long() const; + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned long long() const; +#ifdef ABSL_HAVE_INTRINSIC_INT128 + constexpr explicit operator __int128() const; + constexpr explicit operator unsigned __int128() const; +#endif // ABSL_HAVE_INTRINSIC_INT128 + explicit operator float() const; + explicit operator double() const; + explicit operator long double() const; + + // Trivial copy constructor, assignment operator and destructor. + + // Arithmetic operators. + uint128& operator+=(uint128 other); + uint128& operator-=(uint128 other); + uint128& operator*=(uint128 other); + // Long division/modulo for uint128. + uint128& operator/=(uint128 other); + uint128& operator%=(uint128 other); + uint128 operator++(int); + uint128 operator--(int); + uint128& operator<<=(int); + uint128& operator>>=(int); + uint128& operator&=(uint128 other); + uint128& operator|=(uint128 other); + uint128& operator^=(uint128 other); + uint128& operator++(); + uint128& operator--(); + + // Uint128Low64() + // + // Returns the lower 64-bit value of a `uint128` value. + friend constexpr uint64_t Uint128Low64(uint128 v); + + // Uint128High64() + // + // Returns the higher 64-bit value of a `uint128` value. + friend constexpr uint64_t Uint128High64(uint128 v); + + // MakeUInt128() + // + // Constructs a `uint128` numeric value from two 64-bit unsigned integers. + // Note that this factory function is the only way to construct a `uint128` + // from integer values greater than 2^64. + // + // Example: + // + // absl::uint128 big = absl::MakeUint128(1, 0); + friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low); + + // Uint128Max() + // + // Returns the highest value for a 128-bit unsigned integer. + friend constexpr uint128 Uint128Max(); + + // Support for absl::Hash. + template + friend H AbslHashValue(H h, uint128 v) { + return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v)); + } + + private: + constexpr uint128(uint64_t high, uint64_t low); + + // TODO(strel) Update implementation to use __int128 once all users of + // uint128 are fixed to not depend on alignof(uint128) == 8. Also add + // alignas(16) to class definition to keep alignment consistent across + // platforms. +#if defined(ABSL_IS_LITTLE_ENDIAN) + uint64_t lo_; + uint64_t hi_; +#elif defined(ABSL_IS_BIG_ENDIAN) + uint64_t hi_; + uint64_t lo_; +#else // byte order +#error "Unsupported byte order: must be little-endian or big-endian." +#endif // byte order +}; + +// Prefer to use the constexpr `Uint128Max()`. +// +// TODO(absl-team) deprecate kuint128max once migration tool is released. +ABSL_DLL extern const uint128 kuint128max; + +// allow uint128 to be logged +std::ostream& operator<<(std::ostream& os, uint128 v); + +// TODO(strel) add operator>>(std::istream&, uint128) + +constexpr uint128 Uint128Max() { + return uint128((std::numeric_limits::max)(), + (std::numeric_limits::max)()); +} + +ABSL_NAMESPACE_END +} // namespace absl + +// Specialized numeric_limits for uint128. +namespace std { +template <> +class numeric_limits { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + static constexpr float_round_style round_style = round_toward_zero; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int digits10 = 38; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; +#ifdef ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits::traps; +#else // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits::traps; +#endif // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool tinyness_before = false; + + static constexpr absl::uint128 (min)() { return 0; } + static constexpr absl::uint128 lowest() { return 0; } + static constexpr absl::uint128 (max)() { return absl::Uint128Max(); } + static constexpr absl::uint128 epsilon() { return 0; } + static constexpr absl::uint128 round_error() { return 0; } + static constexpr absl::uint128 infinity() { return 0; } + static constexpr absl::uint128 quiet_NaN() { return 0; } + static constexpr absl::uint128 signaling_NaN() { return 0; } + static constexpr absl::uint128 denorm_min() { return 0; } +}; +} // namespace std + +namespace absl { +ABSL_NAMESPACE_BEGIN + +// int128 +// +// A signed 128-bit integer type. The API is meant to mimic an intrinsic +// integral type as closely as is practical, including exhibiting undefined +// behavior in analogous cases (e.g. division by zero). +// +// An `int128` supports the following: +// +// * Implicit construction from integral types +// * Explicit conversion to integral types +// +// However, an `int128` differs from intrinsic integral types in the following +// ways: +// +// * It is not implicitly convertible to other integral types. +// * Requires explicit construction from and conversion to floating point +// types. + +// Additionally, if your compiler supports `__int128`, `int128` is +// interoperable with that type. (Abseil checks for this compatibility through +// the `ABSL_HAVE_INTRINSIC_INT128` macro.) +// +// The design goal for `int128` is that it will be compatible with a future +// `int128_t`, if that type becomes a part of the standard. +// +// Example: +// +// float y = absl::int128(17); // Error. int128 cannot be implicitly +// // converted to float. +// +// absl::int128 v; +// int64_t i = v; // Error +// int64_t i = static_cast(v); // OK +// +class int128 { + public: + int128() = default; + + // Constructors from arithmetic types + constexpr int128(int v); // NOLINT(runtime/explicit) + constexpr int128(unsigned int v); // NOLINT(runtime/explicit) + constexpr int128(long v); // NOLINT(runtime/int) + constexpr int128(unsigned long v); // NOLINT(runtime/int) + constexpr int128(long long v); // NOLINT(runtime/int) + constexpr int128(unsigned long long v); // NOLINT(runtime/int) +#ifdef ABSL_HAVE_INTRINSIC_INT128 + constexpr int128(__int128 v); // NOLINT(runtime/explicit) + constexpr explicit int128(unsigned __int128 v); +#endif // ABSL_HAVE_INTRINSIC_INT128 + constexpr explicit int128(uint128 v); + explicit int128(float v); + explicit int128(double v); + explicit int128(long double v); + + // Assignment operators from arithmetic types + int128& operator=(int v); + int128& operator=(unsigned int v); + int128& operator=(long v); // NOLINT(runtime/int) + int128& operator=(unsigned long v); // NOLINT(runtime/int) + int128& operator=(long long v); // NOLINT(runtime/int) + int128& operator=(unsigned long long v); // NOLINT(runtime/int) +#ifdef ABSL_HAVE_INTRINSIC_INT128 + int128& operator=(__int128 v); +#endif // ABSL_HAVE_INTRINSIC_INT128 + + // Conversion operators to other arithmetic types + constexpr explicit operator bool() const; + constexpr explicit operator char() const; + constexpr explicit operator signed char() const; + constexpr explicit operator unsigned char() const; + constexpr explicit operator char16_t() const; + constexpr explicit operator char32_t() const; + constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; + constexpr explicit operator short() const; // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned short() const; + constexpr explicit operator int() const; + constexpr explicit operator unsigned int() const; + constexpr explicit operator long() const; // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned long() const; + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator long long() const; + // NOLINTNEXTLINE(runtime/int) + constexpr explicit operator unsigned long long() const; +#ifdef ABSL_HAVE_INTRINSIC_INT128 + constexpr explicit operator __int128() const; + constexpr explicit operator unsigned __int128() const; +#endif // ABSL_HAVE_INTRINSIC_INT128 + explicit operator float() const; + explicit operator double() const; + explicit operator long double() const; + + // Trivial copy constructor, assignment operator and destructor. + + // Arithmetic operators + int128& operator+=(int128 other); + int128& operator-=(int128 other); + int128& operator*=(int128 other); + int128& operator/=(int128 other); + int128& operator%=(int128 other); + int128 operator++(int); // postfix increment: i++ + int128 operator--(int); // postfix decrement: i-- + int128& operator++(); // prefix increment: ++i + int128& operator--(); // prefix decrement: --i + int128& operator&=(int128 other); + int128& operator|=(int128 other); + int128& operator^=(int128 other); + int128& operator<<=(int amount); + int128& operator>>=(int amount); + + // Int128Low64() + // + // Returns the lower 64-bit value of a `int128` value. + friend constexpr uint64_t Int128Low64(int128 v); + + // Int128High64() + // + // Returns the higher 64-bit value of a `int128` value. + friend constexpr int64_t Int128High64(int128 v); + + // MakeInt128() + // + // Constructs a `int128` numeric value from two 64-bit integers. Note that + // signedness is conveyed in the upper `high` value. + // + // (absl::int128(1) << 64) * high + low + // + // Note that this factory function is the only way to construct a `int128` + // from integer values greater than 2^64 or less than -2^64. + // + // Example: + // + // absl::int128 big = absl::MakeInt128(1, 0); + // absl::int128 big_n = absl::MakeInt128(-1, 0); + friend constexpr int128 MakeInt128(int64_t high, uint64_t low); + + // Int128Max() + // + // Returns the maximum value for a 128-bit signed integer. + friend constexpr int128 Int128Max(); + + // Int128Min() + // + // Returns the minimum value for a 128-bit signed integer. + friend constexpr int128 Int128Min(); + + // Support for absl::Hash. + template + friend H AbslHashValue(H h, int128 v) { + return H::combine(std::move(h), Int128High64(v), Int128Low64(v)); + } + + private: + constexpr int128(int64_t high, uint64_t low); + +#if defined(ABSL_HAVE_INTRINSIC_INT128) + __int128 v_; +#else // ABSL_HAVE_INTRINSIC_INT128 +#if defined(ABSL_IS_LITTLE_ENDIAN) + uint64_t lo_; + int64_t hi_; +#elif defined(ABSL_IS_BIG_ENDIAN) + int64_t hi_; + uint64_t lo_; +#else // byte order +#error "Unsupported byte order: must be little-endian or big-endian." +#endif // byte order +#endif // ABSL_HAVE_INTRINSIC_INT128 +}; + +std::ostream& operator<<(std::ostream& os, int128 v); + +// TODO(absl-team) add operator>>(std::istream&, int128) + +constexpr int128 Int128Max() { + return int128((std::numeric_limits::max)(), + (std::numeric_limits::max)()); +} + +constexpr int128 Int128Min() { + return int128((std::numeric_limits::min)(), 0); +} + +ABSL_NAMESPACE_END +} // namespace absl + +// Specialized numeric_limits for int128. +namespace std { +template <> +class numeric_limits { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = true; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + static constexpr float_round_style round_style = round_toward_zero; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = false; + static constexpr int digits = 127; + static constexpr int digits10 = 38; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; +#ifdef ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits<__int128>::traps; +#else // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits::traps; +#endif // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool tinyness_before = false; + + static constexpr absl::int128 (min)() { return absl::Int128Min(); } + static constexpr absl::int128 lowest() { return absl::Int128Min(); } + static constexpr absl::int128 (max)() { return absl::Int128Max(); } + static constexpr absl::int128 epsilon() { return 0; } + static constexpr absl::int128 round_error() { return 0; } + static constexpr absl::int128 infinity() { return 0; } + static constexpr absl::int128 quiet_NaN() { return 0; } + static constexpr absl::int128 signaling_NaN() { return 0; } + static constexpr absl::int128 denorm_min() { return 0; } +}; +} // namespace std + +// -------------------------------------------------------------------------- +// Implementation details follow +// -------------------------------------------------------------------------- +namespace absl { +ABSL_NAMESPACE_BEGIN + +constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { + return uint128(high, low); +} + +// Assignment from integer types. + +inline uint128& uint128::operator=(int v) { return *this = uint128(v); } + +inline uint128& uint128::operator=(unsigned int v) { + return *this = uint128(v); +} + +inline uint128& uint128::operator=(long v) { // NOLINT(runtime/int) + return *this = uint128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline uint128& uint128::operator=(unsigned long v) { + return *this = uint128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline uint128& uint128::operator=(long long v) { + return *this = uint128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline uint128& uint128::operator=(unsigned long long v) { + return *this = uint128(v); +} + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +inline uint128& uint128::operator=(__int128 v) { + return *this = uint128(v); +} + +inline uint128& uint128::operator=(unsigned __int128 v) { + return *this = uint128(v); +} +#endif // ABSL_HAVE_INTRINSIC_INT128 + +inline uint128& uint128::operator=(int128 v) { + return *this = uint128(v); +} + +// Arithmetic operators. + +uint128 operator<<(uint128 lhs, int amount); +uint128 operator>>(uint128 lhs, int amount); +uint128 operator+(uint128 lhs, uint128 rhs); +uint128 operator-(uint128 lhs, uint128 rhs); +uint128 operator*(uint128 lhs, uint128 rhs); +uint128 operator/(uint128 lhs, uint128 rhs); +uint128 operator%(uint128 lhs, uint128 rhs); + +inline uint128& uint128::operator<<=(int amount) { + *this = *this << amount; + return *this; +} + +inline uint128& uint128::operator>>=(int amount) { + *this = *this >> amount; + return *this; +} + +inline uint128& uint128::operator+=(uint128 other) { + *this = *this + other; + return *this; +} + +inline uint128& uint128::operator-=(uint128 other) { + *this = *this - other; + return *this; +} + +inline uint128& uint128::operator*=(uint128 other) { + *this = *this * other; + return *this; +} + +inline uint128& uint128::operator/=(uint128 other) { + *this = *this / other; + return *this; +} + +inline uint128& uint128::operator%=(uint128 other) { + *this = *this % other; + return *this; +} + +constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } + +constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } + +// Constructors from integer types. + +#if defined(ABSL_IS_LITTLE_ENDIAN) + +constexpr uint128::uint128(uint64_t high, uint64_t low) + : lo_{low}, hi_{high} {} + +constexpr uint128::uint128(int v) + : lo_{static_cast(v)}, + hi_{v < 0 ? (std::numeric_limits::max)() : 0} {} +constexpr uint128::uint128(long v) // NOLINT(runtime/int) + : lo_{static_cast(v)}, + hi_{v < 0 ? (std::numeric_limits::max)() : 0} {} +constexpr uint128::uint128(long long v) // NOLINT(runtime/int) + : lo_{static_cast(v)}, + hi_{v < 0 ? (std::numeric_limits::max)() : 0} {} + +constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {} +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {} +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {} + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +constexpr uint128::uint128(__int128 v) + : lo_{static_cast(v & ~uint64_t{0})}, + hi_{static_cast(static_cast(v) >> 64)} {} +constexpr uint128::uint128(unsigned __int128 v) + : lo_{static_cast(v & ~uint64_t{0})}, + hi_{static_cast(v >> 64)} {} +#endif // ABSL_HAVE_INTRINSIC_INT128 + +constexpr uint128::uint128(int128 v) + : lo_{Int128Low64(v)}, hi_{static_cast(Int128High64(v))} {} + +#elif defined(ABSL_IS_BIG_ENDIAN) + +constexpr uint128::uint128(uint64_t high, uint64_t low) + : hi_{high}, lo_{low} {} + +constexpr uint128::uint128(int v) + : hi_{v < 0 ? (std::numeric_limits::max)() : 0}, + lo_{static_cast(v)} {} +constexpr uint128::uint128(long v) // NOLINT(runtime/int) + : hi_{v < 0 ? (std::numeric_limits::max)() : 0}, + lo_{static_cast(v)} {} +constexpr uint128::uint128(long long v) // NOLINT(runtime/int) + : hi_{v < 0 ? (std::numeric_limits::max)() : 0}, + lo_{static_cast(v)} {} + +constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {} +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {} +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {} + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +constexpr uint128::uint128(__int128 v) + : hi_{static_cast(static_cast(v) >> 64)}, + lo_{static_cast(v & ~uint64_t{0})} {} +constexpr uint128::uint128(unsigned __int128 v) + : hi_{static_cast(v >> 64)}, + lo_{static_cast(v & ~uint64_t{0})} {} +#endif // ABSL_HAVE_INTRINSIC_INT128 + +constexpr uint128::uint128(int128 v) + : hi_{static_cast(Int128High64(v))}, lo_{Int128Low64(v)} {} + +#else // byte order +#error "Unsupported byte order: must be little-endian or big-endian." +#endif // byte order + +// Conversion operators to integer types. + +constexpr uint128::operator bool() const { return lo_ || hi_; } + +constexpr uint128::operator char() const { return static_cast(lo_); } + +constexpr uint128::operator signed char() const { + return static_cast(lo_); +} + +constexpr uint128::operator unsigned char() const { + return static_cast(lo_); +} + +constexpr uint128::operator char16_t() const { + return static_cast(lo_); +} + +constexpr uint128::operator char32_t() const { + return static_cast(lo_); +} + +constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const { + return static_cast(lo_); +} + +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::operator short() const { return static_cast(lo_); } + +constexpr uint128::operator unsigned short() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +constexpr uint128::operator int() const { return static_cast(lo_); } + +constexpr uint128::operator unsigned int() const { + return static_cast(lo_); +} + +// NOLINTNEXTLINE(runtime/int) +constexpr uint128::operator long() const { return static_cast(lo_); } + +constexpr uint128::operator unsigned long() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +constexpr uint128::operator long long() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +constexpr uint128::operator unsigned long long() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +#ifdef ABSL_HAVE_INTRINSIC_INT128 +constexpr uint128::operator __int128() const { + return (static_cast<__int128>(hi_) << 64) + lo_; +} + +constexpr uint128::operator unsigned __int128() const { + return (static_cast(hi_) << 64) + lo_; +} +#endif // ABSL_HAVE_INTRINSIC_INT128 + +// Conversion operators to floating point types. + +inline uint128::operator float() const { + return static_cast(lo_) + std::ldexp(static_cast(hi_), 64); +} + +inline uint128::operator double() const { + return static_cast(lo_) + std::ldexp(static_cast(hi_), 64); +} + +inline uint128::operator long double() const { + return static_cast(lo_) + + std::ldexp(static_cast(hi_), 64); +} + +// Comparison operators. + +inline bool operator==(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) == + static_cast(rhs); +#else + return (Uint128Low64(lhs) == Uint128Low64(rhs) && + Uint128High64(lhs) == Uint128High64(rhs)); +#endif +} + +inline bool operator!=(uint128 lhs, uint128 rhs) { + return !(lhs == rhs); +} + +inline bool operator<(uint128 lhs, uint128 rhs) { +#ifdef ABSL_HAVE_INTRINSIC_INT128 + return static_cast(lhs) < + static_cast(rhs); +#else + return (Uint128High64(lhs) == Uint128High64(rhs)) + ? (Uint128Low64(lhs) < Uint128Low64(rhs)) + : (Uint128High64(lhs) < Uint128High64(rhs)); +#endif +} + +inline bool operator>(uint128 lhs, uint128 rhs) { return rhs < lhs; } + +inline bool operator<=(uint128 lhs, uint128 rhs) { return !(rhs < lhs); } + +inline bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); } + +// Unary operators. + +constexpr inline uint128 operator+(uint128 val) { + return val; +} + +constexpr inline int128 operator+(int128 val) { + return val; +} + +inline uint128 operator-(uint128 val) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return -static_cast(val); +#else + uint64_t hi = ~Uint128High64(val); + uint64_t lo = ~Uint128Low64(val) + 1; + if (lo == 0) ++hi; // carry + return MakeUint128(hi, lo); +#endif +} + +constexpr inline bool operator!(uint128 val) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return !static_cast(val); +#else + return !Uint128High64(val) && !Uint128Low64(val); +#endif +} + +// Logical operators. + +constexpr inline uint128 operator~(uint128 val) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return ~static_cast(val); +#else + return MakeUint128(~Uint128High64(val), ~Uint128Low64(val)); +#endif +} + +constexpr inline uint128 operator|(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) | + static_cast(rhs); +#else + return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs), + Uint128Low64(lhs) | Uint128Low64(rhs)); +#endif +} + +constexpr inline uint128 operator&(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) & + static_cast(rhs); +#else + return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs), + Uint128Low64(lhs) & Uint128Low64(rhs)); +#endif +} + +constexpr inline uint128 operator^(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) ^ + static_cast(rhs); +#else + return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs), + Uint128Low64(lhs) ^ Uint128Low64(rhs)); +#endif +} + +inline uint128& uint128::operator|=(uint128 other) { + *this = *this | other; + return *this; +} + +inline uint128& uint128::operator&=(uint128 other) { + *this = *this & other; + return *this; +} + +inline uint128& uint128::operator^=(uint128 other) { + *this = *this ^ other; + return *this; +} + +// Arithmetic operators. + +inline uint128 operator<<(uint128 lhs, int amount) { +#ifdef ABSL_HAVE_INTRINSIC_INT128 + return static_cast(lhs) << amount; +#else + // uint64_t shifts of >= 64 are undefined, so we will need some + // special-casing. + if (amount < 64) { + if (amount != 0) { + return MakeUint128( + (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), + Uint128Low64(lhs) << amount); + } + return lhs; + } + return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0); +#endif +} + +inline uint128 operator>>(uint128 lhs, int amount) { +#ifdef ABSL_HAVE_INTRINSIC_INT128 + return static_cast(lhs) >> amount; +#else + // uint64_t shifts of >= 64 are undefined, so we will need some + // special-casing. + if (amount < 64) { + if (amount != 0) { + return MakeUint128(Uint128High64(lhs) >> amount, + (Uint128Low64(lhs) >> amount) | + (Uint128High64(lhs) << (64 - amount))); + } + return lhs; + } + return MakeUint128(0, Uint128High64(lhs) >> (amount - 64)); +#endif +} + +inline uint128 operator+(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) + + static_cast(rhs); +#else + uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), + Uint128Low64(lhs) + Uint128Low64(rhs)); + if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry + return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)); + } + return result; +#endif +} + +inline uint128 operator-(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + return static_cast(lhs) - + static_cast(rhs); +#else + uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), + Uint128Low64(lhs) - Uint128Low64(rhs)); + if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry + return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)); + } + return result; +#endif +} + +inline uint128 operator*(uint128 lhs, uint128 rhs) { +#if defined(ABSL_HAVE_INTRINSIC_INT128) + // TODO(strel) Remove once alignment issues are resolved and unsigned __int128 + // can be used for uint128 storage. + return static_cast(lhs) * + static_cast(rhs); +#elif defined(_MSC_VER) && defined(_M_X64) + uint64_t carry; + uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry); + return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) + + Uint128High64(lhs) * Uint128Low64(rhs) + carry, + low); +#else // ABSL_HAVE_INTRINSIC128 + uint64_t a32 = Uint128Low64(lhs) >> 32; + uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; + uint64_t b32 = Uint128Low64(rhs) >> 32; + uint64_t b00 = Uint128Low64(rhs) & 0xffffffff; + uint128 result = + MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) + + Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32, + a00 * b00); + result += uint128(a32 * b00) << 32; + result += uint128(a00 * b32) << 32; + return result; +#endif // ABSL_HAVE_INTRINSIC128 +} + +#if defined(ABSL_HAVE_INTRINSIC_INT128) +inline uint128 operator/(uint128 lhs, uint128 rhs) { + return static_cast(lhs) / + static_cast(rhs); +} + +inline uint128 operator%(uint128 lhs, uint128 rhs) { + return static_cast(lhs) % + static_cast(rhs); +} +#endif + +// Increment/decrement operators. + +inline uint128 uint128::operator++(int) { + uint128 tmp(*this); + *this += 1; + return tmp; +} + +inline uint128 uint128::operator--(int) { + uint128 tmp(*this); + *this -= 1; + return tmp; +} + +inline uint128& uint128::operator++() { + *this += 1; + return *this; +} + +inline uint128& uint128::operator--() { + *this -= 1; + return *this; +} + +constexpr int128 MakeInt128(int64_t high, uint64_t low) { + return int128(high, low); +} + +// Assignment from integer types. +inline int128& int128::operator=(int v) { + return *this = int128(v); +} + +inline int128& int128::operator=(unsigned int v) { + return *this = int128(v); +} + +inline int128& int128::operator=(long v) { // NOLINT(runtime/int) + return *this = int128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline int128& int128::operator=(unsigned long v) { + return *this = int128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline int128& int128::operator=(long long v) { + return *this = int128(v); +} + +// NOLINTNEXTLINE(runtime/int) +inline int128& int128::operator=(unsigned long long v) { + return *this = int128(v); +} + +// Arithmetic operators. + +int128 operator+(int128 lhs, int128 rhs); +int128 operator-(int128 lhs, int128 rhs); +int128 operator*(int128 lhs, int128 rhs); +int128 operator/(int128 lhs, int128 rhs); +int128 operator%(int128 lhs, int128 rhs); +int128 operator|(int128 lhs, int128 rhs); +int128 operator&(int128 lhs, int128 rhs); +int128 operator^(int128 lhs, int128 rhs); +int128 operator<<(int128 lhs, int amount); +int128 operator>>(int128 lhs, int amount); + +inline int128& int128::operator+=(int128 other) { + *this = *this + other; + return *this; +} + +inline int128& int128::operator-=(int128 other) { + *this = *this - other; + return *this; +} + +inline int128& int128::operator*=(int128 other) { + *this = *this * other; + return *this; +} + +inline int128& int128::operator/=(int128 other) { + *this = *this / other; + return *this; +} + +inline int128& int128::operator%=(int128 other) { + *this = *this % other; + return *this; +} + +inline int128& int128::operator|=(int128 other) { + *this = *this | other; + return *this; +} + +inline int128& int128::operator&=(int128 other) { + *this = *this & other; + return *this; +} + +inline int128& int128::operator^=(int128 other) { + *this = *this ^ other; + return *this; +} + +inline int128& int128::operator<<=(int amount) { + *this = *this << amount; + return *this; +} + +inline int128& int128::operator>>=(int amount) { + *this = *this >> amount; + return *this; +} + +namespace int128_internal { + +// Casts from unsigned to signed while preserving the underlying binary +// representation. +constexpr int64_t BitCastToSigned(uint64_t v) { + // Casting an unsigned integer to a signed integer of the same + // width is implementation defined behavior if the source value would not fit + // in the destination type. We step around it with a roundtrip bitwise not + // operation to make sure this function remains constexpr. Clang, GCC, and + // MSVC optimize this to a no-op on x86-64. + return v & (uint64_t{1} << 63) ? ~static_cast(~v) + : static_cast(v); +} + +} // namespace int128_internal + +#if defined(ABSL_HAVE_INTRINSIC_INT128) +#include "absl/numeric/int128_have_intrinsic.inc" // IWYU pragma: export +#else // ABSL_HAVE_INTRINSIC_INT128 +#include "absl/numeric/int128_no_intrinsic.inc" // IWYU pragma: export +#endif // ABSL_HAVE_INTRINSIC_INT128 + +ABSL_NAMESPACE_END +} // namespace absl + +#undef ABSL_INTERNAL_WCHAR_T + +#endif // ABSL_NUMERIC_INT128_H_ diff --git a/extern/int128/absl/numeric/int128_have_intrinsic.inc b/extern/int128/absl/numeric/int128_have_intrinsic.inc new file mode 100644 index 00000000000..d6c76dd320c --- /dev/null +++ b/extern/int128/absl/numeric/int128_have_intrinsic.inc @@ -0,0 +1,302 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains :int128 implementation details that depend on internal +// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is +// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. + +namespace int128_internal { + +// Casts from unsigned to signed while preserving the underlying binary +// representation. +constexpr __int128 BitCastToSigned(unsigned __int128 v) { + // Casting an unsigned integer to a signed integer of the same + // width is implementation defined behavior if the source value would not fit + // in the destination type. We step around it with a roundtrip bitwise not + // operation to make sure this function remains constexpr. Clang and GCC + // optimize this to a no-op on x86-64. + return v & (static_cast(1) << 127) + ? ~static_cast<__int128>(~v) + : static_cast<__int128>(v); +} + +} // namespace int128_internal + +inline int128& int128::operator=(__int128 v) { + v_ = v; + return *this; +} + +constexpr uint64_t Int128Low64(int128 v) { + return static_cast(v.v_ & ~uint64_t{0}); +} + +constexpr int64_t Int128High64(int128 v) { + // Initially cast to unsigned to prevent a right shift on a negative value. + return int128_internal::BitCastToSigned( + static_cast(static_cast(v.v_) >> 64)); +} + +constexpr int128::int128(int64_t high, uint64_t low) + // Initially cast to unsigned to prevent a left shift that overflows. + : v_(int128_internal::BitCastToSigned(static_cast(high) + << 64) | + low) {} + + +constexpr int128::int128(int v) : v_{v} {} + +constexpr int128::int128(long v) : v_{v} {} // NOLINT(runtime/int) + +constexpr int128::int128(long long v) : v_{v} {} // NOLINT(runtime/int) + +constexpr int128::int128(__int128 v) : v_{v} {} + +constexpr int128::int128(unsigned int v) : v_{v} {} + +constexpr int128::int128(unsigned long v) : v_{v} {} // NOLINT(runtime/int) + +// NOLINTNEXTLINE(runtime/int) +constexpr int128::int128(unsigned long long v) : v_{v} {} + +constexpr int128::int128(unsigned __int128 v) : v_{static_cast<__int128>(v)} {} + +inline int128::int128(float v) { + v_ = static_cast<__int128>(v); +} + +inline int128::int128(double v) { + v_ = static_cast<__int128>(v); +} + +inline int128::int128(long double v) { + v_ = static_cast<__int128>(v); +} + +constexpr int128::int128(uint128 v) : v_{static_cast<__int128>(v)} {} + +constexpr int128::operator bool() const { return static_cast(v_); } + +constexpr int128::operator char() const { return static_cast(v_); } + +constexpr int128::operator signed char() const { + return static_cast(v_); +} + +constexpr int128::operator unsigned char() const { + return static_cast(v_); +} + +constexpr int128::operator char16_t() const { + return static_cast(v_); +} + +constexpr int128::operator char32_t() const { + return static_cast(v_); +} + +constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const { + return static_cast(v_); +} + +constexpr int128::operator short() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator unsigned short() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator int() const { + return static_cast(v_); +} + +constexpr int128::operator unsigned int() const { + return static_cast(v_); +} + +constexpr int128::operator long() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator unsigned long() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator long long() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) + return static_cast(v_); // NOLINT(runtime/int) +} + +constexpr int128::operator __int128() const { return v_; } + +constexpr int128::operator unsigned __int128() const { + return static_cast(v_); +} + +// Clang on PowerPC sometimes produces incorrect __int128 to floating point +// conversions. In that case, we do the conversion with a similar implementation +// to the conversion operators in int128_no_intrinsic.inc. +#if defined(__clang__) && !defined(__ppc64__) +inline int128::operator float() const { return static_cast(v_); } + +inline int128::operator double () const { return static_cast(v_); } + +inline int128::operator long double() const { + return static_cast(v_); +} + +#else // Clang on PowerPC +// Forward declaration for conversion operators to floating point types. +int128 operator-(int128 v); +bool operator!=(int128 lhs, int128 rhs); + +inline int128::operator float() const { + // We must convert the absolute value and then negate as needed, because + // floating point types are typically sign-magnitude. Otherwise, the + // difference between the high and low 64 bits when interpreted as two's + // complement overwhelms the precision of the mantissa. + // + // Also check to make sure we don't negate Int128Min() + return v_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(Int128Low64(*this)) + + std::ldexp(static_cast(Int128High64(*this)), 64); +} + +inline int128::operator double() const { + // See comment in int128::operator float() above. + return v_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(Int128Low64(*this)) + + std::ldexp(static_cast(Int128High64(*this)), 64); +} + +inline int128::operator long double() const { + // See comment in int128::operator float() above. + return v_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(Int128Low64(*this)) + + std::ldexp(static_cast(Int128High64(*this)), + 64); +} +#endif // Clang on PowerPC + +// Comparison operators. + +inline bool operator==(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) == static_cast<__int128>(rhs); +} + +inline bool operator!=(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) != static_cast<__int128>(rhs); +} + +inline bool operator<(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) < static_cast<__int128>(rhs); +} + +inline bool operator>(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) > static_cast<__int128>(rhs); +} + +inline bool operator<=(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) <= static_cast<__int128>(rhs); +} + +inline bool operator>=(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) >= static_cast<__int128>(rhs); +} + +// Unary operators. + +inline int128 operator-(int128 v) { + return -static_cast<__int128>(v); +} + +inline bool operator!(int128 v) { + return !static_cast<__int128>(v); +} + +inline int128 operator~(int128 val) { + return ~static_cast<__int128>(val); +} + +// Arithmetic operators. + +inline int128 operator+(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) + static_cast<__int128>(rhs); +} + +inline int128 operator-(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) - static_cast<__int128>(rhs); +} + +inline int128 operator*(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) * static_cast<__int128>(rhs); +} + +inline int128 operator/(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) / static_cast<__int128>(rhs); +} + +inline int128 operator%(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) % static_cast<__int128>(rhs); +} + +inline int128 int128::operator++(int) { + int128 tmp(*this); + ++v_; + return tmp; +} + +inline int128 int128::operator--(int) { + int128 tmp(*this); + --v_; + return tmp; +} + +inline int128& int128::operator++() { + ++v_; + return *this; +} + +inline int128& int128::operator--() { + --v_; + return *this; +} + +inline int128 operator|(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) | static_cast<__int128>(rhs); +} + +inline int128 operator&(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) & static_cast<__int128>(rhs); +} + +inline int128 operator^(int128 lhs, int128 rhs) { + return static_cast<__int128>(lhs) ^ static_cast<__int128>(rhs); +} + +inline int128 operator<<(int128 lhs, int amount) { + return static_cast<__int128>(lhs) << amount; +} + +inline int128 operator>>(int128 lhs, int amount) { + return static_cast<__int128>(lhs) >> amount; +} diff --git a/extern/int128/absl/numeric/int128_no_intrinsic.inc b/extern/int128/absl/numeric/int128_no_intrinsic.inc new file mode 100644 index 00000000000..c753771ae73 --- /dev/null +++ b/extern/int128/absl/numeric/int128_no_intrinsic.inc @@ -0,0 +1,308 @@ +// +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file contains :int128 implementation details that depend on internal +// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file +// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. + +constexpr uint64_t Int128Low64(int128 v) { return v.lo_; } + +constexpr int64_t Int128High64(int128 v) { return v.hi_; } + +#if defined(ABSL_IS_LITTLE_ENDIAN) + +constexpr int128::int128(int64_t high, uint64_t low) : + lo_(low), hi_(high) {} + +constexpr int128::int128(int v) + : lo_{static_cast(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} +constexpr int128::int128(long v) // NOLINT(runtime/int) + : lo_{static_cast(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} +constexpr int128::int128(long long v) // NOLINT(runtime/int) + : lo_{static_cast(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} + +constexpr int128::int128(unsigned int v) : lo_{v}, hi_{0} {} +// NOLINTNEXTLINE(runtime/int) +constexpr int128::int128(unsigned long v) : lo_{v}, hi_{0} {} +// NOLINTNEXTLINE(runtime/int) +constexpr int128::int128(unsigned long long v) : lo_{v}, hi_{0} {} + +constexpr int128::int128(uint128 v) + : lo_{Uint128Low64(v)}, hi_{static_cast(Uint128High64(v))} {} + +#elif defined(ABSL_IS_BIG_ENDIAN) + +constexpr int128::int128(int64_t high, uint64_t low) : + hi_{high}, lo_{low} {} + +constexpr int128::int128(int v) + : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast(v)} {} +constexpr int128::int128(long v) // NOLINT(runtime/int) + : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast(v)} {} +constexpr int128::int128(long long v) // NOLINT(runtime/int) + : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast(v)} {} + +constexpr int128::int128(unsigned int v) : hi_{0}, lo_{v} {} +// NOLINTNEXTLINE(runtime/int) +constexpr int128::int128(unsigned long v) : hi_{0}, lo_{v} {} +// NOLINTNEXTLINE(runtime/int) +constexpr int128::int128(unsigned long long v) : hi_{0}, lo_{v} {} + +constexpr int128::int128(uint128 v) + : hi_{static_cast(Uint128High64(v))}, lo_{Uint128Low64(v)} {} + +#else // byte order +#error "Unsupported byte order: must be little-endian or big-endian." +#endif // byte order + +constexpr int128::operator bool() const { return lo_ || hi_; } + +constexpr int128::operator char() const { + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator signed char() const { + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator unsigned char() const { + return static_cast(lo_); +} + +constexpr int128::operator char16_t() const { + return static_cast(lo_); +} + +constexpr int128::operator char32_t() const { + return static_cast(lo_); +} + +constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const { + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator short() const { // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator unsigned short() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +constexpr int128::operator int() const { + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator unsigned int() const { + return static_cast(lo_); +} + +constexpr int128::operator long() const { // NOLINT(runtime/int) + // NOLINTNEXTLINE(runtime/int) + return static_cast(static_cast(*this)); +} + +constexpr int128::operator unsigned long() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +constexpr int128::operator long long() const { // NOLINT(runtime/int) + // We don't bother checking the value of hi_. If *this < 0, lo_'s high bit + // must be set in order for the value to fit into a long long. Conversely, if + // lo_'s high bit is set, *this must be < 0 for the value to fit. + return int128_internal::BitCastToSigned(lo_); +} + +constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) + return static_cast(lo_); // NOLINT(runtime/int) +} + +// Forward declaration for conversion operators to floating point types. +int128 operator-(int128 v); +bool operator!=(int128 lhs, int128 rhs); + +inline int128::operator float() const { + // We must convert the absolute value and then negate as needed, because + // floating point types are typically sign-magnitude. Otherwise, the + // difference between the high and low 64 bits when interpreted as two's + // complement overwhelms the precision of the mantissa. + // + // Also check to make sure we don't negate Int128Min() + return hi_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(lo_) + + std::ldexp(static_cast(hi_), 64); +} + +inline int128::operator double() const { + // See comment in int128::operator float() above. + return hi_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(lo_) + + std::ldexp(static_cast(hi_), 64); +} + +inline int128::operator long double() const { + // See comment in int128::operator float() above. + return hi_ < 0 && *this != Int128Min() + ? -static_cast(-*this) + : static_cast(lo_) + + std::ldexp(static_cast(hi_), 64); +} + +// Comparison operators. + +inline bool operator==(int128 lhs, int128 rhs) { + return (Int128Low64(lhs) == Int128Low64(rhs) && + Int128High64(lhs) == Int128High64(rhs)); +} + +inline bool operator!=(int128 lhs, int128 rhs) { + return !(lhs == rhs); +} + +inline bool operator<(int128 lhs, int128 rhs) { + return (Int128High64(lhs) == Int128High64(rhs)) + ? (Int128Low64(lhs) < Int128Low64(rhs)) + : (Int128High64(lhs) < Int128High64(rhs)); +} + +inline bool operator>(int128 lhs, int128 rhs) { + return (Int128High64(lhs) == Int128High64(rhs)) + ? (Int128Low64(lhs) > Int128Low64(rhs)) + : (Int128High64(lhs) > Int128High64(rhs)); +} + +inline bool operator<=(int128 lhs, int128 rhs) { + return !(lhs > rhs); +} + +inline bool operator>=(int128 lhs, int128 rhs) { + return !(lhs < rhs); +} + +// Unary operators. + +inline int128 operator-(int128 v) { + int64_t hi = ~Int128High64(v); + uint64_t lo = ~Int128Low64(v) + 1; + if (lo == 0) ++hi; // carry + return MakeInt128(hi, lo); +} + +inline bool operator!(int128 v) { + return !Int128Low64(v) && !Int128High64(v); +} + +inline int128 operator~(int128 val) { + return MakeInt128(~Int128High64(val), ~Int128Low64(val)); +} + +// Arithmetic operators. + +inline int128 operator+(int128 lhs, int128 rhs) { + int128 result = MakeInt128(Int128High64(lhs) + Int128High64(rhs), + Int128Low64(lhs) + Int128Low64(rhs)); + if (Int128Low64(result) < Int128Low64(lhs)) { // check for carry + return MakeInt128(Int128High64(result) + 1, Int128Low64(result)); + } + return result; +} + +inline int128 operator-(int128 lhs, int128 rhs) { + int128 result = MakeInt128(Int128High64(lhs) - Int128High64(rhs), + Int128Low64(lhs) - Int128Low64(rhs)); + if (Int128Low64(lhs) < Int128Low64(rhs)) { // check for carry + return MakeInt128(Int128High64(result) - 1, Int128Low64(result)); + } + return result; +} + +inline int128 operator*(int128 lhs, int128 rhs) { + uint128 result = uint128(lhs) * rhs; + return MakeInt128(int128_internal::BitCastToSigned(Uint128High64(result)), + Uint128Low64(result)); +} + +inline int128 int128::operator++(int) { + int128 tmp(*this); + *this += 1; + return tmp; +} + +inline int128 int128::operator--(int) { + int128 tmp(*this); + *this -= 1; + return tmp; +} + +inline int128& int128::operator++() { + *this += 1; + return *this; +} + +inline int128& int128::operator--() { + *this -= 1; + return *this; +} + +inline int128 operator|(int128 lhs, int128 rhs) { + return MakeInt128(Int128High64(lhs) | Int128High64(rhs), + Int128Low64(lhs) | Int128Low64(rhs)); +} + +inline int128 operator&(int128 lhs, int128 rhs) { + return MakeInt128(Int128High64(lhs) & Int128High64(rhs), + Int128Low64(lhs) & Int128Low64(rhs)); +} + +inline int128 operator^(int128 lhs, int128 rhs) { + return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs), + Int128Low64(lhs) ^ Int128Low64(rhs)); +} + +inline int128 operator<<(int128 lhs, int amount) { + // uint64_t shifts of >= 64 are undefined, so we need some special-casing. + if (amount < 64) { + if (amount != 0) { + return MakeInt128( + (Int128High64(lhs) << amount) | + static_cast(Int128Low64(lhs) >> (64 - amount)), + Int128Low64(lhs) << amount); + } + return lhs; + } + return MakeInt128(static_cast(Int128Low64(lhs) << (amount - 64)), 0); +} + +inline int128 operator>>(int128 lhs, int amount) { + // uint64_t shifts of >= 64 are undefined, so we need some special-casing. + if (amount < 64) { + if (amount != 0) { + return MakeInt128( + Int128High64(lhs) >> amount, + (Int128Low64(lhs) >> amount) | + (static_cast(Int128High64(lhs)) << (64 - amount))); + } + return lhs; + } + return MakeInt128(0, + static_cast(Int128High64(lhs) >> (amount - 64))); +} diff --git a/extern/int128/absl/numeric/internal/bits.h b/extern/int128/absl/numeric/internal/bits.h new file mode 100644 index 00000000000..bfef06bce1f --- /dev/null +++ b/extern/int128/absl/numeric/internal/bits.h @@ -0,0 +1,358 @@ +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_NUMERIC_INTERNAL_BITS_H_ +#define ABSL_NUMERIC_INTERNAL_BITS_H_ + +#include +#include +#include + +// Clang on Windows has __builtin_clzll; otherwise we need to use the +// windows intrinsic functions. +#if defined(_MSC_VER) && !defined(__clang__) +#include +#endif + +#include "absl/base/attributes.h" +#include "absl/base/config.h" + +#if defined(__GNUC__) && !defined(__clang__) +// GCC +#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1 +#else +#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x) +#endif + +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) +#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr +#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1 +#else +#define ABSL_INTERNAL_CONSTEXPR_POPCOUNT +#define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0 +#endif + +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) +#define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr +#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1 +#else +#define ABSL_INTERNAL_CONSTEXPR_CLZ +#define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0 +#endif + +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) +#define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr +#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1 +#else +#define ABSL_INTERNAL_CONSTEXPR_CTZ +#define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 0 +#endif + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace numeric_internal { + +constexpr bool IsPowerOf2(unsigned int x) noexcept { + return x != 0 && (x & (x - 1)) == 0; +} + +template +ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight( + T x, int s) noexcept { + static_assert(std::is_unsigned::value, "T must be unsigned"); + static_assert(IsPowerOf2(std::numeric_limits::digits), + "T must have a power-of-2 size"); + + return static_cast(x >> (s & (std::numeric_limits::digits - 1))) | + static_cast(x << ((-s) & (std::numeric_limits::digits - 1))); +} + +template +ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft( + T x, int s) noexcept { + static_assert(std::is_unsigned::value, "T must be unsigned"); + static_assert(IsPowerOf2(std::numeric_limits::digits), + "T must have a power-of-2 size"); + + return static_cast(x << (s & (std::numeric_limits::digits - 1))) | + static_cast(x >> ((-s) & (std::numeric_limits::digits - 1))); +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int +Popcount32(uint32_t x) noexcept { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount) + static_assert(sizeof(unsigned int) == sizeof(x), + "__builtin_popcount does not take 32-bit arg"); + return __builtin_popcount(x); +#else + x -= ((x >> 1) & 0x55555555); + x = ((x >> 2) & 0x33333333) + (x & 0x33333333); + return static_cast((((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24); +#endif +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int +Popcount64(uint64_t x) noexcept { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) + static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) + "__builtin_popcount does not take 64-bit arg"); + return __builtin_popcountll(x); +#else + x -= (x >> 1) & 0x5555555555555555ULL; + x = ((x >> 2) & 0x3333333333333333ULL) + (x & 0x3333333333333333ULL); + return static_cast( + (((x + (x >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56); +#endif +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int +Popcount(T x) noexcept { + static_assert(std::is_unsigned::value, "T must be unsigned"); + static_assert(IsPowerOf2(std::numeric_limits::digits), + "T must have a power-of-2 size"); + static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large"); + return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x); +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int +CountLeadingZeroes32(uint32_t x) { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) + // Use __builtin_clz, which uses the following instructions: + // x86: bsr, lzcnt + // ARM64: clz + // PPC: cntlzd + + static_assert(sizeof(unsigned int) == sizeof(x), + "__builtin_clz does not take 32-bit arg"); + // Handle 0 as a special case because __builtin_clz(0) is undefined. + return x == 0 ? 32 : __builtin_clz(x); +#elif defined(_MSC_VER) && !defined(__clang__) + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse(&result, x)) { + return 31 - result; + } + return 32; +#else + int zeroes = 28; + if (x >> 16) { + zeroes -= 16; + x >>= 16; + } + if (x >> 8) { + zeroes -= 8; + x >>= 8; + } + if (x >> 4) { + zeroes -= 4; + x >>= 4; + } + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes; +#endif +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int +CountLeadingZeroes16(uint16_t x) { +#if ABSL_HAVE_BUILTIN(__builtin_clzs) + static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int) + "__builtin_clzs does not take 16-bit arg"); + return x == 0 ? 16 : __builtin_clzs(x); +#else + return CountLeadingZeroes32(x) - 16; +#endif +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int +CountLeadingZeroes64(uint64_t x) { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) + // Use __builtin_clzll, which uses the following instructions: + // x86: bsr, lzcnt + // ARM64: clz + // PPC: cntlzd + static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) + "__builtin_clzll does not take 64-bit arg"); + + // Handle 0 as a special case because __builtin_clzll(0) is undefined. + return x == 0 ? 64 : __builtin_clzll(x); +#elif defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_X64) || defined(_M_ARM64)) + // MSVC does not have __buitin_clzll. Use _BitScanReverse64. + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse64(&result, x)) { + return 63 - result; + } + return 64; +#elif defined(_MSC_VER) && !defined(__clang__) + // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse + unsigned long result = 0; // NOLINT(runtime/int) + if ((x >> 32) && + _BitScanReverse(&result, static_cast(x >> 32))) { + return 31 - result; + } + if (_BitScanReverse(&result, static_cast(x))) { + return 63 - result; + } + return 64; +#else + int zeroes = 60; + if (x >> 32) { + zeroes -= 32; + x >>= 32; + } + if (x >> 16) { + zeroes -= 16; + x >>= 16; + } + if (x >> 8) { + zeroes -= 8; + x >>= 8; + } + if (x >> 4) { + zeroes -= 4; + x >>= 4; + } + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[x] + zeroes; +#endif +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int +CountLeadingZeroes(T x) { + static_assert(std::is_unsigned::value, "T must be unsigned"); + static_assert(IsPowerOf2(std::numeric_limits::digits), + "T must have a power-of-2 size"); + static_assert(sizeof(T) <= sizeof(uint64_t), "T too large"); + return sizeof(T) <= sizeof(uint16_t) + ? CountLeadingZeroes16(static_cast(x)) - + (std::numeric_limits::digits - + std::numeric_limits::digits) + : (sizeof(T) <= sizeof(uint32_t) + ? CountLeadingZeroes32(static_cast(x)) - + (std::numeric_limits::digits - + std::numeric_limits::digits) + : CountLeadingZeroes64(x)); +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int +CountTrailingZeroesNonzero32(uint32_t x) { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) + static_assert(sizeof(unsigned int) == sizeof(x), + "__builtin_ctz does not take 32-bit arg"); + return __builtin_ctz(x); +#elif defined(_MSC_VER) && !defined(__clang__) + unsigned long result = 0; // NOLINT(runtime/int) + _BitScanForward(&result, x); + return result; +#else + int c = 31; + x &= ~x + 1; + if (x & 0x0000FFFF) c -= 16; + if (x & 0x00FF00FF) c -= 8; + if (x & 0x0F0F0F0F) c -= 4; + if (x & 0x33333333) c -= 2; + if (x & 0x55555555) c -= 1; + return c; +#endif +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int +CountTrailingZeroesNonzero64(uint64_t x) { +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) + static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) + "__builtin_ctzll does not take 64-bit arg"); + return __builtin_ctzll(x); +#elif defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_X64) || defined(_M_ARM64)) + unsigned long result = 0; // NOLINT(runtime/int) + _BitScanForward64(&result, x); + return result; +#elif defined(_MSC_VER) && !defined(__clang__) + unsigned long result = 0; // NOLINT(runtime/int) + if (static_cast(x) == 0) { + _BitScanForward(&result, static_cast(x >> 32)); + return result + 32; + } + _BitScanForward(&result, static_cast(x)); + return result; +#else + int c = 63; + x &= ~x + 1; + if (x & 0x00000000FFFFFFFF) c -= 32; + if (x & 0x0000FFFF0000FFFF) c -= 16; + if (x & 0x00FF00FF00FF00FF) c -= 8; + if (x & 0x0F0F0F0F0F0F0F0F) c -= 4; + if (x & 0x3333333333333333) c -= 2; + if (x & 0x5555555555555555) c -= 1; + return c; +#endif +} + +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int +CountTrailingZeroesNonzero16(uint16_t x) { +#if ABSL_HAVE_BUILTIN(__builtin_ctzs) + static_assert(sizeof(unsigned short) == sizeof(x), // NOLINT(runtime/int) + "__builtin_ctzs does not take 16-bit arg"); + return __builtin_ctzs(x); +#else + return CountTrailingZeroesNonzero32(x); +#endif +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int +CountTrailingZeroes(T x) noexcept { + static_assert(std::is_unsigned::value, "T must be unsigned"); + static_assert(IsPowerOf2(std::numeric_limits::digits), + "T must have a power-of-2 size"); + static_assert(sizeof(T) <= sizeof(uint64_t), "T too large"); + return x == 0 ? std::numeric_limits::digits + : (sizeof(T) <= sizeof(uint16_t) + ? CountTrailingZeroesNonzero16(static_cast(x)) + : (sizeof(T) <= sizeof(uint32_t) + ? CountTrailingZeroesNonzero32( + static_cast(x)) + : CountTrailingZeroesNonzero64(x))); +} + +// If T is narrower than unsigned, T{1} << bit_width will be promoted. We +// want to force it to wraparound so that bit_ceil of an invalid value are not +// core constant expressions. +template +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, T>::type + BitCeilPromotionHelper(T x, T promotion) { + return (T{1} << (x + promotion)) >> promotion; +} + +template +ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline + typename std::enable_if::value, T>::type + BitCeilNonPowerOf2(T x) { + // If T is narrower than unsigned, it undergoes promotion to unsigned when we + // shift. We calculate the number of bits added by the wider type. + return BitCeilPromotionHelper( + static_cast(std::numeric_limits::digits - CountLeadingZeroes(x)), + T{sizeof(T) >= sizeof(unsigned) ? 0 + : std::numeric_limits::digits - + std::numeric_limits::digits}); +} + +} // namespace numeric_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_NUMERIC_INTERNAL_BITS_H_ diff --git a/extern/int128/absl/numeric/internal/representation.h b/extern/int128/absl/numeric/internal/representation.h new file mode 100644 index 00000000000..82d332fdde3 --- /dev/null +++ b/extern/int128/absl/numeric/internal/representation.h @@ -0,0 +1,55 @@ +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_ +#define ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_ + +#include + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace numeric_internal { + +// Returns true iff long double is represented as a pair of doubles added +// together. +inline constexpr bool IsDoubleDouble() { + // A double-double value always has exactly twice the precision of a double + // value--one double carries the high digits and one double carries the low + // digits. This property is not shared with any other common floating-point + // representation, so this test won't trigger false positives. For reference, + // this table gives the number of bits of precision of each common + // floating-point representation: + // + // type precision + // IEEE single 24 b + // IEEE double 53 + // x86 long double 64 + // double-double 106 + // IEEE quadruple 113 + // + // Note in particular that a quadruple-precision float has greater precision + // than a double-double float despite taking up the same amount of memory; the + // quad has more of its bits allocated to the mantissa than the double-double + // has. + return std::numeric_limits::digits == + 2 * std::numeric_limits::digits; +} + +} // namespace numeric_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_NUMERIC_INTERNAL_REPRESENTATION_H_ diff --git a/extern/libtomcrypt/libtomcrypt_MSVC15.vcxproj b/extern/libtomcrypt/libtomcrypt_MSVC15.vcxproj index c261ebcb46d..9e88cea301d 100644 --- a/extern/libtomcrypt/libtomcrypt_MSVC15.vcxproj +++ b/extern/libtomcrypt/libtomcrypt_MSVC15.vcxproj @@ -22,32 +22,42 @@ libtomcrypt {E3802982-DCB6-4D85-A2BD-6B08F0657E79} libtomcrypt - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false NotSet - v141_xp + v141_xp + v142 + v143 StaticLibrary false NotSet - v141 + v141 + v142 + v143 StaticLibrary false NotSet - v141_xp + v141_xp + v142 + v143 StaticLibrary false NotSet - v141 + v141 + v142 + v143 @@ -655,4 +665,4 @@ - \ No newline at end of file + diff --git a/extern/libtomcrypt/src/headers/tomcrypt_custom.h b/extern/libtomcrypt/src/headers/tomcrypt_custom.h index f73e98e5ef0..14ed7ca62f7 100644 --- a/extern/libtomcrypt/src/headers/tomcrypt_custom.h +++ b/extern/libtomcrypt/src/headers/tomcrypt_custom.h @@ -49,6 +49,7 @@ #define LTC_YARROW #define LTC_RNG_MAKE_PRNG #define LTC_RNG_GET_BYTES +#define LTC_DEVRANDOM #define LTC_NO_PK #define LTC_MRSA diff --git a/extern/libtommath/libtommath_MSVC15.vcxproj b/extern/libtommath/libtommath_MSVC15.vcxproj index 83567cf0523..b72547ea8af 100644 --- a/extern/libtommath/libtommath_MSVC15.vcxproj +++ b/extern/libtommath/libtommath_MSVC15.vcxproj @@ -22,32 +22,42 @@ libtommath {42109FEE-B0B9-4FCD-9E56-2863BF8C55D2} libtommath - 10.0.17763.0 + 10.0.17763.0 + 10.0 + 10.0 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 StaticLibrary false MultiByte - v141_xp + v141_xp + v142 + v143 StaticLibrary false MultiByte - v141 + v141 + v142 + v143 @@ -356,4 +366,4 @@ - \ No newline at end of file + diff --git a/extern/ttmath/ttmathint.h b/extern/ttmath/ttmathint.h index 8ad0189f934..f9971bdee69 100644 --- a/extern/ttmath/ttmathint.h +++ b/extern/ttmath/ttmathint.h @@ -1797,6 +1797,24 @@ class Int : public UInt } + Int operator>>(int move) const + { + Int temp( *this ); + + temp.Rcr(move, UInt::IsTheHighestBitSet() ? 1 : 0); + + return temp; + } + + + UInt & operator>>=(int move) + { + UInt::Rcr(move, UInt::IsTheHighestBitSet() ? 1 : 0); + + return *this; + } + + /*! * diff --git a/extern/ttmath/ttmathtypes.h b/extern/ttmath/ttmathtypes.h index 3d9ddbe7b0b..2b966aa1989 100644 --- a/extern/ttmath/ttmathtypes.h +++ b/extern/ttmath/ttmathtypes.h @@ -142,6 +142,7 @@ #endif +#define TTMATH_NOASM namespace ttmath { diff --git a/extern/zlib/Readme.txt b/extern/zlib/Readme.txt index 16f388c16ee..c9a18dadbd7 100644 --- a/extern/zlib/Readme.txt +++ b/extern/zlib/Readme.txt @@ -4,9 +4,9 @@ architectures. The source code of zlib library was downloaded from - http://zlib.net/zlib1211.zip + https://www.zlib.net/zlib131.zip -It was built with MSVC17 compilers using commands specified at win32/Makefile.msc: +It was built with VS 2017 compilers using commands specified at win32/Makefile.msc: win32: nmake -f win32/Makefile.msc diff --git a/extern/zlib/zlib.exe b/extern/zlib/zlib.exe index cfe5367e63d..5f9753ef222 100644 Binary files a/extern/zlib/zlib.exe and b/extern/zlib/zlib.exe differ diff --git a/lang_helpers/gds_codes.ftn b/lang_helpers/gds_codes.ftn index f87f64aa179..bae5ed83675 100644 --- a/lang_helpers/gds_codes.ftn +++ b/lang_helpers/gds_codes.ftn @@ -1684,8 +1684,8 @@ C -- PARAMETER (GDS__overriding_system_invalid = 335545135) INTEGER*4 GDS__overriding_user_invalid PARAMETER (GDS__overriding_user_invalid = 335545136) - INTEGER*4 GDS__overriding_system_missing - PARAMETER (GDS__overriding_system_missing = 335545137) + INTEGER*4 GDS__overriding_missing + PARAMETER (GDS__overriding_missing = 335545137) INTEGER*4 GDS__decprecision_err PARAMETER (GDS__decprecision_err = 335545138) INTEGER*4 GDS__decfloat_divide_by_zero @@ -1958,6 +1958,12 @@ C -- PARAMETER (GDS__ses_reset_failed = 335545272) INTEGER*4 GDS__block_size PARAMETER (GDS__block_size = 335545273) + INTEGER*4 GDS__tom_key_length + PARAMETER (GDS__tom_key_length = 335545274) + INTEGER*4 GDS__inf_invalid_args + PARAMETER (GDS__inf_invalid_args = 335545275) + INTEGER*4 GDS__sysf_invalid_null_empty + PARAMETER (GDS__sysf_invalid_null_empty = 335545276) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw @@ -2920,6 +2926,16 @@ C -- PARAMETER (GDS__nbackup_lostrec_guid_db = 337117261) INTEGER*4 GDS__nbackup_seq_misuse PARAMETER (GDS__nbackup_seq_misuse = 337117265) + INTEGER*4 GDS__nbackup_wrong_param + PARAMETER (GDS__nbackup_wrong_param = 337117268) + INTEGER*4 GDS__nbackup_clean_hist_misuse + PARAMETER (GDS__nbackup_clean_hist_misuse = 337117269) + INTEGER*4 GDS__nbackup_clean_hist_missed + PARAMETER (GDS__nbackup_clean_hist_missed = 337117270) + INTEGER*4 GDS__nbackup_keep_hist_missed + PARAMETER (GDS__nbackup_keep_hist_missed = 337117271) + INTEGER*4 GDS__nbackup_second_keep_switch + PARAMETER (GDS__nbackup_second_keep_switch = 337117272) INTEGER*4 GDS__trace_conflict_acts PARAMETER (GDS__trace_conflict_acts = 337182750) INTEGER*4 GDS__trace_act_notfound diff --git a/lang_helpers/gds_codes.pas b/lang_helpers/gds_codes.pas index 107c51496ef..95ca83f9a77 100644 --- a/lang_helpers/gds_codes.pas +++ b/lang_helpers/gds_codes.pas @@ -1679,8 +1679,8 @@ gds_overriding_system_invalid = 335545135; isc_overriding_user_invalid = 335545136; gds_overriding_user_invalid = 335545136; - isc_overriding_system_missing = 335545137; - gds_overriding_system_missing = 335545137; + isc_overriding_missing = 335545137; + gds_overriding_missing = 335545137; isc_decprecision_err = 335545138; gds_decprecision_err = 335545138; isc_decfloat_divide_by_zero = 335545139; @@ -1953,6 +1953,12 @@ gds_ses_reset_failed = 335545272; isc_block_size = 335545273; gds_block_size = 335545273; + isc_tom_key_length = 335545274; + gds_tom_key_length = 335545274; + isc_inf_invalid_args = 335545275; + gds_inf_invalid_args = 335545275; + isc_sysf_invalid_null_empty = 335545276; + gds_sysf_invalid_null_empty = 335545276; isc_gfix_db_name = 335740929; gds_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; @@ -2915,6 +2921,16 @@ gds_nbackup_lostrec_guid_db = 337117261; isc_nbackup_seq_misuse = 337117265; gds_nbackup_seq_misuse = 337117265; + isc_nbackup_wrong_param = 337117268; + gds_nbackup_wrong_param = 337117268; + isc_nbackup_clean_hist_misuse = 337117269; + gds_nbackup_clean_hist_misuse = 337117269; + isc_nbackup_clean_hist_missed = 337117270; + gds_nbackup_clean_hist_missed = 337117270; + isc_nbackup_keep_hist_missed = 337117271; + gds_nbackup_keep_hist_missed = 337117271; + isc_nbackup_second_keep_switch = 337117272; + gds_nbackup_second_keep_switch = 337117272; isc_trace_conflict_acts = 337182750; gds_trace_conflict_acts = 337182750; isc_trace_act_notfound = 337182751; diff --git a/src/alice/alice.cpp b/src/alice/alice.cpp index 8b120afb9e1..1ee1232d85e 100644 --- a/src/alice/alice.cpp +++ b/src/alice/alice.cpp @@ -113,7 +113,7 @@ int ALICE_main(Firebird::UtilSvc* uSvc) { Firebird::StaticStatusVector status; e.stuffException(status); - uSvc->setServiceStatus(status.begin()); + uSvc->getStatusAccessor().setServiceStatus(status.begin()); uSvc->started(); exit_code = FB_FAILURE; } @@ -414,7 +414,7 @@ int alice(Firebird::UtilSvc* uSvc) } } - if (table->in_sw_value & (sw_attach | sw_force | sw_tran | sw_cache)) + if (table->in_sw_value & (sw_attach | sw_force | sw_tran)) { if (--argc <= 0) { ALICE_error(17); // msg 17: number of seconds required @@ -468,7 +468,7 @@ int alice(Firebird::UtilSvc* uSvc) // put this here since to put it above overly complicates the parsing. // can't use tbl_requires since it only looks backwards on command line. - if ((flags & sw_shut) && !(flags & ((sw_attach | sw_force | sw_tran | sw_cache)))) + if ((flags & sw_shut) && !(flags & ((sw_attach | sw_force | sw_tran)))) { ALICE_error(19); // msg 19: must specify type of shutdown } @@ -493,7 +493,7 @@ int alice(Firebird::UtilSvc* uSvc) { if (uSvc->isService()) { - uSvc->setServiceStatus(ALICE_MSG_FAC, 20, MsgFormat::SafeArg()); + uSvc->getStatusAccessor().setServiceStatus(ALICE_MSG_FAC, 20, MsgFormat::SafeArg()); } else { @@ -594,8 +594,9 @@ int alice(Firebird::UtilSvc* uSvc) if ((exit_code != FINI_OK) && uSvc->isService() && (tdgbl->status[0] == 1) && (tdgbl->status[1] != 0)) { - uSvc->initStatus(); - uSvc->setServiceStatus(tdgbl->status); + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + uSvc->getStatusAccessor().setServiceStatus(tdgbl->status); } tdgbl->uSvc->started(); @@ -628,7 +629,7 @@ void ALICE_print(USHORT number, const SafeArg& arg) AliceGlobals* tdgbl = AliceGlobals::getSpecific(); if (tdgbl->uSvc->isService()) { - tdgbl->uSvc->setServiceStatus(ALICE_MSG_FAC, number, arg); + tdgbl->uSvc->getStatusAccessor().setServiceStatus(ALICE_MSG_FAC, number, arg); tdgbl->uSvc->started(); return; } @@ -651,7 +652,7 @@ void ALICE_print_status(bool error, const ISC_STATUS* status_vector) { const ISC_STATUS* vector = status_vector; AliceGlobals* tdgbl = AliceGlobals::getSpecific(); - tdgbl->uSvc->setServiceStatus(status_vector); + tdgbl->uSvc->getStatusAccessor().setServiceStatus(status_vector); if (error && tdgbl->uSvc->isService()) { @@ -683,7 +684,7 @@ void ALICE_error(USHORT number, const SafeArg& arg) AliceGlobals* tdgbl = AliceGlobals::getSpecific(); TEXT buffer[256]; - tdgbl->uSvc->setServiceStatus(ALICE_MSG_FAC, number, arg); + tdgbl->uSvc->getStatusAccessor().setServiceStatus(ALICE_MSG_FAC, number, arg); if (!tdgbl->uSvc->isService()) { fb_msg_format(0, ALICE_MSG_FAC, number, sizeof(buffer), buffer, arg); diff --git a/src/alice/aliceswi.h b/src/alice/aliceswi.h index d2b0c4d07e8..893a421a870 100644 --- a/src/alice/aliceswi.h +++ b/src/alice/aliceswi.h @@ -52,7 +52,7 @@ const SINT64 sw_user = 0x0000000000200000L; const SINT64 sw_password = 0x0000000000400000L; const SINT64 sw_shut = 0x0000000000800000L; const SINT64 sw_online = 0x0000000001000000L; // Byte 3, Bit 0 -const SINT64 sw_cache = 0x0000000002000000L; +//const SINT64 sw_cache = 0x0000000002000000L; const SINT64 sw_attach = 0x0000000004000000L; const SINT64 sw_force = 0x0000000008000000L; const SINT64 sw_tran = 0x0000000010000000L; @@ -66,6 +66,9 @@ const SINT64 sw_icu = QUADCONST(0x0000002000000000); const SINT64 sw_role = QUADCONST(0x0000004000000000); const SINT64 sw_replica = QUADCONST(0x0000008000000000); +// Popular combination of compatible switches +const SINT64 sw_auth_set = sw_user | sw_password | sw_role | sw_fetch_password | sw_trusted_auth; + enum alice_switches { @@ -95,7 +98,7 @@ enum alice_switches IN_SW_ALICE_PASSWORD = 23, IN_SW_ALICE_SHUT = 24, IN_SW_ALICE_ONLINE = 25, - IN_SW_ALICE_CACHE = 26, +// IN_SW_ALICE_CACHE = 26, IN_SW_ALICE_ATTACH = 27, IN_SW_ALICE_FORCE = 28, IN_SW_ALICE_TRAN = 29, @@ -140,7 +143,7 @@ static const char* const ALICE_SW_SHUT_FULL = "FULL"; static const Switches::in_sw_tab_t alice_in_sw_table[] = { {IN_SW_ALICE_ACTIVATE, isc_spb_prp_activate, "ACTIVATE_SHADOW", sw_activate, - 0, ~(sw_activate | sw_user | sw_password | sw_nolinger | sw_role), false, true, 25, 2, NULL}, + 0, ~(sw_activate | sw_auth_set | sw_nolinger), false, true, 25, 2, NULL}, // msg 25: \t-activate shadow file for database usage {IN_SW_ALICE_ATTACH, isc_spb_prp_attachments_shutdown, "ATTACH", sw_attach, sw_shut, 0, false, false, 26, 2, NULL}, @@ -156,11 +159,8 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = 0, 0, false, false, 28, 1, NULL}, // msg 28: \t-buffers\tset page buffers {IN_SW_ALICE_COMMIT, isc_spb_rpr_commit_trans, "COMMIT", sw_commit, - 0, ~(sw_commit | sw_user | sw_password | sw_nolinger | sw_role), false, false, 29, 2, NULL}, + 0, ~(sw_commit | sw_auth_set | sw_nolinger), false, false, 29, 2, NULL}, // msg 29: \t-commit\t\tcommit transaction - {IN_SW_ALICE_CACHE, 0, "CACHE", sw_cache, - sw_shut, 0, false, false, 30, 2, NULL}, - // msg 30: \t-cache\t\tshutdown cache manager #ifdef DEV_BUILD /* {IN_SW_ALICE_DISABLE, 0, "DISABLE", sw_disable, @@ -175,7 +175,7 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = sw_shut, 0, false, false, 33, 2, NULL}, // msg 33: \t-force\t\tforce database shutdown {IN_SW_ALICE_FETCH_PASSWORD, 0, "FETCH_PASSWORD", sw_fetch_password, - 0, sw_password, false, false, 119, 2, NULL}, + 0, (sw_trusted_auth | sw_password), false, false, 119, 2, NULL}, // msg 119: -fetch_password fetch_password from file {IN_SW_ALICE_HOUSEKEEPING, isc_spb_prp_sweep_interval, "HOUSEKEEPING", sw_housekeeping, 0, 0, false, false, 34, 1, NULL}, @@ -190,13 +190,13 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = 0, 0, false, true, 36, 1, NULL}, // msg 36: \t-kill\t\tkill all unavailable shadow files {IN_SW_ALICE_LIST, isc_spb_rpr_list_limbo_trans, "LIST", sw_list, - 0, ~(sw_list | sw_user | sw_password | sw_nolinger | sw_role), false, true, 37, 1, NULL}, + 0, ~(sw_list | sw_auth_set | sw_nolinger), false, true, 37, 1, NULL}, // msg 37: \t-list\t\tshow limbo transactions {IN_SW_ALICE_MEND, isc_spb_rpr_mend_db, "MEND", sw_mend | sw_validate | sw_full, - 0, ~(sw_no_update | sw_user | sw_password | sw_nolinger | sw_role), false, true, 38, 2, NULL}, + 0, ~(sw_no_update | sw_auth_set | sw_nolinger), false, true, 38, 2, NULL}, // msg 38: \t-mend\t\tprepare corrupt database for backup {IN_SW_ALICE_MODE, 0, "MODE", sw_mode, - 0, ~(sw_mode | sw_user | sw_password | sw_nolinger | sw_role), false, false, 109, 2, NULL}, + 0, ~(sw_mode | sw_auth_set | sw_nolinger), false, false, 109, 2, NULL}, // msg 109: \t-mode\t\tread_only or read_write {IN_SW_ALICE_NOLINGER, isc_spb_prp_nolinger, "NOLINGER", sw_nolinger, 0, sw_shut, false, true, 121, 3, NULL}, @@ -222,46 +222,46 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = */ #endif {IN_SW_ALICE_REPLICA, isc_spb_prp_replica_mode, "REPLICA", sw_replica, - 0, ~(sw_replica | sw_user | sw_password | sw_nolinger | sw_role), false, false, 134, 2, NULL}, + 0, ~(sw_replica | sw_auth_set | sw_nolinger), false, false, 134, 2, NULL}, // msg 134: -replica access mode {IN_SW_ALICE_ROLE, 0, "ROLE", sw_role, 0, 0, false, false, 132, 4, NULL}, // msg 132: -role set SQL role name {IN_SW_ALICE_ROLLBACK, isc_spb_rpr_rollback_trans, "ROLLBACK", sw_rollback, - 0, ~(sw_rollback | sw_user | sw_password | sw_nolinger | sw_role), false, false, 44, 1, NULL}, + 0, ~(sw_rollback | sw_auth_set | sw_nolinger), false, false, 44, 1, NULL}, // msg 44: \t-rollback\trollback transaction {IN_SW_ALICE_SET_DB_SQL_DIALECT, isc_spb_prp_set_sql_dialect, "SQL_DIALECT", sw_set_db_dialect, 0, 0, false, false, 111, 2, NULL}, // msg 111: \t-SQL_dialect\t\set dataabse dialect n {IN_SW_ALICE_SWEEP, isc_spb_rpr_sweep_db, "SWEEP", sw_sweep, - 0, ~(sw_sweep | sw_user | sw_password | sw_nolinger | sw_role), false, true, 45, 2, NULL}, + 0, ~(sw_sweep | sw_auth_set | sw_nolinger), false, true, 45, 2, NULL}, // msg 45: \t-sweep\t\tforce garbage collection {IN_SW_ALICE_SHUT, isc_spb_prp_shutdown_mode, "SHUTDOWN", sw_shut, - 0, ~(sw_shut | sw_attach | sw_cache | sw_force | sw_tran | sw_user | sw_password | sw_role), + 0, ~(sw_shut | sw_attach | sw_force | sw_tran | sw_auth_set), false, false, 46, 2, NULL}, // msg 46: \t-shut\t\tshutdown {IN_SW_ALICE_TWO_PHASE, isc_spb_rpr_recover_two_phase, "TWO_PHASE", sw_two_phase, - 0, ~(sw_two_phase | sw_user | sw_password | sw_nolinger | sw_role), false, false, 47, 2, NULL}, + 0, ~(sw_two_phase | sw_auth_set | sw_nolinger), false, false, 47, 2, NULL}, // msg 47: \t-two_phase\tperform automated two-phase recovery {IN_SW_ALICE_TRAN, isc_spb_prp_transactions_shutdown, "TRANSACTION", sw_tran, sw_shut, 0, false, false, 48, 3, NULL}, // msg 48: \t-tran\t\tshutdown transaction startup #ifdef TRUSTED_AUTH {IN_SW_ALICE_TRUSTED_AUTH, 0, "TRUSTED", sw_trusted_auth, - 0, (sw_user | sw_password), false, false, 115, 3, NULL}, + 0, (sw_user | sw_password | sw_fetch_password), false, false, 115, 3, NULL}, // msg 115: -trusted use trusted authentication #endif {IN_SW_ALICE_NO_RESERVE, 0, "USE", sw_no_reserve, - 0, ~(sw_no_reserve | sw_user | sw_password | sw_nolinger | sw_role), false, false, 49, 1, NULL}, + 0, ~(sw_no_reserve | sw_auth_set | sw_nolinger), false, false, 49, 1, NULL}, // msg 49: \t-use\t\tuse full or reserve space for versions {IN_SW_ALICE_USER, 0, "USER", sw_user, 0, sw_trusted_auth, false, false, 50, 4, NULL}, // msg 50: \t-user\t\tdefault user name {IN_SW_ALICE_VALIDATE, isc_spb_rpr_validate_db, "VALIDATE", sw_validate, - 0, ~(sw_validate | sw_user | sw_password | sw_nolinger | sw_role), false, true, 51, 1, NULL}, + 0, ~(sw_validate | sw_auth_set | sw_nolinger), false, true, 51, 1, NULL}, // msg 51: \t-validate\tvalidate database structure {IN_SW_ALICE_WRITE, 0, "WRITE", sw_write, - 0, ~(sw_write | sw_user | sw_password | sw_nolinger | sw_role), false, false, 52, 1, NULL}, + 0, ~(sw_write | sw_auth_set | sw_nolinger), false, false, 52, 1, NULL}, // msg 52: \t-write\t\twrite synchronously or asynchronously #ifdef DEV_BUILD {IN_SW_ALICE_X, 0, "X", 0, diff --git a/src/alice/exe.cpp b/src/alice/exe.cpp index 727be92517f..330159a78de 100644 --- a/src/alice/exe.cpp +++ b/src/alice/exe.cpp @@ -126,7 +126,7 @@ int EXE_action(const TEXT* database, const SINT64 switches) if (error) { - tdgbl->uSvc->setServiceStatus(tdgbl->status); + tdgbl->uSvc->getStatusAccessor().setServiceStatus(tdgbl->status); } } @@ -182,7 +182,7 @@ int EXE_two_phase(const TEXT* database, const SINT64 switches) if (error) { - tdgbl->uSvc->setServiceStatus(tdgbl->status); + tdgbl->uSvc->getStatusAccessor().setServiceStatus(tdgbl->status); } } @@ -256,8 +256,6 @@ static void buildDpb(Firebird::ClumpletWriter& dpb, const SINT64 switches) UCHAR b = 0; if (switches & sw_attach) b |= isc_dpb_shut_attachment; - else if (switches & sw_cache) - b |= isc_dpb_shut_cache; else if (switches & sw_force) b |= isc_dpb_shut_force; else if (switches & sw_tran) diff --git a/src/alice/tdr.cpp b/src/alice/tdr.cpp index 29762496d6e..168b3391bfc 100644 --- a/src/alice/tdr.cpp +++ b/src/alice/tdr.cpp @@ -288,22 +288,22 @@ void TDR_list_limbo(FB_API_HANDLE handle, const TEXT* name, const SINT64 switche TraNumber id; tdr* trans; - UCHAR* ptr = buffer; - bool flag = true; - while (flag) + for (Firebird::ClumpletReader p(Firebird::ClumpletReader::InfoResponse, buffer, sizeof(buffer)); + !p.isEof(); p.moveNext()) { - const USHORT item = *ptr++; - const USHORT length = (USHORT) gds__vax_integer(ptr, 2); - ptr += 2; + UCHAR item = p.getClumpTag(); + if (item == isc_info_end) + break; + + const USHORT length = (USHORT) p.getClumpLength(); switch (item) { case isc_info_limbo: - id = isc_portable_integer(ptr, length); + id = p.getBigInt(); if (switches & (sw_commit | sw_rollback | sw_two_phase | sw_prompt)) { TDR_reconnect_multiple(handle, id, name, switches); - ptr += length; break; } if (!tdgbl->uSvc->isService()) @@ -326,7 +326,6 @@ void TDR_list_limbo(FB_API_HANDLE handle, const TEXT* name, const SINT64 switche tdgbl->uSvc->putSInt64(isc_spb_single_tra_id_64, id); else tdgbl->uSvc->putSLong(isc_spb_single_tra_id, (SLONG) id); - ptr += length; break; case isc_info_truncated: @@ -336,10 +335,6 @@ void TDR_list_limbo(FB_API_HANDLE handle, const TEXT* name, const SINT64 switche // msg 72: More limbo transactions than fit. Try again // And how it's going to retry with a bigger buffer if the buffer is fixed size? } - // fall through - - case isc_info_end: - flag = false; break; default: diff --git a/src/auth/AuthDbg.cpp b/src/auth/AuthDbg.cpp index 6f2110e629b..386f9f5e231 100644 --- a/src/auth/AuthDbg.cpp +++ b/src/auth/AuthDbg.cpp @@ -38,7 +38,7 @@ static Firebird::SimpleFactory clientFactory; static Firebird::SimpleFactory serverFactory; -extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) { Firebird::CachedMasterInterface::set(master); diff --git a/src/auth/SecDbCache.h b/src/auth/SecDbCache.h index 819fd7f711e..c29037f463b 100644 --- a/src/auth/SecDbCache.h +++ b/src/auth/SecDbCache.h @@ -92,6 +92,16 @@ class CachedSecurityDatabase FB_FINAL (*this)->mutex.enter(FB_FUNCTION); } + void reset() + { + if (hasData()) + { + (*this)->mutex.leave(); + (*this)->close(); + assign(nullptr); + } + } + ~Instance() { if (hasData()) diff --git a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp index 0969523b662..ce173315217 100644 --- a/src/auth/SecureRemotePassword/manage/SrpManagement.cpp +++ b/src/auth/SecureRemotePassword/manage/SrpManagement.cpp @@ -38,14 +38,6 @@ #include "../common/classes/auto.h" #include "../common/classes/ParsedList.h" -#ifndef FB_EXPORTED -#if defined(DARWIN) -#define FB_EXPORTED __attribute__((visibility("default"))) -#else -#define FB_EXPORTED -#endif // OS choice (DARWIN) -#endif // FB_EXPORTED - namespace { const unsigned int SZ_LOGIN = 31; @@ -343,6 +335,8 @@ class SrpManagement FB_FINAL : public Firebird::StdPluginexecute(status, nullptr, 0, "SET BIND OF BOOLEAN TO NATIVE", SQL_DIALECT_V6, NULL, NULL, NULL, NULL); + switch(user->operation()) { case Firebird::IUser::OP_USER_DROP_MAP: @@ -984,7 +978,7 @@ static Firebird::SimpleFactory factory; } // namespace Auth -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) { Firebird::CachedMasterInterface::set(master); Firebird::PluginManagerInterfacePtr()->registerPluginFactory(Firebird::IPluginManager::TYPE_AUTH_USER_MANAGEMENT, Auth::RemotePassword::plugName, &Auth::factory); diff --git a/src/auth/SecureRemotePassword/server/SrpServer.cpp b/src/auth/SecureRemotePassword/server/SrpServer.cpp index 538b417c3bd..0e54a9053fd 100644 --- a/src/auth/SecureRemotePassword/server/SrpServer.cpp +++ b/src/auth/SecureRemotePassword/server/SrpServer.cpp @@ -139,8 +139,11 @@ class SecurityDatabase : public VSecDb instances->shutdown(); } - static void forceClean(IProvider* p, const char* secDbName) + static void forceClean(IProvider* p, CachedSecurityDatabase::Instance& instance) { + Firebird::PathName secDbName(instance->secureDbName); + + instance.reset(); cleanup(); ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); @@ -151,13 +154,14 @@ class SecurityDatabase : public VSecDb dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(secDbName)); FbLocalStatus status; - RefPtr att(REF_NO_INCR, p->attachDatabase(&status, secDbName, dpb.getBufferLength(), dpb.getBuffer())); + RefPtr att(REF_NO_INCR, + p->attachDatabase(&status, secDbName.c_str(), dpb.getBufferLength(), dpb.getBuffer())); check(&status); HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: gfix-like attach to sec db %s\n", secDbName)); } - SecurityDatabase(const char* secDbName, ICryptKeyCallback* cryptCallback) + SecurityDatabase(CachedSecurityDatabase::Instance& instance, ICryptKeyCallback* cryptCallback) : att(nullptr), tra(nullptr), stmt(nullptr) { FbLocalStatus status; @@ -174,10 +178,10 @@ class SecurityDatabase : public VSecDb ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); dpb.insertByte(isc_dpb_sec_attach, TRUE); dpb.insertString(isc_dpb_user_name, DBA_USER_NAME, fb_strlen(DBA_USER_NAME)); - dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(secDbName)); - att = p->attachDatabase(&status, secDbName, dpb.getBufferLength(), dpb.getBuffer()); + dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(instance->secureDbName)); + att = p->attachDatabase(&status, instance->secureDbName, dpb.getBufferLength(), dpb.getBuffer()); check(&status); - HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: attached sec db %s\n", secDbName)); + HANDSHAKE_DEBUG(fprintf(stderr, "Srv SRP: attached sec db %s\n", instance->secureDbName)); const UCHAR tpb[] = { @@ -196,7 +200,7 @@ class SecurityDatabase : public VSecDb stmt = att->prepare(&status, tra, 0, sql, 3, IStatement::PREPARE_PREFETCH_METADATA); if (status->getState() & IStatus::STATE_ERRORS) { - checkStatusVectorForMissingTable(status->getErrors(), [ &p, secDbName ] { forceClean(p, secDbName); }); + checkStatusVectorForMissingTable(status->getErrors(), [ &p, &instance ] { forceClean(p, instance); }); status_exception::raise(&status); } } @@ -270,6 +274,10 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite account = sb->getLogin(); + const size_t len = account.length(); + if (len > SZ_LOGIN) + status_exception::raise(Arg::Gds(isc_long_login) << Arg::Num(len) << Arg::Num(SZ_LOGIN)); + unsigned int length; const unsigned char* val = sb->getData(&length); clientPubKey.assign(val, length); @@ -296,7 +304,7 @@ int SrpServer::authenticate(CheckStatusWrapper* status, IServerBlock* sb, IWrite // Create SecurityDatabase if needed if (!instance->secDb) - instance->secDb = FB_NEW SecurityDatabase(instance->secureDbName, cryptCallback); + instance->secDb = FB_NEW SecurityDatabase(instance, cryptCallback); // Lookup instance->secDb->lookup(messages.param.getData(), messages.data.getData()); diff --git a/src/auth/SecurityDatabase/LegacyManagement.epp b/src/auth/SecurityDatabase/LegacyManagement.epp index b60aeed5648..80cbc070dc0 100644 --- a/src/auth/SecurityDatabase/LegacyManagement.epp +++ b/src/auth/SecurityDatabase/LegacyManagement.epp @@ -762,7 +762,7 @@ int SecurityDatabaseManagement::execute(Firebird::CheckStatusWrapper* st, Firebi // register plugin static Firebird::SimpleFactory factory; -extern "C" void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) { Firebird::CachedMasterInterface::set(master); Firebird::PluginManagerInterfacePtr()->registerPluginFactory( diff --git a/src/auth/SecurityDatabase/LegacyServer.cpp b/src/auth/SecurityDatabase/LegacyServer.cpp index 0b77e7a5a59..1afe87e4abf 100644 --- a/src/auth/SecurityDatabase/LegacyServer.cpp +++ b/src/auth/SecurityDatabase/LegacyServer.cpp @@ -411,7 +411,7 @@ void registerLegacyServer(IPluginManager* iPlugin) #ifdef PLUG_MODULE -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master) { CachedMasterInterface::set(master); diff --git a/src/auth/trusted/AuthSspi.cpp b/src/auth/trusted/AuthSspi.cpp index 4d43cf29ed0..515271b1ec9 100644 --- a/src/auth/trusted/AuthSspi.cpp +++ b/src/auth/trusted/AuthSspi.cpp @@ -67,6 +67,15 @@ namespace namespace Auth { + +static thread_local bool legacySSP = false; + +void setLegacySSP(bool value) +{ + legacySSP = value; +} + + HINSTANCE AuthSspi::library = 0; bool AuthSspi::initEntries() @@ -109,7 +118,8 @@ AuthSspi::AuthSspi() groupNames(*getDefaultMemoryPool()), sessionKey(*getDefaultMemoryPool()) { TimeStamp timeOut; - hasCredentials = initEntries() && (fAcquireCredentialsHandle(0, "NTLM", + hasCredentials = initEntries() && (fAcquireCredentialsHandle(0, + legacySSP ? NTLMSP_NAME_A : NEGOSSP_NAME_A, SECPKG_CRED_BOTH, 0, 0, 0, 0, &secHndl, &timeOut) == SEC_E_OK); } @@ -367,7 +377,8 @@ bool AuthSspi::getLogin(string& login, bool& wh, GroupsList& grNames) WinSspiServer::WinSspiServer(Firebird::IPluginConfig*) - : sspiData(getPool()) + : sspiData(getPool()), + done(false) { } int WinSspiServer::authenticate(Firebird::CheckStatusWrapper* status, @@ -376,17 +387,18 @@ int WinSspiServer::authenticate(Firebird::CheckStatusWrapper* status, { try { - const bool wasActive = sspi.isActive(); - sspiData.clear(); unsigned int length; const unsigned char* bytes = sBlock->getData(&length); sspiData.add(bytes, length); + if (done && !length && !sspi.isActive()) + return AUTH_SUCCESS; + if (!sspi.accept(sspiData)) return AUTH_CONTINUE; - if (wasActive && !sspi.isActive()) + if (!sspi.isActive()) { bool wheel = false; string login; @@ -445,7 +457,9 @@ int WinSspiServer::authenticate(Firebird::CheckStatusWrapper* status, return AUTH_FAILED; } - return AUTH_SUCCESS; + done = true; + if (sspiData.isEmpty()) + return AUTH_SUCCESS; } sBlock->putData(status, sspiData.getCount(), sspiData.begin()); @@ -456,7 +470,7 @@ int WinSspiServer::authenticate(Firebird::CheckStatusWrapper* status, return AUTH_FAILED; } - return AUTH_MORE_DATA; + return done ? AUTH_SUCCESS_WITH_DATA : AUTH_MORE_DATA; } diff --git a/src/auth/trusted/AuthSspi.h b/src/auth/trusted/AuthSspi.h index 9e3f254b5fd..8988a0d6b51 100644 --- a/src/auth/trusted/AuthSspi.h +++ b/src/auth/trusted/AuthSspi.h @@ -124,6 +124,7 @@ class WinSspiServer : private: AuthSspi::DataHolder sspiData; AuthSspi sspi; + bool done; }; class WinSspiClient : @@ -144,6 +145,10 @@ class WinSspiClient : void registerTrustedClient(Firebird::IPluginManager* iPlugin); void registerTrustedServer(Firebird::IPluginManager* iPlugin); +// Set per-thread flag that specify which security package should be used by +// newly created plugin instances: true - use NTLM, false - use Negotiate. +void setLegacySSP(bool value); + } // namespace Auth #endif // TRUSTED_AUTH diff --git a/src/burp/OdsDetection.epp b/src/burp/OdsDetection.epp index 644521a176c..f805618d019 100644 --- a/src/burp/OdsDetection.epp +++ b/src/burp/OdsDetection.epp @@ -61,8 +61,6 @@ namespace } -DATABASE DB = STATIC FILENAME "yachts.lnk"; - #define DB tdgbl->db_handle #define fbTrans tdgbl->tr_handle #define gds_trans tdgbl->tr_handle @@ -70,6 +68,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk"; #define isc_status (&tdgbl->status_vector) #define gds_status (&tdgbl->status_vector) +// unused +#define fbProvider +#define fbStatus2 + +DATABASE DB = STATIC FILENAME "yachts.lnk"; + void detectRuntimeODS() { @@ -163,7 +167,6 @@ namespace **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - BURP_print_status(true, isc_status); - BURP_abort(); + BURP_abort(isc_status); } } diff --git a/src/burp/backup.epp b/src/burp/backup.epp index e2bf9603fdf..6985bdd6d53 100644 --- a/src/burp/backup.epp +++ b/src/burp/backup.epp @@ -70,8 +70,6 @@ using Firebird::FbLocalStatus; // GPRE. This is to avoid multiple threading problems with module // level statics. -DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file; - #define DB tdgbl->db_handle #define fbTrans tdgbl->tr_handle #define gds_trans tdgbl->tr_handle @@ -79,6 +77,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file; #define isc_status (&tdgbl->status_vector) #define gds_status (&tdgbl->status_vector) +// unused +#define fbProvider +#define fbStatus2 + +DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file; + namespace // unnamed, private { @@ -549,8 +553,7 @@ void general_on_error() **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - BURP_print_status(true, isc_status); - BURP_abort(); + BURP_abort(isc_status); } @@ -961,6 +964,7 @@ void put_array( burp_fld* field, burp_rel* relation, ISC_QUAD* blob_id) case blr_long: case blr_quad: case blr_int64: + case blr_int128: add_byte(blr, field->fld_scale); break; case blr_text: @@ -1140,7 +1144,7 @@ void put_asciz( const att_type attribute, const TEXT* string) // We can't honor operating systems that allow longer file names. if (len >= MAX_FILE_NAME_SIZE) { - BURP_print(true, 343, SafeArg() << int(attribute) << "put_asciz()" << (MAX_FILE_NAME_SIZE - 1)); + BURP_print(false, 343, SafeArg() << int(attribute) << "put_asciz()" << (MAX_FILE_NAME_SIZE - 1)); // msg 343: text for attribute @1 is too large in @2, truncating to @3 bytes len = MAX_FILE_NAME_SIZE - 1; } @@ -1961,6 +1965,7 @@ void put_boolean(att_type attribute, const FB_BOOLEAN value) BurpGlobals* tdgbl = BurpGlobals::getSpecific(); put(tdgbl, attribute); + put(tdgbl, (UCHAR) 1); put(tdgbl, value ? 1u : 0u); } @@ -2578,6 +2583,7 @@ void write_database( const TEXT* dbb_file) FbLocalStatus status_vector; UCHAR buffer[256]; Firebird::IRequest* req_handle1 = nullptr; + Firebird::IRequest* req_handle2 = nullptr; BurpGlobals* tdgbl = BurpGlobals::getSpecific(); @@ -2680,6 +2686,26 @@ void write_database( const TEXT* dbb_file) ON_ERROR general_on_error(); END_ERROR; + + if (tdgbl->runtimeODS >= DB_VERSION_DDL13) + { + FOR (REQUEST_HANDLE req_handle2) + PUB IN RDB$PUBLICATIONS + WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION + { + fb_assert(PUB.RDB$SYSTEM_FLAG != 0); + + if (!PUB.RDB$ACTIVE_FLAG.NULL) + put_boolean(att_default_pub_active, PUB.RDB$ACTIVE_FLAG); + + if (!PUB.RDB$AUTO_ENABLE.NULL) + put_boolean(att_default_pub_auto_enable, PUB.RDB$AUTO_ENABLE); + } + END_FOR + ON_ERROR + general_on_error(); + END_ERROR + } } else { @@ -2697,6 +2723,7 @@ void write_database( const TEXT* dbb_file) } MISC_release_request_silent(req_handle1); + MISC_release_request_silent(req_handle2); put(tdgbl, att_end); } @@ -2881,7 +2908,10 @@ void write_functions() BURP_verbose (147, temp); // msg 147 writing function %.*s put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); - put_int32 (att_function_return_arg, X.RDB$RETURN_ARGUMENT); + + if (!X.RDB$RETURN_ARGUMENT.NULL) + put_int32 (att_function_return_arg, X.RDB$RETURN_ARGUMENT); + put_int32 (att_function_type, X.RDB$FUNCTION_TYPE); PUT_TEXT (att_function_query_name, X.RDB$QUERY_NAME); @@ -2935,7 +2965,10 @@ void write_functions() put_source_blob (att_function_description2, att_function_description, X.RDB$DESCRIPTION); PUT_TEXT (att_function_module_name, X.RDB$MODULE_NAME); PUT_TEXT (att_function_entrypoint, X.RDB$ENTRYPOINT); - put_int32 (att_function_return_arg, X.RDB$RETURN_ARGUMENT); + + if (!X.RDB$RETURN_ARGUMENT.NULL) + put_int32 (att_function_return_arg, X.RDB$RETURN_ARGUMENT); + put_int32 (att_function_type, X.RDB$FUNCTION_TYPE); PUT_TEXT (att_function_query_name, X.RDB$QUERY_NAME); put(tdgbl, att_end); @@ -2997,7 +3030,9 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) BURP_verbose (141, temp); // msg 141 writing argument for function %s - put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + if (!X.RDB$ARGUMENT_POSITION.NULL) + put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + put_int32 (att_functionarg_passing_mechanism, X.RDB$MECHANISM); put_int32 (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_int32 (att_functionarg_field_scale, X.RDB$FIELD_SCALE); @@ -3048,7 +3083,10 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (141, temp); // msg 141 writing argument for function %s - put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + + if (!X.RDB$ARGUMENT_POSITION.NULL) + put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + put_int32 (att_functionarg_passing_mechanism, X.RDB$MECHANISM); put_int32 (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_int32 (att_functionarg_field_scale, X.RDB$FIELD_SCALE); @@ -3076,7 +3114,10 @@ void write_function_args(const GDS_NAME package, GDS_NAME funcptr) MISC_terminate (X.RDB$FUNCTION_NAME, temp, l, sizeof(temp)); BURP_verbose (141, temp); // msg 141 writing argument for function %s - put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + + if (!X.RDB$ARGUMENT_POSITION.NULL) + put_int32 (att_functionarg_position, X.RDB$ARGUMENT_POSITION); + put_int32 (att_functionarg_passing_mechanism, X.RDB$MECHANISM); put_int32 (att_functionarg_field_type, X.RDB$FIELD_TYPE); put_int32 (att_functionarg_field_scale, X.RDB$FIELD_SCALE); diff --git a/src/burp/burp.cpp b/src/burp/burp.cpp index b7a40b11c6a..6f83b2a4a64 100644 --- a/src/burp/burp.cpp +++ b/src/burp/burp.cpp @@ -94,7 +94,6 @@ const char switch_char = '-'; const char* const output_suppress = "SUPPRESS"; -const int burp_msg_fac = 12; const int MIN_VERBOSE_INTERVAL = 100; enum gbak_action @@ -161,8 +160,9 @@ int BURP_main(Firebird::UtilSvc* uSvc) { Firebird::StaticStatusVector status; e.stuffException(status); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); exit_code = FB_FAILURE; } @@ -371,9 +371,8 @@ static int svc_api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches) spb.getBufferLength(), spb.getBuffer()); if (!status.isSuccess()) { - BURP_print_status(true, &status); - BURP_print(true, 83); - // msg 83 Exiting before completion due to errors + BURP_print_status(true, &status, 83); + // msg 83 Exiting before completion due to errors return FINI_ERROR; } @@ -406,9 +405,9 @@ static int svc_api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches) svc_handle->start(&status, thdlen, thd); if (!status.isSuccess()) { - BURP_print_status(true, &status); + BURP_print_status(true, &status, 83); + // msg 83 Exiting before completion due to errors svc_handle->release(); - BURP_print(true, 83); // msg 83 Exiting before completion due to errors return FINI_ERROR; } @@ -437,9 +436,9 @@ static int svc_api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches) sizeof(respbuf), respbuf); if (!status.isSuccess()) { - BURP_print_status(true, &status); + BURP_print_status(true, &status, 83); + // msg 83 Exiting before completion due to errors svc_handle->release(); - BURP_print(true, 83); // msg 83 Exiting before completion due to errors return FINI_ERROR; } @@ -487,10 +486,10 @@ static int svc_api_gbak(Firebird::UtilSvc* uSvc, const Switches& switches) { FbLocalStatus s; e.stuffException(&s); - BURP_print_status(true, &s); + BURP_print_status(true, &s, 83); + // msg 83 Exiting before completion due to errors if (svc_handle) svc_handle->release(); - BURP_print(true, 83); // msg 83 Exiting before completion due to errors return FINI_ERROR; } } @@ -571,8 +570,6 @@ int gbak(Firebird::UtilSvc* uSvc) if (switches.exists(IN_SW_BURP_SE, argv.begin(), 1, argc)) return svc_api_gbak(uSvc, switches); - uSvc->started(); - if (argc <= 1) { burp_usage(switches); @@ -1376,12 +1373,11 @@ int gbak(Firebird::UtilSvc* uSvc) tdgbl->action->act_action = ACT_unknown; action = open_files(file1, &file2, sw_replace, dpb); - MVOL_init(tdgbl->io_buffer_size); + uSvc->started(); int result; - tdgbl->uSvc->started(); switch (action) { case RESTORE: @@ -1478,7 +1474,7 @@ int gbak(Firebird::UtilSvc* uSvc) -void BURP_abort() +void BURP_abort(Firebird::IStatus* status) { /************************************** * @@ -1495,14 +1491,20 @@ void BURP_abort() // msg 351 Error closing database, but backup file is OK // msg 83 Exiting before completion due to errors - tdgbl->uSvc->setServiceStatus(burp_msg_fac, code, SafeArg()); - tdgbl->uSvc->started(); + // StatusAccessor is used only as RAII holder here + Firebird::UtilSvc::StatusAccessor sa = tdgbl->uSvc->getStatusAccessor(); - if (!tdgbl->uSvc->isService()) + if (status) + BURP_print_status(true, status, code); + else { - BURP_print(true, code); + sa.setServiceStatus(burp_msg_fac, code, SafeArg()); + + if (!tdgbl->uSvc->isService()) + BURP_print(true, code); } + tdgbl->uSvc->started(); BURP_exit_local(FINI_ERROR, tdgbl); } @@ -1519,8 +1521,10 @@ void BURP_error(USHORT errcode, bool abort, const SafeArg& arg) **************************************/ BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - tdgbl->uSvc->setServiceStatus(burp_msg_fac, errcode, arg); - tdgbl->uSvc->started(); + // StatusAccessor is used only as RAII holder here + Firebird::UtilSvc::StatusAccessor sa = tdgbl->uSvc->getStatusAccessor(); + + sa.setServiceStatus(burp_msg_fac, errcode, arg); if (!tdgbl->uSvc->isService()) { @@ -1529,9 +1533,9 @@ void BURP_error(USHORT errcode, bool abort, const SafeArg& arg) } if (abort) - { BURP_abort(); - } + else + tdgbl->uSvc->started(); } @@ -1565,6 +1569,9 @@ void BURP_error_redirect(Firebird::IStatus* status_vector, USHORT errcode, const * **************************************/ + // StatusAccessor is used only as RAII holder here + Firebird::UtilSvc::StatusAccessor sa = BurpGlobals::getSpecific()->uSvc->getStatusAccessor(); + BURP_print_status(true, status_vector); BURP_error(errcode, true, arg); } @@ -1699,7 +1706,7 @@ void BURP_print(bool err, USHORT number, const char* str) } -void BURP_print_status(bool err, Firebird::IStatus* status_vector) +void BURP_print_status(bool err, Firebird::IStatus* status_vector, USHORT secondNumber) { /************************************** * @@ -1715,11 +1722,13 @@ void BURP_print_status(bool err, Firebird::IStatus* status_vector) if (status_vector) { const ISC_STATUS* vector = status_vector->getErrors(); - if (err) { BurpGlobals* tdgbl = BurpGlobals::getSpecific(); - tdgbl->uSvc->setServiceStatus(vector); + Firebird::UtilSvc::StatusAccessor sa = tdgbl->uSvc->getStatusAccessor(); + sa.setServiceStatus(vector); + if (secondNumber) + sa.setServiceStatus(burp_msg_fac, secondNumber, SafeArg()); tdgbl->uSvc->started(); if (tdgbl->uSvc->isService()) @@ -1740,6 +1749,12 @@ void BURP_print_status(bool err, Firebird::IStatus* status_vector) burp_output(err, " %s\n", s); } } + + if (secondNumber) + { + BURP_msg_partial(err, 169); // msg 169: gbak: + BURP_msg_put(true, secondNumber, SafeArg()); + } } } diff --git a/src/burp/burp.h b/src/burp/burp.h index 184eeaba1a3..905bca01337 100644 --- a/src/burp/burp.h +++ b/src/burp/burp.h @@ -74,6 +74,8 @@ enum redirect_vals { NOOUTPUT = 2 }; +static const int burp_msg_fac = 12; + // Record types in backup file enum rec_type { @@ -252,8 +254,11 @@ enum att_type { att_SQL_dialect, // SQL dialect that it speaks att_db_read_only, // Is the database ReadOnly? att_database_linger, // Disconnection timeout - att_database_sql_security,// default sql security value + att_database_sql_security_deprecated, // can be removed later att_replica_mode, // replica mode + att_database_sql_security, // default sql security value + att_default_pub_active, // default publication status + att_default_pub_auto_enable, // Relation attributes @@ -275,6 +280,7 @@ enum att_type { att_relation_flags, att_relation_ext_file_name, // name of file for external tables att_relation_type, + att_relation_sql_security_deprecated, // can be removed later att_relation_sql_security, // Field attributes (used for both global and local fields) @@ -409,6 +415,7 @@ enum att_type { att_trig_engine_name, att_trig_entrypoint, att_trig_type2, + att_trig_sql_security_deprecated, // can be removed later att_trig_sql_security, // Function attributes @@ -433,6 +440,7 @@ enum att_type { att_function_owner_name, att_function_legacy_flag, att_function_deterministic_flag, + att_function_sql_security_deprecated, // can be removed later att_function_sql_security, // Function argument attributes @@ -529,6 +537,7 @@ enum att_type { att_procedure_entrypoint, att_procedure_package_name, att_procedure_private_flag, + att_procedure_sql_security_deprecated, // can be removed later att_procedure_sql_security, // Stored procedure parameter attributes @@ -630,6 +639,7 @@ enum att_type { att_package_security_class, att_package_owner_name, att_package_description, + att_package_sql_security_deprecated, // can be removed later att_package_sql_security, // Database creators @@ -948,6 +958,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool : ThreadData(ThreadData::tddGBL), GblPool(us->isService()), defaultCollations(getPool()), + systemFields(getPool()), uSvc(us), verboseInterval(10000), flag_on_line(true), @@ -1047,6 +1058,8 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool UCHAR* gbl_crypt_buffer; ULONG gbl_crypt_left; UCHAR* gbl_decompress; + bool gbl_default_pub_active = false; + bool gbl_default_pub_auto_enable = false; burp_rel* relations; burp_pkg* packages; @@ -1149,6 +1162,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool bool hdr_forced_writes; TEXT database_security_class[GDS_NAME_LEN]; // To save database security class for deferred update + unsigned batchInlineBlobLimit; static inline BurpGlobals* getSpecific() { @@ -1174,6 +1188,7 @@ class BurpGlobals : public Firebird::ThreadData, public GblPool Firebird::Array > > defaultCollations; + Firebird::SortedArray systemFields; Firebird::UtilSvc* uSvc; ULONG verboseInterval; // How many records should be backed up or restored before we show this message bool flag_on_line; // indicates whether we will bring the database on-line diff --git a/src/burp/burp_proto.h b/src/burp/burp_proto.h index 95f2d2c36af..393da083ccf 100644 --- a/src/burp/burp_proto.h +++ b/src/burp/burp_proto.h @@ -34,7 +34,7 @@ class BurpGlobals; int BURP_main(Firebird::UtilSvc*); int gbak(Firebird::UtilSvc*); -void BURP_abort(); +void BURP_abort(Firebird::IStatus* status = nullptr); void BURP_error(USHORT, bool, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); void BURP_error(USHORT, bool, const char* str); void BURP_error_redirect(Firebird::IStatus*, USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); @@ -46,7 +46,7 @@ void BURP_msg_get(USHORT, TEXT*, const MsgFormat::SafeArg& arg = MsgFormat::Safe void BURP_output_version(void*, const TEXT*); void BURP_print(bool err, USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); void BURP_print(bool err, USHORT, const char* str); -void BURP_print_status(bool err, Firebird::IStatus* status); +void BURP_print_status(bool err, Firebird::IStatus* status, USHORT secondNumber = 0); void BURP_print_warning(Firebird::IStatus* status); void BURP_verbose(USHORT, const MsgFormat::SafeArg& arg = MsgFormat::SafeArg()); void BURP_verbose(USHORT, const char* str); diff --git a/src/burp/mvol.cpp b/src/burp/mvol.cpp index a89744b0019..dff61424222 100644 --- a/src/burp/mvol.cpp +++ b/src/burp/mvol.cpp @@ -109,8 +109,6 @@ static inline void put(BurpGlobals* tdgbl, UCHAR c) static UCHAR debug_on = 0; // able to turn this on in debug mode #endif -const int burp_msg_fac = 12; - #ifdef HAVE_ZLIB_H static Firebird::InitInstance zlib; #endif // HAVE_ZLIB_H diff --git a/src/burp/restore.epp b/src/burp/restore.epp index d4a5698e202..7cc060385dc 100644 --- a/src/burp/restore.epp +++ b/src/burp/restore.epp @@ -61,6 +61,7 @@ #include "../auth/trusted/AuthSspi.h" #include "../common/dsc_proto.h" #include "../common/ThreadStart.h" +#include "../common/msg_encode.h" using MsgFormat::SafeArg; using Firebird::FbLocalStatus; @@ -71,8 +72,6 @@ using Firebird::FbLocalStatus; // GPRE. This is to avoid multiple threading problems with module // level statics. -DATABASE DB = STATIC FILENAME "yachts.lnk"; - #define DB tdgbl->db_handle #define fbTrans tdgbl->tr_handle #define gds_trans tdgbl->tr_handle @@ -80,6 +79,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk"; #define isc_status (&tdgbl->status_vector) #define gds_status (&tdgbl->status_vector) +// unused +#define fbProvider +#define fbStatus2 + +DATABASE DB = STATIC FILENAME "yachts.lnk"; + namespace // unnamed, private { @@ -93,8 +98,6 @@ const int DEFERRED_ACTIVE = 3; // RDB$INDEX_INACTIVE setting for Foreign Keys // -bsriram, 11-May-1999 BUG: 10016 -const int burp_msg_fac = 12; - enum scan_attr_t { NO_SKIP = 0, // Not in skipping and scanning mode @@ -118,7 +121,6 @@ void fix_security_class_name(BurpGlobals* tdgbl, TEXT* sec_class, bool is_field) bool get_acl(BurpGlobals* tdgbl, const TEXT*, ISC_QUAD*, ISC_QUAD*); void get_array(BurpGlobals* tdgbl, burp_rel*, UCHAR*); void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld*, UCHAR*); -void get_blob_old(BurpGlobals* tdgbl, const burp_fld*, UCHAR*); void get_blr_blob(BurpGlobals* tdgbl, ISC_QUAD&, bool); bool get_character_set(BurpGlobals* tdgbl); bool get_chk_constraint(BurpGlobals* tdgbl); @@ -193,8 +195,13 @@ static inline UCHAR get(BurpGlobals* tdgbl) return tdgbl->get(); } -static inline FB_BOOLEAN get_boolean(BurpGlobals* tdgbl) +static inline FB_BOOLEAN get_boolean(BurpGlobals* tdgbl, bool deprecated = false) { + if (!deprecated) + { + const UCHAR length = get(tdgbl); + fb_assert(length == 1); + } return get(tdgbl) ? FB_TRUE : FB_FALSE; } @@ -521,6 +528,40 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) MISC_release_request_silent(req_handle1); } + // If the default publication was backed up with non-default values, + // update the table accorgingly. + // NOTE: This change should be performed in the last transaction + // of the restore process, to avoid generating a replication stream + // before the database is restored successfully. + + if ((tdgbl->gbl_default_pub_active || tdgbl->gbl_default_pub_auto_enable) && + tdgbl->runtimeODS >= DB_VERSION_DDL12) + { + FOR (REQUEST_HANDLE req_handle1) + PUB IN RDB$PUBLICATIONS + WITH PUB.RDB$PUBLICATION_NAME EQ DEFAULT_PUBLICATION + { + fb_assert(PUB.RDB$SYSTEM_FLAG != 0); + + MODIFY PUB USING + PUB.RDB$ACTIVE_FLAG.NULL = FALSE; + PUB.RDB$ACTIVE_FLAG = tdgbl->gbl_default_pub_active ? 1 : 0; + + PUB.RDB$AUTO_ENABLE.NULL = FALSE; + PUB.RDB$AUTO_ENABLE = tdgbl->gbl_default_pub_auto_enable ? 1 : 0; + END_MODIFY; + ON_ERROR + general_on_error(); + END_ERROR; + } + END_FOR; + ON_ERROR + general_on_error(); + END_ERROR; + + MISC_release_request_silent(req_handle1); + } + // Add missing privileges fix_missing_privileges(tdgbl); @@ -581,10 +622,13 @@ int RESTORE_restore (const TEXT* file_name, const TEXT* database_name) if (!tdgbl->flag_on_line) { - BURP_print(false, 246); - // msg 246 Database is not online due to failure to activate one or more indices. - BURP_print(false, 247); - // msg 247 Run gfix -online to bring database online without active indices. + FbLocalStatus st; + (Firebird::Arg::Gds(ENCODE_ISC_MSG(246, burp_msg_fac)) << + // msg 246 Database is not online due to failure to activate one or more indices. + Firebird::Arg::Gds(ENCODE_ISC_MSG(247, burp_msg_fac))).copyTo(&st); + // msg 247 Run gfix -online to bring database online without active indices. + BURP_print_status(true, &st); + return FINI_DB_NOT_ONLINE; } @@ -1398,9 +1442,7 @@ void general_on_error() newVector.append(oldVector); newVector.copyTo(isc_status); } - BURP_print_status (true, isc_status); - - BURP_abort (); + BURP_abort (isc_status); } bool get_acl(BurpGlobals* tdgbl, const TEXT* owner_nm, ISC_QUAD* blob_id, ISC_QUAD* new_blob_id) @@ -1609,16 +1651,22 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) burp_fld* field = NULL; FbLocalStatus status_vector; USHORT count, field_number, field_length = 0; - UCHAR* buffer = NULL; + UCHAR** buffer = NULL; UCHAR* p = NULL; UCHAR blr_buffer[200]; // enough for a sdl with 16 dimensions lstring xdr_slice; - // don't free something you don't allocate lstring xdr_buffer; xdr_buffer.lstr_allocated = 0; xdr_buffer.lstr_address = NULL; + Firebird::Cleanup datClean( [&] { + if (buffer && *buffer) + BURP_free(*buffer); + if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated) + BURP_free(xdr_buffer.lstr_address); + } ); + // Pick up attributes SLONG fld_ranges[2 * MAX_DIMENSION]; SLONG slice_length = 0; @@ -1767,6 +1815,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) case blr_long: case blr_quad: case blr_int64: + case blr_int128: add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; @@ -1917,7 +1966,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) if (data_at == 0) { - buffer = BURP_alloc (return_length); SLONG lcount = 0; if (tdgbl->gbl_sw_transportable) { @@ -1932,19 +1980,23 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) lcount |= get(tdgbl) << 8; lcount |= get(tdgbl) << 16; lcount |= get(tdgbl) << 24; + xdr_buffer.lstr_length = xdr_buffer.lstr_allocated = lcount; - xdr_buffer.lstr_address = BURP_alloc(lcount); + p = xdr_buffer.lstr_address = BURP_alloc(lcount); + xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length; - xdr_slice.lstr_address = buffer; - p = xdr_buffer.lstr_address; + buffer = &xdr_slice.lstr_address; } } else { - p = buffer; + buffer = &p; lcount = return_length; } + fb_assert(buffer); + *buffer = BURP_alloc(return_length); + if (lcount) get_block(tdgbl, p, lcount); @@ -1954,7 +2006,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer, 0, NULL, // parameters for subset of an array handling - elements_written * field->fld_length, buffer + data_at); + elements_written * field->fld_length, (*buffer) + data_at); if (status_vector->hasData()) { BURP_print (false, 81, field->fld_name); @@ -1998,6 +2050,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) case blr_long: case blr_quad: case blr_int64: + case blr_int128: add_byte(blr, field->fld_type); add_byte(blr, field->fld_scale); break; @@ -2043,7 +2096,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) const USHORT blr_length = blr - blr_buffer; - buffer = BURP_alloc (return_length); SLONG lcount = 0; if (tdgbl->gbl_sw_transportable) { @@ -2059,18 +2111,21 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) xdr_buffer.lstr_allocated |= get(tdgbl) << 16; xdr_buffer.lstr_allocated |= get(tdgbl) << 24; lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated; - xdr_buffer.lstr_address = BURP_alloc (xdr_buffer.lstr_allocated); + p = xdr_buffer.lstr_address = BURP_alloc(xdr_buffer.lstr_allocated); + xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length; - xdr_slice.lstr_address = buffer; - p = xdr_buffer.lstr_address; + buffer = &xdr_slice.lstr_address; } } else { - p = buffer; + buffer = &p; lcount = return_length; } + fb_assert(buffer); + *buffer = BURP_alloc (return_length); + if (lcount) get_block(tdgbl, p, lcount); @@ -2080,7 +2135,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer, 0, NULL, // parameters for subset of an array handling - return_length, buffer); + return_length, *buffer); if (status_vector->hasData()) { BURP_print (false, 81, field->fld_name); @@ -2092,12 +2147,9 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer) return; } } - - BURP_free (buffer); - if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated) - BURP_free (xdr_buffer.lstr_address); } + void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld* fields, UCHAR* record_buffer) { /************************************** @@ -2163,145 +2215,90 @@ void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld* field // msg 36 Can't find field for blob } - // Create new blob - - ISC_QUAD* blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset); + // Choose blob creation method based on maximum possible blob size const UCHAR blob_desc[] = {isc_bpb_version1, isc_bpb_type, 1, blob_type}; - - BlobBuffer local_buffer; - UCHAR* const buffer = local_buffer.getBuffer(max_segment); - - FbLocalStatus status_vector; - bool first = true; - - // Eat up blob segments - - for (; segments > 0; --segments) - { - USHORT length = get(tdgbl); - length |= get(tdgbl) << 8; - if (length) - get_block(tdgbl, buffer, length); - - if (first) - batch->addBlob(&status_vector, length, buffer, blob_id, sizeof(blob_desc), blob_desc); - else - batch->appendBlobData(&status_vector, length, buffer); - - if (status_vector->hasData()) - { - BURP_error_redirect(&status_vector, 370); - // msg 370 could not append BLOB data to batch - } - - first = false; - } -} - - -void get_blob_old(BurpGlobals* tdgbl, const burp_fld* fields, UCHAR* record_buffer) -{ -/************************************** - * - * g e t _ b l o b - * - ************************************** - * - * Functional description - * Read blob attributes and copy data from input file to nice, - * shiny, new blob. - * - **************************************/ - - // Pick up attributes - - ULONG segments = 0; - USHORT field_number = MAX_USHORT; - USHORT max_segment = 0; - UCHAR blob_type = 0; - - att_type attribute; - scan_attr_t scan_next_attr; - skip_init(&scan_next_attr); - - while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data) + bool blobInline = false; + if (batch) { - switch (attribute) + ULONG segHeaderOverhead = 0; + if (!(blob_type & isc_bpb_type_stream)) { - case att_blob_field_number: - field_number = (USHORT) get_int32(tdgbl); - break; - - case att_blob_max_segment: - max_segment = (USHORT) get_int32(tdgbl); - break; - - case att_blob_number_segments: - segments = get_int32(tdgbl); - break; - - case att_blob_type: - blob_type = (UCHAR) get_int32(tdgbl); - break; - - default: - bad_attribute(scan_next_attr, attribute, 64); - // msg 64 blob - break; + // Is it segmented blob? header itself segment alignment + segHeaderOverhead = Firebird::IBatch::BLOB_SEGHDR_ALIGN + (Firebird::IBatch::BLOB_SEGHDR_ALIGN - 1); } - } + FB_UINT64 fullSize = (FB_UINT64(max_segment) + segHeaderOverhead) * segments; - // Find the field associated with the blob - const burp_fld* field; - for (field = fields; field; field = field->fld_next) - { - if (field->fld_number == field_number) - break; - } - - if (!field) - { - BURP_error_redirect(NULL, 36); - // msg 36 Can't find field for blob + // Take into an account parameters size + fullSize += sizeof(blob_desc); + blobInline = fullSize < tdgbl->batchInlineBlobLimit; } // Create new blob - ISC_QUAD* blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset); + BlobBuffer local_buffer; + UCHAR* const buffer = local_buffer.getBuffer(max_segment); + bool first = true; FbLocalStatus status_vector; BlobWrapper blob(&status_vector); - const UCHAR blob_desc[] = {isc_bpb_version1, isc_bpb_type, 1, blob_type}; - if (!blob.create(DB, gds_trans, *blob_id, sizeof(blob_desc), blob_desc)) + if (!blobInline) { - BURP_error_redirect(&status_vector, 37); - // msg 37 isc_create_blob failed + if (!blob.create(DB, gds_trans, *blob_id, sizeof(blob_desc), blob_desc)) + { + BURP_error_redirect(&status_vector, 37); + // msg 37 isc_create_blob failed + } } - // Allocate blob buffer if static buffer is too short - BlobBuffer static_buffer; - UCHAR* const buffer = static_buffer.getBuffer(max_segment); - // Eat up blob segments - for (; segments > 0; --segments ) + for (; segments > 0; --segments) { USHORT length = get(tdgbl); length |= get(tdgbl) << 8; if (length) - { get_block(tdgbl, buffer, length); + + if (blobInline) + { + if (first) + batch->addBlob(&status_vector, length, buffer, blob_id, sizeof(blob_desc), blob_desc); + else + batch->appendBlobData(&status_vector, length, buffer); + + if (status_vector->hasData()) + { + BURP_error_redirect(&status_vector, 370); + // msg 370 could not append BLOB data to batch + } } - if (!blob.putSegment(length, buffer)) + else if (!blob.putSegment(length, buffer)) { BURP_error_redirect(&status_vector, 38); // msg 38 isc_put_segment failed } + + first = false; } - if (!blob.close()) - BURP_error_redirect(&status_vector, 23); - // msg 23 isc_close_blob failed + if (!blobInline) + { + if (!blob.close()) + BURP_error_redirect(&status_vector, 23); + // msg 23 isc_close_blob failed + + if (batch) + { + ISC_QUAD real_id = *blob_id; + batch->registerBlob(&status_vector, &real_id, blob_id); + + if (status_vector->hasData()) + { + BURP_error_redirect(&status_vector, 370); + // msg 370 could not append BLOB data to batch + } + } + } } @@ -3016,6 +3013,12 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) if (tdgbl->gbl_network_protocol == 0) { + // If user relation uses system field there is a chance that definition of such + // system field was changed in target database. Old, BLR-based code, didn't + // coerce data types thus error could happen. To avoid it, let use SQL-based + // approach, while it is a bit slower in embedded mode. + // Here we are mostly interested in legacy UNICODE_FSS fields - see #7611. + bool sysDomFlag = false; for (field = relation->rel_fields; field && !sysDomFlag; field = field->fld_next) @@ -3023,21 +3026,10 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) if (field->fld_flags & FLD_computed) continue; - const char* dom = field->fld_source; - if (strncmp(dom, "RDB$", 4) != 0) - continue; - - for (dom += 4; *dom; ++dom) + if (tdgbl->systemFields.exist(field->fld_source)) { -#ifdef HAVE_CTYPE_H - if (!isdigit(*dom)) -#else - if (*dom < '0' || *dom > '9') -#endif - { - sysDomFlag = true; - break; - } + sysDomFlag = true; + break; } } @@ -3176,13 +3168,13 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) RCRD_LENGTH length = offset; // Create batch + unsigned batchStep = 1000; - const int GBAK_BATCH_STEP = 1000; Firebird::AutoDispose pb(Firebird::UtilInterfacePtr()-> getXpbBuilder(&tdgbl->throwStatus, Firebird::IXpbBuilder::BATCH, NULL, 0)); pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_MULTIERROR, 1); pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BLOB_POLICY, Firebird::IBatch::BLOB_ID_ENGINE); - pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_DETAILED_ERRORS, GBAK_BATCH_STEP); + pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_DETAILED_ERRORS, batchStep); pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BUFFER_BYTES_SIZE, 0); Firebird::RefPtr batch(Firebird::REF_NO_INCR, DB-> @@ -3198,6 +3190,58 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) return get_data_old(tdgbl, relation); } + // determine batch parameters + tdgbl->batchInlineBlobLimit = 0; + + const UCHAR items[] = + {Firebird::IBatch::INF_BUFFER_BYTES_SIZE, + Firebird::IBatch::INF_BLOB_ALIGNMENT, + Firebird::IBatch::INF_BLOB_HEADER}; + UCHAR infoBuf[64]; + batch->getInfo(fbStatus, sizeof items, items, sizeof infoBuf, infoBuf); + if (fbStatus->hasData()) + { + if (fbStatus->getErrors()[1] == isc_interface_version_too_old) // v4.0.0 + tdgbl->batchInlineBlobLimit = 255 * 1024; // 1Kb reserve should be always enough + else + BURP_error_redirect(fbStatus, 405); + } + + if (!tdgbl->batchInlineBlobLimit) + { + ULONG blAlign = 0, blHdr = 0, bufSize = 0; + Firebird::ClumpletReader rdr(Firebird::ClumpletReader::InfoResponse, infoBuf, sizeof infoBuf); + for (rdr.rewind(); !rdr.isEof(); rdr.moveNext()) + { + switch (rdr.getClumpTag()) + { + case Firebird::IBatch::INF_BUFFER_BYTES_SIZE: + bufSize = rdr.getInt(); + break; + case Firebird::IBatch::INF_BLOB_ALIGNMENT: + blAlign = rdr.getInt(); + break; + case Firebird::IBatch::INF_BLOB_HEADER: + blHdr = rdr.getInt(); + break; + } + } + + if (!(bufSize && blAlign && blHdr)) + BURP_error(405, true); + + // correct batchStep if necessary + unsigned msgSize = meta->getAlignedLength(&tdgbl->throwStatus); + if (msgSize * batchStep > bufSize) + batchStep = bufSize / msgSize; + + // determine maximum blob size for inline transfer + tdgbl->batchInlineBlobLimit = bufSize / batchStep; + // take into an account: blob alignment header size + tdgbl->batchInlineBlobLimit -= ((blAlign - 1) + blHdr); + } + fb_assert(tdgbl->batchInlineBlobLimit); + UCHAR* buffer = NULL; Firebird::Array requestBuffer; @@ -3206,8 +3250,13 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) lstring data; data.lstr_allocated = 0; data.lstr_address = NULL; - Firebird::Array dataBuffer; RCRD_LENGTH old_length = 0; + Firebird::Cleanup datClean( [&data] + { + if (data.lstr_address) + BURP_free(data.lstr_address); + } + ); Firebird::Array sqlBuffer; UCHAR* sql = sqlBuffer.getBuffer(meta->getMessageLength(&tdgbl->throwStatus)); @@ -3245,10 +3294,13 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) else { data.lstr_length = len = get_int32(tdgbl); + if (len > data.lstr_allocated) { data.lstr_allocated = len; - data.lstr_address = dataBuffer.getBuffer(data.lstr_allocated); + if (data.lstr_address) + BURP_free (data.lstr_address); + data.lstr_address = BURP_alloc(data.lstr_allocated); } p = data.lstr_address; } @@ -3314,7 +3366,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation) } batch->add(&tdgbl->throwStatus, 1, sql); - if ((records % 1000 != 0) && (record == rec_data)) + if ((records % batchStep != 0) && (record == rec_data)) continue; Firebird::AutoDispose cs(batch->execute(&tdgbl->throwStatus, gds_trans)); @@ -3736,15 +3788,22 @@ rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation) } BURP_free (blr_buffer); - SSHORT* buffer = NULL; BURP_verbose (124, relation->rel_name); // msg 124 restoring data for relation %s + SSHORT* buffer = NULL; lstring data; data.lstr_allocated = 0; data.lstr_address = NULL; - ULONG old_length = 0; + Firebird::Cleanup datClean( [&] { + if (buffer) + BURP_free(buffer); + if (data.lstr_address) + BURP_free(data.lstr_address); + } ); + + ULONG old_length = 0; FB_UINT64 records = 0; rec_type record; bool resync = false; @@ -3831,7 +3890,7 @@ rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation) while (record == rec_blob || record == rec_array) { if (record == rec_blob) - get_blob_old(tdgbl, relation->rel_fields, (UCHAR *) buffer); + get_blob(tdgbl, nullptr, relation->rel_fields, (UCHAR *) buffer); else if (record == rec_array) get_array(tdgbl, relation, (UCHAR *) buffer); get_record(&record, tdgbl); @@ -3895,10 +3954,6 @@ rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation) break; } // while (true) - BURP_free (buffer); - if (data.lstr_address) - BURP_free (data.lstr_address); - request = nullptr; if (tdgbl->gbl_sw_incremental) @@ -4962,6 +5017,7 @@ bool get_function(BurpGlobals* tdgbl) X.RDB$OWNER_NAME.NULL = TRUE; X.RDB$MODULE_NAME.NULL = TRUE; X.RDB$ENTRYPOINT.NULL = TRUE; + X.RDB$RETURN_ARGUMENT.NULL = TRUE; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$SYSTEM_FLAG = 0; @@ -5018,6 +5074,7 @@ bool get_function(BurpGlobals* tdgbl) break; case att_function_return_arg: + X.RDB$RETURN_ARGUMENT.NULL = FALSE; X.RDB$RETURN_ARGUMENT = (USHORT) get_int32(tdgbl); break; @@ -5143,10 +5200,11 @@ bool get_function(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 89); break; + case att_function_sql_security_deprecated: case att_function_sql_security: if (tdgbl->RESTORE_format >= 11) { - X.RDB$SQL_SECURITY = get_boolean(tdgbl); + X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_function_sql_security_deprecated); X.RDB$SQL_SECURITY.NULL = FALSE; } else @@ -5176,6 +5234,7 @@ bool get_function(BurpGlobals* tdgbl) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_req_handle1) X IN RDB$FUNCTIONS + X.RDB$RETURN_ARGUMENT.NULL = TRUE; X.RDB$SYSTEM_FLAG = 0; X.RDB$SYSTEM_FLAG.NULL = FALSE; X.RDB$DESCRIPTION.NULL = TRUE; @@ -5211,6 +5270,7 @@ bool get_function(BurpGlobals* tdgbl) break; case att_function_return_arg: + X.RDB$RETURN_ARGUMENT.NULL = FALSE; X.RDB$RETURN_ARGUMENT = (USHORT) get_int32(tdgbl); break; @@ -5275,9 +5335,10 @@ bool get_function(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 89); break; + case att_function_sql_security_deprecated: case att_function_sql_security: if (tdgbl->RESTORE_format >= 11) - get_boolean(tdgbl); + get_boolean(tdgbl, attribute == att_function_sql_security_deprecated); else bad_attribute(scan_next_attr, attribute, 89); break; @@ -5362,7 +5423,10 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_field_precision: - get_int32(tdgbl); + if (tdgbl->RESTORE_format >= 6) + get_int32(tdgbl); + else + bad_attribute(scan_next_attr, attribute, 90); break; case att_functionarg_package_name: @@ -5424,6 +5488,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1) X IN RDB$FUNCTION_ARGUMENTS + X.RDB$ARGUMENT_POSITION.NULL = TRUE; X.RDB$FIELD_SUB_TYPE.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; X.RDB$FIELD_PRECISION.NULL = TRUE; @@ -5467,6 +5532,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_position: + X.RDB$ARGUMENT_POSITION.NULL = FALSE; X.RDB$ARGUMENT_POSITION = (USHORT) get_int32(tdgbl); break; @@ -5634,6 +5700,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1) X IN RDB$FUNCTION_ARGUMENTS + X.RDB$ARGUMENT_POSITION.NULL = TRUE; X.RDB$FIELD_SUB_TYPE.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; X.RDB$FIELD_PRECISION.NULL = TRUE; @@ -5651,6 +5718,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_position: + X.RDB$ARGUMENT_POSITION.NULL = FALSE; X.RDB$ARGUMENT_POSITION = (USHORT) get_int32(tdgbl); break; @@ -5748,6 +5816,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) STORE (TRANSACTION_HANDLE local_trans REQUEST_HANDLE tdgbl->handles_get_function_arg_req_handle1) X IN RDB$FUNCTION_ARGUMENTS + X.RDB$ARGUMENT_POSITION.NULL = TRUE; X.RDB$FIELD_SUB_TYPE.NULL = TRUE; X.RDB$CHARACTER_SET_ID.NULL = TRUE; @@ -5764,6 +5833,7 @@ void get_function_arg(BurpGlobals* tdgbl, bool skip_arguments) break; case att_functionarg_position: + X.RDB$ARGUMENT_POSITION.NULL = FALSE; X.RDB$ARGUMENT_POSITION = (USHORT) get_int32(tdgbl); break; @@ -7418,10 +7488,11 @@ bool get_package(BurpGlobals* tdgbl) X.RDB$DESCRIPTION.NULL = FALSE; break; + case att_package_sql_security_deprecated: case att_package_sql_security: if (tdgbl->RESTORE_format >= 11) { - X.RDB$SQL_SECURITY = get_boolean(tdgbl); + X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_package_sql_security_deprecated); X.RDB$SQL_SECURITY.NULL = FALSE; } else @@ -7635,10 +7706,11 @@ bool get_procedure(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 290); break; + case att_procedure_sql_security_deprecated: case att_procedure_sql_security: if (tdgbl->RESTORE_format >= 11) { - X.RDB$SQL_SECURITY = get_boolean(tdgbl); + X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_procedure_sql_security_deprecated); X.RDB$SQL_SECURITY.NULL = FALSE; } else @@ -7760,9 +7832,10 @@ bool get_procedure(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 290); break; + case att_procedure_sql_security_deprecated: case att_procedure_sql_security: if (tdgbl->RESTORE_format >= 11) - get_boolean(tdgbl); + get_boolean(tdgbl, attribute == att_procedure_sql_security_deprecated); else bad_attribute(scan_next_attr, attribute, 290); break; @@ -8053,8 +8126,6 @@ bool get_publication(BurpGlobals* tdgbl) * **************************************/ att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT len; scan_attr_t scan_next_attr; if (tdgbl->runtimeODS >= DB_VERSION_DDL13) @@ -8152,8 +8223,6 @@ bool get_pub_table(BurpGlobals* tdgbl) * **************************************/ att_type attribute; - TEXT temp[GDS_NAME_LEN]; - SSHORT len; scan_attr_t scan_next_attr; if (tdgbl->runtimeODS >= DB_VERSION_DDL13) @@ -8444,9 +8513,10 @@ bool get_relation(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 111); break; + case att_relation_sql_security_deprecated: case att_relation_sql_security: sql_security_null = false; - sql_security = get_boolean(tdgbl); + sql_security = get_boolean(tdgbl, attribute == att_relation_sql_security_deprecated); break; default: @@ -8790,8 +8860,8 @@ bool get_sql_roles(BurpGlobals* tdgbl) X.RDB$ROLE_NAME.NULL = TRUE; X.RDB$OWNER_NAME.NULL = TRUE; X.RDB$DESCRIPTION.NULL = TRUE; + memset(X.RDB$SYSTEM_PRIVILEGES, 0, sizeof(X.RDB$SYSTEM_PRIVILEGES)); X.RDB$SYSTEM_FLAG = 0; - X.RDB$SYSTEM_FLAG.NULL = FALSE; skip_init(&scan_next_attr); while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) @@ -9785,10 +9855,11 @@ bool get_trigger(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 134); break; + case att_trig_sql_security_deprecated: case att_trig_sql_security: if (tdgbl->RESTORE_format >= 11) { - X.RDB$SQL_SECURITY = get_boolean(tdgbl); + X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_trig_sql_security_deprecated); X.RDB$SQL_SECURITY.NULL = FALSE; } else @@ -9931,9 +10002,10 @@ bool get_trigger(BurpGlobals* tdgbl) bad_attribute(scan_next_attr, attribute, 134); break; + case att_trig_sql_security_deprecated: case att_trig_sql_security: if (tdgbl->RESTORE_format >= 11) - get_boolean(tdgbl); + get_boolean(tdgbl, attribute == att_trig_sql_security_deprecated); else bad_attribute(scan_next_attr, attribute, 134); break; @@ -10227,6 +10299,8 @@ bool get_user_privilege(BurpGlobals* tdgbl) case att_priv_obj_type: flags |= USER_PRIV_OBJECT_TYPE; object_type = (USHORT) get_int32(tdgbl); + if ( (tdgbl->RESTORE_format < 11) && (object_type > 19) ) // FB 4 has a shift :( + object_type++; break; default: @@ -10298,9 +10372,6 @@ bool get_user_privilege(BurpGlobals* tdgbl) } break; - case obj_database: - break; - default: exists = true; break; @@ -10935,6 +11006,28 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file Firebird::IRequest* req_handle4 = nullptr; Firebird::IRequest* req_handle5 = nullptr; + // Collect system fields + { + Firebird::IRequest* req_handle = nullptr; + tdgbl->systemFields.setSortMode(Firebird::FB_ARRAY_SORT_MANUAL); + + FOR(REQUEST_HANDLE req_handle) + X IN RDB$FIELDS WITH + X.RDB$SYSTEM_FLAG EQ 1 + + const auto len = MISC_symbol_length(X.RDB$FIELD_NAME, sizeof(X.RDB$FIELD_NAME)); + Firebird::MetaString name(X.RDB$FIELD_NAME, len); + tdgbl->systemFields.add(name); + + END_FOR; + ON_ERROR + general_on_error(); + END_ERROR; + + MISC_release_request_silent(req_handle); + tdgbl->systemFields.sort(); + } + while (get_attribute(&attribute, tdgbl) != att_end) { switch (attribute) @@ -11010,6 +11103,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file } break; + case att_database_sql_security_deprecated: case att_database_sql_security: if (tdgbl->RESTORE_format >= 11) { @@ -11018,7 +11112,7 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file FOR (REQUEST_HANDLE req_handle5) X IN RDB$DATABASE MODIFY X USING - X.RDB$SQL_SECURITY = get_boolean(tdgbl); + X.RDB$SQL_SECURITY = get_boolean(tdgbl, attribute == att_database_sql_security_deprecated); END_MODIFY; ON_ERROR general_on_error(); @@ -11029,8 +11123,30 @@ bool restore(BurpGlobals* tdgbl, Firebird::IProvider* provider, const TEXT* file END_ERROR; } else - get_boolean(tdgbl); + get_boolean(tdgbl, attribute == att_database_sql_security_deprecated); + } + else + { + // Functions that use scan_next_attr initialize it to NO_SKIP using skip_init(). + // Here we don't use that logic, hence the first param to bad_attribute is hardcoded. + bad_attribute(NO_SKIP, attribute, 352); } + break; + + case att_default_pub_active: + if (tdgbl->RESTORE_format >= 11) + tdgbl->gbl_default_pub_active = get_boolean(tdgbl); + else + { + // Functions that use scan_next_attr initialize it to NO_SKIP using skip_init(). + // Here we don't use that logic, hence the first param to bad_attribute is hardcoded. + bad_attribute(NO_SKIP, attribute, 352); + } + break; + + case att_default_pub_auto_enable: + if (tdgbl->RESTORE_format >= 11) + tdgbl->gbl_default_pub_auto_enable = get_boolean(tdgbl); else { // Functions that use scan_next_attr initialize it to NO_SKIP using skip_init(). @@ -12093,3 +12209,4 @@ void fix_system_generators(BurpGlobals* tdgbl) } } // namespace + diff --git a/src/common/Int128.cpp b/src/common/Int128.cpp index d3158dddeb3..703bd85e6aa 100644 --- a/src/common/Int128.cpp +++ b/src/common/Int128.cpp @@ -42,6 +42,249 @@ using namespace Firebird; +#ifdef FB_USE_ABSEIL_INT128 + +namespace { + +const CInt128 i64max(MAX_SINT64), i64min(MIN_SINT64); +const double p2_32 = 4294967296.0; +const I128limit i128limit; +const CInt128 minus1(-1); + + +} // anonymous namespace + + +namespace Firebird { + +Int128 Int128::set(const char* value) +{ +// This is simplified method - it does not perform all what's needed for full conversion + for (v = 0; ; ++value) + { + if (*value < '0' or *value > '9') + break; + + v *= 10; + v += (*value - '0'); + } + + return *this; +} + +Int128 Int128::set(DecimalStatus decSt, Decimal128 value) +{ + static CDecimal128 quant(1); + value = value.quantize(decSt, quant); + + Decimal128::BCD bcd; + value.getBcd(&bcd); + fb_assert(bcd.exp == 0); + + v = 0; + for (unsigned b = 0; b < sizeof(bcd.bcd); ++b) + { + v *= 10; + v += bcd.bcd[b]; + } + if (bcd.sign < 0) + v = -v; + + return *this; +} + +void Int128::setScale(int scale) +{ + if (scale > 0) + { + int rem = 0; + while (scale--) + { + if (scale == 0) + rem = int(v % 10); + v /= 10; + } + + if (rem > 4) + v++; + else if (rem < -4) + v--; + } + else if (scale < 0) + { + while (scale++) { + if (v > i128limit.v || v < -i128limit.v) + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)).raise(); + v *= 10; + } + } +} + +void Int128::toString(int scale, unsigned length, char* to) const +{ + string buffer; + toString(scale, buffer); + if (buffer.length() + 1 > length) + { + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << + Arg::Gds(isc_trunc_limits) << Arg::Num(length) << Arg::Num(buffer.length() + 1)).raise(); + } + buffer.copyTo(to, length); +} + +void Int128::toString(int scale, string& to) const +{ + to.erase(); + absl::int128 vv = v; + + bool sgn = (vv < 0); + if (sgn) + vv = -vv; + + while (vv > 0) + { + int dig = int(vv % 10); + to.insert(string::size_type(0), string::size_type(1), char(dig + '0')); + vv /= 10; + } + + if (to.isEmpty()) + to = "0"; + + if (scale) + { + if (scale < -38 || scale > 4) + { + string tmp; + tmp.printf("E%d", scale); + to += tmp; + } + else if (scale > 0) + { + string tmp(scale, '0'); + to += tmp; + } + else + { + unsigned posScale = -scale; + if (posScale > to.length()) + { + string tmp(posScale - to.length(), '0'); + to.insert(0, tmp); + } + if (posScale == to.length()) + { + to.insert(0, "0."); + } + else + to.insert(to.length() - posScale, "."); + } + } + + if (sgn) + to.insert(0, "-"); +} + +Int128 Int128::abs() const +{ + if (compare(MIN_Int128) == 0) + overflow(); + + Int128 rc; + rc.v = v < 0 ? -v : v; + return rc; +} + +Int128 Int128::neg() const +{ + if (compare(MIN_Int128) == 0) + overflow(); + + Int128 rc; + rc.v = -v; + return rc; +} + +Int128 Int128::div(Int128 op2, int scale) const +{ + if (compare(MIN_Int128) == 0 && op2.compare(minus1) == 0) + Arg::Gds(isc_exception_integer_overflow).raise(); + + if (op2.v == 0) + zerodivide(); + + static const CInt128 MIN_BY10(MIN_Int128 / 10); + static const CInt128 MAX_BY10(MAX_Int128 / 10); + + // Scale op1 by as many of the needed powers of 10 as possible without an overflow. + Int128 op1(*this); + int sign1 = op1.sign(); + while ((scale < 0) && (sign1 >= 0 ? op1.compare(MAX_BY10) <= 0 : op1.compare(MIN_BY10) >= 0)) + { + op1.v *= 10; + ++scale; + } + + // Scale op2 shifting it to the right as long as only zeroes are thrown away. + while (scale < 0) + { + int rem = int(v % 10); + if (rem) + break; + op2.v /= 10; + ++scale; + } + + op1.v /= op2.v; + + op1.setScale(scale); + return op1; +} + +void Int128::zerodivide() +{ + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_divide_by_zero)).raise(); +} + +void Int128::overflow() +{ + (Arg::Gds(isc_arith_except) << Arg::Gds(isc_exception_integer_overflow)).raise(); +} + +#ifdef DEV_BUILD +const char* Int128::show() +{ + static char to[64]; + toString(0, sizeof(to), to); + return to; +} +#endif + +CInt128::CInt128(SINT64 value) +{ + set(value, 0); +} + +CInt128::CInt128(minmax mm) +{ + switch(mm) + { + case MkMax: + v = absl::Int128Max(); + break; + case MkMin: + v = absl::Int128Min(); + break; + } +} + +CInt128 MIN_Int128(CInt128::MkMin); +CInt128 MAX_Int128(CInt128::MkMax); + +} // namespace Firebird + +#else // FB_USE_ABSEIL_INT128 + namespace { const CInt128 i64max(MAX_SINT64), i64min(MIN_SINT64); @@ -76,7 +319,7 @@ Int128 Int128::set(SINT64 value, int scale) Int128 Int128::set(const char* value) { -// This is simplified method - it does not perform all what's needed for CVT_decompose +// This is simplified method - it does not perform all what's needed for full conversion v.FromString(value); return *this; } @@ -545,3 +788,6 @@ CInt128 MIN_Int128(CInt128::MkMin); CInt128 MAX_Int128(CInt128::MkMax); } // namespace Firebird + +#endif // FB_USE_ABSEIL_INT128 + diff --git a/src/common/Int128.h b/src/common/Int128.h index 5fde931ff98..509e33d1820 100644 --- a/src/common/Int128.h +++ b/src/common/Int128.h @@ -36,6 +36,313 @@ #include "classes/fb_string.h" +#ifdef FB_USE_ABSEIL_INT128 + +#include "absl/numeric/int128.h" + +namespace Firebird { + +class Decimal64; +class Decimal128; +struct DecimalStatus; + +class Int128 //: public Decimal128Base +{ +public: +#if SIZEOF_LONG < 8 + Int128 set(int value, int scale) + { + return set(SLONG(value), scale); + } +#endif + + Int128 set(SLONG value, int scale) + { + v = value; + setScale(scale); + return *this; + } + + Int128 set(SINT64 value, int scale) + { + v = value; + setScale(scale); + return *this; + } + + Int128 set(double value) + { + v = absl::int128(value); + return *this; + } + + Int128 set(DecimalStatus decSt, Decimal128 value); + + Int128 set(Int128 value) + { + v = value.v; + return *this; + } + + Int128 operator=(SINT64 value) + { + set(value, 0); + return *this; + } + +#ifdef DEV_BUILD + const char* show(); +#endif + + int toInteger(int scale) const + { + Int128 tmp(*this); + tmp.setScale(scale); + int rc = int(tmp.v); + if (tmp.v != rc) + overflow(); + return rc; + } + + SINT64 toInt64(int scale) const + { + Int128 tmp(*this); + tmp.setScale(scale); + SINT64 rc = SINT64(tmp.v); + if (tmp.v != rc) + overflow(); + return rc; + } + + void toString(int scale, unsigned length, char* to) const; + void toString(int scale, string& to) const; + + double toDouble() const + { + return double(v); + } + + Int128 operator&=(FB_UINT64 mask) + { + v &= mask; + return *this; + } + + Int128 operator&=(ULONG mask) + { + v &= mask; + return *this; + } + + Int128 operator-() const + { + Int128 rc; + rc.v = -v; + return rc; + } + + Int128 operator/(unsigned value) const + { + Int128 rc; + rc.v = v / value; + return rc; + } + + Int128 operator+=(unsigned value) + { + v += value; + return *this; + } + + Int128 operator-=(unsigned value) + { + v -= value; + return *this; + } + + Int128 operator*=(unsigned value) + { + v *= value; + return *this; + } + + Int128 operator<<(int value) const + { + Int128 rc; + rc.v = v << value; + return rc; + } + + Int128 operator>>(int value) const + { + Int128 rc; + rc.v = v >> value; + return rc; + } + + int compare(Int128 tgt) const + { + return v < tgt.v ? -1 : v > tgt.v ? 1 : 0; + } + + bool operator>(Int128 value) const + { + return v > value.v; + } + + bool operator>=(Int128 value) const + { + return v >= value.v; + } + + bool operator==(Int128 value) const + { + return v == value.v; + } + + bool operator!=(Int128 value) const + { + return v != value.v; + } + + Int128 operator&=(Int128 value) + { + v &= value.v; + return *this; + } + + Int128 operator|=(Int128 value) + { + v |= value.v; + return *this; + } + + Int128 operator^=(Int128 value) + { + v ^= value.v; + return *this; + } + + Int128 operator~() const + { + Int128 rc; + rc.v = ~v; + return rc; + } + + int sign() const + { + return v < 0 ? -1 : v == 0 ? 0 : 1; + } + + Int128 abs() const; + Int128 neg() const; + + Int128 add(Int128 op2) const + { + Int128 rc; + rc.v = v + op2.v; + + // see comment ArithmeticNode::add2() + if (sign() == op2.sign() && op2.sign() != rc.sign()) + overflow(); + + return rc; + } + + Int128 sub(Int128 op2) const + { + Int128 rc; + rc.v = v - op2.v; + + // see comment ArithmeticNode::add2() + if (sign() != op2.sign() && op2.sign() == rc.sign()) + overflow(); + + return rc; + } + + Int128 mul(Int128 op2) const + { + Int128 rc; + rc.v = v * op2.v; + + if (rc.v / v != op2.v) + overflow(); + + return rc; + } + + Int128 div(Int128 op2, int scale) const; + + Int128 mod(Int128 op2) const + { + if (op2.v == 0) + zerodivide(); + + Int128 rc; + rc.v = v % op2.v; + return rc; + } + + // returns internal data in per-32bit form + void getTable32(unsigned* dwords) const + { + absl::int128 vv = v; + for (int i = 0; i < 4; ++i) + { + dwords[i] = unsigned(vv); + vv >>= 32; + } + } + + void setScale(int scale); + + UCHAR* getBytes() + { + return (UCHAR*)(&v); + } + +protected: + absl::int128 v; + + static void overflow(); + static void zerodivide(); + + Int128 set(const char* value); +}; + +class CInt128 : public Int128 +{ +public: + enum minmax {MkMax, MkMin}; + + CInt128(SINT64 value); + CInt128(minmax mm); + CInt128(const Int128& value) + { + set(value); + } +}; + +extern CInt128 MAX_Int128, MIN_Int128; + +class I128limit : public Int128 +{ +public: + I128limit() + { + v = 1; + for (int i = 0; i < 126; ++i) + v *= 2; + v *= 5; + } +}; + +} // namespace Firebird + +#else // FB_USE_ABSEIL_INT128 + #include "../../extern/ttmath/ttmath.h" namespace Firebird { @@ -152,5 +459,6 @@ class I128limit : public Int128 } // namespace Firebird +#endif // FB_USE_ABSEIL_INT128 #endif // FB_INT128 diff --git a/src/common/IntlUtil.cpp b/src/common/IntlUtil.cpp index 1b8086b74f0..cbe32c5a046 100644 --- a/src/common/IntlUtil.cpp +++ b/src/common/IntlUtil.cpp @@ -601,7 +601,7 @@ ULONG IntlUtil::toLower(Jrd::CharSet* cs, ULONG srcLen, const UCHAR* src, ULONG Firebird::HalfStaticArray utf16_str; UCHAR* utf16_ptr; - if (dstLen >= utf16_length) // if dst buffer is sufficient large, use it as intermediate + if (dst != src && dstLen >= utf16_length) // if dst buffer is sufficient large, use it as intermediate utf16_ptr = dst; else utf16_ptr = utf16_str.getBuffer(utf16_length); @@ -627,7 +627,7 @@ ULONG IntlUtil::toUpper(Jrd::CharSet* cs, ULONG srcLen, const UCHAR* src, ULONG Firebird::HalfStaticArray utf16_str; UCHAR* utf16_ptr; - if (dstLen >= utf16_length) // if dst buffer is sufficient large, use it as intermediate + if (dst != src && dstLen >= utf16_length) // if dst buffer is sufficient large, use it as intermediate utf16_ptr = dst; else utf16_ptr = utf16_str.getBuffer(utf16_length); diff --git a/src/common/SimilarToRegex.cpp b/src/common/SimilarToRegex.cpp index 3a62b245e3f..dfd05725747 100644 --- a/src/common/SimilarToRegex.cpp +++ b/src/common/SimilarToRegex.cpp @@ -35,7 +35,9 @@ namespace UChar32 getChar(bool latin, const char* str, unsigned len, unsigned& pos) { - fb_assert(hasChar(len, pos)); + if (!hasChar(len, pos)) + status_exception::raise(Arg::Gds(isc_invalid_similar_pattern)); + UChar32 c; if (latin) @@ -108,7 +110,7 @@ namespace options.set_log_errors(false); options.set_dot_nl(true); options.set_case_sensitive(!(flags & COMP_FLAG_CASE_INSENSITIVE)); - options.set_utf8(!(flags & COMP_FLAG_LATIN)); + options.set_encoding(flags & COMP_FLAG_LATIN ? RE2::Options::EncodingLatin1 : RE2::Options::EncodingUTF8); re2::StringPiece sp((const char*) re2PatternStr.c_str(), re2PatternStr.length()); regexp = FB_NEW_POOL(pool) RE2(sp, options); @@ -759,7 +761,7 @@ namespace options.set_log_errors(false); options.set_dot_nl(true); options.set_case_sensitive(!(flags & COMP_FLAG_CASE_INSENSITIVE)); - options.set_utf8(!(flags & COMP_FLAG_LATIN)); + options.set_encoding(flags & COMP_FLAG_LATIN ? RE2::Options::EncodingLatin1 : RE2::Options::EncodingUTF8); re2::StringPiece sp((const char*) finalRe2Pattern.c_str(), finalRe2Pattern.length()); regexp = FB_NEW_POOL(pool) RE2(sp, options); diff --git a/src/common/StatusArg.cpp b/src/common/StatusArg.cpp index 6c6f9795587..3c920085678 100644 --- a/src/common/StatusArg.cpp +++ b/src/common/StatusArg.cpp @@ -212,6 +212,14 @@ void StatusVector::ImplStatusVector::append(const StatusVector& v) throw() void StatusVector::ImplStatusVector::prepend(const StatusVector& v) throw() { + auto errFrom = v.implementation->value(); + auto lenFrom = v.implementation->firstWarning() ? v.implementation->firstWarning() : v.implementation->length(); + auto errTo = value(); + auto lenTo = firstWarning() ? firstWarning() : length(); + + if (lenFrom < lenTo && fb_utils::cmpStatus(lenFrom, errFrom, errTo)) + return; // already here - ToDo: check warnings + ImplStatusVector newVector(getKind(), getCode()); if (newVector.appendErrors(v.implementation)) diff --git a/src/common/TextType.cpp b/src/common/TextType.cpp index ed16de3ba5d..b0fcefdbacf 100644 --- a/src/common/TextType.cpp +++ b/src/common/TextType.cpp @@ -364,12 +364,13 @@ ULONG TextType::canonical(ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* d ULONG utf16_len = getCharSet()->getConvToUnicode().convertLength(srcLen); + ULONG errPos; + // convert to UTF-16 utf16_len = getCharSet()->getConvToUnicode().convert(srcLen, src, - utf16_len, utf16_str.getBuffer(utf16_len)); + utf16_len, utf16_str.getBuffer(utf16_len), &errPos); USHORT errCode; - ULONG errPos; // convert UTF-16 to UTF-32 return UnicodeUtil::utf16ToUtf32(utf16_len, Firebird::Aligner(utf16_str.begin(), utf16_len), diff --git a/src/common/ThreadStart.cpp b/src/common/ThreadStart.cpp index 7100fe5fbbc..e54992ebefc 100644 --- a/src/common/ThreadStart.cpp +++ b/src/common/ThreadStart.cpp @@ -30,9 +30,9 @@ #include "firebird.h" #include #include +#include "../common/classes/alloc.h" #include "../common/ThreadStart.h" #include "../yvalve/gds_proto.h" -#include "../common/isc_s_proto.h" #include "../common/gdsassert.h" #ifdef WIN_NT @@ -210,12 +210,21 @@ void Thread::kill(Handle& thread) ThreadId Thread::getId() { #ifdef USE_LWP_AS_THREAD_ID - return syscall(SYS_gettid); + static __thread int tid = 0; + if (!tid) + tid = syscall(SYS_gettid); + return tid; #else return pthread_self(); #endif } +bool Thread::isCurrent(Handle threadHandle) +{ + static_assert(std::is_same().value, "type mismatch"); + return pthread_equal(threadHandle, pthread_self()); +} + bool Thread::isCurrent() { return pthread_equal(internalId, pthread_self()); @@ -360,6 +369,11 @@ ThreadId Thread::getId() return GetCurrentThreadId(); } +bool Thread::isCurrent(Handle threadHandle) +{ + return GetCurrentThreadId() == GetThreadId(threadHandle); +} + bool Thread::isCurrent() { return GetCurrentThreadId() == internalId; diff --git a/src/common/ThreadStart.h b/src/common/ThreadStart.h index cbedab06d25..98a68ba6f91 100644 --- a/src/common/ThreadStart.h +++ b/src/common/ThreadStart.h @@ -87,6 +87,7 @@ class Thread static void sleep(unsigned milliseconds); static void yield(); + static bool isCurrent(Handle threadHandle); bool isCurrent(); Thread() @@ -108,23 +109,14 @@ inline ThreadId getThreadId() } -#ifndef USE_POSIX_THREADS -#define USE_FINI_SEM -#endif - -template +template class ThreadFinishSync { public: typedef void ThreadRoutine(TA); ThreadFinishSync(Firebird::MemoryPool& pool, ThreadRoutine* routine, int priority_arg = THREAD_medium) - : -#ifdef USE_FINI_SEM - fini(pool), -#else - threadHandle(0), -#endif + : threadHandle(0), threadRoutine(routine), threadPriority(priority_arg), closing(false) @@ -133,12 +125,7 @@ class ThreadFinishSync void run(TA arg) { threadArg = arg; - - Thread::start(internalRun, this, threadPriority -#ifndef USE_FINI_SEM - , &threadHandle -#endif - ); + Thread::start(internalRun, this, threadPriority, &threadHandle); } bool tryWait() @@ -153,24 +140,15 @@ class ThreadFinishSync void waitForCompletion() { -#ifdef USE_FINI_SEM - fini.enter(); -#else if (threadHandle) { Thread::waitForCompletion(threadHandle); threadHandle = 0; } -#endif } private: -#ifdef USE_FINI_SEM - Firebird::Semaphore fini; -#else Thread::Handle threadHandle; -#endif - TA threadArg; ThreadRoutine* threadRoutine; int threadPriority; @@ -193,16 +171,8 @@ class ThreadFinishSync threadArg->exceptionHandler(ex, threadRoutine); } -#ifdef USE_FINI_SEM - try - { - fini.release(); - } - catch (const Firebird::Exception& ex) - { - threadArg->exceptionHandler(ex, threadRoutine); - } -#endif + if (cleanup) + cleanup(threadArg); closing = true; } }; diff --git a/src/common/TimeZoneUtil.cpp b/src/common/TimeZoneUtil.cpp index f80f63a7235..ee0a349f5af 100644 --- a/src/common/TimeZoneUtil.cpp +++ b/src/common/TimeZoneUtil.cpp @@ -45,10 +45,20 @@ namespace public: TimeZoneDesc(MemoryPool& pool) : asciiName(pool), - unicodeName(pool) + unicodeName(pool), + icuCachedCalendar(nullptr) { } + ~TimeZoneDesc() + { + if (const auto calendar = icuCachedCalendar.exchange(nullptr)) + { + auto& icuLib = Jrd::UnicodeUtil::getConversionICU(); + icuLib.ucalClose(calendar); + } + } + public: void setName(const char* name) { @@ -70,9 +80,21 @@ namespace return unicodeName.begin(); } + IcuCalendarWrapper getCalendar(const Jrd::UnicodeUtil::ConversionICU& icuLib, UErrorCode* err = nullptr) const + { + auto calendar = icuCachedCalendar.exchange(nullptr); + UErrorCode internalErr = U_ZERO_ERROR; + + if (!calendar) + calendar = icuLib.ucalOpen(getUnicodeName(), -1, nullptr, UCAL_GREGORIAN, (err ? err : &internalErr)); + + return IcuCalendarWrapper(calendar, &icuCachedCalendar); + } + private: string asciiName; Array unicodeName; + mutable std::atomic icuCachedCalendar; }; } @@ -588,8 +610,7 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* of Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU(); - UCalendar* icuCalendar = icuLib.ucalOpen( - getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode); + auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode); if (!icuCalendar) status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open."); @@ -597,21 +618,13 @@ void TimeZoneUtil::extractOffset(const ISC_TIMESTAMP_TZ& timeStampTz, SSHORT* of icuLib.ucalSetMillis(icuCalendar, timeStampToIcuDate(timeStampTz.utc_timestamp), &icuErrorCode); if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis."); - } displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) + icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE; if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get."); - } - - icuLib.ucalClose(icuCalendar); } *offset = displacement; @@ -683,8 +696,7 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz) Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU(); - UCalendar* icuCalendar = icuLib.ucalOpen( - getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode); + auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode); if (!icuCalendar) status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open."); @@ -696,21 +708,13 @@ void TimeZoneUtil::localTimeStampToUtc(ISC_TIMESTAMP_TZ& timeStampTz) times.tm_hour, times.tm_min, times.tm_sec, &icuErrorCode); if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setDateTime."); - } displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) + icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE; if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get."); - } - - icuLib.ucalClose(icuCalendar); } const auto ticks = TimeStamp::timeStampToTicks(timeStampTz.utc_timestamp) - @@ -752,8 +756,7 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt #endif Jrd::UnicodeUtil::ConversionICU& icuLib = Jrd::UnicodeUtil::getConversionICU(); - UCalendar* icuCalendar = icuLib.ucalOpen( - getDesc(timeStampTz.time_zone)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode); + auto icuCalendar = getDesc(timeStampTz.time_zone)->getCalendar(icuLib, &icuErrorCode); if (!icuCalendar) status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open."); @@ -761,21 +764,13 @@ bool TimeZoneUtil::decodeTimeStamp(const ISC_TIMESTAMP_TZ& timeStampTz, bool gmt icuLib.ucalSetMillis(icuCalendar, timeStampToIcuDate(timeStampTz.utc_timestamp), &icuErrorCode); if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_setMillis."); - } displacement = (icuLib.ucalGet(icuCalendar, UCAL_ZONE_OFFSET, &icuErrorCode) + icuLib.ucalGet(icuCalendar, UCAL_DST_OFFSET, &icuErrorCode)) / U_MILLIS_PER_MINUTE; if (U_FAILURE(icuErrorCode)) - { - icuLib.ucalClose(icuCalendar); status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_get."); - } - - icuLib.ucalClose(icuCalendar); } catch (const Exception&) { @@ -1044,12 +1039,11 @@ ISC_TIMESTAMP_TZ TimeZoneUtil::dateToTimeStampTz(const ISC_DATE& date, Callbacks TimeZoneRuleIterator::TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& aFrom, const ISC_TIMESTAMP_TZ& aTo) : id(aId), icuLib(Jrd::UnicodeUtil::getConversionICU()), - toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp)) + toTicks(TimeStamp::timeStampToTicks(aTo.utc_timestamp)), + icuCalendar(getDesc(aId)->getCalendar(icuLib)) { UErrorCode icuErrorCode = U_ZERO_ERROR; - icuCalendar = icuLib.ucalOpen(getDesc(id)->getUnicodeName(), -1, NULL, UCAL_GREGORIAN, &icuErrorCode); - if (!icuCalendar) status_exception::raise(Arg::Gds(isc_random) << "Error calling ICU's ucal_open."); @@ -1086,11 +1080,6 @@ TimeZoneRuleIterator::TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& a startTicks = TimeStamp::timeStampToTicks(TimeZoneUtil::icuDateToTimeStamp(icuDate)); } -TimeZoneRuleIterator::~TimeZoneRuleIterator() -{ - icuLib.ucalClose(icuCalendar); -} - bool TimeZoneRuleIterator::next() { if (startTicks > toTicks) @@ -1114,7 +1103,10 @@ bool TimeZoneRuleIterator::next() } if (!hasNext || icuDate > MAX_ICU_TIMESTAMP) + { icuDate = MAX_ICU_TIMESTAMP; + hasNext = false; + } icuLib.ucalSetMillis(icuCalendar, icuDate, &icuErrorCode); @@ -1124,7 +1116,7 @@ bool TimeZoneRuleIterator::next() (icuDate == MAX_ICU_TIMESTAMP ? ISC_TIME_SECONDS_PRECISION / 1000 : 0)); endTimestamp.time_zone = TimeZoneUtil::GMT_ZONE; - startTicks = endTicks + 1; + startTicks = (hasNext ? endTicks : toTicks) + 1; return true; } diff --git a/src/common/TimeZoneUtil.h b/src/common/TimeZoneUtil.h index f9b20ca0990..0c162607290 100644 --- a/src/common/TimeZoneUtil.h +++ b/src/common/TimeZoneUtil.h @@ -27,6 +27,7 @@ #ifndef COMMON_TIME_ZONE_UTIL_H #define COMMON_TIME_ZONE_UTIL_H +#include #include #include "../common/classes/fb_string.h" #include "../common/classes/timestamp.h" @@ -133,11 +134,63 @@ class TimeZoneUtil static ISC_TIMESTAMP_TZ dateToTimeStampTz(const ISC_DATE& date, Callbacks* cb); }; +class IcuCalendarWrapper +{ +public: + IcuCalendarWrapper(UCalendar* aWrapped, std::atomic* aCachePtr) + : wrapped(aWrapped), + cachePtr(aCachePtr) + {} + + IcuCalendarWrapper(IcuCalendarWrapper&& o) + : wrapped(o.wrapped), + cachePtr(o.cachePtr) + { + o.wrapped = nullptr; + } + + ~IcuCalendarWrapper() + { + if (wrapped) + { + auto newCached = cachePtr->exchange(wrapped); + + if (newCached) + { + auto& icuLib = Jrd::UnicodeUtil::getConversionICU(); + icuLib.ucalClose(newCached); + } + } + } + + IcuCalendarWrapper(const IcuCalendarWrapper&) = delete; + IcuCalendarWrapper& operator=(const IcuCalendarWrapper&) = delete; + +public: + UCalendar* operator->() + { + return wrapped; + } + + operator UCalendar*() + { + return wrapped; + } + + bool operator!() const + { + return !wrapped; + } + +private: + UCalendar* wrapped; + std::atomic* cachePtr; +}; + class TimeZoneRuleIterator { public: TimeZoneRuleIterator(USHORT aId, const ISC_TIMESTAMP_TZ& aFrom, const ISC_TIMESTAMP_TZ& aTo); - ~TimeZoneRuleIterator(); public: bool next(); @@ -153,7 +206,7 @@ class TimeZoneRuleIterator Jrd::UnicodeUtil::ConversionICU& icuLib; SINT64 startTicks; SINT64 toTicks; - UCalendar* icuCalendar; + IcuCalendarWrapper icuCalendar; UDate icuDate; }; diff --git a/src/common/TimeZones.h b/src/common/TimeZones.h index 3ff8fa1f5d0..655f213c94d 100644 --- a/src/common/TimeZones.h +++ b/src/common/TimeZones.h @@ -1,6 +1,6 @@ // The content of this file is generated with help of update-ids utility Do not edit. -static const char* BUILTIN_TIME_ZONE_VERSION = "2021a"; +static const char* BUILTIN_TIME_ZONE_VERSION = "2025b"; // Do not change order of items in this array! The index corresponds to a TimeZone ID, which must be fixed! static const char* BUILTIN_TIME_ZONE_LIST[] = { @@ -637,5 +637,9 @@ static const char* BUILTIN_TIME_ZONE_LIST[] = { "WET", // fb_tzid_wet - 64905 "Zulu", // fb_tzid_zulu - 64904 "America/Nuuk", // fb_tzid_america_nuuk - 64903 - "Asia/Qostanay" // fb_tzid_asia_qostanay - 64902 + "Asia/Qostanay", // fb_tzid_asia_qostanay - 64902 + "Pacific/Kanton", // fb_tzid_pacific_kanton - 64901 + "Europe/Kyiv", // fb_tzid_europe_kyiv - 64900 + "America/Ciudad_Juarez", // fb_tzid_america_ciudad_juarez - 64899 + "America/Coyhaique" // fb_tzid_america_coyhaique - 64898 }; diff --git a/src/common/UtilSvc.cpp b/src/common/UtilSvc.cpp index a916a2164a9..599c283b9d0 100644 --- a/src/common/UtilSvc.cpp +++ b/src/common/UtilSvc.cpp @@ -56,6 +56,7 @@ namespace { void outputFile(FILE* std, const char* text) { outputFile(std, text, strlen(text)); + fflush(std); } } @@ -70,23 +71,23 @@ class StandaloneUtilityInterface : public UtilSvc } } - void outputVerbose(const char* text) + void outputVerbose(const char* text) override { outputFile(usvcDataMode ? stderr : stdout, text); } - void outputError(const char* text) + void outputError(const char* text) override { outputFile(stderr, text); } - void outputData(const void* data, FB_SIZE_T size) + void outputData(const void* data, FB_SIZE_T size) override { fb_assert(usvcDataMode); outputFile(stdout, data, size); } - virtual void printf(bool err, const SCHAR* format, ...) + void printf(bool err, const SCHAR* format, ...) override { va_list arglist; va_start(arglist, format); @@ -99,7 +100,7 @@ class StandaloneUtilityInterface : public UtilSvc } } - virtual void hidePasswd(ArgvType& argv, int pos) + void hidePasswd(ArgvType& argv, int pos) override { const size_t l = strlen(argv[pos]); char* data = FB_NEW_POOL(getPool()) char[l + 1]; @@ -113,17 +114,17 @@ class StandaloneUtilityInterface : public UtilSvc memset(hide, '*', l); } - virtual bool isService() + bool isService() override { return false; } - virtual void checkService() + void checkService() override { status_exception::raise(Arg::Gds(isc_utl_trusted_switch)); } - virtual unsigned int getAuthBlock(const unsigned char** bytes) + unsigned int getAuthBlock(const unsigned char** bytes) override { // Utility has no auth block *bytes = NULL; @@ -131,21 +132,20 @@ class StandaloneUtilityInterface : public UtilSvc } // do nothing for non-service - virtual void started() { } - virtual void putLine(char, const char*) { } - virtual void putSLong(char, SLONG) { } - virtual void putSInt64(char, SINT64) { } - virtual void putChar(char, char) { } - virtual void putBytes(const UCHAR*, FB_SIZE_T) { } - virtual ULONG getBytes(UCHAR*, ULONG) { return 0; } - virtual void setServiceStatus(const ISC_STATUS*) { } - virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) { } - virtual const Firebird::CheckStatusWrapper* getStatus() { return NULL; } - virtual void fillDpb(ClumpletWriter&) { } - virtual bool finished() { return false; } - virtual void initStatus() { } - virtual bool utf8FileNames() { return false; } - virtual Firebird::ICryptKeyCallback* getCryptCallback() { return NULL; } + void started() override { } + void putLine(char, const char*) override { } + void putSLong(char, SLONG) override { } + void putSInt64(char, SINT64) override { } + void putChar(char, char) override { } + void putBytes(const UCHAR*, FB_SIZE_T) override { } + ULONG getBytes(UCHAR*, ULONG) override { return 0; } + void setServiceStatus(const ISC_STATUS*) override { } + void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) override { } + StatusAccessor getStatusAccessor() override { return StatusAccessor(); } + void fillDpb(ClumpletWriter&) override { } + bool finished() override { return false; } + bool utf8FileNames() override { return false; } + Firebird::ICryptKeyCallback* getCryptCallback() override { return NULL; } }; diff --git a/src/common/UtilSvc.h b/src/common/UtilSvc.h index 72f607fe4ae..58169b3275c 100644 --- a/src/common/UtilSvc.h +++ b/src/common/UtilSvc.h @@ -51,6 +51,72 @@ class UtilSvc : public Firebird::GlobalStorage public: typedef Firebird::HalfStaticArray ArgvType; + // Services is rare for our code case where status vector is accessed from 2 different threads + // in async way. To ensure it's stability appropriate protection is needed. + class StatusAccessor + { + public: + StatusAccessor(Mutex& mtx, Firebird::CheckStatusWrapper* st, UtilSvc* u) + : mutex(&mtx), status(st), uSvc(u) + { + mutex->enter(FB_FUNCTION); + } + + StatusAccessor() + : mutex(nullptr), status(nullptr), uSvc(nullptr) + { } + + StatusAccessor(StatusAccessor&& sa) + : mutex(sa.mutex), status(sa.status), uSvc(sa.uSvc) + { + sa.mutex = nullptr; + sa.uSvc = nullptr; + sa.status = nullptr; + } + + operator const Firebird::CheckStatusWrapper*() const + { + return status; + } + + const Firebird::CheckStatusWrapper* operator->() const + { + return status; + } + + void init() + { + if (status) + status->init(); + } + + void setServiceStatus(const ISC_STATUS* status) + { + if (uSvc) + uSvc->setServiceStatus(status); + } + + void setServiceStatus(const USHORT fac, const USHORT code, const MsgFormat::SafeArg& args) + { + if (uSvc) + uSvc->setServiceStatus(fac, code, args); + } + + ~StatusAccessor() + { + if (mutex) + mutex->leave(); + } + + StatusAccessor(const StatusAccessor&) = delete; + StatusAccessor& operator=(const StatusAccessor&) = delete; + + private: + Mutex* mutex; + Firebird::CheckStatusWrapper* status; + UtilSvc* uSvc; + }; + public: UtilSvc() : argv(getPool()), usvcDataMode(false) { } @@ -66,10 +132,13 @@ class UtilSvc : public Firebird::GlobalStorage virtual void putChar(char, char) = 0; virtual void putBytes(const UCHAR*, FB_SIZE_T) = 0; virtual ULONG getBytes(UCHAR*, ULONG) = 0; + +private: virtual void setServiceStatus(const ISC_STATUS*) = 0; virtual void setServiceStatus(const USHORT, const USHORT, const MsgFormat::SafeArg&) = 0; - virtual const Firebird::CheckStatusWrapper* getStatus() = 0; - virtual void initStatus() = 0; + +public: + virtual StatusAccessor getStatusAccessor() = 0; virtual void checkService() = 0; virtual void hidePasswd(ArgvType&, int) = 0; virtual void fillDpb(Firebird::ClumpletWriter& dpb) = 0; diff --git a/src/common/classes/ClumpletReader.cpp b/src/common/classes/ClumpletReader.cpp index 50385bd1372..ab340128bc8 100644 --- a/src/common/classes/ClumpletReader.cpp +++ b/src/common/classes/ClumpletReader.cpp @@ -242,6 +242,7 @@ UCHAR ClumpletReader::getBufferTag() const case SpbReceiveItems: case SpbResponse: case InfoResponse: + case InfoItems: usage_mistake("buffer is not tagged"); return 0; case SpbAttach: @@ -313,6 +314,7 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const } return StringSpb; case SpbReceiveItems: + case InfoItems: return SingleTpb; case SpbStart: switch(tag) @@ -454,7 +456,11 @@ ClumpletReader::ClumpletType ClumpletReader::getClumpletType(UCHAR tag) const return StringSpb; case isc_spb_nbk_level: case isc_spb_options: + case isc_spb_nbk_keep_days: + case isc_spb_nbk_keep_rows: return IntSpb; + case isc_spb_nbk_clean_history: + return SingleTpb; } invalid_structure("unknown parameter for nbackup", tag); break; @@ -682,6 +688,20 @@ void ClumpletReader::moveNext() { if (isEof()) return; // no need to raise useless exceptions + + switch (kind) + { + case InfoResponse: + switch (getClumpTag()) + { + case isc_info_end: + case isc_info_truncated: + // terminating clumplet + cur_offset = getBufferLength(); + return; + } + } + FB_SIZE_T cs = getClumpletSize(true, true, true); adjustSpbState(); cur_offset += cs; @@ -704,6 +724,7 @@ void ClumpletReader::rewind() case SpbReceiveItems: case SpbResponse: case InfoResponse: + case InfoItems: cur_offset = 0; break; default: diff --git a/src/common/classes/ClumpletReader.h b/src/common/classes/ClumpletReader.h index b8861631118..a9be7202cb5 100644 --- a/src/common/classes/ClumpletReader.h +++ b/src/common/classes/ClumpletReader.h @@ -58,7 +58,8 @@ class ClumpletReader : protected AutoStorage SpbSendItems, SpbReceiveItems, SpbResponse, - InfoResponse + InfoResponse, + InfoItems }; struct KindList @@ -132,7 +133,7 @@ class ClumpletReader : protected AutoStorage if (rc == 1 && kind != UnTagged && kind != SpbStart && kind != WideUnTagged && kind != SpbSendItems && kind != SpbReceiveItems && kind != SpbResponse && - kind != InfoResponse) + kind != InfoResponse && kind != InfoItems) { rc = 0; } diff --git a/src/common/classes/ClumpletWriter.cpp b/src/common/classes/ClumpletWriter.cpp index 091c9884865..e03b154b69a 100644 --- a/src/common/classes/ClumpletWriter.cpp +++ b/src/common/classes/ClumpletWriter.cpp @@ -36,15 +36,23 @@ namespace Firebird { -ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, UCHAR tag) : - ClumpletReader(k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool()) +ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, UCHAR tag) + : ClumpletReader(k, NULL, 0), + sizeLimit(limit), + kindList(NULL), + dynamic_buffer(getPool()), + flag_overflow(false) { initNewBuffer(tag); rewind(); } -ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit, UCHAR tag) : - ClumpletReader(given_pool, k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool()) +ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit, UCHAR tag) + : ClumpletReader(given_pool, k, NULL, 0), + sizeLimit(limit), + kindList(NULL), + dynamic_buffer(getPool()), + flag_overflow(false) { initNewBuffer(tag); rewind(); @@ -82,46 +90,72 @@ void ClumpletWriter::initNewBuffer(UCHAR tag) } ClumpletWriter::ClumpletWriter(Kind k, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag) - : ClumpletReader(k, NULL, 0), sizeLimit(limit), kindList(NULL), dynamic_buffer(getPool()) + : ClumpletReader(k, NULL, 0), + sizeLimit(limit), + kindList(NULL), + dynamic_buffer(getPool()), + flag_overflow(false) { create(buffer, buffLen, tag); } ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen) - : ClumpletReader(pool, kl, buffer, buffLen), sizeLimit(limit), - kindList(kl), dynamic_buffer(getPool()) + : ClumpletReader(pool, kl, buffer, buffLen), + sizeLimit(limit), + kindList(kl), + dynamic_buffer(getPool()), + flag_overflow(false) { create(buffer, buffLen, kl->tag); } ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit, const UCHAR* buffer, FB_SIZE_T buffLen) - : ClumpletReader(kl, buffer, buffLen), sizeLimit(limit), kindList(kl), dynamic_buffer(getPool()) + : ClumpletReader(kl, buffer, buffLen), + sizeLimit(limit), + kindList(kl), + dynamic_buffer(getPool()), + flag_overflow(false) { create(buffer, buffLen, kl->tag); } ClumpletWriter::ClumpletWriter(MemoryPool& pool, const KindList* kl, FB_SIZE_T limit) - : ClumpletReader(pool, kl, NULL, 0), sizeLimit(limit), - kindList(kl), dynamic_buffer(getPool()) + : ClumpletReader(pool, kl, NULL, 0), + sizeLimit(limit), + kindList(kl), + dynamic_buffer(getPool()), + flag_overflow(false) { create(NULL, 0, kl->tag); } ClumpletWriter::ClumpletWriter(const KindList* kl, FB_SIZE_T limit) - : ClumpletReader(kl, NULL, 0), sizeLimit(limit), kindList(kl), dynamic_buffer(getPool()) + : ClumpletReader(kl, NULL, 0), + sizeLimit(limit), + kindList(kl), + dynamic_buffer(getPool()), + flag_overflow(false) { create(NULL, 0, kl->tag); } ClumpletWriter::ClumpletWriter(MemoryPool& pool, const ClumpletWriter& from) - : ClumpletReader(pool, from), sizeLimit(from.sizeLimit), kindList(NULL), dynamic_buffer(getPool()) + : ClumpletReader(pool, from), + sizeLimit(from.sizeLimit), + kindList(NULL), + dynamic_buffer(getPool()), + flag_overflow(false) { create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0); } ClumpletWriter::ClumpletWriter(const ClumpletWriter& from) - : ClumpletReader(from), sizeLimit(from.sizeLimit), kindList(NULL), dynamic_buffer(getPool()) + : ClumpletReader(from), + sizeLimit(from.sizeLimit), + kindList(NULL), + dynamic_buffer(getPool()), + flag_overflow(false) { create(from.getBuffer(), from.getBufferEnd() - from.getBuffer(), from.isTagged() ? from.getBufferTag() : 0); } @@ -138,8 +172,11 @@ void ClumpletWriter::create(const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag) } ClumpletWriter::ClumpletWriter(MemoryPool& given_pool, Kind k, FB_SIZE_T limit, - const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag) : - ClumpletReader(given_pool, k, NULL, 0), sizeLimit(limit), dynamic_buffer(getPool()) + const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag) + : ClumpletReader(given_pool, k, NULL, 0), + sizeLimit(limit), + dynamic_buffer(getPool()), + flag_overflow(false) { if (buffer && buffLen) { dynamic_buffer.push(buffer, buffLen); @@ -189,11 +226,23 @@ void ClumpletWriter::reset(const UCHAR* buffer, const FB_SIZE_T buffLen) rewind(); } +void ClumpletWriter::reset(const ClumpletWriter& from) +{ + reset(from.getBuffer(), from.getBufferEnd() - from.getBuffer()); +} + void ClumpletWriter::size_overflow() { fatal_exception::raise("Clumplet buffer size limit reached"); } +void ClumpletWriter::size_overflow(bool condition) +{ + flag_overflow = condition; + if (condition) + size_overflow(); +} + void ClumpletWriter::toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value) { fb_assert(ptr && length > 0 && length < 9); // We can't handle numbers bigger than int64. @@ -362,9 +411,7 @@ void ClumpletWriter::insertBytesLengthCheck(UCHAR tag, const void* bytes, const } // Check that resulting data doesn't overflow size limit - if (dynamic_buffer.getCount() + length + lenSize + 1 > sizeLimit) { - size_overflow(); - } + size_overflow(dynamic_buffer.getCount() + length + lenSize + 1 > sizeLimit); // Insert the data const FB_SIZE_T saved_offset = cur_offset; @@ -415,9 +462,7 @@ void ClumpletWriter::insertEndMarker(UCHAR tag) } // Check that resulting data doesn't overflow size limit - if (cur_offset + 1 > sizeLimit) { - size_overflow(); - } + size_overflow(cur_offset + 1 > sizeLimit); dynamic_buffer.shrink(cur_offset); dynamic_buffer.push(tag); diff --git a/src/common/classes/ClumpletWriter.h b/src/common/classes/ClumpletWriter.h index cd33b21bba7..75dd9c3808e 100644 --- a/src/common/classes/ClumpletWriter.h +++ b/src/common/classes/ClumpletWriter.h @@ -66,6 +66,7 @@ class ClumpletWriter : public ClumpletReader void reset(UCHAR tag = 0); void reset(const UCHAR* buffer, const FB_SIZE_T buffLen); + void reset(const ClumpletWriter& from); void clear(); // Methods to create new clumplet at current position @@ -98,10 +99,14 @@ class ClumpletWriter : public ClumpletReader // Returns true if any found bool deleteWithTag(UCHAR tag); - virtual const UCHAR* getBuffer() const; + const UCHAR* getBuffer() const override; + bool hasOverflow() const + { + return flag_overflow; + } protected: - virtual const UCHAR* getBufferEnd() const; + const UCHAR* getBufferEnd() const override; virtual void size_overflow(); void insertBytesLengthCheck(UCHAR tag, const void* bytes, const FB_SIZE_T length); bool upgradeVersion(); // upgrade clumplet version - obtain newest from kindList @@ -117,14 +122,10 @@ class ClumpletWriter : public ClumpletReader void initNewBuffer(UCHAR tag); void create(const UCHAR* buffer, FB_SIZE_T buffLen, UCHAR tag); static void toVaxInteger(UCHAR* ptr, FB_SIZE_T length, const SINT64 value); + + void size_overflow(bool condition); + bool flag_overflow; }; -/* -template <> -void ClumpletWriter::insertString(UCHAR tag, const char*& str) -{ - insertString(tag, str, strlen(str)); -} -*/ } // namespace Firebird diff --git a/src/common/classes/GenericMap.h b/src/common/classes/GenericMap.h index 230f8e19797..30f7fb5fe1e 100644 --- a/src/common/classes/GenericMap.h +++ b/src/common/classes/GenericMap.h @@ -57,7 +57,7 @@ class GenericMap : public AutoStorage typedef typename KeyValuePair::first_type KeyType; typedef typename KeyValuePair::second_type ValueType; - typedef BePlusTree, KeyComparator> ValuesTree; + typedef BePlusTree, KeyComparator> ValuesTree; typedef typename ValuesTree::Accessor TreeAccessor; typedef typename ValuesTree::ConstAccessor ConstTreeAccessor; @@ -72,7 +72,6 @@ class GenericMap : public AutoStorage bool getNext() { return m_Accessor.getNext(); } bool locate(const KeyType& key) { return m_Accessor.locate(key); } - bool fastRemove() { return m_Accessor.fastRemove(); } private: Accessor(const Accessor&); @@ -91,7 +90,7 @@ class GenericMap : public AutoStorage bool getFirst() { return m_Accessor.getFirst(); } bool getNext() { return m_Accessor.getNext(); } - ValueType* locate(const KeyType& key) { return m_Accessor.locate(key); } + bool locate(const KeyType& key) { return m_Accessor.locate(key); } private: ConstAccessor(const ConstAccessor&); @@ -103,10 +102,10 @@ class GenericMap : public AutoStorage friend class Accessor; friend class ConstAccessor; - GenericMap() : tree(&getPool()), mCount(0) { } + GenericMap() : tree(getPool()), mCount(0) { } explicit GenericMap(MemoryPool& a_pool) - : AutoStorage(a_pool), tree(&getPool()), mCount(0) + : AutoStorage(a_pool), tree(getPool()), mCount(0) { } ~GenericMap() diff --git a/src/common/classes/MsgPrint.cpp b/src/common/classes/MsgPrint.cpp index 66d6af97f63..f5a451ccf7e 100644 --- a/src/common/classes/MsgPrint.cpp +++ b/src/common/classes/MsgPrint.cpp @@ -359,9 +359,8 @@ int MsgPrintErr(const char* format, const SafeArg& arg, bool userFormatting) int fb_msg_format(void* handle, USHORT facility, USHORT number, unsigned int bsize, TEXT* buffer, const MsgFormat::SafeArg& arg) { - // The field MESSAGES.TEXT is 138 bytes long. int total_msg = 0; - char msg[138 + 2] = ""; + char msg[BUFFER_SMALL] = ""; const int n = gds__msg_lookup(handle, facility, number, sizeof(msg), msg, NULL); if (n > 0 && unsigned(n) < sizeof(msg)) diff --git a/src/common/classes/RefCounted.h b/src/common/classes/RefCounted.h index f654afd8cc6..0c21ce90084 100644 --- a/src/common/classes/RefCounted.h +++ b/src/common/classes/RefCounted.h @@ -47,6 +47,11 @@ namespace Firebird return refCnt; } + void assertNonZero() + { + fb_assert(m_refCnt.value() > 0); + } + protected: RefCounted() : m_refCnt(0) {} @@ -137,6 +142,13 @@ namespace Firebird r.ptr = NULL; } + T* clear() // nullify pointer w/o calling release + { + T* rc = ptr; + ptr = NULL; + return rc; + } + T* operator=(T* p) { return assign(p); @@ -147,22 +159,12 @@ namespace Firebird return assign(r.ptr); } - operator T*() - { - return ptr; - } - - T* operator->() - { - return ptr; - } - - operator const T*() const + operator T*() const { return ptr; } - const T* operator->() const + T* operator->() const { return ptr; } diff --git a/src/common/classes/RefMutex.h b/src/common/classes/RefMutex.h index 6c9c9199549..bb3a938a478 100644 --- a/src/common/classes/RefMutex.h +++ b/src/common/classes/RefMutex.h @@ -101,7 +101,7 @@ namespace Firebird } }; - template > + template class RefCounted = DefaultRefCounted > class EnsureUnlock { public: @@ -114,14 +114,14 @@ namespace Firebird #define FB_LOCKED_FROM NULL #endif { - RefCounted::addRef(m_mutex); + RefCounted::addRef(m_mutex); } ~EnsureUnlock() { while (m_locked) leave(); - RefCounted::release(m_mutex); + RefCounted::release(m_mutex); } void enter() @@ -155,9 +155,59 @@ namespace Firebird }; #undef FB_LOCKED_FROM - typedef EnsureUnlock > MutexEnsureUnlock; + typedef EnsureUnlock MutexEnsureUnlock; typedef EnsureUnlock RefMutexEnsureUnlock; + + // Holds mutex lock and reference to data structure, containing that mutex. + // Lock is never taken in ctor, explicit call 'lock()' is needed later. + + class LateRefGuard + { + public: + LateRefGuard(const char* aReason) + : m_lock(nullptr), m_ref(nullptr), m_from(aReason) + { } + + void lock(Mutex* aLock, RefCounted* aRef) + { + fb_assert(aLock); + fb_assert(!m_lock); + m_lock = aLock; + fb_assert(aRef); + fb_assert(!m_ref); + m_ref = aRef; + + m_lock->enter(m_from); + m_ref->assertNonZero(); + m_ref->addRef(); + } + + ~LateRefGuard() + { + try + { + if (m_lock) + m_lock->leave(); + if (m_ref) + m_ref->release(); + } + catch (const Exception&) + { + DtorException::devHalt(); + } + } + + private: + // Forbid copying + LateRefGuard(const LateRefGuard&); + LateRefGuard& operator=(const LateRefGuard&); + + Mutex* m_lock; + RefCounted* m_ref; + const char* m_from; + }; + } // namespace #endif // CLASSES_REF_MUTEX_H diff --git a/src/common/classes/SyncObject.h b/src/common/classes/SyncObject.h index a24d45c1e92..6724c84dc0e 100644 --- a/src/common/classes/SyncObject.h +++ b/src/common/classes/SyncObject.h @@ -62,6 +62,9 @@ class SyncObject : public Reasons ~SyncObject() { + MutexLockGuard waitForWakeupThreads(mutex, FB_FUNCTION); + // No actions - just lock / unlock is needed to prevent races + // when sync object was destroyed before grantLocks() completion } void lock(Sync* sync, SyncType type, const char* from) diff --git a/src/common/classes/TempFile.cpp b/src/common/classes/TempFile.cpp index 2f76995a650..2ef479981be 100644 --- a/src/common/classes/TempFile.cpp +++ b/src/common/classes/TempFile.cpp @@ -140,7 +140,7 @@ PathName TempFile::create(const PathName& prefix, const PathName& directory) // Creates a temporary file and returns its name. // In error case store exception in status arg. // -// Make sure exception will not be passed to the end-user as it +// Make sure exception will not be passed to the end-user as it // contains server-side directory and it could break security! // diff --git a/src/common/classes/TimerImpl.cpp b/src/common/classes/TimerImpl.cpp index 65ff975a391..3c2c0cde687 100644 --- a/src/common/classes/TimerImpl.cpp +++ b/src/common/classes/TimerImpl.cpp @@ -75,7 +75,7 @@ void TimerImpl::reset(unsigned int timeout) MutexLockGuard guard(m_mutex, FB_FUNCTION); // Start timer if necessary. If timer was already started, don't restart - // (or stop) it - handler() will take care about it. + // (or stop) it - handler() will take care about it. if (!timeout) { diff --git a/src/common/classes/XThreadMutex.h b/src/common/classes/XThreadMutex.h index 464b483d829..b3329c3d384 100644 --- a/src/common/classes/XThreadMutex.h +++ b/src/common/classes/XThreadMutex.h @@ -89,7 +89,7 @@ class XThreadMutex : private Semaphore, private Reasons }; typedef RaiiLockGuard XThreadLockGuard; -typedef EnsureUnlock > XThreadEnsureUnlock; +typedef EnsureUnlock XThreadEnsureUnlock; } diff --git a/src/common/classes/array.h b/src/common/classes/array.h index 5121bde6ed5..60241e879a4 100644 --- a/src/common/classes/array.h +++ b/src/common/classes/array.h @@ -110,6 +110,12 @@ class Array : protected Storage ensureCapacity(InitialCapacity); } + Array(const T* items, const size_type itemsCount) + : Storage(), count(0), capacity(this->getStorageSize()), data(this->getStorage()) + { + add(items, itemsCount); + } + Array(const Array& source) : Storage(), count(0), capacity(this->getStorageSize()), data(this->getStorage()) { @@ -403,6 +409,16 @@ class Array : protected Storage return data; } + // prepare array to be used as a buffer of capacity bytes aligned on given alignment + T* getAlignedBuffer(const size_type capacityL, const size_type alignL) + { + static_assert(sizeof(T) == 1, "sizeof(T) != 1"); + + ensureCapacity(capacityL + alignL, false); + count = capacityL + alignL; + return FB_ALIGN(data, alignL); + } + // clear array and release dinamically allocated memory void free() { diff --git a/src/common/classes/auto.h b/src/common/classes/auto.h index a1eb32c9715..f3c04599b95 100644 --- a/src/common/classes/auto.h +++ b/src/common/classes/auto.h @@ -32,6 +32,7 @@ #define CLASSES_AUTO_PTR_H #include +#include namespace Firebird { @@ -116,22 +117,12 @@ class AutoPtr return *this; } - operator Where*() + Where* get() const { return ptr; } - Where* get() - { - return ptr; - } - - operator const Where*() const - { - return ptr; - } - - const Where* get() const + operator Where*() const { return ptr; } @@ -146,12 +137,7 @@ class AutoPtr return ptr != NULL; } - Where* operator->() - { - return ptr; - } - - const Where* operator->() const + Where* operator->() const { return ptr; } @@ -199,30 +185,39 @@ class AutoRelease : public AutoPtr template -class AutoSetRestore +class AutoSaveRestore { public: - AutoSetRestore(T* aValue, T newValue) + AutoSaveRestore(T* aValue) : value(aValue), oldValue(*aValue) - { - *value = newValue; - } + { } - ~AutoSetRestore() + ~AutoSaveRestore() { *value = oldValue; } private: // copying is prohibited - AutoSetRestore(const AutoSetRestore&); - AutoSetRestore& operator =(const AutoSetRestore&); + AutoSaveRestore(const AutoSaveRestore&); + AutoSaveRestore& operator =(const AutoSaveRestore&); T* value; T oldValue; }; +template +class AutoSetRestore : public AutoSaveRestore +{ +public: + AutoSetRestore(T* aValue, T newValue) + : AutoSaveRestore(aValue) + { + *aValue = newValue; + } +}; + template class AutoSetRestoreFlag @@ -245,6 +240,12 @@ class AutoSetRestoreFlag *value |= oldValue; } + void release(T cleanBit) + { + bit &= ~cleanBit; + oldValue &= ~cleanBit; + } + private: // copying is prohibited AutoSetRestoreFlag(const AutoSetRestoreFlag&); @@ -289,6 +290,22 @@ class AutoSetRestore2 }; +class Cleanup +{ +public: + Cleanup(std::function clFunc) + : clean(clFunc) + { } + + ~Cleanup() + { + clean(); + } + +private: + std::function clean; +}; + } //namespace Firebird #endif // CLASSES_AUTO_PTR_H diff --git a/src/common/classes/fb_string.h b/src/common/classes/fb_string.h index 31db8abdf19..cff931e1f9a 100644 --- a/src/common/classes/fb_string.h +++ b/src/common/classes/fb_string.h @@ -662,7 +662,8 @@ namespace Firebird StringBase() : AbstractString(Comparator::getMaxLength()) {} StringBase(const StringType& v) : AbstractString(Comparator::getMaxLength(), v) {} StringBase(const void* s, size_type n) : AbstractString(Comparator::getMaxLength(), n, s) {} - StringBase(const_pointer s) : AbstractString(Comparator::getMaxLength(), static_cast(strlen(s)), s) {} + StringBase(const_pointer s) : + AbstractString(Comparator::getMaxLength(), static_cast(s ? strlen(s) : 0), s) {} explicit StringBase(const unsigned char* s) : AbstractString(Comparator::getMaxLength(), static_cast(strlen((char*)s)), (char*)s) {} StringBase(const MetaString& v) : AbstractString(Comparator::getMaxLength(), v) {} diff --git a/src/common/classes/init.cpp b/src/common/classes/init.cpp index c2898554c20..e26aff21a7e 100644 --- a/src/common/classes/init.cpp +++ b/src/common/classes/init.cpp @@ -27,6 +27,7 @@ #include "firebird.h" #include "init.h" #include "alloc.h" +#include "auto.h" #include "../common/SimpleStatusVector.h" #include "../common/dllinst.h" #include "../common/os/os_utils.h" @@ -163,17 +164,10 @@ namespace } #ifndef DEBUG_INIT - // This class with it's single instance ensures global cleanup - class Cleanup - { - public: - ~Cleanup() - { - allClean(); - } - }; - Cleanup global; + // This instance ensures dtors run when program exits + Firebird::Cleanup global(allClean); + #endif //DEBUG_INIT void init() diff --git a/src/common/classes/init.h b/src/common/classes/init.h index 7bb2952cad8..2feaa44f594 100644 --- a/src/common/classes/init.h +++ b/src/common/classes/init.h @@ -159,6 +159,11 @@ class GlobalPtr : private InstanceControl { return instance; } + + operator bool() noexcept + { + return instance; + } }; // InitMutex - executes static void C::init() once and only once diff --git a/src/common/classes/locks.h b/src/common/classes/locks.h index 0a2b82b8be4..7baae6abc0b 100644 --- a/src/common/classes/locks.h +++ b/src/common/classes/locks.h @@ -320,7 +320,7 @@ typedef Mutex Spinlock; #endif //WIN_NT -// RAII holder +// RAII holders template class RaiiLockGuard { @@ -363,10 +363,12 @@ class RaiiLockGuard typedef RaiiLockGuard MutexLockGuard; -class MutexUnlockGuard + +template +class RaiiUnlockGuard { public: - explicit MutexUnlockGuard(Mutex& aLock, const char* aReason) + explicit RaiiUnlockGuard(M& aLock, const char* aReason) : lock(&aLock) #ifdef DEV_BUILD , saveReason(aReason) @@ -375,7 +377,7 @@ class MutexUnlockGuard lock->leave(); } - ~MutexUnlockGuard() + ~RaiiUnlockGuard() { try { @@ -393,15 +395,17 @@ class MutexUnlockGuard private: // Forbid copying - MutexUnlockGuard(const MutexUnlockGuard&); - MutexUnlockGuard& operator=(const MutexUnlockGuard&); + RaiiUnlockGuard(const RaiiUnlockGuard&); + RaiiUnlockGuard& operator=(const RaiiUnlockGuard&); - Mutex* lock; + M* lock; #ifdef DEV_BUILD const char* saveReason; #endif }; +typedef RaiiUnlockGuard MutexUnlockGuard; + class MutexCheckoutGuard { diff --git a/src/common/classes/sparse_bitmap.h b/src/common/classes/sparse_bitmap.h index faf1f89fea1..e08bbc22f78 100644 --- a/src/common/classes/sparse_bitmap.h +++ b/src/common/classes/sparse_bitmap.h @@ -60,12 +60,12 @@ class SparseBitmap : public AutoStorage public: // Default constructor, stack placement SparseBitmap() : - singular(false), singular_value(0), tree(&getPool()), defaultAccessor(this) + singular(false), singular_value(0), tree(getPool()), defaultAccessor(this) { } // Pooled constructor explicit SparseBitmap(MemoryPool& p) : - AutoStorage(p), singular(false), singular_value(0), tree(&getPool()), defaultAccessor(this) + AutoStorage(p), singular(false), singular_value(0), tree(getPool()), defaultAccessor(this) { } // Default accessor methods @@ -225,7 +225,7 @@ class SparseBitmap : public AutoStorage } }; - typedef BePlusTree BitmapTree; + typedef BePlusTree BitmapTree; typedef typename BitmapTree::Accessor BitmapTreeAccessor; // Set if bitmap contains a single value only diff --git a/src/common/classes/tree.h b/src/common/classes/tree.h index 2bc7c5661b6..252f137324b 100644 --- a/src/common/classes/tree.h +++ b/src/common/classes/tree.h @@ -64,19 +64,6 @@ const int NODE_PAGE_SIZE = 3000; // should be more than enough. No checks are performed in code against overflow of this value const int MAX_TREE_LEVEL = 30; -class MallocAllocator -{ -public: - void *allocate(size_t size ALLOC_PARAMS) - { - return malloc(size); - } - void deallocate(void *p) - { - free(p); - } -}; - enum LocType { locEqual, locLess, locGreat, locGreatEqual, locLessEqual }; // Fast and simple B+ tree of simple types. @@ -106,24 +93,20 @@ enum LocType { locEqual, locLess, locGreat, locGreatEqual, locLessEqual }; // an indexed dynamic array without increase of algorithm calculation costs (this is one // more classical B+ tree feature). This is also not done to improve tree performance a little // -template , - typename Cmp = DefaultComparator > +template , + typename Cmp = DefaultComparator > class BePlusTree { - static const FB_SIZE_T LeafCount = LEAF_PAGE_SIZE / sizeof(Value); - static const FB_SIZE_T NodeCount = NODE_PAGE_SIZE / sizeof(void*); + static const FB_SIZE_T LEAF_COUNT = LEAF_PAGE_SIZE / sizeof(Value); + static const FB_SIZE_T NODE_COUNT = NODE_PAGE_SIZE / sizeof(void*); public: - explicit BePlusTree(Allocator *_pool) - : pool(_pool), level(0), root(NULL), defaultAccessor(this) - { } - - explicit BePlusTree(Allocator& _pool) - : pool(&_pool), level(0), root(NULL), defaultAccessor(this) + explicit BePlusTree(Firebird::MemoryPool& _pool) + : pool(&_pool), level(0), defaultAccessor(this) { } - BePlusTree(Allocator *_pool, const BePlusTree& from) - : pool(_pool), level(0), root(NULL), defaultAccessor(this) + BePlusTree(Firebird::MemoryPool& _pool, const BePlusTree& from) + : pool(&_pool), level(0), defaultAccessor(this) { append(from); } @@ -137,30 +120,29 @@ class BePlusTree void clear() { - defaultAccessor.curr = NULL; + defaultAccessor.curr = nullptr; // Do not deallocate root page if tree is shallow if (level == 0) { if (root) { - ((ItemList*) root)->clear(); + root.items->clear(); } return; } // Find first items page - void *temp = root; + NodePtr temp = root; for (int i = level; i > 0; i--) - temp = (*(NodeList *)temp)[0]; - ItemList *items = (ItemList *)temp; + temp = (*temp.nodes)[0]; + ItemList *items = temp.items; // Delete all items pages NodeList *lists = items->parent; while (items) { ItemList *t = items->next; - items->~ItemList(); - pool->deallocate(items); + delete items; items = t; } @@ -172,26 +154,25 @@ class BePlusTree while (list) { NodeList *t = list->next; - list->~NodeList(); - pool->deallocate(list); + delete list; list = t; } } // Initialize fields to make tree usable again - root = NULL; + root.items = nullptr; level = 0; } ~BePlusTree() { clear(); - pool->deallocate(root); + delete root.items; } bool isEmpty() const { - return root == NULL || (level == 0 && ((ItemList*) root)->getCount() == 0); + return !root || (level == 0 && root.items->getCount() == 0); } bool add(const Value& item) { return defaultAccessor.add(item); } @@ -232,14 +213,14 @@ class BePlusTree if (level == 0) { - if (root == NULL) - return other.root == NULL; - if (other.root == NULL) + if (!root) + return !other.root; + if (!other.root) return true; - return ((ItemList*) root)->getCount() > ((ItemList*) other.root)->getCount(); + return root.items->getCount() > other.root.items->getCount(); } - return ((NodeList*) root)->getCount() > ((NodeList*) other.root)->getCount(); + return root.nodes->getCount() > other.root.nodes->getCount(); } // Compute approximate number of leafs in the tree @@ -249,19 +230,19 @@ class BePlusTree return 0; if (level == 0) - return ((ItemList*) root)->getCount(); + return root.items->getCount(); // Tree is large. Roughly estimate number of leaf nodes using number of // items in root list and depth of the tree. Theoretically possible fill // factor range for the tree on each level for current NEED_MERGE routine // is [0.375, 1]. We take 3/5 = 0.6 as most probable case and // play from there. - size_t items_per_node = LeafCount * 3 / 5; + size_t items_per_node = LEAF_COUNT * 3 / 5; for (int i = 1; i < level; i++) - items_per_node *= NodeCount * 3 / 5; + items_per_node *= NODE_COUNT * 3 / 5; fb_assert(items_per_node); - return ((NodeList*)root)->getCount() * items_per_node; + return root.nodes->getCount() * items_per_node; } // Compute approximate memory consumption for tree in bytes @@ -278,10 +259,10 @@ class BePlusTree // is the same as in approxCount() routine above size_t bytes_per_node = sizeof(ItemList); for (int i = 1; i < level; i++) - bytes_per_node *= NodeCount * 3 / 5; + bytes_per_node *= NODE_COUNT * 3 / 5; fb_assert(bytes_per_node); - return ((NodeList*)root)->getCount() * bytes_per_node; + return root.nodes->getCount() * bytes_per_node; } void append(const BePlusTree& from) @@ -298,12 +279,9 @@ class BePlusTree } private: - BePlusTree(Allocator *_pool, void *rootPage) : pool(_pool), level(0), - root(new(rootPage) ItemList()), defaultAccessor(this) {} - class NodeList; - class ItemList : public SortedVector + class ItemList : public SortedVector { public: NodeList* parent; @@ -312,7 +290,7 @@ class BePlusTree // Adds newly created item to doubly-linked list ItemList(ItemList* items) - : parent(NULL) + : parent(nullptr) { if ((next = items->next)) next->prev = this; @@ -320,21 +298,27 @@ class BePlusTree items->next = this; } // Create first item in the linked list - ItemList() : parent(NULL), next(NULL), prev(NULL) {} + ItemList() : parent(nullptr), next(nullptr), prev(nullptr) {} + }; - friend class BePlusTree; -#ifndef _MSC_VER - friend class BePlusTree::NodeList; - friend class BePlusTree::Accessor; -#endif + union NodePtr + { + NodePtr() : items(nullptr) {} + NodePtr(ItemList* p) : items(p) {} + NodePtr(NodeList* p) : nodes(p) {} + + operator bool() const { return items != nullptr; } + + ItemList* items; + NodeList* nodes; }; - class NodeList : public SortedVector + class NodeList : public SortedVector { public: // Adds newly created item to the doubly-linked list NodeList(NodeList* items) - : parent(NULL) + : parent(nullptr) { if ((next = items->next)) next->prev = this; @@ -342,37 +326,37 @@ class BePlusTree items->next = this; } // Create first item in the linked list - NodeList() : parent(NULL), next(NULL), prev(NULL) {} + NodeList() : parent(nullptr), next(nullptr), prev(nullptr) {} int level; NodeList *parent; NodeList *next, *prev; - static const Key& generate(const void *sender, void *item) + static const Key& generate(const void* sender, NodePtr item) { for (int lev = ((NodeList *)sender)->level; lev > 0; lev--) - item = *((NodeList *)item)->begin(); + item = *(item.nodes->begin()); // ItemList reference below is ISO C++ compliant. // If your compiler has broken name lookup sequence then conditionally // add ItemList typedef for you compiler with whichever syntax it likes - return KeyOfValue::generate(item, *((ItemList *)item)->begin()); + return KeyOfValue::generate(item.items, *(item.items->begin())); } - static void setNodeParentAndLevel(void* node, const int level, NodeList* parent) + static void setNodeParentAndLevel(NodePtr node, const int level, NodeList* parent) { if (level) { - ((NodeList *)node)->parent = parent; - ((NodeList *)node)->level = level - 1; + node.nodes->parent = parent; + node.nodes->level = level - 1; } else - ((ItemList *)node)->parent = parent; + node.items->parent = parent; } - static void setNodeParent(void* node, const int level, NodeList* parent) + static void setNodeParent(NodePtr node, const int level, NodeList* parent) { if (level) - ((NodeList*) node)->parent = parent; + node.nodes->parent = parent; else - ((ItemList*) node)->parent = parent; + node.items->parent = parent; } }; @@ -381,7 +365,7 @@ class BePlusTree { public: explicit ConstAccessor(const BePlusTree* in_tree) : - curr(NULL), curPos(0), tree(in_tree) + curr(nullptr), curPos(0), tree(in_tree) {} bool locate(const Key& key) @@ -395,22 +379,22 @@ class BePlusTree { // Inlining is efficient here because LocType will be known in most cases // and compiler will be able to eliminate most of code - void *list = tree->root; + NodePtr list = tree->root; if (!list) return false; // Uninitialized tree for (int lev = tree->level; lev; lev--) { FB_SIZE_T pos; - if (!((NodeList *)list)->find(key, pos)) + if (!list.nodes->find(key, pos)) { if (pos > 0) pos--; } - list = (*(NodeList *)list)[pos]; + list = (*list.nodes)[pos]; } - curr = (ItemList *)list; + curr = list.items; const bool found = curr->find(key, curPos); switch (lt) { @@ -454,30 +438,30 @@ class BePlusTree // position of accessor is not defined. bool getFirst() { - void* items = tree->root; + NodePtr items = tree->root; if (!items) return false; // Uninitialized tree for (int i = tree->level; i > 0; i--) - items = (*(NodeList*) items)[0]; - curr = (ItemList*) items; + items = (*items.nodes)[0]; + curr = items.items; curPos = 0; - return ((ItemList*) items)->getCount() != 0; + return items.items->getCount() != 0; } // If method returns false it means list is empty and // position of accessor is not defined. bool getLast() { - void *items = tree->root; + NodePtr items = tree->root; if (!items) return false; // Uninitialized tree for (int i = tree->level; i > 0; i--) - items = (*(NodeList*) items)[((NodeList*) items)->getCount() - 1]; - curr = (ItemList *)items; - if (((ItemList*) items)->getCount()) + items = (*items.nodes)[items.nodes->getCount() - 1]; + curr = items.items; + if (items.items->getCount()) { - curPos = ((ItemList*) items)->getCount() - 1; + curPos = items.items->getCount() - 1; return true; } return false; @@ -567,7 +551,7 @@ class BePlusTree // invalidate current position of defaultAccessor // if i'm not a defaultAccessor if (this != &tree->defaultAccessor) - tree->defaultAccessor.curr = NULL; + tree->defaultAccessor.curr = nullptr; if (!tree->level) { @@ -580,14 +564,14 @@ class BePlusTree // because is would invalidate our tree structure fb_assert(this->curPos == 0); ItemList* temp; - if ((temp = this->curr->prev) && NEED_MERGE(temp->getCount(), LeafCount)) + if ((temp = this->curr->prev) && NEED_MERGE(temp->getCount(), LEAF_COUNT)) { temp = this->curr->next; tree->_removePage(0, this->curr); this->curr = temp; return this->curr; } - if ((temp = this->curr->next) && NEED_MERGE(temp->getCount(), LeafCount)) + if ((temp = this->curr->next) && NEED_MERGE(temp->getCount(), LEAF_COUNT)) { tree->_removePage(0, this->curr); this->curr = temp; @@ -613,7 +597,7 @@ class BePlusTree this->curr->remove(this->curPos); ItemList *temp; if ((temp = this->curr->prev) && - NEED_MERGE(temp->getCount() + this->curr->getCount(), LeafCount)) + NEED_MERGE(temp->getCount() + this->curr->getCount(), LEAF_COUNT)) { // After join upper levels of the tree remain stable because join doesn't change // key of the page. The same applies to lower case too. @@ -626,7 +610,7 @@ class BePlusTree else { if ((temp = this->curr->next) && - NEED_MERGE(temp->getCount() + this->curr->getCount(), LeafCount)) + NEED_MERGE(temp->getCount() + this->curr->getCount(), LEAF_COUNT)) { this->curr->join(*temp); tree->_removePage(0, temp); @@ -647,47 +631,41 @@ class BePlusTree private: BePlusTree* tree; - - friend class BePlusTree; }; // class Accessor private: - Allocator* pool; + Firebird::MemoryPool* const pool; int level; - void* root; + NodePtr root; Accessor defaultAccessor; - void _removePage(int level, void *node); - - friend class MemoryPool; - friend class NodeList; - friend class Accessor; + void _removePage(int level, NodePtr node); }; // ************************ BePlusTree implementation ****************** -template -bool BePlusTree::add(const Value& item, Accessor* accessor) +template +bool BePlusTree::add(const Value& item, Accessor* accessor) { // Finish initialization of the tree if necessary if (!root) - root = new (pool->allocate(sizeof(ItemList) ALLOC_ARGS)) ItemList(); + root = FB_NEW_POOL(*pool) ItemList(); // Find leaf page for our item - void *vList = this->root; - const Key& key = KeyOfValue::generate(NULL, item); + NodePtr vList = this->root; + const Key& key = KeyOfValue::generate(nullptr, item); for (int lev = this->level; lev > 0; lev--) { FB_SIZE_T pos; - if (!((NodeList *)vList)->find(key, pos)) + if (!vList.nodes->find(key, pos)) { if (pos > 0) pos--; } - vList = (*(NodeList *)vList)[pos]; + vList = (*vList.nodes)[pos]; } - ItemList *leaf = (ItemList *)vList; + ItemList *leaf = vList.items; FB_SIZE_T pos; if (leaf->find(key, pos)) @@ -700,7 +678,7 @@ bool BePlusTree::add(const Value& item, return false; } - if (leaf->getCount() < LeafCount) + if (leaf->getCount() < LEAF_COUNT) { leaf->insert(pos, item); return true; @@ -710,10 +688,10 @@ bool BePlusTree::add(const Value& item, ItemList *temp; // Adding items to the next page is cheaper in most cases that // is why it is checked first - if ((temp = leaf->next) && temp->getCount() < LeafCount) + if ((temp = leaf->next) && temp->getCount() < LEAF_COUNT) { // Found space on the next page - if (pos == LeafCount) + if (pos == LEAF_COUNT) { // This would be ok if items were unique: temp->insert(0, item); // The same applies to all simular cases below @@ -725,14 +703,14 @@ bool BePlusTree::add(const Value& item, // It should do it in case of random size items. // It would make things slower in case of sequental items addition. // Let's leave it as is now. - temp->insert(0, (*leaf)[LeafCount - 1]); - leaf->shrink(LeafCount - 1); + temp->insert(0, (*leaf)[LEAF_COUNT - 1]); + leaf->shrink(LEAF_COUNT - 1); leaf->insert(pos, item); } return true; } - if ((temp = leaf->prev) && temp->getCount() < LeafCount) + if ((temp = leaf->prev) && temp->getCount() < LEAF_COUNT) { // Found space on the previous page if (pos == 0) { @@ -753,7 +731,7 @@ bool BePlusTree::add(const Value& item, // No re-enterance allowed !!! // Since we haven't done anything with tree yet, thus we don't need to recover // anything in case of error thrown at this allocation here - ItemList *newLeaf = new(this->pool->allocate(sizeof(ItemList) ALLOC_ARGS)) ItemList(leaf); + ItemList *newLeaf = FB_NEW_POOL(*pool) ItemList(leaf); // Start building recovery map. // This array contains index of the element we try to add on page of each level @@ -762,27 +740,27 @@ bool BePlusTree::add(const Value& item, FB_SIZE_T recovery_map[MAX_TREE_LEVEL]; const FB_SIZE_T MAP_NEW_PAGE = ~((FB_SIZE_T) 0); - if (pos == LeafCount) + if (pos == LEAF_COUNT) { newLeaf->insert(0, item); recovery_map[0] = MAP_NEW_PAGE; } else { - newLeaf->insert(0, (*leaf)[LeafCount - 1]); + newLeaf->insert(0, (*leaf)[LEAF_COUNT - 1]); leaf->shrink(leaf->getCount() - 1); leaf->insert(pos, item); recovery_map[0] = pos; } - void *newNode = newLeaf; + NodePtr newNode = newLeaf; NodeList *nodeList = leaf->parent; int curLevel = 0; try { while (nodeList) { // Easy case. We've got some space on the node page - if (nodeList->getCount() < NodeCount) + if (nodeList->getCount() < NODE_COUNT) { NodeList::setNodeParentAndLevel(newNode, curLevel, nodeList); nodeList->add(newNode); @@ -793,27 +771,27 @@ bool BePlusTree::add(const Value& item, nodeList->find(NodeList::generate(nodeList, newNode), pos); NodeList *list; - if ((list = nodeList->next) && list->getCount() < NodeCount) + if ((list = nodeList->next) && list->getCount() < NODE_COUNT) { // Found space on the next page - if (pos == NodeCount) + if (pos == NODE_COUNT) { NodeList::setNodeParentAndLevel(newNode, curLevel, list); list->insert(0, newNode); } else { - void *t = (*nodeList)[NodeCount - 1]; + NodePtr t = (*nodeList)[NODE_COUNT - 1]; NodeList::setNodeParent(t, curLevel, list); list->insert(0, t); - nodeList->shrink(NodeCount - 1); + nodeList->shrink(NODE_COUNT - 1); NodeList::setNodeParentAndLevel(newNode, curLevel, nodeList); nodeList->insert(pos, newNode); } return true; } - if ((list = nodeList->prev) && list->getCount() < NodeCount) + if ((list = nodeList->prev) && list->getCount() < NODE_COUNT) { // Found space on the previous page if (pos == 0) @@ -823,7 +801,7 @@ bool BePlusTree::add(const Value& item, } else { - void *t = (*nodeList)[0]; + NodePtr t = (*nodeList)[0]; NodeList::setNodeParent(t, curLevel, list); list->insert(list->getCount(), t); nodeList->remove(0); @@ -838,9 +816,9 @@ bool BePlusTree::add(const Value& item, // No re-enterance allowed !!! // Exceptions from this point // are cleaned up lower - NodeList *newList = new(this->pool->allocate(sizeof(NodeList) ALLOC_ARGS)) NodeList(nodeList); + NodeList *newList = FB_NEW_POOL(*pool) NodeList(nodeList); - if (pos == NodeCount) + if (pos == NODE_COUNT) { NodeList::setNodeParentAndLevel(newNode, curLevel, newList); newList->insert(0, newNode); @@ -848,10 +826,10 @@ bool BePlusTree::add(const Value& item, } else { - void *t = (*nodeList)[NodeCount - 1]; + NodePtr t = (*nodeList)[NODE_COUNT - 1]; NodeList::setNodeParent(t, curLevel, newList); newList->insert(0, t); - nodeList->shrink(NodeCount - 1); + nodeList->shrink(NODE_COUNT - 1); NodeList::setNodeParentAndLevel(newNode, curLevel, nodeList); nodeList->insert(pos, newNode); recovery_map[curLevel + 1] = pos; @@ -863,7 +841,7 @@ bool BePlusTree::add(const Value& item, // This is the worst case. We reached the top of tree but were not able to insert node // Allocate new root page and increase level of our tree - nodeList = new(this->pool->allocate(sizeof(NodeList) ALLOC_ARGS)) NodeList(); + nodeList = FB_NEW_POOL(*pool) NodeList(); nodeList->level = this->level; nodeList->insert(0, this->root); NodeList::setNodeParentAndLevel(newNode, this->level, nodeList); @@ -877,8 +855,8 @@ bool BePlusTree::add(const Value& item, // Recover tree to innocent state while (curLevel) { - NodeList *itemL = reinterpret_cast(newNode); - void *lower; + NodeList *itemL = newNode.nodes; + NodePtr lower; if (recovery_map[curLevel] == MAP_NEW_PAGE) { lower = (*itemL)[0]; } @@ -889,32 +867,30 @@ bool BePlusTree::add(const Value& item, itemL->prev->insert(itemL->prev->getCount(), (*itemL)[0]); NodeList::setNodeParent((*itemL)[0], curLevel - 1, itemL->prev); } - itemL->~NodeList(); - this->pool->deallocate(newNode); + delete itemL; newNode = lower; curLevel--; } - ItemList *itemL2 = reinterpret_cast(newNode); + ItemList *itemL2 = newNode.items; if (recovery_map[0] != MAP_NEW_PAGE) { itemL2->prev->remove(recovery_map[0]); itemL2->prev->insert(itemL2->prev->getCount(), (*itemL2)[0]); } - itemL2->~ItemList(); - this->pool->deallocate(newNode); + delete itemL2; throw; } return true; } -template -void BePlusTree::_removePage(const int nodeLevel, void *node) +template +void BePlusTree::_removePage(const int nodeLevel, NodePtr node) { NodeList *list; // Get parent and adjust the links if (nodeLevel) { - NodeList *temp = (NodeList *)node; + NodeList *temp = node.nodes; if (temp->prev) temp->prev->next = temp->next; if (temp->next) @@ -923,7 +899,7 @@ void BePlusTree::_removePage(const int n } else { - ItemList *temp = (ItemList *)node; + ItemList *temp = node.items; if (temp->prev) temp->prev->next = temp->next; if (temp->next) @@ -936,11 +912,11 @@ void BePlusTree::_removePage(const int n // Only one node left in the list. We cannot remove it directly // because is would invalidate our tree structure NodeList *temp; - if ((temp = list->prev) && NEED_MERGE(temp->getCount(), NodeCount)) { + if ((temp = list->prev) && NEED_MERGE(temp->getCount(), NODE_COUNT)) { _removePage(nodeLevel + 1, list); } else - if ((temp = list->next) && NEED_MERGE(temp->getCount(), NodeCount)) { + if ((temp = list->next) && NEED_MERGE(temp->getCount(), NODE_COUNT)) { _removePage(nodeLevel + 1, list); } else @@ -972,21 +948,20 @@ void BePlusTree::_removePage(const int n #endif list->remove(pos); - if (list == root && list->getCount() == 1) + if (root.nodes == list && list->getCount() == 1) { // We reached the top of the tree and were asked to modify root // page so only one node will be left in this case. // Reduce the level of the tree root = (*list)[0]; level--; - NodeList::setNodeParent(root, level, NULL); - list->~NodeList(); - pool->deallocate(list); + NodeList::setNodeParent(root, level, nullptr); + delete list; } else { NodeList *temp; - if ((temp = list->prev) && NEED_MERGE(temp->getCount() + list->getCount(), NodeCount)) + if ((temp = list->prev) && NEED_MERGE(temp->getCount() + list->getCount(), NODE_COUNT)) { // After join upper levels of the tree remain stable because join doesn't change // key of the page. The same applies to lower case too. @@ -996,7 +971,7 @@ void BePlusTree::_removePage(const int n _removePage(nodeLevel + 1, list); } else - if ((temp = list->next) && NEED_MERGE(temp->getCount() + list->getCount(), NodeCount)) + if ((temp = list->next) && NEED_MERGE(temp->getCount() + list->getCount(), NODE_COUNT)) { list->join(*temp); for (FB_SIZE_T i = 0; i < temp->getCount(); i++) @@ -1007,10 +982,9 @@ void BePlusTree::_removePage(const int n } if (nodeLevel) - ((NodeList *)node)->~NodeList(); + delete node.nodes; else - ((ItemList *)node)->~ItemList(); - pool->deallocate(node); + delete node.items; } } // namespace Firebird diff --git a/src/common/common.h b/src/common/common.h index 9fbe95410a4..e314e3fc95d 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -230,6 +230,10 @@ #ifdef ARM #define FB_CPU CpuArm #endif /* ARM */ +#ifdef ARM64 +#define DARWIN64 +#define FB_CPU CpuArm64 +#endif /* ARM64 */ #ifdef __ppc__ #define powerpc #define FB_CPU CpuPowerPc @@ -252,8 +256,6 @@ #define API_ROUTINE __attribute__((visibility("default"))) #define API_ROUTINE_VARARG API_ROUTINE -#define INTERNAL_API_ROUTINE API_ROUTINE -#define FB_EXPORTED __attribute__((visibility("default"))) #define O_DIRECT F_NOCACHE #endif /* Darwin Platforms */ @@ -603,10 +605,6 @@ extern "C" int remove(const char* path); #define CLIB_ROUTINE #endif -#ifndef FB_EXPORTED -#define FB_EXPORTED -#endif - #ifdef HAS_NOEXCEPT #define NOEXCEPT noexcept #define NOEXCEPT_ARG(X) noexcept((X)) diff --git a/src/common/config/config.cpp b/src/common/config/config.cpp index 6e17cf9b50c..678eb9e9b42 100644 --- a/src/common/config/config.cpp +++ b/src/common/config/config.cpp @@ -152,7 +152,7 @@ Config::Config(const ConfigFile& file) : valuesSource(*getDefaultMemoryPool()), notifyDatabase(*getDefaultMemoryPool()), serverMode(-1), - defaultConfig(false) + defaultConfig(true) { memset(sourceIdx, 0, sizeof(sourceIdx)); valuesSource.add(NULL); @@ -180,6 +180,7 @@ Config::Config(const ConfigFile& file) } loadValues(file, CONFIG_FILE); + fixDefaults(); } Config::Config(const ConfigFile& file, const char* srcName, const Config& base, const PathName& notify) @@ -242,7 +243,7 @@ void Config::loadValues(const ConfigFile& file, const char* srcName) const ConfigFile::Parameter* par = file.findParameter(entry.key); // Don't assign values to the global keys at non-default config - if (par && (defaultConfig || !entry.is_global)) + if (par && (defaultConfig || !entry.is_global) && (par->hasValue || par->sub)) { // Assign the actual value @@ -294,7 +295,7 @@ static const char* txtServerModes[6] = void Config::setupDefaultConfig() { - defaultConfig = true; + fb_assert(defaultConfig); for (unsigned i = 0; i < MAX_CONFIG_KEY; i++) defaults[i] = entries[i].default_value; @@ -305,26 +306,45 @@ void Config::setupDefaultConfig() serverMode = bootBuild ? MODE_CLASSIC : MODE_SUPER; pDefault->strVal = txtServerModes[2 * serverMode]; - pDefault = &defaults[KEY_TEMP_CACHE_LIMIT]; + defaults[KEY_REMOTE_FILE_OPEN_ABILITY].boolVal = bootBuild; + + //pDefault = &entries[KEY_WIRE_CRYPT].default_value; +// if (!*pDefault) +// *pDefault == (ConfigValue) (xxx == WC_CLIENT) ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED; + +} + +void Config::fixDefaults() +{ + fb_assert(defaultConfig); + + ConfigValue* pDefault = &defaults[KEY_TEMP_CACHE_LIMIT]; + ConfigValue* pValue = &values[KEY_TEMP_CACHE_LIMIT]; if (pDefault->intVal < 0) pDefault->intVal = (serverMode != MODE_SUPER) ? 8388608 : 67108864; // bytes - defaults[KEY_REMOTE_FILE_OPEN_ABILITY].boolVal = bootBuild; + if (pValue->intVal < 0) + pValue->intVal = pDefault->intVal; + pDefault = &defaults[KEY_DEFAULT_DB_CACHE_PAGES]; + pValue = &values[KEY_DEFAULT_DB_CACHE_PAGES]; if (pDefault->intVal < 0) pDefault->intVal = (serverMode != MODE_SUPER) ? 256 : 2048; // pages + if (pValue->intVal < 0) + pValue->intVal = pDefault->intVal; + + pDefault = &defaults[KEY_GC_POLICY]; + pValue = &values[KEY_GC_POLICY]; if (!pDefault->strVal) { pDefault->strVal = (serverMode == MODE_SUPER) ? GCPolicyCombined : GCPolicyCooperative; } - //pDefault = &entries[KEY_WIRE_CRYPT].default_value; -// if (!*pDefault) -// *pDefault == (ConfigValue) (xxx == WC_CLIENT) ? WIRE_CRYPT_ENABLED : WIRE_CRYPT_REQUIRED; - + if (!pValue->strVal) + pValue->strVal = pDefault->strVal; } void Config::checkIntForLoBound(ConfigKey key, SINT64 loBound, bool setDefault) @@ -350,7 +370,7 @@ void Config::checkValues() checkIntForLoBound(KEY_DEFAULT_DB_CACHE_PAGES, 0, true); - checkIntForLoBound(KEY_LOCK_MEM_SIZE, 64 * 1024, false); + checkIntForLoBound(KEY_LOCK_MEM_SIZE, 256 * 1024, false); const char* strVal = values[KEY_GC_POLICY].strVal; if (strVal) diff --git a/src/common/config/config.h b/src/common/config/config.h index dc73bd743aa..262658a63c1 100644 --- a/src/common/config/config.h +++ b/src/common/config/config.h @@ -65,9 +65,9 @@ type getParameterName() const; form, for world-wide (global) parameters static type getParameterName(); - should be used. Also, for world-wide parameters, values of default + should be used. Also, for world-wide parameters, values of default config instance (see getDefaultConfig()) should be used. - 5. Macros CONFIG_GET_GLOBAL_XXX and CONFIG_GET_PER_DB_XXX helps to + 5. Macros CONFIG_GET_GLOBAL_XXX and CONFIG_GET_PER_DB_XXX helps to declare and implement trivial getXXX functions and to enforce rule (4). **/ @@ -177,6 +177,7 @@ enum ConfigKey KEY_ENCRYPT_SECURITY_DATABASE, KEY_STMT_TIMEOUT, KEY_CONN_IDLE_TIMEOUT, + KEY_ON_DISCONNECT_TRIG_TIMEOUT, KEY_CLIENT_BATCH_BUFFER, KEY_OUTPUT_REDIRECTION_FILE, KEY_EXT_CONN_POOL_SIZE, @@ -189,6 +190,7 @@ enum ConfigKey KEY_USE_FILESYSTEM_CACHE, KEY_INLINE_SORT_THRESHOLD, KEY_TEMP_PAGESPACE_DIR, + KEY_LEGACY_KERNEL_NAMES, MAX_CONFIG_KEY // keep it last }; @@ -220,7 +222,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] = {TYPE_INTEGER, "CpuAffinityMask", true, 0}, {TYPE_INTEGER, "TcpRemoteBufferSize", true, 8192}, // bytes {TYPE_BOOLEAN, "TcpNoNagle", false, true}, - {TYPE_BOOLEAN, "TcpLoopbackFastPath", false, true}, + {TYPE_BOOLEAN, "TcpLoopbackFastPath", false, false}, {TYPE_INTEGER, "DefaultDbCachePages", false, -1}, // pages {TYPE_INTEGER, "ConnectionTimeout", false, 180}, // seconds {TYPE_INTEGER, "DummyPacketInterval", false, 0}, // seconds @@ -275,7 +277,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] = {TYPE_STRING, "SecurityDatabase", false, nullptr}, // sec/db alias - rely on ConfigManager::getDefaultSecurityDb( {TYPE_STRING, "ServerMode", true, nullptr}, // actual value differs in boot/regular cases and set at setupDefaultConfig( {TYPE_STRING, "WireCrypt", false, nullptr}, - {TYPE_STRING, "WireCryptPlugin", false, "ChaCha, Arc4"}, + {TYPE_STRING, "WireCryptPlugin", false, "ChaCha64, ChaCha, Arc4"}, {TYPE_STRING, "KeyHolderPlugin", false, ""}, {TYPE_BOOLEAN, "RemoteAccess", false, true}, {TYPE_BOOLEAN, "IPv6V6Only", false, false}, @@ -285,6 +287,7 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] = {TYPE_BOOLEAN, "AllowEncryptedSecurityDatabase", false, false}, {TYPE_INTEGER, "StatementTimeout", false, 0}, {TYPE_INTEGER, "ConnectionIdleTimeout", false, 0}, + {TYPE_INTEGER, "OnDisconnectTriggerTimeout", false, 180}, {TYPE_INTEGER, "ClientBatchBuffer", false, 128 * 1024}, #ifdef DEV_BUILD {TYPE_STRING, "OutputRedirectionFile", true, "-"}, @@ -304,7 +307,8 @@ constexpr ConfigEntry entries[MAX_CONFIG_KEY] = {TYPE_STRING, "DataTypeCompatibility", false, nullptr}, {TYPE_BOOLEAN, "UseFileSystemCache", false, true}, {TYPE_INTEGER, "InlineSortThreshold", false, 1000}, // bytes - {TYPE_STRING, "TempTableDirectory", false, ""} + {TYPE_STRING, "TempTableDirectory", false, ""}, + {TYPE_BOOLEAN, "UseLegacyKernelObjectsNames", true, false} }; @@ -316,9 +320,15 @@ class Config : public RefCounted, public GlobalStorage static ConfigValue specialProcessing(ConfigKey key, ConfigValue val); void loadValues(const ConfigFile& file, const char* srcName); - void setupDefaultConfig(); void checkValues(); + // set default ServerMode and default values that didn't depends on ServerMode + void setupDefaultConfig(); + + // set default values that depends on ServerMode and actual values that was + // not set in config file + void fixDefaults(); + // helper check-value functions void checkIntForLoBound(ConfigKey key, SINT64 loBound, bool setDefault); void checkIntForHiBound(ConfigKey key, SINT64 hiBound, bool setDefault); @@ -434,7 +444,7 @@ class Config : public RefCounted, public GlobalStorage // CONFIG_GET_GLOBAL_XXX (CONFIG_GET_PER_DB_XXX) set of macros helps to - // create trivial static (non-static) getXXX functions. + // create trivial static (non-static) getXXX functions. // Correctness of declaration and implementation is enforced with help // of entries[XXX].is_global. @@ -606,6 +616,9 @@ class Config : public RefCounted, public GlobalStorage // set in minutes CONFIG_GET_PER_DB_KEY(unsigned int, getConnIdleTimeout, KEY_CONN_IDLE_TIMEOUT, getInt); + // set in seconds + CONFIG_GET_PER_DB_KEY(unsigned int, getOnDisconnectTrigTimeout, KEY_ON_DISCONNECT_TRIG_TIMEOUT, getInt); + CONFIG_GET_PER_DB_KEY(unsigned int, getClientBatchBuffer, KEY_CLIENT_BATCH_BUFFER, getInt); CONFIG_GET_GLOBAL_STR(getOutputRedirectionFile, KEY_OUTPUT_REDIRECTION_FILE); @@ -629,6 +642,8 @@ class Config : public RefCounted, public GlobalStorage CONFIG_GET_PER_DB_KEY(ULONG, getInlineSortThreshold, KEY_INLINE_SORT_THRESHOLD, getInt); CONFIG_GET_PER_DB_STR(getTempPageSpaceDirectory, KEY_TEMP_PAGESPACE_DIR); + + CONFIG_GET_GLOBAL_BOOL(getLegacyKernelNames, KEY_LEGACY_KERNEL_NAMES); }; // Implementation of interface to access master configuration file diff --git a/src/common/config/config_file.cpp b/src/common/config/config_file.cpp index f61e665e77e..6629d33ba9c 100644 --- a/src/common/config/config_file.cpp +++ b/src/common/config/config_file.cpp @@ -305,6 +305,7 @@ ConfigFile::LineType ConfigFile::parseLine(const char* fileName, const String& i if (par.name.isEmpty()) // not good - no key return LINE_BAD; valStart = n + 1; + par.hasValue = true; } else if (inString >= 2) // Something after the end of line return LINE_BAD; @@ -413,48 +414,88 @@ ConfigFile::LineType ConfigFile::parseLine(const char* fileName, const String& i * Substitute macro values in a string */ -bool ConfigFile::macroParse(String& value, const char* fileName) const +unsigned ConfigFile::getDirSeparatorLength(const String& value, size_t separatorPosition) const { - if (flags & CUSTOM_MACROS) - return true; + if (separatorPosition >= value.length()) + return 0; + + const char symbol = value[separatorPosition]; + if (symbol == '/') + return 1; + + if (flags & REGEXP_SUPPORT && symbol == '\\') + { + // Check forward and backward for second backslash + if (separatorPosition + 1 < value.length() && value[separatorPosition + 1] == '\\') + return 2; + if (separatorPosition > 0 && value[separatorPosition - 1] == '\\') + return 2; + } + else if (symbol == '\\') + return 1; + return 0; +} + +void ConfigFile::adjustMacroReplacePositions(const String& value, const String& macro, String::size_type& from, String::size_type& to) const +{ + if (macro.empty()) + return; + + // Remove dir separators from value string if macro already contains them at start or end + if (macro[0] == PathUtils::dir_sep && from > 0) + from -= getDirSeparatorLength(value, from - 1); + if (macro[macro.length() - 1] == PathUtils::dir_sep) + to += getDirSeparatorLength(value, to); +} + +bool ConfigFile::macroParse(String& value, const char* fileName) const +{ + String::size_type pos = 0; String::size_type subFrom; - while ((subFrom = value.find("$(")) != String::npos) + while ((subFrom = value.find("$(", pos)) != String::npos) { String::size_type subTo = value.find(")", subFrom); - if (subTo != String::npos) + if (subTo == String::npos) + return false; + + String macro; + String m = value.substr(subFrom + 2, subTo - (subFrom + 2)); + + ++subTo; + + if (!translate(fileName, m, macro)) { - String macro; - String m = value.substr(subFrom + 2, subTo - (subFrom + 2)); - if (! translate(fileName, m, macro)) + if (flags & CUSTOM_MACROS) { - return false; + pos = subTo; + continue; } - ++subTo; - // Avoid incorrect slashes in pathnames - PathUtils::fixupSeparators(value.begin()); - PathUtils::fixupSeparators(macro.begin()); + return false; + } - if (subFrom > 0 && value[subFrom - 1] == PathUtils::dir_sep && - macro.length() > 0 && macro[0] == PathUtils::dir_sep) - { - --subFrom; - } - if (subTo < value.length() && value[subTo] == PathUtils::dir_sep && - macro.length() > 0 && macro[macro.length() - 1] == PathUtils::dir_sep) + // Avoid incorrect slashes in pathnames + PathUtils::fixupSeparators(macro.begin()); + + if (flags & REGEXP_SUPPORT) + { + size_t pos = 0; + while ((pos = macro.find('\\', pos)) != String::npos) { - ++subTo; + macro.insert(pos, "\\"); + pos += 2; } - - // Now perform operation - value.replace(subFrom, subTo - subFrom, macro); } else - { - return false; - } + PathUtils::fixupSeparators(value.begin()); + + adjustMacroReplacePositions(value, macro, subFrom, subTo); + + // Now perform operation + value.replace(subFrom, subTo - subFrom, macro); + pos = subFrom + macro.length(); } return true; @@ -651,6 +692,12 @@ void ConfigFile::parse(Stream* stream) previous = ¶meters[n]; } + if (!previous) + { + badLine(streamName, "master parameter is missing before subconfig start '{'"); + return; + } + { // subconf scope SubStream subStream(stream->getFileName()); int level = 1; @@ -694,7 +741,7 @@ void ConfigFile::parse(Stream* stream) } if (level > 0) - badLine(streamName, "< missed closing bracket '}' >"); + badLine(streamName, "missed closing bracket '}'"); previous->sub = FB_NEW_POOL(getPool()) ConfigFile(getPool(), &subStream, flags); diff --git a/src/common/config/config_file.h b/src/common/config/config_file.h index 4699ff7a5aa..394f7cd8de9 100644 --- a/src/common/config/config_file.h +++ b/src/common/config/config_file.h @@ -57,6 +57,7 @@ class ConfigFile : public Firebird::AutoStorage, public Firebird::RefCounted static const USHORT NATIVE_ORDER = 0x04; static const USHORT NO_COMMENTS = 0x08; static const USHORT CUSTOM_MACROS = 0x10; + static const USHORT REGEXP_SUPPORT = 0x20; // enum to distinguish ctors enum UseText {USE_TEXT}; @@ -78,10 +79,10 @@ class ConfigFile : public Firebird::AutoStorage, public Firebird::RefCounted { Parameter(MemoryPool& p, const Parameter& par) : AutoStorage(p), name(getPool(), par.name), value(getPool(), par.value), - sub(par.sub), line(par.line) + sub(par.sub), line(par.line), hasValue(par.hasValue) { } Parameter() - : AutoStorage(), name(getPool()), value(getPool()), sub(0), line(0) + : AutoStorage(), name(getPool()), value(getPool()), sub(0), line(0), hasValue(false) { } SINT64 asInteger() const; @@ -91,6 +92,7 @@ class ConfigFile : public Firebird::AutoStorage, public Firebird::RefCounted String value; Firebird::RefPtr sub; unsigned int line; + bool hasValue; static const KeyType* generate(const Parameter* item) { @@ -143,6 +145,8 @@ class ConfigFile : public Firebird::AutoStorage, public Firebird::RefCounted void include(const char* currentFileName, const Firebird::PathName& path); bool wildCards(const char* currentFileName, const Firebird::PathName& pathPrefix, FilesArray& components); bool substituteStandardDir(const String& from, String& to) const; + void adjustMacroReplacePositions(const String& value, const String& macro, String::size_type& from, String::size_type& to) const; + unsigned getDirSeparatorLength(const String& value, size_t subFrom) const; }; #endif // CONFIG_CONFIG_FILE_H diff --git a/src/common/cvt.cpp b/src/common/cvt.cpp index 1b7a55f7c7f..397819b1d5c 100644 --- a/src/common/cvt.cpp +++ b/src/common/cvt.cpp @@ -57,6 +57,7 @@ #include "../common/dsc_proto.h" #include "../common/utils_proto.h" #include "../common/StatusArg.h" +#include "../common/status.h" #ifdef HAVE_SYS_TYPES_H @@ -140,6 +141,12 @@ static void integer_to_text(const dsc*, dsc*, Callbacks*); static void int128_to_text(const dsc*, dsc*, Callbacks* cb); static void localError(const Firebird::Arg::StatusVector&); static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err); +static void make_null_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction); + +namespace { + class RetPtr; +} +static SSHORT cvt_decompose(const char*, USHORT, RetPtr* return_value, ErrorFunction err); class DummyException {}; @@ -153,6 +160,88 @@ class DummyException {}; //#endif +namespace { + +class RetPtr +{ +public: + virtual ~RetPtr() { } + + enum lb10 {RETVAL_OVERFLOW, RETVAL_POSSIBLE_OVERFLOW, RETVAL_NO_OVERFLOW}; + + virtual USHORT maxSize() = 0; + virtual void truncate8() = 0; + virtual void truncate16() = 0; + virtual lb10 compareLimitBy10() = 0; + virtual void nextDigit(unsigned digit, unsigned base) = 0; + virtual bool isLowerLimit() = 0; + virtual void neg() = 0; +}; + +template +class RetValue : public RetPtr +{ +public: + RetValue(typename Traits::ValueType* ptr) + : return_value(ptr) + { + value = 0; + } + + ~RetValue() + { + *return_value = value; + } + + USHORT maxSize() override + { + return sizeof(typename Traits::ValueType); + } + + void truncate8() override + { + ULONG mask = 0xFFFFFFFF; + value &= mask; + } + + void truncate16() override + { + FB_UINT64 mask = 0xFFFFFFFFFFFFFFFF; + value &= mask; + } + + lb10 compareLimitBy10() override + { + if (static_cast(value) > Traits::UPPER_LIMIT_BY_10) + return RETVAL_OVERFLOW; + if (static_cast(value) == Traits::UPPER_LIMIT_BY_10) + return RETVAL_POSSIBLE_OVERFLOW; + return RETVAL_NO_OVERFLOW; + } + + void nextDigit(unsigned digit, unsigned base) override + { + value *= base; + value += digit; + } + + bool isLowerLimit() override + { + return value == Traits::LOWER_LIMIT; + } + + void neg() override + { + value = -value; + } + +protected: + typename Traits::ValueType value; + typename Traits::ValueType* return_value; +}; + +} // anonymous namespace + static const double eps_double = 1e-14; static const double eps_float = 1e-5; @@ -1063,6 +1152,15 @@ void adjustForScale(V& val, SSHORT scale, const V limit, ErrorFunction err) } +class SSHORTTraits +{ +public: + typedef SSHORT ValueType; + typedef USHORT UnsignedType; + static const USHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10; + static const SSHORT LOWER_LIMIT = MIN_SSHORT; +}; + static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** @@ -1083,8 +1181,11 @@ static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, VaryStr<20> buffer; // long enough to represent largest short in ASCII const char* p; USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); - scale -= CVT_decompose(p, length, &value, err); + { + RetValue rv(&value); + scale -= cvt_decompose(p, length, &rv, err); + } adjustForScale(value, scale, SHORT_LIMIT, err); } else { @@ -1097,6 +1198,16 @@ static SSHORT cvt_get_short(const dsc* desc, SSHORT scale, DecimalStatus decSt, return value; } + +class SLONGTraits +{ +public: + typedef SLONG ValueType; + typedef ULONG UnsignedType; + static const ULONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10; + static const SLONG LOWER_LIMIT = MIN_SLONG; +}; + SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** @@ -1210,7 +1321,9 @@ SLONG CVT_get_long(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc { USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); - scale -= CVT_decompose(p, length, &value, err); + + RetValue rv(&value); + scale -= cvt_decompose(p, length, &rv, err); } break; @@ -1789,11 +1902,12 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c ptr += sizeof(USHORT); Jrd::CharSet* charSet = cb->getToCharset(to->getCharSet()); + UCHAR maxBytesPerChar = charSet ? charSet->maxBytesPerChar() : 1; - if (len / charSet->maxBytesPerChar() < from->dsc_length) + if (len / maxBytesPerChar < from->dsc_length) { cb->err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << - Arg::Gds(isc_trunc_limits) << Arg::Num(len / charSet->maxBytesPerChar()) << + Arg::Gds(isc_trunc_limits) << Arg::Num(len / maxBytesPerChar) << Arg::Num(from->dsc_length)); } @@ -2081,7 +2195,7 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c } -void CVT_conversion_error(const dsc* desc, ErrorFunction err) +void CVT_conversion_error(const dsc* desc, ErrorFunction err, const Exception* original) { /************************************** * @@ -2107,6 +2221,8 @@ void CVT_conversion_error(const dsc* desc, ErrorFunction err) message = "ARRAY"; else if (desc->dsc_dtype == dtype_boolean) message = "BOOLEAN"; + else if (desc->dsc_dtype == dtype_dbkey) + message = "DBKEY"; else { // CVC: I don't have access here to JRD_get_thread_data())->tdbb_status_vector @@ -2126,6 +2242,18 @@ void CVT_conversion_error(const dsc* desc, ErrorFunction err) const USHORT length = CVT_make_string(desc, ttype_ascii, &p, &s, sizeof(s), 0, localError); message.assign(p, length); + + // Convert to \xDD surely non-printable characters + for (FB_SIZE_T n = 0; n < message.getCount(); ++n) + { + if (message[n] < ' ') + { + string hex; + hex.printf("#x%02x", UCHAR(message[n])); + message.replace(n, 1, hex); + n += (hex.length() - 1); + } + } } /* catch (status_exception& e) @@ -2148,7 +2276,11 @@ void CVT_conversion_error(const dsc* desc, ErrorFunction err) } //// TODO: Need access to transliterate here to convert message to metadata charset. - err(Arg::Gds(isc_convert_error) << message); + Arg::StatusVector vector; + if (original) + vector.assign(*original); + vector << Arg::Gds(isc_convert_error) << message; + err(vector); } @@ -2297,13 +2429,13 @@ static void datetime_to_text(const dsc* from, dsc* to, Callbacks* cb) } -void CVT_make_null_string(const dsc* desc, - USHORT to_interp, - const char** address, - vary* temp, - USHORT length, - DecimalStatus decSt, - ErrorFunction err) +void make_null_string(const dsc* desc, + USHORT to_interp, + const char** address, + vary* temp, + USHORT length, + DecimalStatus decSt, + ErrorFunction err) { /************************************** * @@ -2336,6 +2468,12 @@ void CVT_make_null_string(const dsc* desc, fb_assert(temp->vary_length == len); temp->vary_string[len] = 0; + + for (USHORT n = 0; n < len; ++n) + { + if (!temp->vary_string[n]) // \0 in the middle of a string + CVT_conversion_error(desc, err); + } } @@ -2454,22 +2592,6 @@ double CVT_power_of_ten(const int scale) } -class RetPtr -{ -public: - virtual ~RetPtr() { } - - enum lb10 {RETVAL_OVERFLOW, RETVAL_POSSIBLE_OVERFLOW, RETVAL_NO_OVERFLOW}; - - virtual USHORT maxSize() = 0; - virtual void truncate8() = 0; - virtual void truncate16() = 0; - virtual lb10 compareLimitBy10() = 0; - virtual void nextDigit(unsigned digit, unsigned base) = 0; - virtual bool isLowerLimit() = 0; - virtual void neg() = 0; -}; - static void hex_to_value(const char*& string, const char* end, RetPtr* retValue); static SSHORT cvt_decompose(const char* string, @@ -2697,78 +2819,38 @@ static SSHORT cvt_decompose(const char* string, } -template -class RetValue : public RetPtr +class I128Traits { public: - RetValue(typename Traits::ValueType* ptr) - : return_value(ptr) - { - value = 0; - } - - ~RetValue() - { - *return_value = value; - } + typedef Int128 ValueType; + typedef Int128 UnsignedType; // To be fixed when adding int256 + static const CInt128 UPPER_LIMIT_BY_10; + static const CInt128 LOWER_LIMIT; +}; - USHORT maxSize() - { - return sizeof(typename Traits::ValueType); - } +const CInt128 I128Traits::UPPER_LIMIT_BY_10(CInt128(CInt128::MkMax) / 10); +const CInt128 I128Traits::LOWER_LIMIT(CInt128::MkMin); - void truncate8() - { - ULONG mask = 0xFFFFFFFF; - value &= mask; - } +class RetI128 : public RetValue +{ +public: + RetI128(Int128* v) + : RetValue(v) + { } - void truncate16() + lb10 compareLimitBy10() override { - FB_UINT64 mask = 0xFFFFFFFFFFFFFFFF; - value &= mask; - } + lb10 rc = RetValue::compareLimitBy10(); + if (rc != RETVAL_NO_OVERFLOW) + return rc; - lb10 compareLimitBy10() - { - if (value > Traits::UPPER_LIMIT_BY_10) + if (value.sign() < 0) return RETVAL_OVERFLOW; - if (value == Traits::UPPER_LIMIT_BY_10) - return RETVAL_POSSIBLE_OVERFLOW; return RETVAL_NO_OVERFLOW; } - - void nextDigit(unsigned digit, unsigned base) - { - value *= base; - value += digit; - } - - bool isLowerLimit() - { - return value == Traits::LOWER_LIMIT; - } - - void neg() - { - value = -value; - } - -private: - typename Traits::ValueType value; - typename Traits::ValueType* return_value; -}; - - -class SSHORTTraits -{ -public: - typedef SSHORT ValueType; - static const SSHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10; - static const SSHORT LOWER_LIMIT = MIN_SSHORT; }; -SSHORT CVT_decompose(const char* str, USHORT len, SSHORT* val, ErrorFunction err) +SSHORT CVT_decompose(const char* str, USHORT len, Int128* val, ErrorFunction err) { /************************************** * @@ -2782,93 +2864,19 @@ SSHORT CVT_decompose(const char* str, USHORT len, SSHORT* val, ErrorFunction err * **************************************/ - RetValue value(val); - return cvt_decompose(str, len, &value, err); -} - - -class SLONGTraits -{ -public: - typedef SLONG ValueType; - static const SLONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10; - static const SLONG LOWER_LIMIT = MIN_SLONG; -}; - -SSHORT CVT_decompose(const char* str, USHORT len, SLONG* val, ErrorFunction err) -{ -/************************************** - * - * d e c o m p o s e - * - ************************************** - * - * Functional description - * Decompose a numeric string in mantissa and exponent, - * or if it is in hexadecimal notation. - * - **************************************/ - RetValue value(val); + RetI128 value(val); return cvt_decompose(str, len, &value, err); } -class SINT64Traits +Int128 CVT_hex_to_int128(const char* str, USHORT len) { -public: - typedef SINT64 ValueType; - static const SINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10; - static const SINT64 LOWER_LIMIT = MIN_SINT64; -}; + Int128 val; + RetValue value(&val); + hex_to_value(str, str + len, &value); -SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err) -{ -/************************************** - * - * d e c o m p o s e - * - ************************************** - * - * Functional description - * Decompose a numeric string in mantissa and exponent, - * or if it is in hexadecimal notation. - * - **************************************/ - - RetValue value(val); - return cvt_decompose(str, len, &value, err); -} - - -class I128Traits -{ -public: - typedef Int128 ValueType; - static const CInt128 UPPER_LIMIT_BY_10; - static const CInt128 LOWER_LIMIT; -}; - -const CInt128 I128Traits::UPPER_LIMIT_BY_10(CInt128(CInt128::MkMax) / 10); -const CInt128 I128Traits::LOWER_LIMIT(CInt128::MkMin); - -SSHORT CVT_decompose(const char* str, USHORT len, Int128* val, ErrorFunction err) -{ -/************************************** - * - * d e c o m p o s e - * - ************************************** - * - * Functional description - * Decompose a numeric string in mantissa and exponent, - * or if it is in hexadecimal notation. - * - **************************************/ - - - RetValue value(val); - return cvt_decompose(str, len, &value, err); + return val; } @@ -2947,6 +2955,15 @@ USHORT CVT_get_string_ptr_common(const dsc* desc, USHORT* ttype, UCHAR** address } +static void checkForIndeterminant(const Exception& e, const dsc* desc, ErrorFunction err) +{ + StaticStatusVector st; + e.stuffException(st); + if (fb_utils::containsErrorCode(st.begin(), isc_decfloat_invalid_operation)) + CVT_conversion_error(desc, err, &e); +} + + static inline void SINT64_to_SQUAD(const SINT64 input, const SQUAD& value) { ((SLONG*) &value)[LOW_WORD] = (SLONG) (input & 0xffffffff); @@ -2995,8 +3012,16 @@ Decimal64 CVT_get_dec64(const dsc* desc, DecimalStatus decSt, ErrorFunction err) case dtype_varying: case dtype_cstring: case dtype_text: - CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); - return d64.set(buffer.vary_string, decSt); + make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); + try + { + return d64.set(buffer.vary_string, decSt); + } + catch (const Exception& e) + { + checkForIndeterminant(e, desc, err); + throw; + } case dtype_real: return d64.set(*((float*) p), decSt); @@ -3071,8 +3096,16 @@ Decimal128 CVT_get_dec128(const dsc* desc, DecimalStatus decSt, ErrorFunction er case dtype_varying: case dtype_cstring: case dtype_text: - CVT_make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); - return d128.set(buffer.vary_string, decSt); + make_null_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer) - 1, decSt, err); + try + { + return d128.set(buffer.vary_string, decSt); + } + catch (const Exception& e) + { + checkForIndeterminant(e, desc, err); + throw; + } case dtype_real: return d128.set(*((float*) p), decSt); @@ -3110,15 +3143,16 @@ Int128 CVT_get_int128(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorF { /************************************** * - * C V T _ g e t _ d e c 1 2 8 + * C V T _ g e t _ i n t 1 2 8 * ************************************** * * Functional description - * Convert something arbitrary to a DecFloat(34) / (128 bit). + * Convert something arbitrary to an INT128 (128 bit integer) + * of given scale. * **************************************/ - VaryStr<1024> buffer; // represents unreasonably long decfloat literal in ASCII + VaryStr<1024> buffer; // represents unreasonably INT128 literal in ASCII Int128 int128; Decimal128 tmp; double d, eps; @@ -3300,6 +3334,15 @@ const UCHAR* CVT_get_bytes(const dsc* desc, unsigned& size) } +class SINT64Traits +{ +public: + typedef SINT64 ValueType; + typedef FB_UINT64 UnsignedType; + static const FB_UINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10; + static const SINT64 LOWER_LIMIT = MIN_SINT64; +}; + SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) { /************************************** @@ -3355,8 +3398,12 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc { USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); + SINT64 i64; - scale -= CVT_decompose(p, length, &i64, err); + { + RetValue rv(&i64); + scale -= cvt_decompose(p, length, &rv, err); + } SINT64_to_SQUAD(i64, value); } break; @@ -3497,7 +3544,9 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu { USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); - scale -= CVT_decompose(p, length, &value, err); + + RetValue rv(&value); + scale -= cvt_decompose(p, length, &rv, err); } break; @@ -3538,7 +3587,7 @@ static void hex_to_value(const char*& string, const char* end, RetPtr* retValue) * Functional description * Convert a hex string to a numeric value. This code only * converts a hex string into a numeric value, and the - * biggest hex string supported must fit into a BIGINT. + * size of biggest hex string depends upon RetPtr. * *************************************/ { diff --git a/src/common/cvt.h b/src/common/cvt.h index f656194fbc8..924ace42cbb 100644 --- a/src/common/cvt.h +++ b/src/common/cvt.h @@ -85,7 +85,7 @@ class Int128; } // namespace Firebird -void CVT_conversion_error(const dsc*, ErrorFunction); +void CVT_conversion_error(const dsc*, ErrorFunction, const Firebird::Exception* = nullptr); double CVT_power_of_ten(const int); SLONG CVT_get_long(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); bool CVT_get_boolean(const dsc*, ErrorFunction); @@ -93,13 +93,10 @@ double CVT_get_double(const dsc*, Firebird::DecimalStatus, ErrorFunction, bool* Firebird::Decimal64 CVT_get_dec64(const dsc*, Firebird::DecimalStatus, ErrorFunction); Firebird::Decimal128 CVT_get_dec128(const dsc*, Firebird::DecimalStatus, ErrorFunction); Firebird::Int128 CVT_get_int128(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); +Firebird::Int128 CVT_hex_to_int128(const char* str, USHORT len); USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction); -void CVT_make_null_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction); void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*); void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction); -SSHORT CVT_decompose(const char*, USHORT, SSHORT*, ErrorFunction); -SSHORT CVT_decompose(const char*, USHORT, SLONG*, ErrorFunction); -SSHORT CVT_decompose(const char*, USHORT, SINT64*, ErrorFunction); SSHORT CVT_decompose(const char*, USHORT, Firebird::Int128*, ErrorFunction); USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction); USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*); diff --git a/src/common/db_alias.cpp b/src/common/db_alias.cpp index 6e0a6802ab4..1a5890da70c 100644 --- a/src/common/db_alias.cpp +++ b/src/common/db_alias.cpp @@ -59,19 +59,6 @@ namespace const char* const ALIAS_FILE = "databases.conf"; - void replace_dir_sep(PathName& s) - { - const char correct_dir_sep = PathUtils::dir_sep; - const char incorrect_dir_sep = (correct_dir_sep == '/') ? '\\' : '/'; - for (char* itr = s.begin(); itr < s.end(); ++itr) - { - if (*itr == incorrect_dir_sep) - { - *itr = correct_dir_sep; - } - } - } - struct CalcHash { static FB_SIZE_T chash(FB_SIZE_T sum, FB_SIZE_T hashSize) @@ -291,11 +278,11 @@ namespace const ConfigFile::Parameter* par = ¶ms[n]; PathName file(par->value.ToPathName()); - replace_dir_sep(file); - if (PathUtils::isRelative(file)) + PathUtils::fixupSeparators(file); + if (PathUtils::isRelative(file) && !ISC_check_if_remote(file, false)) { gds__log("Value %s configured for alias %s " - "is not a fully qualified path name, ignored", + "is not a fully qualified path name nor remote server reference, ignored", file.c_str(), par->name.c_str()); continue; } @@ -343,7 +330,7 @@ namespace } PathName correctedAlias(par->name.ToPathName()); - replace_dir_sep(correctedAlias); + PathUtils::fixupSeparators(correctedAlias); AliasName* alias = aliasHash.lookup(correctedAlias); if (alias) { @@ -423,12 +410,12 @@ static inline bool hasSeparator(const PathName& name) return false; } -// Search for 'alias' in databases.conf, return its value in 'file' if found. Else set file to alias. +// Search for 'alias' in databases.conf, return its value in 'file' if found. // Returns true if alias is found in databases.conf. -static bool resolveAlias(const PathName& alias, PathName& file, RefPtr* config) +bool resolveAlias(const PathName& alias, PathName& file, RefPtr* config) { PathName correctedAlias = alias; - replace_dir_sep(correctedAlias); + PathUtils::fixupSeparators(correctedAlias); AliasName* a = aliasesConf().aliasHash.lookup(correctedAlias); DbName* db = a ? a->database : NULL; @@ -557,7 +544,12 @@ bool expandDatabaseName(Firebird::PathName alias, { Id* i = aliasesConf().idHash.lookup(id); if (i) - db = i->db; + { + UCharBuffer oldId; + os_utils::getUniqueFileId(i->db->name.c_str(), oldId); + if (oldId == id) // Yes, that's really same file, and we should use same config + db = i->db; + } } } #endif diff --git a/src/common/db_alias.h b/src/common/db_alias.h index bcaf32cbea2..0718935b280 100644 --- a/src/common/db_alias.h +++ b/src/common/db_alias.h @@ -27,6 +27,10 @@ #include "../common/classes/RefCounted.h" #include "../common/config/config.h" +bool resolveAlias(const Firebird::PathName& alias, + Firebird::PathName& file, + Firebird::RefPtr* config); + bool expandDatabaseName(Firebird::PathName alias, Firebird::PathName& file, Firebird::RefPtr* config); diff --git a/src/common/dsc.cpp b/src/common/dsc.cpp index d2b10f46c61..44f3249506c 100644 --- a/src/common/dsc.cpp +++ b/src/common/dsc.cpp @@ -64,15 +64,15 @@ static const USHORT _DSC_convert_to_text_length[DTYPE_TYPE_MAX] = 9, // dtype_blob FFFF:FFFF 9, // dtype_array FFFF:FFFF 20, // dtype_int64 -9223372036854775808 - 0, // dtype_dbkey + 8, // dtype_dbkey 5, // dtype_boolean 23, // dtype_dec64 1 + 1 + 1 + 1 + 16(34) + 3(4) 42, // dtype_dec128 +- . e +- coeff + exp 47, // dtype_int128 14 + TimeZoneUtil::MAX_LEN, // dtype_sql_time_tz HH:MM:SS.MMMM +NN:NN - 25 + TimeZoneUtil::MAX_LEN, // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN + 26 + TimeZoneUtil::MAX_LEN, // dtype_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN 14 + TimeZoneUtil::MAX_LEN, // dtype_ex_time_tz HH:MM:SS.MMMM +NN:NN - 25 + TimeZoneUtil::MAX_LEN // dtype_ex_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN + 26 + TimeZoneUtil::MAX_LEN // dtype_ex_timestamp_tz YYYY-MM-DD HH:MM:SS.MMMM +NN:NN }; // Unimplemented names are in lowercase & @@ -104,8 +104,8 @@ static const TEXT* const DSC_dtype_names[] = "DECFLOAT(16)", "DECFLOAT(34)", "INT128", - "TIME WITH TIMEZONE", - "TIMESTAMP WITH TIMEZONE" + "TIME WITH TIME ZONE", + "TIMESTAMP WITH TIME ZONE" }; @@ -834,7 +834,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128, dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, @@ -844,7 +844,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, - DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int64, + DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128, dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT}, @@ -942,7 +942,7 @@ const BYTE DSC_multiply_result[DTYPE_TYPE_MAX][DTYPE_TYPE_MAX] = // dtype_int64 {dtype_unknown, dtype_double, dtype_double, dtype_double, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, - dtype_int64, dtype_int64, DTYPE_CANNOT, dtype_double, + dtype_int128, dtype_int128, DTYPE_CANNOT, dtype_double, dtype_double, dtype_d_float, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, DTYPE_CANNOT, dtype_int128, DTYPE_CANNOT, DTYPE_CANNOT, dtype_dec128, dtype_dec128, diff --git a/src/common/dsc.h b/src/common/dsc.h index 267bb71dbf9..689c519f5e3 100644 --- a/src/common/dsc.h +++ b/src/common/dsc.h @@ -138,6 +138,11 @@ typedef struct dsc return dsc_dtype == dtype_blob || dsc_dtype == dtype_quad; } + bool isBoolean() const + { + return dsc_dtype == dtype_boolean; + } + bool isExact() const { return dsc_dtype == dtype_int128 || dsc_dtype == dtype_int64 || @@ -146,12 +151,12 @@ typedef struct dsc bool isNumeric() const { - return (dsc_dtype >= dtype_byte && dsc_dtype <= dtype_d_float) || dsc_dtype == dtype_int64; + return DTYPE_IS_NUMERIC(dsc_dtype); } bool isText() const { - return dsc_dtype >= dtype_text && dsc_dtype <= dtype_varying; + return DTYPE_IS_TEXT(dsc_dtype); } bool isDbKey() const @@ -186,7 +191,7 @@ typedef struct dsc bool isDecFloat() const { - return dsc_dtype == dtype_dec128 || dsc_dtype == dtype_dec64; + return DTYPE_IS_DECFLOAT(dsc_dtype); } bool isInt128() const diff --git a/src/common/fb_exception.cpp b/src/common/fb_exception.cpp index bb554132e4f..4cc407178d9 100644 --- a/src/common/fb_exception.cpp +++ b/src/common/fb_exception.cpp @@ -202,23 +202,25 @@ const char* LongJump::what() const throw() // ********************************* system_error *************************** -system_error::system_error(const char* syscall, int error_code) : +system_error::system_error(const char* syscall, const char* arg, int error_code) : status_exception(), errorCode(error_code) { Arg::Gds temp(isc_sys_request); temp << Arg::Str(syscall); temp << SYS_ERR(errorCode); + if (arg) + temp << Arg::Gds(isc_random) << arg; set_status(temp.value()); } void system_error::raise(const char* syscall, int error_code) { - throw system_error(syscall, error_code); + throw system_error(syscall, nullptr, error_code); } void system_error::raise(const char* syscall) { - throw system_error(syscall, getSystemError()); + throw system_error(syscall, nullptr, getSystemError()); } int system_error::getSystemError() @@ -232,8 +234,8 @@ int system_error::getSystemError() // ********************************* system_call_failed *************************** -system_call_failed::system_call_failed(const char* syscall, int error_code) : - system_error(syscall, error_code) +system_call_failed::system_call_failed(const char* syscall, const char* arg, int error_code) : + system_error(syscall, arg, error_code) { // NS: something unexpected has happened. Log the error to log file // In the future we may consider terminating the process even in PROD_BUILD @@ -247,12 +249,23 @@ system_call_failed::system_call_failed(const char* syscall, int error_code) : void system_call_failed::raise(const char* syscall, int error_code) { - throw system_call_failed(syscall, error_code); + throw system_call_failed(syscall, nullptr, error_code); } void system_call_failed::raise(const char* syscall) { - throw system_call_failed(syscall, getSystemError()); + throw system_call_failed(syscall, nullptr, getSystemError()); +} + + +void system_call_failed::raise(const char* syscall, const char* arg, int error_code) +{ + throw system_call_failed(syscall, arg, error_code); +} + +void system_call_failed::raise(const char* syscall, const char* arg) +{ + raise(syscall, arg, getSystemError()); } // ********************************* fatal_exception ******************************* diff --git a/src/common/file_params.h b/src/common/file_params.h index 0cd4ecc1c4f..effea207142 100644 --- a/src/common/file_params.h +++ b/src/common/file_params.h @@ -44,6 +44,10 @@ static const char* const SNAPSHOTS_FILE = "fb_snap_%s"; static const char* const TRACE_FILE = "fb" COMMON_FILE_PREFIX "_trace"; static const char* const USER_MAP_FILE = "fb" COMMON_FILE_PREFIX "_user_mapping"; +static const char* const SHARED_EVENT = "fb" COMMON_FILE_PREFIX "_process%u_signal%d"; +static const char* const SHARED_EVENT_OLD = "_firebird_process%u_signal%d"; + +static const char* const FB_TRACE_LOG_MUTEX = "fb_trace_log_mutex"; #ifdef UNIX static const char* const INIT_FILE = "fb_init"; diff --git a/src/common/intlobj_new.h b/src/common/intlobj_new.h index 5ce16a6141e..8ba33c079ad 100644 --- a/src/common/intlobj_new.h +++ b/src/common/intlobj_new.h @@ -57,9 +57,15 @@ typedef USHORT (*pfn_INTL_keylength) (texttype* tt, USHORT len); /* Types of the keys which may be returned by str2key routine */ -#define INTL_KEY_SORT 0 /* Full sort key */ -#define INTL_KEY_PARTIAL 1 /* Starting portion of sort key for equality class */ -#define INTL_KEY_UNIQUE 2 /* Full key for the equality class of the string */ +#define INTL_KEY_SORT 0 /* Full sort key */ +#define INTL_KEY_PARTIAL 1 /* Starting portion of sort key for equality class */ +#define INTL_KEY_UNIQUE 2 /* Full key for the equality class of the string */ +#define INTL_KEY_MULTI_STARTING 3 /* Multiple starting keys */ + +/* INTL_KEY_MULTI_STARTING format: + key ::= { }... + key_length ::= +*/ /* Returned value of INTL_BAD_KEY_LENGTH means that key error happened during key construction. When partial key is requested returned string should @@ -98,6 +104,8 @@ typedef ULONG (*pfn_INTL_str2case) ( /* Places exactly texttype_canonical_width number of bytes into dst for each character from src. + src (srcLen) string may be a truncated string and in this case this function must consider + it as valid and process only the fully read characters. Returns INTL_BAD_STR_LENGTH in case of error or number of characters processed if successful. */ typedef ULONG (*pfn_INTL_canonical) ( @@ -128,6 +136,8 @@ typedef void (*pfn_INTL_tt_destroy) (texttype* tt); (char, case, accent) which is case-insensitive, but accent-sensitive */ +#define TEXTTYPE_MULTI_STARTING_KEY 8 /* Supports INTL_KEY_MULTI_STARTING */ + struct texttype { diff --git a/src/common/isc_file.cpp b/src/common/isc_file.cpp index d057f757099..824ce72536e 100644 --- a/src/common/isc_file.cpp +++ b/src/common/isc_file.cpp @@ -364,7 +364,11 @@ bool ISC_analyze_protocol(const char* protocol, tstring& expanded_name, tstring& node_name.erase(); const PathName prefix = PathName(protocol) + "://"; - if (expanded_name.find(prefix) != 0) + + if (prefix.length() > expanded_name.length()) + return false; + + if (IgnoreCaseComparator::compare(prefix.c_str(), expanded_name.c_str(), prefix.length()) != 0) return false; PathName savedName = expanded_name; diff --git a/src/common/isc_s_proto.h b/src/common/isc_s_proto.h index a5cc34bb235..88f0da8e31e 100644 --- a/src/common/isc_s_proto.h +++ b/src/common/isc_s_proto.h @@ -178,7 +178,7 @@ class MemoryHeader #define USE_FCNTL #endif -class CountedFd; +class SharedFileInfo; class FileLock { @@ -186,8 +186,8 @@ class FileLock enum LockMode {FLM_EXCLUSIVE, FLM_TRY_EXCLUSIVE, FLM_SHARED, FLM_TRY_SHARED}; typedef void InitFunction(int fd); - explicit FileLock(const char* fileName, InitFunction* init = NULL); // main ctor - FileLock(const FileLock* main, int s); // creates additional lock for existing file + + explicit FileLock(const char* fileName, InitFunction* init = NULL); ~FileLock(); // Main function to lock file @@ -196,24 +196,18 @@ class FileLock // Alternative locker is using status vector to report errors bool setlock(Firebird::CheckStatusWrapper* status, const LockMode mode); - // unlocking can only put error into log file - we can't throw in dtors + // Unlocking can only put error into log file - we can't throw in dtors void unlock(); + // Obvious access to file descriptor int getFd(); -private: enum LockLevel {LCK_NONE, LCK_SHARED, LCK_EXCL}; +private: + Firebird::RefPtr file; + InitFunction* initFunction; LockLevel level; - CountedFd* oFile; -#ifdef USE_FCNTL - int lStart; -#endif - class CountedRWLock* rwcl; // Due to order of init in ctor rwcl must go after fd & start - - Firebird::string getLockId(); - class CountedRWLock* getRw(); - void rwUnlock(); }; #endif // UNIX @@ -252,9 +246,8 @@ class SharedMemoryBase #endif bool remapFile(Firebird::CheckStatusWrapper* status, ULONG newSize, bool truncateFlag); void removeMapFile(); -#ifdef UNIX - void internalUnmap(); -#endif + static void unlinkFile(const TEXT* expanded_filename) noexcept; + Firebird::PathName getMapFileName(); void mutexLock(); bool mutexLockCond(); @@ -284,10 +277,10 @@ class SharedMemoryBase ULONG sh_mem_length_mapped; #ifdef WIN_NT - void* sh_mem_handle; - void* sh_mem_object; - void* sh_mem_interest; - void* sh_mem_hdr_object; + HANDLE sh_mem_handle; // file handle + HANDLE sh_mem_object; // file mapping + HANDLE sh_mem_interest; // event + HANDLE sh_mem_hdr_object; // file mapping ULONG* sh_mem_hdr_address; #endif TEXT sh_mem_name[MAXPATHLEN]; @@ -302,6 +295,7 @@ class SharedMemoryBase bool sh_mem_unlink; #endif void unlinkFile(); + void internalUnmap(); public: enum MemoryTypes diff --git a/src/common/isc_sync.cpp b/src/common/isc_sync.cpp old mode 100644 new mode 100755 index 74fc797bd6e..c3584b61338 --- a/src/common/isc_sync.cpp +++ b/src/common/isc_sync.cpp @@ -68,6 +68,7 @@ #include "../common/classes/GenericMap.h" #include "../common/classes/RefMutex.h" #include "../common/classes/array.h" +#include "../common/classes/condition.h" #include "../common/StatusHolder.h" static int process_id; @@ -131,6 +132,7 @@ static size_t getpagesize() #include #include +#include #endif @@ -141,87 +143,26 @@ static bool event_blocked(const event_t* event, const SLONG value); #ifdef UNIX -static GlobalPtr openFdInit; +#ifdef FILELOCK_DEBUG -class DevNode -{ -public: - DevNode() - : f_dev(0), f_ino(0) - { } - - DevNode(dev_t d, ino_t i) - : f_dev(d), f_ino(i) - { } - - DevNode(const DevNode& v) - : f_dev(v.f_dev), f_ino(v.f_ino) - { } - - dev_t f_dev; - ino_t f_ino; - - bool operator==(const DevNode& v) const - { - return f_dev == v.f_dev && f_ino == v.f_ino; - } - - bool operator>(const DevNode& v) const - { - return f_dev > v.f_dev ? true : - f_dev < v.f_dev ? false : - f_ino > v.f_ino; - } - - const DevNode& operator=(const DevNode& v) - { - f_dev = v.f_dev; - f_ino = v.f_ino; - return *this; - } -}; - -namespace Firebird { +#include -class CountedRWLock +void DEB_FLOCK(const char* format, ...) { -public: - CountedRWLock() - : sharedAccessCounter(0) - { } - RWLock rwlock; - AtomicCounter cnt; - Mutex sharedAccessMutex; - int sharedAccessCounter; -}; - -class CountedFd -{ -public: - explicit CountedFd(int f) - : fd(f), useCount(0) - { } + va_list params; + va_start(params, format); + ::vfprintf(stderr, format, params); + va_end(params); +} - ~CountedFd() - { - fb_assert(useCount == 0); - } +#else - int fd; - int useCount; +void DEB_FLOCK(const char* format, ...) { } -private: - CountedFd(const CountedFd&); - const CountedFd& operator=(const CountedFd&); -}; - -} // namespace Firebird +#endif //FILELOCK_DEBUG namespace { - typedef GenericMap > > RWLocks; - GlobalPtr rwlocks; - GlobalPtr rwlocksMutex; #ifdef USE_FCNTL const char* NAME = "fcntl"; #else @@ -252,6 +193,44 @@ namespace { FileLock* lock; }; + class DevNode + { + public: + DevNode() + : f_dev(0), f_ino(0) + { } + + DevNode(dev_t d, ino_t i) + : f_dev(d), f_ino(i) + { } + + DevNode(const DevNode& v) + : f_dev(v.f_dev), f_ino(v.f_ino) + { } + + dev_t f_dev; + ino_t f_ino; + + bool operator==(const DevNode& v) const + { + return f_dev == v.f_dev && f_ino == v.f_ino; + } + + bool operator>(const DevNode& v) const + { + return f_dev > v.f_dev ? true : + f_dev < v.f_dev ? false : + f_ino > v.f_ino; + } + + const DevNode& operator=(const DevNode& v) + { + f_dev = v.f_dev; + f_ino = v.f_ino; + return *this; + } + }; + DevNode getNode(const char* name) { struct STAT statistics; @@ -278,80 +257,231 @@ namespace { return DevNode(statistics.st_dev, statistics.st_ino); } + GlobalPtr openFdInit; + } // anonymous namespace -typedef GenericMap > > FdNodes; -static GlobalPtr fdNodesMutex; -static GlobalPtr fdNodes; +namespace Firebird { -FileLock::FileLock(const char* fileName, InitFunction* init) - : level(LCK_NONE), oFile(NULL), -#ifdef USE_FCNTL - lStart(0), -#endif - rwcl(NULL) +class SharedFileInfo : public RefCounted { - MutexLockGuard g(fdNodesMutex, FB_FUNCTION); + SharedFileInfo(int f, const DevNode& id) + : counter(0), threadId(0), fd(f), devNode(id) + { } + + ~SharedFileInfo() + { + fb_assert(sharedFilesMutex->locked()); + fb_assert(counter == 0); - DevNode id(getNode(fileName)); + DEB_FLOCK("~ %p\n", this); + sharedFiles->remove(devNode); + close(fd); + } - if (id.f_ino) +public: + static SharedFileInfo* get(const char* fileName) { - CountedFd** got = fdNodes->get(id); - if (got) + DevNode id(getNode(fileName)); + + MutexLockGuard g(sharedFilesMutex, FB_FUNCTION); + + SharedFileInfo* file = nullptr; + if (id.f_ino) + { + SharedFileInfo** got = sharedFiles->get(id); + if (got) + { + file = *got; + DEB_FLOCK("'%s': in map %p\n", fileName, file); + file->assertNonZero(); + } + } + + if (!file) { - oFile = *got; + int fd = os_utils::openCreateSharedFile(fileName, 0); + id = getNode(fd); + file = FB_NEW_POOL(*getDefaultMemoryPool()) SharedFileInfo(fd, id); + SharedFileInfo** put = sharedFiles->put(id); + fb_assert(put); + *put = file; + DEB_FLOCK("'%s': new %p\n", fileName, file); } + + file->addRef(); + return file; } - if (!oFile) + int release() const override { - int fd = os_utils::openCreateSharedFile(fileName, 0); - oFile = FB_NEW_POOL(*getDefaultMemoryPool()) CountedFd(fd); - CountedFd** put = fdNodes->put(getNode(fd)); - fb_assert(put); - *put = oFile; + // Release should be executed under mutex protection + // in order to modify reference counter & map atomically + MutexLockGuard guard(sharedFilesMutex, FB_FUNCTION); + + return RefCounted::release(); + } - if (init) + int lock(bool shared, bool wait, FileLock::InitFunction* init) + { + MutexEnsureUnlock guard(mutex, FB_FUNCTION); + if (wait) + guard.enter(); + else if (!guard.tryEnter()) + return -1; + + DEB_FLOCK("%d lock %p %c%c\n", Thread::getId(), this, shared ? 's' : 'X', wait ? 'W' : 't'); + + while (counter != 0) // file lock belongs to our process { - init(fd); + // check for compatible locks + if (shared && counter > 0) + { + // one more shared lock + ++counter; + DEB_FLOCK("%d fast %p c=%d\n", Thread::getId(), this, counter); + return 0; + } + if ((!shared) && counter < 0 && threadId == Thread::getId()) + { + // recursive excl lock + --counter; + DEB_FLOCK("%d fast %p c=%d\n", Thread::getId(), this, counter); + return 0; + } + + // non compatible lock needed + // wait for another thread to release a lock + if (!wait) + { + DEB_FLOCK("%d failed internally %p c=%d rc -1\n", Thread::getId(), this, counter); + return -1; + } + + DEB_FLOCK("%d wait %p c=%d\n", Thread::getId(), this, counter); + waitOn.wait(mutex); } + + // Take lock on a file + fb_assert(counter == 0); +#ifdef USE_FCNTL + struct FLOCK lock; + lock.l_type = shared ? F_RDLCK : F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + if (fcntl(fd, wait ? F_SETLKW : F_SETLK, &lock) == -1) + { + int rc = errno; + if (!wait && (rc == EACCES || rc == EAGAIN)) + rc = -1; +#else + if (flock(fd, (shared ? LOCK_SH : LOCK_EX) | (wait ? 0 : LOCK_NB))) + { + int rc = errno; + if (!wait && (rc == EWOULDBLOCK)) + rc = -1; +#endif + DEB_FLOCK("%d failed on file %p c=%d rc %d\n", Thread::getId(), this, counter, rc); + return rc; + } + + if (!shared) + { + threadId = Thread::getId(); + + // call init() when needed + if (init && !shared) + init(fd); + } + + // mark lock as taken + counter = shared ? 1 : -1; + DEB_FLOCK("%d filelock %p c=%d\n", Thread::getId(), this, counter); + return 0; } - rwcl = getRw(); - ++(oFile->useCount); -} + void unlock() + { + fb_assert(counter != 0); + MutexEnsureUnlock guard(mutex, FB_FUNCTION); + guard.enter(); -FileLock::~FileLock() -{ - unlock(); + DEB_FLOCK("%d UNlock %p c=%d\n", Thread::getId(), this, counter); - { // guard scope - MutexLockGuard g(rwlocksMutex, FB_FUNCTION); + if (counter < 0) + ++counter; + else + --counter; - if (--(rwcl->cnt) == 0) + if (counter != 0) { - rwlocks->remove(getLockId()); - delete rwcl; + DEB_FLOCK("%d done %p c=%d\n", Thread::getId(), this, counter); + return; } - } - { // guard scope - MutexLockGuard g(fdNodesMutex, FB_FUNCTION); - if (--(oFile->useCount) == 0) + // release file lock +#ifdef USE_FCNTL + struct FLOCK lock; + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 1; + + if (fcntl(fd, F_SETLK, &lock) != 0) + { +#else + if (flock(fd, LOCK_UN) != 0) { - fdNodes->remove(getNode(oFile->fd)); - close(oFile->fd); - delete oFile; +#endif + LocalStatus ls; + CheckStatusWrapper local(&ls); + error(&local, NAME, errno); + iscLogStatus("Unlock error", &local); } + + DEB_FLOCK("%d file-done %p\n", Thread::getId(), this); + waitOn.notifyAll(); } + + int getFd() + { + return fd; + } + +private: + typedef GenericMap > > SharedFiles; + static GlobalPtr sharedFiles; + static GlobalPtr sharedFilesMutex; + + Condition waitOn; + Mutex mutex; + int counter; + ThreadId threadId; + int fd; + DevNode devNode; +}; + +GlobalPtr SharedFileInfo::sharedFiles; +GlobalPtr SharedFileInfo::sharedFilesMutex; + +} // namespace Firebird + + +FileLock::FileLock(const char* fileName, InitFunction* init) + : file(REF_NO_INCR, SharedFileInfo::get(fileName)), initFunction(init), level(LCK_NONE) +{ } + +FileLock::~FileLock() +{ + unlock(); } int FileLock::getFd() { - return oFile->fd; + return file->getFd(); } int FileLock::setlock(const LockMode mode) @@ -382,99 +512,11 @@ int FileLock::setlock(const LockMode mode) return wait ? EBUSY : -1; } - // first take appropriate rwlock to avoid conflicts with other threads in our process - bool rc = true; - try - { - switch (mode) - { - case FLM_TRY_EXCLUSIVE: - rc = rwcl->rwlock.tryBeginWrite(FB_FUNCTION); - break; - case FLM_EXCLUSIVE: - rwcl->rwlock.beginWrite(FB_FUNCTION); - break; - case FLM_TRY_SHARED: - rc = rwcl->rwlock.tryBeginRead(FB_FUNCTION); - break; - case FLM_SHARED: - rwcl->rwlock.beginRead(FB_FUNCTION); - break; - } - } - catch (const system_call_failed& fail) - { - return fail.getErrorCode(); - } - if (!rc) - { - return -1; - } - - // For shared lock we must take into an account reenterability - MutexEnsureUnlock guard(rwcl->sharedAccessMutex, FB_FUNCTION); - if (shared) - { - if (wait) - { - guard.enter(); - } - else if (!guard.tryEnter()) - { - return -1; - } - - fb_assert(rwcl->sharedAccessCounter >= 0); - if (rwcl->sharedAccessCounter++ > 0) - { - // counter is non-zero - we already have file lock - level = LCK_SHARED; - return 0; - } - } + int rc = file->lock(shared, wait, initFunction); + if (rc == 0) // lock taken + level = newLevel; -#ifdef USE_FCNTL - // Take lock on a file - struct FLOCK lock; - lock.l_type = shared ? F_RDLCK : F_WRLCK; - lock.l_whence = SEEK_SET; - lock.l_start = lStart; - lock.l_len = 1; - if (fcntl(oFile->fd, wait ? F_SETLKW : F_SETLK, &lock) == -1) - { - int rc = errno; - if (!wait && (rc == EACCES || rc == EAGAIN)) - { - rc = -1; - } -#else - if (flock(oFile->fd, (shared ? LOCK_SH : LOCK_EX) | (wait ? 0 : LOCK_NB))) - { - int rc = errno; - if (!wait && (rc == EWOULDBLOCK)) - { - rc = -1; - } -#endif - - try - { - if (shared) - { - rwcl->sharedAccessCounter--; - rwcl->rwlock.endRead(); - } - else - rwcl->rwlock.endWrite(); - } - catch (const Exception&) - { } - - return rc; - } - - level = newLevel; - return 0; + return rc; } bool FileLock::setlock(CheckStatusWrapper* status, const LockMode mode) @@ -491,25 +533,6 @@ bool FileLock::setlock(CheckStatusWrapper* status, const LockMode mode) return true; } -void FileLock::rwUnlock() -{ - fb_assert(level != LCK_NONE); - - try - { - if (level == LCK_SHARED) - rwcl->rwlock.endRead(); - else - rwcl->rwlock.endWrite(); - } - catch (const Exception& ex) - { - iscLogException("rwlock end-operation error", ex); - } - - level = LCK_NONE; -} - void FileLock::unlock() { if (level == LCK_NONE) @@ -517,97 +540,8 @@ void FileLock::unlock() return; } - // For shared lock we must take into an account reenterability - MutexEnsureUnlock guard(rwcl->sharedAccessMutex, FB_FUNCTION); - if (level == LCK_SHARED) - { - guard.enter(); - - fb_assert(rwcl->sharedAccessCounter > 0); - if (--(rwcl->sharedAccessCounter) > 0) - { - // counter is non-zero - we must keep file lock - rwUnlock(); - return; - } - } - -#ifdef USE_FCNTL - struct FLOCK lock; - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = lStart; - lock.l_len = 1; - - if (fcntl(oFile->fd, F_SETLK, &lock) != 0) - { -#else - if (flock(oFile->fd, LOCK_UN) != 0) - { -#endif - LocalStatus ls; - CheckStatusWrapper local(&ls); - error(&local, NAME, errno); - iscLogStatus("Unlock error", &local); - } - - rwUnlock(); -} - -string FileLock::getLockId() -{ - fb_assert(oFile); - - DevNode id(getNode(oFile->fd)); - - const size_t len1 = sizeof(id.f_dev); - const size_t len2 = sizeof(id.f_ino); -#ifdef USE_FCNTL - const size_t len3 = sizeof(int); -#endif - - string rc(len1 + len2 -#ifdef USE_FCNTL - + len3 -#endif - , ' '); - char* p = rc.begin(); - - memcpy(p, &id.f_dev, len1); - p += len1; - memcpy(p, &id.f_ino, len2); -#ifdef USE_FCNTL - p += len2; - memcpy(p, &lStart, len3); -#endif - - return rc; -} - -CountedRWLock* FileLock::getRw() -{ - string id = getLockId(); - CountedRWLock* rc = NULL; - - MutexLockGuard g(rwlocksMutex, FB_FUNCTION); - - CountedRWLock** got = rwlocks->get(id); - if (got) - { - rc = *got; - } - - if (!rc) - { - rc = FB_NEW_POOL(*getDefaultMemoryPool()) CountedRWLock; - CountedRWLock** put = rwlocks->put(id); - fb_assert(put); - *put = rc; - } - - ++(rc->cnt); - - return rc; + file->unlock(); + level = LCK_NONE; } #endif // UNIX @@ -808,9 +742,24 @@ int SharedMemoryBase::eventWait(event_t* event, const SLONG value, const SLONG m struct timespec timer; if (micro_seconds > 0) { - timer.tv_sec = time(NULL); - timer.tv_sec += micro_seconds / 1000000; - timer.tv_nsec = 1000 * (micro_seconds % 1000000); +#if defined(HAVE_CLOCK_GETTIME) + clock_gettime(CLOCK_REALTIME, &timer); +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tp; + GETTIMEOFDAY(&tp); + timer.tv_sec = tp.tv_sec; + timer.tv_nsec = tp.tv_usec * 1000; +#else + struct timeb time_buffer; + ftime(&time_buffer); + timer.tv_sec = time_buffer.time; + timer.tv_nsec = time_buffer.millitm * 1000000; +#endif + const SINT64 BILLION = 1000000000; + const SINT64 nanos = (SINT64) timer.tv_sec * BILLION + timer.tv_nsec + + (SINT64) micro_seconds * 1000; + timer.tv_sec = nanos / BILLION; + timer.tv_nsec = nanos % BILLION; } int ret = FB_SUCCESS; @@ -1168,13 +1117,17 @@ void SharedMemoryBase::removeMapFile() if (!sh_mem_header->isDeleted()) { #ifndef WIN_NT - unlinkFile(); + FileLockHolder initLock(initFile); + if (!sh_mem_header->isDeleted()) + { + unlinkFile(); + sh_mem_header->markAsDeleted(); + } #else fb_assert(!sh_mem_unlink); sh_mem_unlink = true; -#endif // WIN_NT - sh_mem_header->markAsDeleted(); +#endif // WIN_NT } } @@ -1183,6 +1136,19 @@ void SharedMemoryBase::unlinkFile() TEXT expanded_filename[MAXPATHLEN]; iscPrefixLock(expanded_filename, sh_mem_name, false); + unlinkFile(expanded_filename); +} + +PathName SharedMemoryBase::getMapFileName() +{ + TEXT expanded_filename[MAXPATHLEN]; + iscPrefixLock(expanded_filename, sh_mem_name, false); + + return PathName(expanded_filename); +} + +void SharedMemoryBase::unlinkFile(const TEXT* expanded_filename) noexcept +{ // We can't do much (specially in dtors) when it fails // therefore do not check for errors - at least it's just /tmp. @@ -1206,6 +1172,56 @@ void SharedMemoryBase::unlinkFile() #ifdef UNIX +static inline void reportError(const char* func, CheckStatusWrapper* statusVector) +{ + if (!statusVector) + system_call_failed::raise(func); + else + error(statusVector, func, errno); +} + +bool allocFileSpace(int fd, off_t offset, FB_SIZE_T length, CheckStatusWrapper* statusVector) +{ +#if defined(HAVE_LINUX_FALLOC_H) && defined(HAVE_FALLOCATE) + if (fallocate(fd, 0, offset, length) == 0) + return true; + + if (errno != EOPNOTSUPP && errno != ENOSYS) + { + reportError("fallocate", statusVector); + return false; + } + // fallocate is not supported by this kernel or file system + // take the long way around +#endif + static const FB_SIZE_T buf128KSize = 131072; + HalfStaticArray buf; + const FB_SIZE_T bufSize = length < buf128KSize ? length : buf128KSize; + + memset(buf.getBuffer(bufSize), 0, bufSize); + os_utils::lseek(fd, LSEEK_OFFSET_CAST offset, SEEK_SET); + + while (length) + { + const FB_SIZE_T cnt = length < bufSize ? length : bufSize; + if (write(fd, buf.begin(), cnt) != (ssize_t) cnt) + { + reportError("write", statusVector); + return false; + } + length -= cnt; + } + + if (fsync(fd)) + { + reportError("fsync", statusVector); + return false; + } + + return true; +} + + void SharedMemoryBase::internalUnmap() { if (sh_mem_header) @@ -1341,7 +1357,10 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject if (mainLock->setlock(&statusVector, FileLock::FLM_TRY_EXCLUSIVE)) { if (trunc_flag) + { FB_UNUSED(os_utils::ftruncate(mainLock->getFd(), length)); + allocFileSpace(mainLock->getFd(), 0, length, NULL); + } if (callback->initialize(this, true)) { @@ -1466,11 +1485,74 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject #endif // UNIX - #ifdef WIN_NT + +// Get name of the file that was mapped into memory at given address. +// This routine should not throw as caller is not ready currently. +static bool getMappedFileName(void* addr, PathName& mappedName) +{ + char* mapName = mappedName.getBuffer(MAXPATHLEN + 1); + const DWORD mapLen = GetMappedFileName(GetCurrentProcess(), addr, mapName, MAXPATHLEN); + mappedName.resize(mapLen); + if (!mapLen) + //system_call_failed::raise("GetMappedFileName"); + return false; + + char dosDevice[] = {'A', ':', 0}; + + DWORD drives = GetLogicalDrives(); + for (; drives; drives >>= 1, dosDevice[0]++) + if (drives & 1) + { + char ntDevice[MAXPATHLEN + 1]; + DWORD ntLen = QueryDosDevice(dosDevice, ntDevice, MAXPATHLEN); + + if (!ntLen) + //system_call_failed::raise("QueryDosDevice"); + return false; + + ntLen = strlen(ntDevice); + + if (ntLen <= mapLen && + _memicmp(ntDevice, mapName, ntLen) == 0 && + mapName[ntLen] == '\\') + { + mappedName.replace(0, ntLen, dosDevice); + return true; + } + } + + return false; +} + + +void SharedMemoryBase::internalUnmap() +{ + if (!UnmapViewOfFile(sh_mem_header)) + return; + + sh_mem_header = NULL; + CloseHandle(sh_mem_object); + CloseHandle(sh_mem_handle); + + CloseHandle(sh_mem_interest); + + if (!UnmapViewOfFile(sh_mem_hdr_address)) + return; + + sh_mem_hdr_address = NULL; + CloseHandle(sh_mem_hdr_object); + + ISC_mutex_fini(&sh_mem_winMutex); + sh_mem_mutex = NULL; + + if (sh_mem_unlink) + unlinkFile(); +} + SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject* cb, bool /*skipLock*/) : sh_mem_mutex(0), sh_mem_length_mapped(0), - sh_mem_handle(0), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0), + sh_mem_handle(INVALID_HANDLE_VALUE), sh_mem_object(0), sh_mem_interest(0), sh_mem_hdr_object(0), sh_mem_hdr_address(0), sh_mem_header(NULL), sh_mem_callback(cb), sh_mem_unlink(false) { /************************************** @@ -1488,10 +1570,6 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject fb_assert(sh_mem_callback); sh_mem_name[0] = '\0'; - ISC_mutex_init(&sh_mem_winMutex, filename); - sh_mem_mutex = &sh_mem_winMutex; - - HANDLE file_handle; HANDLE event_handle = 0; int retry_count = 0; @@ -1546,14 +1624,13 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject { CloseHandle(event_handle); if (retry_count > 10) - { - system_call_failed::raise("WaitForSingleObject", 0); - } + (Arg::Gds(isc_random) << Arg::Str("Wait for shared memory initialization timed out.")).raise(); + goto retry; } } - file_handle = CreateFile(expanded_filename, + HANDLE file_handle = CreateFile(expanded_filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -1600,7 +1677,6 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject !SetEndOfFile(file_handle) || !FlushFileBuffers(file_handle)) { err = GetLastError(); - CloseHandle(event_handle); CloseHandle(file_handle); if (err == ERROR_USER_MAPPED_FILE) @@ -1608,10 +1684,14 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject if (retry_count < 50) // 0.5 sec goto retry; + CloseHandle(event_handle); Arg::Gds(isc_instance_conflict).raise(); } else + { + CloseHandle(event_handle); system_call_failed::raise("SetFilePointer", err); + } } } @@ -1629,7 +1709,10 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject (Arg::Gds(isc_random) << Arg::Str("File for memory mapping is empty.")).raise(); } - if (SetFilePointer(file_handle, length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + LARGE_INTEGER offset; + offset.QuadPart = length; + + if (SetFilePointer(file_handle, offset.LowPart, &offset.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER || !SetEndOfFile(file_handle) || !FlushFileBuffers(file_handle)) { err = GetLastError(); @@ -1638,15 +1721,6 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject system_call_failed::raise("SetFilePointer", err); } } - else - { - if ((err != ERROR_ALREADY_EXISTS) || SetFilePointer(file_handle, 0, NULL, FILE_END) == 0) - { - CloseHandle(event_handle); - CloseHandle(file_handle); - goto retry; - } - } // Create a file mapping object that will be used to make remapping possible. // The current length of real mapped file and its name are saved in it. @@ -1761,6 +1835,28 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject system_call_failed::raise("MapViewOfFile", err); } + PathName mappedName; + if (!getMappedFileName(address, mappedName) || mappedName != expanded_filename) + { + UnmapViewOfFile(address); + CloseHandle(file_obj); + UnmapViewOfFile(header_address); + CloseHandle(header_obj); + CloseHandle(event_handle); + CloseHandle(file_handle); + + gds__log("Wrong file for memory mapping:\n" + "\t expected %s\n" + "\talready mapped %s\n" + "\tCheck for presence of another Firebird instance with different lock directory", + expanded_filename, mappedName.c_str()); + + (Arg::Gds(isc_random) << Arg::Str("Wrong file for memory mapping, see details in firebird.log")).raise(); + } + + ISC_mutex_init(&sh_mem_winMutex, filename); + sh_mem_mutex = &sh_mem_winMutex; + sh_mem_header = (MemoryHeader*) address; sh_mem_length_mapped = length; sh_mem_handle = file_handle; @@ -1770,27 +1866,26 @@ SharedMemoryBase::SharedMemoryBase(const TEXT* filename, ULONG length, IpcObject sh_mem_hdr_address = header_address; strcpy(sh_mem_name, filename); - sh_mem_callback->initialize(this, init_flag); + try + { + sh_mem_callback->initialize(this, init_flag); + } + catch (const Exception&) + { + internalUnmap(); + throw; + } if (init_flag) { - err = 0; if (!FlushViewOfFile(address, 0)) { err = GetLastError(); + internalUnmap(); + system_call_failed::raise("FlushViewOfFile", err); } SetEvent(event_handle); - if (err) - { - UnmapViewOfFile(address); - CloseHandle(file_obj); - UnmapViewOfFile(header_address); - CloseHandle(header_obj); - CloseHandle(event_handle); - CloseHandle(file_handle); - system_call_failed::raise("FlushViewOfFile", err); - } } } #endif @@ -2401,8 +2496,19 @@ bool SharedMemoryBase::remapFile(CheckStatusWrapper* statusVector, ULONG new_len } if (flag) + { FB_UNUSED(os_utils::ftruncate(mainLock->getFd(), new_length)); + if (new_length > sh_mem_length_mapped) + { + if (!allocFileSpace(mainLock->getFd(), sh_mem_length_mapped, + new_length - sh_mem_length_mapped, statusVector)) + { + return false; + } + } + } + MemoryHeader* const address = (MemoryHeader*) os_utils::mmap(0, new_length, PROT_READ | PROT_WRITE, MAP_SHARED, mainLock->getFd(), 0); @@ -2447,7 +2553,10 @@ bool SharedMemoryBase::remapFile(CheckStatusWrapper* statusVector, if (flag) { - if (SetFilePointer(sh_mem_handle, new_length, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER || + LARGE_INTEGER offset; + offset.QuadPart = new_length; + + if (SetFilePointer(sh_mem_handle, offset.LowPart, &offset.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER || !SetEndOfFile(sh_mem_handle) || !FlushViewOfFile(sh_mem_header, 0)) { @@ -2606,7 +2715,7 @@ static bool make_object_name(TEXT* buffer, size_t bufsize, // CVC: I'm not convinced that if this call has no space to put the prefix, // we can ignore that fact, hence I changed that signature, too. - if (!fb_utils::prefix_kernel_object_name(buffer, bufsize)) + if (!fb_utils::private_kernel_object_name(buffer, bufsize)) { SetLastError(ERROR_FILENAME_EXCED_RANGE); return false; @@ -2712,36 +2821,7 @@ SharedMemoryBase::~SharedMemoryBase() } #endif -#ifdef UNIX internalUnmap(); -#endif - -#ifdef WIN_NT - if (!UnmapViewOfFile(sh_mem_header)) - { - return; - } - sh_mem_header = NULL; - CloseHandle(sh_mem_object); - CloseHandle(sh_mem_handle); - - CloseHandle(sh_mem_interest); - - if (!UnmapViewOfFile(sh_mem_hdr_address)) - { - return; - } - sh_mem_hdr_address = NULL; - CloseHandle(sh_mem_hdr_object); - - ISC_mutex_fini(&sh_mem_winMutex); - sh_mem_mutex = NULL; - - if (sh_mem_unlink) - { - unlinkFile(); - } -#endif } void SharedMemoryBase::logError(const char* text, const CheckStatusWrapper* status) diff --git a/src/common/keywords.cpp b/src/common/keywords.cpp index 0639bc67032..1df963ddb19 100644 --- a/src/common/keywords.cpp +++ b/src/common/keywords.cpp @@ -100,6 +100,7 @@ static const TOK tokens[] = {TOK_BIND, "BIND", true}, {TOK_BIT_LENGTH, "BIT_LENGTH", false}, {TOK_BLOB, "BLOB", false}, + {TOK_BLOB_APPEND, "BLOB_APPEND", true}, {TOK_BLOCK, "BLOCK", true}, {TOK_BODY, "BODY", true}, {TOK_BOOLEAN, "BOOLEAN", false}, @@ -169,6 +170,7 @@ static const TOK tokens[] = {TOK_DATEDIFF, "DATEDIFF", true}, {TOK_DAY, "DAY", false}, {TOK_DDL, "DDL", true}, + {TOK_DEBUG, "DEBUG", true}, {TOK_DEC, "DEC", false}, {TOK_DECFLOAT, "DECFLOAT", false}, {TOK_DECIMAL, "DECIMAL", false}, @@ -357,6 +359,7 @@ static const TOK tokens[] = {TOK_PASSWORD, "PASSWORD", true}, {TOK_PERCENT_RANK, "PERCENT_RANK", true}, {TOK_PI, "PI", true}, + {TOK_PKCS_1_5, "PKCS_1_5", true}, {TOK_PLACING, "PLACING", true}, {TOK_PLAN, "PLAN", false}, {TOK_PLUGIN, "PLUGIN", true}, @@ -431,8 +434,8 @@ static const TOK tokens[] = {TOK_RSA_ENCRYPT, "RSA_ENCRYPT", true}, {TOK_RSA_PRIVATE, "RSA_PRIVATE", true}, {TOK_RSA_PUBLIC, "RSA_PUBLIC", true}, - {TOK_RSA_SIGN, "RSA_SIGN", true}, - {TOK_RSA_VERIFY, "RSA_VERIFY", true}, + {TOK_RSA_SIGN_HASH, "RSA_SIGN_HASH", true}, + {TOK_RSA_VERIFY_HASH, "RSA_VERIFY_HASH", true}, {TOK_SALT_LENGTH, "SALT_LENGTH", true}, {TOK_SAVEPOINT, "SAVEPOINT", false}, {TOK_SCALAR_ARRAY, "SCALAR_ARRAY", true}, diff --git a/src/common/os/mod_loader.h b/src/common/os/mod_loader.h index 1b9a43a4095..933a4c896e9 100644 --- a/src/common/os/mod_loader.h +++ b/src/common/os/mod_loader.h @@ -72,6 +72,10 @@ class ModuleLoader const Firebird::PathName fileName; +#ifdef LINUX + virtual bool getRealPath(Firebird::PathName& realPath) = 0; +#endif + protected: /// The constructor is protected so normal code can't allocate instances /// of the class, but the class itself is still able to be subclassed. diff --git a/src/common/os/posix/guid.cpp b/src/common/os/posix/guid.cpp index 805d12c00c7..5960aca3ac9 100644 --- a/src/common/os/posix/guid.cpp +++ b/src/common/os/posix/guid.cpp @@ -45,6 +45,9 @@ void GenerateRandomBytes(void* buffer, FB_SIZE_T size) { // do not use /dev/random because it may return lesser data than we need. int fd = os_utils::open("/dev/urandom", O_RDONLY); + if (fd < 0) + Firebird::system_call_failed::raise("open"); + for (FB_SIZE_T offset = 0; offset < size; ) { int rc = read(fd, static_cast(buffer) + offset, size - offset); diff --git a/src/common/os/posix/mod_loader.cpp b/src/common/os/posix/mod_loader.cpp index 419f80c239e..9f87818e4a5 100644 --- a/src/common/os/posix/mod_loader.cpp +++ b/src/common/os/posix/mod_loader.cpp @@ -38,6 +38,7 @@ #include #include +#include #include /// This is the POSIX (dlopen) implementation of the mod_loader abstraction. @@ -53,6 +54,8 @@ class DlfcnModule : public ModuleLoader::Module ~DlfcnModule(); void* findSymbol(ISC_STATUS*, const Firebird::string&); + bool getRealPath(Firebird::PathName& realPath); + private: void* module; }; @@ -202,3 +205,39 @@ void* DlfcnModule::findSymbol(ISC_STATUS* status, const Firebird::string& symNam return result; } + +bool DlfcnModule::getRealPath(Firebird::PathName& realPath) +{ +#ifdef HAVE_DLINFO + char b[PATH_MAX]; + +#ifdef HAVE_RTLD_DI_ORIGIN + if (dlinfo(module, RTLD_DI_ORIGIN, b) == 0) + { + realPath = b; + realPath += '/'; + realPath += fileName; + + if (realpath(realPath.c_str(), b)) + { + realPath = b; + return true; + } + } +#endif + +#ifdef HAVE_RTLD_DI_LINKMAP + struct link_map* lm; + if (dlinfo(module, RTLD_DI_LINKMAP, &lm) == 0) + { + if (realpath(lm->l_name, b)) + { + realPath = b; + return true; + } + } +#endif + +#endif + return false; +} diff --git a/src/common/os/posix/os_utils.cpp b/src/common/os/posix/os_utils.cpp index 297a4254061..7ad86d81903 100644 --- a/src/common/os/posix/os_utils.cpp +++ b/src/common/os/posix/os_utils.cpp @@ -170,18 +170,18 @@ void createLockDirectory(const char* pathname) if (access(pathname, R_OK | W_OK | X_OK) == 0) { if (os_utils::stat(pathname, &st) != 0) - system_call_failed::raise("stat"); + system_call_failed::raise("stat", pathname); if (S_ISDIR(st.st_mode)) return; // not exactly original meaning, but very close to it - system_call_failed::raise("access", ENOTDIR); + system_call_failed::raise("mkdir", pathname, ENOTDIR); } if (SYSCALL_INTERRUPTED(errno)) continue; if (errno == ENOENT) break; - system_call_failed::raise("access", ENOTDIR); + system_call_failed::raise("access", pathname); } Firebird::PathName newname(pathname); @@ -238,16 +238,16 @@ void createLockDirectory(const char* pathname) if (access(pathname, R_OK | W_OK | X_OK) == 0) { if (os_utils::stat(pathname, &st) != 0) - system_call_failed::raise("stat"); + system_call_failed::raise("stat", pathname); if (S_ISDIR(st.st_mode)) return; // not exactly original meaning, but very close to it - system_call_failed::raise("access", ENOTDIR); + system_call_failed::raise("stat", pathname, ENOTDIR); } if (SYSCALL_INTERRUPTED(errno)) continue; - system_call_failed::raise("access", ENOTDIR); + system_call_failed::raise("access", pathname); } return; @@ -340,7 +340,7 @@ void setCloseOnExec(int fd) { if (fd >= 0) { - while (fcntl(fd, F_SETFD, O_CLOEXEC) < 0 && SYSCALL_INTERRUPTED(errno)) + while (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 && SYSCALL_INTERRUPTED(errno)) ; } } diff --git a/src/common/os/win32/isc_ipc.cpp b/src/common/os/win32/isc_ipc.cpp index bc7ecd6a659..1e26b35b2f6 100644 --- a/src/common/os/win32/isc_ipc.cpp +++ b/src/common/os/win32/isc_ipc.cpp @@ -45,6 +45,8 @@ #include "../common/isc_proto.h" #include "../common/os/isc_i_proto.h" #include "../common/isc_s_proto.h" +#include "../common/file_params.h" +#include "../common/config/config.h" #include #include @@ -198,9 +200,11 @@ HANDLE ISC_make_signal(bool /*create_flag*/, bool manual_reset, int process_idL, return CreateEvent(NULL, man_rst, FALSE, NULL); TEXT event_name[BUFFER_TINY]; - sprintf(event_name, "_firebird_process%u_signal%d", process_idL, signal_number); - if (!fb_utils::prefix_kernel_object_name(event_name, sizeof(event_name))) + const bool legacyNames = Firebird::Config::getLegacyKernelNames(); + sprintf(event_name, legacyNames ? SHARED_EVENT_OLD : SHARED_EVENT, process_idL, signal_number); + + if (!fb_utils::private_kernel_object_name(event_name, sizeof(event_name))) { SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; diff --git a/src/common/os/win32/mod_loader.cpp b/src/common/os/win32/mod_loader.cpp index 840596db85e..5173b00daa9 100644 --- a/src/common/os/win32/mod_loader.cpp +++ b/src/common/os/win32/mod_loader.cpp @@ -87,26 +87,34 @@ class ContextActivator memset(&ackd, 0, sizeof(ackd)); ackd.cbSize = sizeof(ackd); - // if CRT already present in some activation context then nothing to do - if ((*mFindActCtxSectionString) - (0, NULL, - ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, + const char* crtDll = #if _MSC_VER == 1400 - "msvcr80.dll", + "msvcr80.dll"; #elif _MSC_VER == 1500 - "msvcr90.dll", + "msvcr90.dll"; #elif _MSC_VER == 1600 - "msvcr100.dll", + "msvcr100.dll"; #elif _MSC_VER == 1700 - "msvcr110.dll", + "msvcr110.dll"; #elif _MSC_VER == 1800 - "msvcr120.dll", -#elif _MSC_VER >= 1900 && _MSC_VER < 1930 - "vcruntime140.dll", + "msvcr120.dll"; +#elif _MSC_VER >= 1900 && _MSC_VER < 2000 + "vcruntime140.dll"; #else - #error Specify CRT DLL name here ! + ""; + +#define TO_STR(x) #x +#define ERRSTR(x) "Unknown " #x " value: " TO_STR(x) ". Specify CRT DLL name here !" + + static_assert(false, ERRSTR(_MSC_VER)); +// #error Specify CRT DLL name here ! #endif - &ackd)) + + // if CRT already present in some activation context then nothing to do + if ((*mFindActCtxSectionString) + (0, NULL, + ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, + crtDll, &ackd)) { return; } diff --git a/src/common/status.h b/src/common/status.h index d3e3c2eb468..8e334a273c5 100644 --- a/src/common/status.h +++ b/src/common/status.h @@ -90,6 +90,11 @@ namespace Firebird fb_utils::copyStatus(to, &localStatusVector); } + void loadFrom(const SW* to) + { + fb_utils::copyStatus(&localStatusVector, to); + } + void raise() const { Firebird::status_exception::raise(&localStatus); diff --git a/src/common/unicode_util.cpp b/src/common/unicode_util.cpp index eee2cebff1a..5ba8777de64 100644 --- a/src/common/unicode_util.cpp +++ b/src/common/unicode_util.cpp @@ -194,7 +194,7 @@ void BaseICU::initialize(ModuleLoader::Module* module) namespace Jrd { static ModuleLoader::Module* formatAndLoad(const char* templateName, - int majorVersion, int minorVersion); + int& majorVersion, int& minorVersion); // encapsulate ICU collations libraries @@ -272,10 +272,15 @@ struct UnicodeUtil::ICU : public BaseICU USet* (U_EXPORT2 *usetOpen)(UChar32 start, UChar32 end); void (U_EXPORT2 *ucolClose)(UCollator* coll); - int32_t (U_EXPORT2 *ucolGetContractions)(const UCollator* coll, USet* conts, UErrorCode* status); + int32_t (U_EXPORT2 *ucolGetContractionsAndExpansions)(const UCollator* coll, USet* contractions, USet* expansions, + UBool addPrefixes, UErrorCode* status); + const UChar* (U_EXPORT2 *ucolGetRules)(const UCollator* coll, int32_t* length); + int32_t (U_EXPORT2 *ucolGetSortKey)(const UCollator* coll, const UChar* source, int32_t sourceLength, uint8_t* result, int32_t resultLength); UCollator* (U_EXPORT2 *ucolOpen)(const char* loc, UErrorCode* status); + UCollator* (U_EXPORT2 *ucolOpenRules)(const UChar* rules, int32_t rulesLength, UColAttributeValue normalizationMode, + UCollationStrength strength, UParseError* parseError, UErrorCode* status); void (U_EXPORT2 *ucolSetAttribute)(UCollator* coll, UColAttribute attr, UColAttributeValue value, UErrorCode* status); UCollationResult (U_EXPORT2 *ucolStrColl)(const UCollator* coll, const UChar* source, @@ -309,7 +314,7 @@ class ImplementConversionICU : public UnicodeUtil::ConversionICU, BaseICU ImplementConversionICU(int aMajorVersion, int aMinorVersion) : BaseICU(aMajorVersion, aMinorVersion) { - module = formatAndLoad(ucTemplate, aMajorVersion, aMinorVersion); + module = formatAndLoad(ucTemplate, this->majorVersion, this->minorVersion); if (!module) return; @@ -324,7 +329,6 @@ class ImplementConversionICU : public UnicodeUtil::ConversionICU, BaseICU getEntryPoint("u_countChar32", module, u_countChar32); getEntryPoint("utf8_nextCharSafeBody", module, utf8_nextCharSafeBody); - getEntryPoint("UCNV_FROM_U_CALLBACK_STOP", module, UCNV_FROM_U_CALLBACK_STOP); getEntryPoint("UCNV_TO_U_CALLBACK_STOP", module, UCNV_TO_U_CALLBACK_STOP); getEntryPoint("ucnv_fromUnicode", module, ucnv_fromUnicode); getEntryPoint("ucnv_toUnicode", module, ucnv_toUnicode); @@ -340,6 +344,15 @@ class ImplementConversionICU : public UnicodeUtil::ConversionICU, BaseICU if (!inModule) return; + if (aMajorVersion != this->majorVersion || aMinorVersion != this->minorVersion) + { + string err; + err.printf("Wrong version of IN icu module: loaded %d.%d, expected %d.%d", + aMajorVersion, aMinorVersion, this->majorVersion, this->minorVersion); + + (Arg::Gds(isc_random) << Arg::Str(err)).raise(); + } + getEntryPoint("ucal_getTZDataVersion", inModule, ucalGetTZDataVersion); getEntryPoint("ucal_getDefaultTimeZone", inModule, ucalGetDefaultTimeZone); getEntryPoint("ucal_open", inModule, ucalOpen); @@ -410,9 +423,47 @@ static const char* const COLL_30_VERSION = "41.128.4.4"; // ICU 3.0 collator ver static GlobalPtr icuModules; +static bool extractVersionFromPath(const PathName& realPath, int& major, int& minor) +{ + major = 0; + minor = 0; + int mult = 1; + + const FB_SIZE_T len = realPath.length(); + const char* buf = realPath.begin(); + + bool dot = false; + for (const char* p = buf + len - 1; p >= buf; p--) + { + if (*p >= '0' && *p < '9') + { + major += (*p - '0') * mult; + mult *= 10; + } + else if (*p == '.' && !dot) + { + dot = true; + minor = major; + major = 0; + mult = 1; + } + else + { + break; + } + } + + if (minor && !major) + { + major = minor; + minor = 0; + } + + return major != 0; +} static ModuleLoader::Module* formatAndLoad(const char* templateName, - int majorVersion, int minorVersion) + int& majorVersion, int& minorVersion) { #ifdef ANDROID static ModuleLoader::Module* dat = ModuleLoader::loadModule(NULL, @@ -429,7 +480,28 @@ static ModuleLoader::Module* formatAndLoad(const char* templateName, { PathName filename; filename.printf(templateName, ""); + filename.rtrim("."); + + //gds__log("ICU: link %s", filename.c_str()); + module = ModuleLoader::fixAndLoadModule(NULL, filename); + +#ifdef LINUX + // try to resolve symlinks and extract version numbers from suffix + PathName realPath; + if (module && module->getRealPath(realPath)) + { + //gds__log("ICU: module name %s, real path %s", module->fileName.c_str(), realPath.c_str()); + + int major, minor; + if (extractVersionFromPath(realPath, major, minor)) + { + //gds__log("ICU: extracted version %d.%d", major, minor); + majorVersion = major; + minorVersion = minor; + } + } +#endif } else { @@ -1131,7 +1203,7 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c icu = FB_NEW_POOL(*getDefaultMemoryPool()) ICU(majorVersion, minorVersion); - icu->ucModule = formatAndLoad(ucTemplate, majorVersion, minorVersion); + icu->ucModule = formatAndLoad(ucTemplate, icu->majorVersion, icu->minorVersion); if (!icu->ucModule) { gds__log("failed to load UC icu module version %s", configVersion.c_str()); @@ -1147,6 +1219,14 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c continue; } + if (icu->majorVersion != majorVersion || icu->minorVersion != minorVersion) + { + gds__log("Wrong version of IN icu module: loaded %d.%d, expected %d.%d", + majorVersion, minorVersion, icu->majorVersion, icu->minorVersion); + delete icu; + continue; + } + try { icu->initialize(icu->ucModule); @@ -1160,9 +1240,12 @@ UnicodeUtil::ICU* UnicodeUtil::loadICU(const string& icuVersion, const string& c icu->getEntryPoint("uset_open", icu->ucModule, icu->usetOpen); icu->getEntryPoint("ucol_close", icu->inModule, icu->ucolClose); - icu->getEntryPoint("ucol_getContractions", icu->inModule, icu->ucolGetContractions); + icu->getEntryPoint("ucol_getContractionsAndExpansions", icu->inModule, + icu->ucolGetContractionsAndExpansions); + icu->getEntryPoint("ucol_getRules", icu->inModule, icu->ucolGetRules); icu->getEntryPoint("ucol_getSortKey", icu->inModule, icu->ucolGetSortKey); icu->getEntryPoint("ucol_open", icu->inModule, icu->ucolOpen); + icu->getEntryPoint("ucol_openRules", icu->inModule, icu->ucolOpenRules); icu->getEntryPoint("ucol_setAttribute", icu->inModule, icu->ucolSetAttribute); icu->getEntryPoint("ucol_strcoll", icu->inModule, icu->ucolStrColl); icu->getEntryPoint("ucol_getVersion", icu->inModule, icu->ucolGetVersion); @@ -1260,7 +1343,12 @@ UnicodeUtil::ConversionICU& UnicodeUtil::getConversionICU() for (int major = 79; major >= 3;) { +#ifdef WIN_NT int minor = 0; +#else + int minor = 9; +#endif + if (major == 4) minor = 8; else if (major <= 4) @@ -1376,6 +1464,19 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( } } + string disableCompressions; + if (specificAttributes.get(IntlUtil::convertAsciiToUtf16("DISABLE-COMPRESSIONS"), disableCompressions)) + { + ++attributeCount; + + disableCompressions = IntlUtil::convertUtf16ToAscii(disableCompressions, &error); + if (error || !(disableCompressions == "0" || disableCompressions == "1")) + { + gds__log("IntlUtil::convertUtf16ToAscii failed"); + return NULL; + } + } + locale = IntlUtil::convertUtf16ToAscii(locale, &error); if (error) { @@ -1406,15 +1507,48 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( } UErrorCode status = U_ZERO_ERROR; + HalfStaticArray rulesBuffer; - UCollator* compareCollator = icu->ucolOpen(locale.c_str(), &status); + if (disableCompressions == "1") + { + UCollator* initialCollator = icu->ucolOpen(locale.c_str(), &status); + + if (!initialCollator) + { + gds__log("ucolOpen failed"); + return NULL; + } + + static const char16_t CONTRACTION_RULES[] = u"[suppressContractions [^]]"; + int32_t rulesLen; + const UChar* rules = icu->ucolGetRules(initialCollator, &rulesLen); + rulesBuffer.push(rules, rulesLen); + rulesBuffer.push((const UChar*) CONTRACTION_RULES, FB_NELEM(CONTRACTION_RULES) - 1); + + icu->ucolClose(initialCollator); + } + + auto openCollation = [&]() + { + if (disableCompressions == "1") + { + UParseError parseError; + return icu->ucolOpenRules(rulesBuffer.begin(), rulesBuffer.getCount(), + UCOL_DEFAULT, UCOL_DEFAULT, &parseError, &status); + } + else + return icu->ucolOpen(locale.c_str(), &status); + }; + + UCollator* compareCollator = openCollation(); if (!compareCollator) { gds__log("ucolOpen failed"); return NULL; } - UCollator* partialCollator = icu->ucolOpen(locale.c_str(), &status); + UCollator* partialCollator = openCollation(); + if (!partialCollator) { gds__log("ucolOpen failed"); @@ -1422,7 +1556,7 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( return NULL; } - UCollator* sortCollator = icu->ucolOpen(locale.c_str(), &status); + UCollator* sortCollator = openCollation(); if (!sortCollator) { gds__log("ucolOpen failed"); @@ -1471,10 +1605,6 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( icu->ucolSetAttribute(compareCollator, UCOL_STRENGTH, UCOL_SECONDARY, &status); } - USet* contractions = icu->usetOpen(0, 0); - // status not verified here. - icu->ucolGetContractions(partialCollator, contractions, &status); - Utf16Collation* obj = FB_NEW Utf16Collation(); obj->icu = icu; obj->tt = tt; @@ -1482,9 +1612,150 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( obj->compareCollator = compareCollator; obj->partialCollator = partialCollator; obj->sortCollator = sortCollator; - obj->contractions = contractions; - obj->contractionsCount = icu->usetGetItemCount(contractions); obj->numericSort = isNumericSort; + obj->maxContractionsPrefixLength = 0; + + USet* contractions = icu->usetOpen(1, 0); + // status not verified here. + icu->ucolGetContractionsAndExpansions(partialCollator, contractions, nullptr, false, &status); + + int contractionsCount = icu->usetGetItemCount(contractions); + + for (int contractionIndex = 0; contractionIndex < contractionsCount; ++contractionIndex) + { + UChar strChars[10]; + UChar32 start, end; + + status = U_ZERO_ERROR; + int len = icu->usetGetItem(contractions, contractionIndex, &start, &end, strChars, sizeof(strChars), &status); + + if (len >= 2) + { + obj->maxContractionsPrefixLength = len - 1 > obj->maxContractionsPrefixLength ? + len - 1 : obj->maxContractionsPrefixLength; + + UCHAR key[100]; + int keyLen = icu->ucolGetSortKey(partialCollator, strChars, len, key, sizeof(key)); + + for (int prefixLen = 1; prefixLen < len; ++prefixLen) + { + const Array str(reinterpret_cast(strChars), prefixLen); + auto keySet = obj->contractionsPrefix.get(str); + + if (!keySet) + { + keySet = obj->contractionsPrefix.put(str); + + UCHAR prefixKey[100]; + int prefixKeyLen = icu->ucolGetSortKey(partialCollator, + strChars, prefixLen, prefixKey, sizeof(prefixKey)); + + keySet->add(Array(prefixKey, prefixKeyLen)); + } + + keySet->add(Array(key, keyLen)); + } + } + } + + icu->usetClose(contractions); + + ContractionsPrefixMap::Accessor accessor(&obj->contractionsPrefix); + + for (bool found = accessor.getFirst(); found; found = accessor.getNext()) + { + auto& keySet = accessor.current()->second; + + if (keySet.getCount() <= 1) + continue; + + fb_assert(accessor.current()->first.hasData()); + USHORT firstCh = accessor.current()->first.front(); + USHORT lastCh = accessor.current()->first.back(); + + if ((firstCh >= 0xFDD0 && firstCh <= 0xFDEF) || UTF_IS_SURROGATE(lastCh)) + { + keySet.clear(); + keySet.add(Array()); + continue; + } + + auto firstKeyIt = keySet.begin(); + auto lastKeyIt = --keySet.end(); + + const UCHAR* firstKeyDataIt = firstKeyIt->begin(); + const UCHAR* lastKeyDataIt = lastKeyIt->begin(); + const UCHAR* firstKeyDataEnd = firstKeyIt->end(); + const UCHAR* lastKeyDataEnd = lastKeyIt->end(); + + if (*firstKeyDataIt == *lastKeyDataIt) + { + unsigned common = 0; + + do + { + ++common; + } while (++firstKeyDataIt != firstKeyDataEnd && ++lastKeyDataIt != lastKeyDataEnd && + *firstKeyDataIt == *lastKeyDataIt); + + Array commonKey(firstKeyIt->begin(), common); + keySet.clear(); + keySet.add(commonKey); + } + else + { + auto secondKeyIt = ++keySet.begin(); + const UCHAR* secondKeyDataIt = secondKeyIt->begin(); + const UCHAR* secondKeyDataEnd = secondKeyIt->end(); + + ObjectsArray > commonKeys; + commonKeys.add(*firstKeyIt); + + while (secondKeyIt != keySet.end()) + { + unsigned common = 0; + + while (firstKeyDataIt != firstKeyDataEnd && secondKeyDataIt != secondKeyDataEnd && + *firstKeyDataIt == *secondKeyDataIt) + { + ++common; + ++firstKeyDataIt; + ++secondKeyDataIt; + } + + unsigned backSize = commonKeys.back()->getCount(); + + if (common > backSize) + commonKeys.back()->append(secondKeyIt->begin() + backSize, common - backSize); + else if (common < backSize) + { + if (common == 0) + commonKeys.push(*secondKeyIt); + else + commonKeys.back()->resize(common); + } + + if (++secondKeyIt != keySet.end()) + { + ++firstKeyIt; + + firstKeyDataIt = firstKeyIt->begin(); + secondKeyDataIt = secondKeyIt->begin(); + + firstKeyDataEnd = firstKeyIt->end(); + secondKeyDataEnd = secondKeyIt->end(); + } + } + + keySet.clear(); + + for (auto ck : commonKeys) + keySet.add(ck); + } + } + + if (obj->maxContractionsPrefixLength) + tt->texttype_flags |= TEXTTYPE_MULTI_STARTING_KEY; return obj; } @@ -1492,8 +1763,6 @@ UnicodeUtil::Utf16Collation* UnicodeUtil::Utf16Collation::create( UnicodeUtil::Utf16Collation::~Utf16Collation() { - icu->usetClose(contractions); - icu->ucolClose(compareCollator); icu->ucolClose(partialCollator); icu->ucolClose(sortCollator); @@ -1538,57 +1807,18 @@ USHORT UnicodeUtil::Utf16Collation::stringToKey(USHORT srcLen, const USHORT* src srcLenLong = pad - src + 1; } + if (srcLenLong == 0) + return 0; + HalfStaticArray buffer; const UCollator* coll = NULL; switch (key_type) { case INTL_KEY_PARTIAL: - { + case INTL_KEY_MULTI_STARTING: coll = partialCollator; - - // Remove last bytes of key if they are start of a contraction - // to correctly find in the index. - ConversionICU& cIcu(getConversionICU()); - for (int i = 0; i < contractionsCount; ++i) - { - UChar str[10]; - UErrorCode status = U_ZERO_ERROR; - int len = icu->usetGetItem(contractions, i, NULL, NULL, str, sizeof(str), &status); - if (len < 0) - fatal_exception::raiseFmt("uset_getItem() error %d", status); - - if (unsigned(len) > srcLenLong) // safe cast - sign checked - len = srcLenLong; - else - --len; - - // safe cast - alignment not changed - if (cIcu.u_strCompare(str, len, - reinterpret_cast(src) + srcLenLong - len, len, true) == 0) - { - srcLenLong -= len; - break; - } - } - - if (numericSort) - { - // ASF: Wee need to remove trailing numbers to return sub key that - // matches full key. Example: "abc1" becomes "abc" to match "abc10". - const USHORT* p = src + srcLenLong - 1; - - for (; p >= src; --p) - { - if (!(*p >= '0' && *p <= '9')) - break; - } - - srcLenLong = p - src + 1; - } - break; - } case INTL_KEY_UNIQUE: coll = compareCollator; @@ -1606,11 +1836,125 @@ USHORT UnicodeUtil::Utf16Collation::stringToKey(USHORT srcLen, const USHORT* src return INTL_BAD_KEY_LENGTH; } - if (srcLenLong == 0) - return 0; + if (key_type == INTL_KEY_MULTI_STARTING) + { + bool trailingNumbersRemoved = false; + + if (numericSort) + { + // ASF: Wee need to remove trailing numbers to return sub key that + // matches full key. Example: "abc1" becomes "abc" to match "abc10". + const USHORT* p = src + srcLenLong - 1; + + for (; p >= src; --p) + { + if (!(*p >= '0' && *p <= '9')) + break; + + trailingNumbersRemoved = true; + } + + srcLenLong = p - src + 1; + } + + auto originalDst = dst; + auto originalDstLen = dstLen; + + if (!trailingNumbersRemoved) + { + for (int i = MIN(maxContractionsPrefixLength, srcLenLong); i > 0; --i) + { + auto keys = contractionsPrefix.get(Array(src + srcLenLong - i, i)); + + if (keys) + { + UCHAR lastCharKey[BUFFER_TINY]; // sort key for a single character + ULONG prefixLen, lastCharKeyLen; + + srcLenLong -= i; + + if (srcLenLong != 0) + { + prefixLen = icu->ucolGetSortKey(coll, + reinterpret_cast(src), srcLenLong, dst + 2, dstLen - 2); + + lastCharKeyLen = icu->ucolGetSortKey(coll, + reinterpret_cast(src + srcLenLong), i, lastCharKey, sizeof(lastCharKey)); + + if (prefixLen == 0 || prefixLen > dstLen - 2 || prefixLen > MAX_USHORT || + lastCharKeyLen == 0) + { + return INTL_BAD_KEY_LENGTH; + } + + fb_assert(dst[2 + prefixLen - 1] == '\0'); + --prefixLen; + + fb_assert(lastCharKey[lastCharKeyLen - 1] == '\0'); + --lastCharKeyLen; + } + else + prefixLen = 0; + + bool fallbackToPrefixKey = false; + + for (const auto& keyIt : *keys) + { + const UCHAR advance = prefixLen && lastCharKeyLen > 1 && + keyIt.hasData() && lastCharKey[0] == keyIt.front() ? 1 : 0; + + if (keyIt.getCount() - advance == 0) + { + fallbackToPrefixKey = true; + break; + } - return icu->ucolGetSortKey(coll, + const ULONG keyLen = prefixLen + keyIt.getCount() - advance; + + if (keyLen > dstLen - 2 || keyLen > MAX_USHORT) + return INTL_BAD_KEY_LENGTH; + + dst[0] = UCHAR(keyLen & 0xFF); + dst[1] = UCHAR(keyLen >> 8); + + if (dst != originalDst) + memcpy(dst + 2, originalDst + 2, prefixLen); + + memcpy(dst + 2 + prefixLen, keyIt.begin() + advance, keyIt.getCount() - advance); + dst += 2 + keyLen; + dstLen -= 2 + keyLen; + } + + if (fallbackToPrefixKey) + break; + + return dst - originalDst; + } + } + } + + ULONG keyLen = icu->ucolGetSortKey(coll, + reinterpret_cast(src), srcLenLong, originalDst + 2, originalDstLen - 3); + + if (keyLen == 0 || keyLen > originalDstLen - 3 || keyLen > MAX_USHORT) + return INTL_BAD_KEY_LENGTH; + + fb_assert(originalDst[2 + keyLen - 1] == '\0'); + --keyLen; + + originalDst[0] = UCHAR(keyLen & 0xFF); + originalDst[1] = UCHAR(keyLen >> 8); + + return keyLen + 2; + } + + const ULONG keyLen = icu->ucolGetSortKey(coll, reinterpret_cast(src), srcLenLong, dst, dstLen); + + if (keyLen == 0 || keyLen > dstLen || keyLen > MAX_USHORT) + return INTL_BAD_KEY_LENGTH; + + return keyLen; } @@ -1702,7 +2046,16 @@ UnicodeUtil::ICU* UnicodeUtil::Utf16Collation::loadICU( } if (avail < 0) - continue; + { + UErrorCode status = U_ZERO_ERROR; + UCollator* testCollator = icu->ucolOpen(locale.c_str(), &status); + if (!testCollator) + continue; + + icu->ucolClose(testCollator); + if (status != U_ZERO_ERROR) + continue; + } } char version[U_MAX_VERSION_STRING_LENGTH]; diff --git a/src/common/unicode_util.h b/src/common/unicode_util.h index e98370a693e..ee0aa74aa71 100644 --- a/src/common/unicode_util.h +++ b/src/common/unicode_util.h @@ -30,7 +30,10 @@ #include "intlobj_new.h" #include "../common/IntlUtil.h" #include "../common/os/mod_loader.h" +#include "../common/classes/array.h" #include "../common/classes/fb_string.h" +#include "../common/classes/GenericMap.h" +#include "../common/classes/objects_array.h" #include #include @@ -63,14 +66,6 @@ class UnicodeUtil UChar32 (U_EXPORT2* utf8_nextCharSafeBody) (const uint8_t* s, int32_t* pi, int32_t length, UChar32 c, UBool strict); - void (U_EXPORT2* UCNV_FROM_U_CALLBACK_STOP) ( - const void *context, - UConverterFromUnicodeArgs *fromUArgs, - const UChar* codeUnits, - int32_t length, - UChar32 codePoint, - UConverterCallbackReason reason, - UErrorCode * err); void (U_EXPORT2* UCNV_TO_U_CALLBACK_STOP) ( const void *context, UConverterToUnicodeArgs *toUArgs, @@ -184,6 +179,11 @@ class UnicodeUtil Firebird::IntlUtil::SpecificAttributesMap& specificAttributes, const Firebird::string& configInfo); + Utf16Collation() + : contractionsPrefix(*getDefaultMemoryPool()) + { + } + ~Utf16Collation(); USHORT keyLength(USHORT len) const; @@ -194,6 +194,45 @@ class UnicodeUtil ULONG canonical(ULONG srcLen, const USHORT* src, ULONG dstLen, ULONG* dst, const ULONG* exceptions); private: + template + class ArrayComparator + { + public: + static bool greaterThan(const Firebird::Array& i1, const Firebird::Array& i2) + { + FB_SIZE_T minCount = MIN(i1.getCount(), i2.getCount()); + int cmp = memcmp(i1.begin(), i2.begin(), minCount * sizeof(T)); + + if (cmp != 0) + return cmp > 0; + + return i1.getCount() > i2.getCount(); + } + + static bool greaterThan(const Firebird::Array* i1, const Firebird::Array* i2) + { + return greaterThan(*i1, *i2); + } + }; + + typedef Firebird::SortedObjectsArray< + Firebird::Array, + Firebird::InlineStorage*, 3>, + Firebird::Array, + Firebird::DefaultKeyValue*>, + ArrayComparator + > SortKeyArray; + + typedef Firebird::GenericMap< + Firebird::Pair< + Firebird::Full< + Firebird::Array, // UTF-16 string + SortKeyArray // sort keys + > + >, + ArrayComparator + > ContractionsPrefixMap; + static ICU* loadICU(const Firebird::string& collVersion, const Firebird::string& locale, const Firebird::string& configInfo); @@ -206,8 +245,8 @@ class UnicodeUtil UCollator* compareCollator; UCollator* partialCollator; UCollator* sortCollator; - USet* contractions; - int contractionsCount; + ContractionsPrefixMap contractionsPrefix; + unsigned maxContractionsPrefixLength; // number of characters bool numericSort; }; diff --git a/src/common/utils.cpp b/src/common/utils.cpp index e0f7ac42b79..19f7f394a67 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -43,8 +43,10 @@ #include "../common/gdsassert.h" #include "../common/utils_proto.h" +#include "../common/classes/auto.h" #include "../common/classes/locks.h" #include "../common/classes/init.h" +#include "../common/isc_proto.h" #include "../jrd/constants.h" #include "firebird/impl/inf_pub.h" #include "../jrd/align.h" @@ -56,10 +58,13 @@ #include "../common/classes/ClumpletReader.h" #include "../common/StatusArg.h" #include "../common/TimeZoneUtil.h" +#include "../common/config/config.h" +#include "../common/ThreadStart.h" #ifdef WIN_NT #include #include // isatty() +#include #endif #ifdef HAVE_UNISTD_H @@ -438,26 +443,31 @@ bool prefix_kernel_object_name(char* name, size_t bufsize) class DynLibHandle { public: - explicit DynLibHandle(HMODULE mod) - : m_handle(mod) + explicit DynLibHandle(HMODULE mod, bool unload = true) + : m_handle(mod), m_unload(unload) {} + ~DynLibHandle() { - if (m_handle) + if (m_handle && m_unload) FreeLibrary(m_handle); } + operator HMODULE() const { return m_handle; } - /* The previous conversion is invoked with !object so this is enough. - bool operator!() const + + template + bool getProcAddress(const char* name, PFn& addr) const { - return !m_handle; + addr = (PFn) GetProcAddress(m_handle, name); + return (addr != nullptr); } - */ + private: - HMODULE m_handle; + const HMODULE m_handle; + const bool m_unload; }; @@ -555,6 +565,209 @@ bool isGlobalKernelPrefix() } +// Incapsulates Windows private namespace +class PrivateNamespace +{ +public: + PrivateNamespace(MemoryPool& pool) : + m_hNamespace(NULL), + m_hTestEvent(NULL) + { + try + { + init(); + } + catch (const Firebird::Exception& ex) + { + iscLogException("Error creating private namespace", ex); + } + } + + ~PrivateNamespace() + { + if (m_hNamespace != NULL) + (*pClosePrivateNamespace)(m_hNamespace, 0); + if (m_hTestEvent != NULL) + CloseHandle(m_hTestEvent); + } + + // Add namespace prefix to the name, returns true on success. + bool addPrefix(char* name, size_t bufsize) + { + if (!isReady()) + return false; + + if (strchr(name, '\\') != 0) + return false; + + const size_t prefixLen = strlen(sPrivateNameSpace) + 1; + const size_t nameLen = strlen(name) + 1; + if (prefixLen + nameLen > bufsize) + return false; + + memmove(name + prefixLen, name, nameLen + 1); + memcpy(name, sPrivateNameSpace, prefixLen - 1); + name[prefixLen - 1] = '\\'; + return true; + } + + bool isReady() const + { + return (m_hNamespace != NULL) || (m_hTestEvent != NULL); + } + +private: + typedef HANDLE (APIENTRY *PFnCreateBoundaryDescriptorA)(LPCSTR Name, ULONG Flags); + typedef BOOL (WINAPI *PFnAddSIDToBoundaryDescriptor)(HANDLE* BoundaryDescriptor, PSID RequiredSid); + typedef VOID (WINAPI *PFnDeleteBoundaryDescriptor)(HANDLE BoundaryDescriptor); + typedef HANDLE (WINAPI *PFnCreatePrivateNamespaceA)(LPSECURITY_ATTRIBUTES lpPrivateNamespaceAttributes, + LPVOID lpBoundaryDescriptor, LPCSTR lpAliasPrefix); + typedef HANDLE (WINAPI *PFnOpenPrivateNamespaceA)(LPVOID lpBoundaryDescriptor, LPCSTR lpAliasPrefix); + typedef BOOLEAN (WINAPI *PFnClosePrivateNamespace)(HANDLE Handle, ULONG Flags); + + PFnCreateBoundaryDescriptorA pCreateBoundaryDescriptor; + PFnAddSIDToBoundaryDescriptor pAddSIDToBoundaryDescriptor; + PFnDeleteBoundaryDescriptor pDeleteBoundaryDescriptor; + PFnCreatePrivateNamespaceA pCreatePrivateNamespace; + PFnOpenPrivateNamespaceA pOpenPrivateNamespace; + PFnClosePrivateNamespace pClosePrivateNamespace; + + + const char* sPrivateNameSpace = "FirebirdCommon"; + const char* sBoundaryName = "FirebirdCommonBoundary"; + + void raiseError(const char* apiRoutine) + { + (Firebird::Arg::Gds(isc_sys_request) << apiRoutine << Firebird::Arg::OsError()).raise(); + } + + bool initEntrypoints() + { + DynLibHandle hKernel32(GetModuleHandle("kernel32.dll"), false); + if (!hKernel32) + return false; + + return hKernel32.getProcAddress("CreateBoundaryDescriptorA", pCreateBoundaryDescriptor) && + hKernel32.getProcAddress("AddSIDToBoundaryDescriptor", pAddSIDToBoundaryDescriptor) && + hKernel32.getProcAddress("DeleteBoundaryDescriptor", pDeleteBoundaryDescriptor) && + hKernel32.getProcAddress("CreatePrivateNamespaceA", pCreatePrivateNamespace) && + hKernel32.getProcAddress("OpenPrivateNamespaceA", pOpenPrivateNamespace) && + hKernel32.getProcAddress("ClosePrivateNamespace", pClosePrivateNamespace); + } + + void init() + { + if (!initEntrypoints()) + return; + + alignas(SID) char sid[SECURITY_MAX_SID_SIZE]; + DWORD cbSid = sizeof(sid); + + // For now use EVERYONE, could be changed later + cbSid = sizeof(sid); + if (!CreateWellKnownSid(WinWorldSid, NULL, &sid, &cbSid)) + raiseError("CreateWellKnownSid"); + + // Create security descriptor which allows generic access to the just created SID + + SECURITY_ATTRIBUTES sa; + RtlSecureZeroMemory(&sa, sizeof(sa)); + sa.nLength = sizeof(sa); + sa.bInheritHandle = FALSE; + + char strSecDesc[255]; + LPSTR strSid = NULL; + if (ConvertSidToStringSid(&sid, &strSid)) + { + snprintf(strSecDesc, sizeof(strSecDesc), "D:(A;;GA;;;%s)", strSid); + LocalFree(strSid); + } + else + strncpy(strSecDesc, "D:(A;;GA;;;WD)", sizeof(strSecDesc)); + + if (!ConvertStringSecurityDescriptorToSecurityDescriptor(strSecDesc, SDDL_REVISION_1, + &sa.lpSecurityDescriptor, NULL)) + { + raiseError("ConvertStringSecurityDescriptorToSecurityDescriptor"); + } + + Firebird::Cleanup cleanSecDesc( [&sa] { + LocalFree(sa.lpSecurityDescriptor); + }); + + HANDLE hBoundaryDesc = (*pCreateBoundaryDescriptor)(sBoundaryName, 0); + if (hBoundaryDesc == NULL) + raiseError("CreateBoundaryDescriptor"); + + Firebird::Cleanup cleanBndDesc( [this, &hBoundaryDesc] { + (*pDeleteBoundaryDescriptor)(hBoundaryDesc); + }); + + if (!(*pAddSIDToBoundaryDescriptor)(&hBoundaryDesc, &sid)) + raiseError("AddSIDToBoundaryDescriptor"); + + int retry = 0; + while (true) + { + m_hNamespace = (*pCreatePrivateNamespace)(&sa, hBoundaryDesc, sPrivateNameSpace); + + if (m_hNamespace == NULL) + { + DWORD err = GetLastError(); + if (err != ERROR_ALREADY_EXISTS) + raiseError("CreatePrivateNamespace"); + + m_hNamespace = (*pOpenPrivateNamespace)(hBoundaryDesc, sPrivateNameSpace); + if (m_hNamespace == NULL) + { + err = GetLastError(); + if ((err == ERROR_PATH_NOT_FOUND) && (retry++ < 100)) + { + // Namespace was closed by its last holder, wait a bit and try again + Thread::sleep(10); + continue; + } + + if (err != ERROR_DUP_NAME) + raiseError("OpenPrivateNamespace"); + + Firebird::string name(sPrivateNameSpace); + name.append("\\test"); + + m_hTestEvent = CreateEvent(ISC_get_security_desc(), TRUE, TRUE, name.c_str()); + if (m_hTestEvent == NULL) + raiseError("CreateEvent"); + } + } + + break; + } + } + + HANDLE m_hNamespace; + HANDLE m_hTestEvent; +}; + +static Firebird::InitInstance privateNamespace; + + +bool private_kernel_object_name(char* name, size_t bufsize) +{ + const bool legacyNames = Firebird::Config::getLegacyKernelNames(); + + if (legacyNames || !privateNamespace().addPrefix(name, bufsize)) + return prefix_kernel_object_name(name, bufsize); + + return true; +} + +bool privateNameSpaceReady() +{ + const bool legacyNames = Firebird::Config::getLegacyKernelNames(); + return !legacyNames && privateNamespace().isReady(); +} + + // This is a very basic registry querying class. Not much validation, but avoids // leaving the registry open by mistake. @@ -1370,9 +1583,9 @@ void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items, --itemsLength; unsigned int len = dbpath.length(); - if (len + 3 > bufferLength) + if (len + 4 > bufferLength) { - len = bufferLength - 3; + len = bufferLength - 4; } bufferLength -= (len + 3); *buffer++ = fb_info_tra_dbpath; @@ -1380,6 +1593,7 @@ void getDbPathInfo(unsigned int& itemsLength, const unsigned char*& items, *buffer++ = len >> 8; memcpy(buffer, dbpath.c_str(), len); buffer += len; + *buffer = isc_info_end; } } } @@ -1610,6 +1824,13 @@ bool containsErrorCode(const ISC_STATUS* v, ISC_STATUS code) return false; } +inline bool sqlSymbolChar(char c, bool first) +{ + if (c & 0x80) + return false; + return (isdigit(c) && !first) || isalpha(c) || c == '_' || c == '$'; +} + const char* dpbItemUpper(const char* s, FB_SIZE_T l, Firebird::string& buf) { if (l && (s[0] == '"' || s[0] == '\'')) @@ -1622,30 +1843,37 @@ const char* dpbItemUpper(const char* s, FB_SIZE_T l, Firebird::string& buf) { if (s[i] == end_quote) { - if (++i >= l || s[i] != end_quote) - break; // delimited quote, done processing + if (++i >= l) + { + if (ascii && s[0] == '\'') + buf.upper(); + + return buf.c_str(); + } + + if (s[i] != end_quote) + { + buf.assign(&s[i], l - i); + Firebird::fatal_exception::raiseFmt("Invalid text <%s> after quoted string", buf.c_str()); + } // skipped the escape quote, continue processing } - - if (s[i] & 0x80) + else if (!sqlSymbolChar(s[i], i == 1)) ascii = false; + buf += s[i]; } - if (ascii && s[0] == '\'') - buf.upper(); - - return buf.c_str(); + Firebird::fatal_exception::raiseFmt("Missing terminating quote <%c> in the end of quoted string", s[0]); } // non-quoted string - try to uppercase for (FB_SIZE_T i = 0; i < l; ++i) { - if (!(s[i] & 0x80)) - buf += toupper(s[i]); - else + if (!sqlSymbolChar(s[i], i == 0)) return NULL; // contains non-ascii data + buf += toupper(s[i]); } return buf.c_str(); diff --git a/src/common/utils_proto.h b/src/common/utils_proto.h index d87678ae9dc..d16a11cb21d 100644 --- a/src/common/utils_proto.h +++ b/src/common/utils_proto.h @@ -102,6 +102,8 @@ namespace fb_utils #ifdef WIN_NT bool prefix_kernel_object_name(char* name, size_t bufsize); bool isGlobalKernelPrefix(); + bool private_kernel_object_name(char* name, size_t bufsize); + bool privateNameSpaceReady(); #endif // Compare the absolute value of two SINT64 numbers. diff --git a/src/common/xdr.cpp b/src/common/xdr.cpp index 8a1f54a6c25..555e6e1f40c 100644 --- a/src/common/xdr.cpp +++ b/src/common/xdr.cpp @@ -291,7 +291,7 @@ bool_t xdr_datum( xdr_t* xdrs, const dsc* desc, UCHAR* buffer) break; case dtype_timestamp_tz: - fb_assert(desc->dsc_length >= 2 * sizeof(SLONG) + 1); + fb_assert(desc->dsc_length >= 2 * sizeof(SLONG) + sizeof(SSHORT)); if (!xdr_long(xdrs, &((SLONG*) p)[0])) return FALSE; if (!xdr_long(xdrs, &((SLONG*) p)[1])) @@ -381,23 +381,56 @@ bool_t xdr_double(xdr_t* xdrs, double* ip) return FALSE; } +/* +DecFloat (at least as implemented in IBM's library) has a kind of PDP-endian format: +Bytes in 4-byte words are in endianess dependent order +4-byte words - are in endianess independent order + +Therefore need in special processing +*/ + +static bool_t xdr_decfloat_hyper(xdr_t* xdrs, void* dec) +{ + SLONG temp_long[2]; + + switch (xdrs->x_op) + { + case XDR_ENCODE: + memcpy(temp_long, dec, sizeof temp_long); + if (PUTLONG(xdrs, &temp_long[1]) && + PUTLONG(xdrs, &temp_long[0])) + { + return TRUE; + } + return FALSE; + + case XDR_DECODE: + if (!GETLONG(xdrs, &temp_long[1]) || + !GETLONG(xdrs, &temp_long[0])) + { + return FALSE; + } + memcpy(dec, temp_long, sizeof temp_long); + return TRUE; + + case XDR_FREE: + return TRUE; + } + // TMN: added compiler silencier return FALSE. + return FALSE; +} + bool_t xdr_dec64(xdr_t* xdrs, Firebird::Decimal64* ip) { - return xdr_hyper(xdrs, ip->getBytes()); + return xdr_decfloat_hyper(xdrs, ip->getBytes()); } bool_t xdr_dec128(xdr_t* xdrs, Firebird::Decimal128* ip) { UCHAR* bytes = ip->getBytes(); - -#ifndef WORDS_BIGENDIAN - return xdr_hyper(xdrs, &bytes[8]) && xdr_hyper(xdrs, &bytes[0]); -#else - fb_assert(false); // Dec64/128 XDR not tested on bigendians! - return xdr_hyper(xdrs, &bytes[0]) && xdr_hyper(xdrs, &bytes[8]); -#endif + return xdr_decfloat_hyper(xdrs, &bytes[8]) && xdr_decfloat_hyper(xdrs, &bytes[0]); } diff --git a/src/dsql/AggNodes.cpp b/src/dsql/AggNodes.cpp index a6ef28d6a58..32b722e0509 100644 --- a/src/dsql/AggNodes.cpp +++ b/src/dsql/AggNodes.cpp @@ -516,11 +516,9 @@ void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) return; if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) - { - desc->dsc_dtype = dtype_dec128; - desc->dsc_length = sizeof(Decimal128); - } - else if (dialect1) + return; + + if (dialect1) { if (!DTYPE_IS_NUMERIC(desc->dsc_dtype) && !DTYPE_IS_TEXT(desc->dsc_dtype)) { @@ -540,7 +538,7 @@ void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) ERRD_post(Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_dsql_agg2_wrongarg) << Arg::Str("AVG")); } - else if (desc->dsc_dtype == dtype_int64 || desc->dsc_dtype == dtype_int128) + else if (desc->dsc_dtype == dtype_int128) { desc->dsc_dtype = dtype_int128; desc->dsc_length = sizeof(Int128); @@ -561,15 +559,40 @@ void AvgAggNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { arg->getDesc(tdbb, csb, desc); + outputDesc(desc); + + switch (desc->dsc_dtype) + { + case dtype_dec64: + case dtype_dec128: + nodFlags |= FLAG_DECFLOAT; + break; + case dtype_int64: + case dtype_int128: + nodFlags |= FLAG_INT128; + // fall down... + case dtype_short: + case dtype_long: + nodScale = desc->dsc_scale; + break; + + case dtype_unknown: + break; + + default: + nodFlags |= FLAG_DOUBLE; + break; + } +} + +void AvgAggNode::outputDesc(dsc* desc) const +{ if (DTYPE_IS_DECFLOAT(desc->dsc_dtype)) { - desc->dsc_dtype = dtype_dec128; - desc->dsc_length = sizeof(Decimal128); desc->dsc_scale = 0; desc->dsc_sub_type = 0; desc->dsc_flags = 0; - nodFlags |= FLAG_DECFLOAT; return; } @@ -593,19 +616,16 @@ void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) { case dtype_short: case dtype_long: + case dtype_int64: desc->dsc_dtype = dtype_int64; desc->dsc_length = sizeof(SINT64); desc->dsc_flags = 0; - nodScale = desc->dsc_scale; break; - case dtype_int64: case dtype_int128: desc->dsc_dtype = dtype_int128; desc->dsc_length = sizeof(Int128); desc->dsc_flags = 0; - nodScale = desc->dsc_scale; - nodFlags |= FLAG_INT128; break; case dtype_unknown: @@ -630,7 +650,6 @@ void AvgAggNode::getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc) desc->dsc_scale = 0; desc->dsc_sub_type = 0; desc->dsc_flags = 0; - nodFlags |= FLAG_DOUBLE; break; } } @@ -680,7 +699,7 @@ void AvgAggNode::aggInit(thread_db* tdbb, jrd_req* request) const else { // Initialize the result area as an int64. If the field being aggregated is approximate - // numeric, the first call to add will convert the descriptor to double. + // numeric, the first call to add will convert the descriptor. impure->make_int64(0, nodScale); } } @@ -688,7 +707,12 @@ void AvgAggNode::aggInit(thread_db* tdbb, jrd_req* request) const void AvgAggNode::aggPass(thread_db* tdbb, jrd_req* request, dsc* desc) const { impure_value_ex* impure = request->getImpure(impureOffset); - ++impure->vlux_count; + if (impure->vlux_count++ == 0) // first call to aggPass() + { + impure_value_ex* impureTemp = request->getImpure(tempImpure); + impureTemp->vlu_desc = *desc; + outputDesc(&impureTemp->vlu_desc); + } if (dialect1) ArithmeticNode::add(tdbb, desc, impure, this, blr_add); @@ -707,8 +731,12 @@ dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const SINT64 i; double d; Decimal128 dec; + Decimal64 d64; Int128 i128; + impure_value_ex* impureTemp = request->getImpure(tempImpure); + UCHAR dtype = impureTemp->vlu_desc.dsc_dtype; + if (!dialect1 && impure->vlu_desc.dsc_dtype == dtype_int64) { i = *((SINT64*) impure->vlu_desc.dsc_address) / impure->vlux_count; @@ -718,22 +746,36 @@ dsc* AvgAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const { i128.set(impure->vlux_count, 0); i128 = ((Int128*) impure->vlu_desc.dsc_address)->div(i128, 0); - temp.makeInt128(impure->vlu_desc.dsc_scale, &i128); + if (dtype == dtype_int128) + temp.makeInt128(impure->vlu_desc.dsc_scale, &i128); + else + { + fb_assert(dtype == dtype_int64); + i = i128.toInt64(0); + temp.makeInt64(impure->vlu_desc.dsc_scale, &i); + } } - else if (DTYPE_IS_DECFLOAT(impure->vlu_desc.dsc_dtype)) + else if (dtype == dtype_dec128) { DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; dec.set(impure->vlux_count, decSt, 0); dec = MOV_get_dec128(tdbb, &impure->vlu_desc).div(decSt, dec); temp.makeDecimal128(&dec); } + else if (dtype == dtype_dec64) + { + DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; + // use higher precision for division + dec.set(impure->vlux_count, decSt, 0); + d64 = MOV_get_dec128(tdbb, &impure->vlu_desc).div(decSt, dec).toDecimal64(decSt); + temp.makeDecimal64(&d64); + } else { d = MOV_get_double(tdbb, &impure->vlu_desc) / impure->vlux_count; temp.makeDouble(&d); } - impure_value_ex* impureTemp = request->getImpure(tempImpure); EVL_make_value(tdbb, &temp, impureTemp); return &impureTemp->vlu_desc; @@ -1986,12 +2028,15 @@ void RegrAggNode::aggPass(thread_db* /*tdbb*/, jrd_req* /*request*/, dsc* /*desc dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const { impure_value_ex* impure = request->getImpure(impureOffset); - RegrImpure* impure2 = request->getImpure(impure2Offset); - dsc temp; if (impure->vlux_count == 0) return NULL; + RegrImpure* impure2 = request->getImpure(impure2Offset); + dsc temp; + double doubleVal; + Decimal128 decimal128Val; + if (nodFlags & FLAG_DECFLOAT) { DecimalStatus decSt = tdbb->getAttachment()->att_dec_status; @@ -2012,57 +2057,55 @@ dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const const Decimal128 sq = varPopX.sqrt(decSt).mul(decSt, varPopY.sqrt(decSt)); const Decimal128 corr = covarPop.div(safeDivide, sq); - Decimal128 d; - switch (type) { case TYPE_REGR_AVGX: - d = avgX; + decimal128Val = avgX; break; case TYPE_REGR_AVGY: - d = avgY; + decimal128Val = avgY; break; case TYPE_REGR_INTERCEPT: if (varPopX.compare(decSt, CDecimal128(0)) == 0) return NULL; else - d = avgY.sub(decSt, slope.mul(decSt, avgX)); + decimal128Val = avgY.sub(decSt, slope.mul(decSt, avgX)); break; case TYPE_REGR_R2: if (varPopX.compare(decSt, CDecimal128(0)) == 0) return NULL; else if (varPopY.compare(decSt, CDecimal128(0)) == 0) - d.set(1, decSt, 0); + decimal128Val.set(1, decSt, 0); else if (sq.compare(decSt, CDecimal128(0)) == 0) return NULL; else - d = corr.mul(decSt, corr); + decimal128Val = corr.mul(decSt, corr); break; case TYPE_REGR_SLOPE: if (varPopX.compare(decSt, CDecimal128(0)) == 0) return NULL; else - d = slope; + decimal128Val = slope; break; case TYPE_REGR_SXX: - d = sxx; + decimal128Val = sxx; break; case TYPE_REGR_SXY: - d = sxy; + decimal128Val = sxy; break; case TYPE_REGR_SYY: - d = syy; + decimal128Val = syy; break; } - temp.makeDecimal128(&d); + temp.makeDecimal128(&decimal128Val); } else { @@ -2075,57 +2118,55 @@ dsc* RegrAggNode::aggExecute(thread_db* tdbb, jrd_req* request) const const double sq = sqrt(varPopX) * sqrt(varPopY); const double corr = covarPop / sq; - double d; - switch (type) { case TYPE_REGR_AVGX: - d = avgX; + doubleVal = avgX; break; case TYPE_REGR_AVGY: - d = avgY; + doubleVal = avgY; break; case TYPE_REGR_INTERCEPT: if (varPopX == 0.0) return NULL; else - d = avgY - slope * avgX; + doubleVal = avgY - slope * avgX; break; case TYPE_REGR_R2: if (varPopX == 0.0) return NULL; else if (varPopY == 0.0) - d = 1.0; + doubleVal = 1.0; else if (sq == 0.0) return NULL; else - d = corr * corr; + doubleVal = corr * corr; break; case TYPE_REGR_SLOPE: if (varPopX == 0.0) return NULL; else - d = covarPop / varPopX; + doubleVal = covarPop / varPopX; break; case TYPE_REGR_SXX: - d = impure->vlux_count * varPopX; + doubleVal = impure->vlux_count * varPopX; break; case TYPE_REGR_SXY: - d = impure->vlux_count * covarPop; + doubleVal = impure->vlux_count * covarPop; break; case TYPE_REGR_SYY: - d = impure->vlux_count * varPopY; + doubleVal = impure->vlux_count * varPopY; break; } - temp.makeDouble(&d); + temp.makeDouble(&doubleVal); } EVL_make_value(tdbb, &temp, impure); diff --git a/src/dsql/AggNodes.h b/src/dsql/AggNodes.h index d63d0da693b..2d122c41d28 100644 --- a/src/dsql/AggNodes.h +++ b/src/dsql/AggNodes.h @@ -61,6 +61,7 @@ class AvgAggNode : public AggNode virtual AggNode* dsqlCopy(DsqlCompilerScratch* dsqlScratch) /*const*/; private: + void outputDesc(dsc* desc) const; ULONG tempImpure; }; diff --git a/src/dsql/BoolNodes.cpp b/src/dsql/BoolNodes.cpp index 58a849c709f..eb680c905fe 100644 --- a/src/dsql/BoolNodes.cpp +++ b/src/dsql/BoolNodes.cpp @@ -634,9 +634,12 @@ void ComparativeBoolNode::pass2Boolean2(thread_db* tdbb, CompilerScratch* csb) arg1->nodFlags |= FLAG_DATE; if (nodFlags & FLAG_INVARIANT) + impureOffset = csb->allocImpure(); + // Do not use FLAG_PATTERN_MATCHER_CACHE for blr_starting as it has very fast compilation. + else if (blrOp == blr_containing || blrOp == blr_like || blrOp == blr_similar) { - // This may currently happen for nod_like, nod_contains and nod_similar impureOffset = csb->allocImpure(); + nodFlags |= FLAG_PATTERN_MATCHER_CACHE; } } @@ -653,7 +656,9 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const desc[0] = EVL_expr(tdbb, request, arg1); - const ULONG flags = request->req_flags; + // arg1 IS NULL + const bool null1 = (request->req_flags & req_null); + request->req_flags &= ~req_null; bool force_equal = (request->req_flags & req_same_tx_upd) != 0; @@ -718,19 +723,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const else desc[1] = EVL_expr(tdbb, request, arg2); + // arg2 IS NULL + const bool null2 = (request->req_flags & req_null); + // An equivalence operator evaluates to true when both operands // are NULL and behaves like an equality operator otherwise. // Note that this operator never sets req_null flag if (blrOp == blr_equiv) { - if ((flags & req_null) && (request->req_flags & req_null)) + if (null1 && null2) { request->req_flags &= ~req_null; return true; } - if ((flags & req_null) || (request->req_flags & req_null)) + if (null1 || null2) { request->req_flags &= ~req_null; return false; @@ -738,13 +746,15 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const } // If either of expressions above returned NULL set req_null flag - // and return false + // and return false. The exception is BETWEEN operator that could + // return FALSE even when arg2 IS NULL, for example: + // 1 BETWEEN NULL AND 0 - if (flags & req_null) + if (null1 || (null2 && (blrOp != blr_between))) + { request->req_flags |= req_null; - - if (request->req_flags & req_null) return false; + } force_equal |= (request->req_flags & req_same_tx_upd) != 0; int comparison; // while the two switch() below are in sync, no need to initialize @@ -758,8 +768,19 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const case blr_lss: case blr_leq: case blr_neq: - case blr_between: comparison = MOV_compare(tdbb, desc[0], desc[1]); + break; + + case blr_between: + if (!null2) + { + comparison = MOV_compare(tdbb, desc[0], desc[1]); + if (comparison < 0) + return false; + } + else + comparison = -1; + break; } // If we are checking equality of record_version @@ -796,8 +817,22 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const case blr_between: desc[1] = EVL_expr(tdbb, request, arg3); if (request->req_flags & req_null) + { + if (!null2 && comparison < 0) + request->req_flags &= ~req_null; return false; - return comparison >= 0 && MOV_compare(tdbb, desc[0], desc[1]) <= 0; + } + { + // arg1 <= arg3 + const bool cmp1_3 = (MOV_compare(tdbb, desc[0], desc[1]) <= 0); + if (null2) + { + if (cmp1_3) + request->req_flags |= req_null; + return false; + } + return cmp1_3; + } case blr_containing: case blr_starting: @@ -815,367 +850,208 @@ bool ComparativeBoolNode::execute(thread_db* tdbb, jrd_req* request) const // Perform one of the complex string functions CONTAINING, MATCHES, or STARTS WITH. bool ComparativeBoolNode::stringBoolean(thread_db* tdbb, jrd_req* request, dsc* desc1, - dsc* desc2, bool computed_invariant) const + dsc* desc2, bool computedInvariant) const { - UCHAR* p1 = NULL; - UCHAR* p2 = NULL; - SLONG l2 = 0; - USHORT type1; - MoveBuffer match_str; - SET_TDBB(tdbb); - if (!desc1->isBlob()) - { - // Source is not a blob, do a simple search - - // Get text type of data string + USHORT type1; + if (!desc1->isBlob()) type1 = INTL_TEXT_TYPE(*desc1); - - // Get address and length of search string - convert to datatype of data - - if (!computed_invariant) - l2 = MOV_make_string2(tdbb, desc2, type1, &p2, match_str, false); - - VaryStr<256> temp1; - USHORT xtype1; - const USHORT l1 = MOV_get_string_ptr(tdbb, desc1, &xtype1, &p1, &temp1, sizeof(temp1)); - - fb_assert(xtype1 == type1); - - return stringFunction(tdbb, request, l1, p1, l2, p2, type1, computed_invariant); - } - - // Source string is a blob, things get interesting - - HalfStaticArray buffer; - - if (desc1->dsc_sub_type == isc_blob_text) - type1 = desc1->dsc_blob_ttype(); // pick up character set and collation of blob else - type1 = ttype_none; // Do byte matching - - Collation* obj = INTL_texttype_lookup(tdbb, type1); - CharSet* charset = obj->getCharSet(); - - // Get address and length of search string - make it string if necessary - // but don't transliterate character set if the source blob is binary - if (!computed_invariant) { - l2 = MOV_make_string2(tdbb, desc2, type1, &p2, match_str, false); - } - - blb* blob = blb::open(tdbb, request->req_transaction, reinterpret_cast(desc1->dsc_address)); + // No MATCHES support for blob + if (blrOp == blr_matching) + return false; - if (charset->isMultiByte() && - (blrOp != blr_starting || !(obj->getFlags() & TEXTTYPE_DIRECT_MATCH))) - { - buffer.getBuffer(blob->blb_length); // alloc space to put entire blob in memory + type1 = desc1->dsc_sub_type == isc_blob_text ? desc1->dsc_blob_ttype() : ttype_none; } - // Performs the string_function on each segment of the blob until - // a positive result is obtained + Collation* obj = INTL_texttype_lookup(tdbb, type1); + CharSet* charset = obj->getCharSet(); - bool ret_val = false; + VaryStr escapeTemp; + const UCHAR* escapeStr = nullptr; + USHORT escapeLen = 0; - switch (blrOp) + // Handle escape for LIKE and SIMILAR + if (blrOp == blr_like || blrOp == blr_similar) { - case blr_like: - case blr_similar: + // ensure 3rd argument (escape char) is in operation text type + if (arg3 && !computedInvariant) { - VaryStr temp3; - const UCHAR* escape_str = NULL; - USHORT escape_length = 0; + // Convert ESCAPE to operation character set + dsc* desc = EVL_expr(tdbb, request, arg3); - // ensure 3rd argument (escape char) is in operation text type - if (arg3 && !computed_invariant) + if (request->req_flags & req_null) { - // Convert ESCAPE to operation character set - dsc* desc = EVL_expr(tdbb, request, arg3); - - if (request->req_flags & req_null) - { - if (nodFlags & FLAG_INVARIANT) - { - impure_value* impure = request->getImpure(impureOffset); - impure->vlu_flags |= VLU_computed; - impure->vlu_flags |= VLU_null; - } - ret_val = false; - break; - } - - escape_length = MOV_make_string(tdbb, desc, type1, - reinterpret_cast(&escape_str), &temp3, sizeof(temp3)); - - if (!escape_length || charset->length(escape_length, escape_str, true) != 1) - { - // If characters left, or null byte character, return error - blob->BLB_close(tdbb); - ERR_post(Arg::Gds(isc_escape_invalid)); - } - - USHORT escape[2] = {0, 0}; - - charset->getConvToUnicode().convert(escape_length, escape_str, sizeof(escape), escape); - if (!escape[0]) + if (nodFlags & FLAG_INVARIANT) { - // If or null byte character, return error - blob->BLB_close(tdbb); - ERR_post(Arg::Gds(isc_escape_invalid)); + impure_value* impure = request->getImpure(impureOffset); + impure->vlu_flags |= VLU_computed; + impure->vlu_flags |= VLU_null; } + return false; } - PatternMatcher* evaluator; + escapeLen = MOV_make_string(tdbb, desc, type1, + reinterpret_cast(&escapeStr), &escapeTemp, sizeof(escapeTemp)); - if (nodFlags & FLAG_INVARIANT) + if (!escapeLen || charset->length(escapeLen, escapeStr, true) != 1) { - impure_value* impure = request->getImpure(impureOffset); + // If characters left, or null byte character, return error + ERR_post(Arg::Gds(isc_escape_invalid)); + } - if (!(impure->vlu_flags & VLU_computed)) - { - delete impure->vlu_misc.vlu_invariant; - impure->vlu_flags |= VLU_computed; + USHORT escape[2] = {0, 0}; - if (blrOp == blr_like) - { - impure->vlu_misc.vlu_invariant = evaluator = obj->createLikeMatcher( - *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length); - } - else // nod_similar - { - impure->vlu_misc.vlu_invariant = evaluator = obj->createSimilarToMatcher( - tdbb, *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length); - } - } - else - { - evaluator = impure->vlu_misc.vlu_invariant; - evaluator->reset(); - } - } - else if (blrOp == blr_like) - { - evaluator = obj->createLikeMatcher(*tdbb->getDefaultPool(), - p2, l2, escape_str, escape_length); - } - else // nod_similar - { - evaluator = obj->createSimilarToMatcher(tdbb, *tdbb->getDefaultPool(), - p2, l2, escape_str, escape_length); - } + charset->getConvToUnicode().convert(escapeLen, escapeStr, sizeof(escape), escape); - while (!(blob->blb_flags & BLB_eof)) + if (!escape[0]) { - const SLONG l1 = blob->BLB_get_data(tdbb, buffer.begin(), buffer.getCapacity(), false); - if (!evaluator->process(buffer.begin(), l1)) - break; + // If or null byte character, return error + ERR_post(Arg::Gds(isc_escape_invalid)); } - - ret_val = evaluator->result(); - - if (!(nodFlags & FLAG_INVARIANT)) - delete evaluator; - - break; } + } - case blr_containing: - case blr_starting: - { - PatternMatcher* evaluator; + UCHAR* patternStr = nullptr; + SLONG patternLen = 0; + MoveBuffer patternBuffer; - if (nodFlags & FLAG_INVARIANT) - { - impure_value* impure = request->getImpure(impureOffset); - if (!(impure->vlu_flags & VLU_computed)) - { - delete impure->vlu_misc.vlu_invariant; - - if (blrOp == blr_containing) - { - impure->vlu_misc.vlu_invariant = evaluator = - obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2); - } - else // nod_starts - { - impure->vlu_misc.vlu_invariant = evaluator = - obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2); - } + auto createMatcher = [&]() + { + return blrOp == blr_containing ? obj->createContainsMatcher(*tdbb->getDefaultPool(), patternStr, patternLen) : + blrOp == blr_starting ? obj->createStartsMatcher(*tdbb->getDefaultPool(), patternStr, patternLen) : + blrOp == blr_like ? obj->createLikeMatcher(*tdbb->getDefaultPool(), + patternStr, patternLen, escapeStr, escapeLen) : + blrOp == blr_similar ? obj->createSimilarToMatcher(tdbb, *tdbb->getDefaultPool(), + patternStr, patternLen, escapeStr, escapeLen) : + nullptr; // blr_matching + }; - impure->vlu_flags |= VLU_computed; - } - else - { - evaluator = impure->vlu_misc.vlu_invariant; - evaluator->reset(); - } - } - else - { - if (blrOp == blr_containing) - evaluator = obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2); - else // nod_starts - evaluator = obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2); - } + // Get address and length of search string - convert to datatype of data + if (!computedInvariant) + patternLen = MOV_make_string2(tdbb, desc2, type1, &patternStr, patternBuffer, false); - while (!(blob->blb_flags & BLB_eof)) - { - const SLONG l1 = blob->BLB_get_data(tdbb, buffer.begin(), buffer.getCapacity(), false); - if (!evaluator->process(buffer.begin(), l1)) - break; - } + AutoPtr autoEvaluator; // deallocate non-invariant/non-cached evaluator + PatternMatcher* evaluator; - ret_val = evaluator->result(); + impure_value* impure = request->getImpure(impureOffset); - if (!(nodFlags & FLAG_INVARIANT)) - delete evaluator; + if (nodFlags & FLAG_INVARIANT) + { + auto& matcher = impure->vlu_misc.vlu_invariant; - break; + if (!(impure->vlu_flags & VLU_computed)) + { + delete matcher; + matcher = nullptr; + matcher = createMatcher(); + impure->vlu_flags |= VLU_computed; } - } - - blob->BLB_close(tdbb); - - return ret_val; -} - -// Perform one of the pattern matching string functions. -bool ComparativeBoolNode::stringFunction(thread_db* tdbb, jrd_req* request, - SLONG l1, const UCHAR* p1, SLONG l2, const UCHAR* p2, USHORT ttype, - bool computed_invariant) const -{ - SET_TDBB(tdbb); - - Collation* obj = INTL_texttype_lookup(tdbb, ttype); - CharSet* charset = obj->getCharSet(); + else + matcher->reset(); - // Handle contains and starts - if (blrOp == blr_containing || blrOp == blr_starting) + evaluator = matcher; + } + else if (nodFlags & FLAG_PATTERN_MATCHER_CACHE) { - if (nodFlags & FLAG_INVARIANT) + auto& cache = impure->vlu_misc.vlu_patternMatcherCache; + const bool cacheHit = cache && + cache->matcher && + cache->ttype == type1 && + cache->patternLen == patternLen && + cache->escapeLen == escapeLen && + memcmp(cache->key, patternStr, patternLen) == 0 && + memcmp(cache->key + patternLen, escapeStr, escapeLen) == 0; + + if (cacheHit) + cache->matcher->reset(); + else { - impure_value* impure = request->getImpure(impureOffset); - PatternMatcher* evaluator; - if (!(impure->vlu_flags & VLU_computed)) + if (cache && cache->keySize < patternLen + escapeLen) { - delete impure->vlu_misc.vlu_invariant; - - if (blrOp == blr_containing) - { - impure->vlu_misc.vlu_invariant = evaluator = - obj->createContainsMatcher(*tdbb->getDefaultPool(), p2, l2); - } - else - { - // nod_starts - impure->vlu_misc.vlu_invariant = evaluator = - obj->createStartsMatcher(*tdbb->getDefaultPool(), p2, l2); - } - - impure->vlu_flags |= VLU_computed; + delete cache; + cache = nullptr; } - else + + if (!cache) { - evaluator = impure->vlu_misc.vlu_invariant; - evaluator->reset(); + cache = FB_NEW_RPT(*tdbb->getDefaultPool(), patternLen + escapeLen) + impure_value::PatternMatcherCache(patternLen + escapeLen); } - evaluator->process(p1, l1); - return evaluator->result(); - } + cache->ttype = type1; + cache->patternLen = patternLen; + cache->escapeLen = escapeLen; + memcpy(cache->key, patternStr, patternLen); + memcpy(cache->key + patternLen, escapeStr, escapeLen); - if (blrOp == blr_containing) - return obj->contains(*tdbb->getDefaultPool(), p1, l1, p2, l2); + cache->matcher = createMatcher(); + } - // nod_starts - return obj->starts(*tdbb->getDefaultPool(), p1, l1, p2, l2); + evaluator = cache->matcher; } + else + autoEvaluator = evaluator = desc1->isBlob() ? createMatcher() : nullptr; - // Handle LIKE and SIMILAR - if (blrOp == blr_like || blrOp == blr_similar) + if (!desc1->isBlob()) { - VaryStr temp3; - const UCHAR* escape_str = NULL; - USHORT escape_length = 0; - // ensure 3rd argument (escape char) is in operation text type - if (arg3 && !computed_invariant) - { - // Convert ESCAPE to operation character set - dsc* desc = EVL_expr(tdbb, request, arg3); - if (request->req_flags & req_null) - { - if (nodFlags & FLAG_INVARIANT) - { - impure_value* impure = request->getImpure(impureOffset); - impure->vlu_flags |= VLU_computed; - impure->vlu_flags |= VLU_null; - } - return false; - } - - escape_length = MOV_make_string(tdbb, desc, ttype, - reinterpret_cast(&escape_str), &temp3, sizeof(temp3)); - - if (!escape_length || charset->length(escape_length, escape_str, true) != 1) - { - // If characters left, or null byte character, return error - ERR_post(Arg::Gds(isc_escape_invalid)); - } - - USHORT escape[2] = {0, 0}; + // Source is not a blob, do a simple search - charset->getConvToUnicode().convert(escape_length, escape_str, sizeof(escape), escape); + VaryStr<256> temp1; + UCHAR* str = NULL; + const USHORT strLen = MOV_get_string_ptr(tdbb, desc1, &type1, &str, &temp1, sizeof(temp1)); - if (!escape[0]) + if (evaluator) + { + evaluator->process(str, strLen); + return evaluator->result(); + } + else + { + if (blrOp == blr_containing) + return obj->contains(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); + else if (blrOp == blr_starting) + return obj->starts(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); + else if (blrOp == blr_like) + return obj->like(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen, escapeStr, escapeLen); + else if (blrOp == blr_similar) { - // If or null byte character, return error - ERR_post(Arg::Gds(isc_escape_invalid)); + return obj->similarTo(tdbb, *tdbb->getDefaultPool(), + str, strLen, patternStr, patternLen, escapeStr, escapeLen); } + else // blr_matching + return obj->matches(*tdbb->getDefaultPool(), str, strLen, patternStr, patternLen); } + } - if (nodFlags & FLAG_INVARIANT) - { - impure_value* impure = request->getImpure(impureOffset); - PatternMatcher* evaluator; + fb_assert(evaluator); - if (!(impure->vlu_flags & VLU_computed)) - { - delete impure->vlu_misc.vlu_invariant; - impure->vlu_flags |= VLU_computed; + // Source string is a blob, things get interesting - if (blrOp == blr_like) - { - impure->vlu_misc.vlu_invariant = evaluator = obj->createLikeMatcher( - *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length); - } - else // nod_similar - { - impure->vlu_misc.vlu_invariant = evaluator = obj->createSimilarToMatcher( - tdbb, *tdbb->getDefaultPool(), p2, l2, escape_str, escape_length); - } - } - else - { - evaluator = impure->vlu_misc.vlu_invariant; - evaluator->reset(); - } + AutoBlb blob(tdbb, blb::open(tdbb, request->req_transaction, reinterpret_cast(desc1->dsc_address))); - evaluator->process(p1, l1); + HalfStaticArray buffer; - return evaluator->result(); - } + if (charset->isMultiByte() && + (blrOp != blr_starting || !(obj->getFlags() & TEXTTYPE_DIRECT_MATCH))) + { + buffer.getBuffer(blob->blb_length); // alloc space to put entire blob in memory + } - if (blrOp == blr_like) - return obj->like(*tdbb->getDefaultPool(), p1, l1, p2, l2, escape_str, escape_length); + // Performs the string_function on each segment of the blob until + // a positive result is obtained - // nod_similar - return obj->similarTo(tdbb, *tdbb->getDefaultPool(), p1, l1, p2, l2, escape_str, escape_length); + while (!(blob->blb_flags & BLB_eof)) + { + const SLONG bufferLen = blob->BLB_get_data(tdbb, buffer.begin(), buffer.getCapacity(), false); + if (!evaluator->process(buffer.begin(), bufferLen)) + break; } - // Handle MATCHES - return obj->matches(*tdbb->getDefaultPool(), p1, l1, p2, l2); + return evaluator->result(); } // Execute SLEUTH operator. diff --git a/src/dsql/BoolNodes.h b/src/dsql/BoolNodes.h index cfdf0fc16e1..8e44f6fe98d 100644 --- a/src/dsql/BoolNodes.h +++ b/src/dsql/BoolNodes.h @@ -111,8 +111,6 @@ class ComparativeBoolNode : public TypedNodetra_attachment; - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); AutoCacheRequest request(tdbb, drq_s_usr_prvs, DYN_REQUESTS); @@ -923,7 +923,7 @@ void DdlNode::storePrivileges(thread_db* tdbb, jrd_tra* transaction, X IN RDB$USER_PRIVILEGES { strcpy(X.RDB$RELATION_NAME, name.c_str()); - strcpy(X.RDB$USER, userName.c_str()); + strcpy(X.RDB$USER, ownerName.c_str()); X.RDB$USER_TYPE = obj_user; X.RDB$OBJECT_TYPE = type; X.RDB$PRIVILEGE[0] = *p; @@ -976,7 +976,7 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& const TypeClause* field, const string& computedSource, const BlrDebugWriter::BlrData& computedValue) { Attachment* const attachment = transaction->tra_attachment; - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); const ValueListNode* elements = field->ranges; const USHORT dims = elements ? elements->items.getCount() / 2 : 0; @@ -1000,7 +1000,7 @@ void DdlNode::storeGlobalField(thread_db* tdbb, jrd_tra* transaction, MetaName& strcpy(FLD.RDB$FIELD_NAME, name.c_str()); FLD.RDB$OWNER_NAME.NULL = FALSE; - strcpy(FLD.RDB$OWNER_NAME, userName.c_str()); + strcpy(FLD.RDB$OWNER_NAME, ownerName.c_str()); FLD.RDB$COMPUTED_SOURCE.NULL = TRUE; FLD.RDB$COMPUTED_BLR.NULL = TRUE; @@ -1196,7 +1196,7 @@ string AlterEDSPoolSetNode::internalPrint(NodePrinter& printer) const void AlterEDSPoolSetNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* /*transaction*/) { - EDS::ConnectionsPool* pool = EDS::Manager::getConnPool(false); + EDS::ConnectionsPool* pool = EDS::Manager::getConnPool(true); switch (m_param) { case POOL_SIZE: @@ -1631,15 +1631,15 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_FUNCTION); - // check for duplicated parameter names + // check for duplicated parameters and declaration names - SortedArray names; + StrArray names; for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i) { const ParameterClause* const parameter = parameters[i]; - if (names.exist(parameter->name)) + if (names.exist(parameter->name.c_str())) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-901) << @@ -1647,34 +1647,10 @@ DdlNode* CreateAlterFunctionNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) } if (parameter->name.hasData()) // legacy UDFs has unnamed parameters - names.add(parameter->name); + names.add(parameter->name.c_str()); } - const CompoundStmtNode* variables = localDeclList; - if (variables) - { - // insure that variable names do not duplicate parameter names - - const NestConst* ptr = variables->statements.begin(); - for (const NestConst* const end = variables->statements.end(); ptr != end; ++ptr) - { - const DeclareVariableNode* varNode = nodeAs(*ptr); - - if (varNode) - { - const dsql_fld* field = varNode->dsqlDef->type; - DEV_BLKCHK(field, dsql_type_fld); - - if (names.exist(field->fld_name)) - { - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-901) << - Arg::Gds(isc_dsql_var_conflict) << - Arg::Str(field->fld_name)); - } - } - } - } + PASS1_check_unique_fields_names(names, localDeclList); source.ltrim("\n\r\t "); @@ -1779,7 +1755,7 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); if (package.isEmpty()) { @@ -1827,7 +1803,7 @@ void CreateAlterFunctionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch FUN.RDB$PRIVATE_FLAG.NULL = TRUE; FUN.RDB$OWNER_NAME.NULL = FALSE; - strcpy(FUN.RDB$OWNER_NAME, userName.c_str()); + strcpy(FUN.RDB$OWNER_NAME, ownerName.c_str()); } FUN.RDB$LEGACY_FLAG.NULL = FALSE; @@ -2485,6 +2461,21 @@ void DropFunctionNode::dropArguments(thread_db* tdbb, jrd_tra* transaction, FLD.RDB$FIELD_NAME STARTING WITH IMPLICIT_DOMAIN_PREFIX AND FLD.RDB$SYSTEM_FLAG EQ 0 { + if (!FLD.RDB$SECURITY_CLASS.NULL) + deleteSecurityClass(tdbb, transaction, FLD.RDB$SECURITY_CLASS); + + AutoCacheRequest request3(tdbb, drq_e_arg_prvs, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$RELATION_NAME EQ FLD.RDB$FIELD_NAME AND + PRIV.RDB$OBJECT_TYPE = obj_field AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + ERASE FLD; } END_FOR @@ -2628,63 +2619,39 @@ DdlNode* CreateAlterProcedureNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->flags |= (DsqlCompilerScratch::FLAG_BLOCK | DsqlCompilerScratch::FLAG_PROCEDURE); - // check for duplicated parameter names + // check for duplicated parameters and declaration names - SortedArray names; + StrArray names; for (FB_SIZE_T i = 0; i < parameters.getCount(); ++i) { const ParameterClause* const parameter = parameters[i]; - if (names.exist(parameter->name)) + if (names.exist(parameter->name.c_str())) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-901) << Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name)); } - names.add(parameter->name); + names.add(parameter->name.c_str()); } for (FB_SIZE_T i = 0; i < returns.getCount(); ++i) { const ParameterClause* const parameter = returns[i]; - if (names.exist(parameter->name)) + if (names.exist(parameter->name.c_str())) { status_exception::raise( Arg::Gds(isc_sqlerr) << Arg::Num(-901) << Arg::Gds(isc_dsql_duplicate_spec) << Arg::Str(parameter->name)); } - names.add(parameter->name); + names.add(parameter->name.c_str()); } - const CompoundStmtNode* variables = localDeclList; - if (variables) - { - // insure that variable names do not duplicate parameter names - - const NestConst* ptr = variables->statements.begin(); - for (const NestConst* const end = variables->statements.end(); ptr != end; ++ptr) - { - const DeclareVariableNode* varNode = nodeAs(*ptr); - - if (varNode) - { - const dsql_fld* field = varNode->dsqlDef->type; - DEV_BLKCHK(field, dsql_type_fld); - - if (names.exist(field->fld_name)) - { - status_exception::raise( - Arg::Gds(isc_sqlerr) << Arg::Num(-901) << - Arg::Gds(isc_dsql_var_conflict) << - Arg::Str(field->fld_name)); - } - } - } - } + PASS1_check_unique_fields_names(names, localDeclList); source.ltrim("\n\r\t "); @@ -2787,7 +2754,7 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); if (package.isEmpty()) { @@ -2833,7 +2800,7 @@ void CreateAlterProcedureNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc P.RDB$PACKAGE_NAME.NULL = TRUE; P.RDB$PRIVATE_FLAG.NULL = TRUE; - strcpy(P.RDB$OWNER_NAME, userName.c_str()); + strcpy(P.RDB$OWNER_NAME, ownerName.c_str()); } } END_STORE @@ -3288,6 +3255,21 @@ void DropProcedureNode::dropParameters(thread_db* tdbb, jrd_tra* transaction, FLD.RDB$FIELD_NAME STARTING WITH IMPLICIT_DOMAIN_PREFIX AND FLD.RDB$SYSTEM_FLAG EQ 0 { + if (!FLD.RDB$SECURITY_CLASS.NULL) + deleteSecurityClass(tdbb, transaction, FLD.RDB$SECURITY_CLASS); + + AutoCacheRequest request3(tdbb, drq_e_prm_prvs, DYN_REQUESTS); + + FOR(REQUEST_HANDLE request3 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$RELATION_NAME EQ FLD.RDB$FIELD_NAME AND + PRIV.RDB$OBJECT_TYPE = obj_field AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; + } + END_FOR + ERASE FLD; } END_FOR @@ -3943,7 +3925,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra jrd_tra* transaction) { Attachment* const attachment = transaction->tra_attachment; - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -3961,7 +3943,7 @@ void CreateCollationNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra X.RDB$SYSTEM_FLAG = 0; X.RDB$OWNER_NAME.NULL = FALSE; - strcpy(X.RDB$OWNER_NAME, userName.c_str()); + strcpy(X.RDB$OWNER_NAME, ownerName.c_str()); X.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE; X.RDB$BASE_COLLATION_NAME.NULL = TRUE; @@ -5499,7 +5481,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc jrd_tra* transaction) { Attachment* const attachment = transaction->getAttachment(); - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_EXCEPTION, name, NULL); @@ -5527,7 +5509,7 @@ void CreateAlterExceptionNode::executeCreate(thread_db* tdbb, DsqlCompilerScratc strcpy(X.RDB$EXCEPTION_NAME, name.c_str()); X.RDB$OWNER_NAME.NULL = FALSE; - strcpy(X.RDB$OWNER_NAME, userName.c_str()); + strcpy(X.RDB$OWNER_NAME, ownerName.c_str()); strcpy(X.RDB$MESSAGE, message.c_str()); } @@ -5866,7 +5848,7 @@ SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, con fb_sysflag sysFlag, SINT64 val, SLONG step) { Attachment* const attachment = transaction->tra_attachment; - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); DYN_UTIL_check_unique_name(tdbb, transaction, name, obj_generator); @@ -5892,7 +5874,7 @@ SSHORT CreateAlterSequenceNode::store(thread_db* tdbb, jrd_tra* transaction, con strcpy(X.RDB$GENERATOR_NAME, name.c_str()); X.RDB$OWNER_NAME.NULL = FALSE; - strcpy(X.RDB$OWNER_NAME, userName.c_str()); + strcpy(X.RDB$OWNER_NAME, ownerName.c_str()); X.RDB$INITIAL_VALUE.NULL = FALSE; X.RDB$INITIAL_VALUE = val; @@ -6008,6 +5990,21 @@ void DropSequenceNode::deleteIdentity(thread_db* tdbb, jrd_tra* transaction, con WITH GEN.RDB$GENERATOR_NAME EQ name.c_str() { ERASE GEN; + + if (!GEN.RDB$SECURITY_CLASS.NULL) + deleteSecurityClass(tdbb, transaction, GEN.RDB$SECURITY_CLASS); + } + END_FOR + + AutoRequest request2; + + FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE transaction) + PRIV IN RDB$USER_PRIVILEGES + WITH PRIV.RDB$RELATION_NAME EQ name.c_str() AND + PRIV.RDB$OBJECT_TYPE = obj_generator AND + PRIV.RDB$GRANTOR NOT MISSING + { + ERASE PRIV; } END_FOR } @@ -6778,6 +6775,7 @@ void RelationNode::defineConstraint(thread_db* tdbb, DsqlCompilerScratch* dsqlSc definition.unique = constraint.type != Constraint::TYPE_FK; if (constraint.index->descending) definition.descending = true; + definition.inactive = false; definition.columns = constraint.columns; definition.refRelation = constraint.refRelation; definition.refColumns = constraint.refColumns; @@ -8718,7 +8716,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra jrd_tra* transaction) { Attachment* const attachment = transaction->tra_attachment; - const MetaString& userName = attachment->att_user->getUserName(); + const MetaString& ownerName = attachment->getEffectiveUserName(); const dsql_rel* modifyingView = NULL; @@ -8890,7 +8888,7 @@ void CreateAlterViewNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra // so I included a call to strip trailing blanks. fb_utils::exact_name_limit(PREL.RDB$OWNER_NAME, sizeof(PREL.RDB$OWNER_NAME)); - if (userName != PREL.RDB$OWNER_NAME) + if (ownerName != PREL.RDB$OWNER_NAME) { SecurityClass::flags_t priv; @@ -9872,6 +9870,7 @@ void CreateIndexNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, definition.relation = relation->dsqlName; definition.unique = unique; definition.descending = descending; + definition.inactive = false; if (columns) { @@ -10138,7 +10137,8 @@ void CreateFilterNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) // Define a blob filter. void CreateFilterNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScratch*/, jrd_tra* transaction) { - MetaName ownerName(tdbb->getAttachment()->att_user->getUserName()); + Attachment* const attachment = transaction->tra_attachment; + const MetaString& ownerName = attachment->getEffectiveUserName(); // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -10400,7 +10400,8 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra Arg::PrivateDyn(293).raise(); } - MetaName ownerName(tdbb->getAttachment()->att_user->getUserName()); + Attachment* const attachment = transaction->tra_attachment; + const MetaString& ownerName = attachment->getEffectiveUserName(); // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -10450,8 +10451,6 @@ void CreateAlterRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra newPrivileges.set(convertPrivilegeFromString(tdbb, transaction, *privName)); } - Attachment* attachment = tdbb->getAttachment(); - string p; newPrivileges.store(p.getBuffer(newPrivileges.BYTES_COUNT)); @@ -10639,6 +10638,7 @@ void MappingNode::runInSecurityDb(SecDbContext* secDbContext) ddl += ' '; if (from) { + ddl += "_utf8 "; addItem(ddl, fromUtf8.c_str(), '\''); ddl += ' '; } @@ -10939,8 +10939,6 @@ void DropRoleNode::checkPermission(thread_db* tdbb, jrd_tra* transaction) void DropRoleNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { - MetaName user(tdbb->getAttachment()->att_user->getUserName()); - // run all statements under savepoint control AutoSavePoint savePoint(tdbb, transaction); @@ -11096,13 +11094,10 @@ void CreateAlterUserNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScra if (text.isEmpty() && mode == USER_MOD) { // alter current user - UserId* usr = tdbb->getAttachment()->att_user; - fb_assert(usr); + text = tdbb->getAttachment()->getUserName(); - if (!usr) + if (text.isEmpty()) (Arg::Gds(isc_random) << "Missing user name for ALTER CURRENT USER").raise(); - - text = usr->getUserName(); } Firebird::LocalStatus s; @@ -11762,8 +11757,8 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G (Arg::PrivateDyn(295) << DBA_USER_NAME << owner).raise(); } - MetaName currentUser(attachment->getEffectiveUserId()->getUserName()); - MetaName grantorRevoker(grantor ? *grantor : currentUser); + const MetaName currentUser(attachment->getEffectiveUserName()); + const MetaName grantorRevoker(grantor ? *grantor : currentUser); if (!isGrant && !privs) // REVOKE ALL ON ALL { @@ -11998,11 +11993,11 @@ void GrantRevokeNode::grantRevoke(thread_db* tdbb, jrd_tra* transaction, const G MetaName owner; if ((grantorRevoker == PRIV.RDB$GRANTOR) || + (attachment->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) || // God-like check ((objType == obj_sql_role) && (PRIV.RDB$PRIVILEGE[0] == 'M') && // This is ROLE to USER grant (currentUser != user) && // And current user does not revoke his own grant - ((isItSqlRole(tdbb, transaction, objName, owner) && // Pick up role owner name - (attachment->locksmith(tdbb, GRANT_REVOKE_ON_ANY_OBJECT) || // God-like check - (owner == currentUser))) || // Current user is role owner + (isItSqlRole(tdbb, transaction, objName, owner) && // Pick up role owner name + (owner == currentUser)) || // Current user is role owner (getGrantorOption(tdbb, transaction, currentUser, obj_user, objName) == 2)))) // or has ADMIN option { MetaName newField = NULL; diff --git a/src/dsql/DdlNodes.h b/src/dsql/DdlNodes.h index 83823f1e99a..3c07b01ac2d 100644 --- a/src/dsql/DdlNodes.h +++ b/src/dsql/DdlNodes.h @@ -1636,7 +1636,8 @@ class DropRelationNode : public DdlNode protected: virtual void putErrorPrefix(Firebird::Arg::StatusVector& statusVector) { - statusVector << Firebird::Arg::Gds(isc_dsql_drop_table_failed) << name; + statusVector << Firebird::Arg::Gds(view ? isc_dsql_drop_view_failed : + isc_dsql_drop_table_failed) << name; } public: diff --git a/src/dsql/DsqlBatch.cpp b/src/dsql/DsqlBatch.cpp index d45d74db77c..eb30e9eb3ba 100644 --- a/src/dsql/DsqlBatch.cpp +++ b/src/dsql/DsqlBatch.cpp @@ -30,7 +30,7 @@ #include "../jrd/exe_proto.h" #include "../dsql/dsql.h" #include "../dsql/errd_proto.h" -#include "../common/classes/ClumpletReader.h" +#include "../common/classes/ClumpletWriter.h" #include "../common/classes/auto.h" #include "../common/classes/fb_string.h" #include "../common/utils_proto.h" @@ -124,6 +124,8 @@ DsqlBatch::DsqlBatch(dsql_req* req, const dsql_msg* /*message*/, IMessageMetadat m_bufferSize = pb.getInt(); if (m_bufferSize > HARD_BUFFER_LIMIT) m_bufferSize = HARD_BUFFER_LIMIT; + if (!m_bufferSize) + m_bufferSize = HARD_BUFFER_LIMIT; break; } } @@ -263,7 +265,7 @@ void DsqlBatch::add(thread_db* tdbb, ULONG count, const void* inBuffer) return; m_messages.align(m_alignment); m_messages.put(inBuffer, (count - 1) * m_alignedMessage + m_messageSize); - DEB_BATCH(fprintf(stderr, "Put to batch %d messages\n", count)); + //DEB_BATCH(fprintf(stderr, "Put to batch %d messages\n", count)); } void DsqlBatch::blobCheckMeta() @@ -306,6 +308,7 @@ void DsqlBatch::blobSetSize() m_blobs.put3(&blobSize, sizeof(blobSize), m_lastBlob + sizeof(ISC_QUAD)); m_setBlobSize = false; } + DEB_BATCH(fprintf(stderr, "blobSetSize %u\n", blobSize)); } void DsqlBatch::blobPrepare() @@ -355,6 +358,8 @@ void DsqlBatch::addBlob(thread_db* tdbb, ULONG length, const void* inBuffer, ISC ULONG fullLength = length + parLength; m_blobs.put(&fullLength, sizeof(ULONG)); m_blobs.put(&parLength, sizeof(ULONG)); + DEB_BATCH(fprintf(stderr, "addBlob %08x.%08x par %u full %u ", + blobId->gds_quad_high, blobId->gds_quad_low, parLength, fullLength)); // Store BPB if (parLength) @@ -391,8 +396,11 @@ void DsqlBatch::putSegment(ULONG length, const void* inBuffer) m_blobs.align(IBatch::BLOB_SEGHDR_ALIGN); m_blobs.put(&l, sizeof(l)); m_setBlobSize = true; + + DEB_BATCH(fprintf(stderr, "segment header, ")); } m_blobs.put(inBuffer, length); + DEB_BATCH(fprintf(stderr, "segment data %u ", length)); } void DsqlBatch::addBlobStream(thread_db* tdbb, unsigned length, const void* inBuffer) @@ -537,6 +545,10 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) ISC_QUAD batchBlobId = *reinterpret_cast(flow.data); ULONG* blobSize = reinterpret_cast(flow.data + sizeof(ISC_QUAD)); ULONG* bpbSize = reinterpret_cast(flow.data + sizeof(ISC_QUAD) + sizeof(ULONG)); + + DEB_BATCH(fprintf(stderr, "B-ID: %08x.%08x full=%u par=%u\n", batchBlobId.gds_quad_high, batchBlobId.gds_quad_low, + *blobSize, *bpbSize)); + flow.newHdr(*blobSize); ULONG currentBpbSize = *bpbSize; @@ -587,7 +599,6 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) blob = blb::create2(tdbb, transaction, &engineBlobId, bpb->getCount(), bpb->begin(), true); - //DEB_BATCH(fprintf(stderr, "B-ID: (%x,%x)\n", batchBlobId.gds_quad_high, batchBlobId.gds_quad_low)); registerBlob(reinterpret_cast(&engineBlobId), &batchBlobId); } } @@ -606,6 +617,8 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) flow.move(sizeof(USHORT)); dataSize = *segSize; + + DEB_BATCH(fprintf(stderr, " Seg: %u\n", dataSize)); if (dataSize > flow.currentBlobSize) { ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << @@ -624,7 +637,7 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) } } - blob->BLB_put_segment(tdbb, flow.data, dataSize); + blob->BLB_put_data(tdbb, flow.data, dataSize); flow.move(dataSize); } } @@ -674,6 +687,7 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) while (remains >= m_messageSize) { + const bool start = startRequest; if (startRequest) { EXE_unwind(tdbb, req); @@ -714,7 +728,8 @@ Firebird::IBatchCompletionState* DsqlBatch::execute(thread_db* tdbb) } // map message to internal engine format - m_request->mapInOut(tdbb, false, message, m_meta, NULL, data); + // pass m_meta one time only to avoid parsing its metadata for every message + m_request->mapInOut(tdbb, false, message, start ? m_meta : nullptr, NULL, data); data += m_messageSize; remains -= m_messageSize; @@ -796,8 +811,6 @@ void DsqlBatch::DataCache::setBuf(ULONG size, ULONG cacheCapacity) void DsqlBatch::DataCache::put3(const void* data, ULONG dataSize, ULONG offset) { - // This assertion guarantees that data always fits as a whole into m_cache or m_space, - // never placed half in one storage, half - in another. fb_assert((DsqlBatch::RAM_BATCH % dataSize == 0) && (offset % dataSize == 0)); if (offset >= m_used) @@ -810,6 +823,13 @@ void DsqlBatch::DataCache::put3(const void* data, ULONG dataSize, ULONG offset) } else { + if (offset + dataSize > m_used) + { + // what a pity - data appears partilly divided between cache & tempspace + fb_assert(offset + dataSize <= getSize()); + flush(); + } + const FB_UINT64 writtenBytes = m_space->write(offset, data, dataSize); fb_assert(writtenBytes == dataSize); } @@ -817,11 +837,8 @@ void DsqlBatch::DataCache::put3(const void* data, ULONG dataSize, ULONG offset) void DsqlBatch::DataCache::put(const void* d, ULONG dataSize) { - if (m_limit && (m_used + m_cache.getCount() + dataSize > m_limit)) - { - ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << - Arg::Gds(isc_batch_too_big)); - } + if (m_used + m_cache.getCount() + dataSize > m_limit) + ERR_post(Arg::Gds(isc_batch_too_big)); const UCHAR* data = reinterpret_cast(d); @@ -845,13 +862,7 @@ void DsqlBatch::DataCache::put(const void* d, ULONG dataSize) } // swap ram cache to tempspace - if (!m_space) - m_space = FB_NEW_POOL(getPool()) TempSpace(getPool(), TEMP_NAME); - - const FB_UINT64 writtenBytes = m_space->write(m_used, m_cache.begin(), m_cache.getCount()); - fb_assert(writtenBytes == m_cache.getCount()); - m_used += m_cache.getCount(); - m_cache.clear(); + flush(); // in a case of huge buffer write directly to tempspace if (dataSize > m_cacheCapacity / K) @@ -866,6 +877,17 @@ void DsqlBatch::DataCache::put(const void* d, ULONG dataSize) m_cache.append(data, dataSize); } +void DsqlBatch::DataCache::flush() +{ + if (!m_space) + m_space = FB_NEW_POOL(getPool()) TempSpace(getPool(), TEMP_NAME); + + const FB_UINT64 writtenBytes = m_space->write(m_used, m_cache.begin(), m_cache.getCount()); + fb_assert(writtenBytes == m_cache.getCount()); + m_used += m_cache.getCount(); + m_cache.clear(); +} + void DsqlBatch::DataCache::align(ULONG alignment) { ULONG a = getSize() % alignment; @@ -969,6 +991,14 @@ ULONG DsqlBatch::DataCache::getSize() const return m_used + m_cache.getCount(); } +ULONG DsqlBatch::DataCache::getCapacity() const +{ + if (!m_cacheCapacity) + return 0; + + return m_limit; +} + void DsqlBatch::DataCache::clear() { m_cache.clear(); @@ -976,3 +1006,102 @@ void DsqlBatch::DataCache::clear() m_space->releaseSpace(0, m_used); m_used = m_got = m_shift = 0; } + +void DsqlBatch::info(thread_db* tdbb, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) +{ + // Sanity check + if (bufferLength < 3) // bigger values will be processed by later code OK + { + if (bufferLength-- > 0) + { + *buffer++ = isc_info_truncated; + if (bufferLength-- > 0) + *buffer++ = isc_info_end; + } + return; + } + + ClumpletReader it(ClumpletReader::InfoItems, items, itemsLength); + ClumpletWriter out(ClumpletReader::InfoResponse, bufferLength - 1); // place for isc_info_truncated / isc_info_end + enum BufCloseState {BUF_OPEN, BUF_INTERNAL, BUF_END}; + BufCloseState closeOut = BUF_OPEN; + + try + { + bool flInfoLength = false; + + for (it.rewind(); !it.isEof(); it.moveNext()) + { + UCHAR item = it.getClumpTag(); + if (item == isc_info_end) + break; + + switch(item) + { + case IBatch::INF_BUFFER_BYTES_SIZE: + out.insertInt(item, m_messages.getCapacity()); + break; + case IBatch::INF_DATA_BYTES_SIZE: + out.insertInt(item, FB_ALIGN(m_messages.getSize(), m_alignment)); + break; + case IBatch::INF_BLOBS_BYTES_SIZE: + if (m_blobs.getSize()) + out.insertInt(item, m_blobs.getSize()); + break; + case IBatch::INF_BLOB_ALIGNMENT: + out.insertInt(item, BLOB_STREAM_ALIGN); + break; + case IBatch::INF_BLOB_HEADER: + out.insertInt(item, SIZEOF_BLOB_HEAD); + break; + case isc_info_length: + flInfoLength = true; + break; + default: + out.insertInt(isc_info_error, isc_infunk); + break; + } + } + + // finalize writer + closeOut = BUF_INTERNAL; // finished adding internal info + out.insertTag(isc_info_end); + closeOut = BUF_END; // alreayd marked with isc_info_end but misses isc_info_length + if (flInfoLength) + { + out.rewind(); + out.insertInt(isc_info_length, out.getBufferLength()); + } + } + catch(const fatal_exception&) + { + // here it's sooner of all caused by writer overflow but carefully check that + if (out.hasOverflow()) + { + memcpy(buffer, out.getBuffer(), out.getBufferLength()); + buffer += out.getBufferLength(); + switch (closeOut) + { + case BUF_OPEN: + *buffer++ = isc_info_truncated; + if (out.getBufferLength() <= bufferLength - 2) + *buffer++ = isc_info_end; + break; + case BUF_INTERNAL: + // overflow adding isc_info_end, but we actually have 1 reserved byte + *buffer++ = isc_info_end; + break; + case BUF_END: + // ignore isc_info_length + break; + } + return; + } + else + throw; + } + + memcpy(buffer, out.getBuffer(), out.getBufferLength()); +} + diff --git a/src/dsql/DsqlBatch.h b/src/dsql/DsqlBatch.h index aafc207dde0..aad32150bf7 100644 --- a/src/dsql/DsqlBatch.h +++ b/src/dsql/DsqlBatch.h @@ -76,6 +76,8 @@ class DsqlBatch Firebird::IMessageMetadata* getMetadata(thread_db* tdbb); void cancel(thread_db* tdbb); void setDefaultBpb(thread_db* tdbb, unsigned parLength, const unsigned char* par); + void info(thread_db* tdbb, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer); // Additional flags - start from the maximum one static const UCHAR FLAG_DEFAULT_SEGMENTED = 31; @@ -121,7 +123,9 @@ class DsqlBatch ULONG reget(ULONG size, UCHAR** buffer, ULONG alignment); void remained(ULONG size, ULONG alignment = 0); ULONG getSize() const; + ULONG getCapacity() const; void clear(); + void flush(); private: typedef Firebird::Array Cache; diff --git a/src/dsql/DsqlCursor.cpp b/src/dsql/DsqlCursor.cpp index 4c3fef675a4..564a4764590 100644 --- a/src/dsql/DsqlCursor.cpp +++ b/src/dsql/DsqlCursor.cpp @@ -34,10 +34,10 @@ static const char* const SCRATCH = "fb_cursor_"; static const ULONG PREFETCH_SIZE = 65536; // 64 KB DsqlCursor::DsqlCursor(dsql_req* req, ULONG flags) - : m_request(req), m_resultSet(NULL), m_flags(flags), + : m_request(req), m_message(req->getStatement()->getReceiveMsg()), + m_resultSet(NULL), m_flags(flags), m_space(req->getPool(), SCRATCH), - m_state(BOS), m_eof(false), m_position(0), m_cachedCount(0), - m_messageSize(req->getStatement()->getReceiveMsg()->msg_length) + m_state(BOS), m_eof(false), m_position(0), m_cachedCount(0) { TRA_link_cursor(m_request->req_transaction, this); } @@ -117,11 +117,7 @@ int DsqlCursor::fetchNext(thread_db* tdbb, UCHAR* buffer) return 0; } - if (m_state == EOS) - return 1; - - const FB_UINT64 position = (m_state == BOS) ? 0 : m_position + 1; - return fetchFromCache(tdbb, buffer, position); + return fetchRelative(tdbb, buffer, 1); } int DsqlCursor::fetchPrior(thread_db* tdbb, UCHAR* buffer) @@ -129,17 +125,7 @@ int DsqlCursor::fetchPrior(thread_db* tdbb, UCHAR* buffer) if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE)) (Arg::Gds(isc_invalid_fetch_option) << Arg::Str("PRIOR")).raise(); - if (m_state == BOS) - return -1; - - if (!m_position) - { - m_state = BOS; - return -1; - } - - const FB_UINT64 position = ((m_state == EOS) ? m_cachedCount : m_position) - 1; - return fetchFromCache(tdbb, buffer, position); + return fetchRelative(tdbb, buffer, -1); } int DsqlCursor::fetchFirst(thread_db* tdbb, UCHAR* buffer) @@ -182,6 +168,12 @@ int DsqlCursor::fetchAbsolute(thread_db* tdbb, UCHAR* buffer, SLONG position) offset = m_cachedCount; } + if (position + offset < 0) + { + m_state = BOS; + return -1; + } + return fetchFromCache(tdbb, buffer, position + offset); } @@ -190,12 +182,14 @@ int DsqlCursor::fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset) if (!(m_flags & IStatement::CURSOR_TYPE_SCROLLABLE)) (Arg::Gds(isc_invalid_fetch_option) << Arg::Str("RELATIVE")).raise(); + SINT64 position = m_position + offset; + if (m_state == BOS) { if (offset <= 0) return -1; - return fetchFromCache(tdbb, buffer, offset - 1); + position = offset - 1; } else if (m_state == EOS) { @@ -204,19 +198,16 @@ int DsqlCursor::fetchRelative(thread_db* tdbb, UCHAR* buffer, SLONG offset) fb_assert(m_eof); - if ((SINT64) m_cachedCount + offset < 0) - return -1; - - return fetchFromCache(tdbb, buffer, m_cachedCount + offset); + position = m_cachedCount + offset; } - if ((SINT64) m_position + offset < 0) + if (position < 0) { m_state = BOS; return -1; } - return fetchFromCache(tdbb, buffer, m_position + offset); + return fetchFromCache(tdbb, buffer, position); } int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 position) @@ -232,9 +223,14 @@ int DsqlCursor::fetchFromCache(thread_db* tdbb, UCHAR* buffer, FB_UINT64 positio fb_assert(position < m_cachedCount); - const FB_UINT64 offset = position * m_messageSize; - const FB_UINT64 readBytes = m_space.read(offset, buffer, m_messageSize); - fb_assert(readBytes == m_messageSize); + UCHAR* const msgBuffer = m_request->req_msg_buffers[m_message->msg_buffer_number]; + + const FB_UINT64 offset = position * m_message->msg_length; + const FB_UINT64 readBytes = m_space.read(offset, msgBuffer, m_message->msg_length); + fb_assert(readBytes == m_message->msg_length); + + m_request->mapInOut(tdbb, true, m_message, NULL, buffer); + m_position = position; m_state = POSITIONED; return 0; @@ -244,34 +240,23 @@ bool DsqlCursor::cacheInput(thread_db* tdbb, FB_UINT64 position) { fb_assert(!m_eof); - const ULONG prefetchCount = MAX(PREFETCH_SIZE / m_messageSize, 1); - const ULONG prefetchSize = prefetchCount * m_messageSize; - - UCharBuffer messageBuffer; - UCHAR* const buffer = messageBuffer.getBuffer(prefetchSize); + const ULONG prefetchCount = MAX(PREFETCH_SIZE / m_message->msg_length, 1); + const UCHAR* const msgBuffer = m_request->req_msg_buffers[m_message->msg_buffer_number]; while (position >= m_cachedCount) { - ULONG count = 0; - - for (; count < prefetchCount; count++) + for (ULONG count = 0; count < prefetchCount; count++) { - UCHAR* const ptr = buffer + count * m_messageSize; - - if (!m_request->fetch(tdbb, ptr)) + if (!m_request->fetch(tdbb, NULL)) { m_eof = true; break; } - } - if (count) - { - const FB_UINT64 offset = m_cachedCount * m_messageSize; - const ULONG fetchedSize = count * m_messageSize; - const FB_UINT64 writtenBytes = m_space.write(offset, buffer, fetchedSize); - fb_assert(writtenBytes == fetchedSize); - m_cachedCount += count; + const FB_UINT64 offset = m_cachedCount * m_message->msg_length; + const FB_UINT64 writtenBytes = m_space.write(offset, msgBuffer, m_message->msg_length); + fb_assert(writtenBytes == m_message->msg_length); + m_cachedCount++; } if (m_eof) diff --git a/src/dsql/DsqlCursor.h b/src/dsql/DsqlCursor.h index 04824ffa5b9..864a8b38177 100644 --- a/src/dsql/DsqlCursor.h +++ b/src/dsql/DsqlCursor.h @@ -66,6 +66,7 @@ class DsqlCursor bool cacheInput(thread_db* tdbb, FB_UINT64 position = MAX_UINT64); dsql_req* const m_request; + const dsql_msg* const m_message; JResultSet* m_resultSet; const ULONG m_flags; TempSpace m_space; @@ -73,7 +74,6 @@ class DsqlCursor bool m_eof; FB_UINT64 m_position; FB_UINT64 m_cachedCount; - ULONG m_messageSize; }; } // namespace diff --git a/src/dsql/ExprNodes.cpp b/src/dsql/ExprNodes.cpp index b94284fccd0..e596b8704e5 100644 --- a/src/dsql/ExprNodes.cpp +++ b/src/dsql/ExprNodes.cpp @@ -540,8 +540,8 @@ const UCHAR decimalDescTable[6][6] = { /* DSC_ZTYPE_FLT64 */ {DSC_ZTYPE_FLT64, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128}, /* DSC_ZTYPE_FLT128 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128}, /* DSC_ZTYPE_FIXED */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FLT128}, -/* DSC_ZTYPE_INT64 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}, -/* DSC_ZTYPE_INT */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}, +/* DSC_ZTYPE_INT64 */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD}, +/* DSC_ZTYPE_INT */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FIXED, DSC_ZTYPE_FIXED, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD}, /* DSC_ZTYPE_OTHER */ {DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_FLT128, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD, DSC_ZTYPE_BAD} }; @@ -4170,19 +4170,9 @@ dsc* CurrentDateNode::execute(thread_db* tdbb, jrd_req* request) const request->req_flags &= ~req_null; // Use the request timestamp. - fb_assert(!request->req_gmt_timestamp.isEmpty()); + impure->vlu_misc.vlu_sql_date = request->getLocalTimeStamp().timestamp_date; - ISC_TIMESTAMP_TZ timeStampTz; - timeStampTz.utc_timestamp = request->req_gmt_timestamp.value(); - timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE; - - impure->vlu_misc.vlu_sql_date = TimeZoneUtil::timeStampTzToTimeStamp( - timeStampTz, request->req_attachment->att_current_timezone).timestamp_date; - - memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc)); - impure->vlu_desc.dsc_dtype = dtype_sql_date; - impure->vlu_desc.dsc_length = type_lengths[dtype_sql_date]; - impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_date; + impure->vlu_desc.makeDate(&impure->vlu_misc.vlu_sql_date); return &impure->vlu_desc; } @@ -4283,21 +4273,11 @@ dsc* CurrentTimeNode::execute(thread_db* tdbb, jrd_req* request) const request->req_flags &= ~req_null; // Use the request timestamp. - fb_assert(!request->req_gmt_timestamp.isEmpty()); - - ISC_TIMESTAMP_TZ currentTimeStamp; - currentTimeStamp.utc_timestamp = request->req_gmt_timestamp.value(); - currentTimeStamp.time_zone = tdbb->getAttachment()->att_current_timezone; - - impure->vlu_desc.dsc_dtype = dtype_sql_time_tz; - impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time_tz]; - impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_time_tz; - - impure->vlu_misc.vlu_sql_time_tz.time_zone = tdbb->getAttachment()->att_current_timezone; - impure->vlu_misc.vlu_sql_time_tz.utc_time = TimeZoneUtil::timeStampTzToTimeTz(currentTimeStamp).utc_time; - + impure->vlu_misc.vlu_sql_time_tz = request->getTimeTz(); TimeStamp::round_time(impure->vlu_misc.vlu_sql_time_tz.utc_time, precision); + impure->vlu_desc.makeTimeTz(&impure->vlu_misc.vlu_sql_time_tz); + return &impure->vlu_desc; } @@ -4398,19 +4378,10 @@ dsc* CurrentTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const request->req_flags &= ~req_null; // Use the request timestamp. - fb_assert(!request->req_gmt_timestamp.isEmpty()); - ISC_TIMESTAMP encTimes = request->req_gmt_timestamp.value(); - - memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc)); - impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp_tz; - - TimeStamp::round_time(encTimes.timestamp_time, precision); - - impure->vlu_desc.dsc_dtype = dtype_timestamp_tz; - impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp_tz]; + impure->vlu_misc.vlu_timestamp_tz = request->getTimeStampTz(); + TimeStamp::round_time(impure->vlu_misc.vlu_timestamp_tz.utc_timestamp.timestamp_time, precision); - impure->vlu_misc.vlu_timestamp_tz.utc_timestamp = encTimes; - impure->vlu_misc.vlu_timestamp_tz.time_zone = tdbb->getAttachment()->att_current_timezone; + impure->vlu_desc.makeTimestampTz(&impure->vlu_misc.vlu_timestamp_tz); return &impure->vlu_desc; } @@ -4488,18 +4459,11 @@ dsc* CurrentRoleNode::execute(thread_db* tdbb, jrd_req* request) const impure->vlu_desc.dsc_sub_type = 0; impure->vlu_desc.dsc_scale = 0; impure->vlu_desc.setTextType(ttype_metadata); - const char* curRole = NULL; - if (tdbb->getAttachment()->att_user) - { - curRole = tdbb->getAttachment()->att_user->getSqlRole().c_str(); - impure->vlu_desc.dsc_address = reinterpret_cast(const_cast(curRole)); - } + const char* curRole = tdbb->getAttachment()->getSqlRole().c_str(); - if (curRole) - impure->vlu_desc.dsc_length = static_cast(strlen(curRole)); - else - impure->vlu_desc.dsc_length = 0; + impure->vlu_desc.dsc_address = reinterpret_cast(const_cast(curRole)); + impure->vlu_desc.dsc_length = static_cast(strlen(curRole)); return &impure->vlu_desc; } @@ -4581,18 +4545,11 @@ dsc* CurrentUserNode::execute(thread_db* tdbb, jrd_req* request) const impure->vlu_desc.dsc_sub_type = 0; impure->vlu_desc.dsc_scale = 0; impure->vlu_desc.setTextType(ttype_metadata); - const char* curUser = NULL; - if (tdbb->getAttachment()->att_user) - { - curUser = tdbb->getAttachment()->att_user->getUserName().c_str(); - impure->vlu_desc.dsc_address = reinterpret_cast(const_cast(curUser)); - } + const char* curUser = tdbb->getAttachment()->getUserName().c_str(); - if (curUser) - impure->vlu_desc.dsc_length = static_cast(strlen(curUser)); - else - impure->vlu_desc.dsc_length = 0; + impure->vlu_desc.dsc_address = reinterpret_cast(const_cast(curUser)); + impure->vlu_desc.dsc_length = static_cast(strlen(curUser)); return &impure->vlu_desc; } @@ -8134,21 +8091,10 @@ dsc* LocalTimeNode::execute(thread_db* tdbb, jrd_req* request) const request->req_flags &= ~req_null; // Use the request timestamp. - fb_assert(!request->req_gmt_timestamp.isEmpty()); - - ISC_TIMESTAMP_TZ timeStampTz; - timeStampTz.utc_timestamp = request->req_gmt_timestamp.value(); - timeStampTz.time_zone = TimeZoneUtil::GMT_ZONE; - - impure->vlu_misc.vlu_sql_time = TimeZoneUtil::timeStampTzToTimeStamp( - timeStampTz, request->req_attachment->att_current_timezone).timestamp_time; - + impure->vlu_misc.vlu_sql_time = request->getLocalTimeStamp().timestamp_time; TimeStamp::round_time(impure->vlu_misc.vlu_sql_time, precision); - memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc)); - impure->vlu_desc.dsc_dtype = dtype_sql_time; - impure->vlu_desc.dsc_length = type_lengths[dtype_sql_time]; - impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_sql_time; + impure->vlu_desc.makeTime(&impure->vlu_misc.vlu_sql_time); return &impure->vlu_desc; } @@ -8237,15 +8183,10 @@ dsc* LocalTimeStampNode::execute(thread_db* tdbb, jrd_req* request) const request->req_flags &= ~req_null; // Use the request timestamp. - fb_assert(!request->req_gmt_timestamp.isEmpty()); - - impure->vlu_misc.vlu_timestamp = request->getLocalTimeStamp().value(); + impure->vlu_misc.vlu_timestamp = request->getLocalTimeStamp(); TimeStamp::round_time(impure->vlu_misc.vlu_timestamp.timestamp_time, precision); - memset(&impure->vlu_desc, 0, sizeof(impure->vlu_desc)); - impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc.vlu_timestamp; - impure->vlu_desc.dsc_dtype = dtype_timestamp; - impure->vlu_desc.dsc_length = type_lengths[dtype_timestamp]; + impure->vlu_desc.makeTimestamp(&impure->vlu_misc.vlu_timestamp); return &impure->vlu_desc; } @@ -8577,35 +8518,10 @@ ValueExprNode* DerivedFieldNode::dsqlFieldRemapper(FieldRemapper& visitor) void DerivedFieldNode::setParameterName(dsql_par* parameter) const { - const dsql_ctx* context = NULL; - const FieldNode* fieldNode = NULL; - const RecordKeyNode* dbKeyNode = NULL; - - const DerivedFieldNode* drvField = nodeAs(value); - - while (drvField) - { - if ((fieldNode = nodeAs(drvField->value))) - break; - - if ((dbKeyNode = nodeAs(drvField->value))) - break; - - drvField = nodeAs(drvField->value); - } - - if (fieldNode || (fieldNode = nodeAs(value))) - { - parameter->par_name = fieldNode->dsqlField->fld_name.c_str(); - context = fieldNode->dsqlContext; - } - else if (dbKeyNode || (dbKeyNode = nodeAs(value))) - dbKeyNode->setParameterName(parameter); + value->setParameterName(parameter); parameter->par_alias = name; - setParameterInfo(parameter, context); - - parameter->par_rel_alias = this->context->ctx_alias; + parameter->par_rel_alias = context->ctx_alias; } void DerivedFieldNode::genBlr(DsqlCompilerScratch* dsqlScratch) @@ -9151,6 +9067,8 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch) Arg::Gds(isc_sqlerr) << Arg::Num(-204) << Arg::Gds(isc_dsql_window_cant_overr_frame) << *name); } + + window = window->dsqlPass(dsqlScratch); } else window = this; @@ -9162,14 +9080,13 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch) doDsqlPass(dsqlScratch, extent ? extent : window->extent), exclusion ? exclusion : window->exclusion); - if (node->order && node->extent && node->extent->unit == FrameExtent::Unit::RANGE && + if (node->extent && node->extent->unit == FrameExtent::Unit::RANGE && (node->extent->frame1->value || (node->extent->frame2 && node->extent->frame2->value))) { - if (node->order->items.getCount() > 1) - { - status_exception::raise( - Arg::Gds(isc_dsql_window_range_multi_key)); - } + if (!node->order) + status_exception::raise(Arg::Gds(isc_dsql_window_range_inv_key_type)); + else if (node->order->items.getCount() > 1) + status_exception::raise(Arg::Gds(isc_dsql_window_range_multi_key)); else { OrderNode* key = nodeAs(node->order->items[0]); @@ -9179,10 +9096,7 @@ WindowClause* WindowClause::dsqlPass(DsqlCompilerScratch* dsqlScratch) DsqlDescMaker::fromNode(dsqlScratch, &desc, key->value); if (!desc.isDateTime() && !desc.isNumeric()) - { - status_exception::raise( - Arg::Gds(isc_dsql_window_range_inv_key_type)); - } + status_exception::raise(Arg::Gds(isc_dsql_window_range_inv_key_type)); } } @@ -10675,6 +10589,7 @@ dsc* StrCaseNode::execute(thread_db* tdbb, jrd_req* request) const return NULL; TextType* textType = INTL_texttype_lookup(tdbb, value->getTextType()); + CharSet* charSet = textType->getCharSet(); auto intlFunction = (blrOp == blr_lowcase ? &TextType::str_to_lower : &TextType::str_to_upper); if (value->isBlob()) @@ -10689,13 +10604,15 @@ dsc* StrCaseNode::execute(thread_db* tdbb, jrd_req* request) const blb* blob = blb::open(tdbb, tdbb->getRequest()->req_transaction, reinterpret_cast(value->dsc_address)); - HalfStaticArray buffer; + HalfStaticArray buffer; if (charSet->isMultiByte()) - buffer.getBuffer(blob->blb_length); // alloc space to put entire blob in memory + { + // Alloc space to put entire blob in memory, with extra space for additional bytes when changing case. + buffer.getBuffer(blob->blb_length / charSet->minBytesPerChar() * charSet->maxBytesPerChar()); + } - blb* newBlob = blb::create(tdbb, tdbb->getRequest()->req_transaction, - &impure->vlu_misc.vlu_bid); + blb* newBlob = blb::create(tdbb, tdbb->getRequest()->req_transaction, &impure->vlu_misc.vlu_bid); while (!(blob->blb_flags & BLB_eof)) { @@ -10703,7 +10620,7 @@ dsc* StrCaseNode::execute(thread_db* tdbb, jrd_req* request) const if (len) { - len = (textType->*intlFunction)(len, buffer.begin(), len, buffer.begin()); + len = (textType->*intlFunction)(len, buffer.begin(), buffer.getCapacity(), buffer.begin()); newBlob->BLB_put_data(tdbb, buffer.begin(), len); } } @@ -10716,16 +10633,16 @@ dsc* StrCaseNode::execute(thread_db* tdbb, jrd_req* request) const UCHAR* ptr; VaryStr temp; USHORT ttype; + ULONG len = MOV_get_string_ptr(tdbb, value, &ttype, &ptr, &temp, sizeof(temp)); dsc desc; - desc.dsc_length = MOV_get_string_ptr(tdbb, value, &ttype, &ptr, &temp, sizeof(temp)); + desc.dsc_length = len / charSet->minBytesPerChar() * charSet->maxBytesPerChar(); desc.dsc_dtype = dtype_text; desc.dsc_address = NULL; desc.setTextType(ttype); EVL_make_value(tdbb, &desc, impure); - ULONG len = (textType->*intlFunction)(desc.dsc_length, - ptr, desc.dsc_length, impure->vlu_desc.dsc_address); + len = (textType->*intlFunction)(len, ptr, desc.dsc_length, impure->vlu_desc.dsc_address); if (len == INTL_BAD_STR_LENGTH) status_exception::raise(Arg::Gds(isc_arith_except)); @@ -10985,10 +10902,10 @@ static RegisterNode regSubQueryNode({ blr_via, blr_from, blr_average, blr_count, blr_maximum, blr_minimum, blr_total }); -SubQueryNode::SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, RecordSourceNode* aDsqlRse, +SubQueryNode::SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, SelectExprNode* aDsqlSelectExpr, ValueExprNode* aValue1, ValueExprNode* aValue2) : TypedNode(pool), - dsqlRse(aDsqlRse), + dsqlSelectExpr(aDsqlSelectExpr), value1(aValue1), value2(aValue2), subQuery(NULL), @@ -11016,6 +10933,12 @@ DmlNode* SubQueryNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* if (csb->csb_currentDMLNode) node->ownSavepoint = false; + + if (!csb->csb_currentForNode && !csb->csb_currentDMLNode && + (csb->csb_g_flags & csb_computed_field)) + { + node->ownSavepoint = false; + } } return node; @@ -11025,11 +10948,7 @@ void SubQueryNode::getChildren(NodeRefsHolder& holder, bool dsql) const { ValueExprNode::getChildren(holder, dsql); - if (dsql) - holder.add(dsqlRse); - else - holder.add(rse); - + holder.add(rse); holder.add(value1); holder.add(value2); } @@ -11040,7 +10959,7 @@ string SubQueryNode::internalPrint(NodePrinter& printer) const NODE_PRINT(printer, blrOp); NODE_PRINT(printer, ownSavepoint); - NODE_PRINT(printer, dsqlRse); + NODE_PRINT(printer, dsqlSelectExpr); NODE_PRINT(printer, rse); NODE_PRINT(printer, value1); NODE_PRINT(printer, value2); @@ -11059,10 +10978,11 @@ ValueExprNode* SubQueryNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) const DsqlContextStack::iterator base(*dsqlScratch->context); - RseNode* rse = PASS1_rse(dsqlScratch, nodeAs(dsqlRse), false); + RseNode* rse = PASS1_rse(dsqlScratch, dsqlSelectExpr, false); - SubQueryNode* node = FB_NEW_POOL(dsqlScratch->getPool()) SubQueryNode(dsqlScratch->getPool(), blrOp, rse, + SubQueryNode* node = FB_NEW_POOL(dsqlScratch->getPool()) SubQueryNode(dsqlScratch->getPool(), blrOp, dsqlSelectExpr, rse->dsqlSelectList->items[0], NullNode::instance()); + node->rse = rse; // Finish off by cleaning up contexts. dsqlScratch->context->clear(base); @@ -11078,7 +10998,7 @@ void SubQueryNode::setParameterName(dsql_par* parameter) const void SubQueryNode::genBlr(DsqlCompilerScratch* dsqlScratch) { dsqlScratch->appendUChar(blrOp); - GEN_expr(dsqlScratch, dsqlRse); + GEN_expr(dsqlScratch, rse); GEN_expr(dsqlScratch, value1); GEN_expr(dsqlScratch, value2); } @@ -11094,12 +11014,12 @@ void SubQueryNode::make(DsqlCompilerScratch* dsqlScratch, dsc* desc) bool SubQueryNode::dsqlAggregateFinder(AggregateFinder& visitor) { - return !visitor.ignoreSubSelects && visitor.visit(dsqlRse); + return !visitor.ignoreSubSelects && visitor.visit(rse); } bool SubQueryNode::dsqlAggregate2Finder(Aggregate2Finder& visitor) { - return visitor.visit(dsqlRse); // Pass only the rse. + return visitor.visit(rse); // Pass only the rse. } bool SubQueryNode::dsqlSubSelectFinder(SubSelectFinder& /*visitor*/) @@ -11109,13 +11029,13 @@ bool SubQueryNode::dsqlSubSelectFinder(SubSelectFinder& /*visitor*/) bool SubQueryNode::dsqlFieldFinder(FieldFinder& visitor) { - return visitor.visit(dsqlRse); // Pass only the rse. + return visitor.visit(rse); // Pass only the rse. } ValueExprNode* SubQueryNode::dsqlFieldRemapper(FieldRemapper& visitor) { - doDsqlFieldRemapper(visitor, dsqlRse); - value1 = nodeAs(dsqlRse)->dsqlSelectList->items[0]; + doDsqlFieldRemapper(visitor, rse); + value1 = rse->dsqlSelectList->items[0]; return this; } @@ -11949,6 +11869,8 @@ ValueExprNode* SubstringSimilarNode::pass2(thread_db* tdbb, CompilerScratch* csb { if (nodFlags & FLAG_INVARIANT) csb->csb_invariants.push(&impureOffset); + else + nodFlags |= FLAG_PATTERN_MATCHER_CACHE; ValueExprNode::pass2(tdbb, csb); @@ -11996,33 +11918,73 @@ dsc* SubstringSimilarNode::execute(thread_db* tdbb, jrd_req* request) const if (escapeLen == 0 || charSet->length(escapeLen, escapeStr, true) != 1) ERR_post(Arg::Gds(isc_escape_invalid)); - impure_value* impure = request->getImpure(impureOffset); - AutoPtr autoEvaluator; // deallocate non-invariant evaluator BaseSubstringSimilarMatcher* evaluator; + impure_value* impure = request->getImpure(impureOffset); + + auto createMatcher = [&]() + { + return collation->createSubstringSimilarMatcher( + tdbb, *tdbb->getDefaultPool(), patternStr, patternLen, escapeStr, escapeLen); + }; + if (nodFlags & FLAG_INVARIANT) { if (!(impure->vlu_flags & VLU_computed)) { delete impure->vlu_misc.vlu_invariant; + impure->vlu_misc.vlu_invariant = nullptr; - impure->vlu_misc.vlu_invariant = evaluator = collation->createSubstringSimilarMatcher( - tdbb, *tdbb->getDefaultPool(), patternStr, patternLen, escapeStr, escapeLen); + impure->vlu_misc.vlu_invariant = evaluator = createMatcher(); impure->vlu_flags |= VLU_computed; } + else + impure->vlu_misc.vlu_invariant->reset(); + + evaluator = static_cast(impure->vlu_misc.vlu_invariant); + } + else if (nodFlags & FLAG_PATTERN_MATCHER_CACHE) + { + auto& cache = impure->vlu_misc.vlu_patternMatcherCache; + const bool cacheHit = cache && + cache->matcher && + cache->ttype == textType && + cache->patternLen == patternLen && + cache->escapeLen == escapeLen && + memcmp(cache->key, patternStr, patternLen) == 0 && + memcmp(cache->key + patternLen, escapeStr, escapeLen) == 0; + + if (cacheHit) + cache->matcher->reset(); else { - evaluator = static_cast(impure->vlu_misc.vlu_invariant); - evaluator->reset(); + if (cache && cache->keySize < patternLen + escapeLen) + { + delete cache; + cache = nullptr; + } + + if (!cache) + { + cache = FB_NEW_RPT(*tdbb->getDefaultPool(), patternLen + escapeLen) + impure_value::PatternMatcherCache(patternLen + escapeLen); + } + + cache->ttype = textType; + cache->patternLen = patternLen; + cache->escapeLen = escapeLen; + memcpy(cache->key, patternStr, patternLen); + memcpy(cache->key + patternLen, escapeStr, escapeLen); + + cache->matcher = createMatcher(); } + + evaluator = static_cast(cache->matcher.get()); } else - { - autoEvaluator = evaluator = collation->createSubstringSimilarMatcher(tdbb, *tdbb->getDefaultPool(), - patternStr, patternLen, escapeStr, escapeLen); - } + autoEvaluator = evaluator = createMatcher(); evaluator->process(exprStr, exprLen); @@ -12789,10 +12751,11 @@ void UdfCallNode::make(DsqlCompilerScratch* /*dsqlScratch*/, dsc* desc) // pointer. desc->setNullable(true); - if (desc->dsc_dtype <= dtype_any_text) - desc->dsc_ttype() = dsqlFunction->udf_character_set_id; - else + if (!desc->isText()) desc->dsc_ttype() = dsqlFunction->udf_sub_type; + + if (desc->isText() || (desc->isBlob() && desc->getBlobSubType() == isc_blob_text)) + desc->setTextType(dsqlFunction->udf_character_set_id); } void UdfCallNode::getDesc(thread_db* /*tdbb*/, CompilerScratch* /*csb*/, dsc* desc) @@ -13048,7 +13011,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const { Jrd::ContextPoolHolder context(tdbb, funcRequest->req_pool); // Save the old pool. - funcRequest->req_gmt_timestamp = request->req_gmt_timestamp; + funcRequest->setGmtTimeStamp(request->getGmtTimeStamp()); EXE_start(tdbb, funcRequest, transaction); @@ -13077,7 +13040,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const EXE_unwind(tdbb, funcRequest); funcRequest->req_attachment = NULL; funcRequest->req_flags &= ~(req_in_use | req_proc_fetch); - funcRequest->req_gmt_timestamp.invalidate(); + funcRequest->invalidateTimeStamp(); throw; } @@ -13105,7 +13068,7 @@ dsc* UdfCallNode::execute(thread_db* tdbb, jrd_req* request) const funcRequest->req_attachment = NULL; funcRequest->req_flags &= ~(req_in_use | req_proc_fetch); - funcRequest->req_gmt_timestamp.invalidate(); + funcRequest->invalidateTimeStamp(); } if (!(request->req_flags & req_null)) diff --git a/src/dsql/ExprNodes.h b/src/dsql/ExprNodes.h index 578283ce1a6..71a8ac120af 100644 --- a/src/dsql/ExprNodes.h +++ b/src/dsql/ExprNodes.h @@ -572,6 +572,11 @@ class DecodeNode : public TypedNode virtual void genBlr(DsqlCompilerScratch* dsqlScratch); virtual void make(DsqlCompilerScratch* dsqlScratch, dsc* desc); + virtual bool possiblyUnknown(OptimizerBlk* /*opt*/) + { + return true; + } + virtual void getDesc(thread_db* tdbb, CompilerScratch* csb, dsc* desc); virtual ValueExprNode* copy(thread_db* tdbb, NodeCopier& copier) const; virtual ValueExprNode* pass2(thread_db* tdbb, CompilerScratch* csb); @@ -1862,7 +1867,7 @@ class StrLenNode : public TypedNode class SubQueryNode : public TypedNode { public: - explicit SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, RecordSourceNode* aDsqlRse = NULL, + explicit SubQueryNode(MemoryPool& pool, UCHAR aBlrOp, SelectExprNode* aDsqlSelectExpr = NULL, ValueExprNode* aValue1 = NULL, ValueExprNode* aValue2 = NULL); static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); @@ -1907,7 +1912,7 @@ class SubQueryNode : public TypedNode virtual dsc* execute(thread_db* tdbb, jrd_req* request) const; public: - NestConst dsqlRse; + NestConst dsqlSelectExpr; NestConst rse; NestConst value1; NestConst value2; diff --git a/src/dsql/Nodes.h b/src/dsql/Nodes.h index 35fadff59c9..222dc48cab2 100644 --- a/src/dsql/Nodes.h +++ b/src/dsql/Nodes.h @@ -519,18 +519,19 @@ class ExprNode : public DmlNode // Generic flags. static const USHORT FLAG_INVARIANT = 0x01; // Node is recognized as being invariant. + static const USHORT FLAG_PATTERN_MATCHER_CACHE = 0x02; // Boolean flags. - static const USHORT FLAG_DEOPTIMIZE = 0x02; // Boolean which requires deoptimization. - static const USHORT FLAG_RESIDUAL = 0x04; // Boolean which must remain residual. - static const USHORT FLAG_ANSI_NOT = 0x08; // ANY/ALL predicate is prefixed with a NOT one. + static const USHORT FLAG_DEOPTIMIZE = 0x04; // Boolean which requires deoptimization. + static const USHORT FLAG_RESIDUAL = 0x08; // Boolean which must remain residual. + static const USHORT FLAG_ANSI_NOT = 0x10; // ANY/ALL predicate is prefixed with a NOT one. // Value flags. - static const USHORT FLAG_DOUBLE = 0x10; - static const USHORT FLAG_DATE = 0x20; - static const USHORT FLAG_DECFLOAT = 0x40; - static const USHORT FLAG_VALUE = 0x80; // Full value area required in impure space. - static const USHORT FLAG_INT128 = 0x100; + static const USHORT FLAG_DOUBLE = 0x20; + static const USHORT FLAG_DATE = 0x40; + static const USHORT FLAG_DECFLOAT = 0x80; + static const USHORT FLAG_VALUE = 0x100; // Full value area required in impure space. + static const USHORT FLAG_INT128 = 0x200; explicit ExprNode(Type aType, MemoryPool& pool) : DmlNode(pool), diff --git a/src/dsql/PackageNodes.epp b/src/dsql/PackageNodes.epp index 67d20b1df19..6002763a326 100644 --- a/src/dsql/PackageNodes.epp +++ b/src/dsql/PackageNodes.epp @@ -231,6 +231,11 @@ DdlNode* CreateAlterPackageNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; itemScratch->package = name; + if (itemScratch->clientDialect > SQL_DIALECT_V5) + itemStatement->setBlrVersion(5); + else + itemStatement->setBlrVersion(4); + switch ((*items)[i].type) { case CreateAlterPackageNode::Item::FUNCTION: @@ -330,8 +335,8 @@ void CreateAlterPackageNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlS void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* dsqlScratch, jrd_tra* transaction) { - Attachment* attachment = transaction->getAttachment(); - const MetaString& userName = attachment->att_user->getUserName(); + Attachment* const attachment = transaction->getAttachment(); + const MetaString& ownerName = attachment->getEffectiveUserName(); executeDdlTrigger(tdbb, dsqlScratch, transaction, DTW_BEFORE, DDL_TRIGGER_CREATE_PACKAGE, name, NULL); @@ -348,7 +353,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* PKG.RDB$SYSTEM_FLAG = 0; PKG.RDB$OWNER_NAME.NULL = FALSE; - strcpy(PKG.RDB$OWNER_NAME, userName.c_str()); + strcpy(PKG.RDB$OWNER_NAME, ownerName.c_str()); PKG.RDB$PACKAGE_HEADER_SOURCE.NULL = FALSE; attachment->storeMetaDataBlob(tdbb, transaction, &PKG.RDB$PACKAGE_HEADER_SOURCE, source); @@ -365,7 +370,7 @@ void CreateAlterPackageNode::executeCreate(thread_db* tdbb, DsqlCompilerScratch* storePrivileges(tdbb, transaction, name, obj_package_header, EXEC_PRIVILEGES); - owner = userName; + owner = ownerName; executeItems(tdbb, dsqlScratch, transaction); @@ -432,6 +437,8 @@ bool CreateAlterPackageNode::executeAlter(thread_db* tdbb, DsqlCompilerScratch* PKG.RDB$SQL_SECURITY.NULL = FALSE; PKG.RDB$SQL_SECURITY = ssDefiner.value ? FB_TRUE : FB_FALSE; } + else + PKG.RDB$SQL_SECURITY.NULL = TRUE; END_MODIFY owner = PKG.RDB$OWNER_NAME; @@ -626,6 +633,11 @@ DdlNode* CreatePackageBodyNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) itemScratch->flags |= DsqlCompilerScratch::FLAG_DDL; itemScratch->package = name; + if (itemScratch->clientDialect > SQL_DIALECT_V5) + itemStatement->setBlrVersion(5); + else + itemStatement->setBlrVersion(4); + switch ((*arrays[i])[j].type) { case CreateAlterPackageNode::Item::FUNCTION: diff --git a/src/dsql/Parser.cpp b/src/dsql/Parser.cpp index e5fdb758616..642f317d13a 100644 --- a/src/dsql/Parser.cpp +++ b/src/dsql/Parser.cpp @@ -846,7 +846,7 @@ int Parser::yylexAux() ++charlen; // Okay, just count 'em ++lex.ptr; // and advance... - if (charlen > 16) // Too many digits... + if (charlen > 32) // Too many digits... { hexerror = true; break; @@ -857,11 +857,24 @@ int Parser::yylexAux() // an NUMBER32BIT or NUMBER64BIT. if (!hexerror) { + if (charlen > 16) + { + // we deal with int128 + fb_assert(charlen <= 32); // charlen is always <= 32, see 10-15 lines upper + + Firebird::string sbuff(hexstring, charlen); + sbuff.insert(0, "0X"); + + yylval.lim64ptr = newLim64String(sbuff, 0); + + return TOK_NUM128; + } + // if charlen > 8 (something like FFFF FFFF 0, w/o the spaces) // then we have to return a NUMBER64BIT. We'll make a string // node here, and let make.cpp worry about converting the // string to a number and building the node later. - if (charlen > 8) + else if (charlen > 8) { char cbuff[32]; fb_assert(charlen <= 16); // charlen is always <= 16, see 10-15 lines upper diff --git a/src/dsql/StmtNodes.cpp b/src/dsql/StmtNodes.cpp index a9084e247e3..9a84674f527 100644 --- a/src/dsql/StmtNodes.cpp +++ b/src/dsql/StmtNodes.cpp @@ -2064,8 +2064,10 @@ DeclareSubProcNode* DeclareSubProcNode::dsqlPass(DsqlCompilerScratch* dsqlScratc blockScratch = FB_NEW_POOL(pool) DsqlCompilerScratch(pool, dsqlScratch->getAttachment(), dsqlScratch->getTransaction(), statement, dsqlScratch); blockScratch->clientDialect = dsqlScratch->clientDialect; - blockScratch->flags |= DsqlCompilerScratch::FLAG_PROCEDURE | DsqlCompilerScratch::FLAG_SUB_ROUTINE; - blockScratch->flags |= dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL; + blockScratch->flags |= + DsqlCompilerScratch::FLAG_PROCEDURE | + DsqlCompilerScratch::FLAG_SUB_ROUTINE | + (dsqlScratch->flags & DsqlCompilerScratch::FLAG_DDL); dsqlBlock = dsqlBlock->dsqlPass(blockScratch); @@ -2692,8 +2694,14 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, jrd_req* request, WhichTrigger // This is required for cascading referential integrity, which can be implemented as // post_erase triggers. - if (!relation->rel_file && !relation->rel_view_rse && !relation->isVirtual()) - IDX_erase(tdbb, rpb, transaction); + if (!relation->rel_view_rse) + { + if (!relation->rel_file && !relation->isVirtual()) + IDX_erase(tdbb, rpb, transaction); + + // Mark this rpb as already deleted to skip the subsequent attempts + rpb->rpb_runtime_flags |= RPB_just_deleted; + } if (!relation->rel_view_rse || (whichTrig == ALL_TRIGS || whichTrig == POST_TRIG)) { @@ -2702,7 +2710,6 @@ const StmtNode* EraseNode::erase(thread_db* tdbb, jrd_req* request, WhichTrigger } rpb->rpb_number.setValid(false); - rpb->rpb_runtime_flags |= RPB_just_deleted; return parentStmt; } @@ -2882,6 +2889,7 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr { SET_TDBB(tdbb); + const auto blrStartPos = csb->csb_blr_reader.getPos(); jrd_prc* procedure = NULL; QualifiedName name; @@ -2914,6 +2922,25 @@ DmlNode* ExecProcedureNode::parse(thread_db* tdbb, MemoryPool& pool, CompilerScr if (!procedure) PAR_error(csb, Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString())); + else + { + if (procedure->isImplemented() && !procedure->isDefined()) + { + if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator)) + { + PAR_warning( + Arg::Warning(isc_prcnotdef) << Arg::Str(name.toString()) << + Arg::Warning(isc_modnotfound)); + } + else + { + csb->csb_blr_reader.setPos(blrStartPos); + PAR_error(csb, + Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()) << + Arg::Gds(isc_modnotfound)); + } + } + } ExecProcedureNode* node = FB_NEW_POOL(pool) ExecProcedureNode(pool); node->procedure = procedure; @@ -3191,6 +3218,12 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons Arg::Gds(isc_proc_pack_not_implemented) << Arg::Str(procedure->getName().identifier) << Arg::Str(procedure->getName().package)); } + else if (!procedure->isDefined()) + { + status_exception::raise( + Arg::Gds(isc_prcnotdef) << Arg::Str(procedure->getName().toString()) << + Arg::Gds(isc_modnotfound)); + } const_cast(procedure.getObject())->checkReload(tdbb); @@ -3253,7 +3286,7 @@ void ExecProcedureNode::executeProcedure(thread_db* tdbb, jrd_req* request) cons &tdbb->getAttachment()->att_original_timezone, tdbb->getAttachment()->att_current_timezone); - procRequest->req_gmt_timestamp = request->req_gmt_timestamp; + procRequest->setGmtTimeStamp(request->getGmtTimeStamp()); EXE_start(tdbb, procRequest, transaction); @@ -3990,7 +4023,6 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r jrd_tra* const org_transaction = request->req_transaction; fb_assert(tdbb->getTransaction() == org_transaction); - ULONG transaction_flags = org_transaction->tra_flags; // Replace Read Consistency by Concurrecy isolation mode @@ -4001,6 +4033,7 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r org_transaction->tra_lock_timeout, org_transaction); + request->pushTransaction(); TRA_attach_request(transaction, request); tdbb->setTransaction(transaction); @@ -4011,12 +4044,13 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r } catch (Exception&) { + TRA_detach_request(request); + request->popTransaction(); TRA_attach_request(org_transaction, request); tdbb->setTransaction(org_transaction); throw; } - request->pushTransaction(org_transaction); impure->traNumber = transaction->tra_number; const Savepoint* const savepoint = transaction->startSavepoint(); @@ -4122,6 +4156,10 @@ const StmtNode* InAutonomousTransactionNode::execute(thread_db* tdbb, jrd_req* r } impure->traNumber = impure->savNumber = 0; + + // Normally request is detached by commit/rollback, but they may fail. + // It should be done before request->popTransaction(). + TRA_detach_request(request); transaction = request->popTransaction(); TRA_attach_request(transaction, request); @@ -7039,7 +7077,11 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, else { values = doDsqlPass(dsqlScratch, dsqlValues, false); - needSavePoint = SubSelectFinder::find(dsqlScratch->getPool(), values); + // If this INSERT belongs to some PSQL code block and has subqueries + // inside its VALUES part, signal the caller to create a savepoint frame. + // See bug #5613 (aka CORE-5337) for details. + needSavePoint = (dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK) && + SubSelectFinder::find(dsqlScratch->getPool(), values); } // Process relation @@ -7200,13 +7242,9 @@ StmtNode* StoreNode::internalDsqlPass(DsqlCompilerScratch* dsqlScratch, StmtNode* StoreNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { bool needSavePoint; - StmtNode* node = SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, - internalDsqlPass(dsqlScratch, false, needSavePoint)); - - if (!needSavePoint || nodeIs(node)) - return node; + const auto node = internalDsqlPass(dsqlScratch, false, needSavePoint); - return FB_NEW_POOL(dsqlScratch->getPool()) SavepointEncloseNode(dsqlScratch->getPool(), node); + return SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, node, needSavePoint); } string StoreNode::internalPrint(NodePrinter& printer) const @@ -7685,26 +7723,26 @@ const StmtNode* UserSavepointNode::execute(thread_db* tdbb, jrd_req* request, Ex if (request->req_operation == jrd_req::req_evaluate && !(transaction->tra_flags & TRA_system)) { - // Skip the savepoint created by EXE_start - Savepoint* const previous = transaction->tra_save_point; - - // Find savepoint - Savepoint* savepoint = NULL; + Savepoint* savepoint = nullptr, *previous = transaction->tra_save_point; - for (Savepoint::Iterator iter(previous); *iter; ++iter) + // Skip the savepoint created by EXE_start + if (const auto start = previous ? previous->getNext() : nullptr) { - Savepoint* const current = *iter; + // Find savepoint + for (Savepoint::Iterator iter(start); *iter; ++iter) + { + const auto current = *iter; - if (current == previous) - continue; + if (current->isSystem()) + break; - if (current->isSystem()) - break; + if (current->getName() == name) + { + savepoint = current; + break; + } - if (current->getName() == name) - { - savepoint = current; - break; + previous = current; } } @@ -8343,12 +8381,18 @@ DmlNode* SavepointEncloseNode::parse(thread_db* tdbb, MemoryPool& pool, Compiler return node; } -StmtNode* SavepointEncloseNode::make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node) +StmtNode* SavepointEncloseNode::make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node, bool force) { - // Add savepoint wrapper around the statement having error handlers + // Add savepoint wrapper around the statement having error handlers, or if requested explicitly + + if (dsqlScratch->errorHandlers || force) + { + // Ensure that savepoints are never created around a DSQL statement + fb_assert(dsqlScratch->flags & DsqlCompilerScratch::FLAG_BLOCK); + return FB_NEW_POOL(pool) SavepointEncloseNode(pool, node); + } - return dsqlScratch->errorHandlers ? - FB_NEW_POOL(pool) SavepointEncloseNode(pool, node) : node; + return node; } SavepointEncloseNode* SavepointEncloseNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) @@ -8578,6 +8622,39 @@ void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** /*traHan //-------------------- +SetDebugOptionNode::SetDebugOptionNode(MemoryPool& pool, MetaName* aName, ExprNode* aValue) + : SessionManagementNode(pool), + name(pool, *aName), + value(aValue) +{ +} + +void SetDebugOptionNode::execute(thread_db* tdbb, dsql_req* /*request*/, jrd_tra** /*traHandle*/) const +{ + SET_TDBB(tdbb); + auto& debugOptions = tdbb->getAttachment()->getDebugOptions(); + + const auto literal = nodeAs(value); + + if (!literal) + { + // This currently can happen with negative numbers. + // Since it's not relevant for DSQL_KEEP_BLR, let's throw an error. + ERR_post(Arg::Gds(isc_random) << "Invalid DEBUG option value"); + } + + const auto litDesc = &literal->litDesc; + + if (name == "DSQL_KEEP_BLR") + debugOptions.setDsqlKeepBlr(MOV_get_boolean(litDesc)); + else + ERR_post(Arg::Gds(isc_random) << "Invalid DEBUG option"); +} + + +//-------------------- + + SetDecFloatRoundNode::SetDecFloatRoundNode(MemoryPool& pool, MetaName* name) : SessionManagementNode(pool) { @@ -8935,11 +9012,7 @@ StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) if (!returning) dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_INSERT); - StmtNode* ret = SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, list); - if (!needSavePoint || nodeIs(ret)) - return ret; - - return FB_NEW_POOL(dsqlScratch->getPool()) SavepointEncloseNode(dsqlScratch->getPool(), ret); + return SavepointEncloseNode::make(dsqlScratch->getPool(), dsqlScratch, list, needSavePoint); } string UpdateOrInsertNode::internalPrint(NodePrinter& printer) const @@ -10118,14 +10191,11 @@ static void preprocessAssignments(thread_db* tdbb, CompilerScratch* csb, if (identityType == IDENT_TYPE_BY_DEFAULT && *insertOverride == OverrideClause::SYSTEM_VALUE) ERR_post(Arg::Gds(isc_overriding_system_invalid) << relation->rel_name); - - if (identityType == IDENT_TYPE_ALWAYS && *insertOverride == OverrideClause::USER_VALUE) - ERR_post(Arg::Gds(isc_overriding_user_invalid) << relation->rel_name); } else { if (identityType == IDENT_TYPE_ALWAYS) - ERR_post(Arg::Gds(isc_overriding_system_missing) << relation->rel_name); + ERR_post(Arg::Gds(isc_overriding_missing) << relation->rel_name); } } diff --git a/src/dsql/StmtNodes.h b/src/dsql/StmtNodes.h index 7af802d1bc2..8a8d32ab723 100644 --- a/src/dsql/StmtNodes.h +++ b/src/dsql/StmtNodes.h @@ -1490,17 +1490,10 @@ class ReturnNode : public TypedNode class SavepointEncloseNode : public TypedNode { -public: - explicit SavepointEncloseNode(MemoryPool& pool, StmtNode* stmt) - : TypedNode(pool), - statement(stmt) - { - } - public: static DmlNode* parse(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, const UCHAR blrOp); - static StmtNode* make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node); + static StmtNode* make(MemoryPool& pool, DsqlCompilerScratch* dsqlScratch, StmtNode* node, bool force = false); virtual Firebird::string internalPrint(NodePrinter& printer) const; virtual SavepointEncloseNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); @@ -1511,7 +1504,13 @@ class SavepointEncloseNode : public TypedNode(pool), + statement(stmt) + { + } + NestConst statement; }; @@ -1725,6 +1724,30 @@ class SetSessionNode : public SessionManagementNode }; +class SetDebugOptionNode : public SessionManagementNode +{ +public: + SetDebugOptionNode(MemoryPool& pool, MetaName* aName, ExprNode* aValue); + +public: + virtual Firebird::string internalPrint(NodePrinter& printer) const + { + SessionManagementNode::internalPrint(printer); + + NODE_PRINT(printer, name); + NODE_PRINT(printer, value); + + return "SetDebugOptionNode"; + } + + virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** traHandle) const; + +private: + MetaName name; + ExprNode* value; +}; + + class SetDecFloatRoundNode : public SessionManagementNode { public: diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 5cf343d4c7b..d5532961bcb 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -43,6 +43,7 @@ #include "../common/intlobj_new.h" #include "../jrd/jrd.h" #include "../jrd/status.h" +#include "../jrd/ibsetjmp.h" #include "../common/CharSet.h" #include "../dsql/Parser.h" #include "../dsql/ddl_proto.h" @@ -277,6 +278,12 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer) dsql_msg* message = (dsql_msg*) statement->getReceiveMsg(); + if (delayedFormat && message) + { + parseMetadata(delayedFormat, message->msg_parameters); + delayedFormat = NULL; + } + // Set up things for tracing this call Jrd::Attachment* att = req_dbb->dbb_attachment; TraceDSQLFetch trace(att, this); @@ -288,7 +295,7 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer) UCHAR* dsqlMsgBuffer = req_msg_buffers[message->msg_buffer_number]; if (!firstRowFetched && needRestarts()) { - // Note: tra_handle can't be changed by executeReceiveWithRestarts below + // Note: tra_handle can't be changed by executeReceiveWithRestarts below // and outMetadata and outMsg in not used there, so passing NULL's is safe. jrd_tra* tra = req_transaction; @@ -309,13 +316,17 @@ bool DsqlDmlRequest::fetch(thread_db* tdbb, UCHAR* msgBuffer) if (req_timer) req_timer->stop(); - delayedFormat = NULL; trace.fetch(true, ITracePlugin::RESULT_SUCCESS); return false; } - mapInOut(tdbb, true, message, delayedFormat, msgBuffer); - delayedFormat = NULL; + if (msgBuffer) + { + auto old = tdbb->getRequest(); + Cleanup restoreRequest([tdbb, old] {tdbb->setRequest(old);}); + tdbb->setRequest(req_request); + mapInOut(tdbb, true, message, NULL, msgBuffer); + } trace.fetch(false, ITracePlugin::RESULT_SUCCESS); return true; @@ -392,7 +403,7 @@ void DSQL_free_statement(thread_db* tdbb, dsql_req* request, USHORT option) **/ dsql_req* DSQL_prepare(thread_db* tdbb, Attachment* attachment, jrd_tra* transaction, - ULONG length, const TEXT* string, USHORT dialect, + ULONG length, const TEXT* string, USHORT dialect, unsigned prepareFlags, Array* items, Array* buffer, bool isInternalRequest) { @@ -940,7 +951,9 @@ void DsqlDmlRequest::executeReceiveWithRestarts(thread_db* tdbb, jrd_tra** traHa "\tQuery:\n%s\n", numTries, req_request->getStatement()->sqlText->c_str() ); } - // When restart we must execute query + TraceManager::event_dsql_restart(req_dbb->dbb_attachment, req_transaction, this, numTries); + + // When restart we must execute query exec = true; } } @@ -1011,7 +1024,10 @@ void DsqlDdlRequest::execute(thread_db* tdbb, jrd_tra** traHandle, node->executeDdl(tdbb, internalScratch, req_transaction); - if (node->mustBeReplicated()) + const bool isInternalRequest = + (internalScratch->flags & DsqlCompilerScratch::FLAG_INTERNAL_REQUEST); + + if (!isInternalRequest && node->mustBeReplicated()) REPL_exec_sql(tdbb, req_transaction, getStatement()->getOrgText()); } catch (status_exception& ex) @@ -1057,9 +1073,6 @@ void DsqlTransactionRequest::dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scra ntrace_result_t* /*traceResult*/) { node = Node::doDsqlPass(scratch, node); - - // Don't trace pseudo-statements (without requests associated). - req_traced = false; } // Execute a dynamic SQL statement. @@ -1068,7 +1081,9 @@ void DsqlTransactionRequest::execute(thread_db* tdbb, jrd_tra** traHandle, IMessageMetadata* /*outMetadata*/, UCHAR* /*outMsg*/, bool /*singleton*/) { + TraceDSQLExecute trace(req_dbb->dbb_attachment, this); node->execute(tdbb, this, traHandle); + trace.finish(false, ITracePlugin::RESULT_SUCCESS); } @@ -1476,11 +1491,22 @@ static void checkD(IStatus* st) // Prepare a request for execution. Return SQL status code. // Note: caller is responsible for pool handling. +// Use SEH frame when preparing user requests to catch possible stack overflows static dsql_req* prepareRequest(thread_db* tdbb, dsql_dbb* database, jrd_tra* transaction, ULONG textLength, const TEXT* text, USHORT clientDialect, bool isInternalRequest) { - return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, - isInternalRequest); + if (isInternalRequest) + return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, true); + +#ifdef WIN_NT + START_CHECK_FOR_EXCEPTIONS(NULL); +#endif + + return prepareStatement(tdbb, database, transaction, textLength, text, clientDialect, false); + +#ifdef WIN_NT + END_CHECK_FOR_EXCEPTIONS(NULL); +#endif } @@ -1494,7 +1520,7 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra* if (text && textLength == 0) textLength = static_cast(strlen(text)); - TraceDSQLPrepare trace(database->dbb_attachment, transaction, textLength, text); + TraceDSQLPrepare trace(database->dbb_attachment, transaction, textLength, text, isInternalRequest); if (clientDialect > SQL_DIALECT_CURRENT) { @@ -1621,7 +1647,7 @@ static dsql_req* prepareStatement(thread_db* tdbb, dsql_dbb* database, jrd_tra* statement->setType(DsqlCompiledStatement::TYPE_SELECT); - request->req_traced = true; + request->req_traced = !isInternalRequest; trace.setStatement(request); ntrace_result_t traceResult = ITracePlugin::RESULT_SUCCESS; @@ -1818,7 +1844,7 @@ TimeoutTimer* dsql_req::setupTimer(thread_db* tdbb) { if (req_request) { - if (req_request->getStatement()->flags & JrdStatement::FLAG_INTERNAL) + if (req_request->hasInternalStatement()) return req_timer; req_request->req_timeout = this->req_timeout; @@ -2030,7 +2056,7 @@ static void sql_info(thread_db* tdbb, const DsqlCompiledStatement* statement = request->getStatement(); - while (items < end_items && *items != isc_info_end) + while (items < end_items && *items != isc_info_end && info < end_info) { ULONG length; USHORT number; @@ -2136,9 +2162,25 @@ static void sql_info(thread_db* tdbb, break; case isc_info_sql_sqlda_start: - length = *items++; - first_index = static_cast(gds__vax_integer(items, length)); - items += length; + if (items < end_items) + { + length = *items++; + + if (end_items - items >= length) + { + first_index = static_cast(gds__vax_integer(items, length)); + items += length; + break; + } + } + + buffer[0] = item; + length = 1 + INF_convert(isc_inf_invalid_args, buffer + 1); + + if (!(info = put_item(isc_info_error, length, buffer, info, end_info))) + return; + + items = end_items; break; case isc_info_sql_batch_fetch: @@ -2223,6 +2265,64 @@ static void sql_info(thread_db* tdbb, } break; + case isc_info_sql_exec_path_blr_bytes: + case isc_info_sql_exec_path_blr_text: + { + HalfStaticArray path; + + if (request->req_request && request->req_request->getStatement()) + { + const auto& blr = request->req_request->getStatement()->blr; + + if (blr.hasData()) + { + if (item == isc_info_sql_exec_path_blr_bytes) + path.push(blr.begin(), blr.getCount()); + else if (item == isc_info_sql_exec_path_blr_text) + { + fb_print_blr(blr.begin(), (ULONG) blr.getCount(), + [](void* arg, SSHORT offset, const char* line) + { + auto& localPath = *static_cast*>(arg); + auto lineLen = strlen(line); + + // Trim trailing spaces. + while (lineLen > 0 && line[lineLen - 1] == ' ') + --lineLen; + + char offsetStr[10]; + const auto offsetLen = sprintf(offsetStr, "%5d", (int) offset); + + localPath.push(reinterpret_cast(offsetStr), offsetLen); + localPath.push(' '); + localPath.push(reinterpret_cast(line), lineLen); + localPath.push('\n'); + }, + &path, 0); + } + } + } + + if (path.hasData()) + { + // 1-byte item + 2-byte length + isc_info_end/isc_info_truncated == 4 + const ULONG bufferLength = end_info - info - 4; + const ULONG maxLength = MIN(bufferLength, MAX_USHORT); + + if (path.getCount() > maxLength) + { + *info = isc_info_truncated; + info = NULL; + } + else + info = put_item(item, path.getCount(), path.begin(), info, end_info); + } + + if (!info) + return; + } + break; + case isc_info_sql_num_variables: case isc_info_sql_describe_vars: if (messageFound) @@ -2261,7 +2361,8 @@ static void sql_info(thread_db* tdbb, } } - *info++ = isc_info_end; + if (info < end_info) + *info++ = isc_info_end; if (start_info && (end_info - info >= 7)) { @@ -2332,14 +2433,14 @@ static UCHAR* var_info(const dsql_msg* message, // Scan sources of coercion rules in reverse order to observe // 'last entered in use' rule. Start with dynamic binding rules ... - if (!attachment->att_bindings.coerce(&desc)) + if (!attachment->att_bindings.coerce(tdbb, &desc)) { // next - given in DPB ... - if (!attachment->getInitialBindings()->coerce(&desc)) + if (!attachment->getInitialBindings()->coerce(tdbb, &desc)) { Database* dbb = tdbb->getDatabase(); // and finally - rules from .conf files. - dbb->getBindings()->coerce(&desc, dbb->dbb_compatibility_index); + dbb->getBindings()->coerce(tdbb, &desc, dbb->dbb_compatibility_index); } } diff --git a/src/dsql/dsql.h b/src/dsql/dsql.h index 8c797edd0ff..737ce32246c 100644 --- a/src/dsql/dsql.h +++ b/src/dsql/dsql.h @@ -728,7 +728,6 @@ class DsqlTransactionRequest : public dsql_req : dsql_req(pool), node(aNode) { - req_traced = false; } virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool, @@ -750,7 +749,6 @@ class DsqlSessionManagementRequest : public dsql_req : dsql_req(pool), node(aNode) { - req_traced = false; } virtual void dsqlPass(thread_db* tdbb, DsqlCompilerScratch* scratch, bool* destroyScratchPool, diff --git a/src/dsql/dsql_proto.h b/src/dsql/dsql_proto.h index a1e40edd966..dfd44e6d4d2 100644 --- a/src/dsql/dsql_proto.h +++ b/src/dsql/dsql_proto.h @@ -44,7 +44,7 @@ Jrd::DsqlCursor* DSQL_open(Jrd::thread_db*, Jrd::jrd_tra**, Jrd::dsql_req*, Firebird::IMessageMetadata*, const UCHAR*, Firebird::IMessageMetadata*, ULONG); Jrd::dsql_req* DSQL_prepare(Jrd::thread_db*, Jrd::Attachment*, Jrd::jrd_tra*, ULONG, const TEXT*, - USHORT, Firebird::Array*, Firebird::Array*, bool); + USHORT, unsigned, Firebird::Array*, Firebird::Array*, bool); void DSQL_sql_info(Jrd::thread_db*, Jrd::dsql_req*, ULONG, const UCHAR*, ULONG, UCHAR*); diff --git a/src/dsql/metd.epp b/src/dsql/metd.epp index 9eb1ea85282..60ff0a5f1c4 100644 --- a/src/dsql/metd.epp +++ b/src/dsql/metd.epp @@ -737,40 +737,53 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat else { DSC d; - d.dsc_dtype = (F.RDB$FIELD_TYPE != blr_blob) ? - gds_cvt_blr_dtype[F.RDB$FIELD_TYPE] : dtype_blob; - // dimitr: adjust the UDF arguments for CSTRING - if (d.dsc_dtype == dtype_cstring) { - d.dsc_dtype = dtype_text; - } - d.dsc_scale = F.RDB$FIELD_SCALE; - if (!F.RDB$FIELD_SUB_TYPE.NULL) { - d.dsc_sub_type = F.RDB$FIELD_SUB_TYPE; - } - else { + + if (X.RDB$MECHANISM == FUN_scalar_array) + { + d.dsc_dtype = dtype_array; + d.dsc_scale = 0; d.dsc_sub_type = 0; + d.dsc_length = sizeof(ISC_QUAD); + d.dsc_flags = DSC_nullable; } - d.dsc_length = F.RDB$FIELD_LENGTH; - if (d.dsc_dtype == dtype_varying) { - d.dsc_length += sizeof(USHORT); - } - d.dsc_address = NULL; - - if (!F.RDB$CHARACTER_SET_ID.NULL) + else { - if (d.dsc_dtype != dtype_blob) { - d.dsc_ttype() = F.RDB$CHARACTER_SET_ID; + d.dsc_dtype = (F.RDB$FIELD_TYPE != blr_blob) ? + gds_cvt_blr_dtype[F.RDB$FIELD_TYPE] : dtype_blob; + // dimitr: adjust the UDF arguments for CSTRING + if (d.dsc_dtype == dtype_cstring) { + d.dsc_dtype = dtype_text; + } + d.dsc_scale = F.RDB$FIELD_SCALE; + if (!F.RDB$FIELD_SUB_TYPE.NULL) { + d.dsc_sub_type = F.RDB$FIELD_SUB_TYPE; } else { - d.dsc_scale = F.RDB$CHARACTER_SET_ID; + d.dsc_sub_type = 0; + } + d.dsc_length = F.RDB$FIELD_LENGTH; + if (d.dsc_dtype == dtype_varying) { + d.dsc_length += sizeof(USHORT); } - } - if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference) - { - d.dsc_flags = DSC_nullable; + if (!F.RDB$CHARACTER_SET_ID.NULL) + { + if (d.dsc_dtype != dtype_blob) { + d.dsc_ttype() = F.RDB$CHARACTER_SET_ID; + } + else { + d.dsc_scale = F.RDB$CHARACTER_SET_ID; + } + } + + if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference) + { + d.dsc_flags = DSC_nullable; + } } + d.dsc_address = NULL; + if (!X.RDB$DEFAULT_VALUE.NULL || (fb_utils::implicit_domain(F.RDB$FIELD_NAME) && !F.RDB$DEFAULT_VALUE.NULL)) { @@ -810,40 +823,53 @@ dsql_udf* METD_get_function(jrd_tra* transaction, DsqlCompilerScratch* dsqlScrat else { DSC d; - d.dsc_dtype = (X.RDB$FIELD_TYPE != blr_blob) ? - gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob; - // dimitr: adjust the UDF arguments for CSTRING - if (d.dsc_dtype == dtype_cstring) { - d.dsc_dtype = dtype_text; - } - d.dsc_scale = X.RDB$FIELD_SCALE; - if (!X.RDB$FIELD_SUB_TYPE.NULL) { - d.dsc_sub_type = X.RDB$FIELD_SUB_TYPE; - } - else { + + if (X.RDB$MECHANISM == FUN_scalar_array) + { + d.dsc_dtype = dtype_array; + d.dsc_scale = 0; d.dsc_sub_type = 0; + d.dsc_length = sizeof(ISC_QUAD); + d.dsc_flags = DSC_nullable; } - d.dsc_length = X.RDB$FIELD_LENGTH; - if (d.dsc_dtype == dtype_varying) { - d.dsc_length += sizeof(USHORT); - } - d.dsc_address = NULL; - - if (!X.RDB$CHARACTER_SET_ID.NULL) + else { - if (d.dsc_dtype != dtype_blob) { - d.dsc_ttype() = X.RDB$CHARACTER_SET_ID; + d.dsc_dtype = (X.RDB$FIELD_TYPE != blr_blob) ? + gds_cvt_blr_dtype[X.RDB$FIELD_TYPE] : dtype_blob; + // dimitr: adjust the UDF arguments for CSTRING + if (d.dsc_dtype == dtype_cstring) { + d.dsc_dtype = dtype_text; + } + d.dsc_scale = X.RDB$FIELD_SCALE; + if (!X.RDB$FIELD_SUB_TYPE.NULL) { + d.dsc_sub_type = X.RDB$FIELD_SUB_TYPE; } else { - d.dsc_scale = X.RDB$CHARACTER_SET_ID; + d.dsc_sub_type = 0; + } + d.dsc_length = X.RDB$FIELD_LENGTH; + if (d.dsc_dtype == dtype_varying) { + d.dsc_length += sizeof(USHORT); } - } - if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference) - { - d.dsc_flags = DSC_nullable; + if (!X.RDB$CHARACTER_SET_ID.NULL) + { + if (d.dsc_dtype != dtype_blob) { + d.dsc_ttype() = X.RDB$CHARACTER_SET_ID; + } + else { + d.dsc_scale = X.RDB$CHARACTER_SET_ID; + } + } + + if (X.RDB$MECHANISM != FUN_value && X.RDB$MECHANISM != FUN_reference) + { + d.dsc_flags = DSC_nullable; + } } + d.dsc_address = NULL; + if (!X.RDB$DEFAULT_VALUE.NULL) { defaults++; diff --git a/src/dsql/parse.y b/src/dsql/parse.y index 34020f2cd34..9b9f13433a4 100644 --- a/src/dsql/parse.y +++ b/src/dsql/parse.y @@ -651,8 +651,8 @@ using namespace Firebird; %token RSA_ENCRYPT %token RSA_PRIVATE %token RSA_PUBLIC -%token RSA_SIGN -%token RSA_VERIFY +%token RSA_SIGN_HASH +%token RSA_VERIFY_HASH %token SALT_LENGTH %token SECURITY %token SESSION @@ -677,6 +677,12 @@ using namespace Firebird; %token CLEAR %token OLDEST +// tokens added for Firebird 4.0.1 + +%token DEBUG +%token PKCS_1_5 +%token BLOB_APPEND + // precedence declarations for expression evaluation %left OR @@ -884,7 +890,8 @@ tra_statement %type mng_statement mng_statement - : set_decfloat_round { $$ = $1; } + : set_debug_option { $$ = $1; } + | set_decfloat_round { $$ = $1; } | set_decfloat_traps { $$ = $1; } | session_statement { $$ = $1; } | set_role { $$ = $1; } @@ -5348,6 +5355,12 @@ set_role { $$ = newNode(); } ; +%type set_debug_option +set_debug_option + : SET DEBUG OPTION valid_symbol_name '=' constant + { $$ = newNode($4, $6); } + ; + %type set_decfloat_round set_decfloat_round : SET DECFLOAT ROUND valid_symbol_name @@ -7297,7 +7310,7 @@ map_from_symbol_name %type map_logoninfo map_logoninfo : sql_string - | valid_symbol_name { $$ = newNode($1->c_str()); } + | valid_symbol_name { $$ = newIntlString($1->c_str(), metadataCharSet->getName()); } ; %type map_using() @@ -8094,6 +8107,7 @@ system_function_std_syntax | BIN_SHL | BIN_SHR | BIN_XOR + | BLOB_APPEND | CEIL | CHAR_TO_UUID | COS @@ -8214,25 +8228,25 @@ system_function_special_syntax } | POSITION '(' value_list_opt ')' { $$ = newNode(*$1, $3); } - | rsa_encrypt_decrypt '(' value KEY value crypt_opt_lparam crypt_opt_hash ')' + | rsa_encrypt_decrypt '(' value KEY value crypt_opt_lparam crypt_opt_hash crypt_opt_pkcs')' { $$ = newNode(*$1, newNode($3)->add($5)->add($6)-> - add(MAKE_str_constant(newIntlString($7->c_str()), CS_ASCII))); + add(MAKE_str_constant(newIntlString($7->c_str()), CS_ASCII))->add($8)); $$->dsqlSpecialSyntax = true; } - | RSA_SIGN '(' value KEY value crypt_opt_hash crypt_opt_saltlen ')' + | RSA_SIGN_HASH '(' value KEY value crypt_opt_hash crypt_opt_saltlen crypt_opt_pkcs ')' { $$ = newNode(*$1, newNode($3)->add($5)-> - add(MAKE_str_constant(newIntlString($6->c_str()), CS_ASCII))->add($7)); + add(MAKE_str_constant(newIntlString($6->c_str()), CS_ASCII))->add($7)->add($8)); $$->dsqlSpecialSyntax = true; } - | RSA_VERIFY'(' value SIGNATURE value KEY value crypt_opt_hash crypt_opt_saltlen ')' + | RSA_VERIFY_HASH '(' value SIGNATURE value KEY value crypt_opt_hash crypt_opt_saltlen crypt_opt_pkcs ')' { $$ = newNode(*$1, newNode($3)->add($5)->add($7)-> - add(MAKE_str_constant(newIntlString($8->c_str()), CS_ASCII))->add($9)); + add(MAKE_str_constant(newIntlString($8->c_str()), CS_ASCII))->add($9)->add($10)); $$->dsqlSpecialSyntax = true; } | RDB_SYSTEM_PRIVILEGE '(' valid_symbol_name ')' @@ -8260,6 +8274,14 @@ crypt_opt_lparam { $$ = $2; } ; +%type crypt_opt_pkcs +crypt_opt_pkcs + : // nothing + { $$ = MAKE_const_slong(0); } + | PKCS_1_5 + { $$ = MAKE_const_slong(1); } + ; + %type crypt_opt_hash crypt_opt_hash : // nothing @@ -9028,8 +9050,8 @@ non_reserved_word | RSA_ENCRYPT | RSA_PRIVATE | RSA_PUBLIC - | RSA_SIGN - | RSA_VERIFY + | RSA_SIGN_HASH + | RSA_VERIFY_HASH | SALT_LENGTH | SECURITY | SESSION @@ -9040,6 +9062,9 @@ non_reserved_word | TOTALORDER | TRAPS | ZONE + | DEBUG // added in FB 4.0.1 + | PKCS_1_5 + | BLOB_APPEND ; %% diff --git a/src/dsql/pass1.cpp b/src/dsql/pass1.cpp index eb01c9a4190..dea37cf95ae 100644 --- a/src/dsql/pass1.cpp +++ b/src/dsql/pass1.cpp @@ -2806,16 +2806,11 @@ static void pass1_union_auto_cast(DsqlCompilerScratch* dsqlScratch, ExprNode* in field->length = desc.dsc_length; field->flags = (desc.dsc_flags & DSC_nullable) ? FLD_nullable : 0; - if (desc.dsc_dtype <= dtype_any_text) + if (desc.isText() || desc.isBlob()) { - field->textType = desc.dsc_sub_type; - field->charSetId = INTL_GET_CHARSET(&desc); - field->collationId = INTL_GET_COLLATE(&desc); - } - else if (desc.dsc_dtype == dtype_blob) - { - field->charSetId = desc.dsc_scale; - field->collationId = desc.dsc_flags >> 8; + field->textType = desc.getTextType(); + field->charSetId = desc.getCharSet(); + field->collationId = desc.getCollation(); } // Finally copy the descriptors to the root nodes and swap diff --git a/src/extlib/ib_util.cpp b/src/extlib/ib_util.cpp index 114825ae854..614fc96d2d2 100644 --- a/src/extlib/ib_util.cpp +++ b/src/extlib/ib_util.cpp @@ -19,21 +19,19 @@ */ #include -#include "ib_util.h" #include "firebird.h" - -typedef void* VoidPtr; +#include "ibase.h" // initialized by the engine static void* (*allocFunc)(long) = NULL; -extern "C" void FB_EXPORTED ib_util_init(void* (*aAllocFunc)(long)) +extern "C" FB_DLL_EXPORT void ib_util_init(void* (*aAllocFunc)(long)) { allocFunc = aAllocFunc; } -extern "C" VoidPtr FB_EXPORTED ib_util_malloc(long size) +extern "C" FB_DLL_EXPORT void* ib_util_malloc(long size) { return allocFunc ? allocFunc(size) : malloc(size); } diff --git a/src/gpre/c_cxx.cpp b/src/gpre/c_cxx.cpp index 625cae08b0e..3527c437428 100644 --- a/src/gpre/c_cxx.cpp +++ b/src/gpre/c_cxx.cpp @@ -2016,7 +2016,7 @@ static SSHORT gen_event_block(act* action) int ident = CMP_next_ident(); init->nod_arg[2] = (gpre_nod*)(IPTR)ident; - printa(0, "static %schar\n *isc_%da, *isc_%db;", CONST_STR, ident, ident); + printa(0, "static unsigned char\n *isc_%da, *isc_%db;", ident, ident); printa(0, "static short\n isc_%dl;", ident); const gpre_nod* list = init->nod_arg[1]; diff --git a/src/gpre/obj_cxx.cpp b/src/gpre/obj_cxx.cpp index 6a41b7d449f..5486a902bcf 100644 --- a/src/gpre/obj_cxx.cpp +++ b/src/gpre/obj_cxx.cpp @@ -1413,6 +1413,16 @@ static int gen_cursor_open( const act* action, const gpre_req* request, int colu // Generate insertion text for the database statement. // +static void ifndef(const char* nm, const char* nm2 = "") +{ + fprintf(gpreGlob.out_file, "\n#ifndef %s%s", nm, nm2); +} + +static void endif() +{ + fprintf(gpreGlob.out_file, "\n#endif"); +} + static void gen_database(int column) { if (global_first_flag) @@ -1427,8 +1437,10 @@ static void gen_database(int column) fprintf(gpreGlob.out_file, "#define CAST_CONST_MSG(A) (reinterpret_cast(A))\n"); fprintf(gpreGlob.out_file, "#define CAST_MSG(A) (reinterpret_cast(A))\n"); + ifndef("fbBlobNull"); printa(column, "static %sISC_QUAD", CONST_STR); printa(column + INDENT, "fbBlobNull = {0, 0};\t/* initializer for blobs */"); + endif(); const TEXT* scope = ""; @@ -1440,6 +1452,8 @@ static void gen_database(int column) { all_static = all_static && (db->dbb_scope == DBB_STATIC); all_extern = all_extern && (db->dbb_scope == DBB_EXTERN); + + ifndef(db->dbb_name->sym_string); if (db->dbb_scope == DBB_STATIC) scope = "static "; else if (db->dbb_scope == DBB_EXTERN) @@ -1449,6 +1463,7 @@ static void gen_database(int column) printa(column + INDENT, "%s = 0;\t\t/* database handle */\n", db->dbb_name->sym_string); else printa(column + INDENT, "%s;\t\t/* database handle */\n", db->dbb_name->sym_string); + endif(); } if (all_static) @@ -1456,6 +1471,7 @@ static void gen_database(int column) else if (all_extern) scope = "extern "; + ifndef(gpreGlob.transaction_name); printa(column, "%sFirebird::ITransaction*", scope); if (!all_extern) printa(column + INDENT, "%s = 0;\t\t/* default transaction handle */", @@ -1463,33 +1479,43 @@ static void gen_database(int column) else printa(column + INDENT, "%s;\t\t/* default transaction handle */", gpreGlob.transaction_name); + endif(); + ifndef("fbMaster"); printa(column, "%sFirebird::IMaster* fbMaster%s;\t\t/* master interface */", scope, all_extern ? "" : " = Firebird::fb_get_master_interface()"); + endif(); + + ifndef("fbProvider"); printa(column, "%sFirebird::IProvider* fbProvider%s;\t\t/* provider interface */", scope, all_extern ? "" : " = fbMaster->getDispatcher()"); + endif(); + ifndef(global_status_name); printa(column, "%sFirebird::CheckStatusWrapper %sObj%s;\t/* status vector */", scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())"); - printa(column, "%sFirebird::CheckStatusWrapper %s2Obj%s;\t/* status vector */", - scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())"); - if (all_extern) - { printa(column, "%sFirebird::CheckStatusWrapper* %s;\t/* status vector */", scope, global_status_name); - printa(column, "%sFirebird::CheckStatusWrapper* %s2;\t/* status vector */", - scope, global_status_name); - } else - { printa(column, "%sFirebird::CheckStatusWrapper* %s = &%sObj;\t/* status vector */", scope, global_status_name, global_status_name); + endif(); + + ifndef(global_status_name, "2"); + printa(column, "%sFirebird::CheckStatusWrapper %s2Obj%s;\t/* status vector */", + scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())"); + if (all_extern) + printa(column, "%sFirebird::CheckStatusWrapper* %s2;\t/* status vector */", + scope, global_status_name); + else printa(column, "%sFirebird::CheckStatusWrapper* %s2 = &%s2Obj;\t/* status vector */", scope, global_status_name, global_status_name); - } + endif(); + ifndef("fbIStatus"); printa(column, "%sint fbIStatus;\t/* last completion code */", scope); + endif(); for (db = gpreGlob.isc_databases; db; db = db->dbb_next) for (const tpb* tpb_iterator = db->dbb_tpbs; tpb_iterator; diff --git a/src/include/fb_exception.h b/src/include/fb_exception.h index 2e82a559048..52f7a92b672 100644 --- a/src/include/fb_exception.h +++ b/src/include/fb_exception.h @@ -129,9 +129,11 @@ class system_error : public status_exception { private: int errorCode; -public: - system_error(const char* syscall, int error_code); +protected: + system_error(const char* syscall, const char* arg, int error_code); + +public: static void raise(const char* syscall, int error_code); static void raise(const char* syscall); @@ -147,11 +149,14 @@ class system_error : public status_exception // it will call abort() in DEV_BUILD to create core dump class system_call_failed : public system_error { -public: - system_call_failed(const char* syscall, int error_code); +protected: + system_call_failed(const char* syscall, const char* arg, int error_code); +public: static void raise(const char* syscall, int error_code); static void raise(const char* syscall); + static void raise(const char* syscall, const char* arg, int error_code); + static void raise(const char* syscall, const char* arg); }; class fatal_exception : public status_exception diff --git a/src/include/firebird.h b/src/include/firebird.h index 1bd7f2d4b3a..391d7707ce6 100644 --- a/src/include/firebird.h +++ b/src/include/firebird.h @@ -43,13 +43,6 @@ #define DEBUG_GDS_ALLOC #endif -#if defined(WIN_NT) -#define FB_DLL_EXPORT __declspec(dllexport) -#elif defined(DARWIN) -#define FB_DLL_EXPORT API_ROUTINE -#else -#define FB_DLL_EXPORT -#endif //#if defined(SOLX86) // this pragmas is used only with gcc 2.95! //#define __PRAGMA_REDEFINE_EXTNAME diff --git a/src/include/firebird/FirebirdInterface.idl b/src/include/firebird/FirebirdInterface.idl index c1f17a346a9..901df31f60e 100644 --- a/src/include/firebird/FirebirdInterface.idl +++ b/src/include/firebird/FirebirdInterface.idl @@ -38,6 +38,8 @@ typedef FB_DEC16; typedef FB_DEC34; typedef FB_I128; +boolean FB_UsedInYValve; + // Versioned interface - base for all FB interfaces interface Versioned { @@ -347,9 +349,15 @@ interface Blob : ReferenceCounted void putSegment(Status status, uint length, const void* buffer); + void deprecatedCancel(Status status); + void deprecatedClose(Status status); + int seek(Status status, int mode, int offset); // returns position + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedCancel(status) endif] void cancel(Status status); + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif] void close(Status status); - int seek(Status status, int mode, int offset); // returns position } interface Transaction : ReferenceCounted @@ -359,14 +367,22 @@ interface Transaction : ReferenceCounted uint bufferLength, uchar* buffer); void prepare(Status status, uint msgLength, const uchar* message); - void commit(Status status); + void deprecatedCommit(Status status); void commitRetaining(Status status); - void rollback(Status status); + void deprecatedRollback(Status status); void rollbackRetaining(Status status); - void disconnect(Status status); + void deprecatedDisconnect(Status status); Transaction join(Status status, Transaction transaction); Transaction validate(Status status, Attachment attachment); Transaction enterDtc(Status status); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedCommit(status) endif] + void commit(Status status); + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedRollback(status) endif] + void rollback(Status status); + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedDisconnect(status) endif] + void disconnect(Status status); } interface MessageMetadata : ReferenceCounted @@ -426,12 +442,16 @@ interface ResultSet : ReferenceCounted boolean isEof(Status status); boolean isBof(Status status); MessageMetadata getMetadata(Status status); - void close(Status status); + void deprecatedClose(Status status); // This item is for ISC API emulation only // It may be gone in future versions // Please do not use it! void setDelayedOutputFormat(Status status, MessageMetadata format); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif] + void close(Status status); } interface Statement : ReferenceCounted @@ -472,7 +492,7 @@ interface Statement : ReferenceCounted ResultSet openCursor(Status status, Transaction transaction, MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata, uint flags); void setCursorName(Status status, const string name); - void free(Status status); + void deprecatedFree(Status status); uint getFlags(Status status); version: // 3.0 => 4.0 @@ -487,24 +507,38 @@ version: // 3.0 => 4.0 Pipe createPipe(Status status, Transaction transaction, MessageMetadata inMetadata, void* inBuffer, MessageMetadata outMetadata, uint parLength, const uchar* par); */ + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedFree(status) endif] + void free(Status status); } interface Batch : ReferenceCounted { const uchar VERSION1 = 1; // Tag for parameters block + // Tags for parameters const uchar TAG_MULTIERROR = 1; // Can have >1 buffers with errors const uchar TAG_RECORD_COUNTS = 2; // Per-record modified records accountung const uchar TAG_BUFFER_BYTES_SIZE = 3; // Maximum possible buffer size const uchar TAG_BLOB_POLICY = 4; // What policy is used to store blobs const uchar TAG_DETAILED_ERRORS = 5; // How many vectors with detailed error info are stored + // Info items + const uchar INF_BUFFER_BYTES_SIZE = 10; // Maximum possible buffer size + const uchar INF_DATA_BYTES_SIZE = 11; // Already added messages size + const uchar INF_BLOBS_BYTES_SIZE = 12; // Already added blobs size + const uchar INF_BLOB_ALIGNMENT = 13; // Duplicate getBlobAlignment + const uchar INF_BLOB_HEADER = 14; // Blob header size + + // How should batch work with blobs const uchar BLOB_NONE = 0; // Blobs can't be used const uchar BLOB_ID_ENGINE = 1; // Blobs are added one by one, IDs are generated by firebird const uchar BLOB_ID_USER = 2; // Blobs are added one by one, IDs are generated by user const uchar BLOB_STREAM = 3; // Blobs are added in a stream, IDs are generated by user - const uint BLOB_SEGHDR_ALIGN = 2; // Alignment of segment header in the stream + // Blob stream + const uint BLOB_SEGHDR_ALIGN = 2; // Alignment of segment header in the blob stream void add(Status status, uint count, const void* inBuffer); void addBlob(Status status, uint length, const void* inBuffer, ISC_QUAD* blobId, uint parLength, const uchar* par); @@ -516,7 +550,14 @@ interface Batch : ReferenceCounted uint getBlobAlignment(Status status); MessageMetadata getMetadata(Status status); void setDefaultBpb(Status status, uint parLength, const uchar* par); + void deprecatedClose(Status status); + +version: // 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif] void close(Status status); + void getInfo(Status status, + uint itemsLength, const uchar* items, + uint bufferLength, uchar* buffer); } interface BatchCompletionState : Disposable @@ -554,6 +595,10 @@ interface Replicator : ReferenceCounted void process(Status status, ReplicationBatch batch); */ void process(Status status, uint length, const uchar* data); + void deprecatedClose(Status status); + +version: // 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedClose(status) endif] void close(Status status); } @@ -570,11 +615,19 @@ interface Request : ReferenceCounted void startAndSend(Status status, Transaction tra, int level, uint msgType, uint length, const void* message); void unwind(Status status, int level); + void deprecatedFree(Status status); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedFree(status) endif] void free(Status status); } interface Events : ReferenceCounted { + void deprecatedCancel(Status status); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedCancel(status) endif] void cancel(Status status); } @@ -620,8 +673,8 @@ interface Attachment : ReferenceCounted uint length, const uchar* events); void cancelOperation(Status status, int option); void ping(Status status); - void detach(Status status); - void dropDatabase(Status status); + void deprecatedDetach(Status status); + void deprecatedDropDatabase(Status status); version: // 3.0 => 4.0 // Idle attachment timeout, seconds @@ -643,17 +696,30 @@ version: // 3.0 => 4.0 */ Replicator createReplicator(Status status); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedDetach(status) endif] + void detach(Status status); + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedDropDatabase(status) endif] + void dropDatabase(Status status); } interface Service : ReferenceCounted { - void detach(Status status); + void deprecatedDetach(Status status); void query(Status status, uint sendLength, const uchar* sendItems, uint receiveLength, const uchar* receiveItems, uint bufferLength, uchar* buffer); void start(Status status, uint spbLength, const uchar* spb); + +version: // 3.0.7 => 3.0.8, 4.0.0 => 4.0.1 + [notImplementedAction if ::FB_UsedInYValve then defaultAction else call deprecatedDetach(status) endif] + void detach(Status status); + +version: // 3.0.9 => 3.0.10, 4.0.1 => 4.0.2 + void cancel(Status status); } interface Provider : PluginBase @@ -692,6 +758,7 @@ interface Auth : PluginBase const int AUTH_SUCCESS = 0; const int AUTH_MORE_DATA = 1; const int AUTH_CONTINUE = 2; + const int AUTH_SUCCESS_WITH_DATA = 3; } interface Writer : Versioned @@ -864,6 +931,23 @@ interface CryptKeyCallback : Versioned // any further details. uint callback(uint dataLength, const void* data, uint bufferLength, void* buffer); + +version: // 6.0, 5.0.2, 4.0.6 + + // NULL in attStatus means attach was successful. + // DO_RETRY return will be ignored in this case, but plugin has a chance + // to reflect internally success. + [stub defaultAction] + void dummy1(Status status); + + // interface not needed any more + [stub defaultAction] + void dummy2(); + + // Produce something to be compared with other interface instance + [notImplemented(-1)] + int getHashLength(Status status); + void getHashData(Status status, void* hash); } @@ -1153,6 +1237,8 @@ interface XpbBuilder : Disposable const uint SPB_SEND = 7; const uint SPB_RECEIVE = 8; const uint SPB_RESPONSE = 9; + const uint INFO_SEND = 10; + const uint INFO_RESPONSE = 11; // removing data void clear(Status status); @@ -1463,6 +1549,12 @@ interface TracePlugin : ReferenceCounted [notImplemented(true)] boolean trace_func_execute (TraceDatabaseConnection connection, TraceTransaction transaction, TraceFunction function, boolean started, uint func_result); + +version: // 4.0.1 -> 4.0.2 + [notImplemented(true)] + boolean trace_dsql_restart(TraceDatabaseConnection connection, TraceTransaction transaction, TraceSQLStatement statement, + uint number); + } // Trace plugin second level factory (this is what is known to PluginManager as "trace plugin") diff --git a/src/include/firebird/IdlFbInterfaces.h b/src/include/firebird/IdlFbInterfaces.h index 37de20117f7..9207e8fe9f3 100644 --- a/src/include/firebird/IdlFbInterfaces.h +++ b/src/include/firebird/IdlFbInterfaces.h @@ -1044,9 +1044,11 @@ namespace Firebird void (CLOOP_CARG *getInfo)(IBlob* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw(); int (CLOOP_CARG *getSegment)(IBlob* self, IStatus* status, unsigned bufferLength, void* buffer, unsigned* segmentLength) throw(); void (CLOOP_CARG *putSegment)(IBlob* self, IStatus* status, unsigned length, const void* buffer) throw(); + void (CLOOP_CARG *deprecatedCancel)(IBlob* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedClose)(IBlob* self, IStatus* status) throw(); + int (CLOOP_CARG *seek)(IBlob* self, IStatus* status, int mode, int offset) throw(); void (CLOOP_CARG *cancel)(IBlob* self, IStatus* status) throw(); void (CLOOP_CARG *close)(IBlob* self, IStatus* status) throw(); - int (CLOOP_CARG *seek)(IBlob* self, IStatus* status, int mode, int offset) throw(); }; protected: @@ -1060,7 +1062,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; template void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) { @@ -1084,17 +1086,17 @@ namespace Firebird StatusType::checkException(status); } - template void cancel(StatusType* status) + template void deprecatedCancel(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->cancel(this, status); + static_cast(this->cloopVTable)->deprecatedCancel(this, status); StatusType::checkException(status); } - template void close(StatusType* status) + template void deprecatedClose(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->close(this, status); + static_cast(this->cloopVTable)->deprecatedClose(this, status); StatusType::checkException(status); } @@ -1105,6 +1107,42 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template void cancel(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IBlob", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedCancel(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->cancel(this, status); + StatusType::checkException(status); + } + + template void close(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IBlob", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedClose(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->close(this, status); + StatusType::checkException(status); + } }; class ITransaction : public IReferenceCounted @@ -1114,14 +1152,17 @@ namespace Firebird { void (CLOOP_CARG *getInfo)(ITransaction* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw(); void (CLOOP_CARG *prepare)(ITransaction* self, IStatus* status, unsigned msgLength, const unsigned char* message) throw(); - void (CLOOP_CARG *commit)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedCommit)(ITransaction* self, IStatus* status) throw(); void (CLOOP_CARG *commitRetaining)(ITransaction* self, IStatus* status) throw(); - void (CLOOP_CARG *rollback)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedRollback)(ITransaction* self, IStatus* status) throw(); void (CLOOP_CARG *rollbackRetaining)(ITransaction* self, IStatus* status) throw(); - void (CLOOP_CARG *disconnect)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedDisconnect)(ITransaction* self, IStatus* status) throw(); ITransaction* (CLOOP_CARG *join)(ITransaction* self, IStatus* status, ITransaction* transaction) throw(); ITransaction* (CLOOP_CARG *validate)(ITransaction* self, IStatus* status, IAttachment* attachment) throw(); ITransaction* (CLOOP_CARG *enterDtc)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *commit)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *rollback)(ITransaction* self, IStatus* status) throw(); + void (CLOOP_CARG *disconnect)(ITransaction* self, IStatus* status) throw(); }; protected: @@ -1135,7 +1176,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; template void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) { @@ -1151,10 +1192,10 @@ namespace Firebird StatusType::checkException(status); } - template void commit(StatusType* status) + template void deprecatedCommit(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->commit(this, status); + static_cast(this->cloopVTable)->deprecatedCommit(this, status); StatusType::checkException(status); } @@ -1165,10 +1206,10 @@ namespace Firebird StatusType::checkException(status); } - template void rollback(StatusType* status) + template void deprecatedRollback(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->rollback(this, status); + static_cast(this->cloopVTable)->deprecatedRollback(this, status); StatusType::checkException(status); } @@ -1179,10 +1220,10 @@ namespace Firebird StatusType::checkException(status); } - template void disconnect(StatusType* status) + template void deprecatedDisconnect(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->disconnect(this, status); + static_cast(this->cloopVTable)->deprecatedDisconnect(this, status); StatusType::checkException(status); } @@ -1209,6 +1250,60 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template void commit(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "ITransaction", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedCommit(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->commit(this, status); + StatusType::checkException(status); + } + + template void rollback(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "ITransaction", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedRollback(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->rollback(this, status); + StatusType::checkException(status); + } + + template void disconnect(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "ITransaction", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedDisconnect(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->disconnect(this, status); + StatusType::checkException(status); + } }; class IMessageMetadata : public IReferenceCounted @@ -1570,8 +1665,9 @@ namespace Firebird FB_BOOLEAN (CLOOP_CARG *isEof)(IResultSet* self, IStatus* status) throw(); FB_BOOLEAN (CLOOP_CARG *isBof)(IResultSet* self, IStatus* status) throw(); IMessageMetadata* (CLOOP_CARG *getMetadata)(IResultSet* self, IStatus* status) throw(); - void (CLOOP_CARG *close)(IResultSet* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedClose)(IResultSet* self, IStatus* status) throw(); void (CLOOP_CARG *setDelayedOutputFormat)(IResultSet* self, IStatus* status, IMessageMetadata* format) throw(); + void (CLOOP_CARG *close)(IResultSet* self, IStatus* status) throw(); }; protected: @@ -1585,7 +1681,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; template int fetchNext(StatusType* status, void* message) { @@ -1659,10 +1755,10 @@ namespace Firebird return ret; } - template void close(StatusType* status) + template void deprecatedClose(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->close(this, status); + static_cast(this->cloopVTable)->deprecatedClose(this, status); StatusType::checkException(status); } @@ -1672,6 +1768,24 @@ namespace Firebird static_cast(this->cloopVTable)->setDelayedOutputFormat(this, status, format); StatusType::checkException(status); } + + template void close(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IResultSet", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedClose(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->close(this, status); + StatusType::checkException(status); + } }; class IStatement : public IReferenceCounted @@ -1688,11 +1802,12 @@ namespace Firebird ITransaction* (CLOOP_CARG *execute)(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) throw(); IResultSet* (CLOOP_CARG *openCursor)(IStatement* self, IStatus* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) throw(); void (CLOOP_CARG *setCursorName)(IStatement* self, IStatus* status, const char* name) throw(); - void (CLOOP_CARG *free)(IStatement* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedFree)(IStatement* self, IStatus* status) throw(); unsigned (CLOOP_CARG *getFlags)(IStatement* self, IStatus* status) throw(); unsigned (CLOOP_CARG *getTimeout)(IStatement* self, IStatus* status) throw(); void (CLOOP_CARG *setTimeout)(IStatement* self, IStatus* status, unsigned timeOut) throw(); IBatch* (CLOOP_CARG *createBatch)(IStatement* self, IStatus* status, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) throw(); + void (CLOOP_CARG *free)(IStatement* self, IStatus* status) throw(); }; protected: @@ -1706,7 +1821,7 @@ namespace Firebird } public: - static const unsigned VERSION = 4; + static const unsigned VERSION = 5; static const unsigned PREPARE_PREFETCH_NONE = 0x0; static const unsigned PREPARE_PREFETCH_TYPE = 0x1; @@ -1792,10 +1907,10 @@ namespace Firebird StatusType::checkException(status); } - template void free(StatusType* status) + template void deprecatedFree(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->free(this, status); + static_cast(this->cloopVTable)->deprecatedFree(this, status); StatusType::checkException(status); } @@ -1847,6 +1962,24 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template void free(StatusType* status) + { + if (cloopVTable->version < 5) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IStatement", cloopVTable->version, 5); + StatusType::checkException(status); + } + else { + deprecatedFree(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->free(this, status); + StatusType::checkException(status); + } }; class IBatch : public IReferenceCounted @@ -1864,7 +1997,9 @@ namespace Firebird unsigned (CLOOP_CARG *getBlobAlignment)(IBatch* self, IStatus* status) throw(); IMessageMetadata* (CLOOP_CARG *getMetadata)(IBatch* self, IStatus* status) throw(); void (CLOOP_CARG *setDefaultBpb)(IBatch* self, IStatus* status, unsigned parLength, const unsigned char* par) throw(); + void (CLOOP_CARG *deprecatedClose)(IBatch* self, IStatus* status) throw(); void (CLOOP_CARG *close)(IBatch* self, IStatus* status) throw(); + void (CLOOP_CARG *getInfo)(IBatch* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw(); }; protected: @@ -1878,7 +2013,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; static const unsigned char VERSION1 = 1; static const unsigned char TAG_MULTIERROR = 1; @@ -1886,6 +2021,11 @@ namespace Firebird static const unsigned char TAG_BUFFER_BYTES_SIZE = 3; static const unsigned char TAG_BLOB_POLICY = 4; static const unsigned char TAG_DETAILED_ERRORS = 5; + static const unsigned char INF_BUFFER_BYTES_SIZE = 10; + static const unsigned char INF_DATA_BYTES_SIZE = 11; + static const unsigned char INF_BLOBS_BYTES_SIZE = 12; + static const unsigned char INF_BLOB_ALIGNMENT = 13; + static const unsigned char INF_BLOB_HEADER = 14; static const unsigned char BLOB_NONE = 0; static const unsigned char BLOB_ID_ENGINE = 1; static const unsigned char BLOB_ID_USER = 2; @@ -1965,12 +2105,43 @@ namespace Firebird StatusType::checkException(status); } + template void deprecatedClose(StatusType* status) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->deprecatedClose(this, status); + StatusType::checkException(status); + } + template void close(StatusType* status) { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IBatch", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedClose(status); + } + return; + } StatusType::clearException(status); static_cast(this->cloopVTable)->close(this, status); StatusType::checkException(status); } + + template void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) + { + if (cloopVTable->version < 4) + { + StatusType::setVersionError(status, "IBatch", cloopVTable->version, 4); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->getInfo(this, status, itemsLength, items, bufferLength, buffer); + StatusType::checkException(status); + } }; class IBatchCompletionState : public IDisposable @@ -2039,6 +2210,7 @@ namespace Firebird struct VTable : public IReferenceCounted::VTable { void (CLOOP_CARG *process)(IReplicator* self, IStatus* status, unsigned length, const unsigned char* data) throw(); + void (CLOOP_CARG *deprecatedClose)(IReplicator* self, IStatus* status) throw(); void (CLOOP_CARG *close)(IReplicator* self, IStatus* status) throw(); }; @@ -2053,7 +2225,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; template void process(StatusType* status, unsigned length, const unsigned char* data) { @@ -2062,8 +2234,26 @@ namespace Firebird StatusType::checkException(status); } + template void deprecatedClose(StatusType* status) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->deprecatedClose(this, status); + StatusType::checkException(status); + } + template void close(StatusType* status) { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IReplicator", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedClose(status); + } + return; + } StatusType::clearException(status); static_cast(this->cloopVTable)->close(this, status); StatusType::checkException(status); @@ -2081,6 +2271,7 @@ namespace Firebird void (CLOOP_CARG *start)(IRequest* self, IStatus* status, ITransaction* tra, int level) throw(); void (CLOOP_CARG *startAndSend)(IRequest* self, IStatus* status, ITransaction* tra, int level, unsigned msgType, unsigned length, const void* message) throw(); void (CLOOP_CARG *unwind)(IRequest* self, IStatus* status, int level) throw(); + void (CLOOP_CARG *deprecatedFree)(IRequest* self, IStatus* status) throw(); void (CLOOP_CARG *free)(IRequest* self, IStatus* status) throw(); }; @@ -2095,7 +2286,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; template void receive(StatusType* status, int level, unsigned msgType, unsigned length, void* message) { @@ -2139,8 +2330,26 @@ namespace Firebird StatusType::checkException(status); } + template void deprecatedFree(StatusType* status) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->deprecatedFree(this, status); + StatusType::checkException(status); + } + template void free(StatusType* status) { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IRequest", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedFree(status); + } + return; + } StatusType::clearException(status); static_cast(this->cloopVTable)->free(this, status); StatusType::checkException(status); @@ -2152,6 +2361,7 @@ namespace Firebird public: struct VTable : public IReferenceCounted::VTable { + void (CLOOP_CARG *deprecatedCancel)(IEvents* self, IStatus* status) throw(); void (CLOOP_CARG *cancel)(IEvents* self, IStatus* status) throw(); }; @@ -2166,10 +2376,28 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; + + template void deprecatedCancel(StatusType* status) + { + StatusType::clearException(status); + static_cast(this->cloopVTable)->deprecatedCancel(this, status); + StatusType::checkException(status); + } template void cancel(StatusType* status) { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IEvents", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedCancel(status); + } + return; + } StatusType::clearException(status); static_cast(this->cloopVTable)->cancel(this, status); StatusType::checkException(status); @@ -2197,14 +2425,16 @@ namespace Firebird IEvents* (CLOOP_CARG *queEvents)(IAttachment* self, IStatus* status, IEventCallback* callback, unsigned length, const unsigned char* events) throw(); void (CLOOP_CARG *cancelOperation)(IAttachment* self, IStatus* status, int option) throw(); void (CLOOP_CARG *ping)(IAttachment* self, IStatus* status) throw(); - void (CLOOP_CARG *detach)(IAttachment* self, IStatus* status) throw(); - void (CLOOP_CARG *dropDatabase)(IAttachment* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedDetach)(IAttachment* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedDropDatabase)(IAttachment* self, IStatus* status) throw(); unsigned (CLOOP_CARG *getIdleTimeout)(IAttachment* self, IStatus* status) throw(); void (CLOOP_CARG *setIdleTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw(); unsigned (CLOOP_CARG *getStatementTimeout)(IAttachment* self, IStatus* status) throw(); void (CLOOP_CARG *setStatementTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw(); IBatch* (CLOOP_CARG *createBatch)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) throw(); IReplicator* (CLOOP_CARG *createReplicator)(IAttachment* self, IStatus* status) throw(); + void (CLOOP_CARG *detach)(IAttachment* self, IStatus* status) throw(); + void (CLOOP_CARG *dropDatabase)(IAttachment* self, IStatus* status) throw(); }; protected: @@ -2218,7 +2448,7 @@ namespace Firebird } public: - static const unsigned VERSION = 4; + static const unsigned VERSION = 5; template void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) { @@ -2342,17 +2572,17 @@ namespace Firebird StatusType::checkException(status); } - template void detach(StatusType* status) + template void deprecatedDetach(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->detach(this, status); + static_cast(this->cloopVTable)->deprecatedDetach(this, status); StatusType::checkException(status); } - template void dropDatabase(StatusType* status) + template void deprecatedDropDatabase(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->dropDatabase(this, status); + static_cast(this->cloopVTable)->deprecatedDropDatabase(this, status); StatusType::checkException(status); } @@ -2437,6 +2667,42 @@ namespace Firebird StatusType::checkException(status); return ret; } + + template void detach(StatusType* status) + { + if (cloopVTable->version < 5) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 5); + StatusType::checkException(status); + } + else { + deprecatedDetach(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->detach(this, status); + StatusType::checkException(status); + } + + template void dropDatabase(StatusType* status) + { + if (cloopVTable->version < 5) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 5); + StatusType::checkException(status); + } + else { + deprecatedDropDatabase(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->dropDatabase(this, status); + StatusType::checkException(status); + } }; class IService : public IReferenceCounted @@ -2444,9 +2710,11 @@ namespace Firebird public: struct VTable : public IReferenceCounted::VTable { - void (CLOOP_CARG *detach)(IService* self, IStatus* status) throw(); + void (CLOOP_CARG *deprecatedDetach)(IService* self, IStatus* status) throw(); void (CLOOP_CARG *query)(IService* self, IStatus* status, unsigned sendLength, const unsigned char* sendItems, unsigned receiveLength, const unsigned char* receiveItems, unsigned bufferLength, unsigned char* buffer) throw(); void (CLOOP_CARG *start)(IService* self, IStatus* status, unsigned spbLength, const unsigned char* spb) throw(); + void (CLOOP_CARG *detach)(IService* self, IStatus* status) throw(); + void (CLOOP_CARG *cancel)(IService* self, IStatus* status) throw(); }; protected: @@ -2460,12 +2728,12 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 5; - template void detach(StatusType* status) + template void deprecatedDetach(StatusType* status) { StatusType::clearException(status); - static_cast(this->cloopVTable)->detach(this, status); + static_cast(this->cloopVTable)->deprecatedDetach(this, status); StatusType::checkException(status); } @@ -2482,6 +2750,37 @@ namespace Firebird static_cast(this->cloopVTable)->start(this, status, spbLength, spb); StatusType::checkException(status); } + + template void detach(StatusType* status) + { + if (cloopVTable->version < 4) + { + if (FB_UsedInYValve) { + StatusType::setVersionError(status, "IService", cloopVTable->version, 4); + StatusType::checkException(status); + } + else { + deprecatedDetach(status); + } + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->detach(this, status); + StatusType::checkException(status); + } + + template void cancel(StatusType* status) + { + if (cloopVTable->version < 5) + { + StatusType::setVersionError(status, "IService", cloopVTable->version, 5); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->cancel(this, status); + StatusType::checkException(status); + } }; class IProvider : public IPluginBase @@ -2657,6 +2956,7 @@ namespace Firebird static const int AUTH_SUCCESS = 0; static const int AUTH_MORE_DATA = 1; static const int AUTH_CONTINUE = 2; + static const int AUTH_SUCCESS_WITH_DATA = 3; }; class IWriter : public IVersioned @@ -3463,6 +3763,10 @@ namespace Firebird struct VTable : public IVersioned::VTable { unsigned (CLOOP_CARG *callback)(ICryptKeyCallback* self, unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) throw(); + void (CLOOP_CARG *dummy1)(ICryptKeyCallback* self, IStatus* status) throw(); + void (CLOOP_CARG *dummy2)(ICryptKeyCallback* self) throw(); + int (CLOOP_CARG *getHashLength)(ICryptKeyCallback* self, IStatus* status) throw(); + void (CLOOP_CARG *getHashData)(ICryptKeyCallback* self, IStatus* status, void* hash) throw(); }; protected: @@ -3476,13 +3780,62 @@ namespace Firebird } public: - static const unsigned VERSION = 2; + static const unsigned VERSION = 3; unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) { unsigned ret = static_cast(this->cloopVTable)->callback(this, dataLength, data, bufferLength, buffer); return ret; } + + template void dummy1(StatusType* status) + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "ICryptKeyCallback", cloopVTable->version, 3); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->dummy1(this, status); + StatusType::checkException(status); + } + + void dummy2() + { + if (cloopVTable->version < 3) + { + return; + } + static_cast(this->cloopVTable)->dummy2(this); + } + + template int getHashLength(StatusType* status) + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "ICryptKeyCallback", cloopVTable->version, 3); + StatusType::checkException(status); + return -1; + } + StatusType::clearException(status); + int ret = static_cast(this->cloopVTable)->getHashLength(this, status); + StatusType::checkException(status); + return ret; + } + + template void getHashData(StatusType* status, void* hash) + { + if (cloopVTable->version < 3) + { + StatusType::setVersionError(status, "ICryptKeyCallback", cloopVTable->version, 3); + StatusType::checkException(status); + return; + } + StatusType::clearException(status); + static_cast(this->cloopVTable)->getHashData(this, status, hash); + StatusType::checkException(status); + } }; class IKeyHolderPlugin : public IPluginBase @@ -4489,6 +4842,8 @@ namespace Firebird static const unsigned SPB_SEND = 7; static const unsigned SPB_RECEIVE = 8; static const unsigned SPB_RESPONSE = 9; + static const unsigned INFO_SEND = 10; + static const unsigned INFO_RESPONSE = 11; template void clear(StatusType* status) { @@ -5552,6 +5907,7 @@ namespace Firebird FB_BOOLEAN (CLOOP_CARG *trace_event_error)(ITracePlugin* self, ITraceConnection* connection, ITraceStatusVector* status, const char* function) throw(); FB_BOOLEAN (CLOOP_CARG *trace_event_sweep)(ITracePlugin* self, ITraceDatabaseConnection* connection, ITraceSweepInfo* sweep, unsigned sweep_state) throw(); FB_BOOLEAN (CLOOP_CARG *trace_func_execute)(ITracePlugin* self, ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceFunction* function, FB_BOOLEAN started, unsigned func_result) throw(); + FB_BOOLEAN (CLOOP_CARG *trace_dsql_restart)(ITracePlugin* self, ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceSQLStatement* statement, unsigned number) throw(); }; protected: @@ -5565,7 +5921,7 @@ namespace Firebird } public: - static const unsigned VERSION = 3; + static const unsigned VERSION = 4; static const unsigned RESULT_SUCCESS = 0; static const unsigned RESULT_FAILED = 1; @@ -5700,6 +6056,16 @@ namespace Firebird FB_BOOLEAN ret = static_cast(this->cloopVTable)->trace_func_execute(this, connection, transaction, function, started, func_result); return ret; } + + FB_BOOLEAN trace_dsql_restart(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceSQLStatement* statement, unsigned number) + { + if (cloopVTable->version < 4) + { + return true; + } + FB_BOOLEAN ret = static_cast(this->cloopVTable)->trace_dsql_restart(this, connection, transaction, statement, number); + return ret; + } }; class ITraceFactory : public IPluginBase @@ -8219,9 +8585,11 @@ namespace Firebird this->getInfo = &Name::cloopgetInfoDispatcher; this->getSegment = &Name::cloopgetSegmentDispatcher; this->putSegment = &Name::cloopputSegmentDispatcher; + this->deprecatedCancel = &Name::cloopdeprecatedCancelDispatcher; + this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher; + this->seek = &Name::cloopseekDispatcher; this->cancel = &Name::cloopcancelDispatcher; this->close = &Name::cloopcloseDispatcher; - this->seek = &Name::cloopseekDispatcher; } } vTable; @@ -8271,13 +8639,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopcancelDispatcher(IBlob* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedCancelDispatcher(IBlob* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::cancel(&status2); + static_cast(self)->Name::deprecatedCancel(&status2); } catch (...) { @@ -8285,13 +8653,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopcloseDispatcher(IBlob* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedCloseDispatcher(IBlob* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::close(&status2); + static_cast(self)->Name::deprecatedClose(&status2); } catch (...) { @@ -8314,6 +8682,34 @@ namespace Firebird } } + static void CLOOP_CARG cloopcancelDispatcher(IBlob* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::cancel(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopcloseDispatcher(IBlob* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::close(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -8356,9 +8752,11 @@ namespace Firebird virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0; virtual int getSegment(StatusType* status, unsigned bufferLength, void* buffer, unsigned* segmentLength) = 0; virtual void putSegment(StatusType* status, unsigned length, const void* buffer) = 0; + virtual void deprecatedCancel(StatusType* status) = 0; + virtual void deprecatedClose(StatusType* status) = 0; + virtual int seek(StatusType* status, int mode, int offset) = 0; virtual void cancel(StatusType* status) = 0; virtual void close(StatusType* status) = 0; - virtual int seek(StatusType* status, int mode, int offset) = 0; }; template @@ -8378,14 +8776,17 @@ namespace Firebird this->release = &Name::cloopreleaseDispatcher; this->getInfo = &Name::cloopgetInfoDispatcher; this->prepare = &Name::cloopprepareDispatcher; - this->commit = &Name::cloopcommitDispatcher; + this->deprecatedCommit = &Name::cloopdeprecatedCommitDispatcher; this->commitRetaining = &Name::cloopcommitRetainingDispatcher; - this->rollback = &Name::clooprollbackDispatcher; + this->deprecatedRollback = &Name::cloopdeprecatedRollbackDispatcher; this->rollbackRetaining = &Name::clooprollbackRetainingDispatcher; - this->disconnect = &Name::cloopdisconnectDispatcher; + this->deprecatedDisconnect = &Name::cloopdeprecatedDisconnectDispatcher; this->join = &Name::cloopjoinDispatcher; this->validate = &Name::cloopvalidateDispatcher; this->enterDtc = &Name::cloopenterDtcDispatcher; + this->commit = &Name::cloopcommitDispatcher; + this->rollback = &Name::clooprollbackDispatcher; + this->disconnect = &Name::cloopdisconnectDispatcher; } } vTable; @@ -8420,13 +8821,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopcommitDispatcher(ITransaction* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedCommitDispatcher(ITransaction* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::commit(&status2); + static_cast(self)->Name::deprecatedCommit(&status2); } catch (...) { @@ -8448,13 +8849,13 @@ namespace Firebird } } - static void CLOOP_CARG clooprollbackDispatcher(ITransaction* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedRollbackDispatcher(ITransaction* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::rollback(&status2); + static_cast(self)->Name::deprecatedRollback(&status2); } catch (...) { @@ -8476,13 +8877,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopdisconnectDispatcher(ITransaction* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedDisconnectDispatcher(ITransaction* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::disconnect(&status2); + static_cast(self)->Name::deprecatedDisconnect(&status2); } catch (...) { @@ -8505,33 +8906,75 @@ namespace Firebird } } - static ITransaction* CLOOP_CARG cloopvalidateDispatcher(ITransaction* self, IStatus* status, IAttachment* attachment) throw() + static ITransaction* CLOOP_CARG cloopvalidateDispatcher(ITransaction* self, IStatus* status, IAttachment* attachment) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::validate(&status2, attachment); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + + static ITransaction* CLOOP_CARG cloopenterDtcDispatcher(ITransaction* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::enterDtc(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + + static void CLOOP_CARG cloopcommitDispatcher(ITransaction* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::commit(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG clooprollbackDispatcher(ITransaction* self, IStatus* status) throw() { StatusType status2(status); try { - return static_cast(self)->Name::validate(&status2, attachment); + static_cast(self)->Name::rollback(&status2); } catch (...) { StatusType::catchException(&status2); - return static_cast(0); } } - static ITransaction* CLOOP_CARG cloopenterDtcDispatcher(ITransaction* self, IStatus* status) throw() + static void CLOOP_CARG cloopdisconnectDispatcher(ITransaction* self, IStatus* status) throw() { StatusType status2(status); try { - return static_cast(self)->Name::enterDtc(&status2); + static_cast(self)->Name::disconnect(&status2); } catch (...) { StatusType::catchException(&status2); - return static_cast(0); } } @@ -8576,14 +9019,17 @@ namespace Firebird virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0; virtual void prepare(StatusType* status, unsigned msgLength, const unsigned char* message) = 0; - virtual void commit(StatusType* status) = 0; + virtual void deprecatedCommit(StatusType* status) = 0; virtual void commitRetaining(StatusType* status) = 0; - virtual void rollback(StatusType* status) = 0; + virtual void deprecatedRollback(StatusType* status) = 0; virtual void rollbackRetaining(StatusType* status) = 0; - virtual void disconnect(StatusType* status) = 0; + virtual void deprecatedDisconnect(StatusType* status) = 0; virtual ITransaction* join(StatusType* status, ITransaction* transaction) = 0; virtual ITransaction* validate(StatusType* status, IAttachment* attachment) = 0; virtual ITransaction* enterDtc(StatusType* status) = 0; + virtual void commit(StatusType* status) = 0; + virtual void rollback(StatusType* status) = 0; + virtual void disconnect(StatusType* status) = 0; }; template @@ -9249,8 +9695,9 @@ namespace Firebird this->isEof = &Name::cloopisEofDispatcher; this->isBof = &Name::cloopisBofDispatcher; this->getMetadata = &Name::cloopgetMetadataDispatcher; - this->close = &Name::cloopcloseDispatcher; + this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher; this->setDelayedOutputFormat = &Name::cloopsetDelayedOutputFormatDispatcher; + this->close = &Name::cloopcloseDispatcher; } } vTable; @@ -9392,13 +9839,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopcloseDispatcher(IResultSet* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedCloseDispatcher(IResultSet* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::close(&status2); + static_cast(self)->Name::deprecatedClose(&status2); } catch (...) { @@ -9420,6 +9867,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopcloseDispatcher(IResultSet* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::close(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -9468,8 +9929,9 @@ namespace Firebird virtual FB_BOOLEAN isEof(StatusType* status) = 0; virtual FB_BOOLEAN isBof(StatusType* status) = 0; virtual IMessageMetadata* getMetadata(StatusType* status) = 0; - virtual void close(StatusType* status) = 0; + virtual void deprecatedClose(StatusType* status) = 0; virtual void setDelayedOutputFormat(StatusType* status, IMessageMetadata* format) = 0; + virtual void close(StatusType* status) = 0; }; template @@ -9496,11 +9958,12 @@ namespace Firebird this->execute = &Name::cloopexecuteDispatcher; this->openCursor = &Name::cloopopenCursorDispatcher; this->setCursorName = &Name::cloopsetCursorNameDispatcher; - this->free = &Name::cloopfreeDispatcher; + this->deprecatedFree = &Name::cloopdeprecatedFreeDispatcher; this->getFlags = &Name::cloopgetFlagsDispatcher; this->getTimeout = &Name::cloopgetTimeoutDispatcher; this->setTimeout = &Name::cloopsetTimeoutDispatcher; this->createBatch = &Name::cloopcreateBatchDispatcher; + this->free = &Name::cloopfreeDispatcher; } } vTable; @@ -9640,13 +10103,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopfreeDispatcher(IStatement* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedFreeDispatcher(IStatement* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::free(&status2); + static_cast(self)->Name::deprecatedFree(&status2); } catch (...) { @@ -9713,6 +10176,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopfreeDispatcher(IStatement* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::free(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -9761,11 +10238,12 @@ namespace Firebird virtual ITransaction* execute(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, void* outBuffer) = 0; virtual IResultSet* openCursor(StatusType* status, ITransaction* transaction, IMessageMetadata* inMetadata, void* inBuffer, IMessageMetadata* outMetadata, unsigned flags) = 0; virtual void setCursorName(StatusType* status, const char* name) = 0; - virtual void free(StatusType* status) = 0; + virtual void deprecatedFree(StatusType* status) = 0; virtual unsigned getFlags(StatusType* status) = 0; virtual unsigned getTimeout(StatusType* status) = 0; virtual void setTimeout(StatusType* status, unsigned timeOut) = 0; virtual IBatch* createBatch(StatusType* status, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) = 0; + virtual void free(StatusType* status) = 0; }; template @@ -9793,7 +10271,9 @@ namespace Firebird this->getBlobAlignment = &Name::cloopgetBlobAlignmentDispatcher; this->getMetadata = &Name::cloopgetMetadataDispatcher; this->setDefaultBpb = &Name::cloopsetDefaultBpbDispatcher; + this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher; this->close = &Name::cloopcloseDispatcher; + this->getInfo = &Name::cloopgetInfoDispatcher; } } vTable; @@ -9943,6 +10423,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopdeprecatedCloseDispatcher(IBatch* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::deprecatedClose(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopcloseDispatcher(IBatch* self, IStatus* status) throw() { StatusType status2(status); @@ -9957,6 +10451,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopgetInfoDispatcher(IBatch* self, IStatus* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::getInfo(&status2, itemsLength, items, bufferLength, buffer); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -10006,7 +10514,9 @@ namespace Firebird virtual unsigned getBlobAlignment(StatusType* status) = 0; virtual IMessageMetadata* getMetadata(StatusType* status) = 0; virtual void setDefaultBpb(StatusType* status, unsigned parLength, const unsigned char* par) = 0; + virtual void deprecatedClose(StatusType* status) = 0; virtual void close(StatusType* status) = 0; + virtual void getInfo(StatusType* status, unsigned itemsLength, const unsigned char* items, unsigned bufferLength, unsigned char* buffer) = 0; }; template @@ -10140,6 +10650,7 @@ namespace Firebird this->addRef = &Name::cloopaddRefDispatcher; this->release = &Name::cloopreleaseDispatcher; this->process = &Name::cloopprocessDispatcher; + this->deprecatedClose = &Name::cloopdeprecatedCloseDispatcher; this->close = &Name::cloopcloseDispatcher; } } vTable; @@ -10161,6 +10672,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopdeprecatedCloseDispatcher(IReplicator* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::deprecatedClose(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopcloseDispatcher(IReplicator* self, IStatus* status) throw() { StatusType status2(status); @@ -10215,6 +10740,7 @@ namespace Firebird } virtual void process(StatusType* status, unsigned length, const unsigned char* data) = 0; + virtual void deprecatedClose(StatusType* status) = 0; virtual void close(StatusType* status) = 0; }; @@ -10239,6 +10765,7 @@ namespace Firebird this->start = &Name::cloopstartDispatcher; this->startAndSend = &Name::cloopstartAndSendDispatcher; this->unwind = &Name::cloopunwindDispatcher; + this->deprecatedFree = &Name::cloopdeprecatedFreeDispatcher; this->free = &Name::cloopfreeDispatcher; } } vTable; @@ -10330,6 +10857,20 @@ namespace Firebird } } + static void CLOOP_CARG cloopdeprecatedFreeDispatcher(IRequest* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::deprecatedFree(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopfreeDispatcher(IRequest* self, IStatus* status) throw() { StatusType status2(status); @@ -10389,6 +10930,7 @@ namespace Firebird virtual void start(StatusType* status, ITransaction* tra, int level) = 0; virtual void startAndSend(StatusType* status, ITransaction* tra, int level, unsigned msgType, unsigned length, const void* message) = 0; virtual void unwind(StatusType* status, int level) = 0; + virtual void deprecatedFree(StatusType* status) = 0; virtual void free(StatusType* status) = 0; }; @@ -10407,6 +10949,7 @@ namespace Firebird this->version = Base::VERSION; this->addRef = &Name::cloopaddRefDispatcher; this->release = &Name::cloopreleaseDispatcher; + this->deprecatedCancel = &Name::cloopdeprecatedCancelDispatcher; this->cancel = &Name::cloopcancelDispatcher; } } vTable; @@ -10414,6 +10957,20 @@ namespace Firebird this->cloopVTable = &vTable; } + static void CLOOP_CARG cloopdeprecatedCancelDispatcher(IEvents* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::deprecatedCancel(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopcancelDispatcher(IEvents* self, IStatus* status) throw() { StatusType status2(status); @@ -10467,6 +11024,7 @@ namespace Firebird { } + virtual void deprecatedCancel(StatusType* status) = 0; virtual void cancel(StatusType* status) = 0; }; @@ -10501,14 +11059,16 @@ namespace Firebird this->queEvents = &Name::cloopqueEventsDispatcher; this->cancelOperation = &Name::cloopcancelOperationDispatcher; this->ping = &Name::clooppingDispatcher; - this->detach = &Name::cloopdetachDispatcher; - this->dropDatabase = &Name::cloopdropDatabaseDispatcher; + this->deprecatedDetach = &Name::cloopdeprecatedDetachDispatcher; + this->deprecatedDropDatabase = &Name::cloopdeprecatedDropDatabaseDispatcher; this->getIdleTimeout = &Name::cloopgetIdleTimeoutDispatcher; this->setIdleTimeout = &Name::cloopsetIdleTimeoutDispatcher; this->getStatementTimeout = &Name::cloopgetStatementTimeoutDispatcher; this->setStatementTimeout = &Name::cloopsetStatementTimeoutDispatcher; this->createBatch = &Name::cloopcreateBatchDispatcher; this->createReplicator = &Name::cloopcreateReplicatorDispatcher; + this->detach = &Name::cloopdetachDispatcher; + this->dropDatabase = &Name::cloopdropDatabaseDispatcher; } } vTable; @@ -10749,13 +11309,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopdetachDispatcher(IAttachment* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedDetachDispatcher(IAttachment* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::detach(&status2); + static_cast(self)->Name::deprecatedDetach(&status2); } catch (...) { @@ -10763,13 +11323,13 @@ namespace Firebird } } - static void CLOOP_CARG cloopdropDatabaseDispatcher(IAttachment* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedDropDatabaseDispatcher(IAttachment* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::dropDatabase(&status2); + static_cast(self)->Name::deprecatedDropDatabase(&status2); } catch (...) { @@ -10865,6 +11425,34 @@ namespace Firebird } } + static void CLOOP_CARG cloopdetachDispatcher(IAttachment* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::detach(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopdropDatabaseDispatcher(IAttachment* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::dropDatabase(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -10920,14 +11508,16 @@ namespace Firebird virtual IEvents* queEvents(StatusType* status, IEventCallback* callback, unsigned length, const unsigned char* events) = 0; virtual void cancelOperation(StatusType* status, int option) = 0; virtual void ping(StatusType* status) = 0; - virtual void detach(StatusType* status) = 0; - virtual void dropDatabase(StatusType* status) = 0; + virtual void deprecatedDetach(StatusType* status) = 0; + virtual void deprecatedDropDatabase(StatusType* status) = 0; virtual unsigned getIdleTimeout(StatusType* status) = 0; virtual void setIdleTimeout(StatusType* status, unsigned timeOut) = 0; virtual unsigned getStatementTimeout(StatusType* status) = 0; virtual void setStatementTimeout(StatusType* status, unsigned timeOut) = 0; virtual IBatch* createBatch(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) = 0; virtual IReplicator* createReplicator(StatusType* status) = 0; + virtual void detach(StatusType* status) = 0; + virtual void dropDatabase(StatusType* status) = 0; }; template @@ -10945,22 +11535,24 @@ namespace Firebird this->version = Base::VERSION; this->addRef = &Name::cloopaddRefDispatcher; this->release = &Name::cloopreleaseDispatcher; - this->detach = &Name::cloopdetachDispatcher; + this->deprecatedDetach = &Name::cloopdeprecatedDetachDispatcher; this->query = &Name::cloopqueryDispatcher; this->start = &Name::cloopstartDispatcher; + this->detach = &Name::cloopdetachDispatcher; + this->cancel = &Name::cloopcancelDispatcher; } } vTable; this->cloopVTable = &vTable; } - static void CLOOP_CARG cloopdetachDispatcher(IService* self, IStatus* status) throw() + static void CLOOP_CARG cloopdeprecatedDetachDispatcher(IService* self, IStatus* status) throw() { StatusType status2(status); try { - static_cast(self)->Name::detach(&status2); + static_cast(self)->Name::deprecatedDetach(&status2); } catch (...) { @@ -10996,6 +11588,34 @@ namespace Firebird } } + static void CLOOP_CARG cloopdetachDispatcher(IService* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::detach(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopcancelDispatcher(IService* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::cancel(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -11035,9 +11655,11 @@ namespace Firebird { } - virtual void detach(StatusType* status) = 0; + virtual void deprecatedDetach(StatusType* status) = 0; virtual void query(StatusType* status, unsigned sendLength, const unsigned char* sendItems, unsigned receiveLength, const unsigned char* receiveItems, unsigned bufferLength, unsigned char* buffer) = 0; virtual void start(StatusType* status, unsigned spbLength, const unsigned char* spb) = 0; + virtual void detach(StatusType* status) = 0; + virtual void cancel(StatusType* status) = 0; }; template @@ -13241,6 +13863,10 @@ namespace Firebird { this->version = Base::VERSION; this->callback = &Name::cloopcallbackDispatcher; + this->dummy1 = &Name::cloopdummy1Dispatcher; + this->dummy2 = &Name::cloopdummy2Dispatcher; + this->getHashLength = &Name::cloopgetHashLengthDispatcher; + this->getHashData = &Name::cloopgetHashDataDispatcher; } } vTable; @@ -13259,6 +13885,61 @@ namespace Firebird return static_cast(0); } } + + static void CLOOP_CARG cloopdummy1Dispatcher(ICryptKeyCallback* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::dummy1(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + } + } + + static void CLOOP_CARG cloopdummy2Dispatcher(ICryptKeyCallback* self) throw() + { + try + { + static_cast(self)->Name::dummy2(); + } + catch (...) + { + StatusType::catchException(0); + } + } + + static int CLOOP_CARG cloopgetHashLengthDispatcher(ICryptKeyCallback* self, IStatus* status) throw() + { + StatusType status2(status); + + try + { + return static_cast(self)->Name::getHashLength(&status2); + } + catch (...) + { + StatusType::catchException(&status2); + return static_cast(0); + } + } + + static void CLOOP_CARG cloopgetHashDataDispatcher(ICryptKeyCallback* self, IStatus* status, void* hash) throw() + { + StatusType status2(status); + + try + { + static_cast(self)->Name::getHashData(&status2, hash); + } + catch (...) + { + StatusType::catchException(&status2); + } + } }; template > > @@ -13275,6 +13956,14 @@ namespace Firebird } virtual unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer) = 0; + virtual void dummy1(StatusType* status) + { + } + virtual void dummy2() + { + } + virtual int getHashLength(StatusType* status) = 0; + virtual void getHashData(StatusType* status, void* hash) = 0; }; template @@ -17568,6 +18257,7 @@ namespace Firebird this->trace_event_error = &Name::clooptrace_event_errorDispatcher; this->trace_event_sweep = &Name::clooptrace_event_sweepDispatcher; this->trace_func_execute = &Name::clooptrace_func_executeDispatcher; + this->trace_dsql_restart = &Name::clooptrace_dsql_restartDispatcher; } } vTable; @@ -17847,6 +18537,19 @@ namespace Firebird } } + static FB_BOOLEAN CLOOP_CARG clooptrace_dsql_restartDispatcher(ITracePlugin* self, ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceSQLStatement* statement, unsigned number) throw() + { + try + { + return static_cast(self)->Name::trace_dsql_restart(connection, transaction, statement, number); + } + catch (...) + { + StatusType::catchException(0); + return static_cast(0); + } + } + static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw() { try @@ -17907,6 +18610,7 @@ namespace Firebird virtual FB_BOOLEAN trace_event_error(ITraceConnection* connection, ITraceStatusVector* status, const char* function) = 0; virtual FB_BOOLEAN trace_event_sweep(ITraceDatabaseConnection* connection, ITraceSweepInfo* sweep, unsigned sweep_state) = 0; virtual FB_BOOLEAN trace_func_execute(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceFunction* function, FB_BOOLEAN started, unsigned func_result) = 0; + virtual FB_BOOLEAN trace_dsql_restart(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceSQLStatement* statement, unsigned number) = 0; }; template diff --git a/src/include/firebird/Interface.h b/src/include/firebird/Interface.h index 9fdc60790c7..5af60dca355 100644 --- a/src/include/firebird/Interface.h +++ b/src/include/firebird/Interface.h @@ -47,7 +47,7 @@ struct TraceCounts { // Per-table performance counters, must correspond to RuntimeStatistics::StatType // between RECORD_FIRST_ITEM and RECORD_LAST_ITEM - enum RecordCounters + enum RecordCounters { SEQ_READS = 0, IDX_READS, @@ -106,6 +106,9 @@ inline const intptr_t* stubError() } // namespace Firebird +#ifndef FB_UsedInYValve +#define FB_UsedInYValve false +#endif #include "IdlFbInterfaces.h" @@ -222,6 +225,11 @@ namespace Firebird return !hasData(); } + bool isSuccess() const + { + return isEmpty(); + } + static void setVersionError(IStatus* status, const char* interfaceName, unsigned currentVersion, unsigned expectedVersion) { diff --git a/src/include/firebird/Message.h b/src/include/firebird/Message.h index 0b40b13f7d3..02de5f09ba4 100644 --- a/src/include/firebird/Message.h +++ b/src/include/firebird/Message.h @@ -131,6 +131,11 @@ builder->setLength(status, index, sizeof(ISC_INT64)); \ builder->setScale(status, index, scale); +#define FB__META_FB_SCALED_INT128(scale) \ + builder->setType(status, index, SQL_INT128); \ + builder->setLength(status, index, sizeof(FB_I128)); \ + builder->setScale(status, index, scale); + #define FB__META_FB_FLOAT \ builder->setType(status, index, SQL_FLOAT); \ builder->setLength(status, index, sizeof(float)); @@ -204,15 +209,18 @@ #define FB__META_FB_SMALLINT FB__META_FB_SCALED_SMALLINT(0) #define FB__META_FB_INTEGER FB__META_FB_SCALED_INTEGER(0) #define FB__META_FB_BIGINT FB__META_FB_SCALED_BIGINT(0) +#define FB__META_FB_INT128 FB__META_FB_SCALED_INT128(0) // Types - struct #define FB__TYPE_FB_SCALED_SMALLINT(x) ISC_SHORT #define FB__TYPE_FB_SCALED_INTEGER(x) ISC_LONG #define FB__TYPE_FB_SCALED_BIGINT(x) FB__INT64_ALIGNAS ISC_INT64 +#define FB__TYPE_FB_SCALED_INT128(x) FB__INT64_ALIGNAS FB_I128 #define FB__TYPE_FB_SMALLINT ISC_SHORT #define FB__TYPE_FB_INTEGER ISC_LONG #define FB__TYPE_FB_BIGINT FB__INT64_ALIGNAS ISC_INT64 +#define FB__TYPE_FB_INT128 FB__INT64_ALIGNAS FB_I128 #define FB__TYPE_FB_FLOAT float #define FB__TYPE_FB_DOUBLE double #define FB__TYPE_FB_DECFLOAT16 FB__INT64_ALIGNAS FB_DEC16 diff --git a/src/include/firebird/TimeZones.h b/src/include/firebird/TimeZones.h index 3d0b5621be0..a3bcd858a0b 100644 --- a/src/include/firebird/TimeZones.h +++ b/src/include/firebird/TimeZones.h @@ -637,5 +637,9 @@ #define fb_tzid_zulu 64904 /* Zulu */ #define fb_tzid_america_nuuk 64903 /* America/Nuuk */ #define fb_tzid_asia_qostanay 64902 /* Asia/Qostanay */ +#define fb_tzid_pacific_kanton 64901 /* Pacific/Kanton */ +#define fb_tzid_europe_kyiv 64900 /* Europe/Kyiv */ +#define fb_tzid_america_ciudad_juarez 64899 /* America/Ciudad_Juarez */ +#define fb_tzid_america_coyhaique 64898 /* America/Coyhaique */ #endif /* FIREBIRD_TIME_ZONES_H */ diff --git a/src/include/firebird/UdrCppEngine.h b/src/include/firebird/UdrCppEngine.h index 26ef5a0e90e..d9aac7e5d3e 100644 --- a/src/include/firebird/UdrCppEngine.h +++ b/src/include/firebird/UdrCppEngine.h @@ -43,7 +43,7 @@ } \ } \ \ - extern "C" FB_BOOLEAN* FB_UDR_PLUGIN_ENTRY_POINT(::Firebird::IStatus* status, \ + extern "C" FB_DLL_EXPORT FB_BOOLEAN* FB_UDR_PLUGIN_ENTRY_POINT(::Firebird::IStatus* status, \ FB_BOOLEAN* theirUnloadFlag, ::Firebird::IUdrPlugin* udrPlugin) \ { \ ::Firebird::Udr::FactoryRegistration::finish(status, udrPlugin); \ diff --git a/src/include/firebird/impl/consts_pub.h b/src/include/firebird/impl/consts_pub.h index 75c50897554..828e96b0f83 100644 --- a/src/include/firebird/impl/consts_pub.h +++ b/src/include/firebird/impl/consts_pub.h @@ -128,6 +128,7 @@ #define isc_dpb_set_bind 93 #define isc_dpb_decfloat_round 94 #define isc_dpb_decfloat_traps 95 +#define isc_dpb_clear_map 96 /**************************************************/ @@ -620,6 +621,9 @@ #define isc_spb_nbk_file 6 #define isc_spb_nbk_direct 7 #define isc_spb_nbk_guid 8 +#define isc_spb_nbk_clean_history 9 +#define isc_spb_nbk_keep_days 10 +#define isc_spb_nbk_keep_rows 11 #define isc_spb_nbk_no_triggers 0x01 #define isc_spb_nbk_inplace 0x02 #define isc_spb_nbk_sequence 0x04 diff --git a/src/include/firebird/impl/inf_pub.h b/src/include/firebird/impl/inf_pub.h index c0566b1be95..ca4240fb657 100644 --- a/src/include/firebird/impl/inf_pub.h +++ b/src/include/firebird/impl/inf_pub.h @@ -173,6 +173,9 @@ enum db_info_types fb_info_replica_mode = 146, + fb_info_username = 147, + fb_info_sqlrole = 148, + isc_info_db_last_value /* Leave this LAST! */ }; @@ -475,6 +478,8 @@ enum info_db_provider #define isc_info_sql_stmt_timeout_user 28 #define isc_info_sql_stmt_timeout_run 29 #define isc_info_sql_stmt_blob_align 30 +#define isc_info_sql_exec_path_blr_bytes 31 +#define isc_info_sql_exec_path_blr_text 32 /*********************************/ /* SQL information return values */ diff --git a/src/include/gen/Firebird.pas b/src/include/gen/Firebird.pas index ba63ae2f881..9b065750ce2 100644 --- a/src/include/gen/Firebird.pas +++ b/src/include/gen/Firebird.pas @@ -121,6 +121,8 @@ FbException = class(Exception) class procedure checkException(status: IStatus); class procedure catchException(status: IStatus; e: Exception); + class procedure setVersionError(status: IStatus; interfaceName: AnsiString; + currentVersion, expectedVersion: NativeInt); private status: IStatus; @@ -276,19 +278,24 @@ ISC_TIMESTAMP_TZ_EX = record IBlob_getInfoPtr = procedure(this: IBlob; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; IBlob_getSegmentPtr = function(this: IBlob; status: IStatus; bufferLength: Cardinal; buffer: Pointer; segmentLength: CardinalPtr): Integer; cdecl; IBlob_putSegmentPtr = procedure(this: IBlob; status: IStatus; length: Cardinal; buffer: Pointer); cdecl; + IBlob_deprecatedCancelPtr = procedure(this: IBlob; status: IStatus); cdecl; + IBlob_deprecatedClosePtr = procedure(this: IBlob; status: IStatus); cdecl; + IBlob_seekPtr = function(this: IBlob; status: IStatus; mode: Integer; offset: Integer): Integer; cdecl; IBlob_cancelPtr = procedure(this: IBlob; status: IStatus); cdecl; IBlob_closePtr = procedure(this: IBlob; status: IStatus); cdecl; - IBlob_seekPtr = function(this: IBlob; status: IStatus; mode: Integer; offset: Integer): Integer; cdecl; ITransaction_getInfoPtr = procedure(this: ITransaction; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; ITransaction_preparePtr = procedure(this: ITransaction; status: IStatus; msgLength: Cardinal; message: BytePtr); cdecl; - ITransaction_commitPtr = procedure(this: ITransaction; status: IStatus); cdecl; + ITransaction_deprecatedCommitPtr = procedure(this: ITransaction; status: IStatus); cdecl; ITransaction_commitRetainingPtr = procedure(this: ITransaction; status: IStatus); cdecl; - ITransaction_rollbackPtr = procedure(this: ITransaction; status: IStatus); cdecl; + ITransaction_deprecatedRollbackPtr = procedure(this: ITransaction; status: IStatus); cdecl; ITransaction_rollbackRetainingPtr = procedure(this: ITransaction; status: IStatus); cdecl; - ITransaction_disconnectPtr = procedure(this: ITransaction; status: IStatus); cdecl; + ITransaction_deprecatedDisconnectPtr = procedure(this: ITransaction; status: IStatus); cdecl; ITransaction_joinPtr = function(this: ITransaction; status: IStatus; transaction: ITransaction): ITransaction; cdecl; ITransaction_validatePtr = function(this: ITransaction; status: IStatus; attachment: IAttachment): ITransaction; cdecl; ITransaction_enterDtcPtr = function(this: ITransaction; status: IStatus): ITransaction; cdecl; + ITransaction_commitPtr = procedure(this: ITransaction; status: IStatus); cdecl; + ITransaction_rollbackPtr = procedure(this: ITransaction; status: IStatus); cdecl; + ITransaction_disconnectPtr = procedure(this: ITransaction; status: IStatus); cdecl; IMessageMetadata_getCountPtr = function(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; IMessageMetadata_getFieldPtr = function(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; IMessageMetadata_getRelationPtr = function(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; @@ -329,8 +336,9 @@ ISC_TIMESTAMP_TZ_EX = record IResultSet_isEofPtr = function(this: IResultSet; status: IStatus): Boolean; cdecl; IResultSet_isBofPtr = function(this: IResultSet; status: IStatus): Boolean; cdecl; IResultSet_getMetadataPtr = function(this: IResultSet; status: IStatus): IMessageMetadata; cdecl; - IResultSet_closePtr = procedure(this: IResultSet; status: IStatus); cdecl; + IResultSet_deprecatedClosePtr = procedure(this: IResultSet; status: IStatus); cdecl; IResultSet_setDelayedOutputFormatPtr = procedure(this: IResultSet; status: IStatus; format: IMessageMetadata); cdecl; + IResultSet_closePtr = procedure(this: IResultSet; status: IStatus); cdecl; IStatement_getInfoPtr = procedure(this: IStatement; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; IStatement_getTypePtr = function(this: IStatement; status: IStatus): Cardinal; cdecl; IStatement_getPlanPtr = function(this: IStatement; status: IStatus; detailed: Boolean): PAnsiChar; cdecl; @@ -340,11 +348,12 @@ ISC_TIMESTAMP_TZ_EX = record IStatement_executePtr = function(this: IStatement; status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; outBuffer: Pointer): ITransaction; cdecl; IStatement_openCursorPtr = function(this: IStatement; status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; flags: Cardinal): IResultSet; cdecl; IStatement_setCursorNamePtr = procedure(this: IStatement; status: IStatus; name: PAnsiChar); cdecl; - IStatement_freePtr = procedure(this: IStatement; status: IStatus); cdecl; + IStatement_deprecatedFreePtr = procedure(this: IStatement; status: IStatus); cdecl; IStatement_getFlagsPtr = function(this: IStatement; status: IStatus): Cardinal; cdecl; IStatement_getTimeoutPtr = function(this: IStatement; status: IStatus): Cardinal; cdecl; IStatement_setTimeoutPtr = procedure(this: IStatement; status: IStatus; timeOut: Cardinal); cdecl; IStatement_createBatchPtr = function(this: IStatement; status: IStatus; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; cdecl; + IStatement_freePtr = procedure(this: IStatement; status: IStatus); cdecl; IBatch_addPtr = procedure(this: IBatch; status: IStatus; count: Cardinal; inBuffer: Pointer); cdecl; IBatch_addBlobPtr = procedure(this: IBatch; status: IStatus; length: Cardinal; inBuffer: Pointer; blobId: ISC_QUADPtr; parLength: Cardinal; par: BytePtr); cdecl; IBatch_appendBlobDataPtr = procedure(this: IBatch; status: IStatus; length: Cardinal; inBuffer: Pointer); cdecl; @@ -355,12 +364,15 @@ ISC_TIMESTAMP_TZ_EX = record IBatch_getBlobAlignmentPtr = function(this: IBatch; status: IStatus): Cardinal; cdecl; IBatch_getMetadataPtr = function(this: IBatch; status: IStatus): IMessageMetadata; cdecl; IBatch_setDefaultBpbPtr = procedure(this: IBatch; status: IStatus; parLength: Cardinal; par: BytePtr); cdecl; + IBatch_deprecatedClosePtr = procedure(this: IBatch; status: IStatus); cdecl; IBatch_closePtr = procedure(this: IBatch; status: IStatus); cdecl; + IBatch_getInfoPtr = procedure(this: IBatch; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; IBatchCompletionState_getSizePtr = function(this: IBatchCompletionState; status: IStatus): Cardinal; cdecl; IBatchCompletionState_getStatePtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Integer; cdecl; IBatchCompletionState_findErrorPtr = function(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Cardinal; cdecl; IBatchCompletionState_getStatusPtr = procedure(this: IBatchCompletionState; status: IStatus; to_: IStatus; pos: Cardinal); cdecl; IReplicator_processPtr = procedure(this: IReplicator; status: IStatus; length: Cardinal; data: BytePtr); cdecl; + IReplicator_deprecatedClosePtr = procedure(this: IReplicator; status: IStatus); cdecl; IReplicator_closePtr = procedure(this: IReplicator; status: IStatus); cdecl; IRequest_receivePtr = procedure(this: IRequest; status: IStatus; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); cdecl; IRequest_sendPtr = procedure(this: IRequest; status: IStatus; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); cdecl; @@ -368,7 +380,9 @@ ISC_TIMESTAMP_TZ_EX = record IRequest_startPtr = procedure(this: IRequest; status: IStatus; tra: ITransaction; level: Integer); cdecl; IRequest_startAndSendPtr = procedure(this: IRequest; status: IStatus; tra: ITransaction; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); cdecl; IRequest_unwindPtr = procedure(this: IRequest; status: IStatus; level: Integer); cdecl; + IRequest_deprecatedFreePtr = procedure(this: IRequest; status: IStatus); cdecl; IRequest_freePtr = procedure(this: IRequest; status: IStatus); cdecl; + IEvents_deprecatedCancelPtr = procedure(this: IEvents; status: IStatus); cdecl; IEvents_cancelPtr = procedure(this: IEvents; status: IStatus); cdecl; IAttachment_getInfoPtr = procedure(this: IAttachment; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; IAttachment_startTransactionPtr = function(this: IAttachment; status: IStatus; tpbLength: Cardinal; tpb: BytePtr): ITransaction; cdecl; @@ -386,17 +400,21 @@ ISC_TIMESTAMP_TZ_EX = record IAttachment_queEventsPtr = function(this: IAttachment; status: IStatus; callback: IEventCallback; length: Cardinal; events: BytePtr): IEvents; cdecl; IAttachment_cancelOperationPtr = procedure(this: IAttachment; status: IStatus; option: Integer); cdecl; IAttachment_pingPtr = procedure(this: IAttachment; status: IStatus); cdecl; - IAttachment_detachPtr = procedure(this: IAttachment; status: IStatus); cdecl; - IAttachment_dropDatabasePtr = procedure(this: IAttachment; status: IStatus); cdecl; + IAttachment_deprecatedDetachPtr = procedure(this: IAttachment; status: IStatus); cdecl; + IAttachment_deprecatedDropDatabasePtr = procedure(this: IAttachment; status: IStatus); cdecl; IAttachment_getIdleTimeoutPtr = function(this: IAttachment; status: IStatus): Cardinal; cdecl; IAttachment_setIdleTimeoutPtr = procedure(this: IAttachment; status: IStatus; timeOut: Cardinal); cdecl; IAttachment_getStatementTimeoutPtr = function(this: IAttachment; status: IStatus): Cardinal; cdecl; IAttachment_setStatementTimeoutPtr = procedure(this: IAttachment; status: IStatus; timeOut: Cardinal); cdecl; IAttachment_createBatchPtr = function(this: IAttachment; status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; cdecl; IAttachment_createReplicatorPtr = function(this: IAttachment; status: IStatus): IReplicator; cdecl; - IService_detachPtr = procedure(this: IService; status: IStatus); cdecl; + IAttachment_detachPtr = procedure(this: IAttachment; status: IStatus); cdecl; + IAttachment_dropDatabasePtr = procedure(this: IAttachment; status: IStatus); cdecl; + IService_deprecatedDetachPtr = procedure(this: IService; status: IStatus); cdecl; IService_queryPtr = procedure(this: IService; status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; IService_startPtr = procedure(this: IService; status: IStatus; spbLength: Cardinal; spb: BytePtr); cdecl; + IService_detachPtr = procedure(this: IService; status: IStatus); cdecl; + IService_cancelPtr = procedure(this: IService; status: IStatus); cdecl; IProvider_attachDatabasePtr = function(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl; IProvider_createDatabasePtr = function(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl; IProvider_attachServiceManagerPtr = function(this: IProvider; status: IStatus; service: PAnsiChar; spbLength: Cardinal; spb: BytePtr): IService; cdecl; @@ -468,6 +486,10 @@ ISC_TIMESTAMP_TZ_EX = record IWireCryptPlugin_getSpecificDataPtr = function(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: CardinalPtr): BytePtr; cdecl; IWireCryptPlugin_setSpecificDataPtr = procedure(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: Cardinal; data: BytePtr); cdecl; ICryptKeyCallback_callbackPtr = function(this: ICryptKeyCallback; dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; cdecl; + ICryptKeyCallback_dummy1Ptr = procedure(this: ICryptKeyCallback; status: IStatus); cdecl; + ICryptKeyCallback_dummy2Ptr = procedure(this: ICryptKeyCallback); cdecl; + ICryptKeyCallback_getHashLengthPtr = function(this: ICryptKeyCallback; status: IStatus): Integer; cdecl; + ICryptKeyCallback_getHashDataPtr = procedure(this: ICryptKeyCallback; status: IStatus; hash: Pointer); cdecl; IKeyHolderPlugin_keyCallbackPtr = function(this: IKeyHolderPlugin; status: IStatus; callback: ICryptKeyCallback): Integer; cdecl; IKeyHolderPlugin_keyHandlePtr = function(this: IKeyHolderPlugin; status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; cdecl; IKeyHolderPlugin_useOnlyOwnKeysPtr = function(this: IKeyHolderPlugin; status: IStatus): Boolean; cdecl; @@ -647,6 +669,7 @@ ISC_TIMESTAMP_TZ_EX = record ITracePlugin_trace_event_errorPtr = function(this: ITracePlugin; connection: ITraceConnection; status: ITraceStatusVector; function_: PAnsiChar): Boolean; cdecl; ITracePlugin_trace_event_sweepPtr = function(this: ITracePlugin; connection: ITraceDatabaseConnection; sweep: ITraceSweepInfo; sweep_state: Cardinal): Boolean; cdecl; ITracePlugin_trace_func_executePtr = function(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; function_: ITraceFunction; started: Boolean; func_result: Cardinal): Boolean; cdecl; + ITracePlugin_trace_dsql_restartPtr = function(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; number: Cardinal): Boolean; cdecl; ITraceFactory_trace_needsPtr = function(this: ITraceFactory): QWord; cdecl; ITraceFactory_trace_createPtr = function(this: ITraceFactory; status: IStatus; init_info: ITraceInitInfo): ITracePlugin; cdecl; IUdrFunctionFactory_setupPtr = procedure(this: IUdrFunctionFactory; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata; inBuilder: IMetadataBuilder; outBuilder: IMetadataBuilder); cdecl; @@ -1183,20 +1206,24 @@ BlobVTable = class(ReferenceCountedVTable) getInfo: IBlob_getInfoPtr; getSegment: IBlob_getSegmentPtr; putSegment: IBlob_putSegmentPtr; + deprecatedCancel: IBlob_deprecatedCancelPtr; + deprecatedClose: IBlob_deprecatedClosePtr; + seek: IBlob_seekPtr; cancel: IBlob_cancelPtr; close: IBlob_closePtr; - seek: IBlob_seekPtr; end; IBlob = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); function getSegment(status: IStatus; bufferLength: Cardinal; buffer: Pointer; segmentLength: CardinalPtr): Integer; procedure putSegment(status: IStatus; length: Cardinal; buffer: Pointer); + procedure deprecatedCancel(status: IStatus); + procedure deprecatedClose(status: IStatus); + function seek(status: IStatus; mode: Integer; offset: Integer): Integer; procedure cancel(status: IStatus); procedure close(status: IStatus); - function seek(status: IStatus; mode: Integer; offset: Integer): Integer; end; IBlobImpl = class(IBlob) @@ -1207,37 +1234,45 @@ IBlobImpl = class(IBlob) procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract; function getSegment(status: IStatus; bufferLength: Cardinal; buffer: Pointer; segmentLength: CardinalPtr): Integer; virtual; abstract; procedure putSegment(status: IStatus; length: Cardinal; buffer: Pointer); virtual; abstract; + procedure deprecatedCancel(status: IStatus); virtual; abstract; + procedure deprecatedClose(status: IStatus); virtual; abstract; + function seek(status: IStatus; mode: Integer; offset: Integer): Integer; virtual; abstract; procedure cancel(status: IStatus); virtual; abstract; procedure close(status: IStatus); virtual; abstract; - function seek(status: IStatus; mode: Integer; offset: Integer): Integer; virtual; abstract; end; TransactionVTable = class(ReferenceCountedVTable) getInfo: ITransaction_getInfoPtr; prepare: ITransaction_preparePtr; - commit: ITransaction_commitPtr; + deprecatedCommit: ITransaction_deprecatedCommitPtr; commitRetaining: ITransaction_commitRetainingPtr; - rollback: ITransaction_rollbackPtr; + deprecatedRollback: ITransaction_deprecatedRollbackPtr; rollbackRetaining: ITransaction_rollbackRetainingPtr; - disconnect: ITransaction_disconnectPtr; + deprecatedDisconnect: ITransaction_deprecatedDisconnectPtr; join: ITransaction_joinPtr; validate: ITransaction_validatePtr; enterDtc: ITransaction_enterDtcPtr; + commit: ITransaction_commitPtr; + rollback: ITransaction_rollbackPtr; + disconnect: ITransaction_disconnectPtr; end; ITransaction = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); procedure prepare(status: IStatus; msgLength: Cardinal; message: BytePtr); - procedure commit(status: IStatus); + procedure deprecatedCommit(status: IStatus); procedure commitRetaining(status: IStatus); - procedure rollback(status: IStatus); + procedure deprecatedRollback(status: IStatus); procedure rollbackRetaining(status: IStatus); - procedure disconnect(status: IStatus); + procedure deprecatedDisconnect(status: IStatus); function join(status: IStatus; transaction: ITransaction): ITransaction; function validate(status: IStatus; attachment: IAttachment): ITransaction; function enterDtc(status: IStatus): ITransaction; + procedure commit(status: IStatus); + procedure rollback(status: IStatus); + procedure disconnect(status: IStatus); end; ITransactionImpl = class(ITransaction) @@ -1247,14 +1282,17 @@ ITransactionImpl = class(ITransaction) function release(): Integer; virtual; abstract; procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract; procedure prepare(status: IStatus; msgLength: Cardinal; message: BytePtr); virtual; abstract; - procedure commit(status: IStatus); virtual; abstract; + procedure deprecatedCommit(status: IStatus); virtual; abstract; procedure commitRetaining(status: IStatus); virtual; abstract; - procedure rollback(status: IStatus); virtual; abstract; + procedure deprecatedRollback(status: IStatus); virtual; abstract; procedure rollbackRetaining(status: IStatus); virtual; abstract; - procedure disconnect(status: IStatus); virtual; abstract; + procedure deprecatedDisconnect(status: IStatus); virtual; abstract; function join(status: IStatus; transaction: ITransaction): ITransaction; virtual; abstract; function validate(status: IStatus; attachment: IAttachment): ITransaction; virtual; abstract; function enterDtc(status: IStatus): ITransaction; virtual; abstract; + procedure commit(status: IStatus); virtual; abstract; + procedure rollback(status: IStatus); virtual; abstract; + procedure disconnect(status: IStatus); virtual; abstract; end; MessageMetadataVTable = class(ReferenceCountedVTable) @@ -1390,12 +1428,13 @@ ResultSetVTable = class(ReferenceCountedVTable) isEof: IResultSet_isEofPtr; isBof: IResultSet_isBofPtr; getMetadata: IResultSet_getMetadataPtr; - close: IResultSet_closePtr; + deprecatedClose: IResultSet_deprecatedClosePtr; setDelayedOutputFormat: IResultSet_setDelayedOutputFormatPtr; + close: IResultSet_closePtr; end; IResultSet = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; function fetchNext(status: IStatus; message: Pointer): Integer; function fetchPrior(status: IStatus; message: Pointer): Integer; @@ -1406,8 +1445,9 @@ IResultSet = class(IReferenceCounted) function isEof(status: IStatus): Boolean; function isBof(status: IStatus): Boolean; function getMetadata(status: IStatus): IMessageMetadata; - procedure close(status: IStatus); + procedure deprecatedClose(status: IStatus); procedure setDelayedOutputFormat(status: IStatus; format: IMessageMetadata); + procedure close(status: IStatus); end; IResultSetImpl = class(IResultSet) @@ -1424,8 +1464,9 @@ IResultSetImpl = class(IResultSet) function isEof(status: IStatus): Boolean; virtual; abstract; function isBof(status: IStatus): Boolean; virtual; abstract; function getMetadata(status: IStatus): IMessageMetadata; virtual; abstract; - procedure close(status: IStatus); virtual; abstract; + procedure deprecatedClose(status: IStatus); virtual; abstract; procedure setDelayedOutputFormat(status: IStatus; format: IMessageMetadata); virtual; abstract; + procedure close(status: IStatus); virtual; abstract; end; StatementVTable = class(ReferenceCountedVTable) @@ -1438,15 +1479,16 @@ StatementVTable = class(ReferenceCountedVTable) execute: IStatement_executePtr; openCursor: IStatement_openCursorPtr; setCursorName: IStatement_setCursorNamePtr; - free: IStatement_freePtr; + deprecatedFree: IStatement_deprecatedFreePtr; getFlags: IStatement_getFlagsPtr; getTimeout: IStatement_getTimeoutPtr; setTimeout: IStatement_setTimeoutPtr; createBatch: IStatement_createBatchPtr; + free: IStatement_freePtr; end; IStatement = class(IReferenceCounted) - const VERSION = 4; + const VERSION = 5; const PREPARE_PREFETCH_NONE = Cardinal($0); const PREPARE_PREFETCH_TYPE = Cardinal($1); const PREPARE_PREFETCH_INPUT_PARAMETERS = Cardinal($2); @@ -1470,11 +1512,12 @@ IStatement = class(IReferenceCounted) function execute(status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; outBuffer: Pointer): ITransaction; function openCursor(status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; flags: Cardinal): IResultSet; procedure setCursorName(status: IStatus; name: PAnsiChar); - procedure free(status: IStatus); + procedure deprecatedFree(status: IStatus); function getFlags(status: IStatus): Cardinal; function getTimeout(status: IStatus): Cardinal; procedure setTimeout(status: IStatus; timeOut: Cardinal); function createBatch(status: IStatus; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; + procedure free(status: IStatus); end; IStatementImpl = class(IStatement) @@ -1491,11 +1534,12 @@ IStatementImpl = class(IStatement) function execute(status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; outBuffer: Pointer): ITransaction; virtual; abstract; function openCursor(status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; flags: Cardinal): IResultSet; virtual; abstract; procedure setCursorName(status: IStatus; name: PAnsiChar); virtual; abstract; - procedure free(status: IStatus); virtual; abstract; + procedure deprecatedFree(status: IStatus); virtual; abstract; function getFlags(status: IStatus): Cardinal; virtual; abstract; function getTimeout(status: IStatus): Cardinal; virtual; abstract; procedure setTimeout(status: IStatus; timeOut: Cardinal); virtual; abstract; function createBatch(status: IStatus; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; virtual; abstract; + procedure free(status: IStatus); virtual; abstract; end; BatchVTable = class(ReferenceCountedVTable) @@ -1509,17 +1553,24 @@ BatchVTable = class(ReferenceCountedVTable) getBlobAlignment: IBatch_getBlobAlignmentPtr; getMetadata: IBatch_getMetadataPtr; setDefaultBpb: IBatch_setDefaultBpbPtr; + deprecatedClose: IBatch_deprecatedClosePtr; close: IBatch_closePtr; + getInfo: IBatch_getInfoPtr; end; IBatch = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; const VERSION1 = Byte(1); const TAG_MULTIERROR = Byte(1); const TAG_RECORD_COUNTS = Byte(2); const TAG_BUFFER_BYTES_SIZE = Byte(3); const TAG_BLOB_POLICY = Byte(4); const TAG_DETAILED_ERRORS = Byte(5); + const INF_BUFFER_BYTES_SIZE = Byte(10); + const INF_DATA_BYTES_SIZE = Byte(11); + const INF_BLOBS_BYTES_SIZE = Byte(12); + const INF_BLOB_ALIGNMENT = Byte(13); + const INF_BLOB_HEADER = Byte(14); const BLOB_NONE = Byte(0); const BLOB_ID_ENGINE = Byte(1); const BLOB_ID_USER = Byte(2); @@ -1536,7 +1587,9 @@ IBatch = class(IReferenceCounted) function getBlobAlignment(status: IStatus): Cardinal; function getMetadata(status: IStatus): IMessageMetadata; procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr); + procedure deprecatedClose(status: IStatus); procedure close(status: IStatus); + procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); end; IBatchImpl = class(IBatch) @@ -1554,7 +1607,9 @@ IBatchImpl = class(IBatch) function getBlobAlignment(status: IStatus): Cardinal; virtual; abstract; function getMetadata(status: IStatus): IMessageMetadata; virtual; abstract; procedure setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePtr); virtual; abstract; + procedure deprecatedClose(status: IStatus); virtual; abstract; procedure close(status: IStatus); virtual; abstract; + procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract; end; BatchCompletionStateVTable = class(DisposableVTable) @@ -1588,13 +1643,15 @@ IBatchCompletionStateImpl = class(IBatchCompletionState) ReplicatorVTable = class(ReferenceCountedVTable) process: IReplicator_processPtr; + deprecatedClose: IReplicator_deprecatedClosePtr; close: IReplicator_closePtr; end; IReplicator = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; procedure process(status: IStatus; length: Cardinal; data: BytePtr); + procedure deprecatedClose(status: IStatus); procedure close(status: IStatus); end; @@ -1604,6 +1661,7 @@ IReplicatorImpl = class(IReplicator) procedure addRef(); virtual; abstract; function release(): Integer; virtual; abstract; procedure process(status: IStatus; length: Cardinal; data: BytePtr); virtual; abstract; + procedure deprecatedClose(status: IStatus); virtual; abstract; procedure close(status: IStatus); virtual; abstract; end; @@ -1614,11 +1672,12 @@ RequestVTable = class(ReferenceCountedVTable) start: IRequest_startPtr; startAndSend: IRequest_startAndSendPtr; unwind: IRequest_unwindPtr; + deprecatedFree: IRequest_deprecatedFreePtr; free: IRequest_freePtr; end; IRequest = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; procedure receive(status: IStatus; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); procedure send(status: IStatus; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); @@ -1626,6 +1685,7 @@ IRequest = class(IReferenceCounted) procedure start(status: IStatus; tra: ITransaction; level: Integer); procedure startAndSend(status: IStatus; tra: ITransaction; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); procedure unwind(status: IStatus; level: Integer); + procedure deprecatedFree(status: IStatus); procedure free(status: IStatus); end; @@ -1640,16 +1700,19 @@ IRequestImpl = class(IRequest) procedure start(status: IStatus; tra: ITransaction; level: Integer); virtual; abstract; procedure startAndSend(status: IStatus; tra: ITransaction; level: Integer; msgType: Cardinal; length: Cardinal; message: Pointer); virtual; abstract; procedure unwind(status: IStatus; level: Integer); virtual; abstract; + procedure deprecatedFree(status: IStatus); virtual; abstract; procedure free(status: IStatus); virtual; abstract; end; EventsVTable = class(ReferenceCountedVTable) + deprecatedCancel: IEvents_deprecatedCancelPtr; cancel: IEvents_cancelPtr; end; IEvents = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; + procedure deprecatedCancel(status: IStatus); procedure cancel(status: IStatus); end; @@ -1658,6 +1721,7 @@ IEventsImpl = class(IEvents) procedure addRef(); virtual; abstract; function release(): Integer; virtual; abstract; + procedure deprecatedCancel(status: IStatus); virtual; abstract; procedure cancel(status: IStatus); virtual; abstract; end; @@ -1678,18 +1742,20 @@ AttachmentVTable = class(ReferenceCountedVTable) queEvents: IAttachment_queEventsPtr; cancelOperation: IAttachment_cancelOperationPtr; ping: IAttachment_pingPtr; - detach: IAttachment_detachPtr; - dropDatabase: IAttachment_dropDatabasePtr; + deprecatedDetach: IAttachment_deprecatedDetachPtr; + deprecatedDropDatabase: IAttachment_deprecatedDropDatabasePtr; getIdleTimeout: IAttachment_getIdleTimeoutPtr; setIdleTimeout: IAttachment_setIdleTimeoutPtr; getStatementTimeout: IAttachment_getStatementTimeoutPtr; setStatementTimeout: IAttachment_setStatementTimeoutPtr; createBatch: IAttachment_createBatchPtr; createReplicator: IAttachment_createReplicatorPtr; + detach: IAttachment_detachPtr; + dropDatabase: IAttachment_dropDatabasePtr; end; IAttachment = class(IReferenceCounted) - const VERSION = 4; + const VERSION = 5; procedure getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); function startTransaction(status: IStatus; tpbLength: Cardinal; tpb: BytePtr): ITransaction; @@ -1707,14 +1773,16 @@ IAttachment = class(IReferenceCounted) function queEvents(status: IStatus; callback: IEventCallback; length: Cardinal; events: BytePtr): IEvents; procedure cancelOperation(status: IStatus; option: Integer); procedure ping(status: IStatus); - procedure detach(status: IStatus); - procedure dropDatabase(status: IStatus); + procedure deprecatedDetach(status: IStatus); + procedure deprecatedDropDatabase(status: IStatus); function getIdleTimeout(status: IStatus): Cardinal; procedure setIdleTimeout(status: IStatus; timeOut: Cardinal); function getStatementTimeout(status: IStatus): Cardinal; procedure setStatementTimeout(status: IStatus; timeOut: Cardinal); function createBatch(status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; function createReplicator(status: IStatus): IReplicator; + procedure detach(status: IStatus); + procedure dropDatabase(status: IStatus); end; IAttachmentImpl = class(IAttachment) @@ -1738,28 +1806,34 @@ IAttachmentImpl = class(IAttachment) function queEvents(status: IStatus; callback: IEventCallback; length: Cardinal; events: BytePtr): IEvents; virtual; abstract; procedure cancelOperation(status: IStatus; option: Integer); virtual; abstract; procedure ping(status: IStatus); virtual; abstract; - procedure detach(status: IStatus); virtual; abstract; - procedure dropDatabase(status: IStatus); virtual; abstract; + procedure deprecatedDetach(status: IStatus); virtual; abstract; + procedure deprecatedDropDatabase(status: IStatus); virtual; abstract; function getIdleTimeout(status: IStatus): Cardinal; virtual; abstract; procedure setIdleTimeout(status: IStatus; timeOut: Cardinal); virtual; abstract; function getStatementTimeout(status: IStatus): Cardinal; virtual; abstract; procedure setStatementTimeout(status: IStatus; timeOut: Cardinal); virtual; abstract; function createBatch(status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; virtual; abstract; function createReplicator(status: IStatus): IReplicator; virtual; abstract; + procedure detach(status: IStatus); virtual; abstract; + procedure dropDatabase(status: IStatus); virtual; abstract; end; ServiceVTable = class(ReferenceCountedVTable) - detach: IService_detachPtr; + deprecatedDetach: IService_deprecatedDetachPtr; query: IService_queryPtr; start: IService_startPtr; + detach: IService_detachPtr; + cancel: IService_cancelPtr; end; IService = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 5; - procedure detach(status: IStatus); + procedure deprecatedDetach(status: IStatus); procedure query(status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr); procedure start(status: IStatus; spbLength: Cardinal; spb: BytePtr); + procedure detach(status: IStatus); + procedure cancel(status: IStatus); end; IServiceImpl = class(IService) @@ -1767,9 +1841,11 @@ IServiceImpl = class(IService) procedure addRef(); virtual; abstract; function release(): Integer; virtual; abstract; - procedure detach(status: IStatus); virtual; abstract; + procedure deprecatedDetach(status: IStatus); virtual; abstract; procedure query(status: IStatus; sendLength: Cardinal; sendItems: BytePtr; receiveLength: Cardinal; receiveItems: BytePtr; bufferLength: Cardinal; buffer: BytePtr); virtual; abstract; procedure start(status: IStatus; spbLength: Cardinal; spb: BytePtr); virtual; abstract; + procedure detach(status: IStatus); virtual; abstract; + procedure cancel(status: IStatus); virtual; abstract; end; ProviderVTable = class(PluginBaseVTable) @@ -1855,6 +1931,7 @@ IAuth = class(IPluginBase) const AUTH_SUCCESS = Integer(0); const AUTH_MORE_DATA = Integer(1); const AUTH_CONTINUE = Integer(2); + const AUTH_SUCCESS_WITH_DATA = Integer(3); end; @@ -2261,18 +2338,30 @@ IWireCryptPluginImpl = class(IWireCryptPlugin) CryptKeyCallbackVTable = class(VersionedVTable) callback: ICryptKeyCallback_callbackPtr; + dummy1: ICryptKeyCallback_dummy1Ptr; + dummy2: ICryptKeyCallback_dummy2Ptr; + getHashLength: ICryptKeyCallback_getHashLengthPtr; + getHashData: ICryptKeyCallback_getHashDataPtr; end; ICryptKeyCallback = class(IVersioned) - const VERSION = 2; + const VERSION = 3; function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; + procedure dummy1(status: IStatus); + procedure dummy2(); + function getHashLength(status: IStatus): Integer; + procedure getHashData(status: IStatus; hash: Pointer); end; ICryptKeyCallbackImpl = class(ICryptKeyCallback) constructor create; function callback(dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; virtual; abstract; + procedure dummy1(status: IStatus); virtual; + procedure dummy2(); virtual; + function getHashLength(status: IStatus): Integer; virtual; abstract; + procedure getHashData(status: IStatus; hash: Pointer); virtual; abstract; end; KeyHolderPluginVTable = class(PluginBaseVTable) @@ -2740,6 +2829,8 @@ IXpbBuilder = class(IDisposable) const SPB_SEND = Cardinal(7); const SPB_RECEIVE = Cardinal(8); const SPB_RESPONSE = Cardinal(9); + const INFO_SEND = Cardinal(10); + const INFO_RESPONSE = Cardinal(11); procedure clear(status: IStatus); procedure removeCurrent(status: IStatus); @@ -3276,10 +3367,11 @@ TracePluginVTable = class(ReferenceCountedVTable) trace_event_error: ITracePlugin_trace_event_errorPtr; trace_event_sweep: ITracePlugin_trace_event_sweepPtr; trace_func_execute: ITracePlugin_trace_func_executePtr; + trace_dsql_restart: ITracePlugin_trace_dsql_restartPtr; end; ITracePlugin = class(IReferenceCounted) - const VERSION = 3; + const VERSION = 4; const RESULT_SUCCESS = Cardinal(0); const RESULT_FAILED = Cardinal(1); const RESULT_UNAUTHORIZED = Cardinal(2); @@ -3309,6 +3401,7 @@ ITracePlugin = class(IReferenceCounted) function trace_event_error(connection: ITraceConnection; status: ITraceStatusVector; function_: PAnsiChar): Boolean; function trace_event_sweep(connection: ITraceDatabaseConnection; sweep: ITraceSweepInfo; sweep_state: Cardinal): Boolean; function trace_func_execute(connection: ITraceDatabaseConnection; transaction: ITraceTransaction; function_: ITraceFunction; started: Boolean; func_result: Cardinal): Boolean; + function trace_dsql_restart(connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; number: Cardinal): Boolean; end; ITracePluginImpl = class(ITracePlugin) @@ -3337,6 +3430,7 @@ ITracePluginImpl = class(ITracePlugin) function trace_event_error(connection: ITraceConnection; status: ITraceStatusVector; function_: PAnsiChar): Boolean; virtual; abstract; function trace_event_sweep(connection: ITraceDatabaseConnection; sweep: ITraceSweepInfo; sweep_state: Cardinal): Boolean; virtual; abstract; function trace_func_execute(connection: ITraceDatabaseConnection; transaction: ITraceTransaction; function_: ITraceFunction; started: Boolean; func_result: Cardinal): Boolean; virtual; abstract; + function trace_dsql_restart(connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; number: Cardinal): Boolean; virtual; abstract; end; TraceFactoryVTable = class(PluginBaseVTable) @@ -3481,7 +3575,7 @@ IDecFloat16 = class(IVersioned) const STRING_SIZE = Cardinal(24); procedure toBcd(from: FB_DEC16Ptr; sign: IntegerPtr; bcd: BytePtr; exp: IntegerPtr); - procedure toString(status: IStatus; from: FB_DEC16Ptr; bufferLength: Cardinal; buffer: PAnsiChar); + procedure toString(status: IStatus; from: FB_DEC16Ptr; bufferLength: Cardinal; buffer: PAnsiChar); reintroduce; procedure fromBcd(sign: Integer; bcd: BytePtr; exp: Integer; to_: FB_DEC16Ptr); procedure fromString(status: IStatus; from: PAnsiChar; to_: FB_DEC16Ptr); end; @@ -3508,7 +3602,7 @@ IDecFloat34 = class(IVersioned) const STRING_SIZE = Cardinal(43); procedure toBcd(from: FB_DEC34Ptr; sign: IntegerPtr; bcd: BytePtr; exp: IntegerPtr); - procedure toString(status: IStatus; from: FB_DEC34Ptr; bufferLength: Cardinal; buffer: PAnsiChar); + procedure toString(status: IStatus; from: FB_DEC34Ptr; bufferLength: Cardinal; buffer: PAnsiChar); reintroduce; procedure fromBcd(sign: Integer; bcd: BytePtr; exp: Integer; to_: FB_DEC34Ptr); procedure fromString(status: IStatus; from: PAnsiChar; to_: FB_DEC34Ptr); end; @@ -3531,7 +3625,7 @@ IInt128 = class(IVersioned) const VERSION = 2; const STRING_SIZE = Cardinal(46); - procedure toString(status: IStatus; from: FB_I128Ptr; scale: Integer; bufferLength: Cardinal; buffer: PAnsiChar); + procedure toString(status: IStatus; from: FB_I128Ptr; scale: Integer; bufferLength: Cardinal; buffer: PAnsiChar); reintroduce; procedure fromString(status: IStatus; scale: Integer; from: PAnsiChar; to_: FB_I128Ptr); end; @@ -3677,9 +3771,12 @@ IReplicatedSessionImpl = class(IReplicatedSession) procedure setSequence(status: IStatus; name: PAnsiChar; value: Int64); virtual; abstract; end; +{$IFNDEF NO_FBCLIENT} function fb_get_master_interface : IMaster; cdecl; external 'fbclient'; +{$ENDIF} const + FB_UsedInYValve = FALSE; isc_dpb_version1 = byte(1); isc_dpb_version2 = byte(2); isc_dpb_cdd_pathname = byte(1); @@ -3777,6 +3874,7 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_dpb_set_bind = byte(93); isc_dpb_decfloat_round = byte(94); isc_dpb_decfloat_traps = byte(95); + isc_dpb_clear_map = byte(96); isc_dpb_address = byte(1); isc_dpb_addr_protocol = byte(1); isc_dpb_addr_endpoint = byte(2); @@ -4042,6 +4140,9 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_spb_nbk_file = byte(6); isc_spb_nbk_direct = byte(7); isc_spb_nbk_guid = byte(8); + isc_spb_nbk_clean_history = byte(9); + isc_spb_nbk_keep_days = byte(10); + isc_spb_nbk_keep_rows = byte(11); isc_spb_nbk_no_triggers = $01; isc_spb_nbk_inplace = $02; isc_spb_nbk_sequence = $04; @@ -4110,6 +4211,335 @@ IReplicatedSessionImpl = class(IReplicatedSession) fb_dbg_map_curname = byte(7); fb_dbg_arg_input = byte(0); fb_dbg_arg_output = byte(1); + isc_info_end = byte(1); + isc_info_truncated = byte(2); + isc_info_error = byte(3); + isc_info_data_not_ready = byte(4); + isc_info_length = byte(126); + isc_info_flag_end = byte(127); + isc_info_db_id = byte(4); + isc_info_reads = byte(5); + isc_info_writes = byte(6); + isc_info_fetches = byte(7); + isc_info_marks = byte(8); + isc_info_implementation = byte(11); + isc_info_isc_version = byte(12); + isc_info_base_level = byte(13); + isc_info_page_size = byte(14); + isc_info_num_buffers = byte(15); + isc_info_limbo = byte(16); + isc_info_current_memory = byte(17); + isc_info_max_memory = byte(18); + isc_info_window_turns = byte(19); + isc_info_license = byte(20); + isc_info_allocation = byte(21); + isc_info_attachment_id = byte(22); + isc_info_read_seq_count = byte(23); + isc_info_read_idx_count = byte(24); + isc_info_insert_count = byte(25); + isc_info_update_count = byte(26); + isc_info_delete_count = byte(27); + isc_info_backout_count = byte(28); + isc_info_purge_count = byte(29); + isc_info_expunge_count = byte(30); + isc_info_sweep_interval = byte(31); + isc_info_ods_version = byte(32); + isc_info_ods_minor_version = byte(33); + isc_info_no_reserve = byte(34); + isc_info_logfile = byte(35); + isc_info_cur_logfile_name = byte(36); + isc_info_cur_log_part_offset = byte(37); + isc_info_num_wal_buffers = byte(38); + isc_info_wal_buffer_size = byte(39); + isc_info_wal_ckpt_length = byte(40); + isc_info_wal_cur_ckpt_interval = byte(41); + isc_info_wal_prv_ckpt_fname = byte(42); + isc_info_wal_prv_ckpt_poffset = byte(43); + isc_info_wal_recv_ckpt_fname = byte(44); + isc_info_wal_recv_ckpt_poffset = byte(45); + isc_info_wal_grpc_wait_usecs = byte(47); + isc_info_wal_num_io = byte(48); + isc_info_wal_avg_io_size = byte(49); + isc_info_wal_num_commits = byte(50); + isc_info_wal_avg_grpc_size = byte(51); + isc_info_forced_writes = byte(52); + isc_info_user_names = byte(53); + isc_info_page_errors = byte(54); + isc_info_record_errors = byte(55); + isc_info_bpage_errors = byte(56); + isc_info_dpage_errors = byte(57); + isc_info_ipage_errors = byte(58); + isc_info_ppage_errors = byte(59); + isc_info_tpage_errors = byte(60); + isc_info_set_page_buffers = byte(61); + isc_info_db_sql_dialect = byte(62); + isc_info_db_read_only = byte(63); + isc_info_db_size_in_pages = byte(64); + frb_info_att_charset = byte(101); + isc_info_db_class = byte(102); + isc_info_firebird_version = byte(103); + isc_info_oldest_transaction = byte(104); + isc_info_oldest_active = byte(105); + isc_info_oldest_snapshot = byte(106); + isc_info_next_transaction = byte(107); + isc_info_db_provider = byte(108); + isc_info_active_transactions = byte(109); + isc_info_active_tran_count = byte(110); + isc_info_creation_date = byte(111); + isc_info_db_file_size = byte(112); + fb_info_page_contents = byte(113); + fb_info_implementation = byte(114); + fb_info_page_warns = byte(115); + fb_info_record_warns = byte(116); + fb_info_bpage_warns = byte(117); + fb_info_dpage_warns = byte(118); + fb_info_ipage_warns = byte(119); + fb_info_ppage_warns = byte(120); + fb_info_tpage_warns = byte(121); + fb_info_pip_errors = byte(122); + fb_info_pip_warns = byte(123); + fb_info_pages_used = byte(124); + fb_info_pages_free = byte(125); + fb_info_ses_idle_timeout_db = byte(129); + fb_info_ses_idle_timeout_att = byte(130); + fb_info_ses_idle_timeout_run = byte(131); + fb_info_conn_flags = byte(132); + fb_info_crypt_key = byte(133); + fb_info_crypt_state = byte(134); + fb_info_statement_timeout_db = byte(135); + fb_info_statement_timeout_att = byte(136); + fb_info_protocol_version = byte(137); + fb_info_crypt_plugin = byte(138); + fb_info_creation_timestamp_tz = byte(139); + fb_info_wire_crypt = byte(140); + fb_info_features = byte(141); + fb_info_next_attachment = byte(142); + fb_info_next_statement = byte(143); + fb_info_db_guid = byte(144); + fb_info_db_file_id = byte(145); + fb_info_replica_mode = byte(146); + fb_info_username = byte(147); + fb_info_sqlrole = byte(148); + fb_info_crypt_encrypted = $01; + fb_info_crypt_process = $02; + fb_feature_multi_statements = byte(1); + fb_feature_multi_transactions = byte(2); + fb_feature_named_parameters = byte(3); + fb_feature_session_reset = byte(4); + fb_feature_read_consistency = byte(5); + fb_feature_statement_timeout = byte(6); + fb_feature_statement_long_life = byte(7); + fb_info_replica_none = byte(0); + fb_info_replica_read_only = byte(1); + fb_info_replica_read_write = byte(2); + isc_info_db_impl_rdb_vms = byte(1); + isc_info_db_impl_rdb_eln = byte(2); + isc_info_db_impl_rdb_eln_dev = byte(3); + isc_info_db_impl_rdb_vms_y = byte(4); + isc_info_db_impl_rdb_eln_y = byte(5); + isc_info_db_impl_jri = byte(6); + isc_info_db_impl_jsv = byte(7); + isc_info_db_impl_isc_apl_68K = byte(25); + isc_info_db_impl_isc_vax_ultr = byte(26); + isc_info_db_impl_isc_vms = byte(27); + isc_info_db_impl_isc_sun_68k = byte(28); + isc_info_db_impl_isc_os2 = byte(29); + isc_info_db_impl_isc_sun4 = byte(30); + isc_info_db_impl_isc_hp_ux = byte(31); + isc_info_db_impl_isc_sun_386i = byte(32); + isc_info_db_impl_isc_vms_orcl = byte(33); + isc_info_db_impl_isc_mac_aux = byte(34); + isc_info_db_impl_isc_rt_aix = byte(35); + isc_info_db_impl_isc_mips_ult = byte(36); + isc_info_db_impl_isc_xenix = byte(37); + isc_info_db_impl_isc_dg = byte(38); + isc_info_db_impl_isc_hp_mpexl = byte(39); + isc_info_db_impl_isc_hp_ux68K = byte(40); + isc_info_db_impl_isc_sgi = byte(41); + isc_info_db_impl_isc_sco_unix = byte(42); + isc_info_db_impl_isc_cray = byte(43); + isc_info_db_impl_isc_imp = byte(44); + isc_info_db_impl_isc_delta = byte(45); + isc_info_db_impl_isc_next = byte(46); + isc_info_db_impl_isc_dos = byte(47); + isc_info_db_impl_m88K = byte(48); + isc_info_db_impl_unixware = byte(49); + isc_info_db_impl_isc_winnt_x86 = byte(50); + isc_info_db_impl_isc_epson = byte(51); + isc_info_db_impl_alpha_osf = byte(52); + isc_info_db_impl_alpha_vms = byte(53); + isc_info_db_impl_netware_386 = byte(54); + isc_info_db_impl_win_only = byte(55); + isc_info_db_impl_ncr_3000 = byte(56); + isc_info_db_impl_winnt_ppc = byte(57); + isc_info_db_impl_dg_x86 = byte(58); + isc_info_db_impl_sco_ev = byte(59); + isc_info_db_impl_i386 = byte(60); + isc_info_db_impl_freebsd = byte(61); + isc_info_db_impl_netbsd = byte(62); + isc_info_db_impl_darwin_ppc = byte(63); + isc_info_db_impl_sinixz = byte(64); + isc_info_db_impl_linux_sparc = byte(65); + isc_info_db_impl_linux_amd64 = byte(66); + isc_info_db_impl_freebsd_amd64 = byte(67); + isc_info_db_impl_winnt_amd64 = byte(68); + isc_info_db_impl_linux_ppc = byte(69); + isc_info_db_impl_darwin_x86 = byte(70); + isc_info_db_impl_linux_mipsel = byte(71); + isc_info_db_impl_linux_mips = byte(72); + isc_info_db_impl_darwin_x64 = byte(73); + isc_info_db_impl_sun_amd64 = byte(74); + isc_info_db_impl_linux_arm = byte(75); + isc_info_db_impl_linux_ia64 = byte(76); + isc_info_db_impl_darwin_ppc64 = byte(77); + isc_info_db_impl_linux_s390x = byte(78); + isc_info_db_impl_linux_s390 = byte(79); + isc_info_db_impl_linux_sh = byte(80); + isc_info_db_impl_linux_sheb = byte(81); + isc_info_db_impl_linux_hppa = byte(82); + isc_info_db_impl_linux_alpha = byte(83); + isc_info_db_impl_linux_arm64 = byte(84); + isc_info_db_impl_linux_ppc64el = byte(85); + isc_info_db_impl_linux_ppc64 = byte(86); + isc_info_db_impl_linux_m68k = byte(87); + isc_info_db_impl_linux_riscv64 = byte(88); + isc_info_db_class_access = byte(1); + isc_info_db_class_y_valve = byte(2); + isc_info_db_class_rem_int = byte(3); + isc_info_db_class_rem_srvr = byte(4); + isc_info_db_class_pipe_int = byte(7); + isc_info_db_class_pipe_srvr = byte(8); + isc_info_db_class_sam_int = byte(9); + isc_info_db_class_sam_srvr = byte(10); + isc_info_db_class_gateway = byte(11); + isc_info_db_class_cache = byte(12); + isc_info_db_class_classic_access = byte(13); + isc_info_db_class_server_access = byte(14); + isc_info_db_code_rdb_eln = byte(1); + isc_info_db_code_rdb_vms = byte(2); + isc_info_db_code_interbase = byte(3); + isc_info_db_code_firebird = byte(4); + isc_info_number_messages = byte(4); + isc_info_max_message = byte(5); + isc_info_max_send = byte(6); + isc_info_max_receive = byte(7); + isc_info_state = byte(8); + isc_info_message_number = byte(9); + isc_info_message_size = byte(10); + isc_info_request_cost = byte(11); + isc_info_access_path = byte(12); + isc_info_req_select_count = byte(13); + isc_info_req_insert_count = byte(14); + isc_info_req_update_count = byte(15); + isc_info_req_delete_count = byte(16); + isc_info_rsb_end = byte(0); + isc_info_rsb_begin = byte(1); + isc_info_rsb_type = byte(2); + isc_info_rsb_relation = byte(3); + isc_info_rsb_plan = byte(4); + isc_info_rsb_unknown = byte(1); + isc_info_rsb_indexed = byte(2); + isc_info_rsb_navigate = byte(3); + isc_info_rsb_sequential = byte(4); + isc_info_rsb_cross = byte(5); + isc_info_rsb_sort = byte(6); + isc_info_rsb_first = byte(7); + isc_info_rsb_boolean = byte(8); + isc_info_rsb_union = byte(9); + isc_info_rsb_aggregate = byte(10); + isc_info_rsb_merge = byte(11); + isc_info_rsb_ext_sequential = byte(12); + isc_info_rsb_ext_indexed = byte(13); + isc_info_rsb_ext_dbkey = byte(14); + isc_info_rsb_left_cross = byte(15); + isc_info_rsb_select = byte(16); + isc_info_rsb_sql_join = byte(17); + isc_info_rsb_simulate = byte(18); + isc_info_rsb_sim_cross = byte(19); + isc_info_rsb_once = byte(20); + isc_info_rsb_procedure = byte(21); + isc_info_rsb_skip = byte(22); + isc_info_rsb_virt_sequential = byte(23); + isc_info_rsb_recursive = byte(24); + isc_info_rsb_window = byte(25); + isc_info_rsb_singular = byte(26); + isc_info_rsb_writelock = byte(27); + isc_info_rsb_buffer = byte(28); + isc_info_rsb_hash = byte(29); + isc_info_rsb_and = byte(1); + isc_info_rsb_or = byte(2); + isc_info_rsb_dbkey = byte(3); + isc_info_rsb_index = byte(4); + isc_info_req_active = byte(2); + isc_info_req_inactive = byte(3); + isc_info_req_send = byte(4); + isc_info_req_receive = byte(5); + isc_info_req_select = byte(6); + isc_info_req_sql_stall = byte(7); + isc_info_blob_num_segments = byte(4); + isc_info_blob_max_segment = byte(5); + isc_info_blob_total_length = byte(6); + isc_info_blob_type = byte(7); + isc_info_tra_id = byte(4); + isc_info_tra_oldest_interesting = byte(5); + isc_info_tra_oldest_snapshot = byte(6); + isc_info_tra_oldest_active = byte(7); + isc_info_tra_isolation = byte(8); + isc_info_tra_access = byte(9); + isc_info_tra_lock_timeout = byte(10); + fb_info_tra_dbpath = byte(11); + fb_info_tra_snapshot_number = byte(12); + isc_info_tra_consistency = byte(1); + isc_info_tra_concurrency = byte(2); + isc_info_tra_read_committed = byte(3); + isc_info_tra_no_rec_version = byte(0); + isc_info_tra_rec_version = byte(1); + isc_info_tra_read_consistency = byte(2); + isc_info_tra_readonly = byte(0); + isc_info_tra_readwrite = byte(1); + isc_info_sql_select = byte(4); + isc_info_sql_bind = byte(5); + isc_info_sql_num_variables = byte(6); + isc_info_sql_describe_vars = byte(7); + isc_info_sql_describe_end = byte(8); + isc_info_sql_sqlda_seq = byte(9); + isc_info_sql_message_seq = byte(10); + isc_info_sql_type = byte(11); + isc_info_sql_sub_type = byte(12); + isc_info_sql_scale = byte(13); + isc_info_sql_length = byte(14); + isc_info_sql_null_ind = byte(15); + isc_info_sql_field = byte(16); + isc_info_sql_relation = byte(17); + isc_info_sql_owner = byte(18); + isc_info_sql_alias = byte(19); + isc_info_sql_sqlda_start = byte(20); + isc_info_sql_stmt_type = byte(21); + isc_info_sql_get_plan = byte(22); + isc_info_sql_records = byte(23); + isc_info_sql_batch_fetch = byte(24); + isc_info_sql_relation_alias = byte(25); + isc_info_sql_explain_plan = byte(26); + isc_info_sql_stmt_flags = byte(27); + isc_info_sql_stmt_timeout_user = byte(28); + isc_info_sql_stmt_timeout_run = byte(29); + isc_info_sql_stmt_blob_align = byte(30); + isc_info_sql_exec_path_blr_bytes = byte(31); + isc_info_sql_exec_path_blr_text = byte(32); + isc_info_sql_stmt_select = byte(1); + isc_info_sql_stmt_insert = byte(2); + isc_info_sql_stmt_update = byte(3); + isc_info_sql_stmt_delete = byte(4); + isc_info_sql_stmt_ddl = byte(5); + isc_info_sql_stmt_get_segment = byte(6); + isc_info_sql_stmt_put_segment = byte(7); + isc_info_sql_stmt_exec_procedure = byte(8); + isc_info_sql_stmt_start_trans = byte(9); + isc_info_sql_stmt_commit = byte(10); + isc_info_sql_stmt_rollback = byte(11); + isc_info_sql_stmt_select_for_upd = byte(12); + isc_info_sql_stmt_set_generator = byte(13); + isc_info_sql_stmt_savepoint = byte(14); isc_facility = 20; isc_err_base = 335544320; isc_err_factor = 1; @@ -4939,7 +5369,7 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_overriding_without_identity = 335545134; isc_overriding_system_invalid = 335545135; isc_overriding_user_invalid = 335545136; - isc_overriding_system_missing = 335545137; + isc_overriding_missing = 335545137; isc_decprecision_err = 335545138; isc_decfloat_divide_by_zero = 335545139; isc_decfloat_inexact_result = 335545140; @@ -5076,6 +5506,9 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_repl_error = 335545271; isc_ses_reset_failed = 335545272; isc_block_size = 335545273; + isc_tom_key_length = 335545274; + isc_inf_invalid_args = 335545275; + isc_sysf_invalid_null_empty = 335545276; isc_gfix_db_name = 335740929; isc_gfix_invalid_sw = 335740930; isc_gfix_incmp_sw = 335740932; @@ -5557,6 +5990,11 @@ IReplicatedSessionImpl = class(IReplicatedSession) isc_nbackup_deco_parse = 337117259; isc_nbackup_lostrec_guid_db = 337117261; isc_nbackup_seq_misuse = 337117265; + isc_nbackup_wrong_param = 337117268; + isc_nbackup_clean_hist_misuse = 337117269; + isc_nbackup_clean_hist_missed = 337117270; + isc_nbackup_keep_hist_missed = 337117271; + isc_nbackup_second_keep_switch = 337117272; isc_trace_conflict_acts = 337182750; isc_trace_act_notfound = 337182751; isc_trace_switch_once = 337182752; @@ -5795,7 +6233,13 @@ function IFirebirdConf.asBoolean(key: Cardinal): Boolean; function IFirebirdConf.getVersion(status: IStatus): Cardinal; begin - Result := FirebirdConfVTable(vTable).getVersion(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IFirebirdConf', vTable.version, 4); + Result := 0; + end + else begin + Result := FirebirdConfVTable(vTable).getVersion(Self, status); + end; FbException.checkException(status); end; @@ -5835,7 +6279,11 @@ procedure IPluginModule.doClean(); procedure IPluginModule.threadDetach(); begin - PluginModuleVTable(vTable).threadDetach(Self); + if (vTable.version < 3) then begin + end + else begin + PluginModuleVTable(vTable).threadDetach(Self); + end; end; procedure IPluginManager.registerPluginFactory(pluginType: Cardinal; defaultName: PAnsiChar; factory: IPluginFactory); @@ -5924,7 +6372,12 @@ function IConfigManager.getRootDirectory(): PAnsiChar; function IConfigManager.getDefaultSecurityDb(): PAnsiChar; begin - Result := ConfigManagerVTable(vTable).getDefaultSecurityDb(Self); + if (vTable.version < 3) then begin + Result := nil; + end + else begin + Result := ConfigManagerVTable(vTable).getDefaultSecurityDb(Self); + end; end; procedure IEventCallback.eventCallbackFunction(length: Cardinal; events: BytePtr); @@ -5950,15 +6403,15 @@ procedure IBlob.putSegment(status: IStatus; length: Cardinal; buffer: Pointer); FbException.checkException(status); end; -procedure IBlob.cancel(status: IStatus); +procedure IBlob.deprecatedCancel(status: IStatus); begin - BlobVTable(vTable).cancel(Self, status); + BlobVTable(vTable).deprecatedCancel(Self, status); FbException.checkException(status); end; -procedure IBlob.close(status: IStatus); +procedure IBlob.deprecatedClose(status: IStatus); begin - BlobVTable(vTable).close(Self, status); + BlobVTable(vTable).deprecatedClose(Self, status); FbException.checkException(status); end; @@ -5968,6 +6421,38 @@ function IBlob.seek(status: IStatus; mode: Integer; offset: Integer): Integer; FbException.checkException(status); end; +procedure IBlob.cancel(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IBlob', vTable.version, 4); + end + else begin + deprecatedCancel(status); + end + end + else begin + BlobVTable(vTable).cancel(Self, status); + end; + FbException.checkException(status); +end; + +procedure IBlob.close(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IBlob', vTable.version, 4); + end + else begin + deprecatedClose(status); + end + end + else begin + BlobVTable(vTable).close(Self, status); + end; + FbException.checkException(status); +end; + procedure ITransaction.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); begin TransactionVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer); @@ -5980,9 +6465,9 @@ procedure ITransaction.prepare(status: IStatus; msgLength: Cardinal; message: By FbException.checkException(status); end; -procedure ITransaction.commit(status: IStatus); +procedure ITransaction.deprecatedCommit(status: IStatus); begin - TransactionVTable(vTable).commit(Self, status); + TransactionVTable(vTable).deprecatedCommit(Self, status); FbException.checkException(status); end; @@ -5992,9 +6477,9 @@ procedure ITransaction.commitRetaining(status: IStatus); FbException.checkException(status); end; -procedure ITransaction.rollback(status: IStatus); +procedure ITransaction.deprecatedRollback(status: IStatus); begin - TransactionVTable(vTable).rollback(Self, status); + TransactionVTable(vTable).deprecatedRollback(Self, status); FbException.checkException(status); end; @@ -6004,9 +6489,9 @@ procedure ITransaction.rollbackRetaining(status: IStatus); FbException.checkException(status); end; -procedure ITransaction.disconnect(status: IStatus); +procedure ITransaction.deprecatedDisconnect(status: IStatus); begin - TransactionVTable(vTable).disconnect(Self, status); + TransactionVTable(vTable).deprecatedDisconnect(Self, status); FbException.checkException(status); end; @@ -6028,6 +6513,54 @@ function ITransaction.enterDtc(status: IStatus): ITransaction; FbException.checkException(status); end; +procedure ITransaction.commit(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'ITransaction', vTable.version, 4); + end + else begin + deprecatedCommit(status); + end + end + else begin + TransactionVTable(vTable).commit(Self, status); + end; + FbException.checkException(status); +end; + +procedure ITransaction.rollback(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'ITransaction', vTable.version, 4); + end + else begin + deprecatedRollback(status); + end + end + else begin + TransactionVTable(vTable).rollback(Self, status); + end; + FbException.checkException(status); +end; + +procedure ITransaction.disconnect(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'ITransaction', vTable.version, 4); + end + else begin + deprecatedDisconnect(status); + end + end + else begin + TransactionVTable(vTable).disconnect(Self, status); + end; + FbException.checkException(status); +end; + function IMessageMetadata.getCount(status: IStatus): Cardinal; begin Result := MessageMetadataVTable(vTable).getCount(Self, status); @@ -6120,13 +6653,25 @@ function IMessageMetadata.getMessageLength(status: IStatus): Cardinal; function IMessageMetadata.getAlignment(status: IStatus): Cardinal; begin - Result := MessageMetadataVTable(vTable).getAlignment(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMessageMetadata', vTable.version, 4); + Result := 0; + end + else begin + Result := MessageMetadataVTable(vTable).getAlignment(Self, status); + end; FbException.checkException(status); end; function IMessageMetadata.getAlignedLength(status: IStatus): Cardinal; begin - Result := MessageMetadataVTable(vTable).getAlignedLength(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMessageMetadata', vTable.version, 4); + Result := 0; + end + else begin + Result := MessageMetadataVTable(vTable).getAlignedLength(Self, status); + end; FbException.checkException(status); end; @@ -6192,25 +6737,45 @@ function IMetadataBuilder.getMetadata(status: IStatus): IMessageMetadata; procedure IMetadataBuilder.setField(status: IStatus; index: Cardinal; field: PAnsiChar); begin - MetadataBuilderVTable(vTable).setField(Self, status, index, field); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMetadataBuilder', vTable.version, 4); + end + else begin + MetadataBuilderVTable(vTable).setField(Self, status, index, field); + end; FbException.checkException(status); end; procedure IMetadataBuilder.setRelation(status: IStatus; index: Cardinal; relation: PAnsiChar); begin - MetadataBuilderVTable(vTable).setRelation(Self, status, index, relation); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMetadataBuilder', vTable.version, 4); + end + else begin + MetadataBuilderVTable(vTable).setRelation(Self, status, index, relation); + end; FbException.checkException(status); end; procedure IMetadataBuilder.setOwner(status: IStatus; index: Cardinal; owner: PAnsiChar); begin - MetadataBuilderVTable(vTable).setOwner(Self, status, index, owner); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMetadataBuilder', vTable.version, 4); + end + else begin + MetadataBuilderVTable(vTable).setOwner(Self, status, index, owner); + end; FbException.checkException(status); end; procedure IMetadataBuilder.setAlias(status: IStatus; index: Cardinal; alias: PAnsiChar); begin - MetadataBuilderVTable(vTable).setAlias(Self, status, index, alias); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IMetadataBuilder', vTable.version, 4); + end + else begin + MetadataBuilderVTable(vTable).setAlias(Self, status, index, alias); + end; FbException.checkException(status); end; @@ -6268,9 +6833,9 @@ function IResultSet.getMetadata(status: IStatus): IMessageMetadata; FbException.checkException(status); end; -procedure IResultSet.close(status: IStatus); +procedure IResultSet.deprecatedClose(status: IStatus); begin - ResultSetVTable(vTable).close(Self, status); + ResultSetVTable(vTable).deprecatedClose(Self, status); FbException.checkException(status); end; @@ -6280,6 +6845,22 @@ procedure IResultSet.setDelayedOutputFormat(status: IStatus; format: IMessageMet FbException.checkException(status); end; +procedure IResultSet.close(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IResultSet', vTable.version, 4); + end + else begin + deprecatedClose(status); + end + end + else begin + ResultSetVTable(vTable).close(Self, status); + end; + FbException.checkException(status); +end; + procedure IStatement.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); begin StatementVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer); @@ -6334,9 +6915,9 @@ procedure IStatement.setCursorName(status: IStatus; name: PAnsiChar); FbException.checkException(status); end; -procedure IStatement.free(status: IStatus); +procedure IStatement.deprecatedFree(status: IStatus); begin - StatementVTable(vTable).free(Self, status); + StatementVTable(vTable).deprecatedFree(Self, status); FbException.checkException(status); end; @@ -6348,19 +6929,52 @@ function IStatement.getFlags(status: IStatus): Cardinal; function IStatement.getTimeout(status: IStatus): Cardinal; begin - Result := StatementVTable(vTable).getTimeout(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IStatement', vTable.version, 4); + Result := 0; + end + else begin + Result := StatementVTable(vTable).getTimeout(Self, status); + end; FbException.checkException(status); end; procedure IStatement.setTimeout(status: IStatus; timeOut: Cardinal); begin - StatementVTable(vTable).setTimeout(Self, status, timeOut); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IStatement', vTable.version, 4); + end + else begin + StatementVTable(vTable).setTimeout(Self, status, timeOut); + end; FbException.checkException(status); end; function IStatement.createBatch(status: IStatus; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; begin - Result := StatementVTable(vTable).createBatch(Self, status, inMetadata, parLength, par); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IStatement', vTable.version, 4); + Result := nil; + end + else begin + Result := StatementVTable(vTable).createBatch(Self, status, inMetadata, parLength, par); + end; + FbException.checkException(status); +end; + +procedure IStatement.free(status: IStatus); +begin + if (vTable.version < 5) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IStatement', vTable.version, 5); + end + else begin + deprecatedFree(status); + end + end + else begin + StatementVTable(vTable).free(Self, status); + end; FbException.checkException(status); end; @@ -6424,9 +7038,36 @@ procedure IBatch.setDefaultBpb(status: IStatus; parLength: Cardinal; par: BytePt FbException.checkException(status); end; +procedure IBatch.deprecatedClose(status: IStatus); +begin + BatchVTable(vTable).deprecatedClose(Self, status); + FbException.checkException(status); +end; + procedure IBatch.close(status: IStatus); begin - BatchVTable(vTable).close(Self, status); + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IBatch', vTable.version, 4); + end + else begin + deprecatedClose(status); + end + end + else begin + BatchVTable(vTable).close(Self, status); + end; + FbException.checkException(status); +end; + +procedure IBatch.getInfo(status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); +begin + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IBatch', vTable.version, 4); + end + else begin + BatchVTable(vTable).getInfo(Self, status, itemsLength, items, bufferLength, buffer); + end; FbException.checkException(status); end; @@ -6460,9 +7101,25 @@ procedure IReplicator.process(status: IStatus; length: Cardinal; data: BytePtr); FbException.checkException(status); end; +procedure IReplicator.deprecatedClose(status: IStatus); +begin + ReplicatorVTable(vTable).deprecatedClose(Self, status); + FbException.checkException(status); +end; + procedure IReplicator.close(status: IStatus); begin - ReplicatorVTable(vTable).close(Self, status); + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IReplicator', vTable.version, 4); + end + else begin + deprecatedClose(status); + end + end + else begin + ReplicatorVTable(vTable).close(Self, status); + end; FbException.checkException(status); end; @@ -6502,15 +7159,47 @@ procedure IRequest.unwind(status: IStatus; level: Integer); FbException.checkException(status); end; +procedure IRequest.deprecatedFree(status: IStatus); +begin + RequestVTable(vTable).deprecatedFree(Self, status); + FbException.checkException(status); +end; + procedure IRequest.free(status: IStatus); begin - RequestVTable(vTable).free(Self, status); + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IRequest', vTable.version, 4); + end + else begin + deprecatedFree(status); + end + end + else begin + RequestVTable(vTable).free(Self, status); + end; + FbException.checkException(status); +end; + +procedure IEvents.deprecatedCancel(status: IStatus); +begin + EventsVTable(vTable).deprecatedCancel(Self, status); FbException.checkException(status); end; procedure IEvents.cancel(status: IStatus); begin - EventsVTable(vTable).cancel(Self, status); + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IEvents', vTable.version, 4); + end + else begin + deprecatedCancel(status); + end + end + else begin + EventsVTable(vTable).cancel(Self, status); + end; FbException.checkException(status); end; @@ -6610,57 +7299,123 @@ procedure IAttachment.ping(status: IStatus); FbException.checkException(status); end; -procedure IAttachment.detach(status: IStatus); +procedure IAttachment.deprecatedDetach(status: IStatus); begin - AttachmentVTable(vTable).detach(Self, status); + AttachmentVTable(vTable).deprecatedDetach(Self, status); FbException.checkException(status); end; -procedure IAttachment.dropDatabase(status: IStatus); +procedure IAttachment.deprecatedDropDatabase(status: IStatus); begin - AttachmentVTable(vTable).dropDatabase(Self, status); + AttachmentVTable(vTable).deprecatedDropDatabase(Self, status); FbException.checkException(status); end; function IAttachment.getIdleTimeout(status: IStatus): Cardinal; begin - Result := AttachmentVTable(vTable).getIdleTimeout(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + Result := 0; + end + else begin + Result := AttachmentVTable(vTable).getIdleTimeout(Self, status); + end; FbException.checkException(status); end; procedure IAttachment.setIdleTimeout(status: IStatus; timeOut: Cardinal); begin - AttachmentVTable(vTable).setIdleTimeout(Self, status, timeOut); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + end + else begin + AttachmentVTable(vTable).setIdleTimeout(Self, status, timeOut); + end; FbException.checkException(status); end; function IAttachment.getStatementTimeout(status: IStatus): Cardinal; begin - Result := AttachmentVTable(vTable).getStatementTimeout(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + Result := 0; + end + else begin + Result := AttachmentVTable(vTable).getStatementTimeout(Self, status); + end; FbException.checkException(status); end; procedure IAttachment.setStatementTimeout(status: IStatus; timeOut: Cardinal); begin - AttachmentVTable(vTable).setStatementTimeout(Self, status, timeOut); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + end + else begin + AttachmentVTable(vTable).setStatementTimeout(Self, status, timeOut); + end; FbException.checkException(status); end; function IAttachment.createBatch(status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; begin - Result := AttachmentVTable(vTable).createBatch(Self, status, transaction, stmtLength, sqlStmt, dialect, inMetadata, parLength, par); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + Result := nil; + end + else begin + Result := AttachmentVTable(vTable).createBatch(Self, status, transaction, stmtLength, sqlStmt, dialect, inMetadata, parLength, par); + end; FbException.checkException(status); end; function IAttachment.createReplicator(status: IStatus): IReplicator; begin - Result := AttachmentVTable(vTable).createReplicator(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 4); + Result := nil; + end + else begin + Result := AttachmentVTable(vTable).createReplicator(Self, status); + end; + FbException.checkException(status); +end; + +procedure IAttachment.detach(status: IStatus); +begin + if (vTable.version < 5) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 5); + end + else begin + deprecatedDetach(status); + end + end + else begin + AttachmentVTable(vTable).detach(Self, status); + end; FbException.checkException(status); end; -procedure IService.detach(status: IStatus); +procedure IAttachment.dropDatabase(status: IStatus); begin - ServiceVTable(vTable).detach(Self, status); + if (vTable.version < 5) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IAttachment', vTable.version, 5); + end + else begin + deprecatedDropDatabase(status); + end + end + else begin + AttachmentVTable(vTable).dropDatabase(Self, status); + end; + FbException.checkException(status); +end; + +procedure IService.deprecatedDetach(status: IStatus); +begin + ServiceVTable(vTable).deprecatedDetach(Self, status); FbException.checkException(status); end; @@ -6676,6 +7431,33 @@ procedure IService.start(status: IStatus; spbLength: Cardinal; spb: BytePtr); FbException.checkException(status); end; +procedure IService.detach(status: IStatus); +begin + if (vTable.version < 4) then begin + if FB_UsedInYValve then begin + FbException.setVersionError(status, 'IService', vTable.version, 4); + end + else begin + deprecatedDetach(status); + end + end + else begin + ServiceVTable(vTable).detach(Self, status); + end; + FbException.checkException(status); +end; + +procedure IService.cancel(status: IStatus); +begin + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IService', vTable.version, 5); + end + else begin + ServiceVTable(vTable).cancel(Self, status); + end; + FbException.checkException(status); +end; + function IProvider.attachDatabase(status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; begin Result := ProviderVTable(vTable).attachDatabase(Self, status, fileName, dpbLength, dpb); @@ -6810,7 +7592,13 @@ function IClientBlock.newKey(status: IStatus): ICryptKey; function IClientBlock.getAuthBlock(status: IStatus): IAuthBlock; begin - Result := ClientBlockVTable(vTable).getAuthBlock(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IClientBlock', vTable.version, 4); + Result := nil; + end + else begin + Result := ClientBlockVTable(vTable).getAuthBlock(Self, status); + end; FbException.checkException(status); end; @@ -6822,7 +7610,12 @@ function IServer.authenticate(status: IStatus; sBlock: IServerBlock; writerInter procedure IServer.setDbCryptCallback(status: IStatus; cryptCallback: ICryptKeyCallback); begin - ServerVTable(vTable).setDbCryptCallback(Self, status, cryptCallback); + if (vTable.version < 6) then begin + FbException.setVersionError(status, 'IServer', vTable.version, 6); + end + else begin + ServerVTable(vTable).setDbCryptCallback(Self, status, cryptCallback); + end; FbException.checkException(status); end; @@ -6959,13 +7752,25 @@ function ILogonInfo.authBlock(length: CardinalPtr): BytePtr; function ILogonInfo.attachment(status: IStatus): IAttachment; begin - Result := LogonInfoVTable(vTable).attachment(Self, status); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ILogonInfo', vTable.version, 3); + Result := nil; + end + else begin + Result := LogonInfoVTable(vTable).attachment(Self, status); + end; FbException.checkException(status); end; function ILogonInfo.transaction(status: IStatus): ITransaction; begin - Result := LogonInfoVTable(vTable).transaction(Self, status); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ILogonInfo', vTable.version, 3); + Result := nil; + end + else begin + Result := LogonInfoVTable(vTable).transaction(Self, status); + end; FbException.checkException(status); end; @@ -7056,13 +7861,24 @@ procedure IWireCryptPlugin.decrypt(status: IStatus; length: Cardinal; from: Poin function IWireCryptPlugin.getSpecificData(status: IStatus; keyType: PAnsiChar; length: CardinalPtr): BytePtr; begin - Result := WireCryptPluginVTable(vTable).getSpecificData(Self, status, keyType, length); + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IWireCryptPlugin', vTable.version, 5); + Result := nil; + end + else begin + Result := WireCryptPluginVTable(vTable).getSpecificData(Self, status, keyType, length); + end; FbException.checkException(status); end; procedure IWireCryptPlugin.setSpecificData(status: IStatus; keyType: PAnsiChar; length: Cardinal; data: BytePtr); begin - WireCryptPluginVTable(vTable).setSpecificData(Self, status, keyType, length, data); + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IWireCryptPlugin', vTable.version, 5); + end + else begin + WireCryptPluginVTable(vTable).setSpecificData(Self, status, keyType, length, data); + end; FbException.checkException(status); end; @@ -7071,6 +7887,49 @@ function ICryptKeyCallback.callback(dataLength: Cardinal; data: Pointer; bufferL Result := CryptKeyCallbackVTable(vTable).callback(Self, dataLength, data, bufferLength, buffer); end; +procedure ICryptKeyCallback.dummy1(status: IStatus); +begin + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ICryptKeyCallback', vTable.version, 3); + end + else begin + CryptKeyCallbackVTable(vTable).dummy1(Self, status); + end; + FbException.checkException(status); +end; + +procedure ICryptKeyCallback.dummy2(); +begin + if (vTable.version < 3) then begin + end + else begin + CryptKeyCallbackVTable(vTable).dummy2(Self); + end; +end; + +function ICryptKeyCallback.getHashLength(status: IStatus): Integer; +begin + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ICryptKeyCallback', vTable.version, 3); + Result := -1; + end + else begin + Result := CryptKeyCallbackVTable(vTable).getHashLength(Self, status); + end; + FbException.checkException(status); +end; + +procedure ICryptKeyCallback.getHashData(status: IStatus; hash: Pointer); +begin + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ICryptKeyCallback', vTable.version, 3); + end + else begin + CryptKeyCallbackVTable(vTable).getHashData(Self, status, hash); + end; + FbException.checkException(status); +end; + function IKeyHolderPlugin.keyCallback(status: IStatus; callback: ICryptKeyCallback): Integer; begin Result := KeyHolderPluginVTable(vTable).keyCallback(Self, status, callback); @@ -7085,13 +7944,25 @@ function IKeyHolderPlugin.keyHandle(status: IStatus; keyName: PAnsiChar): ICrypt function IKeyHolderPlugin.useOnlyOwnKeys(status: IStatus): Boolean; begin - Result := KeyHolderPluginVTable(vTable).useOnlyOwnKeys(Self, status); + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IKeyHolderPlugin', vTable.version, 5); + Result := false; + end + else begin + Result := KeyHolderPluginVTable(vTable).useOnlyOwnKeys(Self, status); + end; FbException.checkException(status); end; function IKeyHolderPlugin.chainHandle(status: IStatus): ICryptKeyCallback; begin - Result := KeyHolderPluginVTable(vTable).chainHandle(Self, status); + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IKeyHolderPlugin', vTable.version, 5); + Result := nil; + end + else begin + Result := KeyHolderPluginVTable(vTable).chainHandle(Self, status); + end; FbException.checkException(status); end; @@ -7121,7 +7992,12 @@ procedure IDbCryptPlugin.decrypt(status: IStatus; length: Cardinal; from: Pointe procedure IDbCryptPlugin.setInfo(status: IStatus; info: IDbCryptInfo); begin - DbCryptPluginVTable(vTable).setInfo(Self, status, info); + if (vTable.version < 5) then begin + FbException.setVersionError(status, 'IDbCryptPlugin', vTable.version, 5); + end + else begin + DbCryptPluginVTable(vTable).setInfo(Self, status, info); + end; FbException.checkException(status); end; @@ -7407,55 +8283,103 @@ function IUtil.setOffsets(status: IStatus; metadata: IMessageMetadata; callback: function IUtil.getDecFloat16(status: IStatus): IDecFloat16; begin - Result := UtilVTable(vTable).getDecFloat16(Self, status); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + Result := nil; + end + else begin + Result := UtilVTable(vTable).getDecFloat16(Self, status); + end; FbException.checkException(status); end; function IUtil.getDecFloat34(status: IStatus): IDecFloat34; begin - Result := UtilVTable(vTable).getDecFloat34(Self, status); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + Result := nil; + end + else begin + Result := UtilVTable(vTable).getDecFloat34(Self, status); + end; FbException.checkException(status); end; procedure IUtil.decodeTimeTz(status: IStatus; timeTz: ISC_TIME_TZPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); begin - UtilVTable(vTable).decodeTimeTz(Self, status, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + end + else begin + UtilVTable(vTable).decodeTimeTz(Self, status, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + end; FbException.checkException(status); end; procedure IUtil.decodeTimeStampTz(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); begin - UtilVTable(vTable).decodeTimeStampTz(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + end + else begin + UtilVTable(vTable).decodeTimeStampTz(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + end; FbException.checkException(status); end; procedure IUtil.encodeTimeTz(status: IStatus; timeTz: ISC_TIME_TZPtr; hours: Cardinal; minutes: Cardinal; seconds: Cardinal; fractions: Cardinal; timeZone: PAnsiChar); begin - UtilVTable(vTable).encodeTimeTz(Self, status, timeTz, hours, minutes, seconds, fractions, timeZone); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + end + else begin + UtilVTable(vTable).encodeTimeTz(Self, status, timeTz, hours, minutes, seconds, fractions, timeZone); + end; FbException.checkException(status); end; procedure IUtil.encodeTimeStampTz(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZPtr; year: Cardinal; month: Cardinal; day: Cardinal; hours: Cardinal; minutes: Cardinal; seconds: Cardinal; fractions: Cardinal; timeZone: PAnsiChar); begin - UtilVTable(vTable).encodeTimeStampTz(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZone); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 3); + end + else begin + UtilVTable(vTable).encodeTimeStampTz(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZone); + end; FbException.checkException(status); end; function IUtil.getInt128(status: IStatus): IInt128; begin - Result := UtilVTable(vTable).getInt128(Self, status); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 4); + Result := nil; + end + else begin + Result := UtilVTable(vTable).getInt128(Self, status); + end; FbException.checkException(status); end; procedure IUtil.decodeTimeTzEx(status: IStatus; timeTz: ISC_TIME_TZ_EXPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); begin - UtilVTable(vTable).decodeTimeTzEx(Self, status, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 4); + end + else begin + UtilVTable(vTable).decodeTimeTzEx(Self, status, timeTz, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + end; FbException.checkException(status); end; procedure IUtil.decodeTimeStampTzEx(status: IStatus; timeStampTz: ISC_TIMESTAMP_TZ_EXPtr; year: CardinalPtr; month: CardinalPtr; day: CardinalPtr; hours: CardinalPtr; minutes: CardinalPtr; seconds: CardinalPtr; fractions: CardinalPtr; timeZoneBufferLength: Cardinal; timeZoneBuffer: PAnsiChar); begin - UtilVTable(vTable).decodeTimeStampTzEx(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'IUtil', vTable.version, 4); + end + else begin + UtilVTable(vTable).decodeTimeStampTzEx(Self, status, timeStampTz, year, month, day, hours, minutes, seconds, fractions, timeZoneBufferLength, timeZoneBuffer); + end; FbException.checkException(status); end; @@ -7667,12 +8591,22 @@ function ITraceTransaction.getPerf(): PerformanceInfoPtr; function ITraceTransaction.getInitialID(): Int64; begin - Result := TraceTransactionVTable(vTable).getInitialID(Self); + if (vTable.version < 3) then begin + Result := 0; + end + else begin + Result := TraceTransactionVTable(vTable).getInitialID(Self); + end; end; function ITraceTransaction.getPreviousID(): Int64; begin - Result := TraceTransactionVTable(vTable).getPreviousID(Self); + if (vTable.version < 3) then begin + Result := 0; + end + else begin + Result := TraceTransactionVTable(vTable).getPreviousID(Self); + end; end; function ITraceParams.getCount(): Cardinal; @@ -7687,7 +8621,13 @@ function ITraceParams.getParam(idx: Cardinal): dscPtr; function ITraceParams.getTextUTF8(status: IStatus; idx: Cardinal): PAnsiChar; begin - Result := TraceParamsVTable(vTable).getTextUTF8(Self, status, idx); + if (vTable.version < 3) then begin + FbException.setVersionError(status, 'ITraceParams', vTable.version, 3); + Result := nil; + end + else begin + Result := TraceParamsVTable(vTable).getTextUTF8(Self, status, idx); + end; FbException.checkException(status); end; @@ -7898,7 +8838,13 @@ function ITraceLogWriter.write(buf: Pointer; size: Cardinal): Cardinal; function ITraceLogWriter.write_s(status: IStatus; buf: Pointer; size: Cardinal): Cardinal; begin - Result := TraceLogWriterVTable(vTable).write_s(Self, status, buf, size); + if (vTable.version < 4) then begin + FbException.setVersionError(status, 'ITraceLogWriter', vTable.version, 4); + Result := 0; + end + else begin + Result := TraceLogWriterVTable(vTable).write_s(Self, status, buf, size); + end; FbException.checkException(status); end; @@ -8042,6 +8988,16 @@ function ITracePlugin.trace_func_execute(connection: ITraceDatabaseConnection; t Result := TracePluginVTable(vTable).trace_func_execute(Self, connection, transaction, function_, started, func_result); end; +function ITracePlugin.trace_dsql_restart(connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; number: Cardinal): Boolean; +begin + if (vTable.version < 4) then begin + Result := true; + end + else begin + Result := TracePluginVTable(vTable).trace_dsql_restart(Self, connection, transaction, statement, number); + end; +end; + function ITraceFactory.trace_needs(): QWord; begin Result := TraceFactoryVTable(vTable).trace_needs(Self); @@ -8332,6 +9288,7 @@ procedure IReferenceCountedImpl_addRefDispatcher(this: IReferenceCounted); cdecl function IReferenceCountedImpl_releaseDispatcher(this: IReferenceCounted): Integer; cdecl; begin + Result := 0; try Result := IReferenceCountedImpl(this).release(); except @@ -8384,6 +9341,7 @@ procedure IStatusImpl_initDispatcher(this: IStatus); cdecl; function IStatusImpl_getStateDispatcher(this: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IStatusImpl(this).getState(); except @@ -8429,6 +9387,7 @@ procedure IStatusImpl_setWarningsDispatcher(this: IStatus; value: NativeIntPtr); function IStatusImpl_getErrorsDispatcher(this: IStatus): NativeIntPtr; cdecl; begin + Result := nil; try Result := IStatusImpl(this).getErrors(); except @@ -8438,6 +9397,7 @@ function IStatusImpl_getErrorsDispatcher(this: IStatus): NativeIntPtr; cdecl; function IStatusImpl_getWarningsDispatcher(this: IStatus): NativeIntPtr; cdecl; begin + Result := nil; try Result := IStatusImpl(this).getWarnings(); except @@ -8447,6 +9407,7 @@ function IStatusImpl_getWarningsDispatcher(this: IStatus): NativeIntPtr; cdecl; function IStatusImpl_cloneDispatcher(this: IStatus): IStatus; cdecl; begin + Result := nil; try Result := IStatusImpl(this).clone(); except @@ -8464,6 +9425,7 @@ constructor IStatusImpl.create; function IMasterImpl_getStatusDispatcher(this: IMaster): IStatus; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getStatus(); except @@ -8473,6 +9435,7 @@ function IMasterImpl_getStatusDispatcher(this: IMaster): IStatus; cdecl; function IMasterImpl_getDispatcherDispatcher(this: IMaster): IProvider; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getDispatcher(); except @@ -8482,6 +9445,7 @@ function IMasterImpl_getDispatcherDispatcher(this: IMaster): IProvider; cdecl; function IMasterImpl_getPluginManagerDispatcher(this: IMaster): IPluginManager; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getPluginManager(); except @@ -8491,6 +9455,7 @@ function IMasterImpl_getPluginManagerDispatcher(this: IMaster): IPluginManager; function IMasterImpl_getTimerControlDispatcher(this: IMaster): ITimerControl; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getTimerControl(); except @@ -8500,6 +9465,7 @@ function IMasterImpl_getTimerControlDispatcher(this: IMaster): ITimerControl; cd function IMasterImpl_getDtcDispatcher(this: IMaster): IDtc; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getDtc(); except @@ -8509,6 +9475,7 @@ function IMasterImpl_getDtcDispatcher(this: IMaster): IDtc; cdecl; function IMasterImpl_registerAttachmentDispatcher(this: IMaster; provider: IProvider; attachment: IAttachment): IAttachment; cdecl; begin + Result := nil; try Result := IMasterImpl(this).registerAttachment(provider, attachment); except @@ -8518,6 +9485,7 @@ function IMasterImpl_registerAttachmentDispatcher(this: IMaster; provider: IProv function IMasterImpl_registerTransactionDispatcher(this: IMaster; attachment: IAttachment; transaction: ITransaction): ITransaction; cdecl; begin + Result := nil; try Result := IMasterImpl(this).registerTransaction(attachment, transaction); except @@ -8527,6 +9495,7 @@ function IMasterImpl_registerTransactionDispatcher(this: IMaster; attachment: IA function IMasterImpl_getMetadataBuilderDispatcher(this: IMaster; status: IStatus; fieldCount: Cardinal): IMetadataBuilder; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getMetadataBuilder(status, fieldCount); except @@ -8536,6 +9505,7 @@ function IMasterImpl_getMetadataBuilderDispatcher(this: IMaster; status: IStatus function IMasterImpl_serverModeDispatcher(this: IMaster; mode: Integer): Integer; cdecl; begin + Result := 0; try Result := IMasterImpl(this).serverMode(mode); except @@ -8545,6 +9515,7 @@ function IMasterImpl_serverModeDispatcher(this: IMaster; mode: Integer): Integer function IMasterImpl_getUtilInterfaceDispatcher(this: IMaster): IUtil; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getUtilInterface(); except @@ -8554,6 +9525,7 @@ function IMasterImpl_getUtilInterfaceDispatcher(this: IMaster): IUtil; cdecl; function IMasterImpl_getConfigManagerDispatcher(this: IMaster): IConfigManager; cdecl; begin + Result := nil; try Result := IMasterImpl(this).getConfigManager(); except @@ -8563,6 +9535,7 @@ function IMasterImpl_getConfigManagerDispatcher(this: IMaster): IConfigManager; function IMasterImpl_getProcessExitingDispatcher(this: IMaster): Boolean; cdecl; begin + Result := false; try Result := IMasterImpl(this).getProcessExiting(); except @@ -8589,6 +9562,7 @@ procedure IPluginBaseImpl_addRefDispatcher(this: IPluginBase); cdecl; function IPluginBaseImpl_releaseDispatcher(this: IPluginBase): Integer; cdecl; begin + Result := 0; try Result := IPluginBaseImpl(this).release(); except @@ -8607,6 +9581,7 @@ procedure IPluginBaseImpl_setOwnerDispatcher(this: IPluginBase; r: IReferenceCou function IPluginBaseImpl_getOwnerDispatcher(this: IPluginBase): IReferenceCounted; cdecl; begin + Result := nil; try Result := IPluginBaseImpl(this).getOwner(); except @@ -8633,6 +9608,7 @@ procedure IPluginSetImpl_addRefDispatcher(this: IPluginSet); cdecl; function IPluginSetImpl_releaseDispatcher(this: IPluginSet): Integer; cdecl; begin + Result := 0; try Result := IPluginSetImpl(this).release(); except @@ -8642,6 +9618,7 @@ function IPluginSetImpl_releaseDispatcher(this: IPluginSet): Integer; cdecl; function IPluginSetImpl_getNameDispatcher(this: IPluginSet): PAnsiChar; cdecl; begin + Result := nil; try Result := IPluginSetImpl(this).getName(); except @@ -8651,6 +9628,7 @@ function IPluginSetImpl_getNameDispatcher(this: IPluginSet): PAnsiChar; cdecl; function IPluginSetImpl_getModuleNameDispatcher(this: IPluginSet): PAnsiChar; cdecl; begin + Result := nil; try Result := IPluginSetImpl(this).getModuleName(); except @@ -8660,6 +9638,7 @@ function IPluginSetImpl_getModuleNameDispatcher(this: IPluginSet): PAnsiChar; cd function IPluginSetImpl_getPluginDispatcher(this: IPluginSet; status: IStatus): IPluginBase; cdecl; begin + Result := nil; try Result := IPluginSetImpl(this).getPlugin(status); except @@ -8704,6 +9683,7 @@ procedure IConfigEntryImpl_addRefDispatcher(this: IConfigEntry); cdecl; function IConfigEntryImpl_releaseDispatcher(this: IConfigEntry): Integer; cdecl; begin + Result := 0; try Result := IConfigEntryImpl(this).release(); except @@ -8713,6 +9693,7 @@ function IConfigEntryImpl_releaseDispatcher(this: IConfigEntry): Integer; cdecl; function IConfigEntryImpl_getNameDispatcher(this: IConfigEntry): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigEntryImpl(this).getName(); except @@ -8722,6 +9703,7 @@ function IConfigEntryImpl_getNameDispatcher(this: IConfigEntry): PAnsiChar; cdec function IConfigEntryImpl_getValueDispatcher(this: IConfigEntry): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigEntryImpl(this).getValue(); except @@ -8731,6 +9713,7 @@ function IConfigEntryImpl_getValueDispatcher(this: IConfigEntry): PAnsiChar; cde function IConfigEntryImpl_getIntValueDispatcher(this: IConfigEntry): Int64; cdecl; begin + Result := 0; try Result := IConfigEntryImpl(this).getIntValue(); except @@ -8740,6 +9723,7 @@ function IConfigEntryImpl_getIntValueDispatcher(this: IConfigEntry): Int64; cdec function IConfigEntryImpl_getBoolValueDispatcher(this: IConfigEntry): Boolean; cdecl; begin + Result := false; try Result := IConfigEntryImpl(this).getBoolValue(); except @@ -8749,6 +9733,7 @@ function IConfigEntryImpl_getBoolValueDispatcher(this: IConfigEntry): Boolean; c function IConfigEntryImpl_getSubConfigDispatcher(this: IConfigEntry; status: IStatus): IConfig; cdecl; begin + Result := nil; try Result := IConfigEntryImpl(this).getSubConfig(status); except @@ -8775,6 +9760,7 @@ procedure IConfigImpl_addRefDispatcher(this: IConfig); cdecl; function IConfigImpl_releaseDispatcher(this: IConfig): Integer; cdecl; begin + Result := 0; try Result := IConfigImpl(this).release(); except @@ -8784,6 +9770,7 @@ function IConfigImpl_releaseDispatcher(this: IConfig): Integer; cdecl; function IConfigImpl_findDispatcher(this: IConfig; status: IStatus; name: PAnsiChar): IConfigEntry; cdecl; begin + Result := nil; try Result := IConfigImpl(this).find(status, name); except @@ -8793,6 +9780,7 @@ function IConfigImpl_findDispatcher(this: IConfig; status: IStatus; name: PAnsiC function IConfigImpl_findValueDispatcher(this: IConfig; status: IStatus; name: PAnsiChar; value: PAnsiChar): IConfigEntry; cdecl; begin + Result := nil; try Result := IConfigImpl(this).findValue(status, name, value); except @@ -8802,6 +9790,7 @@ function IConfigImpl_findValueDispatcher(this: IConfig; status: IStatus; name: P function IConfigImpl_findPosDispatcher(this: IConfig; status: IStatus; name: PAnsiChar; pos: Cardinal): IConfigEntry; cdecl; begin + Result := nil; try Result := IConfigImpl(this).findPos(status, name, pos); except @@ -8828,6 +9817,7 @@ procedure IFirebirdConfImpl_addRefDispatcher(this: IFirebirdConf); cdecl; function IFirebirdConfImpl_releaseDispatcher(this: IFirebirdConf): Integer; cdecl; begin + Result := 0; try Result := IFirebirdConfImpl(this).release(); except @@ -8837,6 +9827,7 @@ function IFirebirdConfImpl_releaseDispatcher(this: IFirebirdConf): Integer; cdec function IFirebirdConfImpl_getKeyDispatcher(this: IFirebirdConf; name: PAnsiChar): Cardinal; cdecl; begin + Result := 0; try Result := IFirebirdConfImpl(this).getKey(name); except @@ -8846,6 +9837,7 @@ function IFirebirdConfImpl_getKeyDispatcher(this: IFirebirdConf; name: PAnsiChar function IFirebirdConfImpl_asIntegerDispatcher(this: IFirebirdConf; key: Cardinal): Int64; cdecl; begin + Result := 0; try Result := IFirebirdConfImpl(this).asInteger(key); except @@ -8855,6 +9847,7 @@ function IFirebirdConfImpl_asIntegerDispatcher(this: IFirebirdConf; key: Cardina function IFirebirdConfImpl_asStringDispatcher(this: IFirebirdConf; key: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IFirebirdConfImpl(this).asString(key); except @@ -8864,6 +9857,7 @@ function IFirebirdConfImpl_asStringDispatcher(this: IFirebirdConf; key: Cardinal function IFirebirdConfImpl_asBooleanDispatcher(this: IFirebirdConf; key: Cardinal): Boolean; cdecl; begin + Result := false; try Result := IFirebirdConfImpl(this).asBoolean(key); except @@ -8873,6 +9867,7 @@ function IFirebirdConfImpl_asBooleanDispatcher(this: IFirebirdConf; key: Cardina function IFirebirdConfImpl_getVersionDispatcher(this: IFirebirdConf; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IFirebirdConfImpl(this).getVersion(status); except @@ -8899,6 +9894,7 @@ procedure IPluginConfigImpl_addRefDispatcher(this: IPluginConfig); cdecl; function IPluginConfigImpl_releaseDispatcher(this: IPluginConfig): Integer; cdecl; begin + Result := 0; try Result := IPluginConfigImpl(this).release(); except @@ -8908,6 +9904,7 @@ function IPluginConfigImpl_releaseDispatcher(this: IPluginConfig): Integer; cdec function IPluginConfigImpl_getConfigFileNameDispatcher(this: IPluginConfig): PAnsiChar; cdecl; begin + Result := nil; try Result := IPluginConfigImpl(this).getConfigFileName(); except @@ -8917,6 +9914,7 @@ function IPluginConfigImpl_getConfigFileNameDispatcher(this: IPluginConfig): PAn function IPluginConfigImpl_getDefaultConfigDispatcher(this: IPluginConfig; status: IStatus): IConfig; cdecl; begin + Result := nil; try Result := IPluginConfigImpl(this).getDefaultConfig(status); except @@ -8926,6 +9924,7 @@ function IPluginConfigImpl_getDefaultConfigDispatcher(this: IPluginConfig; statu function IPluginConfigImpl_getFirebirdConfDispatcher(this: IPluginConfig; status: IStatus): IFirebirdConf; cdecl; begin + Result := nil; try Result := IPluginConfigImpl(this).getFirebirdConf(status); except @@ -8952,6 +9951,7 @@ constructor IPluginConfigImpl.create; function IPluginFactoryImpl_createPluginDispatcher(this: IPluginFactory; status: IStatus; factoryParameter: IPluginConfig): IPluginBase; cdecl; begin + Result := nil; try Result := IPluginFactoryImpl(this).createPlugin(status, factoryParameter); except @@ -9022,6 +10022,7 @@ procedure IPluginManagerImpl_unregisterModuleDispatcher(this: IPluginManager; cl function IPluginManagerImpl_getPluginsDispatcher(this: IPluginManager; status: IStatus; pluginType: Cardinal; namesList: PAnsiChar; firebirdConf: IFirebirdConf): IPluginSet; cdecl; begin + Result := nil; try Result := IPluginManagerImpl(this).getPlugins(status, pluginType, namesList, firebirdConf); except @@ -9031,6 +10032,7 @@ function IPluginManagerImpl_getPluginsDispatcher(this: IPluginManager; status: I function IPluginManagerImpl_getConfigDispatcher(this: IPluginManager; status: IStatus; filename: PAnsiChar): IConfig; cdecl; begin + Result := nil; try Result := IPluginManagerImpl(this).getConfig(status, filename); except @@ -9075,6 +10077,7 @@ procedure ICryptKeyImpl_setAsymmetricDispatcher(this: ICryptKey; status: IStatus function ICryptKeyImpl_getEncryptKeyDispatcher(this: ICryptKey; length: CardinalPtr): Pointer; cdecl; begin + Result := nil; try Result := ICryptKeyImpl(this).getEncryptKey(length); except @@ -9084,6 +10087,7 @@ function ICryptKeyImpl_getEncryptKeyDispatcher(this: ICryptKey; length: Cardinal function ICryptKeyImpl_getDecryptKeyDispatcher(this: ICryptKey; length: CardinalPtr): Pointer; cdecl; begin + Result := nil; try Result := ICryptKeyImpl(this).getDecryptKey(length); except @@ -9101,6 +10105,7 @@ constructor ICryptKeyImpl.create; function IConfigManagerImpl_getDirectoryDispatcher(this: IConfigManager; code: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getDirectory(code); except @@ -9110,6 +10115,7 @@ function IConfigManagerImpl_getDirectoryDispatcher(this: IConfigManager; code: C function IConfigManagerImpl_getFirebirdConfDispatcher(this: IConfigManager): IFirebirdConf; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getFirebirdConf(); except @@ -9119,6 +10125,7 @@ function IConfigManagerImpl_getFirebirdConfDispatcher(this: IConfigManager): IFi function IConfigManagerImpl_getDatabaseConfDispatcher(this: IConfigManager; dbName: PAnsiChar): IFirebirdConf; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getDatabaseConf(dbName); except @@ -9128,6 +10135,7 @@ function IConfigManagerImpl_getDatabaseConfDispatcher(this: IConfigManager; dbNa function IConfigManagerImpl_getPluginConfigDispatcher(this: IConfigManager; configuredPlugin: PAnsiChar): IConfig; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getPluginConfig(configuredPlugin); except @@ -9137,6 +10145,7 @@ function IConfigManagerImpl_getPluginConfigDispatcher(this: IConfigManager; conf function IConfigManagerImpl_getInstallDirectoryDispatcher(this: IConfigManager): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getInstallDirectory(); except @@ -9146,6 +10155,7 @@ function IConfigManagerImpl_getInstallDirectoryDispatcher(this: IConfigManager): function IConfigManagerImpl_getRootDirectoryDispatcher(this: IConfigManager): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getRootDirectory(); except @@ -9155,6 +10165,7 @@ function IConfigManagerImpl_getRootDirectoryDispatcher(this: IConfigManager): PA function IConfigManagerImpl_getDefaultSecurityDbDispatcher(this: IConfigManager): PAnsiChar; cdecl; begin + Result := nil; try Result := IConfigManagerImpl(this).getDefaultSecurityDb(); except @@ -9181,6 +10192,7 @@ procedure IEventCallbackImpl_addRefDispatcher(this: IEventCallback); cdecl; function IEventCallbackImpl_releaseDispatcher(this: IEventCallback): Integer; cdecl; begin + Result := 0; try Result := IEventCallbackImpl(this).release(); except @@ -9216,6 +10228,7 @@ procedure IBlobImpl_addRefDispatcher(this: IBlob); cdecl; function IBlobImpl_releaseDispatcher(this: IBlob): Integer; cdecl; begin + Result := 0; try Result := IBlobImpl(this).release(); except @@ -9234,6 +10247,7 @@ procedure IBlobImpl_getInfoDispatcher(this: IBlob; status: IStatus; itemsLength: function IBlobImpl_getSegmentDispatcher(this: IBlob; status: IStatus; bufferLength: Cardinal; buffer: Pointer; segmentLength: CardinalPtr): Integer; cdecl; begin + Result := 0; try Result := IBlobImpl(this).getSegment(status, bufferLength, buffer, segmentLength); except @@ -9250,19 +10264,19 @@ procedure IBlobImpl_putSegmentDispatcher(this: IBlob; status: IStatus; length: C end end; -procedure IBlobImpl_cancelDispatcher(this: IBlob; status: IStatus); cdecl; +procedure IBlobImpl_deprecatedCancelDispatcher(this: IBlob; status: IStatus); cdecl; begin try - IBlobImpl(this).cancel(status); + IBlobImpl(this).deprecatedCancel(status); except on e: Exception do FbException.catchException(status, e); end end; -procedure IBlobImpl_closeDispatcher(this: IBlob; status: IStatus); cdecl; +procedure IBlobImpl_deprecatedCloseDispatcher(this: IBlob; status: IStatus); cdecl; begin try - IBlobImpl(this).close(status); + IBlobImpl(this).deprecatedClose(status); except on e: Exception do FbException.catchException(status, e); end @@ -9270,6 +10284,7 @@ procedure IBlobImpl_closeDispatcher(this: IBlob; status: IStatus); cdecl; function IBlobImpl_seekDispatcher(this: IBlob; status: IStatus; mode: Integer; offset: Integer): Integer; cdecl; begin + Result := 0; try Result := IBlobImpl(this).seek(status, mode, offset); except @@ -9277,6 +10292,24 @@ function IBlobImpl_seekDispatcher(this: IBlob; status: IStatus; mode: Integer; o end end; +procedure IBlobImpl_cancelDispatcher(this: IBlob; status: IStatus); cdecl; +begin + try + IBlobImpl(this).cancel(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IBlobImpl_closeDispatcher(this: IBlob; status: IStatus); cdecl; +begin + try + IBlobImpl(this).close(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IBlobImpl_vTable: BlobVTable; @@ -9296,6 +10329,7 @@ procedure ITransactionImpl_addRefDispatcher(this: ITransaction); cdecl; function ITransactionImpl_releaseDispatcher(this: ITransaction): Integer; cdecl; begin + Result := 0; try Result := ITransactionImpl(this).release(); except @@ -9321,10 +10355,10 @@ procedure ITransactionImpl_prepareDispatcher(this: ITransaction; status: IStatus end end; -procedure ITransactionImpl_commitDispatcher(this: ITransaction; status: IStatus); cdecl; +procedure ITransactionImpl_deprecatedCommitDispatcher(this: ITransaction; status: IStatus); cdecl; begin try - ITransactionImpl(this).commit(status); + ITransactionImpl(this).deprecatedCommit(status); except on e: Exception do FbException.catchException(status, e); end @@ -9339,10 +10373,10 @@ procedure ITransactionImpl_commitRetainingDispatcher(this: ITransaction; status: end end; -procedure ITransactionImpl_rollbackDispatcher(this: ITransaction; status: IStatus); cdecl; +procedure ITransactionImpl_deprecatedRollbackDispatcher(this: ITransaction; status: IStatus); cdecl; begin try - ITransactionImpl(this).rollback(status); + ITransactionImpl(this).deprecatedRollback(status); except on e: Exception do FbException.catchException(status, e); end @@ -9357,10 +10391,10 @@ procedure ITransactionImpl_rollbackRetainingDispatcher(this: ITransaction; statu end end; -procedure ITransactionImpl_disconnectDispatcher(this: ITransaction; status: IStatus); cdecl; +procedure ITransactionImpl_deprecatedDisconnectDispatcher(this: ITransaction; status: IStatus); cdecl; begin try - ITransactionImpl(this).disconnect(status); + ITransactionImpl(this).deprecatedDisconnect(status); except on e: Exception do FbException.catchException(status, e); end @@ -9368,6 +10402,7 @@ procedure ITransactionImpl_disconnectDispatcher(this: ITransaction; status: ISta function ITransactionImpl_joinDispatcher(this: ITransaction; status: IStatus; transaction: ITransaction): ITransaction; cdecl; begin + Result := nil; try Result := ITransactionImpl(this).join(status, transaction); except @@ -9377,6 +10412,7 @@ function ITransactionImpl_joinDispatcher(this: ITransaction; status: IStatus; tr function ITransactionImpl_validateDispatcher(this: ITransaction; status: IStatus; attachment: IAttachment): ITransaction; cdecl; begin + Result := nil; try Result := ITransactionImpl(this).validate(status, attachment); except @@ -9386,6 +10422,7 @@ function ITransactionImpl_validateDispatcher(this: ITransaction; status: IStatus function ITransactionImpl_enterDtcDispatcher(this: ITransaction; status: IStatus): ITransaction; cdecl; begin + Result := nil; try Result := ITransactionImpl(this).enterDtc(status); except @@ -9393,6 +10430,33 @@ function ITransactionImpl_enterDtcDispatcher(this: ITransaction; status: IStatus end end; +procedure ITransactionImpl_commitDispatcher(this: ITransaction; status: IStatus); cdecl; +begin + try + ITransactionImpl(this).commit(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure ITransactionImpl_rollbackDispatcher(this: ITransaction; status: IStatus); cdecl; +begin + try + ITransactionImpl(this).rollback(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure ITransactionImpl_disconnectDispatcher(this: ITransaction; status: IStatus); cdecl; +begin + try + ITransactionImpl(this).disconnect(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var ITransactionImpl_vTable: TransactionVTable; @@ -9412,6 +10476,7 @@ procedure IMessageMetadataImpl_addRefDispatcher(this: IMessageMetadata); cdecl; function IMessageMetadataImpl_releaseDispatcher(this: IMessageMetadata): Integer; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).release(); except @@ -9421,6 +10486,7 @@ function IMessageMetadataImpl_releaseDispatcher(this: IMessageMetadata): Integer function IMessageMetadataImpl_getCountDispatcher(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getCount(status); except @@ -9430,6 +10496,7 @@ function IMessageMetadataImpl_getCountDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_getFieldDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IMessageMetadataImpl(this).getField(status, index); except @@ -9439,6 +10506,7 @@ function IMessageMetadataImpl_getFieldDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_getRelationDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IMessageMetadataImpl(this).getRelation(status, index); except @@ -9448,6 +10516,7 @@ function IMessageMetadataImpl_getRelationDispatcher(this: IMessageMetadata; stat function IMessageMetadataImpl_getOwnerDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IMessageMetadataImpl(this).getOwner(status, index); except @@ -9457,6 +10526,7 @@ function IMessageMetadataImpl_getOwnerDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_getAliasDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := IMessageMetadataImpl(this).getAlias(status, index); except @@ -9466,6 +10536,7 @@ function IMessageMetadataImpl_getAliasDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_getTypeDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getType(status, index); except @@ -9475,6 +10546,7 @@ function IMessageMetadataImpl_getTypeDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_isNullableDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Boolean; cdecl; begin + Result := false; try Result := IMessageMetadataImpl(this).isNullable(status, index); except @@ -9484,6 +10556,7 @@ function IMessageMetadataImpl_isNullableDispatcher(this: IMessageMetadata; statu function IMessageMetadataImpl_getSubTypeDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Integer; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getSubType(status, index); except @@ -9493,6 +10566,7 @@ function IMessageMetadataImpl_getSubTypeDispatcher(this: IMessageMetadata; statu function IMessageMetadataImpl_getLengthDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getLength(status, index); except @@ -9502,6 +10576,7 @@ function IMessageMetadataImpl_getLengthDispatcher(this: IMessageMetadata; status function IMessageMetadataImpl_getScaleDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Integer; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getScale(status, index); except @@ -9511,6 +10586,7 @@ function IMessageMetadataImpl_getScaleDispatcher(this: IMessageMetadata; status: function IMessageMetadataImpl_getCharSetDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getCharSet(status, index); except @@ -9520,6 +10596,7 @@ function IMessageMetadataImpl_getCharSetDispatcher(this: IMessageMetadata; statu function IMessageMetadataImpl_getOffsetDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getOffset(status, index); except @@ -9529,6 +10606,7 @@ function IMessageMetadataImpl_getOffsetDispatcher(this: IMessageMetadata; status function IMessageMetadataImpl_getNullOffsetDispatcher(this: IMessageMetadata; status: IStatus; index: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getNullOffset(status, index); except @@ -9538,6 +10616,7 @@ function IMessageMetadataImpl_getNullOffsetDispatcher(this: IMessageMetadata; st function IMessageMetadataImpl_getBuilderDispatcher(this: IMessageMetadata; status: IStatus): IMetadataBuilder; cdecl; begin + Result := nil; try Result := IMessageMetadataImpl(this).getBuilder(status); except @@ -9547,6 +10626,7 @@ function IMessageMetadataImpl_getBuilderDispatcher(this: IMessageMetadata; statu function IMessageMetadataImpl_getMessageLengthDispatcher(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getMessageLength(status); except @@ -9556,6 +10636,7 @@ function IMessageMetadataImpl_getMessageLengthDispatcher(this: IMessageMetadata; function IMessageMetadataImpl_getAlignmentDispatcher(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getAlignment(status); except @@ -9565,6 +10646,7 @@ function IMessageMetadataImpl_getAlignmentDispatcher(this: IMessageMetadata; sta function IMessageMetadataImpl_getAlignedLengthDispatcher(this: IMessageMetadata; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IMessageMetadataImpl(this).getAlignedLength(status); except @@ -9591,6 +10673,7 @@ procedure IMetadataBuilderImpl_addRefDispatcher(this: IMetadataBuilder); cdecl; function IMetadataBuilderImpl_releaseDispatcher(this: IMetadataBuilder): Integer; cdecl; begin + Result := 0; try Result := IMetadataBuilderImpl(this).release(); except @@ -9672,6 +10755,7 @@ procedure IMetadataBuilderImpl_removeDispatcher(this: IMetadataBuilder; status: function IMetadataBuilderImpl_addFieldDispatcher(this: IMetadataBuilder; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IMetadataBuilderImpl(this).addField(status); except @@ -9681,6 +10765,7 @@ function IMetadataBuilderImpl_addFieldDispatcher(this: IMetadataBuilder; status: function IMetadataBuilderImpl_getMetadataDispatcher(this: IMetadataBuilder; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IMetadataBuilderImpl(this).getMetadata(status); except @@ -9743,6 +10828,7 @@ procedure IResultSetImpl_addRefDispatcher(this: IResultSet); cdecl; function IResultSetImpl_releaseDispatcher(this: IResultSet): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).release(); except @@ -9752,6 +10838,7 @@ function IResultSetImpl_releaseDispatcher(this: IResultSet): Integer; cdecl; function IResultSetImpl_fetchNextDispatcher(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchNext(status, message); except @@ -9761,6 +10848,7 @@ function IResultSetImpl_fetchNextDispatcher(this: IResultSet; status: IStatus; m function IResultSetImpl_fetchPriorDispatcher(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchPrior(status, message); except @@ -9770,6 +10858,7 @@ function IResultSetImpl_fetchPriorDispatcher(this: IResultSet; status: IStatus; function IResultSetImpl_fetchFirstDispatcher(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchFirst(status, message); except @@ -9779,6 +10868,7 @@ function IResultSetImpl_fetchFirstDispatcher(this: IResultSet; status: IStatus; function IResultSetImpl_fetchLastDispatcher(this: IResultSet; status: IStatus; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchLast(status, message); except @@ -9788,6 +10878,7 @@ function IResultSetImpl_fetchLastDispatcher(this: IResultSet; status: IStatus; m function IResultSetImpl_fetchAbsoluteDispatcher(this: IResultSet; status: IStatus; position: Integer; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchAbsolute(status, position, message); except @@ -9797,6 +10888,7 @@ function IResultSetImpl_fetchAbsoluteDispatcher(this: IResultSet; status: IStatu function IResultSetImpl_fetchRelativeDispatcher(this: IResultSet; status: IStatus; offset: Integer; message: Pointer): Integer; cdecl; begin + Result := 0; try Result := IResultSetImpl(this).fetchRelative(status, offset, message); except @@ -9806,6 +10898,7 @@ function IResultSetImpl_fetchRelativeDispatcher(this: IResultSet; status: IStatu function IResultSetImpl_isEofDispatcher(this: IResultSet; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IResultSetImpl(this).isEof(status); except @@ -9815,6 +10908,7 @@ function IResultSetImpl_isEofDispatcher(this: IResultSet; status: IStatus): Bool function IResultSetImpl_isBofDispatcher(this: IResultSet; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IResultSetImpl(this).isBof(status); except @@ -9824,6 +10918,7 @@ function IResultSetImpl_isBofDispatcher(this: IResultSet; status: IStatus): Bool function IResultSetImpl_getMetadataDispatcher(this: IResultSet; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IResultSetImpl(this).getMetadata(status); except @@ -9831,10 +10926,10 @@ function IResultSetImpl_getMetadataDispatcher(this: IResultSet; status: IStatus) end end; -procedure IResultSetImpl_closeDispatcher(this: IResultSet; status: IStatus); cdecl; +procedure IResultSetImpl_deprecatedCloseDispatcher(this: IResultSet; status: IStatus); cdecl; begin try - IResultSetImpl(this).close(status); + IResultSetImpl(this).deprecatedClose(status); except on e: Exception do FbException.catchException(status, e); end @@ -9849,6 +10944,15 @@ procedure IResultSetImpl_setDelayedOutputFormatDispatcher(this: IResultSet; stat end end; +procedure IResultSetImpl_closeDispatcher(this: IResultSet; status: IStatus); cdecl; +begin + try + IResultSetImpl(this).close(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IResultSetImpl_vTable: ResultSetVTable; @@ -9868,6 +10972,7 @@ procedure IStatementImpl_addRefDispatcher(this: IStatement); cdecl; function IStatementImpl_releaseDispatcher(this: IStatement): Integer; cdecl; begin + Result := 0; try Result := IStatementImpl(this).release(); except @@ -9886,6 +10991,7 @@ procedure IStatementImpl_getInfoDispatcher(this: IStatement; status: IStatus; it function IStatementImpl_getTypeDispatcher(this: IStatement; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IStatementImpl(this).getType(status); except @@ -9895,6 +11001,7 @@ function IStatementImpl_getTypeDispatcher(this: IStatement; status: IStatus): Ca function IStatementImpl_getPlanDispatcher(this: IStatement; status: IStatus; detailed: Boolean): PAnsiChar; cdecl; begin + Result := nil; try Result := IStatementImpl(this).getPlan(status, detailed); except @@ -9904,6 +11011,7 @@ function IStatementImpl_getPlanDispatcher(this: IStatement; status: IStatus; det function IStatementImpl_getAffectedRecordsDispatcher(this: IStatement; status: IStatus): QWord; cdecl; begin + Result := 0; try Result := IStatementImpl(this).getAffectedRecords(status); except @@ -9913,6 +11021,7 @@ function IStatementImpl_getAffectedRecordsDispatcher(this: IStatement; status: I function IStatementImpl_getInputMetadataDispatcher(this: IStatement; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IStatementImpl(this).getInputMetadata(status); except @@ -9922,6 +11031,7 @@ function IStatementImpl_getInputMetadataDispatcher(this: IStatement; status: ISt function IStatementImpl_getOutputMetadataDispatcher(this: IStatement; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IStatementImpl(this).getOutputMetadata(status); except @@ -9931,6 +11041,7 @@ function IStatementImpl_getOutputMetadataDispatcher(this: IStatement; status: IS function IStatementImpl_executeDispatcher(this: IStatement; status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; outBuffer: Pointer): ITransaction; cdecl; begin + Result := nil; try Result := IStatementImpl(this).execute(status, transaction, inMetadata, inBuffer, outMetadata, outBuffer); except @@ -9940,6 +11051,7 @@ function IStatementImpl_executeDispatcher(this: IStatement; status: IStatus; tra function IStatementImpl_openCursorDispatcher(this: IStatement; status: IStatus; transaction: ITransaction; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; flags: Cardinal): IResultSet; cdecl; begin + Result := nil; try Result := IStatementImpl(this).openCursor(status, transaction, inMetadata, inBuffer, outMetadata, flags); except @@ -9956,10 +11068,10 @@ procedure IStatementImpl_setCursorNameDispatcher(this: IStatement; status: IStat end end; -procedure IStatementImpl_freeDispatcher(this: IStatement; status: IStatus); cdecl; +procedure IStatementImpl_deprecatedFreeDispatcher(this: IStatement; status: IStatus); cdecl; begin try - IStatementImpl(this).free(status); + IStatementImpl(this).deprecatedFree(status); except on e: Exception do FbException.catchException(status, e); end @@ -9967,6 +11079,7 @@ procedure IStatementImpl_freeDispatcher(this: IStatement; status: IStatus); cdec function IStatementImpl_getFlagsDispatcher(this: IStatement; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IStatementImpl(this).getFlags(status); except @@ -9976,6 +11089,7 @@ function IStatementImpl_getFlagsDispatcher(this: IStatement; status: IStatus): C function IStatementImpl_getTimeoutDispatcher(this: IStatement; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IStatementImpl(this).getTimeout(status); except @@ -9994,6 +11108,7 @@ procedure IStatementImpl_setTimeoutDispatcher(this: IStatement; status: IStatus; function IStatementImpl_createBatchDispatcher(this: IStatement; status: IStatus; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; cdecl; begin + Result := nil; try Result := IStatementImpl(this).createBatch(status, inMetadata, parLength, par); except @@ -10001,6 +11116,15 @@ function IStatementImpl_createBatchDispatcher(this: IStatement; status: IStatus; end end; +procedure IStatementImpl_freeDispatcher(this: IStatement; status: IStatus); cdecl; +begin + try + IStatementImpl(this).free(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IStatementImpl_vTable: StatementVTable; @@ -10020,6 +11144,7 @@ procedure IBatchImpl_addRefDispatcher(this: IBatch); cdecl; function IBatchImpl_releaseDispatcher(this: IBatch): Integer; cdecl; begin + Result := 0; try Result := IBatchImpl(this).release(); except @@ -10074,6 +11199,7 @@ procedure IBatchImpl_registerBlobDispatcher(this: IBatch; status: IStatus; exist function IBatchImpl_executeDispatcher(this: IBatch; status: IStatus; transaction: ITransaction): IBatchCompletionState; cdecl; begin + Result := nil; try Result := IBatchImpl(this).execute(status, transaction); except @@ -10092,6 +11218,7 @@ procedure IBatchImpl_cancelDispatcher(this: IBatch; status: IStatus); cdecl; function IBatchImpl_getBlobAlignmentDispatcher(this: IBatch; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IBatchImpl(this).getBlobAlignment(status); except @@ -10101,6 +11228,7 @@ function IBatchImpl_getBlobAlignmentDispatcher(this: IBatch; status: IStatus): C function IBatchImpl_getMetadataDispatcher(this: IBatch; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IBatchImpl(this).getMetadata(status); except @@ -10117,6 +11245,15 @@ procedure IBatchImpl_setDefaultBpbDispatcher(this: IBatch; status: IStatus; parL end end; +procedure IBatchImpl_deprecatedCloseDispatcher(this: IBatch; status: IStatus); cdecl; +begin + try + IBatchImpl(this).deprecatedClose(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + procedure IBatchImpl_closeDispatcher(this: IBatch; status: IStatus); cdecl; begin try @@ -10126,6 +11263,15 @@ procedure IBatchImpl_closeDispatcher(this: IBatch; status: IStatus); cdecl; end end; +procedure IBatchImpl_getInfoDispatcher(this: IBatch; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl; +begin + try + IBatchImpl(this).getInfo(status, itemsLength, items, bufferLength, buffer); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IBatchImpl_vTable: BatchVTable; @@ -10145,6 +11291,7 @@ procedure IBatchCompletionStateImpl_disposeDispatcher(this: IBatchCompletionStat function IBatchCompletionStateImpl_getSizeDispatcher(this: IBatchCompletionState; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IBatchCompletionStateImpl(this).getSize(status); except @@ -10154,6 +11301,7 @@ function IBatchCompletionStateImpl_getSizeDispatcher(this: IBatchCompletionState function IBatchCompletionStateImpl_getStateDispatcher(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Integer; cdecl; begin + Result := 0; try Result := IBatchCompletionStateImpl(this).getState(status, pos); except @@ -10163,6 +11311,7 @@ function IBatchCompletionStateImpl_getStateDispatcher(this: IBatchCompletionStat function IBatchCompletionStateImpl_findErrorDispatcher(this: IBatchCompletionState; status: IStatus; pos: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := IBatchCompletionStateImpl(this).findError(status, pos); except @@ -10198,6 +11347,7 @@ procedure IReplicatorImpl_addRefDispatcher(this: IReplicator); cdecl; function IReplicatorImpl_releaseDispatcher(this: IReplicator): Integer; cdecl; begin + Result := 0; try Result := IReplicatorImpl(this).release(); except @@ -10214,6 +11364,15 @@ procedure IReplicatorImpl_processDispatcher(this: IReplicator; status: IStatus; end end; +procedure IReplicatorImpl_deprecatedCloseDispatcher(this: IReplicator; status: IStatus); cdecl; +begin + try + IReplicatorImpl(this).deprecatedClose(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + procedure IReplicatorImpl_closeDispatcher(this: IReplicator; status: IStatus); cdecl; begin try @@ -10242,6 +11401,7 @@ procedure IRequestImpl_addRefDispatcher(this: IRequest); cdecl; function IRequestImpl_releaseDispatcher(this: IRequest): Integer; cdecl; begin + Result := 0; try Result := IRequestImpl(this).release(); except @@ -10303,6 +11463,15 @@ procedure IRequestImpl_unwindDispatcher(this: IRequest; status: IStatus; level: end end; +procedure IRequestImpl_deprecatedFreeDispatcher(this: IRequest; status: IStatus); cdecl; +begin + try + IRequestImpl(this).deprecatedFree(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + procedure IRequestImpl_freeDispatcher(this: IRequest; status: IStatus); cdecl; begin try @@ -10331,6 +11500,7 @@ procedure IEventsImpl_addRefDispatcher(this: IEvents); cdecl; function IEventsImpl_releaseDispatcher(this: IEvents): Integer; cdecl; begin + Result := 0; try Result := IEventsImpl(this).release(); except @@ -10338,6 +11508,15 @@ function IEventsImpl_releaseDispatcher(this: IEvents): Integer; cdecl; end end; +procedure IEventsImpl_deprecatedCancelDispatcher(this: IEvents; status: IStatus); cdecl; +begin + try + IEventsImpl(this).deprecatedCancel(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + procedure IEventsImpl_cancelDispatcher(this: IEvents; status: IStatus); cdecl; begin try @@ -10366,6 +11545,7 @@ procedure IAttachmentImpl_addRefDispatcher(this: IAttachment); cdecl; function IAttachmentImpl_releaseDispatcher(this: IAttachment): Integer; cdecl; begin + Result := 0; try Result := IAttachmentImpl(this).release(); except @@ -10384,6 +11564,7 @@ procedure IAttachmentImpl_getInfoDispatcher(this: IAttachment; status: IStatus; function IAttachmentImpl_startTransactionDispatcher(this: IAttachment; status: IStatus; tpbLength: Cardinal; tpb: BytePtr): ITransaction; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).startTransaction(status, tpbLength, tpb); except @@ -10393,6 +11574,7 @@ function IAttachmentImpl_startTransactionDispatcher(this: IAttachment; status: I function IAttachmentImpl_reconnectTransactionDispatcher(this: IAttachment; status: IStatus; length: Cardinal; id: BytePtr): ITransaction; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).reconnectTransaction(status, length, id); except @@ -10402,6 +11584,7 @@ function IAttachmentImpl_reconnectTransactionDispatcher(this: IAttachment; statu function IAttachmentImpl_compileRequestDispatcher(this: IAttachment; status: IStatus; blrLength: Cardinal; blr: BytePtr): IRequest; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).compileRequest(status, blrLength, blr); except @@ -10420,6 +11603,7 @@ procedure IAttachmentImpl_transactRequestDispatcher(this: IAttachment; status: I function IAttachmentImpl_createBlobDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; id: ISC_QUADPtr; bpbLength: Cardinal; bpb: BytePtr): IBlob; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).createBlob(status, transaction, id, bpbLength, bpb); except @@ -10429,6 +11613,7 @@ function IAttachmentImpl_createBlobDispatcher(this: IAttachment; status: IStatus function IAttachmentImpl_openBlobDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; id: ISC_QUADPtr; bpbLength: Cardinal; bpb: BytePtr): IBlob; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).openBlob(status, transaction, id, bpbLength, bpb); except @@ -10438,6 +11623,7 @@ function IAttachmentImpl_openBlobDispatcher(this: IAttachment; status: IStatus; function IAttachmentImpl_getSliceDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; id: ISC_QUADPtr; sdlLength: Cardinal; sdl: BytePtr; paramLength: Cardinal; param: BytePtr; sliceLength: Integer; slice: BytePtr): Integer; cdecl; begin + Result := 0; try Result := IAttachmentImpl(this).getSlice(status, transaction, id, sdlLength, sdl, paramLength, param, sliceLength, slice); except @@ -10465,6 +11651,7 @@ procedure IAttachmentImpl_executeDynDispatcher(this: IAttachment; status: IStatu function IAttachmentImpl_prepareDispatcher(this: IAttachment; status: IStatus; tra: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; flags: Cardinal): IStatement; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).prepare(status, tra, stmtLength, sqlStmt, dialect, flags); except @@ -10474,6 +11661,7 @@ function IAttachmentImpl_prepareDispatcher(this: IAttachment; status: IStatus; t function IAttachmentImpl_executeDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; outBuffer: Pointer): ITransaction; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).execute(status, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, outBuffer); except @@ -10483,6 +11671,7 @@ function IAttachmentImpl_executeDispatcher(this: IAttachment; status: IStatus; t function IAttachmentImpl_openCursorDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; inBuffer: Pointer; outMetadata: IMessageMetadata; cursorName: PAnsiChar; cursorFlags: Cardinal): IResultSet; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).openCursor(status, transaction, stmtLength, sqlStmt, dialect, inMetadata, inBuffer, outMetadata, cursorName, cursorFlags); except @@ -10492,6 +11681,7 @@ function IAttachmentImpl_openCursorDispatcher(this: IAttachment; status: IStatus function IAttachmentImpl_queEventsDispatcher(this: IAttachment; status: IStatus; callback: IEventCallback; length: Cardinal; events: BytePtr): IEvents; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).queEvents(status, callback, length, events); except @@ -10517,19 +11707,19 @@ procedure IAttachmentImpl_pingDispatcher(this: IAttachment; status: IStatus); cd end end; -procedure IAttachmentImpl_detachDispatcher(this: IAttachment; status: IStatus); cdecl; +procedure IAttachmentImpl_deprecatedDetachDispatcher(this: IAttachment; status: IStatus); cdecl; begin try - IAttachmentImpl(this).detach(status); + IAttachmentImpl(this).deprecatedDetach(status); except on e: Exception do FbException.catchException(status, e); end end; -procedure IAttachmentImpl_dropDatabaseDispatcher(this: IAttachment; status: IStatus); cdecl; +procedure IAttachmentImpl_deprecatedDropDatabaseDispatcher(this: IAttachment; status: IStatus); cdecl; begin try - IAttachmentImpl(this).dropDatabase(status); + IAttachmentImpl(this).deprecatedDropDatabase(status); except on e: Exception do FbException.catchException(status, e); end @@ -10537,6 +11727,7 @@ procedure IAttachmentImpl_dropDatabaseDispatcher(this: IAttachment; status: ISta function IAttachmentImpl_getIdleTimeoutDispatcher(this: IAttachment; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IAttachmentImpl(this).getIdleTimeout(status); except @@ -10555,6 +11746,7 @@ procedure IAttachmentImpl_setIdleTimeoutDispatcher(this: IAttachment; status: IS function IAttachmentImpl_getStatementTimeoutDispatcher(this: IAttachment; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IAttachmentImpl(this).getStatementTimeout(status); except @@ -10573,6 +11765,7 @@ procedure IAttachmentImpl_setStatementTimeoutDispatcher(this: IAttachment; statu function IAttachmentImpl_createBatchDispatcher(this: IAttachment; status: IStatus; transaction: ITransaction; stmtLength: Cardinal; sqlStmt: PAnsiChar; dialect: Cardinal; inMetadata: IMessageMetadata; parLength: Cardinal; par: BytePtr): IBatch; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).createBatch(status, transaction, stmtLength, sqlStmt, dialect, inMetadata, parLength, par); except @@ -10582,6 +11775,7 @@ function IAttachmentImpl_createBatchDispatcher(this: IAttachment; status: IStatu function IAttachmentImpl_createReplicatorDispatcher(this: IAttachment; status: IStatus): IReplicator; cdecl; begin + Result := nil; try Result := IAttachmentImpl(this).createReplicator(status); except @@ -10589,6 +11783,24 @@ function IAttachmentImpl_createReplicatorDispatcher(this: IAttachment; status: I end end; +procedure IAttachmentImpl_detachDispatcher(this: IAttachment; status: IStatus); cdecl; +begin + try + IAttachmentImpl(this).detach(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IAttachmentImpl_dropDatabaseDispatcher(this: IAttachment; status: IStatus); cdecl; +begin + try + IAttachmentImpl(this).dropDatabase(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IAttachmentImpl_vTable: AttachmentVTable; @@ -10608,6 +11820,7 @@ procedure IServiceImpl_addRefDispatcher(this: IService); cdecl; function IServiceImpl_releaseDispatcher(this: IService): Integer; cdecl; begin + Result := 0; try Result := IServiceImpl(this).release(); except @@ -10615,10 +11828,10 @@ function IServiceImpl_releaseDispatcher(this: IService): Integer; cdecl; end end; -procedure IServiceImpl_detachDispatcher(this: IService; status: IStatus); cdecl; +procedure IServiceImpl_deprecatedDetachDispatcher(this: IService; status: IStatus); cdecl; begin try - IServiceImpl(this).detach(status); + IServiceImpl(this).deprecatedDetach(status); except on e: Exception do FbException.catchException(status, e); end @@ -10642,6 +11855,24 @@ procedure IServiceImpl_startDispatcher(this: IService; status: IStatus; spbLengt end end; +procedure IServiceImpl_detachDispatcher(this: IService; status: IStatus); cdecl; +begin + try + IServiceImpl(this).detach(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure IServiceImpl_cancelDispatcher(this: IService; status: IStatus); cdecl; +begin + try + IServiceImpl(this).cancel(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var IServiceImpl_vTable: ServiceVTable; @@ -10661,6 +11892,7 @@ procedure IProviderImpl_addRefDispatcher(this: IProvider); cdecl; function IProviderImpl_releaseDispatcher(this: IProvider): Integer; cdecl; begin + Result := 0; try Result := IProviderImpl(this).release(); except @@ -10679,6 +11911,7 @@ procedure IProviderImpl_setOwnerDispatcher(this: IProvider; r: IReferenceCounted function IProviderImpl_getOwnerDispatcher(this: IProvider): IReferenceCounted; cdecl; begin + Result := nil; try Result := IProviderImpl(this).getOwner(); except @@ -10688,6 +11921,7 @@ function IProviderImpl_getOwnerDispatcher(this: IProvider): IReferenceCounted; c function IProviderImpl_attachDatabaseDispatcher(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl; begin + Result := nil; try Result := IProviderImpl(this).attachDatabase(status, fileName, dpbLength, dpb); except @@ -10697,6 +11931,7 @@ function IProviderImpl_attachDatabaseDispatcher(this: IProvider; status: IStatus function IProviderImpl_createDatabaseDispatcher(this: IProvider; status: IStatus; fileName: PAnsiChar; dpbLength: Cardinal; dpb: BytePtr): IAttachment; cdecl; begin + Result := nil; try Result := IProviderImpl(this).createDatabase(status, fileName, dpbLength, dpb); except @@ -10706,6 +11941,7 @@ function IProviderImpl_createDatabaseDispatcher(this: IProvider; status: IStatus function IProviderImpl_attachServiceManagerDispatcher(this: IProvider; status: IStatus; service: PAnsiChar; spbLength: Cardinal; spb: BytePtr): IService; cdecl; begin + Result := nil; try Result := IProviderImpl(this).attachServiceManager(status, service, spbLength, spb); except @@ -10768,6 +12004,7 @@ procedure IDtcStartImpl_addWithTpbDispatcher(this: IDtcStart; status: IStatus; a function IDtcStartImpl_startDispatcher(this: IDtcStart; status: IStatus): ITransaction; cdecl; begin + Result := nil; try Result := IDtcStartImpl(this).start(status); except @@ -10785,6 +12022,7 @@ constructor IDtcStartImpl.create; function IDtcImpl_joinDispatcher(this: IDtc; status: IStatus; one: ITransaction; two: ITransaction): ITransaction; cdecl; begin + Result := nil; try Result := IDtcImpl(this).join(status, one, two); except @@ -10794,6 +12032,7 @@ function IDtcImpl_joinDispatcher(this: IDtc; status: IStatus; one: ITransaction; function IDtcImpl_startBuilderDispatcher(this: IDtc; status: IStatus): IDtcStart; cdecl; begin + Result := nil; try Result := IDtcImpl(this).startBuilder(status); except @@ -10820,6 +12059,7 @@ procedure IAuthImpl_addRefDispatcher(this: IAuth); cdecl; function IAuthImpl_releaseDispatcher(this: IAuth): Integer; cdecl; begin + Result := 0; try Result := IAuthImpl(this).release(); except @@ -10838,6 +12078,7 @@ procedure IAuthImpl_setOwnerDispatcher(this: IAuth; r: IReferenceCounted); cdecl function IAuthImpl_getOwnerDispatcher(this: IAuth): IReferenceCounted; cdecl; begin + Result := nil; try Result := IAuthImpl(this).getOwner(); except @@ -10899,6 +12140,7 @@ constructor IWriterImpl.create; function IServerBlockImpl_getLoginDispatcher(this: IServerBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IServerBlockImpl(this).getLogin(); except @@ -10908,6 +12150,7 @@ function IServerBlockImpl_getLoginDispatcher(this: IServerBlock): PAnsiChar; cde function IServerBlockImpl_getDataDispatcher(this: IServerBlock; length: CardinalPtr): BytePtr; cdecl; begin + Result := nil; try Result := IServerBlockImpl(this).getData(length); except @@ -10926,6 +12169,7 @@ procedure IServerBlockImpl_putDataDispatcher(this: IServerBlock; status: IStatus function IServerBlockImpl_newKeyDispatcher(this: IServerBlock; status: IStatus): ICryptKey; cdecl; begin + Result := nil; try Result := IServerBlockImpl(this).newKey(status); except @@ -10952,6 +12196,7 @@ procedure IClientBlockImpl_addRefDispatcher(this: IClientBlock); cdecl; function IClientBlockImpl_releaseDispatcher(this: IClientBlock): Integer; cdecl; begin + Result := 0; try Result := IClientBlockImpl(this).release(); except @@ -10961,6 +12206,7 @@ function IClientBlockImpl_releaseDispatcher(this: IClientBlock): Integer; cdecl; function IClientBlockImpl_getLoginDispatcher(this: IClientBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IClientBlockImpl(this).getLogin(); except @@ -10970,6 +12216,7 @@ function IClientBlockImpl_getLoginDispatcher(this: IClientBlock): PAnsiChar; cde function IClientBlockImpl_getPasswordDispatcher(this: IClientBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IClientBlockImpl(this).getPassword(); except @@ -10979,6 +12226,7 @@ function IClientBlockImpl_getPasswordDispatcher(this: IClientBlock): PAnsiChar; function IClientBlockImpl_getDataDispatcher(this: IClientBlock; length: CardinalPtr): BytePtr; cdecl; begin + Result := nil; try Result := IClientBlockImpl(this).getData(length); except @@ -10997,6 +12245,7 @@ procedure IClientBlockImpl_putDataDispatcher(this: IClientBlock; status: IStatus function IClientBlockImpl_newKeyDispatcher(this: IClientBlock; status: IStatus): ICryptKey; cdecl; begin + Result := nil; try Result := IClientBlockImpl(this).newKey(status); except @@ -11006,6 +12255,7 @@ function IClientBlockImpl_newKeyDispatcher(this: IClientBlock; status: IStatus): function IClientBlockImpl_getAuthBlockDispatcher(this: IClientBlock; status: IStatus): IAuthBlock; cdecl; begin + Result := nil; try Result := IClientBlockImpl(this).getAuthBlock(status); except @@ -11032,6 +12282,7 @@ procedure IServerImpl_addRefDispatcher(this: IServer); cdecl; function IServerImpl_releaseDispatcher(this: IServer): Integer; cdecl; begin + Result := 0; try Result := IServerImpl(this).release(); except @@ -11050,6 +12301,7 @@ procedure IServerImpl_setOwnerDispatcher(this: IServer; r: IReferenceCounted); c function IServerImpl_getOwnerDispatcher(this: IServer): IReferenceCounted; cdecl; begin + Result := nil; try Result := IServerImpl(this).getOwner(); except @@ -11059,6 +12311,7 @@ function IServerImpl_getOwnerDispatcher(this: IServer): IReferenceCounted; cdecl function IServerImpl_authenticateDispatcher(this: IServer; status: IStatus; sBlock: IServerBlock; writerInterface: IWriter): Integer; cdecl; begin + Result := 0; try Result := IServerImpl(this).authenticate(status, sBlock, writerInterface); except @@ -11094,6 +12347,7 @@ procedure IClientImpl_addRefDispatcher(this: IClient); cdecl; function IClientImpl_releaseDispatcher(this: IClient): Integer; cdecl; begin + Result := 0; try Result := IClientImpl(this).release(); except @@ -11112,6 +12366,7 @@ procedure IClientImpl_setOwnerDispatcher(this: IClient; r: IReferenceCounted); c function IClientImpl_getOwnerDispatcher(this: IClient): IReferenceCounted; cdecl; begin + Result := nil; try Result := IClientImpl(this).getOwner(); except @@ -11121,6 +12376,7 @@ function IClientImpl_getOwnerDispatcher(this: IClient): IReferenceCounted; cdecl function IClientImpl_authenticateDispatcher(this: IClient; status: IStatus; cBlock: IClientBlock): Integer; cdecl; begin + Result := 0; try Result := IClientImpl(this).authenticate(status, cBlock); except @@ -11138,6 +12394,7 @@ constructor IClientImpl.create; function IUserFieldImpl_enteredDispatcher(this: IUserField): Integer; cdecl; begin + Result := 0; try Result := IUserFieldImpl(this).entered(); except @@ -11147,6 +12404,7 @@ function IUserFieldImpl_enteredDispatcher(this: IUserField): Integer; cdecl; function IUserFieldImpl_specifiedDispatcher(this: IUserField): Integer; cdecl; begin + Result := 0; try Result := IUserFieldImpl(this).specified(); except @@ -11173,6 +12431,7 @@ constructor IUserFieldImpl.create; function ICharUserFieldImpl_enteredDispatcher(this: ICharUserField): Integer; cdecl; begin + Result := 0; try Result := ICharUserFieldImpl(this).entered(); except @@ -11182,6 +12441,7 @@ function ICharUserFieldImpl_enteredDispatcher(this: ICharUserField): Integer; cd function ICharUserFieldImpl_specifiedDispatcher(this: ICharUserField): Integer; cdecl; begin + Result := 0; try Result := ICharUserFieldImpl(this).specified(); except @@ -11200,6 +12460,7 @@ procedure ICharUserFieldImpl_setEnteredDispatcher(this: ICharUserField; status: function ICharUserFieldImpl_getDispatcher(this: ICharUserField): PAnsiChar; cdecl; begin + Result := nil; try Result := ICharUserFieldImpl(this).get(); except @@ -11226,6 +12487,7 @@ constructor ICharUserFieldImpl.create; function IIntUserFieldImpl_enteredDispatcher(this: IIntUserField): Integer; cdecl; begin + Result := 0; try Result := IIntUserFieldImpl(this).entered(); except @@ -11235,6 +12497,7 @@ function IIntUserFieldImpl_enteredDispatcher(this: IIntUserField): Integer; cdec function IIntUserFieldImpl_specifiedDispatcher(this: IIntUserField): Integer; cdecl; begin + Result := 0; try Result := IIntUserFieldImpl(this).specified(); except @@ -11253,6 +12516,7 @@ procedure IIntUserFieldImpl_setEnteredDispatcher(this: IIntUserField; status: IS function IIntUserFieldImpl_getDispatcher(this: IIntUserField): Integer; cdecl; begin + Result := 0; try Result := IIntUserFieldImpl(this).get(); except @@ -11279,6 +12543,7 @@ constructor IIntUserFieldImpl.create; function IUserImpl_operationDispatcher(this: IUser): Cardinal; cdecl; begin + Result := 0; try Result := IUserImpl(this).operation(); except @@ -11288,6 +12553,7 @@ function IUserImpl_operationDispatcher(this: IUser): Cardinal; cdecl; function IUserImpl_userNameDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).userName(); except @@ -11297,6 +12563,7 @@ function IUserImpl_userNameDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_passwordDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).password(); except @@ -11306,6 +12573,7 @@ function IUserImpl_passwordDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_firstNameDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).firstName(); except @@ -11315,6 +12583,7 @@ function IUserImpl_firstNameDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_lastNameDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).lastName(); except @@ -11324,6 +12593,7 @@ function IUserImpl_lastNameDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_middleNameDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).middleName(); except @@ -11333,6 +12603,7 @@ function IUserImpl_middleNameDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_commentDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).comment(); except @@ -11342,6 +12613,7 @@ function IUserImpl_commentDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_attributesDispatcher(this: IUser): ICharUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).attributes(); except @@ -11351,6 +12623,7 @@ function IUserImpl_attributesDispatcher(this: IUser): ICharUserField; cdecl; function IUserImpl_activeDispatcher(this: IUser): IIntUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).active(); except @@ -11360,6 +12633,7 @@ function IUserImpl_activeDispatcher(this: IUser): IIntUserField; cdecl; function IUserImpl_adminDispatcher(this: IUser): IIntUserField; cdecl; begin + Result := nil; try Result := IUserImpl(this).admin(); except @@ -11403,6 +12677,7 @@ constructor IListUsersImpl.create; function ILogonInfoImpl_nameDispatcher(this: ILogonInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).name(); except @@ -11412,6 +12687,7 @@ function ILogonInfoImpl_nameDispatcher(this: ILogonInfo): PAnsiChar; cdecl; function ILogonInfoImpl_roleDispatcher(this: ILogonInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).role(); except @@ -11421,6 +12697,7 @@ function ILogonInfoImpl_roleDispatcher(this: ILogonInfo): PAnsiChar; cdecl; function ILogonInfoImpl_networkProtocolDispatcher(this: ILogonInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).networkProtocol(); except @@ -11430,6 +12707,7 @@ function ILogonInfoImpl_networkProtocolDispatcher(this: ILogonInfo): PAnsiChar; function ILogonInfoImpl_remoteAddressDispatcher(this: ILogonInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).remoteAddress(); except @@ -11439,6 +12717,7 @@ function ILogonInfoImpl_remoteAddressDispatcher(this: ILogonInfo): PAnsiChar; cd function ILogonInfoImpl_authBlockDispatcher(this: ILogonInfo; length: CardinalPtr): BytePtr; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).authBlock(length); except @@ -11448,6 +12727,7 @@ function ILogonInfoImpl_authBlockDispatcher(this: ILogonInfo; length: CardinalPt function ILogonInfoImpl_attachmentDispatcher(this: ILogonInfo; status: IStatus): IAttachment; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).attachment(status); except @@ -11457,6 +12737,7 @@ function ILogonInfoImpl_attachmentDispatcher(this: ILogonInfo; status: IStatus): function ILogonInfoImpl_transactionDispatcher(this: ILogonInfo; status: IStatus): ITransaction; cdecl; begin + Result := nil; try Result := ILogonInfoImpl(this).transaction(status); except @@ -11483,6 +12764,7 @@ procedure IManagementImpl_addRefDispatcher(this: IManagement); cdecl; function IManagementImpl_releaseDispatcher(this: IManagement): Integer; cdecl; begin + Result := 0; try Result := IManagementImpl(this).release(); except @@ -11501,6 +12783,7 @@ procedure IManagementImpl_setOwnerDispatcher(this: IManagement; r: IReferenceCou function IManagementImpl_getOwnerDispatcher(this: IManagement): IReferenceCounted; cdecl; begin + Result := nil; try Result := IManagementImpl(this).getOwner(); except @@ -11519,6 +12802,7 @@ procedure IManagementImpl_startDispatcher(this: IManagement; status: IStatus; lo function IManagementImpl_executeDispatcher(this: IManagement; status: IStatus; user: IUser; callback: IListUsers): Integer; cdecl; begin + Result := 0; try Result := IManagementImpl(this).execute(status, user, callback); except @@ -11554,6 +12838,7 @@ constructor IManagementImpl.create; function IAuthBlockImpl_getTypeDispatcher(this: IAuthBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IAuthBlockImpl(this).getType(); except @@ -11563,6 +12848,7 @@ function IAuthBlockImpl_getTypeDispatcher(this: IAuthBlock): PAnsiChar; cdecl; function IAuthBlockImpl_getNameDispatcher(this: IAuthBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IAuthBlockImpl(this).getName(); except @@ -11572,6 +12858,7 @@ function IAuthBlockImpl_getNameDispatcher(this: IAuthBlock): PAnsiChar; cdecl; function IAuthBlockImpl_getPluginDispatcher(this: IAuthBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IAuthBlockImpl(this).getPlugin(); except @@ -11581,6 +12868,7 @@ function IAuthBlockImpl_getPluginDispatcher(this: IAuthBlock): PAnsiChar; cdecl; function IAuthBlockImpl_getSecurityDbDispatcher(this: IAuthBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IAuthBlockImpl(this).getSecurityDb(); except @@ -11590,6 +12878,7 @@ function IAuthBlockImpl_getSecurityDbDispatcher(this: IAuthBlock): PAnsiChar; cd function IAuthBlockImpl_getOriginalPluginDispatcher(this: IAuthBlock): PAnsiChar; cdecl; begin + Result := nil; try Result := IAuthBlockImpl(this).getOriginalPlugin(); except @@ -11599,6 +12888,7 @@ function IAuthBlockImpl_getOriginalPluginDispatcher(this: IAuthBlock): PAnsiChar function IAuthBlockImpl_nextDispatcher(this: IAuthBlock; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IAuthBlockImpl(this).next(status); except @@ -11608,6 +12898,7 @@ function IAuthBlockImpl_nextDispatcher(this: IAuthBlock; status: IStatus): Boole function IAuthBlockImpl_firstDispatcher(this: IAuthBlock; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IAuthBlockImpl(this).first(status); except @@ -11634,6 +12925,7 @@ procedure IWireCryptPluginImpl_addRefDispatcher(this: IWireCryptPlugin); cdecl; function IWireCryptPluginImpl_releaseDispatcher(this: IWireCryptPlugin): Integer; cdecl; begin + Result := 0; try Result := IWireCryptPluginImpl(this).release(); except @@ -11652,6 +12944,7 @@ procedure IWireCryptPluginImpl_setOwnerDispatcher(this: IWireCryptPlugin; r: IRe function IWireCryptPluginImpl_getOwnerDispatcher(this: IWireCryptPlugin): IReferenceCounted; cdecl; begin + Result := nil; try Result := IWireCryptPluginImpl(this).getOwner(); except @@ -11661,6 +12954,7 @@ function IWireCryptPluginImpl_getOwnerDispatcher(this: IWireCryptPlugin): IRefer function IWireCryptPluginImpl_getKnownTypesDispatcher(this: IWireCryptPlugin; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IWireCryptPluginImpl(this).getKnownTypes(status); except @@ -11697,6 +12991,7 @@ procedure IWireCryptPluginImpl_decryptDispatcher(this: IWireCryptPlugin; status: function IWireCryptPluginImpl_getSpecificDataDispatcher(this: IWireCryptPlugin; status: IStatus; keyType: PAnsiChar; length: CardinalPtr): BytePtr; cdecl; begin + Result := nil; try Result := IWireCryptPluginImpl(this).getSpecificData(status, keyType, length); except @@ -11723,6 +13018,7 @@ constructor IWireCryptPluginImpl.create; function ICryptKeyCallbackImpl_callbackDispatcher(this: ICryptKeyCallback; dataLength: Cardinal; data: Pointer; bufferLength: Cardinal; buffer: Pointer): Cardinal; cdecl; begin + Result := 0; try Result := ICryptKeyCallbackImpl(this).callback(dataLength, data, bufferLength, buffer); except @@ -11730,6 +13026,51 @@ function ICryptKeyCallbackImpl_callbackDispatcher(this: ICryptKeyCallback; dataL end end; +procedure ICryptKeyCallbackImpl_dummy1Dispatcher(this: ICryptKeyCallback; status: IStatus); cdecl; +begin + try + ICryptKeyCallbackImpl(this).dummy1(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure ICryptKeyCallbackImpl.dummy1(status: IStatus); +begin +end; + +procedure ICryptKeyCallbackImpl_dummy2Dispatcher(this: ICryptKeyCallback); cdecl; +begin + try + ICryptKeyCallbackImpl(this).dummy2(); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + +procedure ICryptKeyCallbackImpl.dummy2(); +begin +end; + +function ICryptKeyCallbackImpl_getHashLengthDispatcher(this: ICryptKeyCallback; status: IStatus): Integer; cdecl; +begin + Result := 0; + try + Result := ICryptKeyCallbackImpl(this).getHashLength(status); + except + on e: Exception do FbException.catchException(status, e); + end +end; + +procedure ICryptKeyCallbackImpl_getHashDataDispatcher(this: ICryptKeyCallback; status: IStatus; hash: Pointer); cdecl; +begin + try + ICryptKeyCallbackImpl(this).getHashData(status, hash); + except + on e: Exception do FbException.catchException(status, e); + end +end; + var ICryptKeyCallbackImpl_vTable: CryptKeyCallbackVTable; @@ -11749,6 +13090,7 @@ procedure IKeyHolderPluginImpl_addRefDispatcher(this: IKeyHolderPlugin); cdecl; function IKeyHolderPluginImpl_releaseDispatcher(this: IKeyHolderPlugin): Integer; cdecl; begin + Result := 0; try Result := IKeyHolderPluginImpl(this).release(); except @@ -11767,6 +13109,7 @@ procedure IKeyHolderPluginImpl_setOwnerDispatcher(this: IKeyHolderPlugin; r: IRe function IKeyHolderPluginImpl_getOwnerDispatcher(this: IKeyHolderPlugin): IReferenceCounted; cdecl; begin + Result := nil; try Result := IKeyHolderPluginImpl(this).getOwner(); except @@ -11776,6 +13119,7 @@ function IKeyHolderPluginImpl_getOwnerDispatcher(this: IKeyHolderPlugin): IRefer function IKeyHolderPluginImpl_keyCallbackDispatcher(this: IKeyHolderPlugin; status: IStatus; callback: ICryptKeyCallback): Integer; cdecl; begin + Result := 0; try Result := IKeyHolderPluginImpl(this).keyCallback(status, callback); except @@ -11785,6 +13129,7 @@ function IKeyHolderPluginImpl_keyCallbackDispatcher(this: IKeyHolderPlugin; stat function IKeyHolderPluginImpl_keyHandleDispatcher(this: IKeyHolderPlugin; status: IStatus; keyName: PAnsiChar): ICryptKeyCallback; cdecl; begin + Result := nil; try Result := IKeyHolderPluginImpl(this).keyHandle(status, keyName); except @@ -11794,6 +13139,7 @@ function IKeyHolderPluginImpl_keyHandleDispatcher(this: IKeyHolderPlugin; status function IKeyHolderPluginImpl_useOnlyOwnKeysDispatcher(this: IKeyHolderPlugin; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IKeyHolderPluginImpl(this).useOnlyOwnKeys(status); except @@ -11803,6 +13149,7 @@ function IKeyHolderPluginImpl_useOnlyOwnKeysDispatcher(this: IKeyHolderPlugin; s function IKeyHolderPluginImpl_chainHandleDispatcher(this: IKeyHolderPlugin; status: IStatus): ICryptKeyCallback; cdecl; begin + Result := nil; try Result := IKeyHolderPluginImpl(this).chainHandle(status); except @@ -11829,6 +13176,7 @@ procedure IDbCryptInfoImpl_addRefDispatcher(this: IDbCryptInfo); cdecl; function IDbCryptInfoImpl_releaseDispatcher(this: IDbCryptInfo): Integer; cdecl; begin + Result := 0; try Result := IDbCryptInfoImpl(this).release(); except @@ -11838,6 +13186,7 @@ function IDbCryptInfoImpl_releaseDispatcher(this: IDbCryptInfo): Integer; cdecl; function IDbCryptInfoImpl_getDatabaseFullPathDispatcher(this: IDbCryptInfo; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IDbCryptInfoImpl(this).getDatabaseFullPath(status); except @@ -11864,6 +13213,7 @@ procedure IDbCryptPluginImpl_addRefDispatcher(this: IDbCryptPlugin); cdecl; function IDbCryptPluginImpl_releaseDispatcher(this: IDbCryptPlugin): Integer; cdecl; begin + Result := 0; try Result := IDbCryptPluginImpl(this).release(); except @@ -11882,6 +13232,7 @@ procedure IDbCryptPluginImpl_setOwnerDispatcher(this: IDbCryptPlugin; r: IRefere function IDbCryptPluginImpl_getOwnerDispatcher(this: IDbCryptPlugin): IReferenceCounted; cdecl; begin + Result := nil; try Result := IDbCryptPluginImpl(this).getOwner(); except @@ -11935,6 +13286,7 @@ constructor IDbCryptPluginImpl.create; function IExternalContextImpl_getMasterDispatcher(this: IExternalContext): IMaster; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getMaster(); except @@ -11944,6 +13296,7 @@ function IExternalContextImpl_getMasterDispatcher(this: IExternalContext): IMast function IExternalContextImpl_getEngineDispatcher(this: IExternalContext; status: IStatus): IExternalEngine; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getEngine(status); except @@ -11953,6 +13306,7 @@ function IExternalContextImpl_getEngineDispatcher(this: IExternalContext; status function IExternalContextImpl_getAttachmentDispatcher(this: IExternalContext; status: IStatus): IAttachment; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getAttachment(status); except @@ -11962,6 +13316,7 @@ function IExternalContextImpl_getAttachmentDispatcher(this: IExternalContext; st function IExternalContextImpl_getTransactionDispatcher(this: IExternalContext; status: IStatus): ITransaction; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getTransaction(status); except @@ -11971,6 +13326,7 @@ function IExternalContextImpl_getTransactionDispatcher(this: IExternalContext; s function IExternalContextImpl_getUserNameDispatcher(this: IExternalContext): PAnsiChar; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getUserName(); except @@ -11980,6 +13336,7 @@ function IExternalContextImpl_getUserNameDispatcher(this: IExternalContext): PAn function IExternalContextImpl_getDatabaseNameDispatcher(this: IExternalContext): PAnsiChar; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getDatabaseName(); except @@ -11989,6 +13346,7 @@ function IExternalContextImpl_getDatabaseNameDispatcher(this: IExternalContext): function IExternalContextImpl_getClientCharSetDispatcher(this: IExternalContext): PAnsiChar; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getClientCharSet(); except @@ -11998,6 +13356,7 @@ function IExternalContextImpl_getClientCharSetDispatcher(this: IExternalContext) function IExternalContextImpl_obtainInfoCodeDispatcher(this: IExternalContext): Integer; cdecl; begin + Result := 0; try Result := IExternalContextImpl(this).obtainInfoCode(); except @@ -12007,6 +13366,7 @@ function IExternalContextImpl_obtainInfoCodeDispatcher(this: IExternalContext): function IExternalContextImpl_getInfoDispatcher(this: IExternalContext; code: Integer): Pointer; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).getInfo(code); except @@ -12016,6 +13376,7 @@ function IExternalContextImpl_getInfoDispatcher(this: IExternalContext; code: In function IExternalContextImpl_setInfoDispatcher(this: IExternalContext; code: Integer; value: Pointer): Pointer; cdecl; begin + Result := nil; try Result := IExternalContextImpl(this).setInfo(code, value); except @@ -12042,6 +13403,7 @@ procedure IExternalResultSetImpl_disposeDispatcher(this: IExternalResultSet); cd function IExternalResultSetImpl_fetchDispatcher(this: IExternalResultSet; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IExternalResultSetImpl(this).fetch(status); except @@ -12112,6 +13474,7 @@ procedure IExternalProcedureImpl_getCharSetDispatcher(this: IExternalProcedure; function IExternalProcedureImpl_openDispatcher(this: IExternalProcedure; status: IStatus; context: IExternalContext; inMsg: Pointer; outMsg: Pointer): IExternalResultSet; cdecl; begin + Result := nil; try Result := IExternalProcedureImpl(this).open(status, context, inMsg, outMsg); except @@ -12164,6 +13527,7 @@ constructor IExternalTriggerImpl.create; function IRoutineMetadataImpl_getPackageDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getPackage(status); except @@ -12173,6 +13537,7 @@ function IRoutineMetadataImpl_getPackageDispatcher(this: IRoutineMetadata; statu function IRoutineMetadataImpl_getNameDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getName(status); except @@ -12182,6 +13547,7 @@ function IRoutineMetadataImpl_getNameDispatcher(this: IRoutineMetadata; status: function IRoutineMetadataImpl_getEntryPointDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getEntryPoint(status); except @@ -12191,6 +13557,7 @@ function IRoutineMetadataImpl_getEntryPointDispatcher(this: IRoutineMetadata; st function IRoutineMetadataImpl_getBodyDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getBody(status); except @@ -12200,6 +13567,7 @@ function IRoutineMetadataImpl_getBodyDispatcher(this: IRoutineMetadata; status: function IRoutineMetadataImpl_getInputMetadataDispatcher(this: IRoutineMetadata; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getInputMetadata(status); except @@ -12209,6 +13577,7 @@ function IRoutineMetadataImpl_getInputMetadataDispatcher(this: IRoutineMetadata; function IRoutineMetadataImpl_getOutputMetadataDispatcher(this: IRoutineMetadata; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getOutputMetadata(status); except @@ -12218,6 +13587,7 @@ function IRoutineMetadataImpl_getOutputMetadataDispatcher(this: IRoutineMetadata function IRoutineMetadataImpl_getTriggerMetadataDispatcher(this: IRoutineMetadata; status: IStatus): IMessageMetadata; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getTriggerMetadata(status); except @@ -12227,6 +13597,7 @@ function IRoutineMetadataImpl_getTriggerMetadataDispatcher(this: IRoutineMetadat function IRoutineMetadataImpl_getTriggerTableDispatcher(this: IRoutineMetadata; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IRoutineMetadataImpl(this).getTriggerTable(status); except @@ -12236,6 +13607,7 @@ function IRoutineMetadataImpl_getTriggerTableDispatcher(this: IRoutineMetadata; function IRoutineMetadataImpl_getTriggerTypeDispatcher(this: IRoutineMetadata; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IRoutineMetadataImpl(this).getTriggerType(status); except @@ -12262,6 +13634,7 @@ procedure IExternalEngineImpl_addRefDispatcher(this: IExternalEngine); cdecl; function IExternalEngineImpl_releaseDispatcher(this: IExternalEngine): Integer; cdecl; begin + Result := 0; try Result := IExternalEngineImpl(this).release(); except @@ -12280,6 +13653,7 @@ procedure IExternalEngineImpl_setOwnerDispatcher(this: IExternalEngine; r: IRefe function IExternalEngineImpl_getOwnerDispatcher(this: IExternalEngine): IReferenceCounted; cdecl; begin + Result := nil; try Result := IExternalEngineImpl(this).getOwner(); except @@ -12316,6 +13690,7 @@ procedure IExternalEngineImpl_closeAttachmentDispatcher(this: IExternalEngine; s function IExternalEngineImpl_makeFunctionDispatcher(this: IExternalEngine; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata; inBuilder: IMetadataBuilder; outBuilder: IMetadataBuilder): IExternalFunction; cdecl; begin + Result := nil; try Result := IExternalEngineImpl(this).makeFunction(status, context, metadata, inBuilder, outBuilder); except @@ -12325,6 +13700,7 @@ function IExternalEngineImpl_makeFunctionDispatcher(this: IExternalEngine; statu function IExternalEngineImpl_makeProcedureDispatcher(this: IExternalEngine; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata; inBuilder: IMetadataBuilder; outBuilder: IMetadataBuilder): IExternalProcedure; cdecl; begin + Result := nil; try Result := IExternalEngineImpl(this).makeProcedure(status, context, metadata, inBuilder, outBuilder); except @@ -12334,6 +13710,7 @@ function IExternalEngineImpl_makeProcedureDispatcher(this: IExternalEngine; stat function IExternalEngineImpl_makeTriggerDispatcher(this: IExternalEngine; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata; fieldsBuilder: IMetadataBuilder): IExternalTrigger; cdecl; begin + Result := nil; try Result := IExternalEngineImpl(this).makeTrigger(status, context, metadata, fieldsBuilder); except @@ -12360,6 +13737,7 @@ procedure ITimerImpl_addRefDispatcher(this: ITimer); cdecl; function ITimerImpl_releaseDispatcher(this: ITimer): Integer; cdecl; begin + Result := 0; try Result := ITimerImpl(this).release(); except @@ -12465,6 +13843,7 @@ procedure IUtilImpl_getPerfCountersDispatcher(this: IUtil; status: IStatus; att: function IUtilImpl_executeCreateDatabaseDispatcher(this: IUtil; status: IStatus; stmtLength: Cardinal; creatDBstatement: PAnsiChar; dialect: Cardinal; stmtIsCreateDb: BooleanPtr): IAttachment; cdecl; begin + Result := nil; try Result := IUtilImpl(this).executeCreateDatabase(status, stmtLength, creatDBstatement, dialect, stmtIsCreateDb); except @@ -12492,6 +13871,7 @@ procedure IUtilImpl_decodeTimeDispatcher(this: IUtil; time: ISC_TIME; hours: Car function IUtilImpl_encodeDateDispatcher(this: IUtil; year: Cardinal; month: Cardinal; day: Cardinal): ISC_DATE; cdecl; begin + Result := 0; try Result := IUtilImpl(this).encodeDate(year, month, day); except @@ -12501,6 +13881,7 @@ function IUtilImpl_encodeDateDispatcher(this: IUtil; year: Cardinal; month: Card function IUtilImpl_encodeTimeDispatcher(this: IUtil; hours: Cardinal; minutes: Cardinal; seconds: Cardinal; fractions: Cardinal): ISC_TIME; cdecl; begin + Result := 0; try Result := IUtilImpl(this).encodeTime(hours, minutes, seconds, fractions); except @@ -12510,6 +13891,7 @@ function IUtilImpl_encodeTimeDispatcher(this: IUtil; hours: Cardinal; minutes: C function IUtilImpl_formatStatusDispatcher(this: IUtil; buffer: PAnsiChar; bufferSize: Cardinal; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IUtilImpl(this).formatStatus(buffer, bufferSize, status); except @@ -12519,6 +13901,7 @@ function IUtilImpl_formatStatusDispatcher(this: IUtil; buffer: PAnsiChar; buffer function IUtilImpl_getClientVersionDispatcher(this: IUtil): Cardinal; cdecl; begin + Result := 0; try Result := IUtilImpl(this).getClientVersion(); except @@ -12528,6 +13911,7 @@ function IUtilImpl_getClientVersionDispatcher(this: IUtil): Cardinal; cdecl; function IUtilImpl_getXpbBuilderDispatcher(this: IUtil; status: IStatus; kind: Cardinal; buf: BytePtr; len: Cardinal): IXpbBuilder; cdecl; begin + Result := nil; try Result := IUtilImpl(this).getXpbBuilder(status, kind, buf, len); except @@ -12537,6 +13921,7 @@ function IUtilImpl_getXpbBuilderDispatcher(this: IUtil; status: IStatus; kind: C function IUtilImpl_setOffsetsDispatcher(this: IUtil; status: IStatus; metadata: IMessageMetadata; callback: IOffsetsCallback): Cardinal; cdecl; begin + Result := 0; try Result := IUtilImpl(this).setOffsets(status, metadata, callback); except @@ -12546,6 +13931,7 @@ function IUtilImpl_setOffsetsDispatcher(this: IUtil; status: IStatus; metadata: function IUtilImpl_getDecFloat16Dispatcher(this: IUtil; status: IStatus): IDecFloat16; cdecl; begin + Result := nil; try Result := IUtilImpl(this).getDecFloat16(status); except @@ -12555,6 +13941,7 @@ function IUtilImpl_getDecFloat16Dispatcher(this: IUtil; status: IStatus): IDecFl function IUtilImpl_getDecFloat34Dispatcher(this: IUtil; status: IStatus): IDecFloat34; cdecl; begin + Result := nil; try Result := IUtilImpl(this).getDecFloat34(status); except @@ -12600,6 +13987,7 @@ procedure IUtilImpl_encodeTimeStampTzDispatcher(this: IUtil; status: IStatus; ti function IUtilImpl_getInt128Dispatcher(this: IUtil; status: IStatus): IInt128; cdecl; begin + Result := nil; try Result := IUtilImpl(this).getInt128(status); except @@ -12724,6 +14112,7 @@ procedure IXpbBuilderImpl_insertTagDispatcher(this: IXpbBuilder; status: IStatus function IXpbBuilderImpl_isEofDispatcher(this: IXpbBuilder; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IXpbBuilderImpl(this).isEof(status); except @@ -12751,6 +14140,7 @@ procedure IXpbBuilderImpl_rewindDispatcher(this: IXpbBuilder; status: IStatus); function IXpbBuilderImpl_findFirstDispatcher(this: IXpbBuilder; status: IStatus; tag: Byte): Boolean; cdecl; begin + Result := false; try Result := IXpbBuilderImpl(this).findFirst(status, tag); except @@ -12760,6 +14150,7 @@ function IXpbBuilderImpl_findFirstDispatcher(this: IXpbBuilder; status: IStatus; function IXpbBuilderImpl_findNextDispatcher(this: IXpbBuilder; status: IStatus): Boolean; cdecl; begin + Result := false; try Result := IXpbBuilderImpl(this).findNext(status); except @@ -12769,6 +14160,7 @@ function IXpbBuilderImpl_findNextDispatcher(this: IXpbBuilder; status: IStatus): function IXpbBuilderImpl_getTagDispatcher(this: IXpbBuilder; status: IStatus): Byte; cdecl; begin + Result := 0; try Result := IXpbBuilderImpl(this).getTag(status); except @@ -12778,6 +14170,7 @@ function IXpbBuilderImpl_getTagDispatcher(this: IXpbBuilder; status: IStatus): B function IXpbBuilderImpl_getLengthDispatcher(this: IXpbBuilder; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IXpbBuilderImpl(this).getLength(status); except @@ -12787,6 +14180,7 @@ function IXpbBuilderImpl_getLengthDispatcher(this: IXpbBuilder; status: IStatus) function IXpbBuilderImpl_getIntDispatcher(this: IXpbBuilder; status: IStatus): Integer; cdecl; begin + Result := 0; try Result := IXpbBuilderImpl(this).getInt(status); except @@ -12796,6 +14190,7 @@ function IXpbBuilderImpl_getIntDispatcher(this: IXpbBuilder; status: IStatus): I function IXpbBuilderImpl_getBigIntDispatcher(this: IXpbBuilder; status: IStatus): Int64; cdecl; begin + Result := 0; try Result := IXpbBuilderImpl(this).getBigInt(status); except @@ -12805,6 +14200,7 @@ function IXpbBuilderImpl_getBigIntDispatcher(this: IXpbBuilder; status: IStatus) function IXpbBuilderImpl_getStringDispatcher(this: IXpbBuilder; status: IStatus): PAnsiChar; cdecl; begin + Result := nil; try Result := IXpbBuilderImpl(this).getString(status); except @@ -12814,6 +14210,7 @@ function IXpbBuilderImpl_getStringDispatcher(this: IXpbBuilder; status: IStatus) function IXpbBuilderImpl_getBytesDispatcher(this: IXpbBuilder; status: IStatus): BytePtr; cdecl; begin + Result := nil; try Result := IXpbBuilderImpl(this).getBytes(status); except @@ -12823,6 +14220,7 @@ function IXpbBuilderImpl_getBytesDispatcher(this: IXpbBuilder; status: IStatus): function IXpbBuilderImpl_getBufferLengthDispatcher(this: IXpbBuilder; status: IStatus): Cardinal; cdecl; begin + Result := 0; try Result := IXpbBuilderImpl(this).getBufferLength(status); except @@ -12832,6 +14230,7 @@ function IXpbBuilderImpl_getBufferLengthDispatcher(this: IXpbBuilder; status: IS function IXpbBuilderImpl_getBufferDispatcher(this: IXpbBuilder; status: IStatus): BytePtr; cdecl; begin + Result := nil; try Result := IXpbBuilderImpl(this).getBuffer(status); except @@ -12849,6 +14248,7 @@ constructor IXpbBuilderImpl.create; function ITraceConnectionImpl_getKindDispatcher(this: ITraceConnection): Cardinal; cdecl; begin + Result := 0; try Result := ITraceConnectionImpl(this).getKind(); except @@ -12858,6 +14258,7 @@ function ITraceConnectionImpl_getKindDispatcher(this: ITraceConnection): Cardina function ITraceConnectionImpl_getProcessIDDispatcher(this: ITraceConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceConnectionImpl(this).getProcessID(); except @@ -12867,6 +14268,7 @@ function ITraceConnectionImpl_getProcessIDDispatcher(this: ITraceConnection): In function ITraceConnectionImpl_getUserNameDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getUserName(); except @@ -12876,6 +14278,7 @@ function ITraceConnectionImpl_getUserNameDispatcher(this: ITraceConnection): PAn function ITraceConnectionImpl_getRoleNameDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getRoleName(); except @@ -12885,6 +14288,7 @@ function ITraceConnectionImpl_getRoleNameDispatcher(this: ITraceConnection): PAn function ITraceConnectionImpl_getCharSetDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getCharSet(); except @@ -12894,6 +14298,7 @@ function ITraceConnectionImpl_getCharSetDispatcher(this: ITraceConnection): PAns function ITraceConnectionImpl_getRemoteProtocolDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getRemoteProtocol(); except @@ -12903,6 +14308,7 @@ function ITraceConnectionImpl_getRemoteProtocolDispatcher(this: ITraceConnection function ITraceConnectionImpl_getRemoteAddressDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getRemoteAddress(); except @@ -12912,6 +14318,7 @@ function ITraceConnectionImpl_getRemoteAddressDispatcher(this: ITraceConnection) function ITraceConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceConnectionImpl(this).getRemoteProcessID(); except @@ -12921,6 +14328,7 @@ function ITraceConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceConnectio function ITraceConnectionImpl_getRemoteProcessNameDispatcher(this: ITraceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceConnectionImpl(this).getRemoteProcessName(); except @@ -12938,6 +14346,7 @@ constructor ITraceConnectionImpl.create; function ITraceDatabaseConnectionImpl_getKindDispatcher(this: ITraceDatabaseConnection): Cardinal; cdecl; begin + Result := 0; try Result := ITraceDatabaseConnectionImpl(this).getKind(); except @@ -12947,6 +14356,7 @@ function ITraceDatabaseConnectionImpl_getKindDispatcher(this: ITraceDatabaseConn function ITraceDatabaseConnectionImpl_getProcessIDDispatcher(this: ITraceDatabaseConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceDatabaseConnectionImpl(this).getProcessID(); except @@ -12956,6 +14366,7 @@ function ITraceDatabaseConnectionImpl_getProcessIDDispatcher(this: ITraceDatabas function ITraceDatabaseConnectionImpl_getUserNameDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getUserName(); except @@ -12965,6 +14376,7 @@ function ITraceDatabaseConnectionImpl_getUserNameDispatcher(this: ITraceDatabase function ITraceDatabaseConnectionImpl_getRoleNameDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getRoleName(); except @@ -12974,6 +14386,7 @@ function ITraceDatabaseConnectionImpl_getRoleNameDispatcher(this: ITraceDatabase function ITraceDatabaseConnectionImpl_getCharSetDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getCharSet(); except @@ -12983,6 +14396,7 @@ function ITraceDatabaseConnectionImpl_getCharSetDispatcher(this: ITraceDatabaseC function ITraceDatabaseConnectionImpl_getRemoteProtocolDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getRemoteProtocol(); except @@ -12992,6 +14406,7 @@ function ITraceDatabaseConnectionImpl_getRemoteProtocolDispatcher(this: ITraceDa function ITraceDatabaseConnectionImpl_getRemoteAddressDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getRemoteAddress(); except @@ -13001,6 +14416,7 @@ function ITraceDatabaseConnectionImpl_getRemoteAddressDispatcher(this: ITraceDat function ITraceDatabaseConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceDatabaseConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceDatabaseConnectionImpl(this).getRemoteProcessID(); except @@ -13010,6 +14426,7 @@ function ITraceDatabaseConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceD function ITraceDatabaseConnectionImpl_getRemoteProcessNameDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getRemoteProcessName(); except @@ -13019,6 +14436,7 @@ function ITraceDatabaseConnectionImpl_getRemoteProcessNameDispatcher(this: ITrac function ITraceDatabaseConnectionImpl_getConnectionIDDispatcher(this: ITraceDatabaseConnection): Int64; cdecl; begin + Result := 0; try Result := ITraceDatabaseConnectionImpl(this).getConnectionID(); except @@ -13028,6 +14446,7 @@ function ITraceDatabaseConnectionImpl_getConnectionIDDispatcher(this: ITraceData function ITraceDatabaseConnectionImpl_getDatabaseNameDispatcher(this: ITraceDatabaseConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDatabaseConnectionImpl(this).getDatabaseName(); except @@ -13045,6 +14464,7 @@ constructor ITraceDatabaseConnectionImpl.create; function ITraceTransactionImpl_getTransactionIDDispatcher(this: ITraceTransaction): Int64; cdecl; begin + Result := 0; try Result := ITraceTransactionImpl(this).getTransactionID(); except @@ -13054,6 +14474,7 @@ function ITraceTransactionImpl_getTransactionIDDispatcher(this: ITraceTransactio function ITraceTransactionImpl_getReadOnlyDispatcher(this: ITraceTransaction): Boolean; cdecl; begin + Result := false; try Result := ITraceTransactionImpl(this).getReadOnly(); except @@ -13063,6 +14484,7 @@ function ITraceTransactionImpl_getReadOnlyDispatcher(this: ITraceTransaction): B function ITraceTransactionImpl_getWaitDispatcher(this: ITraceTransaction): Integer; cdecl; begin + Result := 0; try Result := ITraceTransactionImpl(this).getWait(); except @@ -13072,6 +14494,7 @@ function ITraceTransactionImpl_getWaitDispatcher(this: ITraceTransaction): Integ function ITraceTransactionImpl_getIsolationDispatcher(this: ITraceTransaction): Cardinal; cdecl; begin + Result := 0; try Result := ITraceTransactionImpl(this).getIsolation(); except @@ -13081,6 +14504,7 @@ function ITraceTransactionImpl_getIsolationDispatcher(this: ITraceTransaction): function ITraceTransactionImpl_getPerfDispatcher(this: ITraceTransaction): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceTransactionImpl(this).getPerf(); except @@ -13090,6 +14514,7 @@ function ITraceTransactionImpl_getPerfDispatcher(this: ITraceTransaction): Perfo function ITraceTransactionImpl_getInitialIDDispatcher(this: ITraceTransaction): Int64; cdecl; begin + Result := 0; try Result := ITraceTransactionImpl(this).getInitialID(); except @@ -13099,6 +14524,7 @@ function ITraceTransactionImpl_getInitialIDDispatcher(this: ITraceTransaction): function ITraceTransactionImpl_getPreviousIDDispatcher(this: ITraceTransaction): Int64; cdecl; begin + Result := 0; try Result := ITraceTransactionImpl(this).getPreviousID(); except @@ -13116,6 +14542,7 @@ constructor ITraceTransactionImpl.create; function ITraceParamsImpl_getCountDispatcher(this: ITraceParams): Cardinal; cdecl; begin + Result := 0; try Result := ITraceParamsImpl(this).getCount(); except @@ -13125,6 +14552,7 @@ function ITraceParamsImpl_getCountDispatcher(this: ITraceParams): Cardinal; cdec function ITraceParamsImpl_getParamDispatcher(this: ITraceParams; idx: Cardinal): dscPtr; cdecl; begin + Result := nil; try Result := ITraceParamsImpl(this).getParam(idx); except @@ -13134,6 +14562,7 @@ function ITraceParamsImpl_getParamDispatcher(this: ITraceParams; idx: Cardinal): function ITraceParamsImpl_getTextUTF8Dispatcher(this: ITraceParams; status: IStatus; idx: Cardinal): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceParamsImpl(this).getTextUTF8(status, idx); except @@ -13151,6 +14580,7 @@ constructor ITraceParamsImpl.create; function ITraceStatementImpl_getStmtIDDispatcher(this: ITraceStatement): Int64; cdecl; begin + Result := 0; try Result := ITraceStatementImpl(this).getStmtID(); except @@ -13160,6 +14590,7 @@ function ITraceStatementImpl_getStmtIDDispatcher(this: ITraceStatement): Int64; function ITraceStatementImpl_getPerfDispatcher(this: ITraceStatement): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceStatementImpl(this).getPerf(); except @@ -13177,6 +14608,7 @@ constructor ITraceStatementImpl.create; function ITraceSQLStatementImpl_getStmtIDDispatcher(this: ITraceSQLStatement): Int64; cdecl; begin + Result := 0; try Result := ITraceSQLStatementImpl(this).getStmtID(); except @@ -13186,6 +14618,7 @@ function ITraceSQLStatementImpl_getStmtIDDispatcher(this: ITraceSQLStatement): I function ITraceSQLStatementImpl_getPerfDispatcher(this: ITraceSQLStatement): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getPerf(); except @@ -13195,6 +14628,7 @@ function ITraceSQLStatementImpl_getPerfDispatcher(this: ITraceSQLStatement): Per function ITraceSQLStatementImpl_getTextDispatcher(this: ITraceSQLStatement): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getText(); except @@ -13204,6 +14638,7 @@ function ITraceSQLStatementImpl_getTextDispatcher(this: ITraceSQLStatement): PAn function ITraceSQLStatementImpl_getPlanDispatcher(this: ITraceSQLStatement): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getPlan(); except @@ -13213,6 +14648,7 @@ function ITraceSQLStatementImpl_getPlanDispatcher(this: ITraceSQLStatement): PAn function ITraceSQLStatementImpl_getInputsDispatcher(this: ITraceSQLStatement): ITraceParams; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getInputs(); except @@ -13222,6 +14658,7 @@ function ITraceSQLStatementImpl_getInputsDispatcher(this: ITraceSQLStatement): I function ITraceSQLStatementImpl_getTextUTF8Dispatcher(this: ITraceSQLStatement): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getTextUTF8(); except @@ -13231,6 +14668,7 @@ function ITraceSQLStatementImpl_getTextUTF8Dispatcher(this: ITraceSQLStatement): function ITraceSQLStatementImpl_getExplainedPlanDispatcher(this: ITraceSQLStatement): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceSQLStatementImpl(this).getExplainedPlan(); except @@ -13248,6 +14686,7 @@ constructor ITraceSQLStatementImpl.create; function ITraceBLRStatementImpl_getStmtIDDispatcher(this: ITraceBLRStatement): Int64; cdecl; begin + Result := 0; try Result := ITraceBLRStatementImpl(this).getStmtID(); except @@ -13257,6 +14696,7 @@ function ITraceBLRStatementImpl_getStmtIDDispatcher(this: ITraceBLRStatement): I function ITraceBLRStatementImpl_getPerfDispatcher(this: ITraceBLRStatement): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceBLRStatementImpl(this).getPerf(); except @@ -13266,6 +14706,7 @@ function ITraceBLRStatementImpl_getPerfDispatcher(this: ITraceBLRStatement): Per function ITraceBLRStatementImpl_getDataDispatcher(this: ITraceBLRStatement): BytePtr; cdecl; begin + Result := nil; try Result := ITraceBLRStatementImpl(this).getData(); except @@ -13275,6 +14716,7 @@ function ITraceBLRStatementImpl_getDataDispatcher(this: ITraceBLRStatement): Byt function ITraceBLRStatementImpl_getDataLengthDispatcher(this: ITraceBLRStatement): Cardinal; cdecl; begin + Result := 0; try Result := ITraceBLRStatementImpl(this).getDataLength(); except @@ -13284,6 +14726,7 @@ function ITraceBLRStatementImpl_getDataLengthDispatcher(this: ITraceBLRStatement function ITraceBLRStatementImpl_getTextDispatcher(this: ITraceBLRStatement): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceBLRStatementImpl(this).getText(); except @@ -13301,6 +14744,7 @@ constructor ITraceBLRStatementImpl.create; function ITraceDYNRequestImpl_getDataDispatcher(this: ITraceDYNRequest): BytePtr; cdecl; begin + Result := nil; try Result := ITraceDYNRequestImpl(this).getData(); except @@ -13310,6 +14754,7 @@ function ITraceDYNRequestImpl_getDataDispatcher(this: ITraceDYNRequest): BytePtr function ITraceDYNRequestImpl_getDataLengthDispatcher(this: ITraceDYNRequest): Cardinal; cdecl; begin + Result := 0; try Result := ITraceDYNRequestImpl(this).getDataLength(); except @@ -13319,6 +14764,7 @@ function ITraceDYNRequestImpl_getDataLengthDispatcher(this: ITraceDYNRequest): C function ITraceDYNRequestImpl_getTextDispatcher(this: ITraceDYNRequest): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceDYNRequestImpl(this).getText(); except @@ -13336,6 +14782,7 @@ constructor ITraceDYNRequestImpl.create; function ITraceContextVariableImpl_getNameSpaceDispatcher(this: ITraceContextVariable): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceContextVariableImpl(this).getNameSpace(); except @@ -13345,6 +14792,7 @@ function ITraceContextVariableImpl_getNameSpaceDispatcher(this: ITraceContextVar function ITraceContextVariableImpl_getVarNameDispatcher(this: ITraceContextVariable): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceContextVariableImpl(this).getVarName(); except @@ -13354,6 +14802,7 @@ function ITraceContextVariableImpl_getVarNameDispatcher(this: ITraceContextVaria function ITraceContextVariableImpl_getVarValueDispatcher(this: ITraceContextVariable): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceContextVariableImpl(this).getVarValue(); except @@ -13371,6 +14820,7 @@ constructor ITraceContextVariableImpl.create; function ITraceProcedureImpl_getProcNameDispatcher(this: ITraceProcedure): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceProcedureImpl(this).getProcName(); except @@ -13380,6 +14830,7 @@ function ITraceProcedureImpl_getProcNameDispatcher(this: ITraceProcedure): PAnsi function ITraceProcedureImpl_getInputsDispatcher(this: ITraceProcedure): ITraceParams; cdecl; begin + Result := nil; try Result := ITraceProcedureImpl(this).getInputs(); except @@ -13389,6 +14840,7 @@ function ITraceProcedureImpl_getInputsDispatcher(this: ITraceProcedure): ITraceP function ITraceProcedureImpl_getPerfDispatcher(this: ITraceProcedure): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceProcedureImpl(this).getPerf(); except @@ -13406,6 +14858,7 @@ constructor ITraceProcedureImpl.create; function ITraceFunctionImpl_getFuncNameDispatcher(this: ITraceFunction): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceFunctionImpl(this).getFuncName(); except @@ -13415,6 +14868,7 @@ function ITraceFunctionImpl_getFuncNameDispatcher(this: ITraceFunction): PAnsiCh function ITraceFunctionImpl_getInputsDispatcher(this: ITraceFunction): ITraceParams; cdecl; begin + Result := nil; try Result := ITraceFunctionImpl(this).getInputs(); except @@ -13424,6 +14878,7 @@ function ITraceFunctionImpl_getInputsDispatcher(this: ITraceFunction): ITracePar function ITraceFunctionImpl_getResultDispatcher(this: ITraceFunction): ITraceParams; cdecl; begin + Result := nil; try Result := ITraceFunctionImpl(this).getResult(); except @@ -13433,6 +14888,7 @@ function ITraceFunctionImpl_getResultDispatcher(this: ITraceFunction): ITracePar function ITraceFunctionImpl_getPerfDispatcher(this: ITraceFunction): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceFunctionImpl(this).getPerf(); except @@ -13450,6 +14906,7 @@ constructor ITraceFunctionImpl.create; function ITraceTriggerImpl_getTriggerNameDispatcher(this: ITraceTrigger): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceTriggerImpl(this).getTriggerName(); except @@ -13459,6 +14916,7 @@ function ITraceTriggerImpl_getTriggerNameDispatcher(this: ITraceTrigger): PAnsiC function ITraceTriggerImpl_getRelationNameDispatcher(this: ITraceTrigger): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceTriggerImpl(this).getRelationName(); except @@ -13468,6 +14926,7 @@ function ITraceTriggerImpl_getRelationNameDispatcher(this: ITraceTrigger): PAnsi function ITraceTriggerImpl_getActionDispatcher(this: ITraceTrigger): Integer; cdecl; begin + Result := 0; try Result := ITraceTriggerImpl(this).getAction(); except @@ -13477,6 +14936,7 @@ function ITraceTriggerImpl_getActionDispatcher(this: ITraceTrigger): Integer; cd function ITraceTriggerImpl_getWhichDispatcher(this: ITraceTrigger): Integer; cdecl; begin + Result := 0; try Result := ITraceTriggerImpl(this).getWhich(); except @@ -13486,6 +14946,7 @@ function ITraceTriggerImpl_getWhichDispatcher(this: ITraceTrigger): Integer; cde function ITraceTriggerImpl_getPerfDispatcher(this: ITraceTrigger): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceTriggerImpl(this).getPerf(); except @@ -13503,6 +14964,7 @@ constructor ITraceTriggerImpl.create; function ITraceServiceConnectionImpl_getKindDispatcher(this: ITraceServiceConnection): Cardinal; cdecl; begin + Result := 0; try Result := ITraceServiceConnectionImpl(this).getKind(); except @@ -13512,6 +14974,7 @@ function ITraceServiceConnectionImpl_getKindDispatcher(this: ITraceServiceConnec function ITraceServiceConnectionImpl_getProcessIDDispatcher(this: ITraceServiceConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceServiceConnectionImpl(this).getProcessID(); except @@ -13521,6 +14984,7 @@ function ITraceServiceConnectionImpl_getProcessIDDispatcher(this: ITraceServiceC function ITraceServiceConnectionImpl_getUserNameDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getUserName(); except @@ -13530,6 +14994,7 @@ function ITraceServiceConnectionImpl_getUserNameDispatcher(this: ITraceServiceCo function ITraceServiceConnectionImpl_getRoleNameDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getRoleName(); except @@ -13539,6 +15004,7 @@ function ITraceServiceConnectionImpl_getRoleNameDispatcher(this: ITraceServiceCo function ITraceServiceConnectionImpl_getCharSetDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getCharSet(); except @@ -13548,6 +15014,7 @@ function ITraceServiceConnectionImpl_getCharSetDispatcher(this: ITraceServiceCon function ITraceServiceConnectionImpl_getRemoteProtocolDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getRemoteProtocol(); except @@ -13557,6 +15024,7 @@ function ITraceServiceConnectionImpl_getRemoteProtocolDispatcher(this: ITraceSer function ITraceServiceConnectionImpl_getRemoteAddressDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getRemoteAddress(); except @@ -13566,6 +15034,7 @@ function ITraceServiceConnectionImpl_getRemoteAddressDispatcher(this: ITraceServ function ITraceServiceConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceServiceConnection): Integer; cdecl; begin + Result := 0; try Result := ITraceServiceConnectionImpl(this).getRemoteProcessID(); except @@ -13575,6 +15044,7 @@ function ITraceServiceConnectionImpl_getRemoteProcessIDDispatcher(this: ITraceSe function ITraceServiceConnectionImpl_getRemoteProcessNameDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getRemoteProcessName(); except @@ -13584,6 +15054,7 @@ function ITraceServiceConnectionImpl_getRemoteProcessNameDispatcher(this: ITrace function ITraceServiceConnectionImpl_getServiceIDDispatcher(this: ITraceServiceConnection): Pointer; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getServiceID(); except @@ -13593,6 +15064,7 @@ function ITraceServiceConnectionImpl_getServiceIDDispatcher(this: ITraceServiceC function ITraceServiceConnectionImpl_getServiceMgrDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getServiceMgr(); except @@ -13602,6 +15074,7 @@ function ITraceServiceConnectionImpl_getServiceMgrDispatcher(this: ITraceService function ITraceServiceConnectionImpl_getServiceNameDispatcher(this: ITraceServiceConnection): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceServiceConnectionImpl(this).getServiceName(); except @@ -13619,6 +15092,7 @@ constructor ITraceServiceConnectionImpl.create; function ITraceStatusVectorImpl_hasErrorDispatcher(this: ITraceStatusVector): Boolean; cdecl; begin + Result := false; try Result := ITraceStatusVectorImpl(this).hasError(); except @@ -13628,6 +15102,7 @@ function ITraceStatusVectorImpl_hasErrorDispatcher(this: ITraceStatusVector): Bo function ITraceStatusVectorImpl_hasWarningDispatcher(this: ITraceStatusVector): Boolean; cdecl; begin + Result := false; try Result := ITraceStatusVectorImpl(this).hasWarning(); except @@ -13637,6 +15112,7 @@ function ITraceStatusVectorImpl_hasWarningDispatcher(this: ITraceStatusVector): function ITraceStatusVectorImpl_getStatusDispatcher(this: ITraceStatusVector): IStatus; cdecl; begin + Result := nil; try Result := ITraceStatusVectorImpl(this).getStatus(); except @@ -13646,6 +15122,7 @@ function ITraceStatusVectorImpl_getStatusDispatcher(this: ITraceStatusVector): I function ITraceStatusVectorImpl_getTextDispatcher(this: ITraceStatusVector): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceStatusVectorImpl(this).getText(); except @@ -13663,6 +15140,7 @@ constructor ITraceStatusVectorImpl.create; function ITraceSweepInfoImpl_getOITDispatcher(this: ITraceSweepInfo): Int64; cdecl; begin + Result := 0; try Result := ITraceSweepInfoImpl(this).getOIT(); except @@ -13672,6 +15150,7 @@ function ITraceSweepInfoImpl_getOITDispatcher(this: ITraceSweepInfo): Int64; cde function ITraceSweepInfoImpl_getOSTDispatcher(this: ITraceSweepInfo): Int64; cdecl; begin + Result := 0; try Result := ITraceSweepInfoImpl(this).getOST(); except @@ -13681,6 +15160,7 @@ function ITraceSweepInfoImpl_getOSTDispatcher(this: ITraceSweepInfo): Int64; cde function ITraceSweepInfoImpl_getOATDispatcher(this: ITraceSweepInfo): Int64; cdecl; begin + Result := 0; try Result := ITraceSweepInfoImpl(this).getOAT(); except @@ -13690,6 +15170,7 @@ function ITraceSweepInfoImpl_getOATDispatcher(this: ITraceSweepInfo): Int64; cde function ITraceSweepInfoImpl_getNextDispatcher(this: ITraceSweepInfo): Int64; cdecl; begin + Result := 0; try Result := ITraceSweepInfoImpl(this).getNext(); except @@ -13699,6 +15180,7 @@ function ITraceSweepInfoImpl_getNextDispatcher(this: ITraceSweepInfo): Int64; cd function ITraceSweepInfoImpl_getPerfDispatcher(this: ITraceSweepInfo): PerformanceInfoPtr; cdecl; begin + Result := nil; try Result := ITraceSweepInfoImpl(this).getPerf(); except @@ -13725,6 +15207,7 @@ procedure ITraceLogWriterImpl_addRefDispatcher(this: ITraceLogWriter); cdecl; function ITraceLogWriterImpl_releaseDispatcher(this: ITraceLogWriter): Integer; cdecl; begin + Result := 0; try Result := ITraceLogWriterImpl(this).release(); except @@ -13734,6 +15217,7 @@ function ITraceLogWriterImpl_releaseDispatcher(this: ITraceLogWriter): Integer; function ITraceLogWriterImpl_writeDispatcher(this: ITraceLogWriter; buf: Pointer; size: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := ITraceLogWriterImpl(this).write(buf, size); except @@ -13743,6 +15227,7 @@ function ITraceLogWriterImpl_writeDispatcher(this: ITraceLogWriter; buf: Pointer function ITraceLogWriterImpl_write_sDispatcher(this: ITraceLogWriter; status: IStatus; buf: Pointer; size: Cardinal): Cardinal; cdecl; begin + Result := 0; try Result := ITraceLogWriterImpl(this).write_s(status, buf, size); except @@ -13760,6 +15245,7 @@ constructor ITraceLogWriterImpl.create; function ITraceInitInfoImpl_getConfigTextDispatcher(this: ITraceInitInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getConfigText(); except @@ -13769,6 +15255,7 @@ function ITraceInitInfoImpl_getConfigTextDispatcher(this: ITraceInitInfo): PAnsi function ITraceInitInfoImpl_getTraceSessionIDDispatcher(this: ITraceInitInfo): Integer; cdecl; begin + Result := 0; try Result := ITraceInitInfoImpl(this).getTraceSessionID(); except @@ -13778,6 +15265,7 @@ function ITraceInitInfoImpl_getTraceSessionIDDispatcher(this: ITraceInitInfo): I function ITraceInitInfoImpl_getTraceSessionNameDispatcher(this: ITraceInitInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getTraceSessionName(); except @@ -13787,6 +15275,7 @@ function ITraceInitInfoImpl_getTraceSessionNameDispatcher(this: ITraceInitInfo): function ITraceInitInfoImpl_getFirebirdRootDirectoryDispatcher(this: ITraceInitInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getFirebirdRootDirectory(); except @@ -13796,6 +15285,7 @@ function ITraceInitInfoImpl_getFirebirdRootDirectoryDispatcher(this: ITraceInitI function ITraceInitInfoImpl_getDatabaseNameDispatcher(this: ITraceInitInfo): PAnsiChar; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getDatabaseName(); except @@ -13805,6 +15295,7 @@ function ITraceInitInfoImpl_getDatabaseNameDispatcher(this: ITraceInitInfo): PAn function ITraceInitInfoImpl_getConnectionDispatcher(this: ITraceInitInfo): ITraceDatabaseConnection; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getConnection(); except @@ -13814,6 +15305,7 @@ function ITraceInitInfoImpl_getConnectionDispatcher(this: ITraceInitInfo): ITrac function ITraceInitInfoImpl_getLogWriterDispatcher(this: ITraceInitInfo): ITraceLogWriter; cdecl; begin + Result := nil; try Result := ITraceInitInfoImpl(this).getLogWriter(); except @@ -13840,6 +15332,7 @@ procedure ITracePluginImpl_addRefDispatcher(this: ITracePlugin); cdecl; function ITracePluginImpl_releaseDispatcher(this: ITracePlugin): Integer; cdecl; begin + Result := 0; try Result := ITracePluginImpl(this).release(); except @@ -13849,6 +15342,7 @@ function ITracePluginImpl_releaseDispatcher(this: ITracePlugin): Integer; cdecl; function ITracePluginImpl_trace_get_errorDispatcher(this: ITracePlugin): PAnsiChar; cdecl; begin + Result := nil; try Result := ITracePluginImpl(this).trace_get_error(); except @@ -13858,6 +15352,7 @@ function ITracePluginImpl_trace_get_errorDispatcher(this: ITracePlugin): PAnsiCh function ITracePluginImpl_trace_attachDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; create_db: Boolean; att_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_attach(connection, create_db, att_result); except @@ -13867,6 +15362,7 @@ function ITracePluginImpl_trace_attachDispatcher(this: ITracePlugin; connection: function ITracePluginImpl_trace_detachDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; drop_db: Boolean): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_detach(connection, drop_db); except @@ -13876,6 +15372,7 @@ function ITracePluginImpl_trace_detachDispatcher(this: ITracePlugin; connection: function ITracePluginImpl_trace_transaction_startDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; tpb_length: Cardinal; tpb: BytePtr; tra_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_transaction_start(connection, transaction, tpb_length, tpb, tra_result); except @@ -13885,6 +15382,7 @@ function ITracePluginImpl_trace_transaction_startDispatcher(this: ITracePlugin; function ITracePluginImpl_trace_transaction_endDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; commit: Boolean; retain_context: Boolean; tra_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_transaction_end(connection, transaction, commit, retain_context, tra_result); except @@ -13894,6 +15392,7 @@ function ITracePluginImpl_trace_transaction_endDispatcher(this: ITracePlugin; co function ITracePluginImpl_trace_proc_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; procedure_: ITraceProcedure; started: Boolean; proc_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_proc_execute(connection, transaction, procedure_, started, proc_result); except @@ -13903,6 +15402,7 @@ function ITracePluginImpl_trace_proc_executeDispatcher(this: ITracePlugin; conne function ITracePluginImpl_trace_trigger_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; trigger: ITraceTrigger; started: Boolean; trig_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_trigger_execute(connection, transaction, trigger, started, trig_result); except @@ -13912,6 +15412,7 @@ function ITracePluginImpl_trace_trigger_executeDispatcher(this: ITracePlugin; co function ITracePluginImpl_trace_set_contextDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; variable: ITraceContextVariable): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_set_context(connection, transaction, variable); except @@ -13921,6 +15422,7 @@ function ITracePluginImpl_trace_set_contextDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_dsql_prepareDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; time_millis: Int64; req_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_dsql_prepare(connection, transaction, statement, time_millis, req_result); except @@ -13930,6 +15432,7 @@ function ITracePluginImpl_trace_dsql_prepareDispatcher(this: ITracePlugin; conne function ITracePluginImpl_trace_dsql_freeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; statement: ITraceSQLStatement; option: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_dsql_free(connection, statement, option); except @@ -13939,6 +15442,7 @@ function ITracePluginImpl_trace_dsql_freeDispatcher(this: ITracePlugin; connecti function ITracePluginImpl_trace_dsql_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; started: Boolean; req_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_dsql_execute(connection, transaction, statement, started, req_result); except @@ -13948,6 +15452,7 @@ function ITracePluginImpl_trace_dsql_executeDispatcher(this: ITracePlugin; conne function ITracePluginImpl_trace_blr_compileDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceBLRStatement; time_millis: Int64; req_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_blr_compile(connection, transaction, statement, time_millis, req_result); except @@ -13957,6 +15462,7 @@ function ITracePluginImpl_trace_blr_compileDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_blr_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceBLRStatement; req_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_blr_execute(connection, transaction, statement, req_result); except @@ -13966,6 +15472,7 @@ function ITracePluginImpl_trace_blr_executeDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_dyn_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; request: ITraceDYNRequest; time_millis: Int64; req_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_dyn_execute(connection, transaction, request, time_millis, req_result); except @@ -13975,6 +15482,7 @@ function ITracePluginImpl_trace_dyn_executeDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_service_attachDispatcher(this: ITracePlugin; service: ITraceServiceConnection; att_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_service_attach(service, att_result); except @@ -13984,6 +15492,7 @@ function ITracePluginImpl_trace_service_attachDispatcher(this: ITracePlugin; ser function ITracePluginImpl_trace_service_startDispatcher(this: ITracePlugin; service: ITraceServiceConnection; switches_length: Cardinal; switches: PAnsiChar; start_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_service_start(service, switches_length, switches, start_result); except @@ -13993,6 +15502,7 @@ function ITracePluginImpl_trace_service_startDispatcher(this: ITracePlugin; serv function ITracePluginImpl_trace_service_queryDispatcher(this: ITracePlugin; service: ITraceServiceConnection; send_item_length: Cardinal; send_items: BytePtr; recv_item_length: Cardinal; recv_items: BytePtr; query_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_service_query(service, send_item_length, send_items, recv_item_length, recv_items, query_result); except @@ -14002,6 +15512,7 @@ function ITracePluginImpl_trace_service_queryDispatcher(this: ITracePlugin; serv function ITracePluginImpl_trace_service_detachDispatcher(this: ITracePlugin; service: ITraceServiceConnection; detach_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_service_detach(service, detach_result); except @@ -14011,6 +15522,7 @@ function ITracePluginImpl_trace_service_detachDispatcher(this: ITracePlugin; ser function ITracePluginImpl_trace_event_errorDispatcher(this: ITracePlugin; connection: ITraceConnection; status: ITraceStatusVector; function_: PAnsiChar): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_event_error(connection, status, function_); except @@ -14020,6 +15532,7 @@ function ITracePluginImpl_trace_event_errorDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_event_sweepDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; sweep: ITraceSweepInfo; sweep_state: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_event_sweep(connection, sweep, sweep_state); except @@ -14029,6 +15542,7 @@ function ITracePluginImpl_trace_event_sweepDispatcher(this: ITracePlugin; connec function ITracePluginImpl_trace_func_executeDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; function_: ITraceFunction; started: Boolean; func_result: Cardinal): Boolean; cdecl; begin + Result := false; try Result := ITracePluginImpl(this).trace_func_execute(connection, transaction, function_, started, func_result); except @@ -14036,6 +15550,16 @@ function ITracePluginImpl_trace_func_executeDispatcher(this: ITracePlugin; conne end end; +function ITracePluginImpl_trace_dsql_restartDispatcher(this: ITracePlugin; connection: ITraceDatabaseConnection; transaction: ITraceTransaction; statement: ITraceSQLStatement; number: Cardinal): Boolean; cdecl; +begin + Result := false; + try + Result := ITracePluginImpl(this).trace_dsql_restart(connection, transaction, statement, number); + except + on e: Exception do FbException.catchException(nil, e); + end +end; + var ITracePluginImpl_vTable: TracePluginVTable; @@ -14055,6 +15579,7 @@ procedure ITraceFactoryImpl_addRefDispatcher(this: ITraceFactory); cdecl; function ITraceFactoryImpl_releaseDispatcher(this: ITraceFactory): Integer; cdecl; begin + Result := 0; try Result := ITraceFactoryImpl(this).release(); except @@ -14073,6 +15598,7 @@ procedure ITraceFactoryImpl_setOwnerDispatcher(this: ITraceFactory; r: IReferenc function ITraceFactoryImpl_getOwnerDispatcher(this: ITraceFactory): IReferenceCounted; cdecl; begin + Result := nil; try Result := ITraceFactoryImpl(this).getOwner(); except @@ -14082,6 +15608,7 @@ function ITraceFactoryImpl_getOwnerDispatcher(this: ITraceFactory): IReferenceCo function ITraceFactoryImpl_trace_needsDispatcher(this: ITraceFactory): QWord; cdecl; begin + Result := 0; try Result := ITraceFactoryImpl(this).trace_needs(); except @@ -14091,6 +15618,7 @@ function ITraceFactoryImpl_trace_needsDispatcher(this: ITraceFactory): QWord; cd function ITraceFactoryImpl_trace_createDispatcher(this: ITraceFactory; status: IStatus; init_info: ITraceInitInfo): ITracePlugin; cdecl; begin + Result := nil; try Result := ITraceFactoryImpl(this).trace_create(status, init_info); except @@ -14126,6 +15654,7 @@ procedure IUdrFunctionFactoryImpl_setupDispatcher(this: IUdrFunctionFactory; sta function IUdrFunctionFactoryImpl_newItemDispatcher(this: IUdrFunctionFactory; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata): IExternalFunction; cdecl; begin + Result := nil; try Result := IUdrFunctionFactoryImpl(this).newItem(status, context, metadata); except @@ -14161,6 +15690,7 @@ procedure IUdrProcedureFactoryImpl_setupDispatcher(this: IUdrProcedureFactory; s function IUdrProcedureFactoryImpl_newItemDispatcher(this: IUdrProcedureFactory; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata): IExternalProcedure; cdecl; begin + Result := nil; try Result := IUdrProcedureFactoryImpl(this).newItem(status, context, metadata); except @@ -14196,6 +15726,7 @@ procedure IUdrTriggerFactoryImpl_setupDispatcher(this: IUdrTriggerFactory; statu function IUdrTriggerFactoryImpl_newItemDispatcher(this: IUdrTriggerFactory; status: IStatus; context: IExternalContext; metadata: IRoutineMetadata): IExternalTrigger; cdecl; begin + Result := nil; try Result := IUdrTriggerFactoryImpl(this).newItem(status, context, metadata); except @@ -14213,6 +15744,7 @@ constructor IUdrTriggerFactoryImpl.create; function IUdrPluginImpl_getMasterDispatcher(this: IUdrPlugin): IMaster; cdecl; begin + Result := nil; try Result := IUdrPluginImpl(this).getMaster(); except @@ -14371,6 +15903,7 @@ constructor IInt128Impl.create; function IReplicatedFieldImpl_getNameDispatcher(this: IReplicatedField): PAnsiChar; cdecl; begin + Result := nil; try Result := IReplicatedFieldImpl(this).getName(); except @@ -14380,6 +15913,7 @@ function IReplicatedFieldImpl_getNameDispatcher(this: IReplicatedField): PAnsiCh function IReplicatedFieldImpl_getTypeDispatcher(this: IReplicatedField): Cardinal; cdecl; begin + Result := 0; try Result := IReplicatedFieldImpl(this).getType(); except @@ -14389,6 +15923,7 @@ function IReplicatedFieldImpl_getTypeDispatcher(this: IReplicatedField): Cardina function IReplicatedFieldImpl_getSubTypeDispatcher(this: IReplicatedField): Integer; cdecl; begin + Result := 0; try Result := IReplicatedFieldImpl(this).getSubType(); except @@ -14398,6 +15933,7 @@ function IReplicatedFieldImpl_getSubTypeDispatcher(this: IReplicatedField): Inte function IReplicatedFieldImpl_getScaleDispatcher(this: IReplicatedField): Integer; cdecl; begin + Result := 0; try Result := IReplicatedFieldImpl(this).getScale(); except @@ -14407,6 +15943,7 @@ function IReplicatedFieldImpl_getScaleDispatcher(this: IReplicatedField): Intege function IReplicatedFieldImpl_getLengthDispatcher(this: IReplicatedField): Cardinal; cdecl; begin + Result := 0; try Result := IReplicatedFieldImpl(this).getLength(); except @@ -14416,6 +15953,7 @@ function IReplicatedFieldImpl_getLengthDispatcher(this: IReplicatedField): Cardi function IReplicatedFieldImpl_getCharSetDispatcher(this: IReplicatedField): Cardinal; cdecl; begin + Result := 0; try Result := IReplicatedFieldImpl(this).getCharSet(); except @@ -14425,6 +15963,7 @@ function IReplicatedFieldImpl_getCharSetDispatcher(this: IReplicatedField): Card function IReplicatedFieldImpl_getDataDispatcher(this: IReplicatedField): Pointer; cdecl; begin + Result := nil; try Result := IReplicatedFieldImpl(this).getData(); except @@ -14442,6 +15981,7 @@ constructor IReplicatedFieldImpl.create; function IReplicatedRecordImpl_getCountDispatcher(this: IReplicatedRecord): Cardinal; cdecl; begin + Result := 0; try Result := IReplicatedRecordImpl(this).getCount(); except @@ -14451,6 +15991,7 @@ function IReplicatedRecordImpl_getCountDispatcher(this: IReplicatedRecord): Card function IReplicatedRecordImpl_getFieldDispatcher(this: IReplicatedRecord; index: Cardinal): IReplicatedField; cdecl; begin + Result := nil; try Result := IReplicatedRecordImpl(this).getField(index); except @@ -14460,6 +16001,7 @@ function IReplicatedRecordImpl_getFieldDispatcher(this: IReplicatedRecord; index function IReplicatedRecordImpl_getRawLengthDispatcher(this: IReplicatedRecord): Cardinal; cdecl; begin + Result := 0; try Result := IReplicatedRecordImpl(this).getRawLength(); except @@ -14469,6 +16011,7 @@ function IReplicatedRecordImpl_getRawLengthDispatcher(this: IReplicatedRecord): function IReplicatedRecordImpl_getRawDataDispatcher(this: IReplicatedRecord): BytePtr; cdecl; begin + Result := nil; try Result := IReplicatedRecordImpl(this).getRawData(); except @@ -14611,6 +16154,7 @@ procedure IReplicatedSessionImpl_addRefDispatcher(this: IReplicatedSession); cde function IReplicatedSessionImpl_releaseDispatcher(this: IReplicatedSession): Integer; cdecl; begin + Result := 0; try Result := IReplicatedSessionImpl(this).release(); except @@ -14629,6 +16173,7 @@ procedure IReplicatedSessionImpl_setOwnerDispatcher(this: IReplicatedSession; r: function IReplicatedSessionImpl_getOwnerDispatcher(this: IReplicatedSession): IReferenceCounted; cdecl; begin + Result := nil; try Result := IReplicatedSessionImpl(this).getOwner(); except @@ -14638,6 +16183,7 @@ function IReplicatedSessionImpl_getOwnerDispatcher(this: IReplicatedSession): IR function IReplicatedSessionImpl_initDispatcher(this: IReplicatedSession; status: IStatus; attachment: IAttachment): Boolean; cdecl; begin + Result := false; try Result := IReplicatedSessionImpl(this).init(status, attachment); except @@ -14647,6 +16193,7 @@ function IReplicatedSessionImpl_initDispatcher(this: IReplicatedSession; status: function IReplicatedSessionImpl_startTransactionDispatcher(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl; begin + Result := nil; try Result := IReplicatedSessionImpl(this).startTransaction(status, transaction, number); except @@ -14708,11 +16255,14 @@ class procedure FbException.catchException(status: IStatus; e: Exception); statusVector: array[0..4] of NativeIntPtr; msg: AnsiString; begin + if (not Assigned(status)) then + Exit; + if (e.inheritsFrom(FbException)) then status.setErrors(FbException(e).getStatus.getErrors) else begin - msg := e.message; + msg := AnsiString(e.message); statusVector[0] := NativeIntPtr(isc_arg_gds); statusVector[1] := NativeIntPtr(isc_random); @@ -14723,6 +16273,24 @@ class procedure FbException.catchException(status: IStatus; e: Exception); status.setErrors(@statusVector); end end; + +class procedure FbException.setVersionError(status: IStatus; interfaceName: AnsiString; + currentVersion, expectedVersion: NativeInt); +var + statusVector: array[0..8] of NativeIntPtr; +begin + statusVector[0] := NativeIntPtr(isc_arg_gds); + statusVector[1] := NativeIntPtr(isc_interface_version_too_old); + statusVector[2] := NativeIntPtr(isc_arg_number); + statusVector[3] := NativeIntPtr(expectedVersion); + statusVector[4] := NativeIntPtr(isc_arg_number); + statusVector[5] := NativeIntPtr(currentVersion); + statusVector[6] := NativeIntPtr(isc_arg_string); + statusVector[7] := NativeIntPtr(PAnsiChar(interfaceName)); + statusVector[8] := NativeIntPtr(isc_arg_end); + + status.setErrors(@statusVector); +end; initialization IVersionedImpl_vTable := VersionedVTable.create; IVersionedImpl_vTable.version := 1; @@ -14860,30 +16428,35 @@ initialization IEventCallbackImpl_vTable.eventCallbackFunction := @IEventCallbackImpl_eventCallbackFunctionDispatcher; IBlobImpl_vTable := BlobVTable.create; - IBlobImpl_vTable.version := 3; + IBlobImpl_vTable.version := 4; IBlobImpl_vTable.addRef := @IBlobImpl_addRefDispatcher; IBlobImpl_vTable.release := @IBlobImpl_releaseDispatcher; IBlobImpl_vTable.getInfo := @IBlobImpl_getInfoDispatcher; IBlobImpl_vTable.getSegment := @IBlobImpl_getSegmentDispatcher; IBlobImpl_vTable.putSegment := @IBlobImpl_putSegmentDispatcher; + IBlobImpl_vTable.deprecatedCancel := @IBlobImpl_deprecatedCancelDispatcher; + IBlobImpl_vTable.deprecatedClose := @IBlobImpl_deprecatedCloseDispatcher; + IBlobImpl_vTable.seek := @IBlobImpl_seekDispatcher; IBlobImpl_vTable.cancel := @IBlobImpl_cancelDispatcher; IBlobImpl_vTable.close := @IBlobImpl_closeDispatcher; - IBlobImpl_vTable.seek := @IBlobImpl_seekDispatcher; ITransactionImpl_vTable := TransactionVTable.create; - ITransactionImpl_vTable.version := 3; + ITransactionImpl_vTable.version := 4; ITransactionImpl_vTable.addRef := @ITransactionImpl_addRefDispatcher; ITransactionImpl_vTable.release := @ITransactionImpl_releaseDispatcher; ITransactionImpl_vTable.getInfo := @ITransactionImpl_getInfoDispatcher; ITransactionImpl_vTable.prepare := @ITransactionImpl_prepareDispatcher; - ITransactionImpl_vTable.commit := @ITransactionImpl_commitDispatcher; + ITransactionImpl_vTable.deprecatedCommit := @ITransactionImpl_deprecatedCommitDispatcher; ITransactionImpl_vTable.commitRetaining := @ITransactionImpl_commitRetainingDispatcher; - ITransactionImpl_vTable.rollback := @ITransactionImpl_rollbackDispatcher; + ITransactionImpl_vTable.deprecatedRollback := @ITransactionImpl_deprecatedRollbackDispatcher; ITransactionImpl_vTable.rollbackRetaining := @ITransactionImpl_rollbackRetainingDispatcher; - ITransactionImpl_vTable.disconnect := @ITransactionImpl_disconnectDispatcher; + ITransactionImpl_vTable.deprecatedDisconnect := @ITransactionImpl_deprecatedDisconnectDispatcher; ITransactionImpl_vTable.join := @ITransactionImpl_joinDispatcher; ITransactionImpl_vTable.validate := @ITransactionImpl_validateDispatcher; ITransactionImpl_vTable.enterDtc := @ITransactionImpl_enterDtcDispatcher; + ITransactionImpl_vTable.commit := @ITransactionImpl_commitDispatcher; + ITransactionImpl_vTable.rollback := @ITransactionImpl_rollbackDispatcher; + ITransactionImpl_vTable.disconnect := @ITransactionImpl_disconnectDispatcher; IMessageMetadataImpl_vTable := MessageMetadataVTable.create; IMessageMetadataImpl_vTable.version := 4; @@ -14927,7 +16500,7 @@ initialization IMetadataBuilderImpl_vTable.setAlias := @IMetadataBuilderImpl_setAliasDispatcher; IResultSetImpl_vTable := ResultSetVTable.create; - IResultSetImpl_vTable.version := 3; + IResultSetImpl_vTable.version := 4; IResultSetImpl_vTable.addRef := @IResultSetImpl_addRefDispatcher; IResultSetImpl_vTable.release := @IResultSetImpl_releaseDispatcher; IResultSetImpl_vTable.fetchNext := @IResultSetImpl_fetchNextDispatcher; @@ -14939,11 +16512,12 @@ initialization IResultSetImpl_vTable.isEof := @IResultSetImpl_isEofDispatcher; IResultSetImpl_vTable.isBof := @IResultSetImpl_isBofDispatcher; IResultSetImpl_vTable.getMetadata := @IResultSetImpl_getMetadataDispatcher; - IResultSetImpl_vTable.close := @IResultSetImpl_closeDispatcher; + IResultSetImpl_vTable.deprecatedClose := @IResultSetImpl_deprecatedCloseDispatcher; IResultSetImpl_vTable.setDelayedOutputFormat := @IResultSetImpl_setDelayedOutputFormatDispatcher; + IResultSetImpl_vTable.close := @IResultSetImpl_closeDispatcher; IStatementImpl_vTable := StatementVTable.create; - IStatementImpl_vTable.version := 4; + IStatementImpl_vTable.version := 5; IStatementImpl_vTable.addRef := @IStatementImpl_addRefDispatcher; IStatementImpl_vTable.release := @IStatementImpl_releaseDispatcher; IStatementImpl_vTable.getInfo := @IStatementImpl_getInfoDispatcher; @@ -14955,14 +16529,15 @@ initialization IStatementImpl_vTable.execute := @IStatementImpl_executeDispatcher; IStatementImpl_vTable.openCursor := @IStatementImpl_openCursorDispatcher; IStatementImpl_vTable.setCursorName := @IStatementImpl_setCursorNameDispatcher; - IStatementImpl_vTable.free := @IStatementImpl_freeDispatcher; + IStatementImpl_vTable.deprecatedFree := @IStatementImpl_deprecatedFreeDispatcher; IStatementImpl_vTable.getFlags := @IStatementImpl_getFlagsDispatcher; IStatementImpl_vTable.getTimeout := @IStatementImpl_getTimeoutDispatcher; IStatementImpl_vTable.setTimeout := @IStatementImpl_setTimeoutDispatcher; IStatementImpl_vTable.createBatch := @IStatementImpl_createBatchDispatcher; + IStatementImpl_vTable.free := @IStatementImpl_freeDispatcher; IBatchImpl_vTable := BatchVTable.create; - IBatchImpl_vTable.version := 3; + IBatchImpl_vTable.version := 4; IBatchImpl_vTable.addRef := @IBatchImpl_addRefDispatcher; IBatchImpl_vTable.release := @IBatchImpl_releaseDispatcher; IBatchImpl_vTable.add := @IBatchImpl_addDispatcher; @@ -14975,7 +16550,9 @@ initialization IBatchImpl_vTable.getBlobAlignment := @IBatchImpl_getBlobAlignmentDispatcher; IBatchImpl_vTable.getMetadata := @IBatchImpl_getMetadataDispatcher; IBatchImpl_vTable.setDefaultBpb := @IBatchImpl_setDefaultBpbDispatcher; + IBatchImpl_vTable.deprecatedClose := @IBatchImpl_deprecatedCloseDispatcher; IBatchImpl_vTable.close := @IBatchImpl_closeDispatcher; + IBatchImpl_vTable.getInfo := @IBatchImpl_getInfoDispatcher; IBatchCompletionStateImpl_vTable := BatchCompletionStateVTable.create; IBatchCompletionStateImpl_vTable.version := 3; @@ -14986,14 +16563,15 @@ initialization IBatchCompletionStateImpl_vTable.getStatus := @IBatchCompletionStateImpl_getStatusDispatcher; IReplicatorImpl_vTable := ReplicatorVTable.create; - IReplicatorImpl_vTable.version := 3; + IReplicatorImpl_vTable.version := 4; IReplicatorImpl_vTable.addRef := @IReplicatorImpl_addRefDispatcher; IReplicatorImpl_vTable.release := @IReplicatorImpl_releaseDispatcher; IReplicatorImpl_vTable.process := @IReplicatorImpl_processDispatcher; + IReplicatorImpl_vTable.deprecatedClose := @IReplicatorImpl_deprecatedCloseDispatcher; IReplicatorImpl_vTable.close := @IReplicatorImpl_closeDispatcher; IRequestImpl_vTable := RequestVTable.create; - IRequestImpl_vTable.version := 3; + IRequestImpl_vTable.version := 4; IRequestImpl_vTable.addRef := @IRequestImpl_addRefDispatcher; IRequestImpl_vTable.release := @IRequestImpl_releaseDispatcher; IRequestImpl_vTable.receive := @IRequestImpl_receiveDispatcher; @@ -15002,16 +16580,18 @@ initialization IRequestImpl_vTable.start := @IRequestImpl_startDispatcher; IRequestImpl_vTable.startAndSend := @IRequestImpl_startAndSendDispatcher; IRequestImpl_vTable.unwind := @IRequestImpl_unwindDispatcher; + IRequestImpl_vTable.deprecatedFree := @IRequestImpl_deprecatedFreeDispatcher; IRequestImpl_vTable.free := @IRequestImpl_freeDispatcher; IEventsImpl_vTable := EventsVTable.create; - IEventsImpl_vTable.version := 3; + IEventsImpl_vTable.version := 4; IEventsImpl_vTable.addRef := @IEventsImpl_addRefDispatcher; IEventsImpl_vTable.release := @IEventsImpl_releaseDispatcher; + IEventsImpl_vTable.deprecatedCancel := @IEventsImpl_deprecatedCancelDispatcher; IEventsImpl_vTable.cancel := @IEventsImpl_cancelDispatcher; IAttachmentImpl_vTable := AttachmentVTable.create; - IAttachmentImpl_vTable.version := 4; + IAttachmentImpl_vTable.version := 5; IAttachmentImpl_vTable.addRef := @IAttachmentImpl_addRefDispatcher; IAttachmentImpl_vTable.release := @IAttachmentImpl_releaseDispatcher; IAttachmentImpl_vTable.getInfo := @IAttachmentImpl_getInfoDispatcher; @@ -15030,22 +16610,26 @@ initialization IAttachmentImpl_vTable.queEvents := @IAttachmentImpl_queEventsDispatcher; IAttachmentImpl_vTable.cancelOperation := @IAttachmentImpl_cancelOperationDispatcher; IAttachmentImpl_vTable.ping := @IAttachmentImpl_pingDispatcher; - IAttachmentImpl_vTable.detach := @IAttachmentImpl_detachDispatcher; - IAttachmentImpl_vTable.dropDatabase := @IAttachmentImpl_dropDatabaseDispatcher; + IAttachmentImpl_vTable.deprecatedDetach := @IAttachmentImpl_deprecatedDetachDispatcher; + IAttachmentImpl_vTable.deprecatedDropDatabase := @IAttachmentImpl_deprecatedDropDatabaseDispatcher; IAttachmentImpl_vTable.getIdleTimeout := @IAttachmentImpl_getIdleTimeoutDispatcher; IAttachmentImpl_vTable.setIdleTimeout := @IAttachmentImpl_setIdleTimeoutDispatcher; IAttachmentImpl_vTable.getStatementTimeout := @IAttachmentImpl_getStatementTimeoutDispatcher; IAttachmentImpl_vTable.setStatementTimeout := @IAttachmentImpl_setStatementTimeoutDispatcher; IAttachmentImpl_vTable.createBatch := @IAttachmentImpl_createBatchDispatcher; IAttachmentImpl_vTable.createReplicator := @IAttachmentImpl_createReplicatorDispatcher; + IAttachmentImpl_vTable.detach := @IAttachmentImpl_detachDispatcher; + IAttachmentImpl_vTable.dropDatabase := @IAttachmentImpl_dropDatabaseDispatcher; IServiceImpl_vTable := ServiceVTable.create; - IServiceImpl_vTable.version := 3; + IServiceImpl_vTable.version := 5; IServiceImpl_vTable.addRef := @IServiceImpl_addRefDispatcher; IServiceImpl_vTable.release := @IServiceImpl_releaseDispatcher; - IServiceImpl_vTable.detach := @IServiceImpl_detachDispatcher; + IServiceImpl_vTable.deprecatedDetach := @IServiceImpl_deprecatedDetachDispatcher; IServiceImpl_vTable.query := @IServiceImpl_queryDispatcher; IServiceImpl_vTable.start := @IServiceImpl_startDispatcher; + IServiceImpl_vTable.detach := @IServiceImpl_detachDispatcher; + IServiceImpl_vTable.cancel := @IServiceImpl_cancelDispatcher; IProviderImpl_vTable := ProviderVTable.create; IProviderImpl_vTable.version := 4; @@ -15205,8 +16789,12 @@ initialization IWireCryptPluginImpl_vTable.setSpecificData := @IWireCryptPluginImpl_setSpecificDataDispatcher; ICryptKeyCallbackImpl_vTable := CryptKeyCallbackVTable.create; - ICryptKeyCallbackImpl_vTable.version := 2; + ICryptKeyCallbackImpl_vTable.version := 3; ICryptKeyCallbackImpl_vTable.callback := @ICryptKeyCallbackImpl_callbackDispatcher; + ICryptKeyCallbackImpl_vTable.dummy1 := @ICryptKeyCallbackImpl_dummy1Dispatcher; + ICryptKeyCallbackImpl_vTable.dummy2 := @ICryptKeyCallbackImpl_dummy2Dispatcher; + ICryptKeyCallbackImpl_vTable.getHashLength := @ICryptKeyCallbackImpl_getHashLengthDispatcher; + ICryptKeyCallbackImpl_vTable.getHashData := @ICryptKeyCallbackImpl_getHashDataDispatcher; IKeyHolderPluginImpl_vTable := KeyHolderPluginVTable.create; IKeyHolderPluginImpl_vTable.version := 5; @@ -15511,7 +17099,7 @@ initialization ITraceInitInfoImpl_vTable.getLogWriter := @ITraceInitInfoImpl_getLogWriterDispatcher; ITracePluginImpl_vTable := TracePluginVTable.create; - ITracePluginImpl_vTable.version := 3; + ITracePluginImpl_vTable.version := 4; ITracePluginImpl_vTable.addRef := @ITracePluginImpl_addRefDispatcher; ITracePluginImpl_vTable.release := @ITracePluginImpl_releaseDispatcher; ITracePluginImpl_vTable.trace_get_error := @ITracePluginImpl_trace_get_errorDispatcher; @@ -15535,6 +17123,7 @@ initialization ITracePluginImpl_vTable.trace_event_error := @ITracePluginImpl_trace_event_errorDispatcher; ITracePluginImpl_vTable.trace_event_sweep := @ITracePluginImpl_trace_event_sweepDispatcher; ITracePluginImpl_vTable.trace_func_execute := @ITracePluginImpl_trace_func_executeDispatcher; + ITracePluginImpl_vTable.trace_dsql_restart := @ITracePluginImpl_trace_dsql_restartDispatcher; ITraceFactoryImpl_vTable := TraceFactoryVTable.create; ITraceFactoryImpl_vTable.version := 4; diff --git a/src/include/gen/codetext.h b/src/include/gen/codetext.h index 14424f4daf5..f6188e45b38 100644 --- a/src/include/gen/codetext.h +++ b/src/include/gen/codetext.h @@ -838,7 +838,7 @@ static const struct { {"overriding_without_identity", 335545134}, {"overriding_system_invalid", 335545135}, {"overriding_user_invalid", 335545136}, - {"overriding_system_missing", 335545137}, + {"overriding_missing", 335545137}, {"decprecision_err", 335545138}, {"decfloat_divide_by_zero", 335545139}, {"decfloat_inexact_result", 335545140}, @@ -975,6 +975,9 @@ static const struct { {"repl_error", 335545271}, {"ses_reset_failed", 335545272}, {"block_size", 335545273}, + {"tom_key_length", 335545274}, + {"inf_invalid_args", 335545275}, + {"sysf_invalid_null_empty", 335545276}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, @@ -1456,6 +1459,11 @@ static const struct { {"nbackup_deco_parse", 337117259}, {"nbackup_lostrec_guid_db", 337117261}, {"nbackup_seq_misuse", 337117265}, + {"nbackup_wrong_param", 337117268}, + {"nbackup_clean_hist_misuse", 337117269}, + {"nbackup_clean_hist_missed", 337117270}, + {"nbackup_keep_hist_missed", 337117271}, + {"nbackup_second_keep_switch", 337117272}, {"trace_conflict_acts", 337182750}, {"trace_act_notfound", 337182751}, {"trace_switch_once", 337182752}, diff --git a/src/include/gen/iberror.h b/src/include/gen/iberror.h index 0e7fd413662..b32a4210afe 100644 --- a/src/include/gen/iberror.h +++ b/src/include/gen/iberror.h @@ -872,7 +872,7 @@ const ISC_STATUS isc_att_shut_engine = 335545133L; const ISC_STATUS isc_overriding_without_identity = 335545134L; const ISC_STATUS isc_overriding_system_invalid = 335545135L; const ISC_STATUS isc_overriding_user_invalid = 335545136L; -const ISC_STATUS isc_overriding_system_missing = 335545137L; +const ISC_STATUS isc_overriding_missing = 335545137L; const ISC_STATUS isc_decprecision_err = 335545138L; const ISC_STATUS isc_decfloat_divide_by_zero = 335545139L; const ISC_STATUS isc_decfloat_inexact_result = 335545140L; @@ -1009,6 +1009,9 @@ const ISC_STATUS isc_wrong_page = 335545270L; const ISC_STATUS isc_repl_error = 335545271L; const ISC_STATUS isc_ses_reset_failed = 335545272L; const ISC_STATUS isc_block_size = 335545273L; +const ISC_STATUS isc_tom_key_length = 335545274L; +const ISC_STATUS isc_inf_invalid_args = 335545275L; +const ISC_STATUS isc_sysf_invalid_null_empty = 335545276L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1490,6 +1493,11 @@ const ISC_STATUS isc_nbackup_user_stop = 337117257L; const ISC_STATUS isc_nbackup_deco_parse = 337117259L; const ISC_STATUS isc_nbackup_lostrec_guid_db = 337117261L; const ISC_STATUS isc_nbackup_seq_misuse = 337117265L; +const ISC_STATUS isc_nbackup_wrong_param = 337117268L; +const ISC_STATUS isc_nbackup_clean_hist_misuse = 337117269L; +const ISC_STATUS isc_nbackup_clean_hist_missed = 337117270L; +const ISC_STATUS isc_nbackup_keep_hist_missed = 337117271L; +const ISC_STATUS isc_nbackup_second_keep_switch = 337117272L; const ISC_STATUS isc_trace_conflict_acts = 337182750L; const ISC_STATUS isc_trace_act_notfound = 337182751L; const ISC_STATUS isc_trace_switch_once = 337182752L; @@ -1501,7 +1509,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L; const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1445; +const ISC_STATUS isc_err_max = 1453; #else /* c definitions */ @@ -2343,7 +2351,7 @@ const ISC_STATUS isc_err_max = 1445; #define isc_overriding_without_identity 335545134L #define isc_overriding_system_invalid 335545135L #define isc_overriding_user_invalid 335545136L -#define isc_overriding_system_missing 335545137L +#define isc_overriding_missing 335545137L #define isc_decprecision_err 335545138L #define isc_decfloat_divide_by_zero 335545139L #define isc_decfloat_inexact_result 335545140L @@ -2480,6 +2488,9 @@ const ISC_STATUS isc_err_max = 1445; #define isc_repl_error 335545271L #define isc_ses_reset_failed 335545272L #define isc_block_size 335545273L +#define isc_tom_key_length 335545274L +#define isc_inf_invalid_args 335545275L +#define isc_sysf_invalid_null_empty 335545276L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2961,6 +2972,11 @@ const ISC_STATUS isc_err_max = 1445; #define isc_nbackup_deco_parse 337117259L #define isc_nbackup_lostrec_guid_db 337117261L #define isc_nbackup_seq_misuse 337117265L +#define isc_nbackup_wrong_param 337117268L +#define isc_nbackup_clean_hist_misuse 337117269L +#define isc_nbackup_clean_hist_missed 337117270L +#define isc_nbackup_keep_hist_missed 337117271L +#define isc_nbackup_second_keep_switch 337117272L #define isc_trace_conflict_acts 337182750L #define isc_trace_act_notfound 337182751L #define isc_trace_switch_once 337182752L @@ -2972,7 +2988,7 @@ const ISC_STATUS isc_err_max = 1445; #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1445 +#define isc_err_max 1453 #endif diff --git a/src/include/gen/msgs.h b/src/include/gen/msgs.h index 65d3caa2b96..54da872faf6 100644 --- a/src/include/gen/msgs.h +++ b/src/include/gen/msgs.h @@ -544,8 +544,8 @@ static const struct { {335544840, "cannot update"}, /* no_update */ {335544841, "Cursor is already open"}, /* cursor_already_open */ {335544842, "@1"}, /* stack_trace */ - {335544843, "Context variable @1 is not found in namespace @2"}, /* ctx_var_not_found */ - {335544844, "Invalid namespace name @1 passed to @2"}, /* ctx_namespace_invalid */ + {335544843, "Context variable '@1' is not found in namespace '@2'"}, /* ctx_var_not_found */ + {335544844, "Invalid namespace name '@1' passed to @2"}, /* ctx_namespace_invalid */ {335544845, "Too many context variables"}, /* ctx_too_big */ {335544846, "Invalid argument passed to @1"}, /* ctx_bad_argument */ {335544847, "BLR syntax error. Identifier @1... is too long"}, /* identifier_too_long */ @@ -688,7 +688,7 @@ Data source : @4"}, /* eds_statement */ {335544981, "Floating point overflow in built-in function @1"}, /* sysf_fp_overflow */ {335544982, "Floating point overflow in result from UDF @1"}, /* udf_fp_overflow */ {335544983, "Invalid floating point value returned by UDF @1"}, /* udf_fp_nan */ - {335544984, "Database is probably already opened by another engine instance in another Windows session"}, /* instance_conflict */ + {335544984, "Shared memory area is probably already created by another engine instance in another Windows session"}, /* instance_conflict */ {335544985, "No free space found in temporary directories"}, /* out_of_temp_space */ {335544986, "Explicit transaction control is not allowed"}, /* eds_expl_tran_ctrl */ {335544987, "Use of TRUSTED switches in spb_command_line is prohibited"}, /* no_trusted_spb */ @@ -822,7 +822,7 @@ Data source : @4"}, /* eds_statement */ {335545115, "Cannot open cursor for non-SELECT statement"}, /* no_cursor */ {335545116, "If specifies @1, then shall not specify @2"}, /* dsql_window_incompat_frames */ {335545117, "RANGE based window with {PRECEDING | FOLLOWING} cannot have ORDER BY with more than one value"}, /* dsql_window_range_multi_key */ - {335545118, "RANGE based window must have an ORDER BY key of numerical, date, time or timestamp types"}, /* dsql_window_range_inv_key_type */ + {335545118, "RANGE based window with PRECEDING/FOLLOWING must have a single ORDER BY key of numerical, date, time or timestamp types"}, /* dsql_window_range_inv_key_type */ {335545119, "Window RANGE/ROWS PRECEDING/FOLLOWING value must be of a numerical type"}, /* dsql_window_frame_value_inv_type */ {335545120, "Invalid PRECEDING or FOLLOWING offset in window function: cannot be negative"}, /* window_frame_value_invalid */ {335545121, "Window @1 not found"}, /* dsql_window_not_found */ @@ -841,7 +841,7 @@ Data source : @4"}, /* eds_statement */ {335545134, "OVERRIDING clause can be used only when an identity column is present in the INSERT's field list for table/view @1"}, /* overriding_without_identity */ {335545135, "OVERRIDING SYSTEM VALUE can be used only for identity column defined as 'GENERATED ALWAYS' in INSERT for table/view @1"}, /* overriding_system_invalid */ {335545136, "OVERRIDING USER VALUE can be used only for identity column defined as 'GENERATED BY DEFAULT' in INSERT for table/view @1"}, /* overriding_user_invalid */ - {335545137, "OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as 'GENERATED ALWAYS' in table/view @1"}, /* overriding_system_missing */ + {335545137, "OVERRIDING clause should be used when an identity column defined as 'GENERATED ALWAYS' is present in the INSERT's field list for table table/view @1"}, /* overriding_missing */ {335545138, "DecFloat precision must be 16 or 34"}, /* decprecision_err */ {335545139, "Decimal float divide by zero. The code attempted to divide a DECFLOAT value by zero."}, /* decfloat_divide_by_zero */ {335545140, "Decimal float inexact result. The result of an operation cannot be represented as a decimal fraction."}, /* decfloat_inexact_result */ @@ -882,7 +882,7 @@ Data source : @4"}, /* eds_statement */ {335545175, "Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob"}, /* big_segment */ {335545176, "Invalid blob policy in the batch for @1() call"}, /* batch_policy */ {335545177, "Can't change default BPB after adding any data to batch"}, /* batch_defbpb */ - {335545178, "Unexpected info buffer structure querying for default blob alignment"}, /* batch_align */ + {335545178, "Unexpected info buffer structure querying for server batch parameters"}, /* batch_align */ {335545179, "Duplicated segment @1 in multisegment connect block parameter"}, /* multi_segment_dup */ {335545180, "Plugin not supported by network protocol"}, /* non_plugin_protocol */ {335545181, "Error parsing message format"}, /* message_format */ @@ -978,6 +978,9 @@ Data source : @4"}, /* eds_statement */ {335545271, "Replication error"}, /* repl_error */ {335545272, "Reset of user session failed. Connection is shut down."}, /* ses_reset_failed */ {335545273, "File size is less than expected"}, /* block_size */ + {335545274, "Invalid key length @1, need >@2"}, /* tom_key_length */ + {335545275, "Invalid information arguments"}, /* inf_invalid_args */ + {335545276, "Empty or NULL parameter @1 is not accepted"}, /* sysf_invalid_null_empty */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ @@ -1459,6 +1462,11 @@ Data source : @4"}, /* eds_statement */ {337117259, "Too complex decompress command (> @1 arguments)"}, /* nbackup_deco_parse */ {337117261, "Cannot find record for database \"@1\" backup GUID @2 in the backup history"}, /* nbackup_lostrec_guid_db */ {337117265, "Switch -SEQ(UENCE) can be used only with -FIXUP or -RESTORE"}, /* nbackup_seq_misuse */ + {337117268, "Wrong parameter value for switch @1"}, /* nbackup_wrong_param */ + {337117269, "Switch -CLEAN_HISTORY can be used only with -BACKUP"}, /* nbackup_clean_hist_misuse */ + {337117270, "-KEEP can be used only with -CLEAN_HISTORY"}, /* nbackup_clean_hist_missed */ + {337117271, "-KEEP is required with -CLEAN_HISTORY"}, /* nbackup_keep_hist_missed */ + {337117272, "-KEEP can be used one time only"}, /* nbackup_second_keep_switch */ {337182750, "conflicting actions \"@1\" and \"@2\" found"}, /* trace_conflict_acts */ {337182751, "action switch not found"}, /* trace_act_notfound */ {337182752, "switch \"@1\" must be set only once"}, /* trace_switch_once */ diff --git a/src/include/gen/sql_code.h b/src/include/gen/sql_code.h index 6eb004667c5..7215defe749 100644 --- a/src/include/gen/sql_code.h +++ b/src/include/gen/sql_code.h @@ -837,7 +837,7 @@ static const struct { {335545134, -902}, /* 814 overriding_without_identity */ {335545135, -902}, /* 815 overriding_system_invalid */ {335545136, -902}, /* 816 overriding_user_invalid */ - {335545137, -902}, /* 817 overriding_system_missing */ + {335545137, -902}, /* 817 overriding_missing */ {335545138, -842}, /* 818 decprecision_err */ {335545139, -901}, /* 819 decfloat_divide_by_zero */ {335545140, -901}, /* 820 decfloat_inexact_result */ @@ -974,6 +974,9 @@ static const struct { {335545271, -902}, /* 951 repl_error */ {335545272, -902}, /* 952 ses_reset_failed */ {335545273, -902}, /* 953 block_size */ + {335545274, -901}, /* 954 tom_key_length */ + {335545275, -901}, /* 955 inf_invalid_args */ + {335545276, -901}, /* 956 sysf_invalid_null_empty */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ @@ -1022,7 +1025,7 @@ static const struct { {336003092, -502}, /* 20 dsql_cursor_exists */ {336003093, -502}, /* 21 dsql_cursor_rel_ambiguous */ {336003094, -502}, /* 22 dsql_cursor_rel_not_found */ - {336003095, -502}, /* 23 dsql_cursor_not_open */ + {336003095, -504}, /* 23 dsql_cursor_not_open */ {336003096, -607}, /* 24 dsql_type_not_supp_ext_tab */ {336003097, -804}, /* 25 dsql_feature_not_supported_ods */ {336003098, -660}, /* 26 primary_key_required */ @@ -1455,6 +1458,11 @@ static const struct { {337117259, -901}, /* 75 nbackup_deco_parse */ {337117261, -901}, /* 77 nbackup_lostrec_guid_db */ {337117265, -901}, /* 81 nbackup_seq_misuse */ + {337117268, -901}, /* 84 nbackup_wrong_param */ + {337117269, -901}, /* 85 nbackup_clean_hist_misuse */ + {337117270, -901}, /* 86 nbackup_clean_hist_missed */ + {337117271, -901}, /* 87 nbackup_keep_hist_missed */ + {337117272, -901}, /* 88 nbackup_second_keep_switch */ {337182750, -901}, /* 30 trace_conflict_acts */ {337182751, -901}, /* 31 trace_act_notfound */ {337182752, -901}, /* 32 trace_switch_once */ diff --git a/src/include/gen/sql_state.h b/src/include/gen/sql_state.h index bee9f7cefbe..9cf65982a15 100644 --- a/src/include/gen/sql_state.h +++ b/src/include/gen/sql_state.h @@ -837,7 +837,7 @@ static const struct { {335545134, "42000"}, // 814 overriding_without_identity {335545135, "42000"}, // 815 overriding_system_invalid {335545136, "42000"}, // 816 overriding_user_invalid - {335545137, "42000"}, // 817 overriding_system_missing + {335545137, "42000"}, // 817 overriding_missing {335545138, "HY104"}, // 818 decprecision_err {335545139, "22012"}, // 819 decfloat_divide_by_zero {335545140, "22000"}, // 820 decfloat_inexact_result @@ -974,6 +974,9 @@ static const struct { {335545271, "HY000"}, // 951 repl_error {335545272, "08003"}, // 952 ses_reset_failed {335545273, "XX000"}, // 953 block_size + {335545274, "22023"}, // 954 tom_key_length + {335545275, "HY000"}, // 955 inf_invalid_args + {335545276, "22023"}, // 956 sysf_invalid_null_empty {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw @@ -1455,6 +1458,11 @@ static const struct { {337117259, "54023"}, // 75 nbackup_deco_parse {337117261, "00000"}, // 77 nbackup_lostrec_guid_db {337117265, "00000"}, // 81 nbackup_seq_misuse + {337117268, "00000"}, // 84 nbackup_wrong_param + {337117269, "00000"}, // 85 nbackup_clean_hist_misuse + {337117270, "00000"}, // 86 nbackup_clean_hist_missed + {337117271, "00000"}, // 87 nbackup_keep_hist_missed + {337117272, "00000"}, // 88 nbackup_second_keep_switch {337182750, "00000"}, // 30 trace_conflict_acts {337182751, "00000"}, // 31 trace_act_notfound {337182752, "00000"}, // 32 trace_switch_once diff --git a/src/include/ibase.h b/src/include/ibase.h index 53820100767..daa69c1ce15 100644 --- a/src/include/ibase.h +++ b/src/include/ibase.h @@ -64,6 +64,18 @@ #define FB_API_DEPRECATED #endif +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#define FB_DLL_EXPORT __declspec(dllexport) +#elif defined __has_attribute +#if __has_attribute (visibility) +#define FB_DLL_EXPORT __attribute__ ((visibility("default"))) +#else +#define FB_DLL_EXPORT +#endif +#else +#define FB_DLL_EXPORT +#endif + #include "./firebird/impl/types_pub.h" /***********************/ diff --git a/src/intl/charsets/cs_437.h b/src/intl/charsets/cs_437.h index 9c70b0fa1ee..b408d39572d 100644 --- a/src/intl/charsets/cs_437.h +++ b/src/intl/charsets/cs_437.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp437 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp437 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp437 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00a2 #CENT SIGN -0x9c 0x00a3 #POUND SIGN -0x9d 0x00a5 #YEN SIGN -0x9e 0x20a7 #PESETA SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x2310 #REVERSED NOT SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_737.h b/src/intl/charsets/cs_737.h index 7f34bc7ceb9..d569532ee36 100644 --- a/src/intl/charsets/cs_737.h +++ b/src/intl/charsets/cs_737.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp737 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp737 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp737 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0391 #GREEK CAPITAL LETTER ALPHA -0x81 0x0392 #GREEK CAPITAL LETTER BETA -0x82 0x0393 #GREEK CAPITAL LETTER GAMMA -0x83 0x0394 #GREEK CAPITAL LETTER DELTA -0x84 0x0395 #GREEK CAPITAL LETTER EPSILON -0x85 0x0396 #GREEK CAPITAL LETTER ZETA -0x86 0x0397 #GREEK CAPITAL LETTER ETA -0x87 0x0398 #GREEK CAPITAL LETTER THETA -0x88 0x0399 #GREEK CAPITAL LETTER IOTA -0x89 0x039a #GREEK CAPITAL LETTER KAPPA -0x8a 0x039b #GREEK CAPITAL LETTER LAMDA -0x8b 0x039c #GREEK CAPITAL LETTER MU -0x8c 0x039d #GREEK CAPITAL LETTER NU -0x8d 0x039e #GREEK CAPITAL LETTER XI -0x8e 0x039f #GREEK CAPITAL LETTER OMICRON -0x8f 0x03a0 #GREEK CAPITAL LETTER PI -0x90 0x03a1 #GREEK CAPITAL LETTER RHO -0x91 0x03a3 #GREEK CAPITAL LETTER SIGMA -0x92 0x03a4 #GREEK CAPITAL LETTER TAU -0x93 0x03a5 #GREEK CAPITAL LETTER UPSILON -0x94 0x03a6 #GREEK CAPITAL LETTER PHI -0x95 0x03a7 #GREEK CAPITAL LETTER CHI -0x96 0x03a8 #GREEK CAPITAL LETTER PSI -0x97 0x03a9 #GREEK CAPITAL LETTER OMEGA -0x98 0x03b1 #GREEK SMALL LETTER ALPHA -0x99 0x03b2 #GREEK SMALL LETTER BETA -0x9a 0x03b3 #GREEK SMALL LETTER GAMMA -0x9b 0x03b4 #GREEK SMALL LETTER DELTA -0x9c 0x03b5 #GREEK SMALL LETTER EPSILON -0x9d 0x03b6 #GREEK SMALL LETTER ZETA -0x9e 0x03b7 #GREEK SMALL LETTER ETA -0x9f 0x03b8 #GREEK SMALL LETTER THETA -0xa0 0x03b9 #GREEK SMALL LETTER IOTA -0xa1 0x03ba #GREEK SMALL LETTER KAPPA -0xa2 0x03bb #GREEK SMALL LETTER LAMDA -0xa3 0x03bc #GREEK SMALL LETTER MU -0xa4 0x03bd #GREEK SMALL LETTER NU -0xa5 0x03be #GREEK SMALL LETTER XI -0xa6 0x03bf #GREEK SMALL LETTER OMICRON -0xa7 0x03c0 #GREEK SMALL LETTER PI -0xa8 0x03c1 #GREEK SMALL LETTER RHO -0xa9 0x03c3 #GREEK SMALL LETTER SIGMA -0xaa 0x03c2 #GREEK SMALL LETTER FINAL SIGMA -0xab 0x03c4 #GREEK SMALL LETTER TAU -0xac 0x03c5 #GREEK SMALL LETTER UPSILON -0xad 0x03c6 #GREEK SMALL LETTER PHI -0xae 0x03c7 #GREEK SMALL LETTER CHI -0xaf 0x03c8 #GREEK SMALL LETTER PSI -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03c9 #GREEK SMALL LETTER OMEGA -0xe1 0x03ac #GREEK SMALL LETTER ALPHA WITH TONOS -0xe2 0x03ad #GREEK SMALL LETTER EPSILON WITH TONOS -0xe3 0x03ae #GREEK SMALL LETTER ETA WITH TONOS -0xe4 0x03ca #GREEK SMALL LETTER IOTA WITH DIALYTIKA -0xe5 0x03af #GREEK SMALL LETTER IOTA WITH TONOS -0xe6 0x03cc #GREEK SMALL LETTER OMICRON WITH TONOS -0xe7 0x03cd #GREEK SMALL LETTER UPSILON WITH TONOS -0xe8 0x03cb #GREEK SMALL LETTER UPSILON WITH DIALYTIKA -0xe9 0x03ce #GREEK SMALL LETTER OMEGA WITH TONOS -0xea 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS -0xeb 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS -0xec 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS -0xed 0x038a #GREEK CAPITAL LETTER IOTA WITH TONOS -0xee 0x038c #GREEK CAPITAL LETTER OMICRON WITH TONOS -0xef 0x038e #GREEK CAPITAL LETTER UPSILON WITH TONOS -0xf0 0x038f #GREEK CAPITAL LETTER OMEGA WITH TONOS -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x03aa #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -0xf5 0x03ab #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_775.h b/src/intl/charsets/cs_775.h index f0eb0bbf631..d387ff0a4bb 100644 --- a/src/intl/charsets/cs_775.h +++ b/src/intl/charsets/cs_775.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp775 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp775 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp775 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x0101 #LATIN SMALL LETTER A WITH MACRON -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x0123 #LATIN SMALL LETTER G WITH CEDILLA -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0x88 0x0142 #LATIN SMALL LETTER L WITH STROKE -0x89 0x0113 #LATIN SMALL LETTER E WITH MACRON -0x8a 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA -0x8b 0x0157 #LATIN SMALL LETTER R WITH CEDILLA -0x8c 0x012b #LATIN SMALL LETTER I WITH MACRON -0x8d 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x014d #LATIN SMALL LETTER O WITH MACRON -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA -0x96 0x00a2 #CENT SIGN -0x97 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0x98 0x015b #LATIN SMALL LETTER S WITH ACUTE -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x00d7 #MULTIPLICATION SIGN -0x9f 0x00a4 #CURRENCY SIGN -0xa0 0x0100 #LATIN CAPITAL LETTER A WITH MACRON -0xa1 0x012a #LATIN CAPITAL LETTER I WITH MACRON -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xa4 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xa5 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xa6 0x201d #RIGHT DOUBLE QUOTATION MARK -0xa7 0x00a6 #BROKEN BAR -0xa8 0x00a9 #COPYRIGHT SIGN -0xa9 0x00ae #REGISTERED SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xb6 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xb7 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xb8 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x012e #LATIN CAPITAL LETTER I WITH OGONEK -0xbe 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK -0xc7 0x016a #LATIN CAPITAL LETTER U WITH MACRON -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xd0 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xd1 0x010d #LATIN SMALL LETTER C WITH CARON -0xd2 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xd3 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE -0xd4 0x012f #LATIN SMALL LETTER I WITH OGONEK -0xd5 0x0161 #LATIN SMALL LETTER S WITH CARON -0xd6 0x0173 #LATIN SMALL LETTER U WITH OGONEK -0xd7 0x016b #LATIN SMALL LETTER U WITH MACRON -0xd8 0x017e #LATIN SMALL LETTER Z WITH CARON -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x014c #LATIN CAPITAL LETTER O WITH MACRON -0xe3 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xe4 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xe5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xe6 0x00b5 #MICRO SIGN -0xe7 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xe8 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA -0xe9 0x0137 #LATIN SMALL LETTER K WITH CEDILLA -0xea 0x013b #LATIN CAPITAL LETTER L WITH CEDILLA -0xeb 0x013c #LATIN SMALL LETTER L WITH CEDILLA -0xec 0x0146 #LATIN SMALL LETTER N WITH CEDILLA -0xed 0x0112 #LATIN CAPITAL LETTER E WITH MACRON -0xee 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA -0xef 0x2019 #RIGHT SINGLE QUOTATION MARK -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x201c #LEFT DOUBLE QUOTATION MARK -0xf3 0x00be #VULGAR FRACTION THREE QUARTERS -0xf4 0x00b6 #PILCROW SIGN -0xf5 0x00a7 #SECTION SIGN -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x201e #DOUBLE LOW-9 QUOTATION MARK -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x00b9 #SUPERSCRIPT ONE -0xfc 0x00b3 #SUPERSCRIPT THREE -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_850.h b/src/intl/charsets/cs_850.h index ff153a2f37f..3825771cc24 100644 --- a/src/intl/charsets/cs_850.h +++ b/src/intl/charsets/cs_850.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp850 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp850 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp850 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x00d7 #MULTIPLICATION SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x00ae #REGISTERED SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xb6 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xb7 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xb8 0x00a9 #COPYRIGHT SIGN -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x00a2 #CENT SIGN -0xbe 0x00a5 #YEN SIGN -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xc7 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x00a4 #CURRENCY SIGN -0xd0 0x00f0 #LATIN SMALL LETTER ETH -0xd1 0x00d0 #LATIN CAPITAL LETTER ETH -0xd2 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xd3 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xd4 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xd5 0x0131 #LATIN SMALL LETTER DOTLESS I -0xd6 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xd7 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xd8 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x00a6 #BROKEN BAR -0xde 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xe3 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xe4 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xe5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xe6 0x00b5 #MICRO SIGN -0xe7 0x00fe #LATIN SMALL LETTER THORN -0xe8 0x00de #LATIN CAPITAL LETTER THORN -0xe9 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xea 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xeb 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xec 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xed 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xee 0x00af #MACRON -0xef 0x00b4 #ACUTE ACCENT -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2017 #DOUBLE LOW LINE -0xf3 0x00be #VULGAR FRACTION THREE QUARTERS -0xf4 0x00b6 #PILCROW SIGN -0xf5 0x00a7 #SECTION SIGN -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x00b8 #CEDILLA -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x00a8 #DIAERESIS -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x00b9 #SUPERSCRIPT ONE -0xfc 0x00b3 #SUPERSCRIPT THREE -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_852.h b/src/intl/charsets/cs_852.h index 9a104cb1fde..629a64bfe3d 100644 --- a/src/intl/charsets/cs_852.h +++ b/src/intl/charsets/cs_852.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp852 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp852 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp852 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x016f #LATIN SMALL LETTER U WITH RING ABOVE -0x86 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x0142 #LATIN SMALL LETTER L WITH STROKE -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x0150 #LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -0x8b 0x0151 #LATIN SMALL LETTER O WITH DOUBLE ACUTE -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x0139 #LATIN CAPITAL LETTER L WITH ACUTE -0x92 0x013a #LATIN SMALL LETTER L WITH ACUTE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x013d #LATIN CAPITAL LETTER L WITH CARON -0x96 0x013e #LATIN SMALL LETTER L WITH CARON -0x97 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0x98 0x015b #LATIN SMALL LETTER S WITH ACUTE -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x0164 #LATIN CAPITAL LETTER T WITH CARON -0x9c 0x0165 #LATIN SMALL LETTER T WITH CARON -0x9d 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0x9e 0x00d7 #MULTIPLICATION SIGN -0x9f 0x010d #LATIN SMALL LETTER C WITH CARON -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xa5 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xa6 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xa7 0x017e #LATIN SMALL LETTER Z WITH CARON -0xa8 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xa9 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xaa 0x00ac #NOT SIGN -0xab 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xac 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xad 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xb6 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xb7 0x011a #LATIN CAPITAL LETTER E WITH CARON -0xb8 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xbe 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x0102 #LATIN CAPITAL LETTER A WITH BREVE -0xc7 0x0103 #LATIN SMALL LETTER A WITH BREVE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x00a4 #CURRENCY SIGN -0xd0 0x0111 #LATIN SMALL LETTER D WITH STROKE -0xd1 0x0110 #LATIN CAPITAL LETTER D WITH STROKE -0xd2 0x010e #LATIN CAPITAL LETTER D WITH CARON -0xd3 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xd4 0x010f #LATIN SMALL LETTER D WITH CARON -0xd5 0x0147 #LATIN CAPITAL LETTER N WITH CARON -0xd6 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xd7 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xd8 0x011b #LATIN SMALL LETTER E WITH CARON -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x0162 #LATIN CAPITAL LETTER T WITH CEDILLA -0xde 0x016e #LATIN CAPITAL LETTER U WITH RING ABOVE -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xe3 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xe4 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xe5 0x0148 #LATIN SMALL LETTER N WITH CARON -0xe6 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xe7 0x0161 #LATIN SMALL LETTER S WITH CARON -0xe8 0x0154 #LATIN CAPITAL LETTER R WITH ACUTE -0xe9 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xea 0x0155 #LATIN SMALL LETTER R WITH ACUTE -0xeb 0x0170 #LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -0xec 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xed 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xee 0x0163 #LATIN SMALL LETTER T WITH CEDILLA -0xef 0x00b4 #ACUTE ACCENT -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x02dd #DOUBLE ACUTE ACCENT -0xf2 0x02db #OGONEK -0xf3 0x02c7 #CARON -0xf4 0x02d8 #BREVE -0xf5 0x00a7 #SECTION SIGN -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x00b8 #CEDILLA -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x00a8 #DIAERESIS -0xfa 0x02d9 #DOT ABOVE -0xfb 0x0171 #LATIN SMALL LETTER U WITH DOUBLE ACUTE -0xfc 0x0158 #LATIN CAPITAL LETTER R WITH CARON -0xfd 0x0159 #LATIN SMALL LETTER R WITH CARON -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_857.h b/src/intl/charsets/cs_857.h index 8e5a3e3cddb..a2e830f98a2 100644 --- a/src/intl/charsets/cs_857.h +++ b/src/intl/charsets/cs_857.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp857 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp857 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp857 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x0131 #LATIN SMALL LETTER DOTLESS I -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0x9f 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x011e #LATIN CAPITAL LETTER G WITH BREVE -0xa7 0x011f #LATIN SMALL LETTER G WITH BREVE -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x00ae #REGISTERED SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xb6 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xb7 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xb8 0x00a9 #COPYRIGHT SIGN -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x00a2 #CENT SIGN -0xbe 0x00a5 #YEN SIGN -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xc7 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x00a4 #CURRENCY SIGN -0xd0 0x00ba #MASCULINE ORDINAL INDICATOR -0xd1 0x00aa #FEMININE ORDINAL INDICATOR -0xd2 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xd3 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xd4 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xd5 #UNDEFINED -0xd6 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xd7 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xd8 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x00a6 #BROKEN BAR -0xde 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xe3 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xe4 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xe5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xe6 0x00b5 #MICRO SIGN -0xe7 #UNDEFINED -0xe8 0x00d7 #MULTIPLICATION SIGN -0xe9 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xea 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xeb 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS -0xee 0x00af #MACRON -0xef 0x00b4 #ACUTE ACCENT -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 #UNDEFINED -0xf3 0x00be #VULGAR FRACTION THREE QUARTERS -0xf4 0x00b6 #PILCROW SIGN -0xf5 0x00a7 #SECTION SIGN -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x00b8 #CEDILLA -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x00a8 #DIAERESIS -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x00b9 #SUPERSCRIPT ONE -0xfc 0x00b3 #SUPERSCRIPT THREE -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_858.h b/src/intl/charsets/cs_858.h index 312b85612fd..c0536f1620e 100644 --- a/src/intl/charsets/cs_858.h +++ b/src/intl/charsets/cs_858.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp858 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp858 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp858 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x00d7 #MULTIPLICATION SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x00ae #REGISTERED SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xb6 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xb7 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xb8 0x00a9 #COPYRIGHT SIGN -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x00a2 #CENT SIGN -0xbe 0x00a5 #YEN SIGN -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xc7 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x00a4 #CURRENCY SIGN -0xd0 0x00f0 #LATIN SMALL LETTER ETH -0xd1 0x00d0 #LATIN CAPITAL LETTER ETH -0xd2 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xd3 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xd4 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xd5 0x20ac #EURO SIGN -0xd6 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xd7 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xd8 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x00a6 #BROKEN BAR -0xde 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xe3 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xe4 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xe5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xe6 0x00b5 #MICRO SIGN -0xe7 0x00fe #LATIN SMALL LETTER THORN -0xe8 0x00de #LATIN CAPITAL LETTER THORN -0xe9 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xea 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xeb 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xec 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xed 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xee 0x00af #MACRON -0xef 0x00b4 #ACUTE ACCENT -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2017 #DOUBLE LOW LINE -0xf3 0x00be #VULGAR FRACTION THREE QUARTERS -0xf4 0x00b6 #PILCROW SIGN -0xf5 0x00a7 #SECTION SIGN -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x00b8 #CEDILLA -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x00a8 #DIAERESIS -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x00b9 #SUPERSCRIPT ONE -0xfc 0x00b3 #SUPERSCRIPT THREE -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_860.h b/src/intl/charsets/cs_860.h index 4f5368c80c5..fee7a9d8676 100644 --- a/src/intl/charsets/cs_860.h +++ b/src/intl/charsets/cs_860.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp860 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp860 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp860 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0x8c 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0x8d 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0x8e 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0x8f 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0x92 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0x99 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00a2 #CENT SIGN -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0x9e 0x20a7 #PESETA SIGN -0x9f 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_861.h b/src/intl/charsets/cs_861.h index 6be97da6682..ed4ba91f8c0 100644 --- a/src/intl/charsets/cs_861.h +++ b/src/intl/charsets/cs_861.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp861 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp861 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp861 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00d0 #LATIN CAPITAL LETTER ETH -0x8c 0x00f0 #LATIN SMALL LETTER ETH -0x8d 0x00de #LATIN CAPITAL LETTER THORN -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00fe #LATIN SMALL LETTER THORN -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0x98 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x20a7 #PESETA SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xa5 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xa6 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xa7 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x2310 #REVERSED NOT SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_862.h b/src/intl/charsets/cs_862.h index 21035f1d2da..bbfe19976b5 100644 --- a/src/intl/charsets/cs_862.h +++ b/src/intl/charsets/cs_862.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp862 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp862 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp862 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x05d0 #HEBREW LETTER ALEF -0x81 0x05d1 #HEBREW LETTER BET -0x82 0x05d2 #HEBREW LETTER GIMEL -0x83 0x05d3 #HEBREW LETTER DALET -0x84 0x05d4 #HEBREW LETTER HE -0x85 0x05d5 #HEBREW LETTER VAV -0x86 0x05d6 #HEBREW LETTER ZAYIN -0x87 0x05d7 #HEBREW LETTER HET -0x88 0x05d8 #HEBREW LETTER TET -0x89 0x05d9 #HEBREW LETTER YOD -0x8a 0x05da #HEBREW LETTER FINAL KAF -0x8b 0x05db #HEBREW LETTER KAF -0x8c 0x05dc #HEBREW LETTER LAMED -0x8d 0x05dd #HEBREW LETTER FINAL MEM -0x8e 0x05de #HEBREW LETTER MEM -0x8f 0x05df #HEBREW LETTER FINAL NUN -0x90 0x05e0 #HEBREW LETTER NUN -0x91 0x05e1 #HEBREW LETTER SAMEKH -0x92 0x05e2 #HEBREW LETTER AYIN -0x93 0x05e3 #HEBREW LETTER FINAL PE -0x94 0x05e4 #HEBREW LETTER PE -0x95 0x05e5 #HEBREW LETTER FINAL TSADI -0x96 0x05e6 #HEBREW LETTER TSADI -0x97 0x05e7 #HEBREW LETTER QOF -0x98 0x05e8 #HEBREW LETTER RESH -0x99 0x05e9 #HEBREW LETTER SHIN -0x9a 0x05ea #HEBREW LETTER TAV -0x9b 0x00a2 #CENT SIGN -0x9c 0x00a3 #POUND SIGN -0x9d 0x00a5 #YEN SIGN -0x9e 0x20a7 #PESETA SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x2310 #REVERSED NOT SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_863.h b/src/intl/charsets/cs_863.h index d07e6c97239..bf3e1bee32e 100644 --- a/src/intl/charsets/cs_863.h +++ b/src/intl/charsets/cs_863.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp863 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp863 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp863 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00b6 #PILCROW SIGN -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x2017 #DOUBLE LOW LINE -0x8e 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0x8f 0x00a7 #SECTION SIGN -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0x92 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0x95 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00a4 #CURRENCY SIGN -0x99 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00a2 #CENT SIGN -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0x9e 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00a6 #BROKEN BAR -0xa1 0x00b4 #ACUTE ACCENT -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00a8 #DIAERESIS -0xa5 0x00b8 #CEDILLA -0xa6 0x00b3 #SUPERSCRIPT THREE -0xa7 0x00af #MACRON -0xa8 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xa9 0x2310 #REVERSED NOT SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00be #VULGAR FRACTION THREE QUARTERS -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_864.h b/src/intl/charsets/cs_864.h index 9e5718f3e08..59481ad3caf 100644 --- a/src/intl/charsets/cs_864.h +++ b/src/intl/charsets/cs_864.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp864 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp864 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp864 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x066a #ARABIC PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00b0 #DEGREE SIGN -0x81 0x00b7 #MIDDLE DOT -0x82 0x2219 #BULLET OPERATOR -0x83 0x221a #SQUARE ROOT -0x84 0x2592 #MEDIUM SHADE -0x85 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0x86 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0x87 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0x88 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0x89 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0x8a 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0x8b 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0x8c 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0x8d 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0x8e 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0x8f 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0x90 0x03b2 #GREEK SMALL LETTER BETA -0x91 0x221e #INFINITY -0x92 0x03c6 #GREEK SMALL LETTER PHI -0x93 0x00b1 #PLUS-MINUS SIGN -0x94 0x00bd #VULGAR FRACTION ONE HALF -0x95 0x00bc #VULGAR FRACTION ONE QUARTER -0x96 0x2248 #ALMOST EQUAL TO -0x97 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0x98 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0x99 0xfef7 #ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM -0x9a 0xfef8 #ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM -0x9b #UNDEFINED -0x9c #UNDEFINED -0x9d 0xfefb #ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM -0x9e 0xfefc #ARABIC LIGATURE LAM WITH ALEF FINAL FORM -0x9f #UNDEFINED -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00ad #SOFT HYPHEN -0xa2 0xfe82 #ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0xfe84 #ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM -0xa6 #UNDEFINED -0xa7 #UNDEFINED -0xa8 0xfe8e #ARABIC LETTER ALEF FINAL FORM -0xa9 0xfe8f #ARABIC LETTER BEH ISOLATED FORM -0xaa 0xfe95 #ARABIC LETTER TEH ISOLATED FORM -0xab 0xfe99 #ARABIC LETTER THEH ISOLATED FORM -0xac 0x060c #ARABIC COMMA -0xad 0xfe9d #ARABIC LETTER JEEM ISOLATED FORM -0xae 0xfea1 #ARABIC LETTER HAH ISOLATED FORM -0xaf 0xfea5 #ARABIC LETTER KHAH ISOLATED FORM -0xb0 0x0660 #ARABIC-INDIC DIGIT ZERO -0xb1 0x0661 #ARABIC-INDIC DIGIT ONE -0xb2 0x0662 #ARABIC-INDIC DIGIT TWO -0xb3 0x0663 #ARABIC-INDIC DIGIT THREE -0xb4 0x0664 #ARABIC-INDIC DIGIT FOUR -0xb5 0x0665 #ARABIC-INDIC DIGIT FIVE -0xb6 0x0666 #ARABIC-INDIC DIGIT SIX -0xb7 0x0667 #ARABIC-INDIC DIGIT SEVEN -0xb8 0x0668 #ARABIC-INDIC DIGIT EIGHT -0xb9 0x0669 #ARABIC-INDIC DIGIT NINE -0xba 0xfed1 #ARABIC LETTER FEH ISOLATED FORM -0xbb 0x061b #ARABIC SEMICOLON -0xbc 0xfeb1 #ARABIC LETTER SEEN ISOLATED FORM -0xbd 0xfeb5 #ARABIC LETTER SHEEN ISOLATED FORM -0xbe 0xfeb9 #ARABIC LETTER SAD ISOLATED FORM -0xbf 0x061f #ARABIC QUESTION MARK -0xc0 0x00a2 #CENT SIGN -0xc1 0xfe80 #ARABIC LETTER HAMZA ISOLATED FORM -0xc2 0xfe81 #ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM -0xc3 0xfe83 #ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM -0xc4 0xfe85 #ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM -0xc5 0xfeca #ARABIC LETTER AIN FINAL FORM -0xc6 0xfe8b #ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM -0xc7 0xfe8d #ARABIC LETTER ALEF ISOLATED FORM -0xc8 0xfe91 #ARABIC LETTER BEH INITIAL FORM -0xc9 0xfe93 #ARABIC LETTER TEH MARBUTA ISOLATED FORM -0xca 0xfe97 #ARABIC LETTER TEH INITIAL FORM -0xcb 0xfe9b #ARABIC LETTER THEH INITIAL FORM -0xcc 0xfe9f #ARABIC LETTER JEEM INITIAL FORM -0xcd 0xfea3 #ARABIC LETTER HAH INITIAL FORM -0xce 0xfea7 #ARABIC LETTER KHAH INITIAL FORM -0xcf 0xfea9 #ARABIC LETTER DAL ISOLATED FORM -0xd0 0xfeab #ARABIC LETTER THAL ISOLATED FORM -0xd1 0xfead #ARABIC LETTER REH ISOLATED FORM -0xd2 0xfeaf #ARABIC LETTER ZAIN ISOLATED FORM -0xd3 0xfeb3 #ARABIC LETTER SEEN INITIAL FORM -0xd4 0xfeb7 #ARABIC LETTER SHEEN INITIAL FORM -0xd5 0xfebb #ARABIC LETTER SAD INITIAL FORM -0xd6 0xfebf #ARABIC LETTER DAD INITIAL FORM -0xd7 0xfec1 #ARABIC LETTER TAH ISOLATED FORM -0xd8 0xfec5 #ARABIC LETTER ZAH ISOLATED FORM -0xd9 0xfecb #ARABIC LETTER AIN INITIAL FORM -0xda 0xfecf #ARABIC LETTER GHAIN INITIAL FORM -0xdb 0x00a6 #BROKEN BAR -0xdc 0x00ac #NOT SIGN -0xdd 0x00f7 #DIVISION SIGN -0xde 0x00d7 #MULTIPLICATION SIGN -0xdf 0xfec9 #ARABIC LETTER AIN ISOLATED FORM -0xe0 0x0640 #ARABIC TATWEEL -0xe1 0xfed3 #ARABIC LETTER FEH INITIAL FORM -0xe2 0xfed7 #ARABIC LETTER QAF INITIAL FORM -0xe3 0xfedb #ARABIC LETTER KAF INITIAL FORM -0xe4 0xfedf #ARABIC LETTER LAM INITIAL FORM -0xe5 0xfee3 #ARABIC LETTER MEEM INITIAL FORM -0xe6 0xfee7 #ARABIC LETTER NOON INITIAL FORM -0xe7 0xfeeb #ARABIC LETTER HEH INITIAL FORM -0xe8 0xfeed #ARABIC LETTER WAW ISOLATED FORM -0xe9 0xfeef #ARABIC LETTER ALEF MAKSURA ISOLATED FORM -0xea 0xfef3 #ARABIC LETTER YEH INITIAL FORM -0xeb 0xfebd #ARABIC LETTER DAD ISOLATED FORM -0xec 0xfecc #ARABIC LETTER AIN MEDIAL FORM -0xed 0xfece #ARABIC LETTER GHAIN FINAL FORM -0xee 0xfecd #ARABIC LETTER GHAIN ISOLATED FORM -0xef 0xfee1 #ARABIC LETTER MEEM ISOLATED FORM -0xf0 0xfe7d #ARABIC SHADDA MEDIAL FORM -0xf1 0x0651 #ARABIC SHADDA -0xf2 0xfee5 #ARABIC LETTER NOON ISOLATED FORM -0xf3 0xfee9 #ARABIC LETTER HEH ISOLATED FORM -0xf4 0xfeec #ARABIC LETTER HEH MEDIAL FORM -0xf5 0xfef0 #ARABIC LETTER ALEF MAKSURA FINAL FORM -0xf6 0xfef2 #ARABIC LETTER YEH FINAL FORM -0xf7 0xfed0 #ARABIC LETTER GHAIN MEDIAL FORM -0xf8 0xfed5 #ARABIC LETTER QAF ISOLATED FORM -0xf9 0xfef5 #ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM -0xfa 0xfef6 #ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM -0xfb 0xfedd #ARABIC LETTER LAM ISOLATED FORM -0xfc 0xfed9 #ARABIC LETTER KAF ISOLATED FORM -0xfd 0xfef1 #ARABIC LETTER YEH ISOLATED FORM -0xfe 0x25a0 #BLACK SQUARE -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_865.h b/src/intl/charsets/cs_865.h index c953fefc2ad..f1f9a4101f5 100644 --- a/src/intl/charsets/cs_865.h +++ b/src/intl/charsets/cs_865.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp865 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp865 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp865 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0x81 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0x82 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0x83 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0x84 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0x85 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0x86 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0x87 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0x88 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0x89 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0x8a 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0x8b 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0x8c 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0x8d 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0x8e 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0x8f 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0x90 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0x91 0x00e6 #LATIN SMALL LETTER AE -0x92 0x00c6 #LATIN CAPITAL LETTER AE -0x93 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0x94 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0x95 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0x96 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0x97 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0x98 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS -0x99 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0x9a 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0x9c 0x00a3 #POUND SIGN -0x9d 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0x9e 0x20a7 #PESETA SIGN -0x9f 0x0192 #LATIN SMALL LETTER F WITH HOOK -0xa0 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xa1 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xa2 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xa3 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xa4 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xa5 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xa6 0x00aa #FEMININE ORDINAL INDICATOR -0xa7 0x00ba #MASCULINE ORDINAL INDICATOR -0xa8 0x00bf #INVERTED QUESTION MARK -0xa9 0x2310 #REVERSED NOT SIGN -0xaa 0x00ac #NOT SIGN -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x00bc #VULGAR FRACTION ONE QUARTER -0xad 0x00a1 #INVERTED EXCLAMATION MARK -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00a4 #CURRENCY SIGN -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b1 #GREEK SMALL LETTER ALPHA -0xe1 0x00df #LATIN SMALL LETTER SHARP S -0xe2 0x0393 #GREEK CAPITAL LETTER GAMMA -0xe3 0x03c0 #GREEK SMALL LETTER PI -0xe4 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xe5 0x03c3 #GREEK SMALL LETTER SIGMA -0xe6 0x00b5 #MICRO SIGN -0xe7 0x03c4 #GREEK SMALL LETTER TAU -0xe8 0x03a6 #GREEK CAPITAL LETTER PHI -0xe9 0x0398 #GREEK CAPITAL LETTER THETA -0xea 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xeb 0x03b4 #GREEK SMALL LETTER DELTA -0xec 0x221e #INFINITY -0xed 0x03c6 #GREEK SMALL LETTER PHI -0xee 0x03b5 #GREEK SMALL LETTER EPSILON -0xef 0x2229 #INTERSECTION -0xf0 0x2261 #IDENTICAL TO -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x2265 #GREATER-THAN OR EQUAL TO -0xf3 0x2264 #LESS-THAN OR EQUAL TO -0xf4 0x2320 #TOP HALF INTEGRAL -0xf5 0x2321 #BOTTOM HALF INTEGRAL -0xf6 0x00f7 #DIVISION SIGN -0xf7 0x2248 #ALMOST EQUAL TO -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x207f #SUPERSCRIPT LATIN SMALL LETTER N -0xfd 0x00b2 #SUPERSCRIPT TWO -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_866.h b/src/intl/charsets/cs_866.h index be52e9dacc7..25a6aca7a1a 100644 --- a/src/intl/charsets/cs_866.h +++ b/src/intl/charsets/cs_866.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp866 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp866 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp866 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0410 #CYRILLIC CAPITAL LETTER A -0x81 0x0411 #CYRILLIC CAPITAL LETTER BE -0x82 0x0412 #CYRILLIC CAPITAL LETTER VE -0x83 0x0413 #CYRILLIC CAPITAL LETTER GHE -0x84 0x0414 #CYRILLIC CAPITAL LETTER DE -0x85 0x0415 #CYRILLIC CAPITAL LETTER IE -0x86 0x0416 #CYRILLIC CAPITAL LETTER ZHE -0x87 0x0417 #CYRILLIC CAPITAL LETTER ZE -0x88 0x0418 #CYRILLIC CAPITAL LETTER I -0x89 0x0419 #CYRILLIC CAPITAL LETTER SHORT I -0x8a 0x041a #CYRILLIC CAPITAL LETTER KA -0x8b 0x041b #CYRILLIC CAPITAL LETTER EL -0x8c 0x041c #CYRILLIC CAPITAL LETTER EM -0x8d 0x041d #CYRILLIC CAPITAL LETTER EN -0x8e 0x041e #CYRILLIC CAPITAL LETTER O -0x8f 0x041f #CYRILLIC CAPITAL LETTER PE -0x90 0x0420 #CYRILLIC CAPITAL LETTER ER -0x91 0x0421 #CYRILLIC CAPITAL LETTER ES -0x92 0x0422 #CYRILLIC CAPITAL LETTER TE -0x93 0x0423 #CYRILLIC CAPITAL LETTER U -0x94 0x0424 #CYRILLIC CAPITAL LETTER EF -0x95 0x0425 #CYRILLIC CAPITAL LETTER HA -0x96 0x0426 #CYRILLIC CAPITAL LETTER TSE -0x97 0x0427 #CYRILLIC CAPITAL LETTER CHE -0x98 0x0428 #CYRILLIC CAPITAL LETTER SHA -0x99 0x0429 #CYRILLIC CAPITAL LETTER SHCHA -0x9a 0x042a #CYRILLIC CAPITAL LETTER HARD SIGN -0x9b 0x042b #CYRILLIC CAPITAL LETTER YERU -0x9c 0x042c #CYRILLIC CAPITAL LETTER SOFT SIGN -0x9d 0x042d #CYRILLIC CAPITAL LETTER E -0x9e 0x042e #CYRILLIC CAPITAL LETTER YU -0x9f 0x042f #CYRILLIC CAPITAL LETTER YA -0xa0 0x0430 #CYRILLIC SMALL LETTER A -0xa1 0x0431 #CYRILLIC SMALL LETTER BE -0xa2 0x0432 #CYRILLIC SMALL LETTER VE -0xa3 0x0433 #CYRILLIC SMALL LETTER GHE -0xa4 0x0434 #CYRILLIC SMALL LETTER DE -0xa5 0x0435 #CYRILLIC SMALL LETTER IE -0xa6 0x0436 #CYRILLIC SMALL LETTER ZHE -0xa7 0x0437 #CYRILLIC SMALL LETTER ZE -0xa8 0x0438 #CYRILLIC SMALL LETTER I -0xa9 0x0439 #CYRILLIC SMALL LETTER SHORT I -0xaa 0x043a #CYRILLIC SMALL LETTER KA -0xab 0x043b #CYRILLIC SMALL LETTER EL -0xac 0x043c #CYRILLIC SMALL LETTER EM -0xad 0x043d #CYRILLIC SMALL LETTER EN -0xae 0x043e #CYRILLIC SMALL LETTER O -0xaf 0x043f #CYRILLIC SMALL LETTER PE -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x2561 #BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -0xb6 0x2562 #BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -0xb7 0x2556 #BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -0xb8 0x2555 #BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x255c #BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -0xbe 0x255b #BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x255e #BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -0xc7 0x255f #BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x2567 #BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -0xd0 0x2568 #BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -0xd1 0x2564 #BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -0xd2 0x2565 #BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -0xd3 0x2559 #BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -0xd4 0x2558 #BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -0xd5 0x2552 #BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -0xd6 0x2553 #BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -0xd7 0x256b #BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -0xd8 0x256a #BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x258c #LEFT HALF BLOCK -0xde 0x2590 #RIGHT HALF BLOCK -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x0440 #CYRILLIC SMALL LETTER ER -0xe1 0x0441 #CYRILLIC SMALL LETTER ES -0xe2 0x0442 #CYRILLIC SMALL LETTER TE -0xe3 0x0443 #CYRILLIC SMALL LETTER U -0xe4 0x0444 #CYRILLIC SMALL LETTER EF -0xe5 0x0445 #CYRILLIC SMALL LETTER HA -0xe6 0x0446 #CYRILLIC SMALL LETTER TSE -0xe7 0x0447 #CYRILLIC SMALL LETTER CHE -0xe8 0x0448 #CYRILLIC SMALL LETTER SHA -0xe9 0x0449 #CYRILLIC SMALL LETTER SHCHA -0xea 0x044a #CYRILLIC SMALL LETTER HARD SIGN -0xeb 0x044b #CYRILLIC SMALL LETTER YERU -0xec 0x044c #CYRILLIC SMALL LETTER SOFT SIGN -0xed 0x044d #CYRILLIC SMALL LETTER E -0xee 0x044e #CYRILLIC SMALL LETTER YU -0xef 0x044f #CYRILLIC SMALL LETTER YA -0xf0 0x0401 #CYRILLIC CAPITAL LETTER IO -0xf1 0x0451 #CYRILLIC SMALL LETTER IO -0xf2 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE -0xf3 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE -0xf4 0x0407 #CYRILLIC CAPITAL LETTER YI -0xf5 0x0457 #CYRILLIC SMALL LETTER YI -0xf6 0x040e #CYRILLIC CAPITAL LETTER SHORT U -0xf7 0x045e #CYRILLIC SMALL LETTER SHORT U -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x2219 #BULLET OPERATOR -0xfa 0x00b7 #MIDDLE DOT -0xfb 0x221a #SQUARE ROOT -0xfc 0x2116 #NUMERO SIGN -0xfd 0x00a4 #CURRENCY SIGN -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_869.h b/src/intl/charsets/cs_869.h index d658f4641e9..f183d32e8f2 100644 --- a/src/intl/charsets/cs_869.h +++ b/src/intl/charsets/cs_869.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp869 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp869 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp869 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 #UNDEFINED -0x81 #UNDEFINED -0x82 #UNDEFINED -0x83 #UNDEFINED -0x84 #UNDEFINED -0x85 #UNDEFINED -0x86 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS -0x87 #UNDEFINED -0x88 0x00b7 #MIDDLE DOT -0x89 0x00ac #NOT SIGN -0x8a 0x00a6 #BROKEN BAR -0x8b 0x2018 #LEFT SINGLE QUOTATION MARK -0x8c 0x2019 #RIGHT SINGLE QUOTATION MARK -0x8d 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS -0x8e 0x2015 #HORIZONTAL BAR -0x8f 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS -0x90 0x038a #GREEK CAPITAL LETTER IOTA WITH TONOS -0x91 0x03aa #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -0x92 0x038c #GREEK CAPITAL LETTER OMICRON WITH TONOS -0x93 #UNDEFINED -0x94 #UNDEFINED -0x95 0x038e #GREEK CAPITAL LETTER UPSILON WITH TONOS -0x96 0x03ab #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -0x97 0x00a9 #COPYRIGHT SIGN -0x98 0x038f #GREEK CAPITAL LETTER OMEGA WITH TONOS -0x99 0x00b2 #SUPERSCRIPT TWO -0x9a 0x00b3 #SUPERSCRIPT THREE -0x9b 0x03ac #GREEK SMALL LETTER ALPHA WITH TONOS -0x9c 0x00a3 #POUND SIGN -0x9d 0x03ad #GREEK SMALL LETTER EPSILON WITH TONOS -0x9e 0x03ae #GREEK SMALL LETTER ETA WITH TONOS -0x9f 0x03af #GREEK SMALL LETTER IOTA WITH TONOS -0xa0 0x03ca #GREEK SMALL LETTER IOTA WITH DIALYTIKA -0xa1 0x0390 #GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -0xa2 0x03cc #GREEK SMALL LETTER OMICRON WITH TONOS -0xa3 0x03cd #GREEK SMALL LETTER UPSILON WITH TONOS -0xa4 0x0391 #GREEK CAPITAL LETTER ALPHA -0xa5 0x0392 #GREEK CAPITAL LETTER BETA -0xa6 0x0393 #GREEK CAPITAL LETTER GAMMA -0xa7 0x0394 #GREEK CAPITAL LETTER DELTA -0xa8 0x0395 #GREEK CAPITAL LETTER EPSILON -0xa9 0x0396 #GREEK CAPITAL LETTER ZETA -0xaa 0x0397 #GREEK CAPITAL LETTER ETA -0xab 0x00bd #VULGAR FRACTION ONE HALF -0xac 0x0398 #GREEK CAPITAL LETTER THETA -0xad 0x0399 #GREEK CAPITAL LETTER IOTA -0xae 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xaf 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xb0 0x2591 #LIGHT SHADE -0xb1 0x2592 #MEDIUM SHADE -0xb2 0x2593 #DARK SHADE -0xb3 0x2502 #BOX DRAWINGS LIGHT VERTICAL -0xb4 0x2524 #BOX DRAWINGS LIGHT VERTICAL AND LEFT -0xb5 0x039a #GREEK CAPITAL LETTER KAPPA -0xb6 0x039b #GREEK CAPITAL LETTER LAMDA -0xb7 0x039c #GREEK CAPITAL LETTER MU -0xb8 0x039d #GREEK CAPITAL LETTER NU -0xb9 0x2563 #BOX DRAWINGS DOUBLE VERTICAL AND LEFT -0xba 0x2551 #BOX DRAWINGS DOUBLE VERTICAL -0xbb 0x2557 #BOX DRAWINGS DOUBLE DOWN AND LEFT -0xbc 0x255d #BOX DRAWINGS DOUBLE UP AND LEFT -0xbd 0x039e #GREEK CAPITAL LETTER XI -0xbe 0x039f #GREEK CAPITAL LETTER OMICRON -0xbf 0x2510 #BOX DRAWINGS LIGHT DOWN AND LEFT -0xc0 0x2514 #BOX DRAWINGS LIGHT UP AND RIGHT -0xc1 0x2534 #BOX DRAWINGS LIGHT UP AND HORIZONTAL -0xc2 0x252c #BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -0xc3 0x251c #BOX DRAWINGS LIGHT VERTICAL AND RIGHT -0xc4 0x2500 #BOX DRAWINGS LIGHT HORIZONTAL -0xc5 0x253c #BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -0xc6 0x03a0 #GREEK CAPITAL LETTER PI -0xc7 0x03a1 #GREEK CAPITAL LETTER RHO -0xc8 0x255a #BOX DRAWINGS DOUBLE UP AND RIGHT -0xc9 0x2554 #BOX DRAWINGS DOUBLE DOWN AND RIGHT -0xca 0x2569 #BOX DRAWINGS DOUBLE UP AND HORIZONTAL -0xcb 0x2566 #BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -0xcc 0x2560 #BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -0xcd 0x2550 #BOX DRAWINGS DOUBLE HORIZONTAL -0xce 0x256c #BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -0xcf 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xd0 0x03a4 #GREEK CAPITAL LETTER TAU -0xd1 0x03a5 #GREEK CAPITAL LETTER UPSILON -0xd2 0x03a6 #GREEK CAPITAL LETTER PHI -0xd3 0x03a7 #GREEK CAPITAL LETTER CHI -0xd4 0x03a8 #GREEK CAPITAL LETTER PSI -0xd5 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xd6 0x03b1 #GREEK SMALL LETTER ALPHA -0xd7 0x03b2 #GREEK SMALL LETTER BETA -0xd8 0x03b3 #GREEK SMALL LETTER GAMMA -0xd9 0x2518 #BOX DRAWINGS LIGHT UP AND LEFT -0xda 0x250c #BOX DRAWINGS LIGHT DOWN AND RIGHT -0xdb 0x2588 #FULL BLOCK -0xdc 0x2584 #LOWER HALF BLOCK -0xdd 0x03b4 #GREEK SMALL LETTER DELTA -0xde 0x03b5 #GREEK SMALL LETTER EPSILON -0xdf 0x2580 #UPPER HALF BLOCK -0xe0 0x03b6 #GREEK SMALL LETTER ZETA -0xe1 0x03b7 #GREEK SMALL LETTER ETA -0xe2 0x03b8 #GREEK SMALL LETTER THETA -0xe3 0x03b9 #GREEK SMALL LETTER IOTA -0xe4 0x03ba #GREEK SMALL LETTER KAPPA -0xe5 0x03bb #GREEK SMALL LETTER LAMDA -0xe6 0x03bc #GREEK SMALL LETTER MU -0xe7 0x03bd #GREEK SMALL LETTER NU -0xe8 0x03be #GREEK SMALL LETTER XI -0xe9 0x03bf #GREEK SMALL LETTER OMICRON -0xea 0x03c0 #GREEK SMALL LETTER PI -0xeb 0x03c1 #GREEK SMALL LETTER RHO -0xec 0x03c3 #GREEK SMALL LETTER SIGMA -0xed 0x03c2 #GREEK SMALL LETTER FINAL SIGMA -0xee 0x03c4 #GREEK SMALL LETTER TAU -0xef 0x0384 #GREEK TONOS -0xf0 0x00ad #SOFT HYPHEN -0xf1 0x00b1 #PLUS-MINUS SIGN -0xf2 0x03c5 #GREEK SMALL LETTER UPSILON -0xf3 0x03c6 #GREEK SMALL LETTER PHI -0xf4 0x03c7 #GREEK SMALL LETTER CHI -0xf5 0x00a7 #SECTION SIGN -0xf6 0x03c8 #GREEK SMALL LETTER PSI -0xf7 0x0385 #GREEK DIALYTIKA TONOS -0xf8 0x00b0 #DEGREE SIGN -0xf9 0x00a8 #DIAERESIS -0xfa 0x03c9 #GREEK SMALL LETTER OMEGA -0xfb 0x03cb #GREEK SMALL LETTER UPSILON WITH DIALYTIKA -0xfc 0x03b0 #GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -0xfd 0x03ce #GREEK SMALL LETTER OMEGA WITH TONOS -0xfe 0x25a0 #BLACK SQUARE -0xff 0x00a0 #NO-BREAK SPACE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_big5.h b/src/intl/charsets/cs_big5.h index f0fdb84bc39..5f19473a58d 100644 --- a/src/intl/charsets/cs_big5.h +++ b/src/intl/charsets/cs_big5.h @@ -4,76 +4,11 @@ Unicode mapping table generated from file asia/OTHER/BIG5.TXT -# # Name: BIG5 to Unicode table (complete) # Unicode version: 1.1 # Table version: 0.0d3 # Table format: Format A # Date: 11 February 1994 -# Authors: Glenn Adams -# John H. Jenkins -# -# -# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). -# No claims are made as to fitness for any particular purpose. No -# warranties of any kind are expressed or implied. The recipient -# agrees to determine applicability of information provided. If this -# file has been provided on magnetic media by Unicode, Inc., the sole -# remedy for any claim will be exchange of defective media within 90 -# days of receipt. -# -# Recipient is granted the right to make copies in any form for -# internal distribution and to freely use the information supplied -# in the creation of products supporting Unicode. Unicode, Inc. -# specifically excludes the right to re-distribute this file directly -# to third parties or other organizations whether for profit or not. -# -# General notes: -# -# This table contains the data Metis and Taligent currently have on how -# BIG5 characters map into Unicode. -# -# WARNING! It is currently impossible to provide round-trip compatibility -# between BIG5 and Unicode. -# -# A number of characters are not currently mapped because -# of conflicts with other mappings. They are as follows: -# -# BIG5 Description Comments -# -# 0xA15A SPACING UNDERSCORE duplicates A1C4 -# 0xA1C3 SPACING HEAVY OVERSCORE not in Unicode -# 0xA1C5 SPACING HEAVY UNDERSCORE not in Unicode -# 0xA1FE LT DIAG UP RIGHT TO LOW LEFT duplicates A2AC -# 0xA240 LT DIAG UP LEFT TO LOW RIGHT duplicates A2AD -# 0xA2CC HANGZHOU NUMERAL TEN conflicts with A451 mapping -# 0xA2CE HANGZHOU NUMERAL THIRTY conflicts with A4CA mapping -# -# We currently map all of these characters to U+FFFD REPLACEMENT CHARACTER. -# It is also possible to map these characters to their duplicates, or to -# the user zone. -# -# Notes: -# -# 1. In addition to the above, there is some uncertainty about the -# mappings in the range C6A1 - C8FE, and F9DD - F9FE. The ETEN -# version of BIG5 organizes the former range differently, and adds -# additional characters in the latter range. The correct mappings -# these ranges need to be determined. -# -# 2. There is an uncertainty in the mapping of the Big Five character -# 0xA3BC. This character occurs within the Big Five block of tone marks -# for bopomofo and is intended to be the tone mark for the first tone in -# Mandarin Chinese. We have selected the mapping U+02C9 MODIFIER LETTER -# MACRON (Mandarin Chinese first tone) to reflect this semantic. -# However, because bopomofo uses the absense of a tone mark to indicate -# the first Mandarin tone, most implementations of Big Five represent -# this character with a blank space, and so a mapping such as U+2003 EM SPACE -# might be preferred. -# -# -# -# Any comments or problems, contact * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_cyrl.h b/src/intl/charsets/cs_cyrl.h index a46dd3a0840..74153fa7731 100644 --- a/src/intl/charsets/cs_cyrl.h +++ b/src/intl/charsets/cs_cyrl.h @@ -3,280 +3,12 @@ Unicode mapping table generated from file maps/WINDOWS/CP1251.TXT -# # Name: cp1251 to Unicode table # Unicode version: 2.0 # Table version: 2.00 # Table format: Format A # Date: 04/15/98 -# -# Contact: cpxlate@microsoft.com -# -# General notes: none -# -# Format: Three tab-separated columns -# Column #1 is the cp1251 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in cp1251 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #HORIZONTAL TABULATION -0x0A 0x000A #LINE FEED -0x0B 0x000B #VERTICAL TABULATION -0x0C 0x000C #FORM FEED -0x0D 0x000D #CARRIAGE RETURN -0x0E 0x000E #SHIFT OUT -0x0F 0x000F #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1A 0x001A #SUBSTITUTE -0x1B 0x001B #ESCAPE -0x1C 0x001C #FILE SEPARATOR -0x1D 0x001D #GROUP SEPARATOR -0x1E 0x001E #RECORD SEPARATOR -0x1F 0x001F #UNIT SEPARATOR -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2A 0x002A #ASTERISK -0x2B 0x002B #PLUS SIGN -0x2C 0x002C #COMMA -0x2D 0x002D #HYPHEN-MINUS -0x2E 0x002E #FULL STOP -0x2F 0x002F #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3A 0x003A #COLON -0x3B 0x003B #SEMICOLON -0x3C 0x003C #LESS-THAN SIGN -0x3D 0x003D #EQUALS SIGN -0x3E 0x003E #GREATER-THAN SIGN -0x3F 0x003F #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4A 0x004A #LATIN CAPITAL LETTER J -0x4B 0x004B #LATIN CAPITAL LETTER K -0x4C 0x004C #LATIN CAPITAL LETTER L -0x4D 0x004D #LATIN CAPITAL LETTER M -0x4E 0x004E #LATIN CAPITAL LETTER N -0x4F 0x004F #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5A 0x005A #LATIN CAPITAL LETTER Z -0x5B 0x005B #LEFT SQUARE BRACKET -0x5C 0x005C #REVERSE SOLIDUS -0x5D 0x005D #RIGHT SQUARE BRACKET -0x5E 0x005E #CIRCUMFLEX ACCENT -0x5F 0x005F #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6A 0x006A #LATIN SMALL LETTER J -0x6B 0x006B #LATIN SMALL LETTER K -0x6C 0x006C #LATIN SMALL LETTER L -0x6D 0x006D #LATIN SMALL LETTER M -0x6E 0x006E #LATIN SMALL LETTER N -0x6F 0x006F #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7A 0x007A #LATIN SMALL LETTER Z -0x7B 0x007B #LEFT CURLY BRACKET -0x7C 0x007C #VERTICAL LINE -0x7D 0x007D #RIGHT CURLY BRACKET -0x7E 0x007E #TILDE -0x7F 0x007F #DELETE -0x80 0x0402 #CYRILLIC CAPITAL LETTER DJE -0x81 0x0403 #CYRILLIC CAPITAL LETTER GJE -0x82 0x201A #SINGLE LOW-9 QUOTATION MARK -0x83 0x0453 #CYRILLIC SMALL LETTER GJE -0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x20AC #EURO SIGN -0x89 0x2030 #PER MILLE SIGN -0x8A 0x0409 #CYRILLIC CAPITAL LETTER LJE -0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8C 0x040A #CYRILLIC CAPITAL LETTER NJE -0x8D 0x040C #CYRILLIC CAPITAL LETTER KJE -0x8E 0x040B #CYRILLIC CAPITAL LETTER TSHE -0x8F 0x040F #CYRILLIC CAPITAL LETTER DZHE -0x90 0x0452 #CYRILLIC SMALL LETTER DJE -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201C #LEFT DOUBLE QUOTATION MARK -0x94 0x201D #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 #UNDEFINED -0x99 0x2122 #TRADE MARK SIGN -0x9A 0x0459 #CYRILLIC SMALL LETTER LJE -0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9C 0x045A #CYRILLIC SMALL LETTER NJE -0x9D 0x045C #CYRILLIC SMALL LETTER KJE -0x9E 0x045B #CYRILLIC SMALL LETTER TSHE -0x9F 0x045F #CYRILLIC SMALL LETTER DZHE -0xA0 0x00A0 #NO-BREAK SPACE -0xA1 0x040E #CYRILLIC CAPITAL LETTER SHORT U -0xA2 0x045E #CYRILLIC SMALL LETTER SHORT U -0xA3 0x0408 #CYRILLIC CAPITAL LETTER JE -0xA4 0x00A4 #CURRENCY SIGN -0xA5 0x0490 #CYRILLIC CAPITAL LETTER GHE WITH UPTURN -0xA6 0x00A6 #BROKEN BAR -0xA7 0x00A7 #SECTION SIGN -0xA8 0x0401 #CYRILLIC CAPITAL LETTER IO -0xA9 0x00A9 #COPYRIGHT SIGN -0xAA 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE -0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xAC 0x00AC #NOT SIGN -0xAD 0x00AD #SOFT HYPHEN -0xAE 0x00AE #REGISTERED SIGN -0xAF 0x0407 #CYRILLIC CAPITAL LETTER YI -0xB0 0x00B0 #DEGREE SIGN -0xB1 0x00B1 #PLUS-MINUS SIGN -0xB2 0x0406 #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -0xB3 0x0456 #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -0xB4 0x0491 #CYRILLIC SMALL LETTER GHE WITH UPTURN -0xB5 0x00B5 #MICRO SIGN -0xB6 0x00B6 #PILCROW SIGN -0xB7 0x00B7 #MIDDLE DOT -0xB8 0x0451 #CYRILLIC SMALL LETTER IO -0xB9 0x2116 #NUMERO SIGN -0xBA 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE -0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xBC 0x0458 #CYRILLIC SMALL LETTER JE -0xBD 0x0405 #CYRILLIC CAPITAL LETTER DZE -0xBE 0x0455 #CYRILLIC SMALL LETTER DZE -0xBF 0x0457 #CYRILLIC SMALL LETTER YI -0xC0 0x0410 #CYRILLIC CAPITAL LETTER A -0xC1 0x0411 #CYRILLIC CAPITAL LETTER BE -0xC2 0x0412 #CYRILLIC CAPITAL LETTER VE -0xC3 0x0413 #CYRILLIC CAPITAL LETTER GHE -0xC4 0x0414 #CYRILLIC CAPITAL LETTER DE -0xC5 0x0415 #CYRILLIC CAPITAL LETTER IE -0xC6 0x0416 #CYRILLIC CAPITAL LETTER ZHE -0xC7 0x0417 #CYRILLIC CAPITAL LETTER ZE -0xC8 0x0418 #CYRILLIC CAPITAL LETTER I -0xC9 0x0419 #CYRILLIC CAPITAL LETTER SHORT I -0xCA 0x041A #CYRILLIC CAPITAL LETTER KA -0xCB 0x041B #CYRILLIC CAPITAL LETTER EL -0xCC 0x041C #CYRILLIC CAPITAL LETTER EM -0xCD 0x041D #CYRILLIC CAPITAL LETTER EN -0xCE 0x041E #CYRILLIC CAPITAL LETTER O -0xCF 0x041F #CYRILLIC CAPITAL LETTER PE -0xD0 0x0420 #CYRILLIC CAPITAL LETTER ER -0xD1 0x0421 #CYRILLIC CAPITAL LETTER ES -0xD2 0x0422 #CYRILLIC CAPITAL LETTER TE -0xD3 0x0423 #CYRILLIC CAPITAL LETTER U -0xD4 0x0424 #CYRILLIC CAPITAL LETTER EF -0xD5 0x0425 #CYRILLIC CAPITAL LETTER HA -0xD6 0x0426 #CYRILLIC CAPITAL LETTER TSE -0xD7 0x0427 #CYRILLIC CAPITAL LETTER CHE -0xD8 0x0428 #CYRILLIC CAPITAL LETTER SHA -0xD9 0x0429 #CYRILLIC CAPITAL LETTER SHCHA -0xDA 0x042A #CYRILLIC CAPITAL LETTER HARD SIGN -0xDB 0x042B #CYRILLIC CAPITAL LETTER YERU -0xDC 0x042C #CYRILLIC CAPITAL LETTER SOFT SIGN -0xDD 0x042D #CYRILLIC CAPITAL LETTER E -0xDE 0x042E #CYRILLIC CAPITAL LETTER YU -0xDF 0x042F #CYRILLIC CAPITAL LETTER YA -0xE0 0x0430 #CYRILLIC SMALL LETTER A -0xE1 0x0431 #CYRILLIC SMALL LETTER BE -0xE2 0x0432 #CYRILLIC SMALL LETTER VE -0xE3 0x0433 #CYRILLIC SMALL LETTER GHE -0xE4 0x0434 #CYRILLIC SMALL LETTER DE -0xE5 0x0435 #CYRILLIC SMALL LETTER IE -0xE6 0x0436 #CYRILLIC SMALL LETTER ZHE -0xE7 0x0437 #CYRILLIC SMALL LETTER ZE -0xE8 0x0438 #CYRILLIC SMALL LETTER I -0xE9 0x0439 #CYRILLIC SMALL LETTER SHORT I -0xEA 0x043A #CYRILLIC SMALL LETTER KA -0xEB 0x043B #CYRILLIC SMALL LETTER EL -0xEC 0x043C #CYRILLIC SMALL LETTER EM -0xED 0x043D #CYRILLIC SMALL LETTER EN -0xEE 0x043E #CYRILLIC SMALL LETTER O -0xEF 0x043F #CYRILLIC SMALL LETTER PE -0xF0 0x0440 #CYRILLIC SMALL LETTER ER -0xF1 0x0441 #CYRILLIC SMALL LETTER ES -0xF2 0x0442 #CYRILLIC SMALL LETTER TE -0xF3 0x0443 #CYRILLIC SMALL LETTER U -0xF4 0x0444 #CYRILLIC SMALL LETTER EF -0xF5 0x0445 #CYRILLIC SMALL LETTER HA -0xF6 0x0446 #CYRILLIC SMALL LETTER TSE -0xF7 0x0447 #CYRILLIC SMALL LETTER CHE -0xF8 0x0448 #CYRILLIC SMALL LETTER SHA -0xF9 0x0449 #CYRILLIC SMALL LETTER SHCHA -0xFA 0x044A #CYRILLIC SMALL LETTER HARD SIGN -0xFB 0x044B #CYRILLIC SMALL LETTER YERU -0xFC 0x044C #CYRILLIC SMALL LETTER SOFT SIGN -0xFD 0x044D #CYRILLIC SMALL LETTER E -0xFE 0x044E #CYRILLIC SMALL LETTER YU -0xFF 0x044F #CYRILLIC SMALL LETTER YA + * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy diff --git a/src/intl/charsets/cs_gb2312.h b/src/intl/charsets/cs_gb2312.h index 88a635ffd9c..ffaaead804b 100644 --- a/src/intl/charsets/cs_gb2312.h +++ b/src/intl/charsets/cs_gb2312.h @@ -4,56 +4,12 @@ Unicode mapping table generated from file gb2312-2.txt -# # Name: GB2312-80 to Unicode table (complete, hex format) # Unicode version: 3.0 # Table version: 1.0 # Table format: Format A # Date: 1999 October 8 -# Author: Ken Whistler -# Original authors: Glenn Adams, John H. Jenkin -# -# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. -# -# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). -# No claims are made as to fitness for any particular purpose. No -# warranties of any kind are expressed or implied. The recipient -# agrees to determine applicability of information provided. If this -# file has been provided on optical media by Unicode, Inc., the sole -# remedy for any claim will be exchange of defective media within 90 -# days of receipt. -# -# Unicode, Inc. hereby grants the right to freely use the information -# supplied in this file in the creation of products supporting the -# Unicode Standard, and to make copies of this file in any form for -# internal or external distribution as long as this notice remains -# attached. -# -# General notes: -# -# This table contains the datathe Unicode Consortium currently has on how -# GB2312-80 characters map into Unicode. -# -# The following algorithms can be used to change the hex form -# of GB2312 to other standard forms: -# -# To change hex to EUC form, add 0x8080 -# To change hex to kuten form, first subtract 0x2020. Then -# the high and low bytes correspond to the ku and ten of -# the kuten form. For example, 0x2121 -> 0x0101 -> 0101; -# 0x777E -> 0x575E -> 8794 -# -# Version history -# 1.0 version updates 0.0d2 version by correcting mapping for 0x212C -# from U+2225 to U+2016. -# -# Updated versions of this file may be found in: -# -# -# Any comments or problems, contact -# Please note that is an archival address; -# notices will be checked, but do not expect an immediate response. -# + * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy diff --git a/src/intl/charsets/cs_iso8859_1.h b/src/intl/charsets/cs_iso8859_1.h index bfbf60e7506..ea48d10add8 100644 --- a/src/intl/charsets/cs_iso8859_1.h +++ b/src/intl/charsets/cs_iso8859_1.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_1 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_1 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_1 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00a1 #INVERTED EXCLAMATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00aa #FEMININE ORDINAL INDICATOR -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00ba #MASCULINE ORDINAL INDICATOR -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00bf #INVERTED QUESTION MARK -0xc0 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x00c6 #LATIN CAPITAL LETTER AE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd0 0x00d0 #LATIN CAPITAL LETTER ETH -0xd1 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xd2 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xd9 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xde 0x00de #LATIN CAPITAL LETTER THORN -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x00e6 #LATIN SMALL LETTER AE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 0x00f0 #LATIN SMALL LETTER ETH -0xf1 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xf2 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xfe 0x00fe #LATIN SMALL LETTER THORN -0xff 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_13.h b/src/intl/charsets/cs_iso8859_13.h index 4b66d980a59..f203b3a41cd 100644 --- a/src/intl/charsets/cs_iso8859_13.h +++ b/src/intl/charsets/cs_iso8859_13.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_13 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_13 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_13 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x201d #RIGHT DOUBLE QUOTATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x201e #DOUBLE LOW-9 QUOTATION MARK -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00c6 #LATIN CAPITAL LETTER AE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x201c #LEFT DOUBLE QUOTATION MARK -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x0157 #LATIN SMALL LETTER R WITH CEDILLA -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00e6 #LATIN SMALL LETTER AE -0xc0 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xc1 0x012e #LATIN CAPITAL LETTER I WITH OGONEK -0xc2 0x0100 #LATIN CAPITAL LETTER A WITH MACRON -0xc3 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xc7 0x0112 #LATIN CAPITAL LETTER E WITH MACRON -0xc8 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0xcb 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE -0xcc 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA -0xcd 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA -0xce 0x012a #LATIN CAPITAL LETTER I WITH MACRON -0xcf 0x013b #LATIN CAPITAL LETTER L WITH CEDILLA -0xd0 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xd1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xd2 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x014c #LATIN CAPITAL LETTER O WITH MACRON -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK -0xd9 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0xda 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0xdb 0x016a #LATIN CAPITAL LETTER U WITH MACRON -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xde 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xe1 0x012f #LATIN SMALL LETTER I WITH OGONEK -0xe2 0x0101 #LATIN SMALL LETTER A WITH MACRON -0xe3 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xe7 0x0113 #LATIN SMALL LETTER E WITH MACRON -0xe8 0x010d #LATIN SMALL LETTER C WITH CARON -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xeb 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE -0xec 0x0123 #LATIN SMALL LETTER G WITH CEDILLA -0xed 0x0137 #LATIN SMALL LETTER K WITH CEDILLA -0xee 0x012b #LATIN SMALL LETTER I WITH MACRON -0xef 0x013c #LATIN SMALL LETTER L WITH CEDILLA -0xf0 0x0161 #LATIN SMALL LETTER S WITH CARON -0xf1 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xf2 0x0146 #LATIN SMALL LETTER N WITH CEDILLA -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x014d #LATIN SMALL LETTER O WITH MACRON -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x0173 #LATIN SMALL LETTER U WITH OGONEK -0xf9 0x0142 #LATIN SMALL LETTER L WITH STROKE -0xfa 0x015b #LATIN SMALL LETTER S WITH ACUTE -0xfb 0x016b #LATIN SMALL LETTER U WITH MACRON -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xfe 0x017e #LATIN SMALL LETTER Z WITH CARON -0xff 0x2019 #RIGHT SINGLE QUOTATION MARK - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_2.h b/src/intl/charsets/cs_iso8859_2.h index 583d26b6a3c..1ce508d9263 100644 --- a/src/intl/charsets/cs_iso8859_2.h +++ b/src/intl/charsets/cs_iso8859_2.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_2 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_2 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_2 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xa2 0x02d8 #BREVE -0xa3 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x013d #LATIN CAPITAL LETTER L WITH CARON -0xa6 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xaa 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xab 0x0164 #LATIN CAPITAL LETTER T WITH CARON -0xac 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0xad 0x00ad #SOFT HYPHEN -0xae 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xaf 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xb2 0x02db #OGONEK -0xb3 0x0142 #LATIN SMALL LETTER L WITH STROKE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x013e #LATIN SMALL LETTER L WITH CARON -0xb6 0x015b #LATIN SMALL LETTER S WITH ACUTE -0xb7 0x02c7 #CARON -0xb8 0x00b8 #CEDILLA -0xb9 0x0161 #LATIN SMALL LETTER S WITH CARON -0xba 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xbb 0x0165 #LATIN SMALL LETTER T WITH CARON -0xbc 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xbd 0x02dd #DOUBLE ACUTE ACCENT -0xbe 0x017e #LATIN SMALL LETTER Z WITH CARON -0xbf 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xc0 0x0154 #LATIN CAPITAL LETTER R WITH ACUTE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x0139 #LATIN CAPITAL LETTER L WITH ACUTE -0xc6 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x011a #LATIN CAPITAL LETTER E WITH CARON -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x010e #LATIN CAPITAL LETTER D WITH CARON -0xd0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE -0xd1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xd2 0x0147 #LATIN CAPITAL LETTER N WITH CARON -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x0150 #LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x0158 #LATIN CAPITAL LETTER R WITH CARON -0xd9 0x016e #LATIN CAPITAL LETTER U WITH RING ABOVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x0170 #LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xde 0x0162 #LATIN CAPITAL LETTER T WITH CEDILLA -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x0155 #LATIN SMALL LETTER R WITH ACUTE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x0103 #LATIN SMALL LETTER A WITH BREVE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x013a #LATIN SMALL LETTER L WITH ACUTE -0xe6 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x010d #LATIN SMALL LETTER C WITH CARON -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x011b #LATIN SMALL LETTER E WITH CARON -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x010f #LATIN SMALL LETTER D WITH CARON -0xf0 0x0111 #LATIN SMALL LETTER D WITH STROKE -0xf1 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xf2 0x0148 #LATIN SMALL LETTER N WITH CARON -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x0151 #LATIN SMALL LETTER O WITH DOUBLE ACUTE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x0159 #LATIN SMALL LETTER R WITH CARON -0xf9 0x016f #LATIN SMALL LETTER U WITH RING ABOVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x0171 #LATIN SMALL LETTER U WITH DOUBLE ACUTE -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xfe 0x0163 #LATIN SMALL LETTER T WITH CEDILLA -0xff 0x02d9 #DOT ABOVE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_3.h b/src/intl/charsets/cs_iso8859_3.h index 6018e13c05f..536f995d095 100644 --- a/src/intl/charsets/cs_iso8859_3.h +++ b/src/intl/charsets/cs_iso8859_3.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_3 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_3 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_3 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x0126 #LATIN CAPITAL LETTER H WITH STROKE -0xa2 0x02d8 #BREVE -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 #UNDEFINED -0xa6 0x0124 #LATIN CAPITAL LETTER H WITH CIRCUMFLEX -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE -0xaa 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xab 0x011e #LATIN CAPITAL LETTER G WITH BREVE -0xac 0x0134 #LATIN CAPITAL LETTER J WITH CIRCUMFLEX -0xad 0x00ad #SOFT HYPHEN -0xae #UNDEFINED -0xaf 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x0127 #LATIN SMALL LETTER H WITH STROKE -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x0125 #LATIN SMALL LETTER H WITH CIRCUMFLEX -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x0131 #LATIN SMALL LETTER DOTLESS I -0xba 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xbb 0x011f #LATIN SMALL LETTER G WITH BREVE -0xbc 0x0135 #LATIN SMALL LETTER J WITH CIRCUMFLEX -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe #UNDEFINED -0xbf 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xc0 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 #UNDEFINED -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x010a #LATIN CAPITAL LETTER C WITH DOT ABOVE -0xc6 0x0108 #LATIN CAPITAL LETTER C WITH CIRCUMFLEX -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd0 #UNDEFINED -0xd1 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xd2 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x0120 #LATIN CAPITAL LETTER G WITH DOT ABOVE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x011c #LATIN CAPITAL LETTER G WITH CIRCUMFLEX -0xd9 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x016c #LATIN CAPITAL LETTER U WITH BREVE -0xde 0x015c #LATIN CAPITAL LETTER S WITH CIRCUMFLEX -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 #UNDEFINED -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x010b #LATIN SMALL LETTER C WITH DOT ABOVE -0xe6 0x0109 #LATIN SMALL LETTER C WITH CIRCUMFLEX -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 #UNDEFINED -0xf1 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xf2 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x0121 #LATIN SMALL LETTER G WITH DOT ABOVE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x011d #LATIN SMALL LETTER G WITH CIRCUMFLEX -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x016d #LATIN SMALL LETTER U WITH BREVE -0xfe 0x015d #LATIN SMALL LETTER S WITH CIRCUMFLEX -0xff 0x02d9 #DOT ABOVE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_4.h b/src/intl/charsets/cs_iso8859_4.h index 6b8d00f559a..96b5fffa3af 100644 --- a/src/intl/charsets/cs_iso8859_4.h +++ b/src/intl/charsets/cs_iso8859_4.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_4 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_4 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_4 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xa2 0x0138 #LATIN SMALL LETTER KRA -0xa3 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x0128 #LATIN CAPITAL LETTER I WITH TILDE -0xa6 0x013b #LATIN CAPITAL LETTER L WITH CEDILLA -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xaa 0x0112 #LATIN CAPITAL LETTER E WITH MACRON -0xab 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA -0xac 0x0166 #LATIN CAPITAL LETTER T WITH STROKE -0xad 0x00ad #SOFT HYPHEN -0xae 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xb2 0x02db #OGONEK -0xb3 0x0157 #LATIN SMALL LETTER R WITH CEDILLA -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x0129 #LATIN SMALL LETTER I WITH TILDE -0xb6 0x013c #LATIN SMALL LETTER L WITH CEDILLA -0xb7 0x02c7 #CARON -0xb8 0x00b8 #CEDILLA -0xb9 0x0161 #LATIN SMALL LETTER S WITH CARON -0xba 0x0113 #LATIN SMALL LETTER E WITH MACRON -0xbb 0x0123 #LATIN SMALL LETTER G WITH CEDILLA -0xbc 0x0167 #LATIN SMALL LETTER T WITH STROKE -0xbd 0x014a #LATIN CAPITAL LETTER ENG -0xbe 0x017e #LATIN SMALL LETTER Z WITH CARON -0xbf 0x014b #LATIN SMALL LETTER ENG -0xc0 0x0100 #LATIN CAPITAL LETTER A WITH MACRON -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x00c6 #LATIN CAPITAL LETTER AE -0xc7 0x012e #LATIN CAPITAL LETTER I WITH OGONEK -0xc8 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x012a #LATIN CAPITAL LETTER I WITH MACRON -0xd0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE -0xd1 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA -0xd2 0x014c #LATIN CAPITAL LETTER O WITH MACRON -0xd3 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xd9 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x0168 #LATIN CAPITAL LETTER U WITH TILDE -0xde 0x016a #LATIN CAPITAL LETTER U WITH MACRON -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x0101 #LATIN SMALL LETTER A WITH MACRON -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x00e6 #LATIN SMALL LETTER AE -0xe7 0x012f #LATIN SMALL LETTER I WITH OGONEK -0xe8 0x010d #LATIN SMALL LETTER C WITH CARON -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x012b #LATIN SMALL LETTER I WITH MACRON -0xf0 0x0111 #LATIN SMALL LETTER D WITH STROKE -0xf1 0x0146 #LATIN SMALL LETTER N WITH CEDILLA -0xf2 0x014d #LATIN SMALL LETTER O WITH MACRON -0xf3 0x0137 #LATIN SMALL LETTER K WITH CEDILLA -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xf9 0x0173 #LATIN SMALL LETTER U WITH OGONEK -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x0169 #LATIN SMALL LETTER U WITH TILDE -0xfe 0x016b #LATIN SMALL LETTER U WITH MACRON -0xff 0x02d9 #DOT ABOVE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_5.h b/src/intl/charsets/cs_iso8859_5.h index 5d5b9dbc708..4e63c2da674 100644 --- a/src/intl/charsets/cs_iso8859_5.h +++ b/src/intl/charsets/cs_iso8859_5.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_5 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_5 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_5 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x0401 #CYRILLIC CAPITAL LETTER IO -0xa2 0x0402 #CYRILLIC CAPITAL LETTER DJE -0xa3 0x0403 #CYRILLIC CAPITAL LETTER GJE -0xa4 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE -0xa5 0x0405 #CYRILLIC CAPITAL LETTER DZE -0xa6 0x0406 #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -0xa7 0x0407 #CYRILLIC CAPITAL LETTER YI -0xa8 0x0408 #CYRILLIC CAPITAL LETTER JE -0xa9 0x0409 #CYRILLIC CAPITAL LETTER LJE -0xaa 0x040a #CYRILLIC CAPITAL LETTER NJE -0xab 0x040b #CYRILLIC CAPITAL LETTER TSHE -0xac 0x040c #CYRILLIC CAPITAL LETTER KJE -0xad 0x00ad #SOFT HYPHEN -0xae 0x040e #CYRILLIC CAPITAL LETTER SHORT U -0xaf 0x040f #CYRILLIC CAPITAL LETTER DZHE -0xb0 0x0410 #CYRILLIC CAPITAL LETTER A -0xb1 0x0411 #CYRILLIC CAPITAL LETTER BE -0xb2 0x0412 #CYRILLIC CAPITAL LETTER VE -0xb3 0x0413 #CYRILLIC CAPITAL LETTER GHE -0xb4 0x0414 #CYRILLIC CAPITAL LETTER DE -0xb5 0x0415 #CYRILLIC CAPITAL LETTER IE -0xb6 0x0416 #CYRILLIC CAPITAL LETTER ZHE -0xb7 0x0417 #CYRILLIC CAPITAL LETTER ZE -0xb8 0x0418 #CYRILLIC CAPITAL LETTER I -0xb9 0x0419 #CYRILLIC CAPITAL LETTER SHORT I -0xba 0x041a #CYRILLIC CAPITAL LETTER KA -0xbb 0x041b #CYRILLIC CAPITAL LETTER EL -0xbc 0x041c #CYRILLIC CAPITAL LETTER EM -0xbd 0x041d #CYRILLIC CAPITAL LETTER EN -0xbe 0x041e #CYRILLIC CAPITAL LETTER O -0xbf 0x041f #CYRILLIC CAPITAL LETTER PE -0xc0 0x0420 #CYRILLIC CAPITAL LETTER ER -0xc1 0x0421 #CYRILLIC CAPITAL LETTER ES -0xc2 0x0422 #CYRILLIC CAPITAL LETTER TE -0xc3 0x0423 #CYRILLIC CAPITAL LETTER U -0xc4 0x0424 #CYRILLIC CAPITAL LETTER EF -0xc5 0x0425 #CYRILLIC CAPITAL LETTER HA -0xc6 0x0426 #CYRILLIC CAPITAL LETTER TSE -0xc7 0x0427 #CYRILLIC CAPITAL LETTER CHE -0xc8 0x0428 #CYRILLIC CAPITAL LETTER SHA -0xc9 0x0429 #CYRILLIC CAPITAL LETTER SHCHA -0xca 0x042a #CYRILLIC CAPITAL LETTER HARD SIGN -0xcb 0x042b #CYRILLIC CAPITAL LETTER YERU -0xcc 0x042c #CYRILLIC CAPITAL LETTER SOFT SIGN -0xcd 0x042d #CYRILLIC CAPITAL LETTER E -0xce 0x042e #CYRILLIC CAPITAL LETTER YU -0xcf 0x042f #CYRILLIC CAPITAL LETTER YA -0xd0 0x0430 #CYRILLIC SMALL LETTER A -0xd1 0x0431 #CYRILLIC SMALL LETTER BE -0xd2 0x0432 #CYRILLIC SMALL LETTER VE -0xd3 0x0433 #CYRILLIC SMALL LETTER GHE -0xd4 0x0434 #CYRILLIC SMALL LETTER DE -0xd5 0x0435 #CYRILLIC SMALL LETTER IE -0xd6 0x0436 #CYRILLIC SMALL LETTER ZHE -0xd7 0x0437 #CYRILLIC SMALL LETTER ZE -0xd8 0x0438 #CYRILLIC SMALL LETTER I -0xd9 0x0439 #CYRILLIC SMALL LETTER SHORT I -0xda 0x043a #CYRILLIC SMALL LETTER KA -0xdb 0x043b #CYRILLIC SMALL LETTER EL -0xdc 0x043c #CYRILLIC SMALL LETTER EM -0xdd 0x043d #CYRILLIC SMALL LETTER EN -0xde 0x043e #CYRILLIC SMALL LETTER O -0xdf 0x043f #CYRILLIC SMALL LETTER PE -0xe0 0x0440 #CYRILLIC SMALL LETTER ER -0xe1 0x0441 #CYRILLIC SMALL LETTER ES -0xe2 0x0442 #CYRILLIC SMALL LETTER TE -0xe3 0x0443 #CYRILLIC SMALL LETTER U -0xe4 0x0444 #CYRILLIC SMALL LETTER EF -0xe5 0x0445 #CYRILLIC SMALL LETTER HA -0xe6 0x0446 #CYRILLIC SMALL LETTER TSE -0xe7 0x0447 #CYRILLIC SMALL LETTER CHE -0xe8 0x0448 #CYRILLIC SMALL LETTER SHA -0xe9 0x0449 #CYRILLIC SMALL LETTER SHCHA -0xea 0x044a #CYRILLIC SMALL LETTER HARD SIGN -0xeb 0x044b #CYRILLIC SMALL LETTER YERU -0xec 0x044c #CYRILLIC SMALL LETTER SOFT SIGN -0xed 0x044d #CYRILLIC SMALL LETTER E -0xee 0x044e #CYRILLIC SMALL LETTER YU -0xef 0x044f #CYRILLIC SMALL LETTER YA -0xf0 0x2116 #NUMERO SIGN -0xf1 0x0451 #CYRILLIC SMALL LETTER IO -0xf2 0x0452 #CYRILLIC SMALL LETTER DJE -0xf3 0x0453 #CYRILLIC SMALL LETTER GJE -0xf4 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE -0xf5 0x0455 #CYRILLIC SMALL LETTER DZE -0xf6 0x0456 #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -0xf7 0x0457 #CYRILLIC SMALL LETTER YI -0xf8 0x0458 #CYRILLIC SMALL LETTER JE -0xf9 0x0459 #CYRILLIC SMALL LETTER LJE -0xfa 0x045a #CYRILLIC SMALL LETTER NJE -0xfb 0x045b #CYRILLIC SMALL LETTER TSHE -0xfc 0x045c #CYRILLIC SMALL LETTER KJE -0xfd 0x00a7 #SECTION SIGN -0xfe 0x045e #CYRILLIC SMALL LETTER SHORT U -0xff 0x045f #CYRILLIC SMALL LETTER DZHE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_6.h b/src/intl/charsets/cs_iso8859_6.h index dab09f166ca..aa9e242c0f9 100644 --- a/src/intl/charsets/cs_iso8859_6.h +++ b/src/intl/charsets/cs_iso8859_6.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_6 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_6 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_6 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 #UNDEFINED -0xa2 #UNDEFINED -0xa3 #UNDEFINED -0xa4 0x00a4 #CURRENCY SIGN -0xa5 #UNDEFINED -0xa6 #UNDEFINED -0xa7 #UNDEFINED -0xa8 #UNDEFINED -0xa9 #UNDEFINED -0xaa #UNDEFINED -0xab #UNDEFINED -0xac 0x060c #ARABIC COMMA -0xad 0x00ad #SOFT HYPHEN -0xae #UNDEFINED -0xaf #UNDEFINED -0xb0 #UNDEFINED -0xb1 #UNDEFINED -0xb2 #UNDEFINED -0xb3 #UNDEFINED -0xb4 #UNDEFINED -0xb5 #UNDEFINED -0xb6 #UNDEFINED -0xb7 #UNDEFINED -0xb8 #UNDEFINED -0xb9 #UNDEFINED -0xba #UNDEFINED -0xbb 0x061b #ARABIC SEMICOLON -0xbc #UNDEFINED -0xbd #UNDEFINED -0xbe #UNDEFINED -0xbf 0x061f #ARABIC QUESTION MARK -0xc0 #UNDEFINED -0xc1 0x0621 #ARABIC LETTER HAMZA -0xc2 0x0622 #ARABIC LETTER ALEF WITH MADDA ABOVE -0xc3 0x0623 #ARABIC LETTER ALEF WITH HAMZA ABOVE -0xc4 0x0624 #ARABIC LETTER WAW WITH HAMZA ABOVE -0xc5 0x0625 #ARABIC LETTER ALEF WITH HAMZA BELOW -0xc6 0x0626 #ARABIC LETTER YEH WITH HAMZA ABOVE -0xc7 0x0627 #ARABIC LETTER ALEF -0xc8 0x0628 #ARABIC LETTER BEH -0xc9 0x0629 #ARABIC LETTER TEH MARBUTA -0xca 0x062a #ARABIC LETTER TEH -0xcb 0x062b #ARABIC LETTER THEH -0xcc 0x062c #ARABIC LETTER JEEM -0xcd 0x062d #ARABIC LETTER HAH -0xce 0x062e #ARABIC LETTER KHAH -0xcf 0x062f #ARABIC LETTER DAL -0xd0 0x0630 #ARABIC LETTER THAL -0xd1 0x0631 #ARABIC LETTER REH -0xd2 0x0632 #ARABIC LETTER ZAIN -0xd3 0x0633 #ARABIC LETTER SEEN -0xd4 0x0634 #ARABIC LETTER SHEEN -0xd5 0x0635 #ARABIC LETTER SAD -0xd6 0x0636 #ARABIC LETTER DAD -0xd7 0x0637 #ARABIC LETTER TAH -0xd8 0x0638 #ARABIC LETTER ZAH -0xd9 0x0639 #ARABIC LETTER AIN -0xda 0x063a #ARABIC LETTER GHAIN -0xdb #UNDEFINED -0xdc #UNDEFINED -0xdd #UNDEFINED -0xde #UNDEFINED -0xdf #UNDEFINED -0xe0 0x0640 #ARABIC TATWEEL -0xe1 0x0641 #ARABIC LETTER FEH -0xe2 0x0642 #ARABIC LETTER QAF -0xe3 0x0643 #ARABIC LETTER KAF -0xe4 0x0644 #ARABIC LETTER LAM -0xe5 0x0645 #ARABIC LETTER MEEM -0xe6 0x0646 #ARABIC LETTER NOON -0xe7 0x0647 #ARABIC LETTER HEH -0xe8 0x0648 #ARABIC LETTER WAW -0xe9 0x0649 #ARABIC LETTER ALEF MAKSURA -0xea 0x064a #ARABIC LETTER YEH -0xeb 0x064b #ARABIC FATHATAN -0xec 0x064c #ARABIC DAMMATAN -0xed 0x064d #ARABIC KASRATAN -0xee 0x064e #ARABIC FATHA -0xef 0x064f #ARABIC DAMMA -0xf0 0x0650 #ARABIC KASRA -0xf1 0x0651 #ARABIC SHADDA -0xf2 0x0652 #ARABIC SUKUN -0xf3 #UNDEFINED -0xf4 #UNDEFINED -0xf5 #UNDEFINED -0xf6 #UNDEFINED -0xf7 #UNDEFINED -0xf8 #UNDEFINED -0xf9 #UNDEFINED -0xfa #UNDEFINED -0xfb #UNDEFINED -0xfc #UNDEFINED -0xfd #UNDEFINED -0xfe #UNDEFINED -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_7.h b/src/intl/charsets/cs_iso8859_7.h index 1cc29f63de4..0cb8da48d35 100644 --- a/src/intl/charsets/cs_iso8859_7.h +++ b/src/intl/charsets/cs_iso8859_7.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_7 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_7 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_7 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x02bd #MODIFIER LETTER REVERSED COMMA -0xa2 0x02bc #MODIFIER LETTER APOSTROPHE -0xa3 0x00a3 #POUND SIGN -0xa4 #UNDEFINED -0xa5 #UNDEFINED -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa #UNDEFINED -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae #UNDEFINED -0xaf 0x2015 #HORIZONTAL BAR -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x0384 #GREEK TONOS -0xb5 0x0385 #GREEK DIALYTIKA TONOS -0xb6 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS -0xb9 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS -0xba 0x038a #GREEK CAPITAL LETTER IOTA WITH TONOS -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x038c #GREEK CAPITAL LETTER OMICRON WITH TONOS -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x038e #GREEK CAPITAL LETTER UPSILON WITH TONOS -0xbf 0x038f #GREEK CAPITAL LETTER OMEGA WITH TONOS -0xc0 0x0390 #GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -0xc1 0x0391 #GREEK CAPITAL LETTER ALPHA -0xc2 0x0392 #GREEK CAPITAL LETTER BETA -0xc3 0x0393 #GREEK CAPITAL LETTER GAMMA -0xc4 0x0394 #GREEK CAPITAL LETTER DELTA -0xc5 0x0395 #GREEK CAPITAL LETTER EPSILON -0xc6 0x0396 #GREEK CAPITAL LETTER ZETA -0xc7 0x0397 #GREEK CAPITAL LETTER ETA -0xc8 0x0398 #GREEK CAPITAL LETTER THETA -0xc9 0x0399 #GREEK CAPITAL LETTER IOTA -0xca 0x039a #GREEK CAPITAL LETTER KAPPA -0xcb 0x039b #GREEK CAPITAL LETTER LAMDA -0xcc 0x039c #GREEK CAPITAL LETTER MU -0xcd 0x039d #GREEK CAPITAL LETTER NU -0xce 0x039e #GREEK CAPITAL LETTER XI -0xcf 0x039f #GREEK CAPITAL LETTER OMICRON -0xd0 0x03a0 #GREEK CAPITAL LETTER PI -0xd1 0x03a1 #GREEK CAPITAL LETTER RHO -0xd2 #UNDEFINED -0xd3 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xd4 0x03a4 #GREEK CAPITAL LETTER TAU -0xd5 0x03a5 #GREEK CAPITAL LETTER UPSILON -0xd6 0x03a6 #GREEK CAPITAL LETTER PHI -0xd7 0x03a7 #GREEK CAPITAL LETTER CHI -0xd8 0x03a8 #GREEK CAPITAL LETTER PSI -0xd9 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xda 0x03aa #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -0xdb 0x03ab #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -0xdc 0x03ac #GREEK SMALL LETTER ALPHA WITH TONOS -0xdd 0x03ad #GREEK SMALL LETTER EPSILON WITH TONOS -0xde 0x03ae #GREEK SMALL LETTER ETA WITH TONOS -0xdf 0x03af #GREEK SMALL LETTER IOTA WITH TONOS -0xe0 0x03b0 #GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -0xe1 0x03b1 #GREEK SMALL LETTER ALPHA -0xe2 0x03b2 #GREEK SMALL LETTER BETA -0xe3 0x03b3 #GREEK SMALL LETTER GAMMA -0xe4 0x03b4 #GREEK SMALL LETTER DELTA -0xe5 0x03b5 #GREEK SMALL LETTER EPSILON -0xe6 0x03b6 #GREEK SMALL LETTER ZETA -0xe7 0x03b7 #GREEK SMALL LETTER ETA -0xe8 0x03b8 #GREEK SMALL LETTER THETA -0xe9 0x03b9 #GREEK SMALL LETTER IOTA -0xea 0x03ba #GREEK SMALL LETTER KAPPA -0xeb 0x03bb #GREEK SMALL LETTER LAMDA -0xec 0x03bc #GREEK SMALL LETTER MU -0xed 0x03bd #GREEK SMALL LETTER NU -0xee 0x03be #GREEK SMALL LETTER XI -0xef 0x03bf #GREEK SMALL LETTER OMICRON -0xf0 0x03c0 #GREEK SMALL LETTER PI -0xf1 0x03c1 #GREEK SMALL LETTER RHO -0xf2 0x03c2 #GREEK SMALL LETTER FINAL SIGMA -0xf3 0x03c3 #GREEK SMALL LETTER SIGMA -0xf4 0x03c4 #GREEK SMALL LETTER TAU -0xf5 0x03c5 #GREEK SMALL LETTER UPSILON -0xf6 0x03c6 #GREEK SMALL LETTER PHI -0xf7 0x03c7 #GREEK SMALL LETTER CHI -0xf8 0x03c8 #GREEK SMALL LETTER PSI -0xf9 0x03c9 #GREEK SMALL LETTER OMEGA -0xfa 0x03ca #GREEK SMALL LETTER IOTA WITH DIALYTIKA -0xfb 0x03cb #GREEK SMALL LETTER UPSILON WITH DIALYTIKA -0xfc 0x03cc #GREEK SMALL LETTER OMICRON WITH TONOS -0xfd 0x03cd #GREEK SMALL LETTER UPSILON WITH TONOS -0xfe 0x03ce #GREEK SMALL LETTER OMEGA WITH TONOS -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_8.h b/src/intl/charsets/cs_iso8859_8.h index b5e582a2d07..a7ceed8852c 100644 --- a/src/intl/charsets/cs_iso8859_8.h +++ b/src/intl/charsets/cs_iso8859_8.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_8 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_8 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_8 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 #UNDEFINED -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00d7 #MULTIPLICATION SIGN -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x203e #OVERLINE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00f7 #DIVISION SIGN -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf #UNDEFINED -0xc0 #UNDEFINED -0xc1 #UNDEFINED -0xc2 #UNDEFINED -0xc3 #UNDEFINED -0xc4 #UNDEFINED -0xc5 #UNDEFINED -0xc6 #UNDEFINED -0xc7 #UNDEFINED -0xc8 #UNDEFINED -0xc9 #UNDEFINED -0xca #UNDEFINED -0xcb #UNDEFINED -0xcc #UNDEFINED -0xcd #UNDEFINED -0xce #UNDEFINED -0xcf #UNDEFINED -0xd0 #UNDEFINED -0xd1 #UNDEFINED -0xd2 #UNDEFINED -0xd3 #UNDEFINED -0xd4 #UNDEFINED -0xd5 #UNDEFINED -0xd6 #UNDEFINED -0xd7 #UNDEFINED -0xd8 #UNDEFINED -0xd9 #UNDEFINED -0xda #UNDEFINED -0xdb #UNDEFINED -0xdc #UNDEFINED -0xdd #UNDEFINED -0xde #UNDEFINED -0xdf 0x2017 #DOUBLE LOW LINE -0xe0 0x05d0 #HEBREW LETTER ALEF -0xe1 0x05d1 #HEBREW LETTER BET -0xe2 0x05d2 #HEBREW LETTER GIMEL -0xe3 0x05d3 #HEBREW LETTER DALET -0xe4 0x05d4 #HEBREW LETTER HE -0xe5 0x05d5 #HEBREW LETTER VAV -0xe6 0x05d6 #HEBREW LETTER ZAYIN -0xe7 0x05d7 #HEBREW LETTER HET -0xe8 0x05d8 #HEBREW LETTER TET -0xe9 0x05d9 #HEBREW LETTER YOD -0xea 0x05da #HEBREW LETTER FINAL KAF -0xeb 0x05db #HEBREW LETTER KAF -0xec 0x05dc #HEBREW LETTER LAMED -0xed 0x05dd #HEBREW LETTER FINAL MEM -0xee 0x05de #HEBREW LETTER MEM -0xef 0x05df #HEBREW LETTER FINAL NUN -0xf0 0x05e0 #HEBREW LETTER NUN -0xf1 0x05e1 #HEBREW LETTER SAMEKH -0xf2 0x05e2 #HEBREW LETTER AYIN -0xf3 0x05e3 #HEBREW LETTER FINAL PE -0xf4 0x05e4 #HEBREW LETTER PE -0xf5 0x05e5 #HEBREW LETTER FINAL TSADI -0xf6 0x05e6 #HEBREW LETTER TSADI -0xf7 0x05e7 #HEBREW LETTER QOF -0xf8 0x05e8 #HEBREW LETTER RESH -0xf9 0x05e9 #HEBREW LETTER SHIN -0xfa 0x05ea #HEBREW LETTER TAV -0xfb #UNDEFINED -0xfc #UNDEFINED -0xfd #UNDEFINED -0xfe #UNDEFINED -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_iso8859_9.h b/src/intl/charsets/cs_iso8859_9.h index 16feb6ad239..0c255b3e7ae 100644 --- a/src/intl/charsets/cs_iso8859_9.h +++ b/src/intl/charsets/cs_iso8859_9.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: ISO8859_9 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the ISO8859_9 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in ISO8859_9 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0080 # -0x81 0x0081 # -0x82 0x0082 #BREAK PERMITTED HERE -0x83 0x0083 #NO BREAK HERE -0x84 0x0084 # -0x85 0x0085 #NEXT LINE (NEL) -0x86 0x0086 #START OF SELECTED AREA -0x87 0x0087 #END OF SELECTED AREA -0x88 0x0088 #CHARACTER TABULATION SET -0x89 0x0089 #CHARACTER TABULATION WITH JUSTIFICATION -0x8a 0x008a #LINE TABULATION SET -0x8b 0x008b #PARTIAL LINE FORWARD -0x8c 0x008c #PARTIAL LINE BACKWARD -0x8d 0x008d #REVERSE LINE FEED -0x8e 0x008e #SINGLE SHIFT TWO -0x8f 0x008f #SINGLE SHIFT THREE -0x90 0x0090 #DEVICE CONTROL STRING -0x91 0x0091 #PRIVATE USE ONE -0x92 0x0092 #PRIVATE USE TWO -0x93 0x0093 #SET TRANSMIT STATE -0x94 0x0094 #CANCEL CHARACTER -0x95 0x0095 #MESSAGE WAITING -0x96 0x0096 #START OF GUARDED AREA -0x97 0x0097 #END OF GUARDED AREA -0x98 0x0098 #START OF STRING -0x99 0x0099 # -0x9a 0x009a #SINGLE CHARACTER INTRODUCER -0x9b 0x009b #CONTROL SEQUENCE INTRODUCER -0x9c 0x009c #STRING TERMINATOR -0x9d 0x009d #OPERATING SYSTEM COMMAND -0x9e 0x009e #PRIVACY MESSAGE -0x9f 0x009f #APPLICATION PROGRAM COMMAND -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00a1 #INVERTED EXCLAMATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00aa #FEMININE ORDINAL INDICATOR -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00ba #MASCULINE ORDINAL INDICATOR -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00bf #INVERTED QUESTION MARK -0xc0 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x00c6 #LATIN CAPITAL LETTER AE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd0 0x011e #LATIN CAPITAL LETTER G WITH BREVE -0xd1 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xd2 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xd9 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE -0xde 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x00e6 #LATIN SMALL LETTER AE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 0x011f #LATIN SMALL LETTER G WITH BREVE -0xf1 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xf2 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x0131 #LATIN SMALL LETTER DOTLESS I -0xfe 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xff 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_jis_0208_1990.h b/src/intl/charsets/cs_jis_0208_1990.h index 481211d311e..3c64e6a6f0a 100644 --- a/src/intl/charsets/cs_jis_0208_1990.h +++ b/src/intl/charsets/cs_jis_0208_1990.h @@ -4,46 +4,12 @@ Unicode mapping table generated from file asia/JIS/JIS0208.TXT -# # Name: JIS X 0208 (1990) to Unicode # Unicode version: 1.1 # Table version: 0.9 # Table format: Format A # Date: 8 March 1994 -# Authors: Glenn Adams -# John H. Jenkins -# -# -# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). -# No claims are made as to fitness for any particular purpose. No -# warranties of any kind are expressed or implied. The recipient -# agrees to determine applicability of information provided. If this -# file has been provided on magnetic media by Unicode, Inc., the sole -# remedy for any claim will be exchange of defective media within 90 -# days of receipt. -# -# Recipient is granted the right to make copies in any form for -# internal distribution and to freely use the information supplied -# in the creation of products supporting Unicode. Unicode, Inc. -# specifically excludes the right to re-distribute this file directly -# to third parties or other organizations whether for profit or not. -# -# General notes: -# -# The following algorithms can be used to change the hex form -# of JIS 0208 to other standard forms: -# -# To change hex to EUC form, add 0x8080 -# To change hex to kuten form, first subtract 0x2020. Then -# the high and low bytes correspond to the ku and ten of -# the kuten form. For example, 0x2121 -> 0x0101 -> 0101; -# 0x7426 -> 0x5406 -> 8406 -# -# The kanji mappings are a normative part of ISO/IEC 10646. The -# non-kanji mappings are provisional, pending definition of -# official mappings by Japanese standards bodies -# -# Any comments or problems, contact + * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy diff --git a/src/intl/charsets/cs_koi8r.h b/src/intl/charsets/cs_koi8r.h index 21d928a1742..0cea98729ef 100644 --- a/src/intl/charsets/cs_koi8r.h +++ b/src/intl/charsets/cs_koi8r.h @@ -4,266 +4,9 @@ Unicode mapping table generated from file koi8r.txt -0x00 0x0000 # -0x01 0x0001 # -0x02 0x0002 # -0x03 0x0003 # -0x04 0x0004 # -0x05 0x0005 # -0x06 0x0006 # -0x07 0x0007 # -0x08 0x0008 # -0x09 0x0009 # -0x0A 0x000A # -0x0B 0x000B # -0x0C 0x000C # -0x0D 0x000D # -0x0E 0x000E # -0x0F 0x000F # -0x10 0x0010 # -0x11 0x0011 # -0x12 0x0012 # -0x13 0x0013 # -0x14 0x0014 # -0x15 0x0015 # -0x16 0x0016 # -0x17 0x0017 # -0x18 0x0018 # -0x19 0x0019 # -0x1A 0x001A # -0x1B 0x001B # -0x1C 0x001C # -0x1D 0x001D # -0x1E 0x001E # -0x1F 0x001F # -0x20 0x0020 # -0x21 0x0021 # -0x22 0x0022 # -0x23 0x0023 # -0x24 0x0024 # -0x25 0x0025 # -0x26 0x0026 # -0x27 0x0027 # -0x28 0x0028 # -0x29 0x0029 # -0x2A 0x002A # -0x2B 0x002B # -0x2C 0x002C # -0x2D 0x002D # -0x2E 0x002E # -0x2F 0x002F # -0x30 0x0030 # -0x31 0x0031 # -0x32 0x0032 # -0x33 0x0033 # -0x34 0x0034 # -0x35 0x0035 # -0x36 0x0036 # -0x37 0x0037 # -0x38 0x0038 # -0x39 0x0039 # -0x3A 0x003A # -0x3B 0x003B # -0x3C 0x003C # -0x3D 0x003D # -0x3E 0x003E # -0x3F 0x003F # -0x40 0x0040 # -0x41 0x0041 # -0x42 0x0042 # -0x43 0x0043 # -0x44 0x0044 # -0x45 0x0045 # -0x46 0x0046 # -0x47 0x0047 # -0x48 0x0048 # -0x49 0x0049 # -0x4A 0x004A # -0x4B 0x004B # -0x4C 0x004C # -0x4D 0x004D # -0x4E 0x004E # -0x4F 0x004F # -0x50 0x0050 # -0x51 0x0051 # -0x52 0x0052 # -0x53 0x0053 # -0x54 0x0054 # -0x55 0x0055 # -0x56 0x0056 # -0x57 0x0057 # -0x58 0x0058 # -0x59 0x0059 # -0x5A 0x005A # -0x5B 0x005B # -0x5C 0x005C # -0x5D 0x005D # -0x5E 0x005E # -0x5F 0x005F # -0x60 0x0060 # -0x61 0x0061 # -0x62 0x0062 # -0x63 0x0063 # -0x64 0x0064 # -0x65 0x0065 # -0x66 0x0066 # -0x67 0x0067 # -0x68 0x0068 # -0x69 0x0069 # -0x6A 0x006A # -0x6B 0x006B # -0x6C 0x006C # -0x6D 0x006D # -0x6E 0x006E # -0x6F 0x006F # -0x70 0x0070 # -0x71 0x0071 # -0x72 0x0072 # -0x73 0x0073 # -0x74 0x0074 # -0x75 0x0075 # -0x76 0x0076 # -0x77 0x0077 # -0x78 0x0078 # -0x79 0x0079 # -0x7A 0x007A # -0x7B 0x007B # -0x7C 0x007C # -0x7D 0x007D # -0x7E 0x007E # -0x7F 0x007F # -0x80 0x2500 # -0x81 0x2502 # -0x82 0x250C # -0x83 0x2510 # -0x84 0x2514 # -0x85 0x2518 # -0x86 0x251C # -0x87 0x2524 # -0x88 0x252C # -0x89 0x2534 # -0x8A 0x253C # -0x8B 0x2580 # -0x8C 0x2584 # -0x8D 0x2588 # -0x8E 0x258C # -0x8F 0x2590 # -0x90 0x2591 # -0x91 0x2592 # -0x92 0x2593 # -0x93 0x2320 # -0x94 0x25A0 # -0x95 0x2219 # -0x96 0x221A # -0x97 0x2248 # -0x98 0x2264 # -0x99 0x2265 # -0x9A 0x00A0 # -0x9B 0x2321 # -0x9C 0x00B0 # -0x9D 0x00B2 # -0x9E 0x00B7 # -0x9F 0x00F7 # -0xA0 0x2550 # -0xA1 0x2551 # -0xA2 0x2552 # -0xA3 0x0451 # -0xA4 0x2553 # -0xA5 0x2554 # -0xA6 0x2555 # -0xA7 0x2556 # -0xA8 0x2557 # -0xA9 0x2558 # -0xAA 0x2559 # -0xAB 0x255A # -0xAC 0x255B # -0xAD 0x255C # -0xAE 0x255D # -0xAF 0x255E # -0xB0 0x255F # -0xB1 0x2560 # -0xB2 0x2561 # -0xB3 0x0401 # -0xB4 0x2562 # -0xB5 0x2563 # -0xB6 0x2564 # -0xB7 0x2565 # -0xB8 0x2566 # -0xB9 0x2567 # -0xBA 0x2568 # -0xBB 0x2569 # -0xBC 0x256A # -0xBD 0x256B # -0xBE 0x256C # -0xBF 0x00A9 # -0xC0 0x044E # -0xC1 0x0430 # -0xC2 0x0431 # -0xC3 0x0446 # -0xC4 0x0434 # -0xC5 0x0435 # -0xC6 0x0444 # -0xC7 0x0433 # -0xC8 0x0445 # -0xC9 0x0438 # -0xCA 0x0439 # -0xCB 0x043A # -0xCC 0x043B # -0xCD 0x043C # -0xCE 0x043D # -0xCF 0x043E # -0xD0 0x043F # -0xD1 0x044F # -0xD2 0x0440 # -0xD3 0x0441 # -0xD4 0x0442 # -0xD5 0x0443 # -0xD6 0x0436 # -0xD7 0x0432 # -0xD8 0x044C # -0xD9 0x044B # -0xDA 0x0437 # -0xDB 0x0448 # -0xDC 0x044D # -0xDD 0x0449 # -0xDE 0x0447 # -0xDF 0x044A # -0xE0 0x042E # -0xE1 0x0410 # -0xE2 0x0411 # -0xE3 0x0426 # -0xE4 0x0414 # -0xE5 0x0415 # -0xE6 0x0424 # -0xE7 0x0413 # -0xE8 0x0425 # -0xE9 0x0418 # -0xEA 0x0419 # -0xEB 0x041A # -0xEC 0x041B # -0xED 0x041C # -0xEE 0x041D # -0xEF 0x041E # -0xF0 0x041F # -0xF1 0x042F # -0xF2 0x0420 # -0xF3 0x0421 # -0xF4 0x0422 # -0xF5 0x0423 # -0xF6 0x0416 # -0xF7 0x0412 # -0xF8 0x042C # -0xF9 0x042B # -0xFA 0x0417 # -0xFB 0x0428 # -0xFC 0x042D # -0xFD 0x0429 # -0xFE 0x0427 # -0xFF 0x042A # -------------------------------------------- */ -static const int UNICODE_REPLACEMENT_CHARACTER = 0xFFFD; static const int CANT_MAP_CHARACTER = 0; static const USHORT to_unicode_map[256] = { diff --git a/src/intl/charsets/cs_koi8u.h b/src/intl/charsets/cs_koi8u.h index a811d31f425..6c8866774d8 100644 --- a/src/intl/charsets/cs_koi8u.h +++ b/src/intl/charsets/cs_koi8u.h @@ -4,262 +4,6 @@ Unicode mapping table generated from file cs_koi8u.txt -0x00 0x0000 # -0x01 0x0001 # -0x02 0x0002 # -0x03 0x0003 # -0x04 0x0004 # -0x05 0x0005 # -0x06 0x0006 # -0x07 0x0007 # -0x08 0x0008 # -0x09 0x0009 # -0x0A 0x000A # -0x0B 0x000B # -0x0C 0x000C # -0x0D 0x000D # -0x0E 0x000E # -0x0F 0x000F # -0x10 0x0010 # -0x11 0x0011 # -0x12 0x0012 # -0x13 0x0013 # -0x14 0x0014 # -0x15 0x0015 # -0x16 0x0016 # -0x17 0x0017 # -0x18 0x0018 # -0x19 0x0019 # -0x1A 0x001A # -0x1B 0x001B # -0x1C 0x001C # -0x1D 0x001D # -0x1E 0x001E # -0x1F 0x001F # -0x20 0x0020 # -0x21 0x0021 # -0x22 0x0022 # -0x23 0x0023 # -0x24 0x0024 # -0x25 0x0025 # -0x26 0x0026 # -0x27 0x0027 # -0x28 0x0028 # -0x29 0x0029 # -0x2A 0x002A # -0x2B 0x002B # -0x2C 0x002C # -0x2D 0x002D # -0x2E 0x002E # -0x2F 0x002F # -0x30 0x0030 # -0x31 0x0031 # -0x32 0x0032 # -0x33 0x0033 # -0x34 0x0034 # -0x35 0x0035 # -0x36 0x0036 # -0x37 0x0037 # -0x38 0x0038 # -0x39 0x0039 # -0x3A 0x003A # -0x3B 0x003B # -0x3C 0x003C # -0x3D 0x003D # -0x3E 0x003E # -0x3F 0x003F # -0x40 0x0040 # -0x41 0x0041 # -0x42 0x0042 # -0x43 0x0043 # -0x44 0x0044 # -0x45 0x0045 # -0x46 0x0046 # -0x47 0x0047 # -0x48 0x0048 # -0x49 0x0049 # -0x4A 0x004A # -0x4B 0x004B # -0x4C 0x004C # -0x4D 0x004D # -0x4E 0x004E # -0x4F 0x004F # -0x50 0x0050 # -0x51 0x0051 # -0x52 0x0052 # -0x53 0x0053 # -0x54 0x0054 # -0x55 0x0055 # -0x56 0x0056 # -0x57 0x0057 # -0x58 0x0058 # -0x59 0x0059 # -0x5A 0x005A # -0x5B 0x005B # -0x5C 0x005C # -0x5D 0x005D # -0x5E 0x005E # -0x5F 0x005F # -0x60 0x0060 # -0x61 0x0061 # -0x62 0x0062 # -0x63 0x0063 # -0x64 0x0064 # -0x65 0x0065 # -0x66 0x0066 # -0x67 0x0067 # -0x68 0x0068 # -0x69 0x0069 # -0x6A 0x006A # -0x6B 0x006B # -0x6C 0x006C # -0x6D 0x006D # -0x6E 0x006E # -0x6F 0x006F # -0x70 0x0070 # -0x71 0x0071 # -0x72 0x0072 # -0x73 0x0073 # -0x74 0x0074 # -0x75 0x0075 # -0x76 0x0076 # -0x77 0x0077 # -0x78 0x0078 # -0x79 0x0079 # -0x7A 0x007A # -0x7B 0x007B # -0x7C 0x007C # -0x7D 0x007D # -0x7E 0x007E # -0x7F 0x007F # -0x80 0x2500 # -0x81 0x2502 # -0x82 0x250C # -0x83 0x2510 # -0x84 0x2514 # -0x85 0x2518 # -0x86 0x251C # -0x87 0x2524 # -0x88 0x252C # -0x89 0x2534 # -0x8A 0x253C # -0x8B 0x2580 # -0x8C 0x2584 # -0x8D 0x2588 # -0x8E 0x258C # -0x8F 0x2590 # -0x90 0x2591 # -0x91 0x2592 # -0x92 0x2593 # -0x93 0x2320 # -0x94 0x25A0 # -0x95 0x2219 # -0x96 0x221A # -0x97 0x2248 # -0x98 0x2264 # -0x99 0x2265 # -0x9A 0x00A0 # -0x9B 0x2321 # -0x9C 0x00B0 # -0x9D 0x00B2 # -0x9E 0x00B7 # -0x9F 0x00F7 # -0xA0 0x2550 # -0xA1 0x2551 # -0xA2 0x2552 # -0xA3 0x0451 # -0xA4 0x0454 # -0xA5 0x2554 # -0xA6 0x0456 # -0xA7 0x0457 # -0xA8 0x2557 # -0xA9 0x2558 # -0xAA 0x2559 # -0xAB 0x255A # -0xAC 0x255B # -0xAD 0x0491 # -0xAE 0x045E # -0xAF 0x255E # -0xB0 0x255F # -0xB1 0x2560 # -0xB2 0x2561 # -0xB3 0x0401 # -0xB4 0x0404 # -0xB5 0x2563 # -0xB6 0x0406 # -0xB7 0x0407 # -0xB8 0x2566 # -0xB9 0x2567 # -0xBA 0x2568 # -0xBB 0x2569 # -0xBC 0x256A # -0xBD 0x0490 # -0xBE 0x040E # -0xBF 0x00A9 # -0xC0 0x044E # -0xC1 0x0430 # -0xC2 0x0431 # -0xC3 0x0446 # -0xC4 0x0434 # -0xC5 0x0435 # -0xC6 0x0444 # -0xC7 0x0433 # -0xC8 0x0445 # -0xC9 0x0438 # -0xCA 0x0439 # -0xCB 0x043A # -0xCC 0x043B # -0xCD 0x043C # -0xCE 0x043D # -0xCF 0x043E # -0xD0 0x043F # -0xD1 0x044F # -0xD2 0x0440 # -0xD3 0x0441 # -0xD4 0x0442 # -0xD5 0x0443 # -0xD6 0x0436 # -0xD7 0x0432 # -0xD8 0x044C # -0xD9 0x044B # -0xDA 0x0437 # -0xDB 0x0448 # -0xDC 0x044D # -0xDD 0x0449 # -0xDE 0x0447 # -0xDF 0x044A # -0xE0 0x042E # -0xE1 0x0410 # -0xE2 0x0411 # -0xE3 0x0426 # -0xE4 0x0414 # -0xE5 0x0415 # -0xE6 0x0424 # -0xE7 0x0413 # -0xE8 0x0425 # -0xE9 0x0418 # -0xEA 0x0419 # -0xEB 0x041A # -0xEC 0x041B # -0xED 0x041C # -0xEE 0x041D # -0xEF 0x041E # -0xF0 0x041F # -0xF1 0x042F # -0xF2 0x0420 # -0xF3 0x0421 # -0xF4 0x0422 # -0xF5 0x0423 # -0xF6 0x0416 # -0xF7 0x0412 # -0xF8 0x042C # -0xF9 0x042B # -0xFA 0x0417 # -0xFB 0x0428 # -0xFC 0x042D # -0xFD 0x0429 # -0xFE 0x0427 # -0xFF 0x042A # -------------------------------------------- */ diff --git a/src/intl/charsets/cs_ksc5601.h b/src/intl/charsets/cs_ksc5601.h index 8492bbafe88..be84d51ec59 100644 --- a/src/intl/charsets/cs_ksc5601.h +++ b/src/intl/charsets/cs_ksc5601.h @@ -4,16 +4,11 @@ Unicode mapping table generated from file asia/KSC/KSC5601.TXT -# # Name: Unified Hangeul(KSC5601-1992) to Unicode table # Unicode version: 2.0 # Table version: 1.0 # Table format: Format A # Date: 07/24/95 -# Authors: Lori Hoerth -# K.D.Chang -# General notes: none -# * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_next.h b/src/intl/charsets/cs_next.h index ceb0a9a3602..8b0f18f39dc 100644 --- a/src/intl/charsets/cs_next.h +++ b/src/intl/charsets/cs_next.h @@ -3,301 +3,12 @@ Unicode mapping table generated from file NEXTSTEP.TXT -# # Name: NextStep Encoding to Unicode # Unicode version: 1.1 # Table version: 0.1 # Table format: Format A # Date: 14 February 1995 -# Authors: Rick McGowan (rick@unicode.org) -# -# -# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). -# No claims are made as to fitness for any particular purpose. No -# warranties of any kind are expressed or implied. The recipient -# agrees to determine applicability of information provided. If this -# file has been provided on magnetic media by Unicode, Inc., the sole -# remedy for any claim will be exchange of defective media within 90 -# days of receipt. -# -# Recipient is granted the right to make copies in any form for -# internal distribution and to freely use the information supplied -# in the creation of products supporting Unicode. Unicode, Inc. -# specifically excludes the right to re-distribute this file directly -# to third parties or other organizations whether for profit or not. -# -# General notes: -# -# This table contains the data the Unicode Consortium has on how -# NextStep Encoding characters map into Unicode. Since the first -# 128 characters (0x0 - 0x7f) are identical to ASCII and Unicode, -# this table only maps the NextStep range from 0x80 - 0xFF. -# -# Format: Three tab-separated columns -# Column #1 is the NextStep code (in hex as 0xXX) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 NextStep name, Unicode name (follows a comment sign, '#') -# -# The entries are in NextStep order -# -# Any comments or problems, contact rick@unicode.org -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #HORIZONTAL TABULATION -0x0a 0x000a #LINE FEED -0x0b 0x000b #VERTICAL TABULATION -0x0c 0x000c #FORM FEED -0x0d 0x000d #CARRIAGE RETURN -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #FILE SEPARATOR -0x1d 0x001d #GROUP SEPARATOR -0x1e 0x001e #RECORD SEPARATOR -0x1f 0x001f #UNIT SEPARATOR -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x00a0 # NO-BREAK SPACE -0x81 0x00c0 # LATIN CAPITAL LETTER A WITH GRAVE -0x82 0x00c1 # LATIN CAPITAL LETTER A WITH ACUTE -0x83 0x00c2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0x84 0x00c3 # LATIN CAPITAL LETTER A WITH TILDE -0x85 0x00c4 # LATIN CAPITAL LETTER A WITH DIAERESIS -0x86 0x00c5 # LATIN CAPITAL LETTER A WITH RING -0x87 0x00c7 # LATIN CAPITAL LETTER C WITH CEDILLA -0x88 0x00c8 # LATIN CAPITAL LETTER E WITH GRAVE -0x89 0x00c9 # LATIN CAPITAL LETTER E WITH ACUTE -0x8a 0x00ca # LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0x8b 0x00cb # LATIN CAPITAL LETTER E WITH DIAERESIS -0x8c 0x00cc # LATIN CAPITAL LETTER I WITH GRAVE -0x8d 0x00cd # LATIN CAPITAL LETTER I WITH ACUTE -0x8e 0x00ce # LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0x8f 0x00cf # LATIN CAPITAL LETTER I WITH DIAERESIS -0x90 0x00d0 # LATIN CAPITAL LETTER ETH -0x91 0x00d1 # LATIN CAPITAL LETTER N WITH TILDE -0x92 0x00d2 # LATIN CAPITAL LETTER O WITH GRAVE -0x93 0x00d3 # LATIN CAPITAL LETTER O WITH ACUTE -0x94 0x00d4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0x95 0x00d5 # LATIN CAPITAL LETTER O WITH TILDE -0x96 0x00d6 # LATIN CAPITAL LETTER O WITH DIAERESIS -0x97 0x00d9 # LATIN CAPITAL LETTER U WITH GRAVE -0x98 0x00da # LATIN CAPITAL LETTER U WITH ACUTE -0x99 0x00db # LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0x9a 0x00dc # LATIN CAPITAL LETTER U WITH DIAERESIS -0x9b 0x00dd # LATIN CAPITAL LETTER Y WITH ACUTE -0x9c 0x00de # LATIN CAPITAL LETTER THORN -0x9d 0x00b5 # MICRO SIGN -0x9e 0x00d7 # MULTIPLICATION SIGN -0x9f 0x00f7 # DIVISION SIGN -0xa0 0x00a9 # COPYRIGHT SIGN -0xa1 0x00a1 # INVERTED EXCLAMATION MARK -0xa2 0x00a2 # CENT SIGN -0xa3 0x00a3 # POUND SIGN -0xa4 0x2044 # FRACTION SLASH -0xa5 0x00a5 # YEN SIGN -0xa6 0x0192 # LATIN SMALL LETTER F WITH HOOK -0xa7 0x00a7 # SECTION SIGN -0xa8 0x00a4 # CURRENCY SIGN -0xa9 0x2019 # RIGHT SINGLE QUOTATION MARK -0xaa 0x201c # LEFT DOUBLE QUOTATION MARK -0xab 0x00ab # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x2039 # LATIN SMALL LETTER -0xad 0x203a # LATIN SMALL LETTER -0xae 0xfb01 # LATIN SMALL LIGATURE FI -0xaf 0xfb02 # LATIN SMALL LIGATURE FL -0xb0 0x00ae # REGISTERED SIGN -0xb1 0x2013 # EN DASH -0xb2 0x2020 # DAGGER -0xb3 0x2021 # DOUBLE DAGGER -0xb4 0x00b7 # MIDDLE DOT -0xb5 0x00a6 # BROKEN BAR -0xb6 0x00b6 # PILCROW SIGN -0xb7 0x2022 # BULLET -0xb8 0x201a # SINGLE LOW-9 QUOTATION MARK -0xb9 0x201e # DOUBLE LOW-9 QUOTATION MARK -0xba 0x201d # RIGHT DOUBLE QUOTATION MARK -0xbb 0x00bb # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x2026 # HORIZONTAL ELLIPSIS -0xbd 0x2030 # PER MILLE SIGN -0xbe 0x00ac # NOT SIGN -0xbf 0x00bf # INVERTED QUESTION MARK -0xc0 0x00b9 # SUPERSCRIPT ONE -0xc1 0x02cb # MODIFIER LETTER GRAVE ACCENT -0xc2 0x00b4 # ACUTE ACCENT -0xc3 0x02c6 # MODIFIER LETTER CIRCUMFLEX ACCENT -0xc4 0x02dc # SMALL TILDE -0xc5 0x00af # MACRON -0xc6 0x02d8 # BREVE -0xc7 0x02d9 # DOT ABOVE -0xc8 0x00a8 # DIAERESIS -0xc9 0x00b2 # SUPERSCRIPT TWO -0xca 0x02da # RING ABOVE -0xcb 0x00b8 # CEDILLA -0xcc 0x00b3 # SUPERSCRIPT THREE -0xcd 0x02dd # DOUBLE ACUTE ACCENT -0xce 0x02db # OGONEK -0xcf 0x02c7 # CARON -0xd0 0x2014 # EM DASH -0xd1 0x00b1 # PLUS-MINUS SIGN -0xd2 0x00bc # VULGAR FRACTION ONE QUARTER -0xd3 0x00bd # VULGAR FRACTION ONE HALF -0xd4 0x00be # VULGAR FRACTION THREE QUARTERS -0xd5 0x00e0 # LATIN SMALL LETTER A WITH GRAVE -0xd6 0x00e1 # LATIN SMALL LETTER A WITH ACUTE -0xd7 0x00e2 # LATIN SMALL LETTER A WITH CIRCUMFLEX -0xd8 0x00e3 # LATIN SMALL LETTER A WITH TILDE -0xd9 0x00e4 # LATIN SMALL LETTER A WITH DIAERESIS -0xda 0x00e5 # LATIN SMALL LETTER A WITH RING ABOVE -0xdb 0x00e7 # LATIN SMALL LETTER C WITH CEDILLA -0xdc 0x00e8 # LATIN SMALL LETTER E WITH GRAVE -0xdd 0x00e9 # LATIN SMALL LETTER E WITH ACUTE -0xde 0x00ea # LATIN SMALL LETTER E WITH CIRCUMFLEX -0xdf 0x00eb # LATIN SMALL LETTER E WITH DIAERESIS -0xe0 0x00ec # LATIN SMALL LETTER I WITH GRAVE -0xe1 0x00c6 # LATIN CAPITAL LETTER AE -0xe2 0x00ed # LATIN SMALL LETTER I WITH ACUTE -0xe3 0x00aa # FEMININE ORDINAL INDICATOR -0xe4 0x00ee # LATIN SMALL LETTER I WITH CIRCUMFLEX -0xe5 0x00ef # LATIN SMALL LETTER I WITH DIAERESIS -0xe6 0x00f0 # LATIN SMALL LETTER ETH -0xe7 0x00f1 # LATIN SMALL LETTER N WITH TILDE -0xe8 0x0141 # LATIN CAPITAL LETTER L WITH STROKE -0xe9 0x00d8 # LATIN CAPITAL LETTER O WITH STROKE -0xea 0x0152 # LATIN CAPITAL LIGATURE OE -0xeb 0x00ba # MASCULINE ORDINAL INDICATOR -0xec 0x00f2 # LATIN SMALL LETTER O WITH GRAVE -0xed 0x00f3 # LATIN SMALL LETTER O WITH ACUTE -0xee 0x00f4 # LATIN SMALL LETTER O WITH CIRCUMFLEX -0xef 0x00f5 # LATIN SMALL LETTER O WITH TILDE -0xf0 0x00f6 # LATIN SMALL LETTER O WITH DIAERESIS -0xf1 0x00e6 # LATIN SMALL LETTER AE -0xf2 0x00f9 # LATIN SMALL LETTER U WITH GRAVE -0xf3 0x00fa # LATIN SMALL LETTER U WITH ACUTE -0xf4 0x00fb # LATIN SMALL LETTER U WITH CIRCUMFLEX -0xf5 0x0131 # LATIN SMALL LETTER DOTLESS I -0xf6 0x00fc # LATIN SMALL LETTER U WITH DIAERESIS -0xf7 0x00fd # LATIN SMALL LETTER Y WITH ACUTE -0xf8 0x0142 # LATIN SMALL LETTER L WITH STROKE -0xf9 0x00f8 # LATIN SMALL LETTER O WITH STROKE -0xfa 0x0153 # LATIN SMALL LIGATURE OE -0xfb 0x00df # LATIN SMALL LETTER SHARP S -0xfc 0x00fe # LATIN SMALL LETTER THORN -0xfd 0x00ff # LATIN SMALL LETTER Y WITH DIAERESIS -0xfe 0xfffd # .notdef, REPLACEMENT CHARACTER -0xff 0xfffd # .notdef, REPLACEMENT CHARACTER + * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy diff --git a/src/intl/charsets/cs_sjis.h b/src/intl/charsets/cs_sjis.h index 3e7a90dfeab..588cdf2a05e 100644 --- a/src/intl/charsets/cs_sjis.h +++ b/src/intl/charsets/cs_sjis.h @@ -4,269 +4,18 @@ Unicode mapping table generated from file SHIFTJIS.TXT -# # --- This is a trunctated version of the SHIFTJIS.TXT file # --- Provided by Unicode, Inc. This version contains only # --- The shift-JIS codes in 0x80 .. 0xFF which are not also # --- part of JIS (eg: the half-width Katakana) # --- David B. Schnepper - # # Name: Shift-JIS to Unicode # Unicode version: 1.1 # Table version: 0.9 # Table format: Format A # Date: 8 March 1994 -# Authors: Glenn Adams -# John H. Jenkins -# -# -# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). -# No claims are made as to fitness for any particular purpose. No -# warranties of any kind are expressed or implied. The recipient -# agrees to determine applicability of information provided. If this -# file has been provided on magnetic media by Unicode, Inc., the sole -# remedy for any claim will be exchange of defective media within 90 -# days of receipt. -# -# Recipient is granted the right to make copies in any form for -# internal distribution and to freely use the information supplied -# in the creation of products supporting Unicode. Unicode, Inc. -# specifically excludes the right to re-distribute this file directly -# to third parties or other organizations whether for profit or not. -# -# General notes: -# -# This table contains the data the Unicode Consortium has on how -# Shift-JIS (a combination of JIS 0201 and JIS 0208) maps into Unicode. -# -# Format: Three tab-separated columns -# Column #1 is the shift-JIS code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 the Unicode name (follows a comment sign, '#') -# The official names for Unicode characters U+4E00 -# to U+9FA5, inclusive, is "CJK UNIFIED IDEOGRAPH-XXXX", -# where XXXX is the code point. Including all these -# names in this file increases its size substantially -# and needlessly. The token "" is used for the -# name of these characters. If necessary, it can be -# expanded algorithmically by a parser or editor. -# -# The entries are ordered by their Shift-JIS codes as follows: -# Single-byte characters precede double-byte characters -# The single-byte and double-byte blocks are in ascending -# hexadecimal order -# There is an alternative order some people might be preferred, -# where all the entries are in order of the top (or only) byte. -# This alternate order can be generated from the one given here -# by a simple sort. -# -# The kanji mappings are a normative part of ISO/IEC 10646. The -# non-kanji mappings are provisional, pending definition of -# official mappings by Japanese standards bodies -# -# Any comments or problems, contact -# -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #HORIZONTAL TABULATION -0x0a 0x000a #LINE FEED -0x0b 0x000b #VERTICAL TABULATION -0x0c 0x000c #FORM FEED -0x0d 0x000d #CARRIAGE RETURN -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #FILE SEPARATOR -0x1d 0x001d #GROUP SEPARATOR -0x1e 0x001e #RECORD SEPARATOR -0x1f 0x001f #UNIT SEPARATOR -# -# --- Start of actual lines from SHIFTJIS.TXT -# -0x20 0x0020 # SPACE -0x21 0x0021 # EXCLAMATION MARK -0x22 0x0022 # QUOTATION MARK -0x23 0x0023 # NUMBER SIGN -0x24 0x0024 # DOLLAR SIGN -0x25 0x0025 # PERCENT SIGN -0x26 0x0026 # AMPERSAND -0x27 0x0027 # APOSTROPHE -0x28 0x0028 # LEFT PARENTHESIS -0x29 0x0029 # RIGHT PARENTHESIS -0x2A 0x002A # ASTERISK -0x2B 0x002B # PLUS SIGN -0x2C 0x002C # COMMA -0x2D 0x002D # HYPHEN-MINUS -0x2E 0x002E # FULL STOP -0x2F 0x002F # SOLIDUS -0x30 0x0030 # DIGIT ZERO -0x31 0x0031 # DIGIT ONE -0x32 0x0032 # DIGIT TWO -0x33 0x0033 # DIGIT THREE -0x34 0x0034 # DIGIT FOUR -0x35 0x0035 # DIGIT FIVE -0x36 0x0036 # DIGIT SIX -0x37 0x0037 # DIGIT SEVEN -0x38 0x0038 # DIGIT EIGHT -0x39 0x0039 # DIGIT NINE -0x3A 0x003A # COLON -0x3B 0x003B # SEMICOLON -0x3C 0x003C # LESS-THAN SIGN -0x3D 0x003D # EQUALS SIGN -0x3E 0x003E # GREATER-THAN SIGN -0x3F 0x003F # QUESTION MARK -0x40 0x0040 # COMMERCIAL AT -0x41 0x0041 # LATIN CAPITAL LETTER A -0x42 0x0042 # LATIN CAPITAL LETTER B -0x43 0x0043 # LATIN CAPITAL LETTER C -0x44 0x0044 # LATIN CAPITAL LETTER D -0x45 0x0045 # LATIN CAPITAL LETTER E -0x46 0x0046 # LATIN CAPITAL LETTER F -0x47 0x0047 # LATIN CAPITAL LETTER G -0x48 0x0048 # LATIN CAPITAL LETTER H -0x49 0x0049 # LATIN CAPITAL LETTER I -0x4A 0x004A # LATIN CAPITAL LETTER J -0x4B 0x004B # LATIN CAPITAL LETTER K -0x4C 0x004C # LATIN CAPITAL LETTER L -0x4D 0x004D # LATIN CAPITAL LETTER M -0x4E 0x004E # LATIN CAPITAL LETTER N -0x4F 0x004F # LATIN CAPITAL LETTER O -0x50 0x0050 # LATIN CAPITAL LETTER P -0x51 0x0051 # LATIN CAPITAL LETTER Q -0x52 0x0052 # LATIN CAPITAL LETTER R -0x53 0x0053 # LATIN CAPITAL LETTER S -0x54 0x0054 # LATIN CAPITAL LETTER T -0x55 0x0055 # LATIN CAPITAL LETTER U -0x56 0x0056 # LATIN CAPITAL LETTER V -0x57 0x0057 # LATIN CAPITAL LETTER W -0x58 0x0058 # LATIN CAPITAL LETTER X -0x59 0x0059 # LATIN CAPITAL LETTER Y -0x5A 0x005A # LATIN CAPITAL LETTER Z -0x5B 0x005B # LEFT SQUARE BRACKET -0x5C 0x00A5 # YEN SIGN -0x5D 0x005D # RIGHT SQUARE BRACKET -0x5E 0x005E # CIRCUMFLEX ACCENT -0x5F 0x005F # LOW LINE -0x60 0x0060 # GRAVE ACCENT -0x61 0x0061 # LATIN SMALL LETTER A -0x62 0x0062 # LATIN SMALL LETTER B -0x63 0x0063 # LATIN SMALL LETTER C -0x64 0x0064 # LATIN SMALL LETTER D -0x65 0x0065 # LATIN SMALL LETTER E -0x66 0x0066 # LATIN SMALL LETTER F -0x67 0x0067 # LATIN SMALL LETTER G -0x68 0x0068 # LATIN SMALL LETTER H -0x69 0x0069 # LATIN SMALL LETTER I -0x6A 0x006A # LATIN SMALL LETTER J -0x6B 0x006B # LATIN SMALL LETTER K -0x6C 0x006C # LATIN SMALL LETTER L -0x6D 0x006D # LATIN SMALL LETTER M -0x6E 0x006E # LATIN SMALL LETTER N -0x6F 0x006F # LATIN SMALL LETTER O -0x70 0x0070 # LATIN SMALL LETTER P -0x71 0x0071 # LATIN SMALL LETTER Q -0x72 0x0072 # LATIN SMALL LETTER R -0x73 0x0073 # LATIN SMALL LETTER S -0x74 0x0074 # LATIN SMALL LETTER T -0x75 0x0075 # LATIN SMALL LETTER U -0x76 0x0076 # LATIN SMALL LETTER V -0x77 0x0077 # LATIN SMALL LETTER W -0x78 0x0078 # LATIN SMALL LETTER X -0x79 0x0079 # LATIN SMALL LETTER Y -0x7A 0x007A # LATIN SMALL LETTER Z -0x7B 0x007B # LEFT CURLY BRACKET -0x7C 0x007C # VERTICAL LINE -0x7D 0x007D # RIGHT CURLY BRACKET -0x7E 0x203E # OVERLINE -# -# --- Kanji mappings from SHIFTJIS.TXT removed -# -0xA1 0xFF61 # HALFWIDTH IDEOGRAPHIC FULL STOP -0xA2 0xFF62 # HALFWIDTH LEFT CORNER BRACKET -0xA3 0xFF63 # HALFWIDTH RIGHT CORNER BRACKET -0xA4 0xFF64 # HALFWIDTH IDEOGRAPHIC COMMA -0xA5 0xFF65 # HALFWIDTH KATAKANA MIDDLE DOT -0xA6 0xFF66 # HALFWIDTH KATAKANA LETTER WO -0xA7 0xFF67 # HALFWIDTH KATAKANA LETTER SMALL A -0xA8 0xFF68 # HALFWIDTH KATAKANA LETTER SMALL I -0xA9 0xFF69 # HALFWIDTH KATAKANA LETTER SMALL U -0xAA 0xFF6A # HALFWIDTH KATAKANA LETTER SMALL E -0xAB 0xFF6B # HALFWIDTH KATAKANA LETTER SMALL O -0xAC 0xFF6C # HALFWIDTH KATAKANA LETTER SMALL YA -0xAD 0xFF6D # HALFWIDTH KATAKANA LETTER SMALL YU -0xAE 0xFF6E # HALFWIDTH KATAKANA LETTER SMALL YO -0xAF 0xFF6F # HALFWIDTH KATAKANA LETTER SMALL TU -0xB0 0xFF70 # HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK -0xB1 0xFF71 # HALFWIDTH KATAKANA LETTER A -0xB2 0xFF72 # HALFWIDTH KATAKANA LETTER I -0xB3 0xFF73 # HALFWIDTH KATAKANA LETTER U -0xB4 0xFF74 # HALFWIDTH KATAKANA LETTER E -0xB5 0xFF75 # HALFWIDTH KATAKANA LETTER O -0xB6 0xFF76 # HALFWIDTH KATAKANA LETTER KA -0xB7 0xFF77 # HALFWIDTH KATAKANA LETTER KI -0xB8 0xFF78 # HALFWIDTH KATAKANA LETTER KU -0xB9 0xFF79 # HALFWIDTH KATAKANA LETTER KE -0xBA 0xFF7A # HALFWIDTH KATAKANA LETTER KO -0xBB 0xFF7B # HALFWIDTH KATAKANA LETTER SA -0xBC 0xFF7C # HALFWIDTH KATAKANA LETTER SI -0xBD 0xFF7D # HALFWIDTH KATAKANA LETTER SU -0xBE 0xFF7E # HALFWIDTH KATAKANA LETTER SE -0xBF 0xFF7F # HALFWIDTH KATAKANA LETTER SO -0xC0 0xFF80 # HALFWIDTH KATAKANA LETTER TA -0xC1 0xFF81 # HALFWIDTH KATAKANA LETTER TI -0xC2 0xFF82 # HALFWIDTH KATAKANA LETTER TU -0xC3 0xFF83 # HALFWIDTH KATAKANA LETTER TE -0xC4 0xFF84 # HALFWIDTH KATAKANA LETTER TO -0xC5 0xFF85 # HALFWIDTH KATAKANA LETTER NA -0xC6 0xFF86 # HALFWIDTH KATAKANA LETTER NI -0xC7 0xFF87 # HALFWIDTH KATAKANA LETTER NU -0xC8 0xFF88 # HALFWIDTH KATAKANA LETTER NE -0xC9 0xFF89 # HALFWIDTH KATAKANA LETTER NO -0xCA 0xFF8A # HALFWIDTH KATAKANA LETTER HA -0xCB 0xFF8B # HALFWIDTH KATAKANA LETTER HI -0xCC 0xFF8C # HALFWIDTH KATAKANA LETTER HU -0xCD 0xFF8D # HALFWIDTH KATAKANA LETTER HE -0xCE 0xFF8E # HALFWIDTH KATAKANA LETTER HO -0xCF 0xFF8F # HALFWIDTH KATAKANA LETTER MA -0xD0 0xFF90 # HALFWIDTH KATAKANA LETTER MI -0xD1 0xFF91 # HALFWIDTH KATAKANA LETTER MU -0xD2 0xFF92 # HALFWIDTH KATAKANA LETTER ME -0xD3 0xFF93 # HALFWIDTH KATAKANA LETTER MO -0xD4 0xFF94 # HALFWIDTH KATAKANA LETTER YA -0xD5 0xFF95 # HALFWIDTH KATAKANA LETTER YU -0xD6 0xFF96 # HALFWIDTH KATAKANA LETTER YO -0xD7 0xFF97 # HALFWIDTH KATAKANA LETTER RA -0xD8 0xFF98 # HALFWIDTH KATAKANA LETTER RI -0xD9 0xFF99 # HALFWIDTH KATAKANA LETTER RU -0xDA 0xFF9A # HALFWIDTH KATAKANA LETTER RE -0xDB 0xFF9B # HALFWIDTH KATAKANA LETTER RO -0xDC 0xFF9C # HALFWIDTH KATAKANA LETTER WA -0xDD 0xFF9D # HALFWIDTH KATAKANA LETTER N -0xDE 0xFF9E # HALFWIDTH KATAKANA VOICED SOUND MARK -0xDF 0xFF9F # HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK -# -# --- Kanji mappings from SHIFTJIS.TXT removed -# + * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy diff --git a/src/intl/charsets/cs_w1250.h b/src/intl/charsets/cs_w1250.h index fd2da9aca48..0adc9599ae5 100644 --- a/src/intl/charsets/cs_w1250.h +++ b/src/intl/charsets/cs_w1250.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1250 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1250 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1250 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 #UNDEFINED -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 #UNDEFINED -0x89 0x2030 #PER MILLE SIGN -0x8a 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0x8d 0x0164 #LATIN CAPITAL LETTER T WITH CARON -0x8e 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0x8f 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 #UNDEFINED -0x99 0x2122 #TRADE MARK SIGN -0x9a 0x0161 #LATIN SMALL LETTER S WITH CARON -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c 0x015b #LATIN SMALL LETTER S WITH ACUTE -0x9d 0x0165 #LATIN SMALL LETTER T WITH CARON -0x9e 0x017e #LATIN SMALL LETTER Z WITH CARON -0x9f 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x02c7 #CARON -0xa2 0x02d8 #BREVE -0xa3 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x02db #OGONEK -0xb3 0x0142 #LATIN SMALL LETTER L WITH STROKE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xba 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x013d #LATIN CAPITAL LETTER L WITH CARON -0xbd 0x02dd #DOUBLE ACUTE ACCENT -0xbe 0x013e #LATIN SMALL LETTER L WITH CARON -0xbf 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xc0 0x0154 #LATIN CAPITAL LETTER R WITH ACUTE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x0139 #LATIN CAPITAL LETTER L WITH ACUTE -0xc6 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x011a #LATIN CAPITAL LETTER E WITH CARON -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x010e #LATIN CAPITAL LETTER D WITH CARON -0xd0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE -0xd1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xd2 0x0147 #LATIN CAPITAL LETTER N WITH CARON -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x0150 #LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x0158 #LATIN CAPITAL LETTER R WITH CARON -0xd9 0x016e #LATIN CAPITAL LETTER U WITH RING ABOVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x0170 #LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xde 0x0162 #LATIN CAPITAL LETTER T WITH CEDILLA -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x0155 #LATIN SMALL LETTER R WITH ACUTE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x0103 #LATIN SMALL LETTER A WITH BREVE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x013a #LATIN SMALL LETTER L WITH ACUTE -0xe6 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x010d #LATIN SMALL LETTER C WITH CARON -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x011b #LATIN SMALL LETTER E WITH CARON -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x010f #LATIN SMALL LETTER D WITH CARON -0xf0 0x0111 #LATIN SMALL LETTER D WITH STROKE -0xf1 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xf2 0x0148 #LATIN SMALL LETTER N WITH CARON -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x0151 #LATIN SMALL LETTER O WITH DOUBLE ACUTE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x0159 #LATIN SMALL LETTER R WITH CARON -0xf9 0x016f #LATIN SMALL LETTER U WITH RING ABOVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x0171 #LATIN SMALL LETTER U WITH DOUBLE ACUTE -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xfe 0x0163 #LATIN SMALL LETTER T WITH CEDILLA -0xff 0x02d9 #DOT ABOVE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1251.h b/src/intl/charsets/cs_w1251.h index d4e8457c42d..f4cae816be9 100644 --- a/src/intl/charsets/cs_w1251.h +++ b/src/intl/charsets/cs_w1251.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1251 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1251 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1251 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x0402 #CYRILLIC CAPITAL LETTER DJE -0x81 0x0403 #CYRILLIC CAPITAL LETTER GJE -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0453 #CYRILLIC SMALL LETTER GJE -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x20ac #EURO SIGN -0x89 0x2030 #PER MILLE SIGN -0x8a 0x0409 #CYRILLIC CAPITAL LETTER LJE -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c 0x040a #CYRILLIC CAPITAL LETTER NJE -0x8d 0x040c #CYRILLIC CAPITAL LETTER KJE -0x8e 0x040b #CYRILLIC CAPITAL LETTER TSHE -0x8f 0x040f #CYRILLIC CAPITAL LETTER DZHE -0x90 0x0452 #CYRILLIC SMALL LETTER DJE -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 #UNDEFINED -0x99 0x2122 #TRADE MARK SIGN -0x9a 0x0459 #CYRILLIC SMALL LETTER LJE -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c 0x045a #CYRILLIC SMALL LETTER NJE -0x9d 0x045c #CYRILLIC SMALL LETTER KJE -0x9e 0x045b #CYRILLIC SMALL LETTER TSHE -0x9f 0x045f #CYRILLIC SMALL LETTER DZHE -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x040e #CYRILLIC CAPITAL LETTER SHORT U -0xa2 0x045e #CYRILLIC SMALL LETTER SHORT U -0xa3 0x0408 #CYRILLIC CAPITAL LETTER JE -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x0490 #CYRILLIC CAPITAL LETTER GHE WITH UPTURN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x0401 #CYRILLIC CAPITAL LETTER IO -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x0407 #CYRILLIC CAPITAL LETTER YI -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x0406 #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -0xb3 0x0456 #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -0xb4 0x0491 #CYRILLIC SMALL LETTER GHE WITH UPTURN -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x0451 #CYRILLIC SMALL LETTER IO -0xb9 0x2116 #NUMERO SIGN -0xba 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x0458 #CYRILLIC SMALL LETTER JE -0xbd 0x0405 #CYRILLIC CAPITAL LETTER DZE -0xbe 0x0455 #CYRILLIC SMALL LETTER DZE -0xbf 0x0457 #CYRILLIC SMALL LETTER YI -0xc0 0x0410 #CYRILLIC CAPITAL LETTER A -0xc1 0x0411 #CYRILLIC CAPITAL LETTER BE -0xc2 0x0412 #CYRILLIC CAPITAL LETTER VE -0xc3 0x0413 #CYRILLIC CAPITAL LETTER GHE -0xc4 0x0414 #CYRILLIC CAPITAL LETTER DE -0xc5 0x0415 #CYRILLIC CAPITAL LETTER IE -0xc6 0x0416 #CYRILLIC CAPITAL LETTER ZHE -0xc7 0x0417 #CYRILLIC CAPITAL LETTER ZE -0xc8 0x0418 #CYRILLIC CAPITAL LETTER I -0xc9 0x0419 #CYRILLIC CAPITAL LETTER SHORT I -0xca 0x041a #CYRILLIC CAPITAL LETTER KA -0xcb 0x041b #CYRILLIC CAPITAL LETTER EL -0xcc 0x041c #CYRILLIC CAPITAL LETTER EM -0xcd 0x041d #CYRILLIC CAPITAL LETTER EN -0xce 0x041e #CYRILLIC CAPITAL LETTER O -0xcf 0x041f #CYRILLIC CAPITAL LETTER PE -0xd0 0x0420 #CYRILLIC CAPITAL LETTER ER -0xd1 0x0421 #CYRILLIC CAPITAL LETTER ES -0xd2 0x0422 #CYRILLIC CAPITAL LETTER TE -0xd3 0x0423 #CYRILLIC CAPITAL LETTER U -0xd4 0x0424 #CYRILLIC CAPITAL LETTER EF -0xd5 0x0425 #CYRILLIC CAPITAL LETTER HA -0xd6 0x0426 #CYRILLIC CAPITAL LETTER TSE -0xd7 0x0427 #CYRILLIC CAPITAL LETTER CHE -0xd8 0x0428 #CYRILLIC CAPITAL LETTER SHA -0xd9 0x0429 #CYRILLIC CAPITAL LETTER SHCHA -0xda 0x042a #CYRILLIC CAPITAL LETTER HARD SIGN -0xdb 0x042b #CYRILLIC CAPITAL LETTER YERU -0xdc 0x042c #CYRILLIC CAPITAL LETTER SOFT SIGN -0xdd 0x042d #CYRILLIC CAPITAL LETTER E -0xde 0x042e #CYRILLIC CAPITAL LETTER YU -0xdf 0x042f #CYRILLIC CAPITAL LETTER YA -0xe0 0x0430 #CYRILLIC SMALL LETTER A -0xe1 0x0431 #CYRILLIC SMALL LETTER BE -0xe2 0x0432 #CYRILLIC SMALL LETTER VE -0xe3 0x0433 #CYRILLIC SMALL LETTER GHE -0xe4 0x0434 #CYRILLIC SMALL LETTER DE -0xe5 0x0435 #CYRILLIC SMALL LETTER IE -0xe6 0x0436 #CYRILLIC SMALL LETTER ZHE -0xe7 0x0437 #CYRILLIC SMALL LETTER ZE -0xe8 0x0438 #CYRILLIC SMALL LETTER I -0xe9 0x0439 #CYRILLIC SMALL LETTER SHORT I -0xea 0x043a #CYRILLIC SMALL LETTER KA -0xeb 0x043b #CYRILLIC SMALL LETTER EL -0xec 0x043c #CYRILLIC SMALL LETTER EM -0xed 0x043d #CYRILLIC SMALL LETTER EN -0xee 0x043e #CYRILLIC SMALL LETTER O -0xef 0x043f #CYRILLIC SMALL LETTER PE -0xf0 0x0440 #CYRILLIC SMALL LETTER ER -0xf1 0x0441 #CYRILLIC SMALL LETTER ES -0xf2 0x0442 #CYRILLIC SMALL LETTER TE -0xf3 0x0443 #CYRILLIC SMALL LETTER U -0xf4 0x0444 #CYRILLIC SMALL LETTER EF -0xf5 0x0445 #CYRILLIC SMALL LETTER HA -0xf6 0x0446 #CYRILLIC SMALL LETTER TSE -0xf7 0x0447 #CYRILLIC SMALL LETTER CHE -0xf8 0x0448 #CYRILLIC SMALL LETTER SHA -0xf9 0x0449 #CYRILLIC SMALL LETTER SHCHA -0xfa 0x044a #CYRILLIC SMALL LETTER HARD SIGN -0xfb 0x044b #CYRILLIC SMALL LETTER YERU -0xfc 0x044c #CYRILLIC SMALL LETTER SOFT SIGN -0xfd 0x044d #CYRILLIC SMALL LETTER E -0xfe 0x044e #CYRILLIC SMALL LETTER YU -0xff 0x044f #CYRILLIC SMALL LETTER YA - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1252.h b/src/intl/charsets/cs_w1252.h index b24b3bfdfac..0b76230915e 100644 --- a/src/intl/charsets/cs_w1252.h +++ b/src/intl/charsets/cs_w1252.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1252 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1252 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1252 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x02c6 #MODIFIER LETTER CIRCUMFLEX ACCENT -0x89 0x2030 #PER MILLE SIGN -0x8a 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c 0x0152 #LATIN CAPITAL LIGATURE OE -0x8d #UNDEFINED -0x8e 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0x8f #UNDEFINED -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 0x02dc #SMALL TILDE -0x99 0x2122 #TRADE MARK SIGN -0x9a 0x0161 #LATIN SMALL LETTER S WITH CARON -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c 0x0153 #LATIN SMALL LIGATURE OE -0x9d #UNDEFINED -0x9e 0x017e #LATIN SMALL LETTER Z WITH CARON -0x9f 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00a1 #INVERTED EXCLAMATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00aa #FEMININE ORDINAL INDICATOR -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00ba #MASCULINE ORDINAL INDICATOR -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00bf #INVERTED QUESTION MARK -0xc0 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x00c6 #LATIN CAPITAL LETTER AE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd0 0x00d0 #LATIN CAPITAL LETTER ETH -0xd1 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xd2 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xd9 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x00dd #LATIN CAPITAL LETTER Y WITH ACUTE -0xde 0x00de #LATIN CAPITAL LETTER THORN -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x00e6 #LATIN SMALL LETTER AE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 0x00f0 #LATIN SMALL LETTER ETH -0xf1 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xf2 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x00fd #LATIN SMALL LETTER Y WITH ACUTE -0xfe 0x00fe #LATIN SMALL LETTER THORN -0xff 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1253.h b/src/intl/charsets/cs_w1253.h index 60ba9e1ba5b..450b36298f9 100644 --- a/src/intl/charsets/cs_w1253.h +++ b/src/intl/charsets/cs_w1253.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1253 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1253 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1253 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 #UNDEFINED -0x89 0x2030 #PER MILLE SIGN -0x8a #UNDEFINED -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c #UNDEFINED -0x8d #UNDEFINED -0x8e #UNDEFINED -0x8f #UNDEFINED -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 #UNDEFINED -0x99 0x2122 #TRADE MARK SIGN -0x9a #UNDEFINED -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c #UNDEFINED -0x9d #UNDEFINED -0x9e #UNDEFINED -0x9f #UNDEFINED -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x0385 #GREEK DIALYTIKA TONOS -0xa2 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa #UNDEFINED -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x2015 #HORIZONTAL BAR -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x0384 #GREEK TONOS -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS -0xb9 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS -0xba 0x038a #GREEK CAPITAL LETTER IOTA WITH TONOS -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x038c #GREEK CAPITAL LETTER OMICRON WITH TONOS -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x038e #GREEK CAPITAL LETTER UPSILON WITH TONOS -0xbf 0x038f #GREEK CAPITAL LETTER OMEGA WITH TONOS -0xc0 0x0390 #GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -0xc1 0x0391 #GREEK CAPITAL LETTER ALPHA -0xc2 0x0392 #GREEK CAPITAL LETTER BETA -0xc3 0x0393 #GREEK CAPITAL LETTER GAMMA -0xc4 0x0394 #GREEK CAPITAL LETTER DELTA -0xc5 0x0395 #GREEK CAPITAL LETTER EPSILON -0xc6 0x0396 #GREEK CAPITAL LETTER ZETA -0xc7 0x0397 #GREEK CAPITAL LETTER ETA -0xc8 0x0398 #GREEK CAPITAL LETTER THETA -0xc9 0x0399 #GREEK CAPITAL LETTER IOTA -0xca 0x039a #GREEK CAPITAL LETTER KAPPA -0xcb 0x039b #GREEK CAPITAL LETTER LAMDA -0xcc 0x039c #GREEK CAPITAL LETTER MU -0xcd 0x039d #GREEK CAPITAL LETTER NU -0xce 0x039e #GREEK CAPITAL LETTER XI -0xcf 0x039f #GREEK CAPITAL LETTER OMICRON -0xd0 0x03a0 #GREEK CAPITAL LETTER PI -0xd1 0x03a1 #GREEK CAPITAL LETTER RHO -0xd2 #UNDEFINED -0xd3 0x03a3 #GREEK CAPITAL LETTER SIGMA -0xd4 0x03a4 #GREEK CAPITAL LETTER TAU -0xd5 0x03a5 #GREEK CAPITAL LETTER UPSILON -0xd6 0x03a6 #GREEK CAPITAL LETTER PHI -0xd7 0x03a7 #GREEK CAPITAL LETTER CHI -0xd8 0x03a8 #GREEK CAPITAL LETTER PSI -0xd9 0x03a9 #GREEK CAPITAL LETTER OMEGA -0xda 0x03aa #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -0xdb 0x03ab #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -0xdc 0x03ac #GREEK SMALL LETTER ALPHA WITH TONOS -0xdd 0x03ad #GREEK SMALL LETTER EPSILON WITH TONOS -0xde 0x03ae #GREEK SMALL LETTER ETA WITH TONOS -0xdf 0x03af #GREEK SMALL LETTER IOTA WITH TONOS -0xe0 0x03b0 #GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -0xe1 0x03b1 #GREEK SMALL LETTER ALPHA -0xe2 0x03b2 #GREEK SMALL LETTER BETA -0xe3 0x03b3 #GREEK SMALL LETTER GAMMA -0xe4 0x03b4 #GREEK SMALL LETTER DELTA -0xe5 0x03b5 #GREEK SMALL LETTER EPSILON -0xe6 0x03b6 #GREEK SMALL LETTER ZETA -0xe7 0x03b7 #GREEK SMALL LETTER ETA -0xe8 0x03b8 #GREEK SMALL LETTER THETA -0xe9 0x03b9 #GREEK SMALL LETTER IOTA -0xea 0x03ba #GREEK SMALL LETTER KAPPA -0xeb 0x03bb #GREEK SMALL LETTER LAMDA -0xec 0x03bc #GREEK SMALL LETTER MU -0xed 0x03bd #GREEK SMALL LETTER NU -0xee 0x03be #GREEK SMALL LETTER XI -0xef 0x03bf #GREEK SMALL LETTER OMICRON -0xf0 0x03c0 #GREEK SMALL LETTER PI -0xf1 0x03c1 #GREEK SMALL LETTER RHO -0xf2 0x03c2 #GREEK SMALL LETTER FINAL SIGMA -0xf3 0x03c3 #GREEK SMALL LETTER SIGMA -0xf4 0x03c4 #GREEK SMALL LETTER TAU -0xf5 0x03c5 #GREEK SMALL LETTER UPSILON -0xf6 0x03c6 #GREEK SMALL LETTER PHI -0xf7 0x03c7 #GREEK SMALL LETTER CHI -0xf8 0x03c8 #GREEK SMALL LETTER PSI -0xf9 0x03c9 #GREEK SMALL LETTER OMEGA -0xfa 0x03ca #GREEK SMALL LETTER IOTA WITH DIALYTIKA -0xfb 0x03cb #GREEK SMALL LETTER UPSILON WITH DIALYTIKA -0xfc 0x03cc #GREEK SMALL LETTER OMICRON WITH TONOS -0xfd 0x03cd #GREEK SMALL LETTER UPSILON WITH TONOS -0xfe 0x03ce #GREEK SMALL LETTER OMEGA WITH TONOS -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1254.h b/src/intl/charsets/cs_w1254.h index 8413b256522..a5ea7ff1b78 100644 --- a/src/intl/charsets/cs_w1254.h +++ b/src/intl/charsets/cs_w1254.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1254 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1254 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1254 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x02c6 #MODIFIER LETTER CIRCUMFLEX ACCENT -0x89 0x2030 #PER MILLE SIGN -0x8a 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c 0x0152 #LATIN CAPITAL LIGATURE OE -0x8d #UNDEFINED -0x8e #UNDEFINED -0x8f #UNDEFINED -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 0x02dc #SMALL TILDE -0x99 0x2122 #TRADE MARK SIGN -0x9a 0x0161 #LATIN SMALL LETTER S WITH CARON -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c 0x0153 #LATIN SMALL LIGATURE OE -0x9d #UNDEFINED -0x9e #UNDEFINED -0x9f 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00a1 #INVERTED EXCLAMATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00aa #FEMININE ORDINAL INDICATOR -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00ba #MASCULINE ORDINAL INDICATOR -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00bf #INVERTED QUESTION MARK -0xc0 0x00c0 #LATIN CAPITAL LETTER A WITH GRAVE -0xc1 0x00c1 #LATIN CAPITAL LETTER A WITH ACUTE -0xc2 0x00c2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xc3 0x00c3 #LATIN CAPITAL LETTER A WITH TILDE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x00c6 #LATIN CAPITAL LETTER AE -0xc7 0x00c7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xc8 0x00c8 #LATIN CAPITAL LETTER E WITH GRAVE -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x00ca #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xcb 0x00cb #LATIN CAPITAL LETTER E WITH DIAERESIS -0xcc 0x00cc #LATIN CAPITAL LETTER I WITH GRAVE -0xcd 0x00cd #LATIN CAPITAL LETTER I WITH ACUTE -0xce 0x00ce #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xcf 0x00cf #LATIN CAPITAL LETTER I WITH DIAERESIS -0xd0 0x011e #LATIN CAPITAL LETTER G WITH BREVE -0xd1 0x00d1 #LATIN CAPITAL LETTER N WITH TILDE -0xd2 0x00d2 #LATIN CAPITAL LETTER O WITH GRAVE -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x00d4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xd9 0x00d9 #LATIN CAPITAL LETTER U WITH GRAVE -0xda 0x00da #LATIN CAPITAL LETTER U WITH ACUTE -0xdb 0x00db #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE -0xde 0x015e #LATIN CAPITAL LETTER S WITH CEDILLA -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x00e1 #LATIN SMALL LETTER A WITH ACUTE -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x00e3 #LATIN SMALL LETTER A WITH TILDE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x00e6 #LATIN SMALL LETTER AE -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x00ec #LATIN SMALL LETTER I WITH GRAVE -0xed 0x00ed #LATIN SMALL LETTER I WITH ACUTE -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 0x011f #LATIN SMALL LETTER G WITH BREVE -0xf1 0x00f1 #LATIN SMALL LETTER N WITH TILDE -0xf2 0x00f2 #LATIN SMALL LETTER O WITH GRAVE -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x00fa #LATIN SMALL LETTER U WITH ACUTE -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x0131 #LATIN SMALL LETTER DOTLESS I -0xfe 0x015f #LATIN SMALL LETTER S WITH CEDILLA -0xff 0x00ff #LATIN SMALL LETTER Y WITH DIAERESIS - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1255.h b/src/intl/charsets/cs_w1255.h index 9c38172bf87..af5485d723d 100644 --- a/src/intl/charsets/cs_w1255.h +++ b/src/intl/charsets/cs_w1255.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1255 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1255 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1255 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x02c6 #MODIFIER LETTER CIRCUMFLEX ACCENT -0x89 0x2030 #PER MILLE SIGN -0x8a #UNDEFINED -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c #UNDEFINED -0x8d #UNDEFINED -0x8e #UNDEFINED -0x8f #UNDEFINED -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 0x02dc #SMALL TILDE -0x99 0x2122 #TRADE MARK SIGN -0x9a #UNDEFINED -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c #UNDEFINED -0x9d #UNDEFINED -0x9e #UNDEFINED -0x9f #UNDEFINED -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x00a1 #INVERTED EXCLAMATION MARK -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x20aa #NEW SHEQEL SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x00d7 #MULTIPLICATION SIGN -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x00f7 #DIVISION SIGN -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00bf #INVERTED QUESTION MARK -0xc0 0x05b0 #HEBREW POINT SHEVA -0xc1 0x05b1 #HEBREW POINT HATAF SEGOL -0xc2 0x05b2 #HEBREW POINT HATAF PATAH -0xc3 0x05b3 #HEBREW POINT HATAF QAMATS -0xc4 0x05b4 #HEBREW POINT HIRIQ -0xc5 0x05b5 #HEBREW POINT TSERE -0xc6 0x05b6 #HEBREW POINT SEGOL -0xc7 0x05b7 #HEBREW POINT PATAH -0xc8 0x05b8 #HEBREW POINT QAMATS -0xc9 0x05b9 #HEBREW POINT HOLAM -0xca #UNDEFINED -0xcb 0x05bb #HEBREW POINT QUBUTS -0xcc 0x05bc #HEBREW POINT DAGESH OR MAPIQ -0xcd 0x05bd #HEBREW POINT METEG -0xce 0x05be #HEBREW PUNCTUATION MAQAF -0xcf 0x05bf #HEBREW POINT RAFE -0xd0 0x05c0 #HEBREW PUNCTUATION PASEQ -0xd1 0x05c1 #HEBREW POINT SHIN DOT -0xd2 0x05c2 #HEBREW POINT SIN DOT -0xd3 0x05c3 #HEBREW PUNCTUATION SOF PASUQ -0xd4 0x05f0 #HEBREW LIGATURE YIDDISH DOUBLE VAV -0xd5 0x05f1 #HEBREW LIGATURE YIDDISH VAV YOD -0xd6 0x05f2 #HEBREW LIGATURE YIDDISH DOUBLE YOD -0xd7 0x05f3 #HEBREW PUNCTUATION GERESH -0xd8 0x05f4 #HEBREW PUNCTUATION GERSHAYIM -0xd9 #UNDEFINED -0xda #UNDEFINED -0xdb #UNDEFINED -0xdc #UNDEFINED -0xdd #UNDEFINED -0xde #UNDEFINED -0xdf #UNDEFINED -0xe0 0x05d0 #HEBREW LETTER ALEF -0xe1 0x05d1 #HEBREW LETTER BET -0xe2 0x05d2 #HEBREW LETTER GIMEL -0xe3 0x05d3 #HEBREW LETTER DALET -0xe4 0x05d4 #HEBREW LETTER HE -0xe5 0x05d5 #HEBREW LETTER VAV -0xe6 0x05d6 #HEBREW LETTER ZAYIN -0xe7 0x05d7 #HEBREW LETTER HET -0xe8 0x05d8 #HEBREW LETTER TET -0xe9 0x05d9 #HEBREW LETTER YOD -0xea 0x05da #HEBREW LETTER FINAL KAF -0xeb 0x05db #HEBREW LETTER KAF -0xec 0x05dc #HEBREW LETTER LAMED -0xed 0x05dd #HEBREW LETTER FINAL MEM -0xee 0x05de #HEBREW LETTER MEM -0xef 0x05df #HEBREW LETTER FINAL NUN -0xf0 0x05e0 #HEBREW LETTER NUN -0xf1 0x05e1 #HEBREW LETTER SAMEKH -0xf2 0x05e2 #HEBREW LETTER AYIN -0xf3 0x05e3 #HEBREW LETTER FINAL PE -0xf4 0x05e4 #HEBREW LETTER PE -0xf5 0x05e5 #HEBREW LETTER FINAL TSADI -0xf6 0x05e6 #HEBREW LETTER TSADI -0xf7 0x05e7 #HEBREW LETTER QOF -0xf8 0x05e8 #HEBREW LETTER RESH -0xf9 0x05e9 #HEBREW LETTER SHIN -0xfa 0x05ea #HEBREW LETTER TAV -0xfb #UNDEFINED -0xfc #UNDEFINED -0xfd 0x200e #LEFT-TO-RIGHT MARK -0xfe 0x200f #RIGHT-TO-LEFT MARK -0xff #UNDEFINED - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1256.h b/src/intl/charsets/cs_w1256.h index 485115a3cc1..7108ee9f6ac 100644 --- a/src/intl/charsets/cs_w1256.h +++ b/src/intl/charsets/cs_w1256.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1256 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1256 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1256 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 0x067e #ARABIC LETTER PEH -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x02c6 #MODIFIER LETTER CIRCUMFLEX ACCENT -0x89 0x2030 #PER MILLE SIGN -0x8a 0x0679 #ARABIC LETTER TTEH -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c 0x0152 #LATIN CAPITAL LIGATURE OE -0x8d 0x0686 #ARABIC LETTER TCHEH -0x8e 0x0698 #ARABIC LETTER JEH -0x8f 0x0688 #ARABIC LETTER DDAL -0x90 0x06af #ARABIC LETTER GAF -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 0x06a9 #ARABIC LETTER KEHEH -0x99 0x2122 #TRADE MARK SIGN -0x9a 0x0691 #ARABIC LETTER RREH -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c 0x0153 #LATIN SMALL LIGATURE OE -0x9d 0x200c #ZERO WIDTH NON-JOINER -0x9e 0x200d #ZERO WIDTH JOINER -0x9f 0x06ba #ARABIC LETTER NOON GHUNNA -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 0x060c #ARABIC COMMA -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 0x00a5 #YEN SIGN -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00a8 #DIAERESIS -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x06be #ARABIC LETTER HEH DOACHASHMEE -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00af #MACRON -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00b8 #CEDILLA -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x061b #ARABIC SEMICOLON -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x061f #ARABIC QUESTION MARK -0xc0 0x06c1 #ARABIC LETTER HEH GOAL -0xc1 0x0621 #ARABIC LETTER HAMZA -0xc2 0x0622 #ARABIC LETTER ALEF WITH MADDA ABOVE -0xc3 0x0623 #ARABIC LETTER ALEF WITH HAMZA ABOVE -0xc4 0x0624 #ARABIC LETTER WAW WITH HAMZA ABOVE -0xc5 0x0625 #ARABIC LETTER ALEF WITH HAMZA BELOW -0xc6 0x0626 #ARABIC LETTER YEH WITH HAMZA ABOVE -0xc7 0x0627 #ARABIC LETTER ALEF -0xc8 0x0628 #ARABIC LETTER BEH -0xc9 0x0629 #ARABIC LETTER TEH MARBUTA -0xca 0x062a #ARABIC LETTER TEH -0xcb 0x062b #ARABIC LETTER THEH -0xcc 0x062c #ARABIC LETTER JEEM -0xcd 0x062d #ARABIC LETTER HAH -0xce 0x062e #ARABIC LETTER KHAH -0xcf 0x062f #ARABIC LETTER DAL -0xd0 0x0630 #ARABIC LETTER THAL -0xd1 0x0631 #ARABIC LETTER REH -0xd2 0x0632 #ARABIC LETTER ZAIN -0xd3 0x0633 #ARABIC LETTER SEEN -0xd4 0x0634 #ARABIC LETTER SHEEN -0xd5 0x0635 #ARABIC LETTER SAD -0xd6 0x0636 #ARABIC LETTER DAD -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x0637 #ARABIC LETTER TAH -0xd9 0x0638 #ARABIC LETTER ZAH -0xda 0x0639 #ARABIC LETTER AIN -0xdb 0x063a #ARABIC LETTER GHAIN -0xdc 0x0640 #ARABIC TATWEEL -0xdd 0x0641 #ARABIC LETTER FEH -0xde 0x0642 #ARABIC LETTER QAF -0xdf 0x0643 #ARABIC LETTER KAF -0xe0 0x00e0 #LATIN SMALL LETTER A WITH GRAVE -0xe1 0x0644 #ARABIC LETTER LAM -0xe2 0x00e2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xe3 0x0645 #ARABIC LETTER MEEM -0xe4 0x0646 #ARABIC LETTER NOON -0xe5 0x0647 #ARABIC LETTER HEH -0xe6 0x0648 #ARABIC LETTER WAW -0xe7 0x00e7 #LATIN SMALL LETTER C WITH CEDILLA -0xe8 0x00e8 #LATIN SMALL LETTER E WITH GRAVE -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x00ea #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xeb 0x00eb #LATIN SMALL LETTER E WITH DIAERESIS -0xec 0x0649 #ARABIC LETTER ALEF MAKSURA -0xed 0x064a #ARABIC LETTER YEH -0xee 0x00ee #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xef 0x00ef #LATIN SMALL LETTER I WITH DIAERESIS -0xf0 0x064b #ARABIC FATHATAN -0xf1 0x064c #ARABIC DAMMATAN -0xf2 0x064d #ARABIC KASRATAN -0xf3 0x064e #ARABIC FATHA -0xf4 0x00f4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xf5 0x064f #ARABIC DAMMA -0xf6 0x0650 #ARABIC KASRA -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x0651 #ARABIC SHADDA -0xf9 0x00f9 #LATIN SMALL LETTER U WITH GRAVE -0xfa 0x0652 #ARABIC SUKUN -0xfb 0x00fb #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x200e #LEFT-TO-RIGHT MARK -0xfe 0x200f #RIGHT-TO-LEFT MARK -0xff 0x06d2 #ARABIC LETTER YEH BARREE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1257.h b/src/intl/charsets/cs_w1257.h index adcb1892178..34426a3025c 100644 --- a/src/intl/charsets/cs_w1257.h +++ b/src/intl/charsets/cs_w1257.h @@ -3,274 +3,8 @@ Unicode mapping table generated from java mapping and UnicodeData.txt -# # Name: Cp1257 to Unicode table # Unicode version: Java 1.3 -# -# Format: Three tab-separated columns -# Column #1 is the Cp1257 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in Cp1257 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #CHARACTER TABULATION -0x0a 0x000a #LINE FEED (LF) -0x0b 0x000b #LINE TABULATION -0x0c 0x000c #FORM FEED (FF) -0x0d 0x000d #CARRIAGE RETURN (CR) -0x0e 0x000e #SHIFT OUT -0x0f 0x000f #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1a 0x001a #SUBSTITUTE -0x1b 0x001b #ESCAPE -0x1c 0x001c #INFORMATION SEPARATOR FOUR -0x1d 0x001d #INFORMATION SEPARATOR THREE -0x1e 0x001e #INFORMATION SEPARATOR TWO -0x1f 0x001f #INFORMATION SEPARATOR ONE -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2a 0x002a #ASTERISK -0x2b 0x002b #PLUS SIGN -0x2c 0x002c #COMMA -0x2d 0x002d #HYPHEN-MINUS -0x2e 0x002e #FULL STOP -0x2f 0x002f #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3a 0x003a #COLON -0x3b 0x003b #SEMICOLON -0x3c 0x003c #LESS-THAN SIGN -0x3d 0x003d #EQUALS SIGN -0x3e 0x003e #GREATER-THAN SIGN -0x3f 0x003f #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4a 0x004a #LATIN CAPITAL LETTER J -0x4b 0x004b #LATIN CAPITAL LETTER K -0x4c 0x004c #LATIN CAPITAL LETTER L -0x4d 0x004d #LATIN CAPITAL LETTER M -0x4e 0x004e #LATIN CAPITAL LETTER N -0x4f 0x004f #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5a 0x005a #LATIN CAPITAL LETTER Z -0x5b 0x005b #LEFT SQUARE BRACKET -0x5c 0x005c #REVERSE SOLIDUS -0x5d 0x005d #RIGHT SQUARE BRACKET -0x5e 0x005e #CIRCUMFLEX ACCENT -0x5f 0x005f #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6a 0x006a #LATIN SMALL LETTER J -0x6b 0x006b #LATIN SMALL LETTER K -0x6c 0x006c #LATIN SMALL LETTER L -0x6d 0x006d #LATIN SMALL LETTER M -0x6e 0x006e #LATIN SMALL LETTER N -0x6f 0x006f #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7a 0x007a #LATIN SMALL LETTER Z -0x7b 0x007b #LEFT CURLY BRACKET -0x7c 0x007c #VERTICAL LINE -0x7d 0x007d #RIGHT CURLY BRACKET -0x7e 0x007e #TILDE -0x7f 0x007f #DELETE -0x80 0x20ac #EURO SIGN -0x81 #UNDEFINED -0x82 0x201a #SINGLE LOW-9 QUOTATION MARK -0x83 #UNDEFINED -0x84 0x201e #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 #UNDEFINED -0x89 0x2030 #PER MILLE SIGN -0x8a #UNDEFINED -0x8b 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8c #UNDEFINED -0x8d 0x00a8 #DIAERESIS -0x8e 0x02c7 #CARON -0x8f 0x00b8 #CEDILLA -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201c #LEFT DOUBLE QUOTATION MARK -0x94 0x201d #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 #UNDEFINED -0x99 0x2122 #TRADE MARK SIGN -0x9a #UNDEFINED -0x9b 0x203a #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9c #UNDEFINED -0x9d 0x00af #MACRON -0x9e 0x02db #OGONEK -0x9f #UNDEFINED -0xa0 0x00a0 #NO-BREAK SPACE -0xa1 #UNDEFINED -0xa2 0x00a2 #CENT SIGN -0xa3 0x00a3 #POUND SIGN -0xa4 0x00a4 #CURRENCY SIGN -0xa5 #UNDEFINED -0xa6 0x00a6 #BROKEN BAR -0xa7 0x00a7 #SECTION SIGN -0xa8 0x00d8 #LATIN CAPITAL LETTER O WITH STROKE -0xa9 0x00a9 #COPYRIGHT SIGN -0xaa 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA -0xab 0x00ab #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xac 0x00ac #NOT SIGN -0xad 0x00ad #SOFT HYPHEN -0xae 0x00ae #REGISTERED SIGN -0xaf 0x00c6 #LATIN CAPITAL LETTER AE -0xb0 0x00b0 #DEGREE SIGN -0xb1 0x00b1 #PLUS-MINUS SIGN -0xb2 0x00b2 #SUPERSCRIPT TWO -0xb3 0x00b3 #SUPERSCRIPT THREE -0xb4 0x00b4 #ACUTE ACCENT -0xb5 0x00b5 #MICRO SIGN -0xb6 0x00b6 #PILCROW SIGN -0xb7 0x00b7 #MIDDLE DOT -0xb8 0x00f8 #LATIN SMALL LETTER O WITH STROKE -0xb9 0x00b9 #SUPERSCRIPT ONE -0xba 0x0157 #LATIN SMALL LETTER R WITH CEDILLA -0xbb 0x00bb #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xbc 0x00bc #VULGAR FRACTION ONE QUARTER -0xbd 0x00bd #VULGAR FRACTION ONE HALF -0xbe 0x00be #VULGAR FRACTION THREE QUARTERS -0xbf 0x00e6 #LATIN SMALL LETTER AE -0xc0 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK -0xc1 0x012e #LATIN CAPITAL LETTER I WITH OGONEK -0xc2 0x0100 #LATIN CAPITAL LETTER A WITH MACRON -0xc3 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE -0xc4 0x00c4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xc5 0x00c5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xc6 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK -0xc7 0x0112 #LATIN CAPITAL LETTER E WITH MACRON -0xc8 0x010c #LATIN CAPITAL LETTER C WITH CARON -0xc9 0x00c9 #LATIN CAPITAL LETTER E WITH ACUTE -0xca 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE -0xcb 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE -0xcc 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA -0xcd 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA -0xce 0x012a #LATIN CAPITAL LETTER I WITH MACRON -0xcf 0x013b #LATIN CAPITAL LETTER L WITH CEDILLA -0xd0 0x0160 #LATIN CAPITAL LETTER S WITH CARON -0xd1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE -0xd2 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA -0xd3 0x00d3 #LATIN CAPITAL LETTER O WITH ACUTE -0xd4 0x014c #LATIN CAPITAL LETTER O WITH MACRON -0xd5 0x00d5 #LATIN CAPITAL LETTER O WITH TILDE -0xd6 0x00d6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xd7 0x00d7 #MULTIPLICATION SIGN -0xd8 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK -0xd9 0x0141 #LATIN CAPITAL LETTER L WITH STROKE -0xda 0x015a #LATIN CAPITAL LETTER S WITH ACUTE -0xdb 0x016a #LATIN CAPITAL LETTER U WITH MACRON -0xdc 0x00dc #LATIN CAPITAL LETTER U WITH DIAERESIS -0xdd 0x017b #LATIN CAPITAL LETTER Z WITH DOT ABOVE -0xde 0x017d #LATIN CAPITAL LETTER Z WITH CARON -0xdf 0x00df #LATIN SMALL LETTER SHARP S -0xe0 0x0105 #LATIN SMALL LETTER A WITH OGONEK -0xe1 0x012f #LATIN SMALL LETTER I WITH OGONEK -0xe2 0x0101 #LATIN SMALL LETTER A WITH MACRON -0xe3 0x0107 #LATIN SMALL LETTER C WITH ACUTE -0xe4 0x00e4 #LATIN SMALL LETTER A WITH DIAERESIS -0xe5 0x00e5 #LATIN SMALL LETTER A WITH RING ABOVE -0xe6 0x0119 #LATIN SMALL LETTER E WITH OGONEK -0xe7 0x0113 #LATIN SMALL LETTER E WITH MACRON -0xe8 0x010d #LATIN SMALL LETTER C WITH CARON -0xe9 0x00e9 #LATIN SMALL LETTER E WITH ACUTE -0xea 0x017a #LATIN SMALL LETTER Z WITH ACUTE -0xeb 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE -0xec 0x0123 #LATIN SMALL LETTER G WITH CEDILLA -0xed 0x0137 #LATIN SMALL LETTER K WITH CEDILLA -0xee 0x012b #LATIN SMALL LETTER I WITH MACRON -0xef 0x013c #LATIN SMALL LETTER L WITH CEDILLA -0xf0 0x0161 #LATIN SMALL LETTER S WITH CARON -0xf1 0x0144 #LATIN SMALL LETTER N WITH ACUTE -0xf2 0x0146 #LATIN SMALL LETTER N WITH CEDILLA -0xf3 0x00f3 #LATIN SMALL LETTER O WITH ACUTE -0xf4 0x014d #LATIN SMALL LETTER O WITH MACRON -0xf5 0x00f5 #LATIN SMALL LETTER O WITH TILDE -0xf6 0x00f6 #LATIN SMALL LETTER O WITH DIAERESIS -0xf7 0x00f7 #DIVISION SIGN -0xf8 0x0173 #LATIN SMALL LETTER U WITH OGONEK -0xf9 0x0142 #LATIN SMALL LETTER L WITH STROKE -0xfa 0x015b #LATIN SMALL LETTER S WITH ACUTE -0xfb 0x016b #LATIN SMALL LETTER U WITH MACRON -0xfc 0x00fc #LATIN SMALL LETTER U WITH DIAERESIS -0xfd 0x017c #LATIN SMALL LETTER Z WITH DOT ABOVE -0xfe 0x017e #LATIN SMALL LETTER Z WITH CARON -0xff 0x02d9 #DOT ABOVE - * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file diff --git a/src/intl/charsets/cs_w1258.h b/src/intl/charsets/cs_w1258.h index aa196704188..475cdd0ae41 100644 --- a/src/intl/charsets/cs_w1258.h +++ b/src/intl/charsets/cs_w1258.h @@ -1,279 +1,11 @@ /* ------------------------------------------- This file was created with csUtility.java -# + # Name: cp1258 to Unicode table # Unicode version: 2.0 # Table version: 2.01 # Table format: Format A # Date: 04/15/98 -# -# Contact: cpxlate@microsoft.com -# -# General notes: none -# -# Format: Three tab-separated columns -# Column #1 is the cp1258 code (in hex) -# Column #2 is the Unicode (in hex as 0xXXXX) -# Column #3 is the Unicode name (follows a comment sign, '#') -# -# The entries are in cp1258 order -# -0x00 0x0000 #NULL -0x01 0x0001 #START OF HEADING -0x02 0x0002 #START OF TEXT -0x03 0x0003 #END OF TEXT -0x04 0x0004 #END OF TRANSMISSION -0x05 0x0005 #ENQUIRY -0x06 0x0006 #ACKNOWLEDGE -0x07 0x0007 #BELL -0x08 0x0008 #BACKSPACE -0x09 0x0009 #HORIZONTAL TABULATION -0x0A 0x000A #LINE FEED -0x0B 0x000B #VERTICAL TABULATION -0x0C 0x000C #FORM FEED -0x0D 0x000D #CARRIAGE RETURN -0x0E 0x000E #SHIFT OUT -0x0F 0x000F #SHIFT IN -0x10 0x0010 #DATA LINK ESCAPE -0x11 0x0011 #DEVICE CONTROL ONE -0x12 0x0012 #DEVICE CONTROL TWO -0x13 0x0013 #DEVICE CONTROL THREE -0x14 0x0014 #DEVICE CONTROL FOUR -0x15 0x0015 #NEGATIVE ACKNOWLEDGE -0x16 0x0016 #SYNCHRONOUS IDLE -0x17 0x0017 #END OF TRANSMISSION BLOCK -0x18 0x0018 #CANCEL -0x19 0x0019 #END OF MEDIUM -0x1A 0x001A #SUBSTITUTE -0x1B 0x001B #ESCAPE -0x1C 0x001C #FILE SEPARATOR -0x1D 0x001D #GROUP SEPARATOR -0x1E 0x001E #RECORD SEPARATOR -0x1F 0x001F #UNIT SEPARATOR -0x20 0x0020 #SPACE -0x21 0x0021 #EXCLAMATION MARK -0x22 0x0022 #QUOTATION MARK -0x23 0x0023 #NUMBER SIGN -0x24 0x0024 #DOLLAR SIGN -0x25 0x0025 #PERCENT SIGN -0x26 0x0026 #AMPERSAND -0x27 0x0027 #APOSTROPHE -0x28 0x0028 #LEFT PARENTHESIS -0x29 0x0029 #RIGHT PARENTHESIS -0x2A 0x002A #ASTERISK -0x2B 0x002B #PLUS SIGN -0x2C 0x002C #COMMA -0x2D 0x002D #HYPHEN-MINUS -0x2E 0x002E #FULL STOP -0x2F 0x002F #SOLIDUS -0x30 0x0030 #DIGIT ZERO -0x31 0x0031 #DIGIT ONE -0x32 0x0032 #DIGIT TWO -0x33 0x0033 #DIGIT THREE -0x34 0x0034 #DIGIT FOUR -0x35 0x0035 #DIGIT FIVE -0x36 0x0036 #DIGIT SIX -0x37 0x0037 #DIGIT SEVEN -0x38 0x0038 #DIGIT EIGHT -0x39 0x0039 #DIGIT NINE -0x3A 0x003A #COLON -0x3B 0x003B #SEMICOLON -0x3C 0x003C #LESS-THAN SIGN -0x3D 0x003D #EQUALS SIGN -0x3E 0x003E #GREATER-THAN SIGN -0x3F 0x003F #QUESTION MARK -0x40 0x0040 #COMMERCIAL AT -0x41 0x0041 #LATIN CAPITAL LETTER A -0x42 0x0042 #LATIN CAPITAL LETTER B -0x43 0x0043 #LATIN CAPITAL LETTER C -0x44 0x0044 #LATIN CAPITAL LETTER D -0x45 0x0045 #LATIN CAPITAL LETTER E -0x46 0x0046 #LATIN CAPITAL LETTER F -0x47 0x0047 #LATIN CAPITAL LETTER G -0x48 0x0048 #LATIN CAPITAL LETTER H -0x49 0x0049 #LATIN CAPITAL LETTER I -0x4A 0x004A #LATIN CAPITAL LETTER J -0x4B 0x004B #LATIN CAPITAL LETTER K -0x4C 0x004C #LATIN CAPITAL LETTER L -0x4D 0x004D #LATIN CAPITAL LETTER M -0x4E 0x004E #LATIN CAPITAL LETTER N -0x4F 0x004F #LATIN CAPITAL LETTER O -0x50 0x0050 #LATIN CAPITAL LETTER P -0x51 0x0051 #LATIN CAPITAL LETTER Q -0x52 0x0052 #LATIN CAPITAL LETTER R -0x53 0x0053 #LATIN CAPITAL LETTER S -0x54 0x0054 #LATIN CAPITAL LETTER T -0x55 0x0055 #LATIN CAPITAL LETTER U -0x56 0x0056 #LATIN CAPITAL LETTER V -0x57 0x0057 #LATIN CAPITAL LETTER W -0x58 0x0058 #LATIN CAPITAL LETTER X -0x59 0x0059 #LATIN CAPITAL LETTER Y -0x5A 0x005A #LATIN CAPITAL LETTER Z -0x5B 0x005B #LEFT SQUARE BRACKET -0x5C 0x005C #REVERSE SOLIDUS -0x5D 0x005D #RIGHT SQUARE BRACKET -0x5E 0x005E #CIRCUMFLEX ACCENT -0x5F 0x005F #LOW LINE -0x60 0x0060 #GRAVE ACCENT -0x61 0x0061 #LATIN SMALL LETTER A -0x62 0x0062 #LATIN SMALL LETTER B -0x63 0x0063 #LATIN SMALL LETTER C -0x64 0x0064 #LATIN SMALL LETTER D -0x65 0x0065 #LATIN SMALL LETTER E -0x66 0x0066 #LATIN SMALL LETTER F -0x67 0x0067 #LATIN SMALL LETTER G -0x68 0x0068 #LATIN SMALL LETTER H -0x69 0x0069 #LATIN SMALL LETTER I -0x6A 0x006A #LATIN SMALL LETTER J -0x6B 0x006B #LATIN SMALL LETTER K -0x6C 0x006C #LATIN SMALL LETTER L -0x6D 0x006D #LATIN SMALL LETTER M -0x6E 0x006E #LATIN SMALL LETTER N -0x6F 0x006F #LATIN SMALL LETTER O -0x70 0x0070 #LATIN SMALL LETTER P -0x71 0x0071 #LATIN SMALL LETTER Q -0x72 0x0072 #LATIN SMALL LETTER R -0x73 0x0073 #LATIN SMALL LETTER S -0x74 0x0074 #LATIN SMALL LETTER T -0x75 0x0075 #LATIN SMALL LETTER U -0x76 0x0076 #LATIN SMALL LETTER V -0x77 0x0077 #LATIN SMALL LETTER W -0x78 0x0078 #LATIN SMALL LETTER X -0x79 0x0079 #LATIN SMALL LETTER Y -0x7A 0x007A #LATIN SMALL LETTER Z -0x7B 0x007B #LEFT CURLY BRACKET -0x7C 0x007C #VERTICAL LINE -0x7D 0x007D #RIGHT CURLY BRACKET -0x7E 0x007E #TILDE -0x7F 0x007F #DELETE -0x80 0x20AC #EURO SIGN -0x81 #UNDEFINED -0x82 0x201A #SINGLE LOW-9 QUOTATION MARK -0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK -0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK -0x85 0x2026 #HORIZONTAL ELLIPSIS -0x86 0x2020 #DAGGER -0x87 0x2021 #DOUBLE DAGGER -0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT -0x89 0x2030 #PER MILLE SIGN -0x8A #UNDEFINED -0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK -0x8C 0x0152 #LATIN CAPITAL LIGATURE OE -0x8D #UNDEFINED -0x8E #UNDEFINED -0x8F #UNDEFINED -0x90 #UNDEFINED -0x91 0x2018 #LEFT SINGLE QUOTATION MARK -0x92 0x2019 #RIGHT SINGLE QUOTATION MARK -0x93 0x201C #LEFT DOUBLE QUOTATION MARK -0x94 0x201D #RIGHT DOUBLE QUOTATION MARK -0x95 0x2022 #BULLET -0x96 0x2013 #EN DASH -0x97 0x2014 #EM DASH -0x98 0x02DC #SMALL TILDE -0x99 0x2122 #TRADE MARK SIGN -0x9A #UNDEFINED -0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -0x9C 0x0153 #LATIN SMALL LIGATURE OE -0x9D #UNDEFINED -0x9E #UNDEFINED -0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS -0xA0 0x00A0 #NO-BREAK SPACE -0xA1 0x00A1 #INVERTED EXCLAMATION MARK -0xA2 0x00A2 #CENT SIGN -0xA3 0x00A3 #POUND SIGN -0xA4 0x00A4 #CURRENCY SIGN -0xA5 0x00A5 #YEN SIGN -0xA6 0x00A6 #BROKEN BAR -0xA7 0x00A7 #SECTION SIGN -0xA8 0x00A8 #DIAERESIS -0xA9 0x00A9 #COPYRIGHT SIGN -0xAA 0x00AA #FEMININE ORDINAL INDICATOR -0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -0xAC 0x00AC #NOT SIGN -0xAD 0x00AD #SOFT HYPHEN -0xAE 0x00AE #REGISTERED SIGN -0xAF 0x00AF #MACRON -0xB0 0x00B0 #DEGREE SIGN -0xB1 0x00B1 #PLUS-MINUS SIGN -0xB2 0x00B2 #SUPERSCRIPT TWO -0xB3 0x00B3 #SUPERSCRIPT THREE -0xB4 0x00B4 #ACUTE ACCENT -0xB5 0x00B5 #MICRO SIGN -0xB6 0x00B6 #PILCROW SIGN -0xB7 0x00B7 #MIDDLE DOT -0xB8 0x00B8 #CEDILLA -0xB9 0x00B9 #SUPERSCRIPT ONE -0xBA 0x00BA #MASCULINE ORDINAL INDICATOR -0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -0xBC 0x00BC #VULGAR FRACTION ONE QUARTER -0xBD 0x00BD #VULGAR FRACTION ONE HALF -0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS -0xBF 0x00BF #INVERTED QUESTION MARK -0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE -0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE -0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX -0xC3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE -0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS -0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE -0xC6 0x00C6 #LATIN CAPITAL LETTER AE -0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA -0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE -0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE -0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX -0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS -0xCC 0x0300 #COMBINING GRAVE ACCENT -0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE -0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX -0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS -0xD0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE -0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE -0xD2 0x0309 #COMBINING HOOK ABOVE -0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE -0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX -0xD5 0x01A0 #LATIN CAPITAL LETTER O WITH HORN -0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS -0xD7 0x00D7 #MULTIPLICATION SIGN -0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE -0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE -0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE -0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX -0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS -0xDD 0x01AF #LATIN CAPITAL LETTER U WITH HORN -0xDE 0x0303 #COMBINING TILDE -0xDF 0x00DF #LATIN SMALL LETTER SHARP S -0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE -0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE -0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX -0xE3 0x0103 #LATIN SMALL LETTER A WITH BREVE -0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS -0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE -0xE6 0x00E6 #LATIN SMALL LETTER AE -0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA -0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE -0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE -0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX -0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS -0xEC 0x0301 #COMBINING ACUTE ACCENT -0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE -0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX -0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS -0xF0 0x0111 #LATIN SMALL LETTER D WITH STROKE -0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE -0xF2 0x0323 #COMBINING DOT BELOW -0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE -0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX -0xF5 0x01A1 #LATIN SMALL LETTER O WITH HORN -0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS -0xF7 0x00F7 #DIVISION SIGN -0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE -0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE -0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE -0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX -0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS -0xFD 0x01B0 #LATIN SMALL LETTER U WITH HORN -0xFE 0x20AB #DONG SIGN -0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS -------------------------------------------- */ diff --git a/src/intl/cv_icu.cpp b/src/intl/cv_icu.cpp index b1ac01fce5a..5bbe65f0255 100644 --- a/src/intl/cv_icu.cpp +++ b/src/intl/cv_icu.cpp @@ -31,6 +31,34 @@ #include #include "../common/unicode_util.h" +namespace { + +static void U_EXPORT2 FB_UCNV_FROM_U_CALLBACK_STOP( + const void* /*context*/, + UConverterFromUnicodeArgs* /*fromUArgs*/, + const UChar* /*codeUnits*/, + int32_t /*length*/, + UChar32 /*codePoint*/, + UConverterCallbackReason /*reason*/, + UErrorCode* /*err*/) +{ + /* + * A stable implementation of callback function UCNV_FROM_U_CALLBACK_STOP. + * + * It is equal to a behaviour of old ICU (from FB2.1 and FB3). + * + * ICU from FB4 (v63.1) translates "ignorable" symbols (..., 0x115F, ...) into an empty string + * and this is incompatible with conversion of built-in charsets where + * a such case leads to a translation error. + * + */ + + /* the caller must have set the error code accordingly */ + return; +} + +} // namespace + static UConverter* create_converter(csconvert* cv, UErrorCode* status) { @@ -41,7 +69,7 @@ static UConverter* create_converter(csconvert* cv, UErrorCode* status) UConverterFromUCallback oldFromAction; cIcu.ucnv_setFromUCallBack( conv, - cIcu.UCNV_FROM_U_CALLBACK_STOP, + FB_UCNV_FROM_U_CALLBACK_STOP, NULL, &oldFromAction, &oldContext, diff --git a/src/intl/lc_ascii.cpp b/src/intl/lc_ascii.cpp index 22cc9b9d9dd..e70eadd900c 100644 --- a/src/intl/lc_ascii.cpp +++ b/src/intl/lc_ascii.cpp @@ -523,8 +523,6 @@ USHORT famasc_string_to_key(texttype* obj, USHORT iInLen, const BYTE* pInChar, U { fb_assert(pOutChar != NULL); fb_assert(pInChar != NULL); - fb_assert(iInLen <= LANGASCII_MAX_KEY); - fb_assert(iOutLen <= LANGASCII_MAX_KEY); fb_assert(iOutLen >= famasc_key_length(obj, iInLen)); // point inbuff at last character diff --git a/src/intl/lc_ksc.cpp b/src/intl/lc_ksc.cpp index 54ed5fc8d1b..e24d5a18692 100644 --- a/src/intl/lc_ksc.cpp +++ b/src/intl/lc_ksc.cpp @@ -139,8 +139,6 @@ static USHORT LCKSC_string_to_key(texttype* obj, USHORT iInLen, const BYTE* pInC { fb_assert(pOutChar != NULL); fb_assert(pInChar != NULL); - fb_assert(iInLen <= LANGKSC_MAX_KEY); - fb_assert(iOutLen <= LANGKSC_MAX_KEY); fb_assert(iOutLen >= LCKSC_key_length(obj, iInLen)); const BYTE* inbuff = pInChar + iInLen - 1; diff --git a/src/intl/lc_narrow.cpp b/src/intl/lc_narrow.cpp index f4e4943e4d0..f391f7fc5b6 100644 --- a/src/intl/lc_narrow.cpp +++ b/src/intl/lc_narrow.cpp @@ -168,8 +168,6 @@ USHORT LC_NARROW_string_to_key(texttype* obj, USHORT iInLen, const BYTE* pInChar { fb_assert(pOutChar != NULL); fb_assert(pInChar != NULL); - // fb_assert (iInLen <= LANGFAM2_MAX_KEY); - fb_assert(iOutLen <= LANGFAM2_MAX_KEY); fb_assert(iOutLen >= LC_NARROW_key_length(obj, iInLen)); TextTypeImpl* impl = static_cast(obj->texttype_impl); diff --git a/src/intl/ld.cpp b/src/intl/ld.cpp index 1056921ee34..151cd3e812f 100644 --- a/src/intl/ld.cpp +++ b/src/intl/ld.cpp @@ -468,7 +468,7 @@ struct }; -INTL_BOOL FB_DLL_EXPORT LD_lookup_charset(charset* cs, const ASCII* name, const ASCII* /*config_info*/) +FB_DLL_EXPORT INTL_BOOL LD_lookup_charset(charset* cs, const ASCII* name, const ASCII* /*config_info*/) { // ASF: We can't read config_info if version < INTL_VERSION_2, // since it wasn't pushed in the stack by the engine. @@ -491,7 +491,7 @@ INTL_BOOL FB_DLL_EXPORT LD_lookup_charset(charset* cs, const ASCII* name, const } -INTL_BOOL FB_DLL_EXPORT LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, +FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, USHORT attributes, const UCHAR* specific_attributes, ULONG specific_attributes_length, INTL_BOOL ignore_attributes, const ASCII* config_info) @@ -557,7 +557,7 @@ INTL_BOOL FB_DLL_EXPORT LD_lookup_texttype(texttype* tt, const ASCII* texttype_n } -ULONG FB_DLL_EXPORT LD_setup_attributes( +FB_DLL_EXPORT ULONG LD_setup_attributes( const ASCII* textTypeName, const ASCII* charSetName, const ASCII* configInfo, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst) { @@ -583,7 +583,7 @@ ULONG FB_DLL_EXPORT LD_setup_attributes( } -void FB_DLL_EXPORT LD_version(USHORT* version) +FB_DLL_EXPORT void LD_version(USHORT* version) { // We support version 1 and 2. if (*version != INTL_VERSION_1) diff --git a/src/intl/ld.h b/src/intl/ld.h index 0ee001f733b..0fc0237bad0 100644 --- a/src/intl/ld.h +++ b/src/intl/ld.h @@ -55,14 +55,6 @@ #define UINT16 USHORT -#if defined(WIN_NT) -#define FB_DLL_EXPORT __declspec(dllexport) -#elif defined(DARWIN) -#define FB_DLL_EXPORT API_ROUTINE -#else -#define FB_DLL_EXPORT -#endif - /* Following this line is LD.H from Borland Language Driver Kit */ diff --git a/src/intl/ld_proto.h b/src/intl/ld_proto.h index 6a6636dfa15..f20fdf076a8 100644 --- a/src/intl/ld_proto.h +++ b/src/intl/ld_proto.h @@ -38,13 +38,13 @@ struct CsConvertImpl extern USHORT version; -INTL_BOOL FB_DLL_EXPORT LD_lookup_charset(charset* cs, const ASCII* name, const ASCII* config_info); -INTL_BOOL FB_DLL_EXPORT LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, +FB_DLL_EXPORT INTL_BOOL LD_lookup_charset(charset* cs, const ASCII* name, const ASCII* config_info); +FB_DLL_EXPORT INTL_BOOL LD_lookup_texttype(texttype* tt, const ASCII* texttype_name, const ASCII* charset_name, USHORT attributes, const UCHAR* specific_attributes, ULONG specific_attributes_length, INTL_BOOL ignore_attributes, const ASCII* config_info); -void FB_DLL_EXPORT LD_version(USHORT* version); -ULONG FB_DLL_EXPORT LD_setup_attributes( +FB_DLL_EXPORT void LD_version(USHORT* version); +FB_DLL_EXPORT ULONG LD_setup_attributes( const ASCII* textTypeName, const ASCII* charSetName, const ASCII* configInfo, ULONG srcLen, const UCHAR* src, ULONG dstLen, UCHAR* dst); diff --git a/src/isql/ColList.cpp b/src/isql/ColList.cpp index be814c2e20d..342b1409284 100644 --- a/src/isql/ColList.cpp +++ b/src/isql/ColList.cpp @@ -95,7 +95,7 @@ bool ColList::remove(const char* name) if (pold) pold->next = p->next; else - m_head = NULL; + m_head = p->next; delete p; --m_count; diff --git a/src/isql/InputDevices.cpp b/src/isql/InputDevices.cpp index 24e8ae1e088..faae0a84e74 100644 --- a/src/isql/InputDevices.cpp +++ b/src/isql/InputDevices.cpp @@ -25,6 +25,8 @@ #if defined(DARWIN) && !defined(IOS) #if defined(i386) || defined(__x86_64__) #include +#elif defined(__aarch64__) +#include #else #include #endif diff --git a/src/isql/extract.epp b/src/isql/extract.epp index 0ae52145275..c3c0f784747 100644 --- a/src/isql/extract.epp +++ b/src/isql/extract.epp @@ -519,8 +519,24 @@ int EXTRACT_list_table(const SCHAR* relation_name, (RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_BY_DEFAULT ? "BY DEFAULT" : RFR.RDB$IDENTITY_TYPE == IDENT_TYPE_ALWAYS ? "ALWAYS" : "")); - if (!GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0) - isqlGlob.printf(" (START WITH %" SQUADFORMAT ")", GEN.RDB$INITIAL_VALUE); + const bool printInitial = !GEN.RDB$INITIAL_VALUE.NULL && GEN.RDB$INITIAL_VALUE != 0; + const bool printIncrement = !GEN.RDB$GENERATOR_INCREMENT.NULL && GEN.RDB$GENERATOR_INCREMENT != 1; + + if (printInitial || printIncrement) + { + isqlGlob.printf(" ("); + + if (printInitial) + { + isqlGlob.printf("START WITH %" SQUADFORMAT "%s", + GEN.RDB$INITIAL_VALUE, (printIncrement ? " " : "")); + } + + if (printIncrement) + isqlGlob.printf("INCREMENT %" SLONGFORMAT, GEN.RDB$GENERATOR_INCREMENT); + + isqlGlob.printf(")"); + } } END_FOR ON_ERROR diff --git a/src/isql/isql.epp b/src/isql/isql.epp index 1ed6541abe4..f92d81c4989 100644 --- a/src/isql/isql.epp +++ b/src/isql/isql.epp @@ -313,6 +313,114 @@ static inline int fb_isdigit(const char c) } +#ifdef WIN_NT +// This function is highly based on code written by https://github.com/xenu +// He permitted our usage here: https://github.com/Perl/perl5/pull/18702#issuecomment-1156050577 +static int win32ReadConsole(FILE* file, char* buffer, size_t bufferSize) +{ + // This function is a workaround for a bug in Windows: + // https://github.com/microsoft/terminal/issues/4551 + // tl;dr: ReadFile() and ReadConsoleA() return garbage when reading + // non-ASCII characters from the console with the 65001 codepage. + auto handle = (HANDLE) _get_osfhandle(fileno(file)); + + if (handle == INVALID_HANDLE_VALUE) + { + fb_assert(false); + return -1; + } + + DWORD mode; + if (!GetConsoleMode(handle, &mode)) + { + fb_assert(false); + return -1; + } + + size_t leftToRead = bufferSize; + + while (leftToRead) + { + // The purpose of convertedBuf is to preserve partial UTF-8 (or of any + // other multibyte encoding) code points between read() calls. Since + // there's only one console, the buffer is global. It's needed because + // ReadConsoleW() returns a string of UTF-16 code units and its result, + // after conversion to the current console codepage, may not fit in the + // return buffer. + // + // The buffer's size is 8 because it will contain at most two UTF-8 code + // points. + static char convertedBuf[8]; + static size_t convertedBufLen = 0; + + if (convertedBufLen) + { + bool newline = false; + const size_t toWrite = MIN(convertedBufLen, leftToRead); + + // Don't read anything if the *first* character is ^Z and + // ENABLE_PROCESSED_INPUT is enabled. On some versions of Windows, + // ReadFile() ignores ENABLE_PROCESSED_INPUT, but apparently it's a + // bug: https://github.com/microsoft/terminal/issues/4958 + if (leftToRead == bufferSize && (mode & ENABLE_PROCESSED_INPUT) && convertedBuf[0] == 0x1A) + break; + + // Are we returning a newline? + if (memchr(convertedBuf, '\n', toWrite) != 0) + newline = true; + + memcpy(buffer, convertedBuf, toWrite); + buffer += toWrite; + + // If there's anything left in convertedBuf, move it to the beginning of the buffer. + convertedBufLen -= toWrite; + + if (convertedBufLen) + memmove(convertedBuf, convertedBuf + toWrite, convertedBufLen); + + leftToRead -= toWrite; + + // With ENABLE_LINE_INPUT enabled, we stop reading after the first + // newline, otherwise we stop reading after the first character. + if (!leftToRead || newline || (mode & ENABLE_LINE_INPUT) == 0) + break; + } + + WCHAR wideBuf[2]; + DWORD charsRead; + + // Reading one code unit at a time is inefficient, but since this code + // is used only for the interactive console, that shouldn't matter. + if (!ReadConsoleW(handle, wideBuf, 1, &charsRead, 0)) + return -1; + + if (!charsRead) + break; + + DWORD wideBufLen = 1; + + if (wideBuf[0] >= 0xD800 && wideBuf[0] <= 0xDBFF) + { + // High surrogate, read one more code unit. + if (!ReadConsoleW(handle, wideBuf + 1, 1, &charsRead, 0)) + return -1; + + if (charsRead) + ++wideBufLen; + } + + convertedBufLen = WideCharToMultiByte(GetConsoleCP(), 0, wideBuf, wideBufLen, + convertedBuf, sizeof(convertedBuf), NULL, NULL); + + if (!convertedBufLen) + return -1; + } + + return bufferSize - leftToRead; +} +#endif + + IsqlGlobals::IsqlGlobals() { Firebird::AutoPtr @@ -368,6 +476,7 @@ static processing_state drop_db(); static processing_state edit(const TEXT* const*); static processing_state end_trans(); static processing_state escape(const TEXT*); +static processing_state execSetDebugCommand(); static processing_state frontend(const TEXT*); static processing_state frontend_set(const char* cmd, const char* const* parms, const char* const* lparms, char* const bad_dialect_buf, bool& bad_dialect); @@ -400,6 +509,7 @@ static processing_state print_performance(const SINT64* perf_before); static void print_message(Firebird::IMessageMetadata* msg, const char* dir); static void process_header(Firebird::IMessageMetadata*, const unsigned pad[], TEXT header[], TEXT header2[]); static void process_plan(); +static void process_exec_path(); static SINT64 process_record_count(const unsigned statement_type); static unsigned process_message_display(Firebird::IMessageMetadata* msg, unsigned pad[]); static processing_state process_statement(const TEXT*); @@ -457,6 +567,7 @@ public: Echo = false; Time_display = false; Sqlda_display = false; + ExecPathDisplay[0] = 0; Stats = false; Autocommit = true; // Commit ddl Warnings = true; // Print warnings @@ -480,6 +591,7 @@ public: bool Echo; bool Time_display; bool Sqlda_display; + UCHAR ExecPathDisplay[10]; bool Stats; bool Autocommit; // Commit ddl bool Warnings; // Print warnings @@ -917,11 +1029,22 @@ static void readNextInputLine(const char* prompt) { // Read the line char buffer[MAX_USHORT]; + int lineSize; - if (fgets(buffer, sizeof(buffer), Filelist->Ifp().indev_fpointer) != NULL) +#ifdef WIN_NT + if (!Input_file && isatty(fileno(Filelist->Ifp().indev_fpointer))) + lineSize = win32ReadConsole(Filelist->Ifp().indev_fpointer, buffer, sizeof(buffer)); + else +#endif { - size_t lineSize = strlen(buffer); + if (fgets(buffer, sizeof(buffer), Filelist->Ifp().indev_fpointer) != NULL) + lineSize = strlen(buffer); + else + lineSize = -1; + } + if (lineSize > 0) + { // If the last non empty line doesn't end in '\n', indev_aux won't be // updated, but then there're no more commands, so it's irrelevant. while (lineSize > 0 && @@ -1041,25 +1164,10 @@ bool ISQL_errmsg(Firebird::IStatus* st) } } - /* - if (state & Firebird::IStatus::STATE_WARNINGS) - { - const ISC_STATUS* w = st->getWarnings(); - TEXT* err = errbuf; - unsigned es = sizeof(errbuf); - while (fb_interpret(err, es, &w)) { - STDERROUT(errbuf); - if (err == errbuf) - { - *err++ = '-'; - --es; - } - } - } - */ - if (Input_file) { + // This must be done before call ISQL_warning, as it init the status object. + int linenum = -1; if (status[0] == isc_arg_gds && status[1] == isc_dsql_error && status[2] == isc_arg_gds && status[3] == isc_sqlerr && vec > &status[9]) @@ -1112,15 +1220,19 @@ bool ISQL_errmsg(Firebird::IStatus* st) else IUTILS_msg_get(AFTERLINE, errbuf, SafeArg() << Ifp.indev_line << Ifp.fileName(true).c_str()); + ISQL_warning(st); + STDERROUT(errbuf); } + else + ISQL_warning(st); } return (state & Firebird::IStatus::STATE_ERRORS); } -void ISQL_warning(Firebird::CheckStatusWrapper* st) +void ISQL_warning(Firebird::IStatus* st) { /************************************** * @@ -4787,6 +4899,27 @@ static processing_state escape(const TEXT* cmd) } +static processing_state execSetDebugCommand() +{ + if (!DB) + return SKIP; + + const char* stmt = setValues.ExecPathDisplay[0] ? + "set debug option dsql_keep_blr = true" : + "set debug option dsql_keep_blr = false"; + + DB->execute(fbStatus, nullptr, 0, stmt, isqlGlob.SQL_dialect, nullptr, nullptr, nullptr, nullptr); + + if (setValues.ExecPathDisplay[0] && (fbStatus->getState() & Firebird::IStatus::STATE_ERRORS)) + { + STDERROUT("SET EXEC_PATH_DISPLAY is not supported in this connection."); + return FAIL; + } + + return SKIP; +} + + static processing_state frontend(const TEXT* statement) { /************************************** @@ -5175,9 +5308,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, { stat, count, list, plan, planonly, explain, blobdisplay, echo, autoddl, width, transaction, terminator, names, time, -//#ifdef DEV_BUILD sqlda_display, -//#endif + exec_path_display, sql, warning, sqlCont, heading, bail, bulk_insert, maxrows, stmtTimeout, keepTranParams, @@ -5204,9 +5336,8 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, {SetOptions::terminator, "TERMINATOR", 4}, {SetOptions::names, "NAMES", 0}, {SetOptions::time, "TIME", 0}, -//#ifdef DEV_BUILD {SetOptions::sqlda_display, "SQLDA_DISPLAY", 0}, -//#endif + {SetOptions::exec_path_display, "EXEC_PATH_DISPLAY", 0}, {SetOptions::sql, "SQL", 0}, {SetOptions::warning, "WARNINGS", 7}, {SetOptions::warning, "WNG", 0}, @@ -5350,11 +5481,59 @@ static processing_state frontend_set(const char* cmd, const char* const* parms, ret = do_set_command(parms[2], &setValues.Time_display); break; -//#ifdef DEV_BUILD case SetOptions::sqlda_display: ret = do_set_command(parms[2], &setValues.Sqlda_display); break; -//#endif // DEV_BUILD + + case SetOptions::exec_path_display: + ret = SKIP; + + if (!*parms[2]) + ret = ps_ERR; + else if (strcmp(parms[2], "OFF") == 0) + setValues.ExecPathDisplay[0] = 0; + else + { + Firebird::Array execPath; + + for (int parNum = 2; parNum < MAX_TERMS - 1 && *parms[parNum]; ++parNum) + { + const char* param = parms[parNum]; + UCHAR code; + + if (strcmp(param, "BLR") == 0) + code = isc_info_sql_exec_path_blr_text; + else + { + ret = ps_ERR; + break; + } + + if (execPath.exist(code)) + { + ret = ps_ERR; + break; + } + + execPath.push(code); + } + + if (ret != ps_ERR) + { + if (execPath.getCount() < sizeof(setValues.ExecPathDisplay)) + { + memcpy(setValues.ExecPathDisplay, execPath.begin(), execPath.getCount()); + setValues.ExecPathDisplay[execPath.getCount()] = 0; + } + else + ret = ps_ERR; + } + } + + if (ret != ps_ERR) + ret = execSetDebugCommand(); + + break; case SetOptions::sql: if (!strcmp(parms[2], "DIALECT")) @@ -5897,22 +6076,22 @@ void ISQL_get_version(bool call_by_create_db) return; } - const UCHAR* p = buffer; - while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer)) + for (Firebird::ClumpletReader p(Firebird::ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { - const UCHAR item = (UCHAR) *p++; - const USHORT length = gds__vax_integer(p, sizeof(USHORT)); - p += sizeof(USHORT); + UCHAR item = p.getClumpTag(); + if (item == isc_info_end) + break; + switch (item) { case isc_info_ods_version: - isqlGlob.major_ods = gds__vax_integer(p, length); + isqlGlob.major_ods = p.getInt(); break; case isc_info_ods_minor_version: - isqlGlob.minor_ods = gds__vax_integer(p, length); + isqlGlob.minor_ods = p.getInt(); break; case isc_info_db_sql_dialect: - global_dialect_spoken = gds__vax_integer(p, length); + global_dialect_spoken = p.getInt(); if (isqlGlob.major_ods < ODS_VERSION10) { if (isqlGlob.SQL_dialect > SQL_DIALECT_V5 && setValues.Warnings) @@ -5961,7 +6140,7 @@ void ISQL_get_version(bool call_by_create_db) case isc_info_error: // Error indicates an option was not understood by the // remote server. - if (*p == isc_info_firebird_version) + if (p.getBytes()[0] == isc_info_firebird_version) { // must be an old or non Firebird server break; @@ -6007,8 +6186,8 @@ void ISQL_get_version(bool call_by_create_db) // to put it all. It's a FULL or NOTHING answer. It grows with redirection. // The command SHOW version that calls isc_version() will return more info. isqlGlob.printf("Server version:%s", NEWLINE); - const UCHAR* q = p; // We don't want to spoil p with a wrong calculation. - const UCHAR* limit = q + length; + const UCHAR* q = p.getBytes(); // We don't want to spoil p with a wrong calculation. + const UCHAR* limit = q + p.getClumpLength(); for (int times = *q++; times && q < limit; --times) { int l = *q++; @@ -6022,7 +6201,7 @@ void ISQL_get_version(bool call_by_create_db) break; case frb_info_att_charset: - isqlGlob.att_charset = gds__vax_integer(p, length); + isqlGlob.att_charset = p.getInt(); break; default: @@ -6030,7 +6209,6 @@ void ISQL_get_version(bool call_by_create_db) item, NEWLINE); break; } - p += length; } if (isqlGlob.major_ods < ODS_VERSION8) @@ -6058,6 +6236,9 @@ void ISQL_get_version(bool call_by_create_db) isqlGlob.db_SQL_dialect = global_dialect_spoken; else isqlGlob.db_SQL_dialect = SQL_DIALECT_V5; + + if (setValues.ExecPathDisplay[0]) + execSetDebugCommand(); } @@ -6368,6 +6549,67 @@ static bool isyesno(const TEXT* buffer) static bool printUser(const char* dbName) { + unsigned char info[] = {fb_info_username, fb_info_sqlrole}; + unsigned char buffer[(1 + 2 + MAX_SQL_IDENTIFIER_SIZE) * 2 + 2]; + Firebird::string login, role; + + DB->getInfo(fbStatus, sizeof(info), info, sizeof(buffer), buffer); + if (failed()) + return false; + + UCHAR* p = buffer; + + while (p) + { + unsigned int len; + switch (*p++) + { + case fb_info_username: + len = gds__vax_integer(p, 2); + login.assign(p + 2, len); + break; + + case fb_info_sqlrole: + len = gds__vax_integer(p, 2); + role.assign(p + 2, len); + if (role == "NONE") + role.erase(); + break; + + default: + p = NULL; + continue; + } + + p += (2 + len); + } + + if (login.hasData() || role.hasData()) + { + bool wasOut = dbName && dbName[0]; + if (wasOut) + isqlGlob.printf("Database: %s", dbName); + + if (login.hasData()) + { + isqlGlob.printf("%sUser: %s", wasOut ? ", " : "", login.c_str()); + wasOut = true; + } + + if (role.hasData()) + { + isqlGlob.printf("%sRole: %s", wasOut ? ", " : "", role.c_str()); + wasOut = true; + } + + if (wasOut) + isqlGlob.printf("%s", NEWLINE); + + return true; + } + + // fallback to SQL way to do job + if (!frontendTransaction()) return false; @@ -6658,6 +6900,9 @@ static processing_state newdb(TEXT* dbname, } } + if (setValues.ExecPathDisplay[0]) + execSetDebugCommand(); + global_Stmt = NULL; return SKIP; @@ -8399,6 +8644,58 @@ static void process_plan() } +static void process_exec_path() +{ + if (!global_Stmt) + return; + + Firebird::Array pathBuffer; + pathBuffer.getBuffer(MAX_USHORT, false); + + for (const UCHAR* code = setValues.ExecPathDisplay; *code; ++code) + { + global_Stmt->getInfo(fbStatus, 1, code, pathBuffer.getCount(), pathBuffer.begin()); + + if (ISQL_errmsg(fbStatus)) + return; + + Firebird::string pathString; + + for (const UCHAR* ptr = pathBuffer.begin(); ptr < pathBuffer.end();) + { + const UCHAR tag = *ptr++; + + if (tag == *code) + { + const USHORT len = (USHORT) gds__vax_integer(ptr, sizeof(USHORT)); + ptr += sizeof(USHORT); + pathString.assign((const char*) ptr, len); + ptr += len; + } + else if (tag == isc_info_end) + break; + else if (tag == isc_info_truncated) + { + pathString = "* error: overflow *\n"; + break; + } + else + pathString = "* unknown error *\n"; + } + + if (pathString.hasData()) + { + IUTILS_printf2(Diag, "%sExecution path (%s):%s%s%s", NEWLINE, + (*code == isc_info_sql_exec_path_blr_text ? "BLR" : + "* unknown *" + ), + NEWLINE, NEWLINE, + pathString.c_str()); + } + } +} + + // *************************************** // p r o c e s s _ r e c o r d _ c o u n t // *************************************** @@ -8599,9 +8896,13 @@ static unsigned process_message_display(Firebird::IMessageMetadata* message, uns pad[i] = setValues.global_Col_default; disp_length = pad[i]; - if (charSet == CS_UTF8) + if (charSet == CS_UNICODE_FSS) + disp_length *= 3; + else if (charSet == CS_UTF8) disp_length *= 4; } + else if (isqlGlob.att_charset == CS_UNICODE_FSS) + disp_length = MAX(disp_length, namelength * 3); else if (isqlGlob.att_charset == CS_UTF8) disp_length = MAX(disp_length, namelength * 4); @@ -8767,7 +9068,6 @@ static processing_state process_statement(const TEXT* str2) } } - const bool is_selectable = statement_type == isc_info_sql_stmt_select || statement_type == isc_info_sql_stmt_select_for_upd || @@ -8786,6 +9086,9 @@ static processing_state process_statement(const TEXT* str2) } } + if (setValues.ExecPathDisplay[0]) + process_exec_path(); + // If the statement isn't a select, execute it and be done if (!is_selectable && !setValues.Planonly) @@ -9056,6 +9359,10 @@ static processing_state process_statement(const TEXT* str2) } curs->close(fbStatus); + if (ISQL_errmsg(fbStatus)) + { + return ps_ERR; + } } // Avoid cancel during cleanup diff --git a/src/isql/isql_proto.h b/src/isql/isql_proto.h index 906e161eb2b..283742f38dc 100644 --- a/src/isql/isql_proto.h +++ b/src/isql/isql_proto.h @@ -35,7 +35,7 @@ void ISQL_array_dimensions(const TEXT*); bool ISQL_dbcheck(); void ISQL_disconnect_database(bool); bool ISQL_errmsg(Firebird::IStatus*); -void ISQL_warning(ISC_STATUS*); +void ISQL_warning(Firebird::IStatus*); void ISQL_exit_db(); // CVC: Not found. //int ISQL_extract(TEXT*, int, FILE*, FILE*, FILE*); diff --git a/src/isql/show.epp b/src/isql/show.epp index 52cb5c30756..e383d9ac7a5 100644 --- a/src/isql/show.epp +++ b/src/isql/show.epp @@ -46,6 +46,7 @@ #include "../jrd/intl.h" #include "../common/intlobj_new.h" #include "../common/classes/AlignedBuffer.h" +#include "../common/classes/ClumpletReader.h" #include "../isql/isql_proto.h" #include "../isql/show_proto.h" #include "../isql/iutils_proto.h" @@ -57,6 +58,7 @@ #include "../common/classes/UserBlob.h" #include "../common/classes/VaryStr.h" #include "../common/classes/ImplementHelper.h" +#include "../common/TimeZoneUtil.h" #include "../isql/OptionsBase.h" #include @@ -251,7 +253,11 @@ static const UCHAR db_items[] = isc_info_db_id, #endif fb_info_crypt_state, + fb_info_protocol_version, fb_info_wire_crypt, + fb_info_creation_timestamp_tz, + isc_info_creation_date, + fb_info_replica_mode, isc_info_end }; @@ -400,14 +406,16 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, if (ISQL_errmsg(status_vector)) return false; + bool crdatePrinted = false; + *info_buf = '\0'; SCHAR* info = info_buf; - for (const UCHAR* d = buffer; *d != isc_info_end;) + + for (Firebird::ClumpletReader p(Firebird::ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { + UCHAR item = p.getClumpTag(); SINT64 value_out = 0; - const UCHAR item = *d++; - const int length = ISQL_vax_integer(d, 2); - d += 2; + /* * This is not the best solution but it fixes the lack of characters * in Windows ISQL. This will need to remain until we modify the messages @@ -420,12 +428,12 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case isc_info_page_size: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); sprintf(info, "PAGE_SIZE %" SQUADFORMAT"%s", value_out, separator); break; case isc_info_db_size_in_pages: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(NUMBER_PAGES, msg, SafeArg() << value_out); @@ -436,7 +444,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case fb_info_pages_used: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(NUMBER_USED_PAGES, msg, SafeArg() << value_out); @@ -447,7 +455,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case fb_info_pages_free: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(NUMBER_FREE_PAGES, msg, SafeArg() << value_out); @@ -458,8 +466,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case fb_info_crypt_state: - value_out = ISQL_vax_integer(d, length); - + value_out = p.getInt(); if (translate) { Firebird::string s; @@ -489,7 +496,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case isc_info_sweep_interval: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(SWEEP_INTERV, msg, SafeArg() << value_out); @@ -500,32 +507,32 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case isc_info_forced_writes: - value_out = ISQL_vax_integer (d, length); + value_out = p.getInt(); sprintf (info, "Forced Writes are %s%s", (value_out == 1 ? "ON" : "OFF"), separator); break; case isc_info_oldest_transaction : - value_out = ISQL_vax_integer (d, length); + value_out = p.getInt(); sprintf(info, "Transaction - oldest = %" SQUADFORMAT"%s", value_out, separator); break; case isc_info_oldest_active : - value_out = ISQL_vax_integer (d, length); + value_out = p.getInt(); sprintf(info, "Transaction - oldest active = %" SQUADFORMAT"%s", value_out, separator); break; case isc_info_oldest_snapshot : - value_out = ISQL_vax_integer (d, length); + value_out = p.getInt(); sprintf(info, "Transaction - oldest snapshot = %" SQUADFORMAT"%s", value_out, separator); break; case isc_info_next_transaction : - value_out = ISQL_vax_integer (d, length); + value_out = p.getInt(); sprintf (info, "Transaction - Next = %" SQUADFORMAT"%s", value_out, separator); break; case isc_info_base_level: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(BASE_LEVEL, msg, SafeArg() << value_out); @@ -536,7 +543,7 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case isc_info_limbo: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); if (translate) { IUTILS_msg_get(LIMBO, msg, SafeArg() << value_out); @@ -547,17 +554,73 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; case isc_info_ods_version: - isqlGlob.major_ods = ISQL_vax_integer(d, length); + isqlGlob.major_ods = p.getInt(); break; case isc_info_ods_minor_version: - value_out = ISQL_vax_integer(d, length); + value_out = p.getInt(); sprintf(info, "ODS = %" SLONGFORMAT".%" SQUADFORMAT"%s", (SLONG) isqlGlob.major_ods, value_out, separator); break; case fb_info_wire_crypt: - if (d && length) - sprintf (info, "Wire crypt plugin: %.*s%s", length, d, separator); + if (p.getClumpLength()) + sprintf (info, "Wire crypt plugin: %.*s%s", p.getClumpLength(), p.getBytes(), separator); + break; + + case isc_info_creation_date: + if (p.getClumpLength() == sizeof(ISC_TIMESTAMP) && !crdatePrinted) + { + ISC_TIMESTAMP ts; + + const UCHAR* t = p.getBytes(); + ts.timestamp_date = ISQL_vax_integer(t, sizeof(ISC_DATE)); + t += sizeof(ISC_DATE); + ts.timestamp_time = ISQL_vax_integer(t, sizeof(ISC_TIME)); + + struct tm time; + isc_decode_timestamp(&ts, &time); + + sprintf(info, "Creation date: %s %d, %d %d:%02d:%02d%s", + FB_SHORT_MONTHS[time.tm_mon], time.tm_mday, time.tm_year + 1900, + time.tm_hour, time.tm_min, time.tm_sec, separator); + } + break; + + case fb_info_creation_timestamp_tz: + if (p.getClumpLength() == sizeof(ISC_TIMESTAMP)) + { + ISC_TIMESTAMP_TZ tsz; + + const UCHAR* t = p.getBytes(); + tsz.utc_timestamp.timestamp_date = ISQL_vax_integer(t, sizeof(ISC_DATE)); + t += sizeof(ISC_DATE); + tsz.utc_timestamp.timestamp_time = ISQL_vax_integer(t, sizeof(ISC_TIME)); + t += sizeof(ISC_TIME); + tsz.time_zone = ISQL_vax_integer(t, sizeof(ULONG)); + + unsigned year, month, day, hours, minutes, seconds, fractions; + char timeZone[Firebird::TimeZoneUtil::MAX_SIZE]; + + Firebird::UtilInterfacePtr()->decodeTimeStampTz(fbStatus, &tsz, + &year, &month, &day, &hours, &minutes, &seconds, &fractions, sizeof(timeZone), timeZone); + + if (ISQL_errmsg(fbStatus)) + break; + + sprintf(info, "Creation date: %s %d, %d %d:%02d:%02d %s%s", + FB_SHORT_MONTHS[month - 1], day, year, + hours, minutes, seconds, timeZone, separator); + + crdatePrinted = true; + } + break; + + case fb_info_protocol_version: + value_out = p.getInt(); + if (value_out) + sprintf(info, "Protocol version = %" SQUADFORMAT"%s", value_out, separator); + else + sprintf(info, "Embedded connection%s", separator); break; #ifdef DEV_BUILD @@ -565,8 +628,8 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, { // Will print with garbage for now. //It's sprintf(info, "DB/Host = %.*s", length, d); - const UCHAR* s = d; - const UCHAR* end = s + length; + const UCHAR* s = p.getBytes(); + const UCHAR* end = s + p.getClumpLength(); ++s; // Skip useless indicator. int len = *s++; printf("DB = %.*s\n", len, s); @@ -581,11 +644,21 @@ bool SHOW_dbb_parameters(Firebird::IAttachment* db_handle, break; #endif + case fb_info_replica_mode: + { + value_out = p.getInt(); + const char* mode = + (value_out == fb_info_replica_none) ? "NONE" : + (value_out == fb_info_replica_read_only) ? "READ_ONLY" : + (value_out == fb_info_replica_read_write) ? "READ_WRITE" : + "unknown"; + sprintf(info, "Replica mode: %s%s", mode, separator); + } + break; + case isc_info_truncated: return info > info_buf; // If we got some items, we are (partially) successful. } - - d += length; info += strlen(info); } @@ -3536,7 +3609,7 @@ static void show_db() return; END_ERROR; - SCHAR info_buf[BUFFER_LENGTH400]; + SCHAR info_buf[BUFFER_LENGTH512]; // First general database parameters @@ -4970,7 +5043,7 @@ static void printMap(bool extract, bool global, char* name, char* usng, char* pl isqlGlob.printf("FROM %s", anyObj ? "ANY " : ""); printIdent(extract, fromType, "%s "); if (!anyObj) - printIdent(extract, from, "%s "); + isqlGlob.printf("\'%s\' ", from); isqlGlob.printf("TO %s ", toType ? "ROLE" : "USER"); if (to) @@ -6393,17 +6466,10 @@ static processing_state show_users() processing_state rc = OBJECT_NOT_FOUND; - for (const UCHAR* data = buffer; *data != isc_info_end;) + for (Firebird::ClumpletReader p(Firebird::ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { - const UCHAR item = *data++; - const int length = gds__vax_integer(data, 2); - data += 2; - - switch (item) + switch (p.getClumpTag()) { - case isc_info_end: - break; - case isc_info_user_names: { if (rc == OBJECT_NOT_FOUND) @@ -6414,9 +6480,9 @@ static processing_state show_users() rc = SKIP; // We found at least one user. } - int len = *data; - fb_assert(len == length - 1); - const UCHAR* uname = data + 1; + unsigned len = p.getBytes()[0]; + fb_assert(len == p.getClumpLength() - 1); + const UCHAR* uname = p.getBytes() + 1; // Let's mark all attachments with our same user with a # prefix. bool same(len == my_user->vary_length && !memcmp(my_user->vary_string, uname, len)); isqlGlob.printf("%c %.*s", same ? '#' : ' ', len, uname); @@ -6431,10 +6497,6 @@ static processing_state show_users() isqlGlob.printf("%s\n", msg); return rc; // If we got some items, we are (partially) successful. } - - data += length; - if (data >= buffer + sizeof(buffer)) - break; } return rc; diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index 8a038cc6f90..f102c0ce236 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -24,6 +24,7 @@ #include "firebird.h" #include "../jrd/Attachment.h" +#include "../jrd/MetaName.h" #include "../jrd/Database.h" #include "../jrd/Function.h" #include "../jrd/nbak.h" @@ -47,7 +48,6 @@ #include "../jrd/replication/Manager.h" #include "../common/classes/fb_string.h" -#include "../jrd/MetaName.h" #include "../common/StatusArg.h" #include "../common/TimeZoneUtil.h" #include "../common/isc_proto.h" @@ -597,6 +597,12 @@ void Jrd::Attachment::resetSession(thread_db* tdbb, jrd_tra** traHandle) } catch (const Exception& ex) { + if (att_ext_call_depth && !shutAtt) + { + flags.release(ATT_resetting); // reset is incomplete - keep state + shutAtt = true; + } + if (shutAtt) signalShutdown(isc_ses_reset_failed); @@ -989,10 +995,10 @@ void Jrd::Attachment::SyncGuard::init(const char* f, bool if (jStable) { - jStable->getMutex()->enter(f); + jStable->getSync()->enter(f); if (!jStable->getHandle()) { - jStable->getMutex()->leave(); + jStable->getSync()->leave(); Arg::Gds(isc_att_shutdown).raise(); } } @@ -1004,13 +1010,13 @@ void StableAttachmentPart::manualLock(ULONG& flags, const ULONG whatLock) if (whatLock & ATT_async_manual_lock) { - asyncMutex.enter(FB_FUNCTION); + async.enter(FB_FUNCTION); flags |= ATT_async_manual_lock; } if (whatLock & ATT_manual_lock) { - mainMutex.enter(FB_FUNCTION); + mainSync.enter(FB_FUNCTION); flags |= ATT_manual_lock; } } @@ -1020,7 +1026,7 @@ void StableAttachmentPart::manualUnlock(ULONG& flags) if (flags & ATT_manual_lock) { flags &= ~ATT_manual_lock; - mainMutex.leave(); + mainSync.leave(); } manualAsyncUnlock(flags); } @@ -1030,7 +1036,7 @@ void StableAttachmentPart::manualAsyncUnlock(ULONG& flags) if (flags & ATT_async_manual_lock) { flags &= ~ATT_async_manual_lock; - asyncMutex.leave(); + async.leave(); } } @@ -1038,7 +1044,7 @@ void StableAttachmentPart::onIdleTimer(TimerImpl*) { // Ensure attachment is still alive and still idle - MutexEnsureUnlock guard(*this->getMutex(), FB_FUNCTION); + EnsureUnlock guard(*this->getSync(), FB_FUNCTION); if (!guard.tryEnter()) return; @@ -1109,6 +1115,18 @@ void Attachment::checkReplSetLock(thread_db* tdbb) void Attachment::invalidateReplSet(thread_db* tdbb, bool broadcast) { + if (broadcast) + { + // Signal other attachments about the changed state + if (att_repl_lock->lck_logical == LCK_none) + LCK_lock(tdbb, att_repl_lock, LCK_EX, LCK_WAIT); + else + LCK_convert(tdbb, att_repl_lock, LCK_EX, LCK_WAIT); + } + + if (att_flags & ATT_repl_reset) + return; + att_flags |= ATT_repl_reset; if (att_relations) @@ -1120,15 +1138,6 @@ void Attachment::invalidateReplSet(thread_db* tdbb, bool broadcast) } } - if (broadcast) - { - // Signal other attachments about the changed state - if (att_repl_lock->lck_logical == LCK_none) - LCK_lock(tdbb, att_repl_lock, LCK_EX, LCK_WAIT); - else - LCK_convert(tdbb, att_repl_lock, LCK_EX, LCK_WAIT); - } - LCK_release(tdbb, att_repl_lock); } diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index aa032c3eebb..389d2045099 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -50,7 +50,7 @@ #include -#define DEBUG_LCK_LIST +//#define DEBUG_LCK_LIST namespace EDS { class Connection; @@ -203,6 +203,103 @@ class ActiveSnapshots class StableAttachmentPart : public Firebird::RefCounted, public Firebird::GlobalStorage { public: + class Sync + { + public: + Sync() + : waiters(0), threadId(0), totalLocksCounter(0), currentLocksCounter(0) + { } + + void enter(const char* aReason) + { + ThreadId curTid = getThreadId(); + + if (threadId == curTid) + { + currentLocksCounter++; + return; + } + + if (threadId || !syncMutex.tryEnter(aReason)) + { + // we have contention with another thread + waiters.fetch_add(1, std::memory_order_relaxed); + syncMutex.enter(aReason); + waiters.fetch_sub(1, std::memory_order_relaxed); + } + + threadId = curTid; + totalLocksCounter++; + fb_assert(currentLocksCounter == 0); + currentLocksCounter++; + } + + bool tryEnter(const char* aReason) + { + ThreadId curTid = getThreadId(); + + if (threadId == curTid) + { + currentLocksCounter++; + return true; + } + + if (threadId || !syncMutex.tryEnter(aReason)) + return false; + + threadId = curTid; + totalLocksCounter++; + fb_assert(currentLocksCounter == 0); + currentLocksCounter++; + return true; + } + + void leave() + { + fb_assert(currentLocksCounter > 0); + + if (--currentLocksCounter == 0) + { + threadId = 0; + syncMutex.leave(); + } + } + + bool hasContention() const + { + return (waiters.load(std::memory_order_relaxed) > 0); + } + + FB_UINT64 getLockCounter() const + { + return totalLocksCounter; + } + + bool locked() const + { + return threadId == getThreadId(); + } + + ~Sync() + { + if (threadId == getThreadId()) + { + syncMutex.leave(); + } + } + + private: + // copying is prohibited + Sync(const Sync&); + Sync& operator=(const Sync&); + + Firebird::Mutex syncMutex; + std::atomic waiters; + ThreadId threadId; + volatile FB_UINT64 totalLocksCounter; + int currentLocksCounter; + }; + explicit StableAttachmentPart(Attachment* handle) : att(handle), jAtt(NULL), shutError(0) { } @@ -226,13 +323,13 @@ class StableAttachmentPart : public Firebird::RefCounted, public Firebird::Globa shutError = 0; } - Firebird::Mutex* getMutex(bool useAsync = false, bool forceAsync = false) + Sync* getSync(bool useAsync = false, bool forceAsync = false) { if (useAsync && !forceAsync) { - fb_assert(!mainMutex.locked()); + fb_assert(!mainSync.locked()); } - return useAsync ? &asyncMutex : &mainMutex; + return useAsync ? &async : &mainSync; } Firebird::Mutex* getBlockingMutex() @@ -242,8 +339,8 @@ class StableAttachmentPart : public Firebird::RefCounted, public Firebird::Globa void cancel() { - fb_assert(asyncMutex.locked()); - fb_assert(mainMutex.locked()); + fb_assert(async.locked()); + fb_assert(mainSync.locked()); att = NULL; } @@ -279,13 +376,16 @@ class StableAttachmentPart : public Firebird::RefCounted, public Firebird::Globa JAttachment* jAtt; ISC_STATUS shutError; - // These mutexes guarantee attachment existence. After releasing both of them with possibly + // These syncs guarantee attachment existence. After releasing both of them with possibly // zero att_use_count one should check does attachment still exists calling getHandle(). - Firebird::Mutex mainMutex, asyncMutex; + Sync mainSync, async; // This mutex guarantees attachment is not accessed by more than single external thread. Firebird::Mutex blockingMutex; }; +typedef Firebird::RaiiLockGuard AttSyncLockGuard; +typedef Firebird::RaiiUnlockGuard AttSyncUnlockGuard; + // // the attachment block; one is created for each attachment to a database // @@ -310,7 +410,7 @@ class Attachment : public pool_alloc ~SyncGuard() { if (jStable) - jStable->getMutex()->leave(); + jStable->getSync()->leave(); } private: @@ -349,7 +449,7 @@ class Attachment : public pool_alloc bool lookup(SLONG id, MetaName& name) { - if (id < (int) m_objects.getCount()) + if (id < (int) m_objects.getCount() && m_objects[id].hasData()) { name = m_objects[id]; return true; @@ -401,6 +501,43 @@ class Attachment : public pool_alloc USHORT originalTimeZone = Firebird::TimeZoneUtil::GMT_ZONE; }; + class DebugOptions + { + public: + bool getDsqlKeepBlr() const + { + return dsqlKeepBlr; + } + + void setDsqlKeepBlr(bool value) + { + dsqlKeepBlr = value; + } + + private: + bool dsqlKeepBlr = false; + }; + + class UseCountHolder + { + public: + explicit UseCountHolder(Attachment* a) + : att(a) + { + if (att) + att->att_use_count++; + } + + ~UseCountHolder() + { + if (att) + att->att_use_count--; + } + + private: + Attachment* att; + }; + public: static Attachment* create(Database* dbb, JProvider* provider); static void destroy(Attachment* const attachment); @@ -636,6 +773,16 @@ class Attachment : public pool_alloc UserId* getUserId(const Firebird::MetaString& userName); + const Firebird::MetaString& getUserName(const Firebird::MetaString& emptyName = "") const + { + return att_user ? att_user->getUserName() : emptyName; + } + + const Firebird::MetaString& getSqlRole(const Firebird::MetaString& emptyName = "") const + { + return att_user ? att_user->getSqlRole() : emptyName; + } + const UserId* getEffectiveUserId() const { if (att_ss_user) @@ -643,11 +790,10 @@ class Attachment : public pool_alloc return att_user; } - UserId* getEffectiveUserId() + const Firebird::MetaString& getEffectiveUserName(const Firebird::MetaString& emptyName = "") const { - if (att_ss_user) - return att_ss_user; - return att_user; + const auto user = getEffectiveUserId(); + return user ? user->getUserName() : emptyName; } void setInitialOptions(thread_db* tdbb, DatabaseOptions& options, bool newDb); @@ -656,6 +802,11 @@ class Attachment : public pool_alloc return att_initial_options.getBindings(); } + DebugOptions& getDebugOptions() + { + return att_debug_options; + } + void checkReplSetLock(thread_db* tdbb); void invalidateReplSet(thread_db* tdbb, bool broadcast); @@ -677,6 +828,7 @@ class Attachment : public pool_alloc Firebird::Array att_batches; InitialOptions att_initial_options; // Initial session options + DebugOptions att_debug_options; Lock* att_repl_lock; // Replication set lock JProvider* att_provider; // Provider which created this attachment @@ -685,8 +837,8 @@ class Attachment : public pool_alloc inline bool Attachment::locksmith(thread_db* tdbb, SystemPrivilege sp) const { - return (att_user && att_user->locksmith(tdbb, sp)) || - (att_ss_user && att_ss_user->locksmith(tdbb, sp)); + const auto user = getEffectiveUserId(); + return (user && user->locksmith(tdbb, sp)); } inline jrd_tra* Attachment::getSysTransaction() @@ -768,9 +920,13 @@ class AttachmentsRefHolder : m_attachments(p) {} + AttachmentsRefHolder() + : m_attachments(*MemoryPool::getContextPool()) + {} + AttachmentsRefHolder& operator=(const AttachmentsRefHolder& other) { - this->~AttachmentsRefHolder(); + clear(); for (FB_SIZE_T i = 0; i < other.m_attachments.getCount(); i++) add(other.m_attachments[i]); @@ -778,7 +934,7 @@ class AttachmentsRefHolder return *this; } - ~AttachmentsRefHolder() + void clear() { while (m_attachments.hasData()) { @@ -786,6 +942,11 @@ class AttachmentsRefHolder } } + ~AttachmentsRefHolder() + { + clear(); + } + void add(StableAttachmentPart* jAtt) { if (jAtt) @@ -795,9 +956,9 @@ class AttachmentsRefHolder } } - void remove(Iterator& iter) + bool hasData() const { - iter.remove(); + return m_attachments.hasData(); } private: diff --git a/src/jrd/Coercion.cpp b/src/jrd/Coercion.cpp index 2efd29cf28f..8d635bfd580 100644 --- a/src/jrd/Coercion.cpp +++ b/src/jrd/Coercion.cpp @@ -32,6 +32,7 @@ #include "../dsql/dsql.h" #include "../dsql/make_proto.h" #include "../jrd/align.h" +#include "../jrd/DataTypeUtil.h" using namespace Jrd; using namespace Firebird; @@ -41,12 +42,12 @@ static const USHORT FROM_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | static const USHORT TO_MASK = FLD_has_len | FLD_has_chset | FLD_has_scale | FLD_legacy | FLD_native | FLD_has_sub | FLD_has_prec | FLD_extended; -bool CoercionArray::coerce(dsc* d, unsigned startItem) const +bool CoercionArray::coerce(thread_db* tdbb, dsc* d, unsigned startItem) const { // move down through array to ensure correct order: newer rule overrides older one for (unsigned n = getCount(); n-- > startItem; ) { - if (getElement(n).coerce(d)) + if (getElement(n).coerce(tdbb, d)) return true; } @@ -111,15 +112,30 @@ void CoercionRule::setRule(const TypeClause* from, const TypeClause *to) raiseError(); // Generic check + class BufSize + { + public: + static constexpr unsigned makeSize(unsigned len) + { + return (len + FB_ALIGNMENT) * 2; + } + }; + const unsigned DATASIZE = 256; - UCHAR buf[DATASIZE * 2 + FB_ALIGNMENT]; - memset(buf, 0, sizeof buf); + HalfStaticArray buffer; + + unsigned datasize = MAX(toMask & FLD_has_len ? toDsc.dsc_length : 0, + fromMask & FLD_has_len ? fromDsc.dsc_length : 0); + datasize = MAX(DATASIZE, datasize); + UCHAR* buf = buffer.getBuffer(BufSize::makeSize(datasize)); + memset(buf, 0, buffer.getCount()); + toDsc.dsc_address = FB_ALIGN(buf, FB_ALIGNMENT); if (! (toMask & FLD_has_len)) { - toDsc.dsc_length = DATASIZE - 2; + toDsc.dsc_length = datasize - 2; } - fromDsc.dsc_address = toDsc.dsc_address + DATASIZE; + fromDsc.dsc_address = FB_ALIGN(toDsc.dsc_address + datasize, FB_ALIGNMENT); try { @@ -224,7 +240,7 @@ static const USHORT subTypeCompatibility[DTYPE_TYPE_MAX] = }; -bool CoercionRule::coerce(dsc* d) const +bool CoercionRule::coerce(thread_db* tdbb, dsc* d) const { // check does descriptor match FROM clause if (! match(d)) @@ -295,6 +311,8 @@ bool CoercionRule::coerce(dsc* d) const // final pass - order is important + const auto srcCharSet = d->getCharSet(); + // scale if (toMask & FLD_has_scale) d->dsc_scale = toDsc.dsc_scale; @@ -319,25 +337,31 @@ bool CoercionRule::coerce(dsc* d) const subTypeCompatibility[d->dsc_dtype] != COMPATIBLE_INT || subTypeCompatibility[toDsc.dsc_dtype] != COMPATIBLE_INT) { - if (!type_lengths[toDsc.dsc_dtype]) + if (!(toMask & FLD_has_len)) { - fb_assert(toDsc.isText()); - d->dsc_length = d->getStringLength(); + if (!type_lengths[toDsc.dsc_dtype]) + { + fb_assert(toDsc.isText()); + d->dsc_length = d->getStringLength(); + } + else + d->dsc_length = type_lengths[toDsc.dsc_dtype]; } - else - d->dsc_length = type_lengths[toDsc.dsc_dtype]; d->dsc_dtype = toDsc.dsc_dtype; } - // varchar length - if (d->dsc_dtype == dtype_varying) - d->dsc_length += sizeof(USHORT); - // charset if (toMask & FLD_has_chset) d->setTextType(toDsc.getTextType()); + if (d->isText()) + d->dsc_length = DataTypeUtil(tdbb).convertLength(d->dsc_length, srcCharSet, toDsc.getCharSet()); + + // varchar length + if (d->dsc_dtype == dtype_varying && !(toMask & FLD_has_len)) + d->dsc_length += sizeof(USHORT); + // subtype - special processing for BLOBs if (toMask & FLD_has_sub) d->setBlobSubType(toDsc.getBlobSubType()); diff --git a/src/jrd/Coercion.h b/src/jrd/Coercion.h index e4f58d4271a..f0a36824adf 100644 --- a/src/jrd/Coercion.h +++ b/src/jrd/Coercion.h @@ -50,7 +50,7 @@ class CoercionRule void setRule(const TypeClause* from, const TypeClause *to); dsc* makeLegacy(USHORT mask = 0); - bool coerce(dsc* d) const; + bool coerce(thread_db* tdbb, dsc* d) const; bool match(const dsc* d) const; bool operator==(const CoercionRule& rule) const; @@ -68,7 +68,7 @@ class CoercionArray : public Firebird::HalfStaticArray { } - bool coerce(dsc* d, unsigned startItem = 0) const; + bool coerce(thread_db* tdbb, dsc* d, unsigned startItem = 0) const; void setRule(const TypeClause* from, const TypeClause *to); }; diff --git a/src/jrd/Collation.cpp b/src/jrd/Collation.cpp index c535dcca347..68cb602471a 100644 --- a/src/jrd/Collation.cpp +++ b/src/jrd/Collation.cpp @@ -444,15 +444,21 @@ template class StartsMatcher : public PatternMatcher { public: - StartsMatcher(MemoryPool& pool, TextType* ttype, const CharType* str, SLONG str_len) + StartsMatcher(MemoryPool& pool, TextType* ttype, const CharType* str, SLONG str_len, SLONG aByteLengthLimit) : PatternMatcher(pool, ttype), evaluator(pool, str, str_len) { + auto charSet = ttype->getCharSet(); + + byteLengthLimit = charSet->isMultiByte() ? + aByteLengthLimit / charSet->minBytesPerChar() * charSet->maxBytesPerChar() : + aByteLengthLimit; } void reset() { evaluator.reset(); + processedByteLength = 0; } bool result() @@ -462,8 +468,14 @@ class StartsMatcher : public PatternMatcher bool process(const UCHAR* str, SLONG length) { + if (processedByteLength + length > byteLengthLimit) + length = byteLengthLimit - processedByteLength; + + processedByteLength += length; + StrConverter cvt(pool, textType, str, length); fb_assert(length % sizeof(CharType) == 0); + return evaluator.processNextChunk( reinterpret_cast(str), length / sizeof(CharType)); } @@ -471,27 +483,45 @@ class StartsMatcher : public PatternMatcher static StartsMatcher* create(MemoryPool& pool, TextType* ttype, const UCHAR* str, SLONG length) { + const auto byteLengthLimit = length; + StrConverter cvt(pool, ttype, str, length); fb_assert(length % sizeof(CharType) == 0); + return FB_NEW_POOL(pool) StartsMatcher(pool, ttype, - reinterpret_cast(str), length / sizeof(CharType)); + reinterpret_cast(str), length / sizeof(CharType), byteLengthLimit); } static bool evaluate(MemoryPool& pool, TextType* ttype, const UCHAR* s, SLONG sl, const UCHAR* p, SLONG pl) { + if (sl > pl) + { + auto charSet = ttype->getCharSet(); + + sl = charSet->isMultiByte() ? + MIN(sl, pl / charSet->minBytesPerChar() * charSet->maxBytesPerChar()) : + pl; + } + StrConverter cvt1(pool, ttype, p, pl); - StrConverter cvt2(pool, ttype, s, sl); fb_assert(pl % sizeof(CharType) == 0); + + StrConverter cvt2(pool, ttype, s, sl); fb_assert(sl % sizeof(CharType) == 0); + Firebird::StartsEvaluator evaluator(pool, reinterpret_cast(p), pl / sizeof(CharType)); + evaluator.processNextChunk(reinterpret_cast(s), sl / sizeof(CharType)); + return evaluator.getResult(); } private: Firebird::StartsEvaluator evaluator; + SLONG byteLengthLimit; + SLONG processedByteLength = 0; }; template > > diff --git a/src/jrd/ConfigTable.cpp b/src/jrd/ConfigTable.cpp index 6147fb2262c..5f7f6344b7b 100644 --- a/src/jrd/ConfigTable.cpp +++ b/src/jrd/ConfigTable.cpp @@ -49,7 +49,7 @@ RecordBuffer* ConfigTable::getRecords(thread_db* tdbb, jrd_rel* relation) // Check privileges to see RDB$CONFIG const Attachment* att = tdbb->getAttachment(); - if (!att->att_user->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE)) + if (!att->getEffectiveUserId()->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE)) return recordBuffer; for (unsigned int key = 0; key < Config::getKeyCount(); key++) diff --git a/src/jrd/CryptoManager.cpp b/src/jrd/CryptoManager.cpp index 757f4d4677d..baf98d44057 100644 --- a/src/jrd/CryptoManager.cpp +++ b/src/jrd/CryptoManager.cpp @@ -201,9 +201,9 @@ namespace Jrd { Jrd::BufferDesc bdb(bcb); bdb.bdb_page = Jrd::HEADER_PAGE_NUMBER; - UCHAR* h = FB_NEW_POOL(*Firebird::MemoryPool::getContextPool()) UCHAR[dbb->dbb_page_size + PAGE_ALIGNMENT]; + UCHAR* h = FB_NEW_POOL(*MemoryPool::getContextPool()) UCHAR[dbb->dbb_page_size + dbb->getIOBlockSize()]; buffer.reset(h); - h = FB_ALIGN(h, PAGE_ALIGNMENT); + h = FB_ALIGN(h, dbb->getIOBlockSize()); bdb.bdb_buffer = (Ods::pag*) h; Jrd::FbStatusVector* const status = tdbb->tdbb_status_vector; @@ -226,7 +226,29 @@ namespace Jrd { if (bak_state != Ods::hdr_nbak_normal) diff_page = bm->getPageIndex(tdbb, bdb.bdb_page.getPageNum()); + bool readPageAsNormal = false; if (bak_state == Ods::hdr_nbak_normal || !diff_page) + readPageAsNormal = true; + else + { + if (!bm->readDifference(tdbb, diff_page, page)) + { + if (page->pag_type == 0 && page->pag_generation == 0 && page->pag_scn == 0) + { + // We encountered a page which was allocated, but never written to the + // difference file. In this case we try to read the page from database. With + // this approach if the page was old we get it from DISK, and if the page + // was new IO error (EOF) or BUGCHECK (checksum error) will be the result. + // Engine is not supposed to read a page which was never written unless + // this is a merge process. + readPageAsNormal = true; + } + else + ERR_punt(); + } + } + + if (readPageAsNormal) { // Read page from disk as normal int retryCount = 0; @@ -248,11 +270,6 @@ namespace Jrd { } } } - else - { - if (!bm->readDifference(tdbb, diff_page, page)) - ERR_punt(); - } setHeader(h); } @@ -261,16 +278,49 @@ namespace Jrd { AutoPtr buffer; }; + // Ensures that at least one of attachment's syncs (main or async) is locked + class AttachmentAnySyncHolder : public EnsureUnlock + { + public: + AttachmentAnySyncHolder(StableAttachmentPart* sAtt) + : EnsureUnlock(*(sAtt->getSync(true, true)), FB_FUNCTION), + att(sAtt->getHandle()) + { + if (!sAtt->getSync()->locked()) + enter(); + } + + bool hasData() + { + return att; + } + + Attachment* operator->() + { + return att; + } + + operator Attachment*() + { + return att; + } + + private: + Attachment* att; + }; + + CryptoManager::CryptoManager(thread_db* tdbb) : PermanentStorage(*tdbb->getDatabase()->dbb_permanent), sync(this), keyName(getPool()), pluginName(getPool()), + currentPage(0), keyProviders(getPool()), keyConsumers(getPool()), hash(getPool()), dbInfo(FB_NEW DbInfo(this)), - cryptThreadId(0), + cryptThreadHandle(0), cryptPlugin(NULL), checkFactory(NULL), dbb(*tdbb->getDatabase()), @@ -288,8 +338,8 @@ namespace Jrd { CryptoManager::~CryptoManager() { - if (cryptThreadId) - Thread::waitForCompletion(cryptThreadId); + if (cryptThreadHandle) + Thread::waitForCompletion(cryptThreadHandle); delete stateLock; delete threadLock; @@ -318,7 +368,7 @@ namespace Jrd { return; fb_assert(tdbb); - lockAndReadHeader(tdbb, CRYPT_HDR_NOWAIT); + lockAndReadHeader(tdbb, CRYPT_HDR_NOWAIT | CRYPT_RELOAD_PLUGIN); } void CryptoManager::lockAndReadHeader(thread_db* tdbb, unsigned flags) @@ -357,9 +407,15 @@ namespace Jrd { crypt = hdr->hdr_flags & Ods::hdr_encrypted; process = hdr->hdr_flags & Ods::hdr_crypt_process; + if (flags & CRYPT_RELOAD_PLUGIN && cryptPlugin) + { + PluginManagerInterfacePtr()->releasePlugin(cryptPlugin); + cryptPlugin = NULL; + } + // tdbb w/o attachment comes when database is shutting down in the end of detachDatabase() // the only needed here page is header, i.e. we can live w/o cryptPlugin - if ((crypt || process) && (!cryptPlugin) && tdbb->getAttachment()) + if ((crypt || process) && !cryptPlugin && tdbb->getAttachment()) { ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size); hdr.getClumplets(hc); @@ -370,7 +426,6 @@ namespace Jrd { loadPlugin(tdbb, hdr->hdr_crypt_plugin); pluginName = hdr->hdr_crypt_plugin; - string valid; calcValidation(valid, cryptPlugin); if (hc.find(Ods::HDR_crypt_hash)) @@ -444,7 +499,7 @@ namespace Jrd { if (!keyPlugin->useOnlyOwnKeys(&st)) { MutexLockGuard g(holdersMutex, FB_FUNCTION); - keyProviders.push(tdbb->getAttachment()); + keyProviders.add(tdbb->getAttachment()->getStable()); } fLoad = true; break; @@ -484,7 +539,7 @@ namespace Jrd { checkFactory = NULL; // store new one - if (dbb.dbb_config->getServerMode() == MODE_SUPER && !holderLess) + if (!holderLess) checkFactory = cryptControl.release(); } @@ -579,6 +634,20 @@ namespace Jrd { try { + // Create local copy of existing attachments + Sync dSync(&dbb.dbb_sync, FB_FUNCTION); + dSync.lock(SYNC_EXCLUSIVE); + + AttachmentsRefHolder existing; + { + MutexLockGuard g(holdersMutex, FB_FUNCTION); + for (Attachment* att = dbb.dbb_attachments; att; att = att->att_next) + existing.add(att->getStable()); + } + + dSync.unlock(); + + // Disable cache I/O BarSync::LockGuard writeGuard(tdbb, sync); // header scope @@ -641,27 +710,50 @@ namespace Jrd { if (checkFactory) { - // Create local copy of existing attachments - AttVector existing; + // Loop through attachments + for (AttachmentsRefHolder::Iterator iter(existing); *iter; ++iter) { - SyncLockGuard dsGuard(&dbb.dbb_sync, SYNC_EXCLUSIVE, FB_FUNCTION); - for (Attachment* att = dbb.dbb_attachments; att; att = att->att_next) - existing.push(att); + AttachmentAnySyncHolder a(*iter); + if (a.hasData()) + validateAttachment(tdbb, a, true); } - // Loop through attachments - MutexLockGuard g(holdersMutex, FB_FUNCTION); - - for (unsigned n = 0; n < existing.getCount(); ++n) - validateAttachment(tdbb, existing[n], true); - // In case of missing providers close consumers - if (keyProviders.getCount() == 0) + if (!keyProviders.hasData()) shutdownConsumers(tdbb); } } else + { + for (GetPlugins keyControl(IPluginManager::TYPE_KEY_HOLDER, dbb.dbb_config); + keyControl.hasData(); keyControl.next()) + { + // check does keyHolder want to provide a key for us + IKeyHolderPlugin* keyHolder = keyControl.plugin(); + + FbLocalStatus st; + int keyCallbackRc = keyHolder->keyCallback(&st, tdbb->getAttachment()->att_crypt_callback); + st.check(); + if (!keyCallbackRc) + continue; + + // validate a key + AutoPlugin crypt(checkFactory->makeInstance()); + setDbInfo(crypt); + crypt->setKey(&st, 1, &keyHolder, keyName.c_str()); + + + string valid; + calcValidation(valid, crypt); + if (hc.find(Ods::HDR_crypt_hash)) + { + hc.getString(hash); + if (hash != valid) + (Arg::Gds(isc_bad_crypt_key) << keyName).raise(); + } + } header->hdr_flags &= ~Ods::hdr_encrypted; + } hdr.setClumplets(hc); @@ -704,20 +796,29 @@ namespace Jrd { { MutexLockGuard g(holdersMutex, FB_FUNCTION); - for (unsigned i = 0; i < keyConsumers.getCount(); ++i) - keyConsumers[i]->signalShutdown(isc_db_crypt_key); + for (AttachmentsRefHolder::Iterator iter(keyConsumers); *iter; ++iter) + { + AttachmentAnySyncHolder a(*iter); + if (a.hasData()) + a->signalShutdown(isc_db_crypt_key); + } keyConsumers.clear(); } void CryptoManager::blockingAstChangeCryptState() { - AsyncContextHolder tdbb(&dbb, FB_FUNCTION); - - if (stateLock->lck_physical != CRYPT_CHANGE && stateLock->lck_physical != CRYPT_INIT) + try { - sync.ast(tdbb); + AsyncContextHolder tdbb(&dbb, FB_FUNCTION); + + if (stateLock->lck_physical != CRYPT_CHANGE && stateLock->lck_physical != CRYPT_INIT) + { + sync.ast(tdbb); + } } + catch (const Exception&) + { } } void CryptoManager::doOnAst(thread_db* tdbb) @@ -763,11 +864,12 @@ namespace Jrd { } // Apply results + MutexLockGuard g(holdersMutex, FB_FUNCTION); if (fProvide) - keyProviders.push(att); + keyProviders.add(att->getStable()); else if (consume && !fLoad) - keyConsumers.push(att); + keyConsumers.add(att->getStable()); return fLoad; } @@ -776,14 +878,13 @@ namespace Jrd { { if (checkFactory) { - MutexLockGuard g(holdersMutex, FB_FUNCTION); - if (!validateAttachment(tdbb, att, false)) { - if (keyProviders.getCount() == 0) - Arg::Gds(isc_db_crypt_key).raise(); + MutexLockGuard g(holdersMutex, FB_FUNCTION); - keyConsumers.push(att); + if (!keyProviders.hasData()) + Arg::Gds(isc_db_crypt_key).raise(); + keyConsumers.add(att->getStable()); } } @@ -796,21 +897,25 @@ namespace Jrd { return; MutexLockGuard g(holdersMutex, FB_FUNCTION); - for (unsigned n = 0; n < keyConsumers.getCount(); ++n) + for (AttachmentsRefHolder::Iterator iter(keyConsumers); *iter; ++iter) { - if (keyConsumers[n] == att) + StableAttachmentPart* const sAtt = *iter; + + if (sAtt->getHandle() == att) { - keyConsumers.remove(n); + iter.remove(); return; } } - for (unsigned n = 0; n < keyProviders.getCount(); ++n) + for (AttachmentsRefHolder::Iterator iter(keyProviders); *iter; ++iter) { - if (keyProviders[n] == att) + StableAttachmentPart* const sAtt = *iter; + + if (sAtt->getHandle() == att) { - keyProviders.remove(n); - if (keyProviders.getCount() == 0) + iter.remove(); + if (!keyProviders.hasData()) shutdownConsumers(tdbb); return; } @@ -820,10 +925,10 @@ namespace Jrd { void CryptoManager::terminateCryptThread(thread_db*, bool wait) { flDown = true; - if (wait && cryptThreadId) + if (wait && cryptThreadHandle) { - Thread::waitForCompletion(cryptThreadId); - cryptThreadId = 0; + Thread::waitForCompletion(cryptThreadHandle); + cryptThreadHandle = 0; } } @@ -850,7 +955,7 @@ namespace Jrd { if (!LCK_lock(tdbb, threadLock, LCK_EX, LCK_NO_WAIT)) { // Cleanup lock manager error - fb_utils::init_status(tdbb->tdbb_status_vector); + tdbb->tdbb_status_vector->init(); return; } @@ -882,7 +987,7 @@ namespace Jrd { // ready to go guard.leave(); // release in advance to avoid races with cryptThread() - Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, THREAD_medium, &cryptThreadId); + Thread::start(cryptThreadStatic, (THREAD_ENTRY_PARAM) this, THREAD_medium, &cryptThreadHandle); } catch (const Firebird::Exception&) { @@ -915,36 +1020,13 @@ namespace Jrd { return; } - // Establish temp context - // Needed to take crypt thread lock - UserId user; - user.setUserName("Database Crypter"); - - Jrd::Attachment* const attachment = Jrd::Attachment::create(&dbb, nullptr); - RefPtr sAtt(FB_NEW SysStableAttachment(attachment)); - attachment->setStable(sAtt); - attachment->att_filename = dbb.dbb_filename; - attachment->att_user = &user; - - BackgroundContextHolder tempDbb(&dbb, attachment, &status_vector, FB_FUNCTION); - - LCK_init(tempDbb, LCK_OWNER_attachment); - PAG_header(tempDbb, true); - PAG_attachment_id(tempDbb); - - Monitoring::publishAttachment(tempDbb); - - sAtt->initDone(); + // Establish temp context needed to take crypt thread lock + ThreadContextHolder tempDbb(&dbb, nullptr, &status_vector); // Take exclusive threadLock // If can't take that lock - nothing to do, cryptThread already runs somewhere if (!LCK_lock(tempDbb, threadLock, LCK_EX, LCK_NO_WAIT)) - { - Monitoring::cleanupAttachment(tempDbb); - attachment->releaseLocks(tempDbb); - LCK_fini(tempDbb, LCK_OWNER_attachment); return; - } try { @@ -971,7 +1053,7 @@ namespace Jrd { dbb.dbb_database_name.c_str(), writer.getBufferLength(), writer.getBuffer())); check(&status_vector); - MutexLockGuard attGuard(*(jAtt->getStable()->getMutex()), FB_FUNCTION); + AttSyncLockGuard attGuard(*(jAtt->getStable()->getSync()), FB_FUNCTION); Attachment* att = jAtt->getHandle(); if (!att) Arg::Gds(isc_att_shutdown).raise(); @@ -982,23 +1064,7 @@ namespace Jrd { tdbb->markAsSweeper(); DatabaseContextHolder dbHolder(tdbb); - - class UseCountHolder - { - public: - explicit UseCountHolder(Attachment* a) - : att(a) - { - att->att_use_count++; - } - ~UseCountHolder() - { - att->att_use_count--; - } - private: - Attachment* att; - }; - UseCountHolder use_count(att); + Attachment::UseCountHolder use_count(att); // get ready... AutoSetRestore attSet(&cryptAtt, att); @@ -1073,9 +1139,6 @@ namespace Jrd { // Release exclusive lock on StartCryptThread lckRelease = true; LCK_release(tempDbb, threadLock); - Monitoring::cleanupAttachment(tempDbb); - attachment->releaseLocks(tempDbb); - LCK_fini(tempDbb, LCK_OWNER_attachment); } catch (const Exception&) { @@ -1085,9 +1148,6 @@ namespace Jrd { { // Release exclusive lock on StartCryptThread LCK_release(tempDbb, threadLock); - Monitoring::cleanupAttachment(tempDbb); - attachment->releaseLocks(tempDbb); - LCK_fini(tempDbb, LCK_OWNER_attachment); } } catch (const Exception&) @@ -1322,9 +1382,16 @@ namespace Jrd { return 0; } - ULONG CryptoManager::getCurrentPage() const + ULONG CryptoManager::getCurrentPage(thread_db* tdbb) const { - return process ? currentPage : 0; + if (!process) + return 0; + + if (currentPage) + return currentPage; + + CchHdr hdr(tdbb, LCK_read); + return hdr->hdr_crypt_page; } ULONG CryptoManager::getLastPage(thread_db* tdbb) @@ -1332,9 +1399,19 @@ namespace Jrd { return PAG_last_page(tdbb) + 1; } - UCHAR CryptoManager::getCurrentState() const + UCHAR CryptoManager::getCurrentState(thread_db* tdbb) const { - return (crypt ? fb_info_crypt_encrypted : 0) | (process ? fb_info_crypt_process : 0); + bool p = process; + bool c = crypt; + if (!currentPage) + { + CchHdr hdr(tdbb, LCK_read); + + p = hdr->hdr_flags & Ods::hdr_crypt_process; + c = hdr->hdr_flags & Ods::hdr_encrypted; + } + + return (c ? fb_info_crypt_encrypted : 0) | (p ? fb_info_crypt_process : 0); } const char* CryptoManager::getKeyName() const diff --git a/src/jrd/CryptoManager.h b/src/jrd/CryptoManager.h index adc637ff7ff..334f9cbe0e8 100644 --- a/src/jrd/CryptoManager.h +++ b/src/jrd/CryptoManager.h @@ -36,6 +36,7 @@ #include "../common/classes/objects_array.h" #include "../common/classes/condition.h" #include "../jrd/MetaName.h" +#include "../jrd/Attachment.h" #include "../common/classes/GetPlugins.h" #include "../common/ThreadStart.h" #include "../jrd/ods.h" @@ -266,7 +267,6 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync { public: typedef Firebird::GetPlugins Factory; - typedef Firebird::HalfStaticArray AttVector; explicit CryptoManager(thread_db* tdbb); ~CryptoManager(); @@ -297,10 +297,14 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync bool checkValidation(Firebird::IDbCryptPlugin* crypt); void setDbInfo(Firebird::IDbCryptPlugin* cp); - ULONG getCurrentPage() const; - UCHAR getCurrentState() const; + ULONG getCurrentPage(thread_db* tdbb) const; + UCHAR getCurrentState(thread_db* tdbb) const; const char* getKeyName() const; const char* getPluginName() const; + Thread::Handle getCryptThreadHandle() const + { + return cryptThreadHandle; + } private: enum IoResult {SUCCESS_ALL, FAILED_CRYPT, FAILED_IO}; @@ -312,16 +316,16 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync public: operator Ods::pag*() { - return reinterpret_cast(FB_ALIGN(buf, PAGE_ALIGNMENT)); + return reinterpret_cast(buf); } Ods::pag* operator->() { - return reinterpret_cast(FB_ALIGN(buf, PAGE_ALIGNMENT)); + return reinterpret_cast(buf); } private: - char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1]; + alignas(DIRECT_IO_BLOCK_SIZE) char buf[MAX_PAGE_SIZE]; }; class DbInfo; @@ -364,6 +368,7 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync void lockAndReadHeader(thread_db* tdbb, unsigned flags = 0); static const unsigned CRYPT_HDR_INIT = 0x01; static const unsigned CRYPT_HDR_NOWAIT = 0x02; + static const unsigned CRYPT_RELOAD_PLUGIN = 0x04; void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag); void calcDigitalSignature(thread_db* tdbb, Firebird::string& signature, const class Header& hdr); @@ -374,10 +379,10 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync MetaName keyName, pluginName; ULONG currentPage; Firebird::Mutex pluginLoadMtx, cryptThreadMtx, holdersMutex; - AttVector keyProviders, keyConsumers; + AttachmentsRefHolder keyProviders, keyConsumers; Firebird::string hash; Firebird::RefPtr dbInfo; - Thread::Handle cryptThreadId; + Thread::Handle cryptThreadHandle; Firebird::IDbCryptPlugin* cryptPlugin; Factory* checkFactory; Database& dbb; diff --git a/src/jrd/DataTypeUtil.cpp b/src/jrd/DataTypeUtil.cpp index b6fef634c0d..581ab201352 100644 --- a/src/jrd/DataTypeUtil.cpp +++ b/src/jrd/DataTypeUtil.cpp @@ -172,12 +172,7 @@ void DataTypeUtilBase::makeFromList(dsc* result, const char* expressionName, int if (result->isUnknown()) *result = *arg; else if (result->dsc_dtype != arg->dsc_dtype) - { - // Datatypes @1are not comparable in expression @2 - status_exception::raise(Arg::Gds(isc_sqlerr) << Arg::Num(-104) << - Arg::Gds(isc_dsql_datatypes_not_comparable) << Arg::Str("") << - Arg::Str(expressionName)); - } + makeBlobOrText(result, arg, true); } else // we don't support this datatype here { diff --git a/src/jrd/Database.cpp b/src/jrd/Database.cpp index 36f59fcd590..f2e4f61b66a 100644 --- a/src/jrd/Database.cpp +++ b/src/jrd/Database.cpp @@ -55,6 +55,14 @@ namespace Jrd return pageSpace->onRawDevice(); } + ULONG Database::getIOBlockSize() const + { + if ((dbb_flags & DBB_no_fs_cache) || onRawDevice()) + return DIRECT_IO_BLOCK_SIZE; + + return PAGE_ALIGNMENT; + } + AttNumber Database::generateAttachmentId() { fb_assert(dbb_tip_cache); @@ -452,14 +460,86 @@ namespace Jrd void Database::initGlobalObjects() { - dbb_gblobj_holder = - GlobalObjectHolder::init(getUniqueFileId(), dbb_filename, dbb_config); + dbb_gblobj_holder.assignRefNoIncr(GlobalObjectHolder::init(getUniqueFileId(), + dbb_filename, dbb_config)); + } + + void Database::startTipCache(thread_db* tdbb) + { + fb_assert(!dbb_tip_cache); + + TipCache* cache = FB_NEW_POOL(*dbb_permanent) TipCache(this); + try + { + cache->initializeTpc(tdbb); + } + catch(const Exception&) + { + cache->finalizeTpc(tdbb); + delete cache; + throw; + } + + dbb_tip_cache = cache; + } + + // Methods encapsulating operations with vectors of known pages + + ULONG Database::getKnownPagesCount(SCHAR ptype) + { + fb_assert(ptype == pag_transactions || ptype == pag_ids); + + SyncLockGuard guard(&dbb_pages_sync, SYNC_SHARED, FB_FUNCTION); + + const auto vector = + (ptype == pag_transactions) ? dbb_tip_pages : + (ptype == pag_ids) ? dbb_gen_pages : + nullptr; + + return vector ? (ULONG) vector->count() : 0; } - void Database::shutdownGlobalObjects() + ULONG Database::getKnownPage(SCHAR ptype, ULONG sequence) { - if (dbb_gblobj_holder) - dbb_gblobj_holder->shutdown(); + fb_assert(ptype == pag_transactions || ptype == pag_ids); + + SyncLockGuard guard(&dbb_pages_sync, SYNC_SHARED, FB_FUNCTION); + + const auto vector = + (ptype == pag_transactions) ? dbb_tip_pages : + (ptype == pag_ids) ? dbb_gen_pages : + nullptr; + + if (!vector || sequence >= vector->count()) + return 0; + + return (*vector)[sequence]; + } + + void Database::setKnownPage(SCHAR ptype, ULONG sequence, ULONG value) + { + fb_assert(ptype == pag_transactions || ptype == pag_ids); + + SyncLockGuard guard(&dbb_pages_sync, SYNC_EXCLUSIVE, FB_FUNCTION); + + auto& rvector = (ptype == pag_transactions) ? dbb_tip_pages : dbb_gen_pages; + + rvector = vcl::newVector(*dbb_permanent, rvector, sequence + 1); + + (*rvector)[sequence] = value; + } + + void Database::copyKnownPages(SCHAR ptype, ULONG count, ULONG* data) + { + fb_assert(ptype == pag_transactions || ptype == pag_ids); + + SyncLockGuard guard(&dbb_pages_sync, SYNC_EXCLUSIVE, FB_FUNCTION); + + auto& rvector = (ptype == pag_transactions) ? dbb_tip_pages : dbb_gen_pages; + + rvector = vcl::newVector(*dbb_permanent, rvector, count); + + memcpy(rvector->memPtr(), data, count * sizeof(ULONG)); } // Database::Linger class implementation @@ -499,6 +579,15 @@ namespace Jrd // Database::GlobalObjectHolder class implementation + int Database::GlobalObjectHolder::release() const + { + // Release should be executed under g_mutex protection + // in order to modify reference counter & hash table atomically + MutexLockGuard guard(g_mutex, FB_FUNCTION); + + return RefCounted::release(); + } + Database::GlobalObjectHolder* Database::GlobalObjectHolder::init(const string& id, const PathName& filename, RefPtr config) @@ -513,26 +602,31 @@ namespace Jrd g_hashTable->add(entry); } + entry->holder->addRef(); return entry->holder; } Database::GlobalObjectHolder::~GlobalObjectHolder() { - MutexLockGuard guard(g_mutex, FB_FUNCTION); - + // dtor is executed under g_mutex protection + Database::GlobalObjectHolder::DbId* entry = g_hashTable->lookup(m_id); if (!g_hashTable->remove(m_id)) fb_assert(false); - // these objects should be deleted under g_mutex protection + { // scope + // here we cleanup what should not be globally protected + MutexUnlockGuard guard(g_mutex, FB_FUNCTION); + if (m_replMgr) + m_replMgr->shutdown(); + } + m_lockMgr = nullptr; m_eventMgr = nullptr; m_replMgr = nullptr; - } - void Database::GlobalObjectHolder::shutdown() - { - if (m_replMgr) - m_replMgr->shutdown(); + delete entry; + + fb_assert(m_tempCacheUsage == 0); } LockManager* Database::GlobalObjectHolder::getLockManager() @@ -574,6 +668,28 @@ namespace Jrd return m_replMgr; } + bool Database::GlobalObjectHolder::incTempCacheUsage(FB_SIZE_T size) + { + if (m_tempCacheUsage + size > m_tempCacheLimit) + return false; + + const auto old = m_tempCacheUsage.fetch_add(size); + if (old + size > m_tempCacheLimit) + { + m_tempCacheUsage.fetch_sub(size); + return false; + } + + return true; + } + + void Database::GlobalObjectHolder::decTempCacheUsage(FB_SIZE_T size) + { + fb_assert(m_tempCacheUsage >= size); + + m_tempCacheUsage.fetch_sub(size); + } + GlobalPtr Database::GlobalObjectHolder::g_hashTable; GlobalPtr Database::GlobalObjectHolder::g_mutex; diff --git a/src/jrd/Database.h b/src/jrd/Database.h index bc491f8805a..e7a732f8ebc 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -305,9 +305,9 @@ class Database : public pool_alloc const Firebird::PathName& filename, Firebird::RefPtr config); - ~GlobalObjectHolder(); + int release() const override; - void shutdown(); + ~GlobalObjectHolder(); LockManager* getLockManager(); EventManager* getEventManager(); @@ -318,6 +318,9 @@ class Database : public pool_alloc return m_replConfig.get(); } + bool incTempCacheUsage(FB_SIZE_T size); + void decTempCacheUsage(FB_SIZE_T size); + private: const Firebird::string m_id; const Firebird::RefPtr m_config; @@ -326,12 +329,16 @@ class Database : public pool_alloc Firebird::AutoPtr m_eventMgr; Firebird::AutoPtr m_replMgr; Firebird::Mutex m_mutex; + std::atomic m_tempCacheUsage; // total size of in-memory temp space chunks (see TempSpace class) + const FB_UINT64 m_tempCacheLimit; explicit GlobalObjectHolder(const Firebird::string& id, const Firebird::PathName& filename, Firebird::RefPtr config) : m_id(getPool(), id), m_config(config), - m_replConfig(Replication::Config::get(filename)) + m_replConfig(Replication::Config::get(filename)), + m_tempCacheUsage(0), + m_tempCacheLimit(m_config->getTempCacheLimit()) {} }; @@ -451,8 +458,6 @@ class Database : public pool_alloc Lock* dbb_retaining_lock; // lock for preserving commit retaining snapshot PageManager dbb_page_manager; - vcl* dbb_t_pages; // pages number for transactions - vcl* dbb_gen_id_pages; // known pages for gen_id BlobFilter* dbb_blob_filters; // known blob filters MonitoringData* dbb_monitoring_data; // monitoring data @@ -463,6 +468,10 @@ class Database : public pool_alloc Firebird::SyncObject dbb_modules_sync; DatabaseModules dbb_modules; // external function/filter modules + // Vectors of known pages and their synchronization + Firebird::SyncObject dbb_pages_sync; // guard access to dbb_XXX_pages vectors + vcl* dbb_tip_pages; // known TIP pages + vcl* dbb_gen_pages; // known generator pages public: Firebird::AutoPtr dbb_extManager; // external engine manager @@ -495,9 +504,6 @@ class Database : public pool_alloc Firebird::SyncObject dbb_sortbuf_sync; Firebird::Array dbb_sort_buffers; // sort buffers ready for reuse - Firebird::Mutex dbb_temp_cache_mutex; - FB_UINT64 dbb_temp_cache_size; // total size of in-memory temp space chunks (see TempSpace class) - TraNumber dbb_oldest_active; // Cached "oldest active" transaction TraNumber dbb_oldest_transaction; // Cached "oldest interesting" transaction TraNumber dbb_oldest_snapshot; // Cached "oldest snapshot" of all active transactions @@ -553,6 +559,9 @@ class Database : public pool_alloc // returns an unique ID string for a database file const Firebird::string& getUniqueFileId(); + // returns the minimum IO block size + ULONG getIOBlockSize() const; + #ifdef DEV_BUILD // returns true if main lock is in exclusive state bool locked() const @@ -584,6 +593,12 @@ class Database : public pool_alloc return (dbb_replica_mode == mode); } + // Methods encapsulating operations with vectors of known pages + ULONG getKnownPagesCount(SCHAR ptype); + ULONG getKnownPage(SCHAR ptype, ULONG sequence); + void setKnownPage(SCHAR ptype, ULONG sequence, ULONG value); + void copyKnownPages(SCHAR ptype, ULONG count, ULONG* data); + private: Database(MemoryPool* p, Firebird::IPluginConfig* pConf, bool shared) : dbb_permanent(p), @@ -659,6 +674,7 @@ class Database : public pool_alloc static int replStateAst(void*); const CoercionArray *getBindings() const; + void startTipCache(thread_db* tdbb); void initGlobalObjects(); void shutdownGlobalObjects(); @@ -683,6 +699,16 @@ class Database : public pool_alloc return dbb_gblobj_holder->getReplConfig(); } + bool incTempCacheUsage(FB_SIZE_T size) + { + return dbb_gblobj_holder->incTempCacheUsage(size); + } + + void decTempCacheUsage(FB_SIZE_T size) + { + dbb_gblobj_holder->decTempCacheUsage(size); + } + private: //static int blockingAstSharedCounter(void*); static int blocking_ast_sweep(void* ast_object); diff --git a/src/jrd/DbCreators.cpp b/src/jrd/DbCreators.cpp index de60a5dd65b..8e472fb210b 100644 --- a/src/jrd/DbCreators.cpp +++ b/src/jrd/DbCreators.cpp @@ -124,21 +124,15 @@ bool checkCreateDatabaseGrant(const MetaString& userName, const MetaString& trus check("IAttachment::getInfo", &st); int dialect = SQL_DIALECT_V5; // reasonable default - const UCHAR* p = buffer; - while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer)) - { - const UCHAR item = (UCHAR) *p++; - const USHORT length = gds__vax_integer(p, sizeof(USHORT)); - p += sizeof(USHORT); - switch (item) + for (ClumpletReader p(ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) + { + switch (p.getClumpTag()) { case isc_info_db_sql_dialect: - dialect = gds__vax_integer(p, length); + dialect = p.getInt(); break; } - - p += length; } UserId::makeRoleName(role, dialect); diff --git a/src/jrd/EngineInterface.h b/src/jrd/EngineInterface.h index 72c8f52dea9..e935315837b 100644 --- a/src/jrd/EngineInterface.h +++ b/src/jrd/EngineInterface.h @@ -63,6 +63,8 @@ class JBlob FB_FINAL : void cancel(Firebird::CheckStatusWrapper* status) override; void close(Firebird::CheckStatusWrapper* status) override; int seek(Firebird::CheckStatusWrapper* status, int mode, int offset) override; // returns position + void deprecatedCancel(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; public: JBlob(blb* handle, StableAttachmentPart* sa); @@ -87,6 +89,7 @@ class JBlob FB_FINAL : Firebird::RefPtr sAtt; void freeEngineData(Firebird::CheckStatusWrapper* status); + void internalClose(Firebird::CheckStatusWrapper* status); }; class JTransaction FB_FINAL : @@ -108,6 +111,9 @@ class JTransaction FB_FINAL : Firebird::ITransaction* join(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction) override; JTransaction* validate(Firebird::CheckStatusWrapper* status, Firebird::IAttachment* testAtt) override; JTransaction* enterDtc(Firebird::CheckStatusWrapper* status) override; + void deprecatedCommit(Firebird::CheckStatusWrapper* status) override; + void deprecatedRollback(Firebird::CheckStatusWrapper* status) override; + void deprecatedDisconnect(Firebird::CheckStatusWrapper* status) override; public: JTransaction(jrd_tra* handle, StableAttachmentPart* sa); @@ -140,6 +146,9 @@ class JTransaction FB_FINAL : JTransaction(JTransaction* from); void freeEngineData(Firebird::CheckStatusWrapper* status); + void internalCommit(Firebird::CheckStatusWrapper* status); + void internalRollback(Firebird::CheckStatusWrapper* status); + void internalDisconnect(Firebird::CheckStatusWrapper* status); }; class JResultSet FB_FINAL : @@ -158,6 +167,7 @@ class JResultSet FB_FINAL : FB_BOOLEAN isBof(Firebird::CheckStatusWrapper* status) override; Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status) override; void close(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; void setDelayedOutputFormat(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* format) override; public: @@ -202,6 +212,9 @@ class JBatch FB_FINAL : Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status) override; void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par) override; void close(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; + void getInfo(Firebird::CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) override; public: JBatch(DsqlBatch* handle, JStatement* aStatement, Firebird::IMessageMetadata* aMetadata); @@ -234,6 +247,7 @@ class JReplicator FB_FINAL : int release() override; void process(Firebird::CheckStatusWrapper* status, unsigned length, const unsigned char* data) override; void close(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; public: JReplicator(Applier* appl, StableAttachmentPart* sa); @@ -270,6 +284,7 @@ class JStatement FB_FINAL : unsigned int itemsLength, const unsigned char* items, unsigned int bufferLength, unsigned char* buffer) override; void free(Firebird::CheckStatusWrapper* status) override; + void deprecatedFree(Firebird::CheckStatusWrapper* status) override; ISC_UINT64 getAffectedRecords(Firebird::CheckStatusWrapper* userStatus) override; Firebird::IMessageMetadata* getOutputMetadata(Firebird::CheckStatusWrapper* userStatus) override; Firebird::IMessageMetadata* getInputMetadata(Firebird::CheckStatusWrapper* userStatus) override; @@ -328,6 +343,7 @@ class JRequest FB_FINAL : unsigned int msg_type, unsigned int length, const void* message) override; void unwind(Firebird::CheckStatusWrapper* status, int level) override; void free(Firebird::CheckStatusWrapper* status) override; + void deprecatedFree(Firebird::CheckStatusWrapper* status) override; public: JRequest(JrdStatement* handle, StableAttachmentPart* sa); @@ -355,6 +371,7 @@ class JEvents FB_FINAL : public Firebird::RefCntIfacegetDatabase()) +{ + engine->addRef(); +} + + +//--------------------- + + +ExtEngineManager::Function::Function(thread_db* tdbb, ExtEngineManager* aExtManager, + IExternalEngine* aEngine, RoutineMetadata* aMetadata, IExternalFunction* aFunction, + const Jrd::Function* aUdf) + : ExtRoutine(tdbb, aExtManager, aEngine, aMetadata), + function(aFunction), + udf(aUdf) { } @@ -750,12 +761,9 @@ void ExtEngineManager::Function::execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* o ExtEngineManager::Procedure::Procedure(thread_db* tdbb, ExtEngineManager* aExtManager, IExternalEngine* aEngine, RoutineMetadata* aMetadata, IExternalProcedure* aProcedure, const jrd_prc* aPrc) - : extManager(aExtManager), - engine(aEngine), - metadata(aMetadata), + : ExtRoutine(tdbb, aExtManager, aEngine, aMetadata), procedure(aProcedure), - prc(aPrc), - database(tdbb->getDatabase()) + prc(aPrc) { } @@ -840,15 +848,12 @@ bool ExtEngineManager::ResultSet::fetch(thread_db* tdbb) ExtEngineManager::Trigger::Trigger(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, ExtEngineManager* aExtManager, IExternalEngine* aEngine, RoutineMetadata* aMetadata, IExternalTrigger* aTrigger, const Jrd::Trigger* aTrg) - : computedStatements(pool), - extManager(aExtManager), - engine(aEngine), - metadata(aMetadata), + : ExtRoutine(tdbb, aExtManager, aEngine, aMetadata), + computedStatements(pool), trigger(aTrigger), trg(aTrg), fieldsPos(pool), varDecls(pool), - database(tdbb->getDatabase()), computedCount(0) { jrd_rel* relation = trg->relation; @@ -1130,6 +1135,12 @@ namespace } public: + int release() override + { + // Never delete static instance of SystemEngine + return 1; + } + void open(ThrowStatusExceptionWrapper* status, IExternalContext* context, char* name, unsigned nameSize) override { @@ -1247,25 +1258,28 @@ void ExtEngineManager::closeAttachment(thread_db* tdbb, Attachment* attachment) FbLocalStatus status; engine->closeAttachment(&status, attInfo->context); //// FIXME: log status - // Check whether the engine is used by other attachments. + // Check whether a non-SYSTEM engine is used by other attachments. // If no one uses, release it. - bool close = true; - WriteLockGuard writeGuard(enginesLock, FB_FUNCTION); - - EnginesAttachmentsMap::Accessor ea_accessor(&enginesAttachments); - for (bool ea_found = ea_accessor.getFirst(); ea_found; ea_found = ea_accessor.getNext()) + if (engine != SystemEngine::INSTANCE) { - if (ea_accessor.current()->first.engine == engine) + bool close = true; + WriteLockGuard writeGuard(enginesLock, FB_FUNCTION); + + EnginesAttachmentsMap::Accessor ea_accessor(&enginesAttachments); + for (bool ea_found = ea_accessor.getFirst(); ea_found; ea_found = ea_accessor.getNext()) { - close = false; // engine is in use, no need to release - break; + if (ea_accessor.current()->first.engine == engine) + { + close = false; // engine is in use, no need to release + break; + } } - } - if (close) - { - if (engines.remove(accessor.current()->first)) // If engine has already been deleted - nothing to do - engine->release(); + if (close) + { + if (engines.remove(accessor.current()->first)) // If engine has already been deleted - nothing to do + PluginManagerInterfacePtr()->releasePlugin(engine); + } } } @@ -1288,16 +1302,18 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: CallerName(obj_udf, udf->getName().identifier, userName) : CallerName(obj_package_header, udf->getName().package, userName))); - ///MemoryPool& pool = *tdbb->getDefaultPool(); - MemoryPool& pool = *getDefaultMemoryPool(); + MemoryPool& pool = *tdbb->getAttachment()->att_pool; AutoPtr metadata(FB_NEW_POOL(pool) RoutineMetadata(pool)); metadata->package = udf->getName().package; metadata->name = udf->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; - metadata->inputParameters = Routine::createMetadata(udf->getInputFields(), true); - metadata->outputParameters = Routine::createMetadata(udf->getOutputFields(), true); + metadata->inputParameters.assignRefNoIncr(Routine::createMetadata(udf->getInputFields(), true)); + metadata->outputParameters.assignRefNoIncr(Routine::createMetadata(udf->getOutputFields(), true)); + + udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); + udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); FbLocalStatus status; @@ -1315,36 +1331,46 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: externalFunction = attInfo->engine->makeFunction(&status, attInfo->context, metadata, inBuilder, outBuilder); - status.check(); - if (!externalFunction) + try { - status_exception::raise( - Arg::Gds(isc_eem_func_not_returned) << udf->getName().toString() << engine); + status.check(); + + if (!externalFunction) + { + status_exception::raise( + Arg::Gds(isc_eem_func_not_returned) << udf->getName().toString() << engine); + } + } + catch (const Exception&) + { + if (tdbb->getAttachment()->isGbak()) + return; + else + throw; } - extInputParameters = inBuilder->getMetadata(&status); + extInputParameters.assignRefNoIncr(inBuilder->getMetadata(&status)); status.check(); - extOutputParameters = outBuilder->getMetadata(&status); + extOutputParameters.assignRefNoIncr(outBuilder->getMetadata(&status)); status.check(); } - udf->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); - udf->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); - const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false); const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true); try { - udf->fun_external = FB_NEW_POOL(getPool()) Function(tdbb, this, attInfo->engine, + udf->fun_external = FB_NEW_POOL(pool) Function(tdbb, this, attInfo->engine, metadata.release(), externalFunction, udf); - CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); + MemoryPool& csbPool = csb->csb_pool; + + CompoundStmtNode* mainNode = FB_NEW_POOL(csbPool) CompoundStmtNode(csbPool); IntMessageNode* intInMessageNode = udf->getInputFields().hasData() ? - FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0, + FB_NEW_POOL(csbPool) IntMessageNode(tdbb, csbPool, csb, 0, udf->getInputFields(), udf->getInputFormat()) : NULL; ExtMessageNode* extInMessageNode = NULL; @@ -1353,38 +1379,38 @@ void ExtEngineManager::makeFunction(thread_db* tdbb, CompilerScratch* csb, Jrd:: { mainNode->statements.add(intInMessageNode); - extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat); + extInMessageNode = FB_NEW_POOL(csbPool) ExtMessageNode(tdbb, csbPool, csb, 2, extInputFormat); mainNode->statements.add(extInMessageNode); } - IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1, + IntMessageNode* intOutMessageNode = FB_NEW_POOL(csbPool) IntMessageNode(tdbb, csbPool, csb, 1, udf->getOutputFields(), udf->getOutputFormat()); mainNode->statements.add(intOutMessageNode); - ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 3, + ExtMessageNode* extOutMessageNode = FB_NEW_POOL(csbPool) ExtMessageNode(tdbb, csbPool, csb, 3, extOutputFormat); mainNode->statements.add(extOutMessageNode); // Initialize the output fields into the external message. - InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode( - tdbb, getPool(), csb, udf->getOutputFields(), extOutMessageNode); + InitOutputNode* initOutputNode = FB_NEW_POOL(csbPool) InitOutputNode( + tdbb, csbPool, csb, udf->getOutputFields(), extOutMessageNode); mainNode->statements.add(initOutputNode); if (intInMessageNode) { - ReceiveNode* receiveNode = intInMessageNode ? FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; + ReceiveNode* receiveNode = intInMessageNode ? FB_NEW_POOL(csbPool) ReceiveNode(csbPool) : NULL; receiveNode->message = intInMessageNode; - receiveNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode( - getPool(), intInMessageNode, extInMessageNode); + receiveNode->statement = FB_NEW_POOL(csbPool) MessageMoverNode( + csbPool, intInMessageNode, extInMessageNode); mainNode->statements.add(receiveNode); } - ExtFunctionNode* extFunctionNode = FB_NEW_POOL(getPool()) ExtFunctionNode(getPool(), + ExtFunctionNode* extFunctionNode = FB_NEW_POOL(csbPool) ExtFunctionNode(csbPool, extInMessageNode, extOutMessageNode, udf->fun_external); mainNode->statements.add(extFunctionNode); extFunctionNode->message = intOutMessageNode; - extFunctionNode->statement = FB_NEW_POOL(getPool()) MessageMoverNode( - getPool(), extOutMessageNode, intOutMessageNode); + extFunctionNode->statement = FB_NEW_POOL(csbPool) MessageMoverNode( + csbPool, extOutMessageNode, intOutMessageNode); JrdStatement* statement = udf->getStatement(); PAR_preparsed_node(tdbb, NULL, mainNode, NULL, &csb, &statement, false, 0); @@ -1412,16 +1438,18 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ CallerName(obj_procedure, prc->getName().identifier, userName) : CallerName(obj_package_header, prc->getName().package, userName))); - ///MemoryPool& pool = *tdbb->getDefaultPool(); - MemoryPool& pool = *getDefaultMemoryPool(); + MemoryPool& pool = *tdbb->getAttachment()->att_pool; AutoPtr metadata(FB_NEW_POOL(pool) RoutineMetadata(pool)); metadata->package = prc->getName().package; metadata->name = prc->getName().identifier; metadata->entryPoint = entryPointTrimmed; metadata->body = body; - metadata->inputParameters = Routine::createMetadata(prc->getInputFields(), true); - metadata->outputParameters = Routine::createMetadata(prc->getOutputFields(), true); + metadata->inputParameters.assignRefNoIncr(Routine::createMetadata(prc->getInputFields(), true)); + metadata->outputParameters.assignRefNoIncr(Routine::createMetadata(prc->getOutputFields(), true)); + + prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); + prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); FbLocalStatus status; @@ -1439,37 +1467,47 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ externalProcedure = attInfo->engine->makeProcedure(&status, attInfo->context, metadata, inBuilder, outBuilder); - status.check(); - if (!externalProcedure) + try { - status_exception::raise( - Arg::Gds(isc_eem_proc_not_returned) << - prc->getName().toString() << engine); + status.check(); + + if (!externalProcedure) + { + status_exception::raise( + Arg::Gds(isc_eem_proc_not_returned) << + prc->getName().toString() << engine); + } + } + catch (const Exception&) + { + if (tdbb->getAttachment()->isGbak()) + return; + else + throw; } - extInputParameters = inBuilder->getMetadata(&status); + extInputParameters.assignRefNoIncr(inBuilder->getMetadata(&status)); status.check(); - extOutputParameters = outBuilder->getMetadata(&status); + extOutputParameters.assignRefNoIncr(outBuilder->getMetadata(&status)); status.check(); } - prc->setInputFormat(Routine::createFormat(pool, metadata->inputParameters, false)); - prc->setOutputFormat(Routine::createFormat(pool, metadata->outputParameters, true)); - const Format* extInputFormat = Routine::createFormat(pool, extInputParameters, false); const Format* extOutputFormat = Routine::createFormat(pool, extOutputParameters, true); try { - prc->setExternal(FB_NEW_POOL(getPool()) Procedure(tdbb, this, attInfo->engine, + prc->setExternal(FB_NEW_POOL(pool) Procedure(tdbb, this, attInfo->engine, metadata.release(), externalProcedure, prc)); - CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); + MemoryPool& csbPool = csb->csb_pool; + + CompoundStmtNode* mainNode = FB_NEW_POOL(csbPool) CompoundStmtNode(csbPool); IntMessageNode* intInMessageNode = prc->getInputFields().hasData() ? - FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 0, + FB_NEW_POOL(csbPool) IntMessageNode(tdbb, csbPool, csb, 0, prc->getInputFields(), prc->getInputFormat()) : NULL; ExtMessageNode* extInMessageNode = NULL; @@ -1478,32 +1516,32 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ { mainNode->statements.add(intInMessageNode); - extInMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), csb, 2, extInputFormat); + extInMessageNode = FB_NEW_POOL(csbPool) ExtMessageNode(tdbb, csbPool, csb, 2, extInputFormat); mainNode->statements.add(extInMessageNode); } - IntMessageNode* intOutMessageNode = FB_NEW_POOL(getPool()) IntMessageNode(tdbb, getPool(), csb, 1, + IntMessageNode* intOutMessageNode = FB_NEW_POOL(csbPool) IntMessageNode(tdbb, csbPool, csb, 1, prc->getOutputFields(), prc->getOutputFormat()); mainNode->statements.add(intOutMessageNode); - ExtMessageNode* extOutMessageNode = FB_NEW_POOL(getPool()) ExtMessageNode(tdbb, getPool(), + ExtMessageNode* extOutMessageNode = FB_NEW_POOL(csbPool) ExtMessageNode(tdbb, csbPool, csb, 3, extOutputFormat); mainNode->statements.add(extOutMessageNode); // Initialize the output fields into the external message. - InitOutputNode* initOutputNode = FB_NEW_POOL(getPool()) InitOutputNode( - tdbb, getPool(), csb, prc->getOutputFields(), extOutMessageNode); + InitOutputNode* initOutputNode = FB_NEW_POOL(csbPool) InitOutputNode( + tdbb, csbPool, csb, prc->getOutputFields(), extOutMessageNode); mainNode->statements.add(initOutputNode); ReceiveNode* receiveNode = intInMessageNode ? - FB_NEW_POOL(getPool()) ReceiveNode(getPool()) : NULL; + FB_NEW_POOL(csbPool) ReceiveNode(csbPool) : NULL; if (intInMessageNode) { - CompoundStmtNode* receiveSubStatement = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); - receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) MessageMoverNode( - getPool(), intInMessageNode, extInMessageNode)); - receiveSubStatement->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool())); + CompoundStmtNode* receiveSubStatement = FB_NEW_POOL(csbPool) CompoundStmtNode(csbPool); + receiveSubStatement->statements.add(FB_NEW_POOL(csbPool) MessageMoverNode( + csbPool, intInMessageNode, extInMessageNode)); + receiveSubStatement->statements.add(FB_NEW_POOL(csbPool) StallNode(csbPool)); receiveNode->statement = receiveSubStatement; receiveNode->message = intInMessageNode; @@ -1511,9 +1549,9 @@ void ExtEngineManager::makeProcedure(thread_db* tdbb, CompilerScratch* csb, jrd_ mainNode->statements.add(receiveNode); } else - mainNode->statements.add(FB_NEW_POOL(getPool()) StallNode(getPool())); + mainNode->statements.add(FB_NEW_POOL(csbPool) StallNode(csbPool)); - ExtProcedureNode* extProcedureNode = FB_NEW_POOL(getPool()) ExtProcedureNode(getPool(), + ExtProcedureNode* extProcedureNode = FB_NEW_POOL(csbPool) ExtProcedureNode(csbPool, extInMessageNode, extOutMessageNode, intOutMessageNode, prc->getExternal()); mainNode->statements.add(extProcedureNode); @@ -1542,8 +1580,7 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T ContextManager ctxManager(tdbb, attInfo, attInfo->adminCharSet, CallerName(obj_trigger, trg->name, userName)); - ///MemoryPool& pool = *tdbb->getDefaultPool(); - MemoryPool& pool = *getDefaultMemoryPool(); + MemoryPool& pool = *tdbb->getAttachment()->att_pool; AutoPtr metadata(FB_NEW_POOL(pool) RoutineMetadata(pool)); metadata->name = trg->name; @@ -1607,13 +1644,15 @@ void ExtEngineManager::makeTrigger(thread_db* tdbb, CompilerScratch* csb, Jrd::T try { - trg->extTrigger = FB_NEW_POOL(getPool()) Trigger(tdbb, pool, csb, this, attInfo->engine, + trg->extTrigger = FB_NEW_POOL(pool) Trigger(tdbb, pool, csb, this, attInfo->engine, metadata.release(), externalTrigger, trg); - CompoundStmtNode* mainNode = FB_NEW_POOL(getPool()) CompoundStmtNode(getPool()); + MemoryPool& csbPool = csb->csb_pool; + + CompoundStmtNode* mainNode = FB_NEW_POOL(csbPool) CompoundStmtNode(csbPool); mainNode->statements.append(trg->extTrigger->computedStatements); - ExtTriggerNode* extTriggerNode = FB_NEW_POOL(getPool()) ExtTriggerNode(getPool(), + ExtTriggerNode* extTriggerNode = FB_NEW_POOL(csbPool) ExtTriggerNode(csbPool, trg->extTrigger); mainNode->statements.add(extTriggerNode); diff --git a/src/jrd/ExtEngineManager.h b/src/jrd/ExtEngineManager.h index e124cc628c7..c2f3b111eb7 100644 --- a/src/jrd/ExtEngineManager.h +++ b/src/jrd/ExtEngineManager.h @@ -33,6 +33,7 @@ #include "../common/classes/rwlock.h" #include "../common/classes/ImplementHelper.h" #include "../common/StatementMetadata.h" +#include "../common/classes/GetPlugins.h" struct dsc; @@ -209,7 +210,20 @@ class ExtEngineManager FB_FINAL : public Firebird::PermanentStorage }; public: - class Function + class ExtRoutine + { + public: + ExtRoutine(thread_db* tdbb, ExtEngineManager* aExtManager, + Firebird::IExternalEngine* aEngine, RoutineMetadata* aMetadata); + + protected: + ExtEngineManager* extManager; + Firebird::AutoPlugin engine; + Firebird::AutoPtr metadata; + Database* database; + }; + + class Function : public ExtRoutine { public: Function(thread_db* tdbb, ExtEngineManager* aExtManager, @@ -222,17 +236,13 @@ class ExtEngineManager FB_FINAL : public Firebird::PermanentStorage void execute(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const; private: - ExtEngineManager* extManager; - Firebird::IExternalEngine* engine; - Firebird::AutoPtr metadata; Firebird::IExternalFunction* function; const Jrd::Function* udf; - Database* database; }; class ResultSet; - class Procedure + class Procedure : public ExtRoutine { public: Procedure(thread_db* tdbb, ExtEngineManager* aExtManager, @@ -245,12 +255,8 @@ class ExtEngineManager FB_FINAL : public Firebird::PermanentStorage ResultSet* open(thread_db* tdbb, UCHAR* inMsg, UCHAR* outMsg) const; private: - ExtEngineManager* extManager; - Firebird::IExternalEngine* engine; - Firebird::AutoPtr metadata; Firebird::IExternalProcedure* procedure; const jrd_prc* prc; - Database* database; friend class ResultSet; }; @@ -272,7 +278,7 @@ class ExtEngineManager FB_FINAL : public Firebird::PermanentStorage USHORT charSet; }; - class Trigger + class Trigger : public ExtRoutine { public: Trigger(thread_db* tdbb, MemoryPool& pool, CompilerScratch* csb, ExtEngineManager* aExtManager, @@ -291,15 +297,11 @@ class ExtEngineManager FB_FINAL : public Firebird::PermanentStorage Firebird::Array> computedStatements; private: - ExtEngineManager* extManager; - Firebird::IExternalEngine* engine; - Firebird::AutoPtr metadata; Firebird::AutoPtr format; Firebird::IExternalTrigger* trigger; const Jrd::Trigger* trg; Firebird::Array fieldsPos; Firebird::Array varDecls; - Database* database; USHORT computedCount; }; diff --git a/src/jrd/Function.epp b/src/jrd/Function.epp index 5bc45e10299..cc54bdbd19e 100644 --- a/src/jrd/Function.epp +++ b/src/jrd/Function.epp @@ -65,6 +65,7 @@ Function* Function::lookup(thread_db* tdbb, USHORT id, bool return_deleted, bool Function* function = (id < attachment->att_functions.getCount()) ? attachment->att_functions[id] : NULL; if (function && function->getId() == id && + !(function->flags & Routine::FLAG_CLEARED) && !(function->flags & Routine::FLAG_BEING_SCANNED) && ((function->flags & Routine::FLAG_SCANNED) || noscan) && !(function->flags & Routine::FLAG_BEING_ALTERED) && @@ -118,6 +119,7 @@ Function* Function::lookup(thread_db* tdbb, const QualifiedName& name, bool nosc Function* const function = *iter; if (function && !(function->flags & Routine::FLAG_OBSOLETE) && + !(function->flags & Routine::FLAG_CLEARED) && ((function->flags & Routine::FLAG_SCANNED) || noscan) && !(function->flags & Routine::FLAG_BEING_SCANNED) && !(function->flags & Routine::FLAG_BEING_ALTERED)) @@ -194,7 +196,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT try { function->flags |= (Routine::FLAG_BEING_SCANNED | flags); - function->flags &= ~Routine::FLAG_OBSOLETE; + function->flags &= ~(Routine::FLAG_OBSOLETE | Routine::FLAG_CLEARED); function->setId(id); attachment->att_functions[id] = function; @@ -458,7 +460,7 @@ Function* Function::loadMetadata(thread_db* tdbb, USHORT id, bool noscan, USHORT throw; } - fb_assert(function->getStatement()->function == function); + fb_assert(!function->isDefined() || function->getStatement()->function == function); } else { diff --git a/src/jrd/GarbageCollector.h b/src/jrd/GarbageCollector.h index 860f30de3b4..8f9ef6791e8 100644 --- a/src/jrd/GarbageCollector.h +++ b/src/jrd/GarbageCollector.h @@ -70,7 +70,7 @@ class GarbageCollector return item.pageno; } }; - typedef Firebird::BePlusTree PageTranMap; + typedef Firebird::BePlusTree PageTranMap; class RelationData diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index 9887c66c6c9..f25ace7fa0f 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -397,18 +397,17 @@ jrd_req* JrdStatement::getRequest(thread_db* tdbb, USHORT level) if (level < requests.getCount() && requests[level]) return requests[level]; - requests.grow(level + 1); - + // Create the request. MemoryStats* const parentStats = (flags & FLAG_INTERNAL) ? &dbb->dbb_memory_stats : &attachment->att_memory_stats; - // Create the request. - jrd_req* const request = FB_NEW_POOL(*pool) jrd_req(attachment, this, parentStats); + AutoPtr request(FB_NEW_POOL(*pool) jrd_req(attachment, this, parentStats)); request->setRequestId(dbb->generateStatementId()); + requests.grow(level + 1); requests[level] = request; - return request; + return request.release(); } // Check that we have enough rights to access all resources this request touches including @@ -640,7 +639,10 @@ void JrdStatement::release(thread_db* tdbb) } for (jrd_req** instance = requests.begin(); instance != requests.end(); ++instance) - EXE_release(tdbb, *instance); + { + if (*instance) + EXE_release(tdbb, *instance); + } sqlText = NULL; diff --git a/src/jrd/Mapping.cpp b/src/jrd/Mapping.cpp index bfe48e3aee5..74a0410e00a 100644 --- a/src/jrd/Mapping.cpp +++ b/src/jrd/Mapping.cpp @@ -209,7 +209,7 @@ bool Mapping::DbHandle::attach(const char* aliasDb, ICryptKeyCallback* cryptCb) if (!(missing || down)) check("IProvider::attachDatabase", &st); - // down/missing security DB is not a reason to fail mapping + // down/missing DB is not a reason to fail mapping } else assignRefNoIncr(att); @@ -654,14 +654,17 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject void shutdown() { + if (!sharedMemory) + return; + MutexLockGuard gLocal(initMutex, FB_FUNCTION); if (!sharedMemory) return; { // scope Guard gShared(this); - MappingHeader* sMem = sharedMemory->getHeader(); - startupSemaphore.tryEnter(5); + MappingHeader* sMem = sharedMemory->getHeader(); + fb_assert(sMem->process[process].id); sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE; (void) // Ignore errors in cleanup @@ -673,18 +676,14 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject sharedMemory->eventFini(&sMem->process[process].notifyEvent); sharedMemory->eventFini(&sMem->process[process].callbackEvent); - bool found = false; - - for (unsigned n = 0; n < sMem->processes; ++n) + while (sMem->processes) { - if (sMem->process[n].flags & MappingHeader::FLAG_ACTIVE) - { - found = true; + if (sMem->process[sMem->processes - 1].flags & MappingHeader::FLAG_ACTIVE) break; - } + sMem->processes--; } - if (!found) + if (!sMem->processes) sharedMemory->removeMapFile(); } @@ -750,15 +749,21 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject (Arg::Gds(isc_map_event) << "POST").raise(); } + int tout = 0; while (sharedMemory->eventWait(¤t->callbackEvent, value, 10000) != FB_SUCCESS) { if (!ISC_check_process_existence(p->id)) { + MAP_DEBUG(fprintf(stderr, "clearMapping: dead process found %d", p->id)); + p->flags &= ~MappingHeader::FLAG_ACTIVE; sharedMemory->eventFini(&p->notifyEvent); sharedMemory->eventFini(&p->callbackEvent); break; } + + if (++tout >= 1000) // 10 sec + (Arg::Gds(isc_random) << "Timeout when waiting callback from other process.").raise(); } MAP_DEBUG(fprintf(stderr, "Notified pid %d about reset map %s\n", p->id, sMem->databaseForReset)); @@ -773,19 +778,21 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject if (sharedMemory) return; - Arg::StatusVector statusVector; + AutoSharedMemory tempSharedMemory; try { - sharedMemory.reset(FB_NEW_POOL(*getDefaultMemoryPool()) + tempSharedMemory.reset(FB_NEW_POOL(*getDefaultMemoryPool()) SharedMemory(USER_MAP_FILE, DEFAULT_SIZE, this)); } catch (const Exception& ex) { + StaticStatusVector s; + ex.stuffException(s); iscLogException("MappingIpc: Cannot initialize the shared memory region", ex); throw; } - MappingHeader* sMem = sharedMemory->getHeader(); + MappingHeader* sMem = tempSharedMemory->getHeader(); if (sMem->mhb_type != SharedMemoryBase::SRAM_MAPPING_RESET || sMem->mhb_header_version != MemoryHeader::HEADER_VERSION || @@ -796,21 +803,39 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject sMem->mhb_type, sMem->mhb_header_version, sMem->mhb_version, SharedMemoryBase::SRAM_MAPPING_RESET, MemoryHeader::HEADER_VERSION, MAPPING_VERSION); - sharedMemory = NULL; (Arg::Gds(isc_random) << Arg::Str(err)).raise(); } - Guard gShared(this); + Guard gShared(tempSharedMemory); - for (process = 0; process < sMem->processes; ++process) + process = sMem->processes; + for (unsigned idx = 0; idx < sMem->processes; ++idx) { - if (!(sMem->process[process].flags & MappingHeader::FLAG_ACTIVE)) - break; - if (!ISC_check_process_existence(sMem->process[process].id)) + MappingHeader::Process& p = sMem->process[idx]; + + if (p.id == processId) { - sharedMemory->eventFini(&sMem->process[process].notifyEvent); - sharedMemory->eventFini(&sMem->process[process].callbackEvent); - break; + if (p.flags & MappingHeader::FLAG_ACTIVE) { + MAP_DEBUG(fprintf(stderr, "MappingIpc::setup: found existing entry for pid %d", processId)); + } + + process = idx; + continue; + } + + if ((p.flags & MappingHeader::FLAG_ACTIVE) && !ISC_check_process_existence(p.id)) + { + MAP_DEBUG(fprintf(stderr, "MappingIpc::setup: dead process found %d", p.id)); + + p.flags = 0; + tempSharedMemory->eventFini(&p.notifyEvent); + tempSharedMemory->eventFini(&p.callbackEvent); + } + + if (!(p.flags & MappingHeader::FLAG_ACTIVE)) + { + if (process == sMem->processes) + process = idx; } } @@ -826,6 +851,8 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject sMem->process[process].id = processId; sMem->process[process].flags = MappingHeader::FLAG_ACTIVE; + sharedMemory.reset(tempSharedMemory.release()); + if (sharedMemory->eventInit(&sMem->process[process].notifyEvent) != FB_SUCCESS) { (Arg::Gds(isc_map_event) << "INIT").raise(); @@ -844,6 +871,7 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject sMem->process[process].flags &= ~MappingHeader::FLAG_ACTIVE; throw; } + startupSemaphore.enter(); } void exceptionHandler(const Exception& ex, ThreadFinishSync::ThreadRoutine*) @@ -867,13 +895,13 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject { MappingHeader* sMem = sharedMemory->getHeader(); resetMap(sMem->databaseForReset, sMem->resetIndex); + p->flags &= ~MappingHeader::FLAG_DELIVER; MappingHeader::Process* cur = &sMem->process[sMem->currentProcess]; if (sharedMemory->eventPost(&cur->callbackEvent) != FB_SUCCESS) { (Arg::Gds(isc_map_event) << "POST").raise(); } - p->flags &= ~MappingHeader::FLAG_DELIVER; } if (startup) @@ -925,26 +953,36 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject class Guard; friend class Guard; + typedef SharedMemory MappingSharedMemory; + typedef AutoPtr AutoSharedMemory; class Guard { public: explicit Guard(MappingIpc* ptr) + : data(ptr->sharedMemory) + { + fb_assert(data); + data->mutexLock(); + } + + explicit Guard(MappingSharedMemory* ptr) : data(ptr) { - data->sharedMemory->mutexLock(); + fb_assert(data); + data->mutexLock(); } ~Guard() { - data->sharedMemory->mutexUnlock(); + data->mutexUnlock(); } private: Guard(const Guard&); Guard& operator=(const Guard&); - MappingIpc* const data; + MappingSharedMemory* const data; }; static void clearDelivery(MappingIpc* mapping) @@ -952,7 +990,7 @@ class MappingIpc FB_FINAL : public Firebird::IpcObject mapping->clearDeliveryThread(); } - AutoPtr > sharedMemory; + AutoSharedMemory sharedMemory; Mutex initMutex; const SLONG processId; unsigned process; @@ -1094,7 +1132,7 @@ class SysPrivCache : public PermanentStorage bool getPrivileges(const string& key, UserId::Privileges& system_privileges) { if (!key.hasData()) - return false; + return true; UserId::Privileges p; if (!get(key, p)) @@ -1133,7 +1171,11 @@ class SysPrivCache : public PermanentStorage g |= l; } - ULONG gg = 0; g.store(&gg); + FB_UINT64 gg = 0; + static_assert(sizeof(gg) >= g.BYTES_COUNT, + "The value for storing system privileges is too small"); + + g.store(&gg); MAP_DEBUG(fprintf(stderr, "poprole %s 0x%x\n", key.c_str(), gg)); put(key, g); } @@ -1235,7 +1277,7 @@ InitInstance spCache; void resetMap(const char* db, ULONG index) { - switch(index) + switch (index) { case Mapping::MAPPING_CACHE: resetMap(db); @@ -1631,7 +1673,14 @@ ULONG Mapping::mapUser(string& name, string& trustedRole) void Mapping::clearCache(const char* dbName, USHORT index) { - mappingIpc->clearCache(dbName, index); + if (index == ALL_CACHE) + { + // use only old index values not to conflict with previous FB versions (if any used) + mappingIpc->clearCache(dbName, MAPPING_CACHE); + mappingIpc->clearCache(dbName, SYSTEM_PRIVILEGES_CACHE); + } + else + mappingIpc->clearCache(dbName, index); } diff --git a/src/jrd/Mapping.h b/src/jrd/Mapping.h index 64dccddd30d..f9db7e7d00b 100644 --- a/src/jrd/Mapping.h +++ b/src/jrd/Mapping.h @@ -77,8 +77,9 @@ class Mapping void clearMainHandle(); // possible clearCache() flags - static const USHORT MAPPING_CACHE = 0; + static const USHORT MAPPING_CACHE = 0; static const USHORT SYSTEM_PRIVILEGES_CACHE = 1; + static const USHORT ALL_CACHE = MAX_USHORT; // Helper statuc functions to perform cleanup & shutdown. static void clearCache(const char* dbName, USHORT id); static void shutdownIpc(); diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index e347f3831f3..5deb675da23 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -100,7 +100,10 @@ namespace private: TempSpace& tempSpace; }; -} + + const ULONG HEADER_SIZE = (ULONG) FB_ALIGN(sizeof(MonitoringHeader), FB_ALIGNMENT); + +} // namespace const Format* MonitoringTableScan::getFormat(thread_db* tdbb, jrd_rel* relation) const @@ -171,7 +174,7 @@ MonitoringData::~MonitoringData() try { if (m_sharedMemory->getHeader() && - m_sharedMemory->getHeader()->used == alignOffset(sizeof(Header))) + m_sharedMemory->getHeader()->used == HEADER_SIZE) { m_sharedMemory->removeMapFile(); } @@ -213,7 +216,7 @@ void MonitoringData::acquire() while (m_sharedMemory->getHeader()->isDeleted()) { // Shared memory must be empty at this point - fb_assert(m_sharedMemory->getHeader()->used == alignOffset(sizeof(Header))); + fb_assert(m_sharedMemory->getHeader()->used == HEADER_SIZE); m_sharedMemory->mutexUnlock(); m_sharedMemory.reset(); @@ -254,11 +257,11 @@ void MonitoringData::read(const char* user_name, TempSpace& temp) // Copy data of all permitted sessions - for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;) + for (ULONG offset = HEADER_SIZE; offset < m_sharedMemory->getHeader()->used;) { UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset; const Element* const element = (Element*) ptr; - const ULONG length = alignOffset(sizeof(Element) + element->length); + const ULONG length = element->getBlockLength(); if (!user_name || !strcmp(element->userName, user_name)) { @@ -273,7 +276,7 @@ void MonitoringData::read(const char* user_name, TempSpace& temp) ULONG MonitoringData::setup(AttNumber att_id, const char* user_name) { - const ULONG offset = alignOffset(m_sharedMemory->getHeader()->used); + const FB_UINT64 offset = FB_ALIGN(m_sharedMemory->getHeader()->used, FB_ALIGNMENT); const ULONG delta = offset + sizeof(Element) - m_sharedMemory->getHeader()->used; ensureSpace(delta); @@ -308,11 +311,11 @@ void MonitoringData::cleanup(AttNumber att_id) { // Remove information about the given session - for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;) + for (ULONG offset = HEADER_SIZE; offset < m_sharedMemory->getHeader()->used;) { UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset; const Element* const element = (Element*) ptr; - const ULONG length = alignOffset(sizeof(Element) + element->length); + const ULONG length = element->getBlockLength(); if (element->attId == att_id) { @@ -338,11 +341,11 @@ void MonitoringData::enumerate(SessionList& sessions, const char* user_name) { // Return IDs for all known (and permitted) sessions - for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;) + for (ULONG offset = HEADER_SIZE; offset < m_sharedMemory->getHeader()->used;) { UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset; const Element* const element = (Element*) ptr; - const ULONG length = alignOffset(sizeof(Element) + element->length); + const ULONG length = element->getBlockLength(); if (!user_name || !strcmp(element->userName, user_name)) sessions.add(element->attId); @@ -354,15 +357,23 @@ void MonitoringData::enumerate(SessionList& sessions, const char* user_name) void MonitoringData::ensureSpace(ULONG length) { - ULONG newSize = m_sharedMemory->getHeader()->used + length; + FB_UINT64 newSize = m_sharedMemory->getHeader()->used + length; if (newSize > m_sharedMemory->getHeader()->allocated) { - newSize = FB_ALIGN(newSize, DEFAULT_SIZE); + if (newSize > MAX_ULONG) + { + (Arg::Gds(isc_montabexh) << + Arg::Gds(isc_random) << Arg::Str("storage size exceeds limit")).raise(); + } + + FB_UINT64 remapSize = FB_ALIGN(newSize, DEFAULT_SIZE); + if (remapSize > MAX_ULONG) + remapSize = newSize; #ifdef HAVE_OBJECT_MAP FbLocalStatus statusVector; - if (!m_sharedMemory->remapFile(&statusVector, newSize, true)) + if (!m_sharedMemory->remapFile(&statusVector, (ULONG) remapSize, true)) { status_exception::raise(&statusVector); } @@ -391,7 +402,7 @@ bool MonitoringData::initialize(SharedMemoryBase* sm, bool initialize) // Initialize the shared data header header->init(SharedMemoryBase::SRAM_DATABASE_SNAPSHOT, MONITOR_VERSION); - header->used = alignOffset(sizeof(Header)); + header->used = HEADER_SIZE; header->allocated = sm->sh_mem_length_mapped; } @@ -399,12 +410,6 @@ bool MonitoringData::initialize(SharedMemoryBase* sm, bool initialize) } -ULONG MonitoringData::alignOffset(ULONG unaligned) -{ - return (ULONG) Firebird::MEM_ALIGN(unaligned); -} - - // MonitoringSnapshot class @@ -467,8 +472,8 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool) // Enumerate active sessions const bool locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT); - const char* user_name_ptr = locksmith ? NULL : attachment->att_user ? - attachment->att_user->getUserName().c_str() : ""; + const MetaString& user_name = attachment->getEffectiveUserName(); + const char* const user_name_ptr = locksmith ? NULL : user_name.c_str(); MonitoringData::SessionList sessions(pool); @@ -901,8 +906,8 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record) // crypt thread status if (dbb->dbb_crypto_manager) { - record.storeInteger(f_mon_db_crypt_page, dbb->dbb_crypto_manager->getCurrentPage()); - record.storeInteger(f_mon_db_crypt_state, dbb->dbb_crypto_manager->getCurrentState()); + record.storeInteger(f_mon_db_crypt_page, dbb->dbb_crypto_manager->getCurrentPage(tdbb)); + record.storeInteger(f_mon_db_crypt_state, dbb->dbb_crypto_manager->getCurrentState(tdbb)); } // database owner @@ -967,7 +972,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta ISC_systemToUtf8(attName); // user (MUST BE ALWAYS THE FIRST ITEM PASSED!) - record.storeString(f_mon_att_user, attachment->att_user->getUserName()); + record.storeString(f_mon_att_user, attachment->getUserName()); // attachment id record.storeInteger(f_mon_att_id, attachment->att_attachment_id); // process id @@ -978,7 +983,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta // attachment name record.storeString(f_mon_att_name, attName); // role - record.storeString(f_mon_att_role, attachment->att_user->getSqlRole()); + record.storeString(f_mon_att_role, attachment->getSqlRole()); // remote protocol record.storeString(f_mon_att_remote_proto, attachment->att_network_protocol); // remote address @@ -1381,7 +1386,7 @@ void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment) attachment->mergeStats(); const AttNumber att_id = attachment->att_attachment_id; - const MetaString& user_name = attachment->att_user->getUserName(); + const MetaString& user_name = attachment->getUserName(); fb_assert(dbb->dbb_monitoring_data); @@ -1446,8 +1451,7 @@ void Monitoring::publishAttachment(thread_db* tdbb) Database* const dbb = tdbb->getDatabase(); Attachment* const attachment = tdbb->getAttachment(); - const char* user_name = attachment->att_user ? - attachment->att_user->getUserName().c_str() : ""; + const char* user_name = attachment->getUserName().c_str(); fb_assert(dbb->dbb_monitoring_data); diff --git a/src/jrd/Monitoring.h b/src/jrd/Monitoring.h index 7e8d266c614..3442c6a62d3 100644 --- a/src/jrd/Monitoring.h +++ b/src/jrd/Monitoring.h @@ -256,9 +256,12 @@ class MonitoringData FB_FINAL : public Firebird::PermanentStorage, public Firebi AttNumber attId; TEXT userName[USERNAME_LENGTH + 1]; ULONG length; - }; - static ULONG alignOffset(ULONG absoluteOffset); + inline ULONG getBlockLength() const + { + return (ULONG) FB_ALIGN(sizeof(Element) + length, FB_ALIGNMENT); + } + }; public: class Guard diff --git a/src/jrd/Optimizer.cpp b/src/jrd/Optimizer.cpp index 99f895ab6ee..aa7674f201b 100644 --- a/src/jrd/Optimizer.cpp +++ b/src/jrd/Optimizer.cpp @@ -96,29 +96,6 @@ namespace return false; } - ValueExprNode* injectCast(CompilerScratch* csb, - ValueExprNode* value, CastNode*& cast, - const dsc& desc) - { - // If the indexed column is of type int64, then we need to inject - // an extra cast to deliver the scale value to the BTR level - - if (value && desc.dsc_dtype == dtype_int64) - { - if (!cast) - { - cast = FB_NEW_POOL(csb->csb_pool) CastNode(csb->csb_pool); - cast->source = value; - cast->castDesc = desc; - cast->impureOffset = csb->allocImpure(); - } - - value = cast; - } - - return value; - } - ValueExprNode* invertBoolValue(CompilerScratch* csb, ValueExprNode* value) { // Having a condition ( != ), @@ -212,6 +189,7 @@ IndexScratchSegment::IndexScratchSegment(MemoryPool& p) : excludeUpper = false; scope = 0; scanType = segmentScanNone; + scale = 0; } IndexScratchSegment::IndexScratchSegment(MemoryPool& p, IndexScratchSegment* segment) : @@ -232,6 +210,7 @@ IndexScratchSegment::IndexScratchSegment(MemoryPool& p, IndexScratchSegment* seg excludeUpper = segment->excludeUpper; scope = segment->scope; scanType = segment->scanType; + scale = 0; for (FB_SIZE_T i = 0; i < segment->matches.getCount(); i++) { matches.add(segment->matches[i]); @@ -258,7 +237,8 @@ IndexScratch::IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* ix, lowerCount = 0; upperCount = 0; nonFullMatchedSegments = 0; - fuzzy = false; + usePartialKey = false; + useMultiStartingKeys = false; segments.grow(idx->idx_count); @@ -307,7 +287,8 @@ IndexScratch::IndexScratch(MemoryPool& p, const IndexScratch& scratch) : lowerCount = scratch.lowerCount; upperCount = scratch.upperCount; nonFullMatchedSegments = scratch.nonFullMatchedSegments; - fuzzy = scratch.fuzzy; + usePartialKey = scratch.usePartialKey; + useMultiStartingKeys = scratch.useMultiStartingKeys; idx = scratch.idx; // Allocate needed segments @@ -582,6 +563,7 @@ InversionCandidate* OptimizerRetrieval::generateInversion() if (!(tail->opt_conjunct_flags & opt_conjunct_used) && node->computable(csb, stream, true) && + node->findStream(csb, stream) && !invCandidate->matches.exist(node)) { const ComparativeBoolNode* const cmpNode = nodeAs(node); @@ -667,6 +649,13 @@ void OptimizerRetrieval::analyzeNavigation(const InversionCandidateList& inversi **************************************/ fb_assert(sort); + OptimizerBlk::opt_conjunct* const opt_begin = + optimizer->opt_conjuncts.begin() + (outerFlag ? optimizer->opt_base_parent_conjuncts : 0); + + const OptimizerBlk::opt_conjunct* const opt_end = + innerFlag ? optimizer->opt_conjuncts.begin() + optimizer->opt_base_missing_conjuncts : + optimizer->opt_conjuncts.end(); + for (FB_SIZE_T i = 0; i < indexScratches.getCount(); ++i) { IndexScratch* const indexScratch = &indexScratches[i]; @@ -734,8 +723,7 @@ void OptimizerRetrieval::analyzeNavigation(const InversionCandidateList& inversi HalfStaticArray nodes; nodes.add(orgNode); - for (const OptimizerBlk::opt_conjunct* tail = optimizer->opt_conjuncts.begin(); - tail < optimizer->opt_conjuncts.end(); tail++) + for (const OptimizerBlk::opt_conjunct* tail = opt_begin; tail < opt_end; tail++) { BoolExprNode* const boolean = tail->opt_conjunct_node; fb_assert(boolean); @@ -1011,7 +999,8 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio scratch.lowerCount = 0; scratch.upperCount = 0; scratch.nonFullMatchedSegments = MAX_INDEX_SEGMENTS + 1; - scratch.fuzzy = false; + scratch.usePartialKey = false; + scratch.useMultiStartingKeys = false; if (scratch.candidate) { @@ -1027,26 +1016,34 @@ void OptimizerRetrieval::getInversionCandidates(InversionCandidateList* inversio if (segment->scope == scope) scratch.scopeCandidate = true; - if (segment->scanType != segmentScanMissing && !(scratch.idx->idx_flags & idx_unique)) + const USHORT iType = scratch.idx->idx_rpt[j].idx_itype; + + if (iType >= idx_first_intl_string) { - const USHORT iType = scratch.idx->idx_rpt[j].idx_itype; + auto textType = INTL_texttype_lookup(tdbb, INTL_INDEX_TO_TEXT(iType)); - if (iType >= idx_first_intl_string) + if (segment->scanType != segmentScanMissing && !(scratch.idx->idx_flags & idx_unique)) { - TextType* textType = INTL_texttype_lookup(tdbb, INTL_INDEX_TO_TEXT(iType)); - if (textType->getFlags() & TEXTTYPE_SEPARATE_UNIQUE) { // ASF: Order is more precise than equivalence class. // We can't use the next segments, and we'll need to use // INTL_KEY_PARTIAL to construct the last segment's key. - scratch.fuzzy = true; + scratch.usePartialKey = true; } } + + if (segment->scanType == segmentScanStarting) + { + if (textType->getFlags() & TEXTTYPE_MULTI_STARTING_KEY) + scratch.useMultiStartingKeys = true; // use INTL_KEY_MULTI_STARTING + + scratch.usePartialKey = true; + } } // Check if this is the last usable segment - if (!scratch.fuzzy && + if (!scratch.usePartialKey && (segment->scanType == segmentScanEqual || segment->scanType == segmentScanEquivalent || segment->scanType == segmentScanMissing)) @@ -1285,8 +1282,9 @@ InversionNode* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) int i = 0; bool ignoreNullsOnScan = true; IndexScratchSegment** segment = indexScratch->segments.begin(); + const auto count = MAX(indexScratch->lowerCount, indexScratch->upperCount); - for (i = 0; i < MAX(indexScratch->lowerCount, indexScratch->upperCount); i++) + for (i = 0; i < count; i++) { if (segment[i]->scanType == segmentScanMissing) { @@ -1304,6 +1302,16 @@ InversionNode* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) if (segment[i]->scanType == segmentScanEquivalent) ignoreNullsOnScan = false; } + + if (segment[i]->scale) + { + if (!retrieval->irb_scale) + { + retrieval->irb_scale = FB_NEW_POOL(getPool()) SSHORT[count]; + memset(retrieval->irb_scale, 0, sizeof(SSHORT) * count); + } + retrieval->irb_scale[i] = segment[i]->scale; + } } i = MAX(indexScratch->lowerCount, indexScratch->upperCount) - 1; @@ -1320,9 +1328,15 @@ InversionNode* OptimizerRetrieval::makeIndexScanNode(IndexScratch* indexScratch) retrieval->irb_generic |= irb_exclude_upper; } - if (indexScratch->fuzzy) + if (indexScratch->usePartialKey) retrieval->irb_generic |= irb_starting; // Flag the need to use INTL_KEY_PARTIAL in btr. + if (indexScratch->useMultiStartingKeys) + { + // Flag the need to use INTL_KEY_MULTI_STARTING in btr. + retrieval->irb_generic |= irb_multi_starting | irb_starting; + } + // This index is never used for IS NULL, thus we can ignore NULLs // already at index scan. But this rule doesn't apply to nod_equiv // which requires NULLs to be found in the index. @@ -1857,9 +1871,6 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* const bool isDesc = (indexScratch->idx->idx_flags & idx_descending); - // Needed for int64 matches, see injectCast() function - CastNode *cast = NULL, *cast2 = NULL; - fb_assert(indexScratch->segments.getCount() == indexScratch->idx->idx_count); for (int i = 0; i < indexScratch->idx->idx_count; i++) @@ -1885,8 +1896,8 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* if (!((segment->scanType == segmentScanEqual) || (segment->scanType == segmentScanEquivalent))) { - segment->lowerValue = injectCast(csb, value, cast, matchDesc); - segment->upperValue = injectCast(csb, value2, cast2, matchDesc); + segment->lowerValue = value; + segment->upperValue = value2; segment->scanType = segmentScanBetween; segment->excludeLower = false; segment->excludeUpper = false; @@ -1899,8 +1910,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* // override it with worser matches. if (!(segment->scanType == segmentScanEqual)) { - segment->lowerValue = segment->upperValue = - injectCast(csb, value, cast, matchDesc); + segment->lowerValue = segment->upperValue = value; segment->scanType = segmentScanEquivalent; segment->excludeLower = false; segment->excludeUpper = false; @@ -1909,8 +1919,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* case blr_eql: segment->matches.add(boolean); - segment->lowerValue = segment->upperValue = - injectCast(csb, value, cast, matchDesc); + segment->lowerValue = segment->upperValue = value; segment->scanType = segmentScanEqual; segment->excludeLower = false; segment->excludeUpper = false; @@ -1946,7 +1955,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* if (forward) { - segment->lowerValue = injectCast(csb, value, cast, matchDesc); + segment->lowerValue = value; if (segment->scanType == segmentScanLess) segment->scanType = segmentScanBetween; else @@ -1954,7 +1963,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* } else { - segment->upperValue = injectCast(csb, value, cast, matchDesc); + segment->upperValue = value; if (segment->scanType == segmentScanGreater) segment->scanType = segmentScanBetween; else @@ -1977,7 +1986,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* if (forward) { - segment->upperValue = injectCast(csb, value, cast, matchDesc); + segment->upperValue = value; if (segment->scanType == segmentScanGreater) segment->scanType = segmentScanBetween; else @@ -1985,7 +1994,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* } else { - segment->lowerValue = injectCast(csb, value, cast, matchDesc); + segment->lowerValue = value; if (segment->scanType == segmentScanLess) segment->scanType = segmentScanBetween; else @@ -2002,8 +2011,7 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* if (!((segment->scanType == segmentScanEqual) || (segment->scanType == segmentScanEquivalent))) { - segment->lowerValue = segment->upperValue = - injectCast(csb, value, cast, matchDesc); + segment->lowerValue = segment->upperValue = value; segment->scanType = segmentScanStarting; segment->excludeLower = false; segment->excludeUpper = false; @@ -2032,6 +2040,10 @@ bool OptimizerRetrieval::matchBoolean(IndexScratch* indexScratch, BoolExprNode* return false; } + // Scale idx_numeric2 + if ((!missingNode) && (matchDesc.dsc_dtype == dtype_int64)) + segment->scale = matchDesc.dsc_scale; + // A match could be made if (segment->scope < scope) segment->scope = scope; @@ -2672,15 +2684,19 @@ void OptimizerInnerJoin::calculateStreamInfo() * all streams. * **************************************/ + StreamList streams; FB_SIZE_T i = 0; // First get the base cost without any relation to an other inner join stream. for (i = 0; i < innerStreams.getCount(); i++) { - CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[innerStreams[i]->stream]; + const StreamType stream = innerStreams[i]->stream; + streams.add(stream); + + CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[stream]; csb_tail->activate(); - OptimizerRetrieval optimizerRetrieval(pool, optimizer, innerStreams[i]->stream, + OptimizerRetrieval optimizerRetrieval(pool, optimizer, stream, false, false, sort); AutoPtr candidate(optimizerRetrieval.getCost()); @@ -2693,20 +2709,36 @@ void OptimizerInnerJoin::calculateStreamInfo() csb_tail->deactivate(); } - for (i = 0; i < innerStreams.getCount(); i++) + // Collect dependencies between every pair of streams + + for (StreamType* iter = streams.begin(); iter != streams.end(); ++iter) { - CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[innerStreams[i]->stream]; - csb_tail->activate(); + csb->csb_rpt[*iter].activate(); - // Find streams that have a indexed relationship to this - // stream and add the information. for (FB_SIZE_T j = 0; j < innerStreams.getCount(); j++) { - if (innerStreams[j]->stream != innerStreams[i]->stream) - getIndexedRelationship(innerStreams[i], innerStreams[j]); + const StreamType testStream = innerStreams[j]->stream; + + if (*iter != testStream) + { + csb->csb_rpt[testStream].activate(); + getIndexedRelationships(innerStreams[j]); + csb->csb_rpt[testStream].deactivate(); + } } - csb_tail->deactivate(); + csb->csb_rpt[*iter].deactivate(); + } + + // Collect more complex inter-dependencies (involving three and more streams), if any + + if (streams.getCount() > 2) + { + StreamStateHolder stateHolder(csb, streams); + stateHolder.activate(); + + for (i = 0; i < innerStreams.getCount(); i++) + getIndexedRelationships(innerStreams[i]); } // Sort the streams based on independecy and cost. @@ -2999,43 +3031,57 @@ void OptimizerInnerJoin::findBestOrder(StreamType position, InnerJoinStreamInfo* if (!done && !plan) { // Add these relations to the processing list - for (FB_SIZE_T j = 0; j < stream->indexedRelationships.getCount(); j++) + for (const auto relationship : stream->indexedRelationships) { - IndexRelationship* relationship = stream->indexedRelationships[j]; - InnerJoinStreamInfo* relationStreamInfo = getStreamInfo(relationship->stream); - if (!relationStreamInfo->used) + const auto relationStreamInfo = getStreamInfo(relationship->stream); + + if (relationStreamInfo->used) + continue; + + bool usable = true; + for (const auto depStream : relationship->depStreams) { - bool found = false; - IndexRelationship** processRelationship = processList->begin(); - FB_SIZE_T index; - for (index = 0; index < processList->getCount(); index++) + if (!(csb->csb_rpt[depStream].csb_flags & csb_active)) { - if (relationStreamInfo->stream == processRelationship[index]->stream) - { - // If the cost of this relationship is cheaper then remove the - // old relationship and add this one. - if (cheaperRelationship(relationship, processRelationship[index])) - { - processList->remove(index); - break; - } - - found = true; - break; - } + usable = false; + break; } - if (!found) + } + + if (!usable) + continue; + + bool found = false; + IndexRelationship** processRelationship = processList->begin(); + FB_SIZE_T index; + for (index = 0; index < processList->getCount(); index++) + { + if (relationStreamInfo->stream == processRelationship[index]->stream) { - // Add relationship sorted on cost (cheapest as first) - IndexRelationship** relationships = processList->begin(); - for (index = 0; index < processList->getCount(); index++) + // If the cost of this relationship is cheaper then remove the + // old relationship and add this one. + if (cheaperRelationship(relationship, processRelationship[index])) { - if (cheaperRelationship(relationship, relationships[index])) - break; + processList->remove(index); + break; } - processList->insert(index, relationship); + + found = true; + break; } } + + if (found) + continue; + + // Add relationship sorted on cost (cheapest as first) + IndexRelationship** relationships = processList->begin(); + for (index = 0; index < processList->getCount(); index++) + { + if (cheaperRelationship(relationship, relationships[index])) + break; + } + processList->insert(index, relationship); } IndexRelationship** nextRelationship = processList->begin(); @@ -3072,12 +3118,11 @@ void OptimizerInnerJoin::findBestOrder(StreamType position, InnerJoinStreamInfo* innerStreams[i]->used = streamFlags[i]; } -void OptimizerInnerJoin::getIndexedRelationship(InnerJoinStreamInfo* baseStream, - InnerJoinStreamInfo* testStream) +void OptimizerInnerJoin::getIndexedRelationships(InnerJoinStreamInfo* testStream) { /************************************** * - * g e t I n d e x e d R e l a t i o n s h i p + * g e t I n d e x e d R e l a t i o n s h i p s * ************************************** * @@ -3092,36 +3137,57 @@ void OptimizerInnerJoin::getIndexedRelationship(InnerJoinStreamInfo* baseStream, **************************************/ CompilerScratch::csb_repeat* csb_tail = &csb->csb_rpt[testStream->stream]; - csb_tail->activate(); OptimizerRetrieval optimizerRetrieval(pool, optimizer, testStream->stream, false, false, NULL); AutoPtr candidate(optimizerRetrieval.getCost()); - if (candidate->dependentFromStreams.exist(baseStream->stream)) - { - // If we could use more conjunctions on the testing stream - // with the base stream active as without the base stream - // then the test stream has a indexed relationship with the base stream. - IndexRelationship* indexRelationship = FB_NEW_POOL(pool) IndexRelationship(); - indexRelationship->stream = testStream->stream; - indexRelationship->unique = candidate->unique; - indexRelationship->cost = candidate->cost; - indexRelationship->cardinality = candidate->unique ? - csb_tail->csb_cardinality : csb_tail->csb_cardinality * candidate->selectivity; - - // indexRelationship are kept sorted on cost and unique in the indexRelations array. - // The unique and cheapest indexed relatioships are on the first position. - FB_SIZE_T index = 0; - for (; index < baseStream->indexedRelationships.getCount(); index++) + for (const auto baseStream : innerStreams) + { + if (baseStream->stream != testStream->stream && + candidate->dependentFromStreams.exist(baseStream->stream)) { - if (cheaperRelationship(indexRelationship, baseStream->indexedRelationships[index])) - break; + // If the base stream already depends on the testing stream, don't store it again + bool found = false; + for (const auto relationship : baseStream->indexedRelationships) + { + if (relationship->stream == testStream->stream) + { + found = true; + break; + } + } + + if (found) + continue; + + if (candidate->dependentFromStreams.getCount() > IndexRelationship::MAX_DEP_STREAMS) + continue; + + // If we could use more conjunctions on the testing stream + // with the base stream active as without the base stream + // then the test stream has a indexed relationship with the base stream. + IndexRelationship* indexRelationship = FB_NEW_POOL(pool) IndexRelationship(); + indexRelationship->stream = testStream->stream; + indexRelationship->unique = candidate->unique; + indexRelationship->cost = candidate->cost; + indexRelationship->cardinality = candidate->unique ? + csb_tail->csb_cardinality : csb_tail->csb_cardinality * candidate->selectivity; + + for (const auto depStream : candidate->dependentFromStreams) + indexRelationship->depStreams.add(depStream); + + // indexRelationship are kept sorted on cost and unique in the indexRelations array. + // The unique and cheapest indexed relatioships are on the first position. + FB_SIZE_T index = 0; + for (; index < baseStream->indexedRelationships.getCount(); index++) + { + if (cheaperRelationship(indexRelationship, baseStream->indexedRelationships[index])) + break; + } + baseStream->indexedRelationships.insert(index, indexRelationship); + testStream->previousExpectedStreams++; } - baseStream->indexedRelationships.insert(index, indexRelationship); - testStream->previousExpectedStreams++; } - - csb_tail->deactivate(); } InnerJoinStreamInfo* OptimizerInnerJoin::getStreamInfo(StreamType stream) diff --git a/src/jrd/Optimizer.h b/src/jrd/Optimizer.h index 26a146291d8..e52855c3c84 100644 --- a/src/jrd/Optimizer.h +++ b/src/jrd/Optimizer.h @@ -103,6 +103,7 @@ class IndexScratchSegment bool excludeUpper; // exclude upper bound value from scan int scope; // highest scope level segmentScanType scanType; // scan type + SSHORT scale; Firebird::Array matches; }; @@ -121,7 +122,8 @@ class IndexScratch int lowerCount; // int upperCount; // int nonFullMatchedSegments; // - bool fuzzy; // Need to use INTL_KEY_PARTIAL in btr lookups + bool usePartialKey; // Use INTL_KEY_PARTIAL + bool useMultiStartingKeys; // Use INTL_KEY_MULTI_STARTING double cardinality; // Estimated cardinality when using the whole index Firebird::Array segments; @@ -239,10 +241,13 @@ class IndexRelationship : stream(0), unique(false), cost(0), cardinality(0) {} + static const unsigned MAX_DEP_STREAMS = 8; + StreamType stream; bool unique; double cost; double cardinality; + Firebird::Vector depStreams; }; typedef Firebird::Array IndexedRelationships; @@ -299,7 +304,7 @@ class OptimizerInnerJoin void estimateCost(StreamType stream, double* cost, double* resulting_cardinality, bool start) const; void findBestOrder(StreamType position, InnerJoinStreamInfo* stream, IndexedRelationships* processList, double cost, double cardinality); - void getIndexedRelationship(InnerJoinStreamInfo* baseStream, InnerJoinStreamInfo* testStream); + void getIndexedRelationships(InnerJoinStreamInfo* testStream); InnerJoinStreamInfo* getStreamInfo(StreamType stream); #ifdef OPT_DEBUG void printBestOrder() const; diff --git a/src/jrd/PreparedStatement.cpp b/src/jrd/PreparedStatement.cpp index 3468ea300d3..e58a309d3d7 100644 --- a/src/jrd/PreparedStatement.cpp +++ b/src/jrd/PreparedStatement.cpp @@ -322,7 +322,7 @@ void PreparedStatement::init(thread_db* tdbb, Attachment* attachment, jrd_tra* t const int dialect = isInternalRequest || (dbb.dbb_flags & DBB_DB_SQL_dialect_3) ? SQL_DIALECT_V6 : SQL_DIALECT_V5; - request = DSQL_prepare(tdbb, attachment, transaction, text.length(), text.c_str(), dialect, + request = DSQL_prepare(tdbb, attachment, transaction, text.length(), text.c_str(), dialect, 0, NULL, NULL, isInternalRequest); const DsqlCompiledStatement* statement = request->getStatement(); diff --git a/src/jrd/Record.h b/src/jrd/Record.h index 5cf437ae65a..1a00d6b785c 100644 --- a/src/jrd/Record.h +++ b/src/jrd/Record.h @@ -29,30 +29,24 @@ namespace Jrd { - // Record flags - const UCHAR REC_fake_nulls = 1; // all fields simulate being NULLs - const UCHAR REC_gc_active = 2; // relation garbage collect record block in use - const UCHAR REC_undo_active = 4; // record block in use for undo purposes - class Record { - template friend class AutoTempRecord; + friend class AutoTempRecord; public: - Record(MemoryPool& p, const Format* format, UCHAR flags = 0) - : m_precedence(p), m_data(p) + Record(MemoryPool& p, const Format* format, const bool temp_active = false) + : m_precedence(p), m_data(p), m_fake_nulls(false), m_temp_active(temp_active) { m_data.resize(format->fmt_length); m_format = format; - m_flags = flags; } Record(MemoryPool& p, const Record* other) : m_precedence(p), m_data(p, other->m_data), - m_format(other->m_format), m_flags(other->m_flags) + m_format(other->m_format), m_fake_nulls(other->m_fake_nulls), m_temp_active(false) {} - void reset(const Format* format = NULL, UCHAR flags = 0) + void reset(const Format* format = NULL) { if (format && format != m_format) { @@ -60,24 +54,24 @@ namespace Jrd m_format = format; } - m_flags = flags; + m_fake_nulls = false; } void setNull(USHORT id) { - fb_assert(!(m_flags & REC_fake_nulls)); + fb_assert(!m_fake_nulls); getData()[id >> 3] |= (1 << (id & 7)); } void clearNull(USHORT id) { - fb_assert(!(m_flags & REC_fake_nulls)); + fb_assert(!m_fake_nulls); getData()[id >> 3] &= ~(1 << (id & 7)); } bool isNull(USHORT id) const { - if (m_flags & REC_fake_nulls) + if (m_fake_nulls) return true; return ((getData()[id >> 3] & (1 << (id & 7))) != 0); @@ -91,7 +85,7 @@ namespace Jrd memset(getData() + null_bytes, 0, getLength() - null_bytes); // Record has real NULLs now, so clear the "fake-nulls" flag - m_flags &= ~REC_fake_nulls; + m_fake_nulls = false; } PageStack& getPrecedence() @@ -107,7 +101,7 @@ namespace Jrd void copyFrom(const Record* other) { m_format = other->m_format; - m_flags = other->m_flags; + m_fake_nulls = other->m_fake_nulls; copyDataFrom(other); } @@ -137,12 +131,12 @@ namespace Jrd void fakeNulls() { - m_flags |= REC_fake_nulls; + m_fake_nulls = true; } bool isNull() const { - return (m_flags & REC_fake_nulls); + return m_fake_nulls; } ULONG getLength() const @@ -160,9 +154,14 @@ namespace Jrd return m_data.begin(); } - bool testFlags(UCHAR mask) const + bool isTempActive() const { - return ((m_flags & mask) != 0); + return m_temp_active; + } + + void setTempActive() + { + m_temp_active = true; } TraNumber getTransactionNumber() const @@ -179,13 +178,13 @@ namespace Jrd PageStack m_precedence; // stack of higher precedence pages/transactions Firebird::Array m_data; // space for record data const Format* m_format; // what the data looks like - UCHAR m_flags; // misc record flags - TraNumber m_transaction_nr; // transaction number for a record + TraNumber m_transaction_nr; // transaction number for a record + bool m_fake_nulls; // all fields simulate being NULLs + bool m_temp_active; // record block in use for garbage collection or undo purposes }; // Wrapper for reusable temporary records - template class AutoTempRecord { public: @@ -193,7 +192,7 @@ namespace Jrd : m_record(record) { // validate record and its flag - fb_assert(!record || (record->m_flags & FLAG)); + fb_assert(!record || record->m_temp_active); } ~AutoTempRecord() @@ -206,7 +205,7 @@ namespace Jrd // class object can be initialized just once fb_assert(!m_record); // validate record and its flag - fb_assert(!record || (record->m_flags & FLAG)); + fb_assert(!record || record->m_temp_active); m_record = record; return m_record; @@ -216,7 +215,8 @@ namespace Jrd { if (m_record) { - m_record->m_flags &= ~FLAG; + fb_assert(m_record->m_temp_active); + m_record->m_temp_active = false; m_record = NULL; } } @@ -234,9 +234,6 @@ namespace Jrd private: Record* m_record; }; - - typedef AutoTempRecord AutoGCRecord; - typedef AutoTempRecord AutoUndoRecord; } // namespace #endif // JRD_RECORD_H diff --git a/src/jrd/RecordSourceNodes.cpp b/src/jrd/RecordSourceNodes.cpp index 6f288304ff0..085b9cf11f2 100644 --- a/src/jrd/RecordSourceNodes.cpp +++ b/src/jrd/RecordSourceNodes.cpp @@ -810,6 +810,7 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch { SET_TDBB(tdbb); + const auto blrStartPos = csb->csb_blr_reader.getPos(); jrd_prc* procedure = NULL; string* aliasString = NULL; QualifiedName name; @@ -876,6 +877,25 @@ ProcedureSourceNode* ProcedureSourceNode::parse(thread_db* tdbb, CompilerScratch if (!procedure) PAR_error(csb, Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString())); + else + { + if (procedure->isImplemented() && !procedure->isDefined()) + { + if (tdbb->getAttachment()->isGbak() || (tdbb->tdbb_flags & TDBB_replicator)) + { + PAR_warning( + Arg::Warning(isc_prcnotdef) << Arg::Str(name.toString()) << + Arg::Warning(isc_modnotfound)); + } + else + { + csb->csb_blr_reader.setPos(blrStartPos); + PAR_error(csb, + Arg::Gds(isc_prcnotdef) << Arg::Str(name.toString()) << + Arg::Gds(isc_modnotfound)); + } + } + } if (procedure->prc_type == prc_executable) { diff --git a/src/jrd/Relation.cpp b/src/jrd/Relation.cpp index cb04c530cb7..7d753399a7e 100644 --- a/src/jrd/Relation.cpp +++ b/src/jrd/Relation.cpp @@ -213,6 +213,9 @@ void jrd_rel::retainPages(thread_db* tdbb, TraNumber oldNumber, TraNumber newNum fb_assert(oldNumber != 0); fb_assert(newNumber != 0); + if (!rel_pages_inst) + return; + SINT64 inst_id = oldNumber; FB_SIZE_T pos; if (!rel_pages_inst->find(oldNumber, pos)) diff --git a/src/jrd/Routine.cpp b/src/jrd/Routine.cpp index 92f38372f91..412cf5331eb 100644 --- a/src/jrd/Routine.cpp +++ b/src/jrd/Routine.cpp @@ -45,8 +45,6 @@ MsgMetadata* Routine::createMetadata(const Array >& paramet ++i) { dsc d((*i)->prm_desc); - if (isExtern && d.dsc_dtype == dtype_int128) - d.dsc_dtype = dtype_dec128; metadata->addItem((*i)->prm_name, (*i)->prm_nullable, d); } @@ -111,8 +109,8 @@ Format* Routine::createFormat(MemoryPool& pool, IMessageMetadata* params, bool a return format; } -void Routine::setStatement(JrdStatement* value) -{ +void Routine::setStatement(JrdStatement* value) +{ statement = value; if (statement) @@ -142,7 +140,7 @@ void Routine::checkReload(thread_db* tdbb) if (!reload(tdbb)) { string err; - err.printf("Recompile of %s \"%s\" failed", + err.printf("Recompile of %s \"%s\" failed", getObjectType() == obj_udf ? "FUNCTION" : "PROCEDURE", getName().toString().c_str()); @@ -365,12 +363,12 @@ void Routine::remove(thread_db* tdbb) else { // Fully clear routine block. Some pieces of code check for empty - // routine name and ID, this is why we do it. + // routine name, this is why we do it. setName(QualifiedName()); setSecurityName(""); - setId(0); setDefaultCount(0); releaseExternal(); + flags |= FLAG_CLEARED; } } diff --git a/src/jrd/Routine.h b/src/jrd/Routine.h index 90d62f4dc48..1de4ef5463d 100644 --- a/src/jrd/Routine.h +++ b/src/jrd/Routine.h @@ -82,6 +82,7 @@ namespace Jrd // invalidating procedure pointers from other parts of metadata cache static const USHORT FLAG_CHECK_EXISTENCE = 16; // Existence lock released static const USHORT FLAG_RELOAD = 32; // Recompile before execution + static const USHORT FLAG_CLEARED = 64; // Routine cleared but not removed from cache static const USHORT MAX_ALTER_COUNT = 64; // Number of times an in-cache routine can be altered diff --git a/src/jrd/RuntimeStatistics.h b/src/jrd/RuntimeStatistics.h index 68c0c51fb61..7c9eb59af8d 100644 --- a/src/jrd/RuntimeStatistics.h +++ b/src/jrd/RuntimeStatistics.h @@ -32,7 +32,7 @@ namespace Firebird { // declared in firebird/Interface.h -struct TraceCounts; +struct TraceCounts; struct PerformanceInfo; } // namespace Firebird diff --git a/src/jrd/Savepoint.cpp b/src/jrd/Savepoint.cpp index 187928834cf..6c5a7efa4e6 100644 --- a/src/jrd/Savepoint.cpp +++ b/src/jrd/Savepoint.cpp @@ -86,7 +86,7 @@ void VerbAction::garbageCollectIdxLite(thread_db* tdbb, jrd_tra* transaction, SI rpb.rpb_transaction_nr = transaction->tra_number; Record* next_ver; - AutoUndoRecord undo_next_ver(transaction->findNextUndo(this, vct_relation, recordNumber)); + AutoTempRecord undo_next_ver(transaction->findNextUndo(this, vct_relation, recordNumber)); AutoPtr real_next_ver; next_ver = undo_next_ver; @@ -108,7 +108,7 @@ void VerbAction::garbageCollectIdxLite(thread_db* tdbb, jrd_tra* transaction, SI BUGCHECK(185); // msg 185 wrong record version Record* prev_ver = NULL; - AutoUndoRecord undo_prev_ver; + AutoTempRecord undo_prev_ver; AutoPtr real_prev_ver; if (nextAction && nextAction->vct_undo && nextAction->vct_undo->locate(recordNumber)) @@ -197,7 +197,7 @@ void VerbAction::mergeTo(thread_db* tdbb, jrd_tra* transaction, VerbAction* next // because going version for sure has all index entries successfully set up (in contrast with undo) // we can use lightweigth version of garbage collection without collection of full staying list - AutoUndoRecord this_ver(item.setupRecord(transaction)); + AutoTempRecord this_ver(item.setupRecord(transaction)); garbageCollectIdxLite(tdbb, transaction, recordNumber, nextAction, this_ver); @@ -307,13 +307,13 @@ void VerbAction::undo(thread_db* tdbb, jrd_tra* transaction, bool preserveLocks, if (preserveAction) RBM_SET(transaction->tra_pool, &preserveAction->vct_records, rpb.rpb_number.getValue()); - } + } else VIO_backout(tdbb, &rpb, transaction); } else { - AutoUndoRecord record(vct_undo->current().setupRecord(transaction)); + AutoTempRecord record(vct_undo->current().setupRecord(transaction)); Record* const save_record = rpb.rpb_record; record_param new_rpb = rpb; diff --git a/src/jrd/Savepoint.h b/src/jrd/Savepoint.h index a69d5ed235c..97c3e545135 100644 --- a/src/jrd/Savepoint.h +++ b/src/jrd/Savepoint.h @@ -73,7 +73,7 @@ namespace Jrd const Format* m_format; }; - typedef Firebird::BePlusTree UndoItemTree; + typedef Firebird::BePlusTree UndoItemTree; class VerbAction { @@ -94,7 +94,7 @@ namespace Jrd UndoItemTree* vct_undo; // Data for undo records void mergeTo(thread_db* tdbb, jrd_tra* transaction, VerbAction* nextAction); - void undo(thread_db* tdbb, jrd_tra* transaction, bool preserveLocks, + void undo(thread_db* tdbb, jrd_tra* transaction, bool preserveLocks, VerbAction* preserveAction); void garbageCollectIdxLite(thread_db* tdbb, jrd_tra* transaction, SINT64 recordNumber, VerbAction* nextAction, Record* goingRecord); diff --git a/src/jrd/SysFunction.cpp b/src/jrd/SysFunction.cpp index 1edfc45383e..43a6f84a817 100644 --- a/src/jrd/SysFunction.cpp +++ b/src/jrd/SysFunction.cpp @@ -222,6 +222,7 @@ bool dscHasData(const dsc* param); // specific setParams functions void setParamsAsciiVal(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsBin(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); +void setParamsBlobAppend(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsCharToUuid(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsDateAdd(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); void setParamsDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, int argsCount, dsc** args); @@ -256,14 +257,15 @@ void makeAbs(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* r void makeAsciiChar(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeBin(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeBinShift(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeBlobAppend(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeCeilFloor(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeDateAdd(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeDecode64(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeEncode64(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeDecodeHex(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeEncodeHex(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); -void makeDecrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); -void makeEncrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeCrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeFirstLastDayResult(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeGetSetContext(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeGetTranCN(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); @@ -276,8 +278,7 @@ void makePi(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* re void makeReplace(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeReverse(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeRound(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); -void makeRsaDecrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); -void makeRsaEncrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); +void makeRsaCrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeRsaPrivate(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeRsaPublic(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); void makeRsaSign(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args); @@ -295,6 +296,7 @@ dsc* evlAsciiVal(thread_db* tdbb, const SysFunction* function, const NestValueAr dsc* evlAtan2(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlBin(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlBinShift(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); +dsc* evlBlobAppend(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlCeil(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlCharToUuid(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, impure_value* impure); @@ -377,8 +379,10 @@ const char WIRE_CRYPT_PLUGIN_NAME[] = "WIRE_CRYPT_PLUGIN", CLIENT_ADDRESS_NAME[] = "CLIENT_ADDRESS", CLIENT_HOST_NAME[] = "CLIENT_HOST", + CLIENT_OS_USER_NAME[] = "CLIENT_OS_USER", CLIENT_PID_NAME[] = "CLIENT_PID", CLIENT_PROCESS_NAME[] = "CLIENT_PROCESS", + CLIENT_VERSION_NAME[] = "CLIENT_VERSION", CURRENT_USER_NAME[] = "CURRENT_USER", CURRENT_ROLE_NAME[] = "CURRENT_ROLE", SESSION_IDLE_TIMEOUT[] = "SESSION_IDLE_TIMEOUT", @@ -605,6 +609,19 @@ void setParamsAsciiVal(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc } +void setParamsBlobAppend(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) +{ + if (argsCount >= 1 && args[0]->isUnknown()) + args[0]->makeBlob(isc_blob_text, CS_dynamic); + + for (int i = 1; i < argsCount; ++i) + { + if (args[i]->isUnknown()) + args[i]->makeVarying(80, args[0]->getTextType()); + } +} + + void setParamsCharToUuid(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) { if (argsCount >= 1 && args[0]->isUnknown()) @@ -695,11 +712,12 @@ const unsigned RSA_CRYPT_ARG_VALUE = 0; const unsigned RSA_CRYPT_ARG_KEY = 1; const unsigned RSA_CRYPT_ARG_LPARAM = 2; const unsigned RSA_CRYPT_ARG_HASH = 3; -const unsigned RSA_CRYPT_ARG_MAX = 4; +const unsigned RSA_CRYPT_ARG_PKCS_1_5 = 4; +const unsigned RSA_CRYPT_ARG_MAX = 5; void setParamsRsaEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) { - fb_assert(argsCount == RSA_CRYPT_ARG_MAX); + fb_assert(argsCount == RSA_CRYPT_ARG_MAX || argsCount == RSA_CRYPT_ARG_MAX - 1); setParamVarying(args[RSA_CRYPT_ARG_VALUE], ttype_binary); setParamVarying(args[RSA_CRYPT_ARG_KEY], ttype_binary); @@ -709,6 +727,9 @@ void setParamsRsaEncrypt(DataTypeUtilBase*, const SysFunction*, int argsCount, d if (args[RSA_CRYPT_ARG_HASH]->dsc_length) args[RSA_CRYPT_ARG_HASH]->makeVarying(args[RSA_CRYPT_ARG_HASH]->getStringLength(), ttype_binary); + + if (argsCount == RSA_CRYPT_ARG_MAX) + args[RSA_CRYPT_ARG_PKCS_1_5]->makeShort(0); } @@ -716,11 +737,12 @@ const unsigned RSA_SIGN_ARG_VALUE = 0; const unsigned RSA_SIGN_ARG_KEY = 1; const unsigned RSA_SIGN_ARG_HASH = 2; const unsigned RSA_SIGN_ARG_SALTLEN = 3; -const unsigned RSA_SIGN_ARG_MAX = 4; +const unsigned RSA_SIGN_ARG_PKCS_1_5 = 4; +const unsigned RSA_SIGN_ARG_MAX = 5; void setParamsRsaSign(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) { - fb_assert(argsCount == RSA_SIGN_ARG_MAX); + fb_assert(argsCount == RSA_SIGN_ARG_MAX || argsCount == RSA_SIGN_ARG_MAX - 1); setParamVarying(args[RSA_SIGN_ARG_VALUE], ttype_binary); setParamVarying(args[RSA_SIGN_ARG_KEY], ttype_binary); @@ -730,6 +752,9 @@ void setParamsRsaSign(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc* if (args[RSA_SIGN_ARG_SALTLEN]->dsc_length) args[RSA_SIGN_ARG_SALTLEN]->makeShort(0); + + if (argsCount == RSA_SIGN_ARG_MAX) + args[RSA_SIGN_ARG_PKCS_1_5]->makeShort(0); } @@ -738,11 +763,12 @@ const unsigned RSA_VERIFY_ARG_SIGNATURE = 1; const unsigned RSA_VERIFY_ARG_KEY = 2; const unsigned RSA_VERIFY_ARG_HASH = 3; const unsigned RSA_VERIFY_ARG_SALTLEN = 4; -const unsigned RSA_VERIFY_ARG_MAX = 5; +const unsigned RSA_VERIFY_ARG_PKCS_1_5 = 5; +const unsigned RSA_VERIFY_ARG_MAX = 6; void setParamsRsaVerify(DataTypeUtilBase*, const SysFunction*, int argsCount, dsc** args) { - fb_assert(argsCount == RSA_VERIFY_ARG_MAX); + fb_assert(argsCount == RSA_VERIFY_ARG_MAX || argsCount == RSA_VERIFY_ARG_MAX - 1); setParamVarying(args[RSA_VERIFY_ARG_VALUE], ttype_binary); setParamVarying(args[RSA_VERIFY_ARG_KEY], ttype_binary); @@ -753,6 +779,9 @@ void setParamsRsaVerify(DataTypeUtilBase*, const SysFunction*, int argsCount, ds if (args[RSA_VERIFY_ARG_SALTLEN]->dsc_length) args[RSA_VERIFY_ARG_SALTLEN]->makeShort(0); + + if (argsCount == RSA_VERIFY_ARG_MAX) + args[RSA_VERIFY_ARG_PKCS_1_5]->makeShort(0); } @@ -808,11 +837,14 @@ void setParamsMakeDbkey(DataTypeUtilBase*, const SysFunction*, int argsCount, ds { // MAKE_DBKEY ( REL_NAME | REL_ID, RECNUM [, DPNUM [, PPNUM] ] ) - if (args[0]->isUnknown()) - args[0]->makeLong(0); + if (argsCount > 1) + { + if (args[0]->isUnknown()) + args[0]->makeLong(0); - if (args[1]->isUnknown()) - args[1]->makeInt64(0); + if (args[1]->isUnknown()) + args[1]->makeInt64(0); + } if (argsCount > 2 && args[2]->isUnknown()) args[2]->makeInt64(0); @@ -1207,6 +1239,69 @@ void makeBinShift(DataTypeUtilBase*, const SysFunction* function, dsc* result, } +bool makeBlobAppendBlob(dsc* result, const dsc* arg, bid* blob_id = nullptr) +{ + if (!arg) + return false; + + ISC_QUAD* ptr = reinterpret_cast(blob_id); + + if (arg->isBlob()) + { + result->makeBlob(arg->getBlobSubType(), arg->getTextType(), ptr); + return true; + } + + if (arg->isNull()) + return false; + + if (arg->isText()) + { + USHORT ttype = arg->getTextType(); + if (ttype == ttype_binary) + result->makeBlob(isc_blob_untyped, ttype_binary, ptr); + else + result->makeBlob(isc_blob_text, ttype, ptr); + } + else + { + result->makeBlob(isc_blob_text, ttype_ascii, ptr); + } + + return true; +} + + +void makeBlobAppend(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, + int argsCount, const dsc** args) +{ + fb_assert(argsCount >= function->minArgCount); + + result->makeBlob(isc_blob_untyped, ttype_binary); + result->setNullable(true); + + if (argsCount > 0) + { + for (int i = 0; i < argsCount; ++i) + { + if (makeBlobAppendBlob(result, args[i])) + break; + } + + result->setNullable(true); + + for (int i = 0; i < argsCount; ++i) + { + if (!args[i]->isNullable()) + { + result->setNullable(false); + break; + } + } + } +} + + void makeCeilFloor(DataTypeUtilBase*, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { @@ -1265,6 +1360,30 @@ void makeDateAdd(DataTypeUtilBase*, const SysFunction*, dsc* result, int argsCou } +void makeDateDiff(DataTypeUtilBase* dataTypeUtil, const SysFunction*, dsc* result, int argsCount, const dsc** args) +{ + if (dataTypeUtil->getDialect() == 1) + result->makeDouble(); + else + { + if (argsCount >= 1 && + args[0]->dsc_address && // constant + CVT_get_long(args[0], 0, JRD_get_thread_data()->getAttachment()->att_dec_status, ERR_post) == blr_extract_millisecond) + { + result->makeInt64(ISC_TIME_SECONDS_PRECISION_SCALE + 3); + } + else + result->makeInt64(0); + } + + bool isNullable; + if (initResult(result, argsCount, args, &isNullable)) + return; + + result->setNullable(isNullable); +} + + void makeFirstLastDayResult(DataTypeUtilBase*, const SysFunction*, dsc* result, int argsCount, const dsc** args) { @@ -1348,13 +1467,23 @@ unsigned decodeLen(unsigned len) } +unsigned characterLen(DataTypeUtilBase* dataTypeUtil, const dsc* arg) +{ + unsigned len = arg->getStringLength(); + unsigned maxBytes = dataTypeUtil->maxBytesPerChar(arg->getCharSet()); + fb_assert(maxBytes); + fb_assert(!(len % maxBytes)); + return len / maxBytes; +} + + void makeDecode64(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { fb_assert(argsCount == 1); if (args[0]->isBlob()) result->makeBlob(isc_blob_untyped, ttype_binary); else if (args[0]->isText()) - result->makeVarying(decodeLen(args[0]->getStringLength()), ttype_binary); + result->makeVarying(decodeLen(characterLen(dataTypeUtil, args[0])), ttype_binary); else status_exception::raise(Arg::Gds(isc_tom_strblob)); @@ -1375,7 +1504,13 @@ void makeEncode64(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, d if (args[0]->isBlob()) result->makeBlob(isc_blob_text, ttype_ascii); else if (args[0]->isText()) - result->makeVarying(encodeLen(args[0]->dsc_length), ttype_ascii); + { + unsigned len = encodeLen(args[0]->getStringLength()); + if (len <= MAX_VARY_COLUMN_SIZE) + result->makeVarying(len, ttype_ascii); + else + result->makeBlob(isc_blob_text, ttype_ascii); + } else status_exception::raise(Arg::Gds(isc_tom_strblob)); @@ -1390,7 +1525,7 @@ void makeDecodeHex(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, result->makeBlob(isc_blob_untyped, ttype_binary); else if (args[0]->isText()) { - unsigned len = args[0]->getStringLength(); + unsigned len = characterLen(dataTypeUtil, args[0]); if (len % 2 || !len) status_exception::raise(Arg::Gds(isc_odd_hex_len) << Arg::Num(len)); result->makeVarying(len / 2, ttype_binary); @@ -1408,7 +1543,13 @@ void makeEncodeHex(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, if (args[0]->isBlob()) result->makeBlob(isc_blob_text, ttype_ascii); else if (args[0]->isText()) - result->makeVarying(args[0]->dsc_length * 2, ttype_ascii); + { + unsigned len = args[0]->getStringLength() * 2; + if (len <= MAX_VARY_COLUMN_SIZE) + result->makeVarying(len, ttype_ascii); + else + result->makeBlob(isc_blob_text, ttype_ascii); + } else status_exception::raise(Arg::Gds(isc_tom_strblob)); @@ -1416,7 +1557,7 @@ void makeEncodeHex(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, } -void makeEncrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, +void makeCrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { fb_assert(argsCount == CRYPT_ARG_MAX); @@ -1430,40 +1571,16 @@ void makeEncrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, ds } -void makeDecrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, - int argsCount, const dsc** args) -{ - fb_assert(argsCount == CRYPT_ARG_MAX); - - if (args[0]->isBlob()) - result->makeBlob(0, ttype_none); - else - result->makeVarying(args[0]->getStringLength(), ttype_none); - - result->setNullable(args[0]->isNullable()); -} - - -void makeRsaEncrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, +void makeRsaCrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { - fb_assert(argsCount == RSA_CRYPT_ARG_MAX); + fb_assert(argsCount == RSA_CRYPT_ARG_MAX || argsCount == RSA_CRYPT_ARG_MAX - 1); result->makeVarying(256, ttype_binary); result->setNullable(args[0]->isNullable()); } -void makeRsaDecrypt(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, - int argsCount, const dsc** args) -{ - fb_assert(argsCount == RSA_CRYPT_ARG_MAX); - - result->makeVarying(255, ttype_none); - result->setNullable(args[0]->isNullable()); -} - - void makeLeftRight(DataTypeUtilBase* dataTypeUtil, const SysFunction* function, dsc* result, int argsCount, const dsc** args) { @@ -2195,6 +2312,149 @@ HUGEINT getScale(impure_value* impure) } +static void appendFromBlob(thread_db* tdbb, jrd_tra* transaction, blb* blob, + const dsc* blobDsc, const dsc* srcDsc) +{ + if (!srcDsc->dsc_address) + return; + + bid* srcBlobID = (bid*)srcDsc->dsc_address; + if (srcBlobID->isEmpty()) + return; + + if (memcmp(blobDsc->dsc_address, srcDsc->dsc_address, sizeof(bid)) == 0) + status_exception::raise(Arg::Gds(isc_random) << Arg::Str("Can not append blob to itself")); + + UCharBuffer bpb; + BLB_gen_bpb_from_descs(srcDsc, blobDsc, bpb); + + AutoBlb srcBlob(tdbb, blb::open2(tdbb, transaction, srcBlobID, bpb.getCount(), bpb.begin())); + + Database* dbb = tdbb->getDatabase(); + + HalfStaticArray buffer; + const SLONG buffSize = (srcBlob->getLevel() == 0) ? + MAX(BUFFER_LARGE, srcBlob->blb_length) : dbb->dbb_page_size - BLP_SIZE; + + UCHAR* buff = buffer.getBuffer(buffSize); + while (!(srcBlob->blb_flags & BLB_eof)) + { + const SLONG len = srcBlob->BLB_get_data(tdbb, buff, buffSize, false); + if (len) + blob->BLB_put_data(tdbb, buff, len); + } +} + + +dsc* evlBlobAppend(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, + impure_value* impure) +{ + jrd_req* request = tdbb->getRequest(); + jrd_tra* transaction = request ? request->req_transaction : tdbb->getTransaction(); + transaction = transaction->getOuter(); + + blb* blob = NULL; + bid blob_id; + dsc blobDsc; + + blob_id.clear(); + blobDsc.clear(); + + const dsc* argDsc = EVL_expr(tdbb, request, args[0]); + const bool arg0_null = (request->req_flags & req_null) || (argDsc == NULL); + + if (!arg0_null && argDsc->isBlob()) + { + blob_id = *reinterpret_cast(argDsc->dsc_address); + makeBlobAppendBlob(&blobDsc, argDsc, &blob_id); + } + + // Try to get blob type from declared var\param + if (!argDsc && (nodeIs(args[0]) || + nodeIs(args[0]) )) + { + argDsc = EVL_assign_to(tdbb, args[0]); + if (argDsc && argDsc->isBlob()) + makeBlobAppendBlob(&blobDsc, argDsc, &blob_id); + } + + bool copyBlob = !blob_id.isEmpty(); + if (copyBlob) + { + if (!blob_id.bid_internal.bid_relation_id) + { + if (!transaction->tra_blobs->locate(blob_id.bid_temp_id())) + status_exception::raise(Arg::Gds(isc_bad_segstr_id)); + + BlobIndex blobIdx = transaction->tra_blobs->current(); + if (!blobIdx.bli_materialized && (blobIdx.bli_blob_object->blb_flags & BLB_close_on_read)) + { + blob = blobIdx.bli_blob_object; + copyBlob = false; + } + } + } + + for (FB_SIZE_T i = 0; i < args.getCount(); i++) + { + if (i == 0) + { + if (arg0_null || argDsc->isBlob() && !copyBlob) + continue; + } + else + { + argDsc = EVL_expr(tdbb, request, args[i]); + if ((request->req_flags & req_null) || !argDsc) + continue; + } + + fb_assert(argDsc != nullptr); + + if (!blobDsc.isBlob()) + { + if (!makeBlobAppendBlob(&blobDsc, argDsc, &blob_id)) + continue; + } + + fb_assert(blobDsc.isBlob()); + + if (!blob) + { + UCharBuffer bpb; + BLB_gen_bpb_from_descs(&blobDsc, &blobDsc, bpb); + bpb.push(isc_bpb_storage); + bpb.push(1); + bpb.push(isc_bpb_storage_temp); + + blob = blb::create2(tdbb, transaction, &blob_id, bpb.getCount(), bpb.begin()); + blob->blb_flags |= BLB_stream | BLB_close_on_read; + blob->blb_charset = blobDsc.getCharSet(); + } + + if (!argDsc->isBlob()) + { + MoveBuffer temp; + UCHAR* addr = NULL; + SLONG len = MOV_make_string2(tdbb, argDsc, blob->blb_charset, &addr, temp); + + if (addr) + blob->BLB_put_data(tdbb, addr, len); + } + else + { + appendFromBlob(tdbb, transaction, blob, &blobDsc, argDsc); + } + } + + if (!blob) + return nullptr; + + EVL_make_value(tdbb, &blobDsc, impure); + return &impure->vlu_desc; +} + + dsc* evlCeil(thread_db* tdbb, const SysFunction*, const NestValueArray& args, impure_value* impure) { @@ -2485,9 +2745,10 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr ERR_post(Arg::Gds(rangeExceededStatus)); tm times; - timestamp.decode(×); + int fractions; + timestamp.decode(×, &fractions); times.tm_year += quantity; - timestamp.encode(×); + timestamp.encode(×, fractions); int day = times.tm_mday; timestamp.decode(×); @@ -2503,7 +2764,8 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr ERR_post(Arg::Gds(rangeExceededStatus)); tm times; - timestamp.decode(×); + int fractions; + timestamp.decode(×, &fractions); int md[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -2538,7 +2800,7 @@ dsc* evlDateAdd(thread_db* tdbb, const SysFunction* function, const NestValueArr else if (times.tm_mday < 1) times.tm_mday = 1; - timestamp.encode(×); + timestamp.encode(×, fractions); } break; @@ -2769,7 +3031,7 @@ class DataPipe if (!completed) { dsc result; - result.makeText(0, ttype_none, outBuf.begin()); + result.makeText(0, ttype_binary, outBuf.begin()); EVL_make_value(tdbb, &result, impure); impure->vlu_desc.setNull(); } @@ -2855,6 +3117,54 @@ class DataPipe }; +// Descriptor value loader, taking into an account BLOBs + +class DscValue +{ +public: + DscValue(thread_db* tdbb, const dsc* desc, const char* objectName = nullptr) + { + if (!desc) + l = 0; + else if (desc->isBlob()) + { + AutoPtr b(blb::open(tdbb, tdbb->getRequest()->req_transaction, (bid*) desc->dsc_address)); + if (b->blb_length > MAX_VARY_COLUMN_SIZE) + (Arg::Gds(isc_expression_eval_err) << Arg::Gds(isc_malformed_string)).raise(); + + UCHAR* data = buf.getBuffer(b->blb_length); + l = b->BLB_get_data(tdbb, data, b->blb_length, false); + v = data; + } + else + v = CVT_get_bytes(desc, l); + + if (l == 0) + { + if (objectName) + (Arg::Gds(isc_sysf_invalid_null_empty) << objectName).raise(); + + v = nullptr; + } + } + + unsigned getLength() const + { + return l; + } + + const UCHAR* getBytes() const + { + return v; + } + +private: + UCharBuffer buf; + const UCHAR* v; + unsigned l; +}; + + // Lists of constant parameter values class CodeValue @@ -2942,20 +3252,15 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV else if (modeName.hasData()) status_exception::raise(Arg::Gds(isc_tom_no_mode)); - unsigned len; - const void* data = CVT_get_bytes(dscs[CRYPT_ARG_KEY], len); - UCharBuffer key; - memcpy(key.getBuffer(len), data, len); + DscValue key(tdbb, dscs[CRYPT_ARG_KEY], "crypt key"); - UCharBuffer iv; - data = CVT_get_bytes(dscs[CRYPT_ARG_IV], len); + DscValue iv(tdbb, dscs[CRYPT_ARG_IV]); if ((m && (m->code != MODE_ECB)) || (a && (a->code != ALG_RC4))) // all other need IV { - if (!len) + if (!iv.getLength()) status_exception::raise(Arg::Gds(isc_tom_iv_miss)); - memcpy(iv.getBuffer(len), data, len); } - else if (len) + else if (iv.getLength()) status_exception::raise(Arg::Gds(isc_tom_no_iv)); const unsigned CTR_32 = 1; @@ -2991,27 +3296,30 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV if (dscHasData(dscs[CRYPT_ARG_COUNTER])) { ctrVal = MOV_get_int64(tdbb, dscs[CRYPT_ARG_COUNTER], 0); - if (m && ctrVal > key.getCount()) - status_exception::raise(Arg::Gds(isc_tom_ctr_big) << Arg::Num(ctrVal) << Arg::Num(key.getCount())); + if (m && ctrVal > key.getLength()) + status_exception::raise(Arg::Gds(isc_tom_ctr_big) << Arg::Num(ctrVal) << Arg::Num(key.getLength())); } } else if (dscHasData(dscs[CRYPT_ARG_COUNTER])) status_exception::raise(Arg::Gds(isc_tom_no_ctr) << (m ? "mode" : "cipher") << (m ? m->value : a->value)); + if (!dscs[CRYPT_ARG_VALUE]) + return nullptr; + // Run selected algorithm DataPipe dp(tdbb, dscs[CRYPT_ARG_VALUE], impure); if (m) { unsigned blockLen = cipher_descriptor[cipher].block_length; - if (iv.hasData() && iv.getCount() != blockLen) - status_exception::raise(Arg::Gds(isc_tom_iv_length) << Arg::Num(iv.getCount()) << Arg::Num(blockLen)); + if (iv.getLength() && iv.getLength() != blockLen) + status_exception::raise(Arg::Gds(isc_tom_iv_length) << Arg::Num(iv.getLength()) << Arg::Num(blockLen)); switch (m->code) { case MODE_ECB: { symmetric_ECB ecb; - tomCheck(ecb_start(cipher, key.begin(), key.getCount(), 0, &ecb), Arg::Gds(isc_tom_init_mode) << "ECB"); + tomCheck(ecb_start(cipher, key.getBytes(), key.getLength(), 0, &ecb), Arg::Gds(isc_tom_init_mode) << "ECB"); while (dp.hasData()) { @@ -3028,7 +3336,7 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case MODE_CBC: { symmetric_CBC cbc; - tomCheck(cbc_start(cipher, iv.begin(), key.begin(), key.getCount(), 0, &cbc), Arg::Gds(isc_tom_init_mode) << "CBC"); + tomCheck(cbc_start(cipher, iv.getBytes(), key.getBytes(), key.getLength(), 0, &cbc), Arg::Gds(isc_tom_init_mode) << "CBC"); while (dp.hasData()) { @@ -3045,7 +3353,7 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case MODE_CFB: { symmetric_CFB cfb; - tomCheck(cfb_start(cipher, iv.begin(), key.begin(), key.getCount(), 0, &cfb), Arg::Gds(isc_tom_init_mode) << "CFB"); + tomCheck(cfb_start(cipher, iv.getBytes(), key.getBytes(), key.getLength(), 0, &cfb), Arg::Gds(isc_tom_init_mode) << "CFB"); while (dp.hasData()) { @@ -3062,7 +3370,7 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case MODE_OFB: { symmetric_OFB ofb; - tomCheck(ofb_start(cipher, iv.begin(), key.begin(), key.getCount(), 0, &ofb), Arg::Gds(isc_tom_init_mode) << "OFB"); + tomCheck(ofb_start(cipher, iv.getBytes(), key.getBytes(), key.getLength(), 0, &ofb), Arg::Gds(isc_tom_init_mode) << "OFB"); while (dp.hasData()) { @@ -3079,7 +3387,7 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case MODE_CTR: { symmetric_CTR ctr; - tomCheck(ctr_start(cipher, iv.begin(), key.begin(), key.getCount(), 0, + tomCheck(ctr_start(cipher, iv.getBytes(), key.getBytes(), key.getLength(), 0, (c->code == CTR_LITTLE_ENDIAN ? CTR_COUNTER_LITTLE_ENDIAN : CTR_COUNTER_BIG_ENDIAN) | ctrVal, &ctr), Arg::Gds(isc_tom_init_mode) << "CTR"); @@ -3103,8 +3411,10 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV { case ALG_RC4: { + if (key.getLength() < 5) // 40 bit - constant from tomcrypt + (Arg::Gds(isc_tom_key_length) << Arg::Num(key.getLength()) << Arg::Num(4)).raise(); rc4_state rc4; - tomCheck(rc4_stream_setup(&rc4, key.begin(), key.getCount()), Arg::Gds(isc_tom_init_cip) << "RC4"); + tomCheck(rc4_stream_setup(&rc4, key.getBytes(), key.getLength()), Arg::Gds(isc_tom_init_cip) << "RC4"); while (dp.hasData()) { @@ -3119,25 +3429,25 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case ALG_CHACHA: { chacha_state chacha; - switch (key.getCount()) + switch (key.getLength()) { case 16: case 32: break; default: - status_exception::raise(Arg::Gds(isc_tom_chacha_key) << Arg::Num(key.getCount())); + status_exception::raise(Arg::Gds(isc_tom_chacha_key) << Arg::Num(key.getLength())); } - tomCheck(chacha_setup(&chacha, key.begin(), key.getCount(), 20), Arg::Gds(isc_tom_init_cip) << "CHACHA#20"); - switch (iv.getCount()) + tomCheck(chacha_setup(&chacha, key.getBytes(), key.getLength(), 20), Arg::Gds(isc_tom_init_cip) << "CHACHA#20"); + switch (iv.getLength()) { case 12: - tomCheck(chacha_ivctr32(&chacha, iv.begin(), iv.getCount(), ctrVal), Arg::Gds(isc_tom_setup_cip) << "CHACHA#20"); + tomCheck(chacha_ivctr32(&chacha, iv.getBytes(), iv.getLength(), ctrVal), Arg::Gds(isc_tom_setup_cip) << "CHACHA#20"); break; case 8: - tomCheck(chacha_ivctr64(&chacha, iv.begin(), iv.getCount(), ctrVal), Arg::Gds(isc_tom_setup_cip) << "CHACHA#20"); + tomCheck(chacha_ivctr64(&chacha, iv.getBytes(), iv.getLength(), ctrVal), Arg::Gds(isc_tom_setup_cip) << "CHACHA#20"); break; default: - status_exception::raise(Arg::Gds(isc_tom_setup_chacha) << Arg::Num(iv.getCount())); + status_exception::raise(Arg::Gds(isc_tom_setup_chacha) << Arg::Num(iv.getLength())); break; } @@ -3153,9 +3463,11 @@ dsc* evlEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const NestV case ALG_SOBER: { + if (key.getLength() < 4) // 4, 8, 12, ... + (Arg::Gds(isc_tom_key_length) << Arg::Num(key.getLength()) << Arg::Num(3)).raise(); sober128_state sober128; - tomCheck(sober128_stream_setup(&sober128, key.begin(), key.getCount()), Arg::Gds(isc_tom_init_cip) << "SOBER-128"); - tomCheck(sober128_stream_setiv(&sober128, iv.begin(), iv.getCount()), Arg::Gds(isc_tom_setup_cip) << "SOBER-128"); + tomCheck(sober128_stream_setup(&sober128, key.getBytes(), key.getLength()), Arg::Gds(isc_tom_init_cip) << "SOBER-128"); + tomCheck(sober128_stream_setiv(&sober128, iv.getBytes(), iv.getLength()), Arg::Gds(isc_tom_setup_cip) << "SOBER-128"); while (dp.hasData()) { @@ -3225,7 +3537,8 @@ dsc* evlEncodeDecode64(thread_db* tdbb, bool encodeFlag, const SysFunction* func out.resize(outLen); dsc result; - if (arg->isBlob()) + unsigned len = encodeLen(arg->getStringLength()); + if (arg->isBlob() || (encodeFlag && len > MAX_VARY_COLUMN_SIZE)) { AutoPtr blob(blb::create2(tdbb, tdbb->getRequest()->req_transaction, &impure->vlu_misc.vlu_bid, sizeof(streamBpb), streamBpb)); @@ -3341,6 +3654,7 @@ dsc* evlEncodeDecodeHex(thread_db* tdbb, bool encodeFlag, const SysFunction* fun status_exception::raise(Arg::Gds(isc_odd_hex_len) << Arg::Num(pos)); dsc result; + bool mkBlob = true; if (arg->isBlob()) { if(out.hasData()) @@ -3351,12 +3665,30 @@ dsc* evlEncodeDecodeHex(thread_db* tdbb, bool encodeFlag, const SysFunction* fun inBlob->BLB_close(tdbb); inBlob.release(); + } + else + { + if (encodeFlag && arg->getStringLength() * 2 > MAX_VARY_COLUMN_SIZE) + { + outBlob.reset(blb::create2(tdbb, tdbb->getRequest()->req_transaction, + &impure->vlu_misc.vlu_bid, sizeof(streamBpb), streamBpb)); + if(out.hasData()) + outBlob->BLB_put_data(tdbb, out.begin(), out.getCount()); + outBlob->BLB_close(tdbb); + outBlob.release(); + } + else + { + result.makeText(out.getCount(), encodeFlag ? ttype_ascii : ttype_binary, const_cast(out.begin())); + mkBlob = false; + } + } + if (mkBlob) + { result.makeBlob(encodeFlag ? isc_blob_text : isc_blob_untyped, encodeFlag ? ttype_ascii : ttype_binary, (ISC_QUAD*)&impure->vlu_misc.vlu_bid); } - else - result.makeText(out.getCount(), encodeFlag ? ttype_ascii : ttype_binary, const_cast(out.begin())); EVL_make_value(tdbb, &result, impure); return &impure->vlu_desc; @@ -3377,14 +3709,15 @@ dsc* evlRsaEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const Ne { tomcryptInitializer(); - fb_assert(args.getCount() == RSA_CRYPT_ARG_MAX); + fb_assert(args.getCount() == RSA_CRYPT_ARG_MAX || args.getCount() == RSA_CRYPT_ARG_MAX - 1); jrd_req* request = tdbb->getRequest(); // parse args and check correctness const dsc* dscs[RSA_CRYPT_ARG_MAX]; - for (unsigned i = 0; i < RSA_CRYPT_ARG_MAX; ++i) + for (unsigned i = 0; i < args.getCount(); ++i) dscs[i] = EVL_expr(tdbb, request, args[i]); + SSHORT pkcs15 = args.getCount() < RSA_CRYPT_ARG_MAX ? 0 : *(SSHORT*)(dscs[RSA_CRYPT_ARG_PKCS_1_5]->dsc_address); MetaName hashName; if (dscs[RSA_CRYPT_ARG_HASH]) @@ -3397,31 +3730,30 @@ dsc* evlRsaEncryptDecrypt(thread_db* tdbb, const SysFunction* function, const Ne if (hash < 0) status_exception::raise(Arg::Gds(isc_tom_hash_bad) << hashName); - unsigned len; - const UCHAR* data = CVT_get_bytes(dscs[RSA_CRYPT_ARG_VALUE], len); - if (!data) + DscValue data(tdbb, dscs[RSA_CRYPT_ARG_VALUE]); + if (!data.getBytes()) return nullptr; - unsigned keyLen; - const UCHAR* key = CVT_get_bytes(dscs[RSA_CRYPT_ARG_KEY], keyLen); - if (!key) + DscValue key(tdbb, dscs[RSA_CRYPT_ARG_KEY], "crypt key"); + if (!key.getBytes()) return nullptr; - unsigned paramLen; - const UCHAR* lParam = CVT_get_bytes(dscs[RSA_CRYPT_ARG_LPARAM], paramLen); - if (!paramLen) - lParam = nullptr; + DscValue lParam(tdbb, dscs[RSA_CRYPT_ARG_LPARAM]); // Run tomcrypt functions rsa_key rsaKey; - tomCheck(rsa_import(key, keyLen, &rsaKey), Arg::Gds(isc_tom_rsa_import)); + tomCheck(rsa_import(key.getBytes(), key.getLength(), &rsaKey), Arg::Gds(isc_tom_rsa_import)); unsigned long outlen = encryptFlag ? 256 : 190; UCharBuffer outBuf; int stat = 0; - int cryptRc = encryptFlag ? rsa_encrypt_key(data, len, outBuf.getBuffer(outlen), &outlen, lParam, paramLen, - prng().getState(), prng().getIndex(), hash, &rsaKey) : - rsa_decrypt_key(data, len, outBuf.getBuffer(outlen), &outlen, lParam, paramLen, hash, &stat, &rsaKey); + int cryptRc = encryptFlag ? + rsa_encrypt_key_ex(data.getBytes(), data.getLength(), outBuf.getBuffer(outlen), &outlen, + lParam.getBytes(), lParam.getLength(), prng().getState(), prng().getIndex(), hash, + pkcs15 ? LTC_PKCS_1_V1_5 : LTC_PKCS_1_OAEP, &rsaKey) : + rsa_decrypt_key_ex(data.getBytes(), data.getLength(), outBuf.getBuffer(outlen), &outlen, + lParam.getBytes(), lParam.getLength(), hash, + pkcs15 ? LTC_PKCS_1_V1_5 : LTC_PKCS_1_OAEP, &stat, &rsaKey); rsa_free(&rsaKey); tomCheck(cryptRc, Arg::Gds(encryptFlag ? isc_tom_crypt_cip : isc_tom_decrypt_cip) << "RSA"); if ((!encryptFlag) && (!stat)) @@ -3486,12 +3818,11 @@ dsc* evlRsaPublic(thread_db* tdbb, const SysFunction* function, const NestValueA if (request->req_flags & req_null) // return NULL if value is NULL return NULL; - unsigned len; - const UCHAR* data = CVT_get_bytes(value, len); + DscValue data(tdbb, value, "private key"); rsa_key rsaKey; - tomCheck(rsa_import(data, len, &rsaKey), Arg::Gds(isc_tom_rsa_import)); + tomCheck(rsa_import(data.getBytes(), data.getLength(), &rsaKey), Arg::Gds(isc_tom_rsa_import)); - unsigned long outlen = len; + unsigned long outlen = data.getLength(); UCharBuffer key; int cryptRc = rsa_export(key.getBuffer(outlen), &outlen, PK_PUBLIC, &rsaKey); rsa_free(&rsaKey); @@ -3508,15 +3839,17 @@ dsc* evlRsaSign(thread_db* tdbb, const SysFunction* function, const NestValueArr { tomcryptInitializer(); - fb_assert(args.getCount() == RSA_SIGN_ARG_MAX); + fb_assert(args.getCount() == RSA_SIGN_ARG_MAX || args.getCount() == RSA_SIGN_ARG_MAX - 1); jrd_req* request = tdbb->getRequest(); // parse args and check correctness const dsc* dscs[RSA_SIGN_ARG_MAX]; - for (unsigned i = 0; i < RSA_SIGN_ARG_MAX; ++i) + for (unsigned i = 0; i < args.getCount(); ++i) dscs[i] = EVL_expr(tdbb, request, args[i]); + SSHORT pkcs15 = args.getCount() < RSA_SIGN_ARG_MAX ? 0 : *(SSHORT*)(dscs[RSA_SIGN_ARG_PKCS_1_5]->dsc_address); + MetaName hashName; if (dscs[RSA_SIGN_ARG_HASH]) MOV_get_metaname(tdbb, dscs[RSA_SIGN_ARG_HASH], hashName); @@ -3528,10 +3861,15 @@ dsc* evlRsaSign(thread_db* tdbb, const SysFunction* function, const NestValueArr if (hash < 0) status_exception::raise(Arg::Gds(isc_tom_hash_bad) << hashName); - unsigned len; - const UCHAR* data = CVT_get_bytes(dscs[RSA_SIGN_ARG_VALUE], len); - if (!data) + DscValue data(tdbb, dscs[RSA_SIGN_ARG_VALUE]); + if (!data.getBytes()) + return nullptr; + + DscValue key(tdbb, dscs[RSA_SIGN_ARG_KEY], "private key"); + if (!key.getBytes()) return nullptr; + rsa_key rsaKey; + tomCheck(rsa_import(key.getBytes(), key.getLength(), &rsaKey), Arg::Gds(isc_tom_rsa_import)); SLONG saltLength = 8; if (dscHasData(dscs[RSA_SIGN_ARG_SALTLEN])) @@ -3541,17 +3879,10 @@ dsc* evlRsaSign(thread_db* tdbb, const SysFunction* function, const NestValueArr status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); } - unsigned keyLen; - const UCHAR* key = CVT_get_bytes(dscs[RSA_SIGN_ARG_KEY], keyLen); - if (!key) - return nullptr; - rsa_key rsaKey; - tomCheck(rsa_import(key, keyLen, &rsaKey), Arg::Gds(isc_tom_rsa_import)); - unsigned long signLen = 1024; UCharBuffer sign; - int cryptRc = rsa_sign_hash(data, len, sign.getBuffer(signLen), &signLen, - prng().getState(), prng().getIndex(), hash, saltLength, &rsaKey); + int cryptRc = rsa_sign_hash_ex(data.getBytes(), data.getLength(), sign.getBuffer(signLen), &signLen, + pkcs15 ? LTC_PKCS_1_V1_5 : LTC_PKCS_1_PSS, prng().getState(), prng().getIndex(), hash, saltLength, &rsaKey); rsa_free(&rsaKey); tomCheck(cryptRc, Arg::Gds(isc_tom_rsa_sign)); @@ -3577,14 +3908,15 @@ dsc* evlRsaVerify(thread_db* tdbb, const SysFunction* function, const NestValueA { tomcryptInitializer(); - fb_assert(args.getCount() == RSA_VERIFY_ARG_MAX); + fb_assert(args.getCount() == RSA_VERIFY_ARG_MAX || args.getCount() == RSA_VERIFY_ARG_MAX - 1); jrd_req* request = tdbb->getRequest(); // parse args and check correctness const dsc* dscs[RSA_VERIFY_ARG_MAX]; - for (unsigned i = 0; i < RSA_VERIFY_ARG_MAX; ++i) + for (unsigned i = 0; i < args.getCount(); ++i) dscs[i] = EVL_expr(tdbb, request, args[i]); + SSHORT pkcs15 = args.getCount() < RSA_VERIFY_ARG_MAX ? 0 : *(SSHORT*)(dscs[RSA_VERIFY_ARG_PKCS_1_5]->dsc_address); MetaName hashName; if (dscs[RSA_VERIFY_ARG_HASH]) @@ -3597,15 +3929,19 @@ dsc* evlRsaVerify(thread_db* tdbb, const SysFunction* function, const NestValueA if (hash < 0) status_exception::raise(Arg::Gds(isc_tom_hash_bad) << hashName); - unsigned len; - const UCHAR* data = CVT_get_bytes(dscs[RSA_VERIFY_ARG_VALUE], len); - if (!data) + DscValue data(tdbb, dscs[RSA_VERIFY_ARG_VALUE]); + if (!data.getBytes()) return nullptr; - unsigned signLen; - const UCHAR* sign = CVT_get_bytes(dscs[RSA_VERIFY_ARG_SIGNATURE], signLen); - if (!sign) + DscValue sign(tdbb, dscs[RSA_VERIFY_ARG_SIGNATURE]); + if (!sign.getBytes()) + return boolResult(tdbb, impure, false); + + DscValue key(tdbb, dscs[RSA_VERIFY_ARG_KEY], "public key"); + if (!key.getBytes()) return boolResult(tdbb, impure, false); + rsa_key rsaKey; + tomCheck(rsa_import(key.getBytes(), key.getLength(), &rsaKey), Arg::Gds(isc_tom_rsa_import)); SLONG saltLength = 8; if (dscHasData(dscs[RSA_VERIFY_ARG_SALTLEN])) @@ -3615,15 +3951,9 @@ dsc* evlRsaVerify(thread_db* tdbb, const SysFunction* function, const NestValueA status_exception::raise(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); } - unsigned keyLen; - const UCHAR* key = CVT_get_bytes(dscs[RSA_VERIFY_ARG_KEY], keyLen); - if (!key) - return boolResult(tdbb, impure, false); - rsa_key rsaKey; - tomCheck(rsa_import(key, keyLen, &rsaKey), Arg::Gds(isc_tom_rsa_import)); - int state = 0; - int cryptRc = rsa_verify_hash(sign, signLen, data, len, hash, saltLength, &state, &rsaKey); + int cryptRc = rsa_verify_hash_ex(sign.getBytes(), sign.getLength(), data.getBytes(), data.getLength(), + pkcs15 ? LTC_PKCS_1_V1_5 : LTC_PKCS_1_PSS, hash, saltLength, &state, &rsaKey); rsa_free(&rsaKey); if (cryptRc != CRYPT_INVALID_PACKET) tomCheck(cryptRc, Arg::Gds(isc_tom_rsa_verify)); @@ -3797,6 +4127,7 @@ dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueAr } SINT64 result = 0; + SCHAR scale = 0; switch (part) { @@ -3843,10 +4174,9 @@ dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueAr case blr_extract_millisecond: result = (SINT64) ONE_DAY * - (timestamp2.value().timestamp_date - timestamp1.value().timestamp_date) * 1000; - result += ((SINT64) timestamp2.value().timestamp_time - - (SINT64) timestamp1.value().timestamp_time) / - (ISC_TIME_SECONDS_PRECISION / 1000); + (timestamp2.value().timestamp_date - timestamp1.value().timestamp_date) * ISC_TIME_SECONDS_PRECISION; + result += (SINT64) timestamp2.value().timestamp_time - (SINT64) timestamp1.value().timestamp_time; + scale = ISC_TIME_SECONDS_PRECISION_SCALE + 3; break; default: @@ -3858,7 +4188,7 @@ dsc* evlDateDiff(thread_db* tdbb, const SysFunction* function, const NestValueAr } impure->vlu_misc.vlu_int64 = result; - impure->vlu_desc.makeInt64(0, &impure->vlu_misc.vlu_int64); + impure->vlu_desc.makeInt64(scale, &impure->vlu_misc.vlu_int64); return &impure->vlu_desc; } @@ -4191,6 +4521,11 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar resultStr = RO_VALUE; else if (dbb->dbb_replica_mode == REPLICA_READ_WRITE) resultStr = RW_VALUE; + else + { + fb_assert(dbb->dbb_replica_mode == REPLICA_NONE); + return NULL; + } } else if (nameStr == SESSION_ID_NAME) resultStr.printf("%" SQUADFORMAT, PAG_attachment_id(tdbb)); @@ -4236,6 +4571,13 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar resultStr = attachment->att_remote_host; } + else if (nameStr == CLIENT_OS_USER_NAME) + { + if (attachment->att_remote_os_user.isEmpty()) + return NULL; + + resultStr = attachment->att_remote_os_user; + } else if (nameStr == CLIENT_PID_NAME) { if (!attachment->att_remote_pid) @@ -4250,24 +4592,29 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar resultStr = attachment->att_remote_process.ToString(); } + else if (nameStr == CLIENT_VERSION_NAME) + { + if (attachment->att_client_version.isEmpty()) + return NULL; + + resultStr = attachment->att_client_version; + } else if (nameStr == CURRENT_USER_NAME) { - MetaName user; - if (attachment->att_user) - user = attachment->att_user->getUserName(); + const MetaString& user = attachment->getUserName(); if (user.isEmpty()) return NULL; + resultStr = user.c_str(); } else if (nameStr == CURRENT_ROLE_NAME) { - MetaName role; - if (attachment->att_user) - role = attachment->att_user->getSqlRole(); + const MetaString& role = attachment->getSqlRole(); if (role.isEmpty()) return NULL; + resultStr = role.c_str(); } else if (nameStr == SESSION_IDLE_TIMEOUT) @@ -4322,14 +4669,11 @@ dsc* evlGetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar resultStr.printf("%" UQUADFORMAT, dbb->getReplSequence(tdbb)); else if (nameStr == EFFECTIVE_USER_NAME) { - MetaName user; - if (attachment->att_ss_user) - user = attachment->att_ss_user->getUserName(); - else if (attachment->att_user) - user = attachment->att_user->getUserName(); + const MetaString& user = attachment->getEffectiveUserName(); if (user.isEmpty()) return NULL; + resultStr = user.c_str(); } else if (nameStr == SESSION_TIMEZONE) @@ -4482,7 +4826,7 @@ dsc* evlSetContext(thread_db* tdbb, const SysFunction*, const NestValueArray& ar { // "Invalid namespace name %s passed to %s" ERR_post(Arg::Gds(isc_ctx_namespace_invalid) << - Arg::Str(nameStr) << Arg::Str(RDB_SET_CONTEXT)); + Arg::Str(nameSpaceStr) << Arg::Str(RDB_SET_CONTEXT)); } string valueStr; @@ -5025,19 +5369,22 @@ dsc* evlMakeDbkey(Jrd::thread_db* tdbb, const SysFunction* function, const NestV dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValueArray& args, - impure_value*) + impure_value* impure) { fb_assert(args.getCount() >= 1); fb_assert(function->misc != NULL); - jrd_req* request = tdbb->getRequest(); - dsc* result = NULL; + const auto request = tdbb->getRequest(); + HalfStaticArray argTypes(args.getCount()); + dsc* result = nullptr; for (FB_SIZE_T i = 0; i < args.getCount(); ++i) { - dsc* value = EVL_expr(tdbb, request, args[i]); + const auto value = EVL_expr(tdbb, request, args[i]); if (request->req_flags & req_null) // return NULL if value is NULL - return NULL; + return nullptr; + + argTypes.add(value); if (i == 0) result = value; @@ -5061,7 +5408,39 @@ dsc* evlMaxMinValue(thread_db* tdbb, const SysFunction* function, const NestValu } } - return result; + DataTypeUtil(tdbb).makeFromList(&impure->vlu_desc, function->name, argTypes.getCount(), argTypes.begin()); + + if (impure->vlu_desc.isText()) + { + const USHORT length = impure->vlu_desc.dsc_length; + + // Allocate a string block of sufficient size + + auto string = impure->vlu_string; + + if (string && string->str_length < length) + { + delete string; + string = nullptr; + } + + if (!string) + { + string = impure->vlu_string = FB_NEW_RPT(*tdbb->getDefaultPool(), length) VaryingString(); + string->str_length = length; + } + + impure->vlu_desc.dsc_address = string->str_data; + } + else + impure->vlu_desc.dsc_address = (UCHAR*) &impure->vlu_misc; + + MOV_move(tdbb, result, &impure->vlu_desc); + + if (impure->vlu_desc.dsc_dtype == dtype_text) + INTL_adjust_text_descriptor(tdbb, &impure->vlu_desc); + + return &impure->vlu_desc; } @@ -6376,6 +6755,7 @@ const SysFunction SysFunction::functions[] = {"BIN_SHL_ROT", 2, 2, setParamsInteger, makeBinShift, evlBinShift, (void*) funBinShlRot}, {"BIN_SHR_ROT", 2, 2, setParamsInteger, makeBinShift, evlBinShift, (void*) funBinShrRot}, {"BIN_XOR", 2, -1, setParamsBin, makeBin, evlBin, (void*) funBinXor}, + {"BLOB_APPEND", 2, -1, setParamsBlobAppend, makeBlobAppend, evlBlobAppend, NULL}, {"CEIL", 1, 1, setParamsDblDec, makeCeilFloor, evlCeil, NULL}, {"CEILING", 1, 1, setParamsDblDec, makeCeilFloor, evlCeil, NULL}, {"CHAR_TO_UUID", 1, 1, setParamsCharToUuid, makeUuid, evlCharToUuid, NULL}, @@ -6385,9 +6765,9 @@ const SysFunction SysFunction::functions[] = {"COT", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfCot}, {"CRYPT_HASH", 2, 2, setParamsHash, makeHash, evlHash, NULL}, {"DATEADD", 3, 3, setParamsDateAdd, makeDateAdd, evlDateAdd, NULL}, - {"DATEDIFF", 3, 3, setParamsDateDiff, makeInt64Result, evlDateDiff, NULL}, - {"DECRYPT", 7, 7, setParamsEncrypt, makeDecrypt, evlDecrypt, NULL}, - {"ENCRYPT", 7, 7, setParamsEncrypt, makeEncrypt, evlEncrypt, NULL}, + {"DATEDIFF", 3, 3, setParamsDateDiff, makeDateDiff, evlDateDiff, NULL}, + {"DECRYPT", CRYPT_ARG_MAX, CRYPT_ARG_MAX, setParamsEncrypt, makeCrypt, evlDecrypt, NULL}, + {"ENCRYPT", CRYPT_ARG_MAX, CRYPT_ARG_MAX, setParamsEncrypt, makeCrypt, evlEncrypt, NULL}, {"EXP", 1, 1, setParamsDblDec, makeDblDecResult, evlExp, NULL}, {"FIRST_DAY", 2, 2, setParamsFirstLastDay, makeFirstLastDayResult, evlFirstLastDay, (void*) funFirstDay}, {"FLOOR", 1, 1, setParamsDblDec, makeCeilFloor, evlFloor, NULL}, @@ -6422,12 +6802,12 @@ const SysFunction SysFunction::functions[] = {"RIGHT", 2, 2, setParamsSecondInteger, makeLeftRight, evlRight, NULL}, {"ROUND", 1, 2, setParamsRoundTrunc, makeRound, evlRound, NULL}, {"RPAD", 2, 3, setParamsSecondInteger, makePad, evlPad, (void*) funRPad}, - {"RSA_DECRYPT", 4, 4, setParamsRsaEncrypt, makeRsaDecrypt, evlRsaDecrypt, NULL}, - {"RSA_ENCRYPT", 4, 4, setParamsRsaEncrypt, makeRsaEncrypt, evlRsaEncrypt, NULL}, + {"RSA_DECRYPT", RSA_CRYPT_ARG_MAX, RSA_CRYPT_ARG_MAX, setParamsRsaEncrypt, makeRsaCrypt, evlRsaDecrypt, NULL}, + {"RSA_ENCRYPT", RSA_CRYPT_ARG_MAX, RSA_CRYPT_ARG_MAX, setParamsRsaEncrypt, makeRsaCrypt, evlRsaEncrypt, NULL}, {"RSA_PRIVATE", 1, 1, setParamsInteger, makeRsaPrivate, evlRsaPrivate, NULL}, {"RSA_PUBLIC", 1, 1, setParamsRsaPublic, makeRsaPublic, evlRsaPublic, NULL}, - {"RSA_SIGN", 4, 4, setParamsRsaSign, makeRsaSign, evlRsaSign, NULL}, - {"RSA_VERIFY", 5, 5, setParamsRsaVerify, makeBoolResult, evlRsaVerify, NULL}, + {"RSA_SIGN_HASH", RSA_SIGN_ARG_MAX, RSA_SIGN_ARG_MAX, setParamsRsaSign, makeRsaSign, evlRsaSign, NULL}, + {"RSA_VERIFY_HASH", RSA_VERIFY_ARG_MAX, RSA_VERIFY_ARG_MAX, setParamsRsaVerify, makeBoolResult, evlRsaVerify, NULL}, {"SIGN", 1, 1, setParamsDblDec, makeShortResult, evlSign, NULL}, {"SIN", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfSin}, {"SINH", 1, 1, setParamsDouble, makeDoubleResult, evlStdMath, (void*) trfSinh}, diff --git a/src/jrd/TempSpace.cpp b/src/jrd/TempSpace.cpp index 207436cacfe..3ef28f7f455 100644 --- a/src/jrd/TempSpace.cpp +++ b/src/jrd/TempSpace.cpp @@ -49,36 +49,35 @@ namespace class TempCacheLimitGuard { public: - explicit TempCacheLimitGuard(FB_SIZE_T size) - : m_dbb(GET_DBB()), m_size(size), - m_guard(m_dbb->dbb_temp_cache_mutex, FB_FUNCTION) - { - m_allowed = (m_dbb->dbb_temp_cache_size + size <= m_dbb->dbb_config->getTempCacheLimit()); - } + explicit TempCacheLimitGuard(Database* dbb) : + m_dbb(dbb), + m_size(0) + {} - bool isAllowed() const + ~TempCacheLimitGuard() { - return m_allowed; + if (m_size) + m_dbb->decTempCacheUsage(m_size); } - void increment() + bool reserve(FB_SIZE_T size) { - fb_assert(m_allowed); - m_dbb->dbb_temp_cache_size += m_size; + if (m_dbb->incTempCacheUsage(size)) + { + m_size = size; + return true; + } + return false; } - static void decrement(FB_SIZE_T size) + void commit() { - Database* const dbb = GET_DBB(); - MutexLockGuard guard(dbb->dbb_temp_cache_mutex, FB_FUNCTION); - dbb->dbb_temp_cache_size -= size; + m_size = 0; } private: Database* const m_dbb; FB_SIZE_T m_size; - MutexLockGuard m_guard; - bool m_allowed; }; } @@ -175,7 +174,11 @@ TempSpace::~TempSpace() head = temp; } - TempCacheLimitGuard::decrement(localCacheUsage); + if (localCacheUsage) + { + Database* const dbb = GET_DBB(); + dbb->decTempCacheUsage(localCacheUsage); + } while (tempFiles.getCount()) delete tempFiles.pop(); @@ -312,16 +315,16 @@ void TempSpace::extend(FB_SIZE_T size) Block* block = NULL; { // scope - TempCacheLimitGuard guard(size); + TempCacheLimitGuard guard(GET_DBB()); - if (guard.isAllowed()) + if (guard.reserve(size)) { try { // allocate block in virtual memory block = FB_NEW_POOL(pool) MemoryBlock(FB_NEW_POOL(pool) UCHAR[size], tail, size); localCacheUsage += size; - guard.increment(); + guard.commit(); } catch (const BadAlloc&) { diff --git a/src/jrd/TempSpace.h b/src/jrd/TempSpace.h index da004f1b0dd..274c1db5ad3 100644 --- a/src/jrd/TempSpace.h +++ b/src/jrd/TempSpace.h @@ -209,7 +209,7 @@ class TempSpace : public Firebird::File Firebird::Array initialBuffer; bool initiallyDynamic; - typedef Firebird::BePlusTree FreeSegmentTree; + typedef Firebird::BePlusTree FreeSegmentTree; FreeSegmentTree freeSegments; static Firebird::GlobalPtr initMutex; diff --git a/src/jrd/ThreadCollect.h b/src/jrd/ThreadCollect.h new file mode 100644 index 00000000000..d1566825d0a --- /dev/null +++ b/src/jrd/ThreadCollect.h @@ -0,0 +1,138 @@ +/* + * PROGRAM: JRD threading support + * MODULE: ThreadCollect.h + * DESCRIPTION: Threads' group completion handling + * + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/ + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Alexander Peshkov + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2018, 2022 Alexander Peshkov + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + * + * + */ + +#ifndef JRD_THREADCOLLECT_H +#define JRD_THREADCOLLECT_H + +#include "../common/ThreadStart.h" +#include "../common/classes/alloc.h" +#include "../common/classes/array.h" +#include "../common/classes/locks.h" + + +namespace Jrd { + + class ThreadCollect + { + public: + ThreadCollect(MemoryPool& p) + : threads(p) + { } + + void join() + { + if (!threads.hasData()) + return; + + waitFor(threads); + } + + void ending(Thread::Handle& h) + { + // put thread into completion wait queue when it finished running + Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); + + for (unsigned n = 0; n < threads.getCount(); ++n) + { + if (threads[n].hndl == h) + { + threads[n].ending = true; + return; + } + } + + Thrd t = {h, true}; + threads.add(t); + } + + void running(Thread::Handle& h) + { + // put thread into completion wait queue when it starts running + Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); + + Thrd t = {h, false}; + threads.add(t); + } + + void houseKeeping() + { + if (!threads.hasData()) + return; + + // join finished threads + AllThreads t; + { // mutex scope + Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); + + for (unsigned n = 0; n < threads.getCount(); ) + { + if (threads[n].ending) + { + t.add(threads[n]); + threads.remove(n); + } + else + ++n; + } + } + + waitFor(t); + } + + private: + struct Thrd + { + Thread::Handle hndl; + bool ending; + }; + typedef Firebird::HalfStaticArray AllThreads; + + void waitFor(AllThreads& thr) + { + Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION); + while (thr.hasData()) + { + FB_SIZE_T n = thr.getCount() - 1; + Thrd t = thr[n]; + thr.remove(n); + { + Firebird::MutexUnlockGuard u(threadsMutex, FB_FUNCTION); + Thread::waitForCompletion(t.hndl); + fb_assert(t.ending); + } + } + } + + AllThreads threads; + Firebird::Mutex threadsMutex; + }; + +} // namespace Jrd + + +#endif // JRD_THREADCOLLECT_H diff --git a/src/jrd/UserManagement.cpp b/src/jrd/UserManagement.cpp index 5fa011b09e4..3b013cae1d8 100644 --- a/src/jrd/UserManagement.cpp +++ b/src/jrd/UserManagement.cpp @@ -375,6 +375,7 @@ void UserManagement::execute(USHORT id) LocalStatus status; CheckStatusWrapper statusWrapper(&status); ChangeCharset cc(att); + AutoSaveRestore restoreBindings(&att->att_bindings); if (command->attr.entered() || command->op == Auth::ADDMOD_OPER) { @@ -590,6 +591,7 @@ RecordBuffer* UserManagement::getList(thread_db* tdbb, jrd_rel* relation) try { openAllManagers(); + bool flagSuccess = false; LocalStatus st1, st2; CheckStatusWrapper statusWrapper1(&st1); @@ -598,6 +600,8 @@ RecordBuffer* UserManagement::getList(thread_db* tdbb, jrd_rel* relation) int errcode1, errcode2; int* ec(&errcode1); + AutoSaveRestore restoreBindings(&att->att_bindings); + threadDbb = tdbb; MemoryPool* const pool = threadDbb->getTransaction()->tra_pool; allocBuffer(threadDbb, *pool, rel_sec_users); diff --git a/src/jrd/align.h b/src/jrd/align.h index aa4631488d7..c94f0f4da35 100644 --- a/src/jrd/align.h +++ b/src/jrd/align.h @@ -114,7 +114,7 @@ static const USHORT type_alignments[DTYPE_TYPE_MAX] = sizeof(UCHAR), /* dtype_boolean */ sizeof(Firebird::Decimal64),/* dtype_dec64 */ sizeof(Firebird::Decimal64),/* dtype_dec128 */ - sizeof(Firebird::Decimal64),/* dtype_int128 */ + sizeof(SINT64), /* dtype_int128 */ sizeof(GDS_TIME), /* dtype_sql_time_tz */ sizeof(GDS_DATE), /* dtype_timestamp_tz */ sizeof(GDS_TIME), /* dtype_ex_time_tz */ diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index e7eeb129755..3cca7f4805e 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -59,6 +59,7 @@ #include "../jrd/dpm_proto.h" #include "../jrd/err_proto.h" #include "../jrd/evl_proto.h" +#include "../jrd/exe_proto.h" #include "../jrd/filte_proto.h" #include "../yvalve/gds_proto.h" #include "../jrd/intl_proto.h" @@ -113,7 +114,12 @@ void blb::BLB_cancel(thread_db* tdbb) // Release filter control resources if (blb_flags & BLB_temporary) + { + if (!(blb_flags & BLB_closed)) + blb_transaction->tra_temp_blobs_count--; + delete_blob(tdbb, 0); + } destroy(true); } @@ -189,11 +195,14 @@ bool blb::BLB_close(thread_db* tdbb) SET_TDBB(tdbb); + const bool alreadyClosed = (blb_flags & BLB_closed); + // Release filter control resources if (blb_filter) BLF_close_blob(tdbb, &blb_filter); + blb_flags &= ~BLB_close_on_read; blb_flags |= BLB_closed; if (!(blb_flags & BLB_temporary)) @@ -202,6 +211,9 @@ bool blb::BLB_close(thread_db* tdbb) return true; } + if (!alreadyClosed) + blb_transaction->tra_temp_blobs_count--; + if (blb_level == 0) { //Database* dbb = tdbb->getDatabase(); @@ -267,6 +279,40 @@ blb* blb::create2(thread_db* tdbb, Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); + const int maxTempBlobs = MAX_TEMP_BLOBS; + if (maxTempBlobs > 0 && transaction->tra_temp_blobs_count >= maxTempBlobs) + { + const jrd_req* request = tdbb->getRequest(); + string info; + + if (userBlob) + { + Attachment* att = tdbb->getAttachment(); + info = "By user application"; + if (att->att_remote_process.hasData()) + { + info += string(" (") + att->att_remote_process.c_str() + ")"; + } + } + else if (request) + { + const JrdStatement* const statement = request->getStatement(); + if (statement && statement->sqlText) + info = string("By query: ") + *statement->sqlText; + + string stack; + if (EXE_get_stack_trace(request, stack)) + { + info += "\n"; + info += stack; + } + } + + gds__log("Too many temporary blobs (%i allowed)\n%s", maxTempBlobs, info.c_str()); + + ERR_post(Arg::Gds(isc_random) << Arg::Str("Too many temporary blobs")); + } + // Create a blob large enough to hold a single data page SSHORT from, to; SSHORT from_charset, to_charset; @@ -322,6 +368,7 @@ blb* blb::create2(thread_db* tdbb, blob->blb_space_remaining = blob->blb_clump_size; blob->blb_flags |= BLB_temporary; + blob->blb_transaction->tra_temp_blobs_count++; if (filter_required) { @@ -401,6 +448,7 @@ void BLB_garbage_collect(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); + fb_assert(prior_page > 0); RecordBitmap bmGoing; ULONG cntGoing = 0; @@ -1163,7 +1211,10 @@ void blb::move(thread_db* tdbb, dsc* from_desc, dsc* to_desc, const record_param if (!blob || !(blob->blb_flags & BLB_closed)) { - ERR_post(Arg::Gds(isc_bad_segstr_id)); + if (blob && (blob->blb_flags & BLB_close_on_read)) + blob->BLB_close(tdbb); + else + ERR_post(Arg::Gds(isc_bad_segstr_id)); } if (blob->blb_level && (blob->blb_pg_space_id != relPages->rel_pg_space_id)) @@ -1327,7 +1378,7 @@ blb* blb::open2(thread_db* tdbb, */ // Search the index of transaction blobs for a match - const blb* new_blob = NULL; + blb* new_blob = NULL; if (transaction->tra_blobs->locate(blobId.bid_temp_id())) { current = &transaction->tra_blobs->current(); @@ -1342,7 +1393,10 @@ blb* blb::open2(thread_db* tdbb, if (!new_blob || !(new_blob->blb_flags & BLB_temporary) || !(new_blob->blb_flags & BLB_closed)) { - ERR_post(Arg::Gds(isc_bad_segstr_id)); + if (new_blob && (new_blob->blb_flags & BLB_close_on_read)) + new_blob->BLB_close(tdbb); + else + ERR_post(Arg::Gds(isc_bad_segstr_id)); } blob->blb_lead_page = new_blob->blb_lead_page; @@ -1542,7 +1596,7 @@ void blb::BLB_put_segment(thread_db* tdbb, const void* seg, USHORT segment_lengt // Make sure blob is a temporary blob. If not, complain bitterly. - if (!(blb_flags & BLB_temporary)) + if (!(blb_flags & BLB_temporary) || (blb_flags & BLB_closed)) ERR_post(Arg::Gds(isc_cannot_update_old_blob)); if (blb_filter) diff --git a/src/jrd/blb.h b/src/jrd/blb.h index 1bb8f1925fb..6f425bd5086 100644 --- a/src/jrd/blb.h +++ b/src/jrd/blb.h @@ -124,6 +124,13 @@ class blb : public pool_alloc void getFromPage(USHORT length, const UCHAR* data); void storeToPage(USHORT* length, Firebird::Array& buffer, const UCHAR** data, void* stack); + static bid copy(thread_db* tdbb, const bid* source) + { + bid destination; + copy_blob(tdbb, source, &destination, 0, nullptr, 0); + return destination; + } + private: static blb* allocate_blob(thread_db*, jrd_tra*); static blb* copy_blob(thread_db* tdbb, const bid* source, bid* destination, @@ -172,6 +179,7 @@ const int BLB_closed = 8; // Temporary blob has been closed const int BLB_damaged = 16; // Blob is busted const int BLB_seek = 32; // Seek is pending const int BLB_large_scan = 64; // Blob is larger than page buffer cache +const int BLB_close_on_read = 128; // Temporary blob is not closed until read /* Blob levels are: diff --git a/src/jrd/blp.h b/src/jrd/blp.h index af795117d35..e8b17425b00 100644 --- a/src/jrd/blp.h +++ b/src/jrd/blp.h @@ -30,7 +30,7 @@ static const struct {"begin", begin}, {"declare", declare}, {"message", message}, - {"erase", byte_line}, + {"erase", erase}, {"fetch", two}, {"for", two}, {"if", three}, @@ -57,7 +57,7 @@ static const struct {"maximum", two}, {"minimum", two}, // 30 {"total", two}, - {NULL, NULL}, // {"count2", two}, + {"receive_batch", byte_verb}, {NULL, NULL}, {"add", two}, {"subtract", two}, diff --git a/src/jrd/btr.cpp b/src/jrd/btr.cpp index d720e610b77..3015f9249b0 100644 --- a/src/jrd/btr.cpp +++ b/src/jrd/btr.cpp @@ -188,7 +188,8 @@ namespace static ULONG add_node(thread_db*, WIN*, index_insertion*, temporary_key*, RecordNumber*, ULONG*, ULONG*); -static void compress(thread_db*, const dsc*, temporary_key*, USHORT, bool, bool, USHORT); +static void compress(thread_db*, const dsc*, const SSHORT, temporary_key*, USHORT, bool, bool, + USHORT, bool*); static USHORT compress_root(thread_db*, index_root_page*); static void copy_key(const temporary_key*, temporary_key*); static contents delete_node(thread_db*, WIN*, UCHAR*); @@ -198,13 +199,13 @@ static ULONG fast_load(thread_db*, IndexCreation&, SelectivityList&); static index_root_page* fetch_root(thread_db*, WIN*, const jrd_rel*, const RelationPages*); static UCHAR* find_node_start_point(btree_page*, temporary_key*, UCHAR*, USHORT*, - bool, bool, bool = false, RecordNumber = NO_VALUE); + bool, int, bool = false, RecordNumber = NO_VALUE); static UCHAR* find_area_start_point(btree_page*, const temporary_key*, UCHAR*, - USHORT*, bool, bool, RecordNumber = NO_VALUE); + USHORT*, bool, int, RecordNumber = NO_VALUE); static ULONG find_page(btree_page*, const temporary_key*, const index_desc*, RecordNumber = NO_VALUE, - bool = false); + int = 0); static contents garbage_collect(thread_db*, WIN*, ULONG); static void generate_jump_nodes(thread_db*, btree_page*, JumpNodeList*, USHORT, @@ -222,7 +223,7 @@ static contents remove_node(thread_db*, index_insertion*, WIN*); static contents remove_leaf_node(thread_db*, index_insertion*, WIN*); static bool scan(thread_db*, UCHAR*, RecordBitmap**, RecordBitmap*, index_desc*, const IndexRetrieval*, USHORT, temporary_key*, - bool&, const temporary_key&); + bool&, const temporary_key&, USHORT); static void update_selectivity(index_root_page*, USHORT, const SelectivityList&); static void checkForLowerKeySkip(bool&, const bool, const IndexNode&, const temporary_key&, const index_desc&, const IndexRetrieval*); @@ -252,7 +253,9 @@ void BtrPageGCLock::disablePageGC(thread_db* tdbb, const PageNumber& page) void BtrPageGCLock::enablePageGC(thread_db* tdbb) { - LCK_release(tdbb, this); + fb_assert(lck_id); + if (lck_id) + LCK_release(tdbb, this); } bool BtrPageGCLock::isPageGCAllowed(thread_db* tdbb, const PageNumber& page) @@ -364,6 +367,10 @@ USHORT BTR_all(thread_db* tdbb, jrd_rel* relation, IndexDescAlloc** csb_idx, Rel if (!root) return 0; + Cleanup release_root([&] { + CCH_RELEASE(tdbb, &window); + }); + delete *csb_idx; *csb_idx = FB_NEW_RPT(*tdbb->getDefaultPool(), root->irt_count) IndexDescAlloc(); @@ -374,8 +381,6 @@ USHORT BTR_all(thread_db* tdbb, jrd_rel* relation, IndexDescAlloc** csb_idx, Rel if (BTR_description(tdbb, relation, root, &buffer[count], i)) count++; } - - CCH_RELEASE(tdbb, &window); return count; } @@ -392,9 +397,12 @@ void BTR_complement_key(temporary_key* key) * Negate a key for descending index. * **************************************/ - UCHAR* p = key->key_data; - for (const UCHAR* const end = p + key->key_length; p < end; p++) - *p ^= -1; + do + { + UCHAR* p = key->key_data; + for (const UCHAR* const end = p + key->key_length; p < end; p++) + *p ^= -1; + } while (key = key->key_next.get()); } @@ -528,7 +536,7 @@ bool BTR_description(thread_db* tdbb, jrd_rel* relation, index_root_page* root, idx_desc->idx_selectivity = key_descriptor->irtd_selectivity; ptr += sizeof(irtd); } - idx->idx_selectivity = idx_desc->idx_selectivity; + idx->idx_selectivity = idx->idx_rpt[idx->idx_count - 1].idx_selectivity; if (idx->idx_flags & idx_expressn) { @@ -577,9 +585,9 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool& Jrd::ContextPoolHolder context(tdbb, expr_request->req_pool); if (org_request) - expr_request->req_gmt_timestamp = org_request->req_gmt_timestamp; + expr_request->setGmtTimeStamp(org_request->getGmtTimeStamp()); else - TimeZoneUtil::validateGmtTimeStamp(expr_request->req_gmt_timestamp); + expr_request->validateTimeStamp(); if (!(result = EVL_expr(tdbb, expr_request, idx->idx_expression))) result = &idx->idx_expression_desc; @@ -594,7 +602,7 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool& expr_request->req_caller = NULL; expr_request->req_flags &= ~req_in_use; expr_request->req_attachment = NULL; - expr_request->req_gmt_timestamp.invalidate(); + expr_request->invalidateTimeStamp(); throw; } @@ -605,7 +613,7 @@ DSC* BTR_eval_expression(thread_db* tdbb, index_desc* idx, Record* record, bool& expr_request->req_caller = NULL; expr_request->req_flags &= ~req_in_use; expr_request->req_attachment = NULL; - expr_request->req_gmt_timestamp.invalidate(); + expr_request->invalidateTimeStamp(); return result; } @@ -650,28 +658,36 @@ static void checkForLowerKeySkip(bool& skipLowerKey, } else { - // Check if we have a duplicate node (for the same page) - if (node.prefix < lower.key_length) + if ((lower.key_length == node.prefix + node.length) || + ((lower.key_length <= node.prefix + node.length) && partLower)) { - if (node.prefix + node.length == lower.key_length) - skipLowerKey = (memcmp(node.data, lower.key_data + node.prefix, node.length) == 0); - else - skipLowerKey = false; - } - else if ((node.prefix == lower.key_length) && node.length) - { - // In case of multi-segment check segment-number else - // it's a different key - if (partLower) + const UCHAR* p = node.data, *q = lower.key_data + node.prefix; + const UCHAR* const end = lower.key_data + lower.key_length; + while (q < end) { - const USHORT segnum = idx.idx_count - (UCHAR)((idx.idx_flags & idx_descending) ? - (*node.data) ^ -1 : *node.data); + if (*p++ != *q++) + { + skipLowerKey = false; + break; + } + } + + if ((q >= end) && (p < node.data + node.length) && skipLowerKey && partLower) + { + const bool descending = idx.idx_flags & idx_descending; + + // since key length always is multiplier of (STUFF_COUNT + 1) (for partial + // compound keys) and we passed lower key completely then p pointed + // us to the next segment number and we can use this fact to calculate + // how many segments is equal to lower key + const USHORT segnum = idx.idx_count - (UCHAR) (descending ? ((*p) ^ -1) : *p); if (segnum < retrieval->irb_lower_count) skipLowerKey = false; } - else - skipLowerKey = false; + } + else { + skipLowerKey = false; } } } @@ -699,154 +715,136 @@ void BTR_evaluate(thread_db* tdbb, const IndexRetrieval* retrieval, RecordBitmap index_desc idx; RelationPages* relPages = retrieval->irb_relation->getPages(tdbb); WIN window(relPages->rel_pg_space_id, -1); - temporary_key lower, upper; - lower.key_flags = 0; - lower.key_length = 0; - upper.key_flags = 0; - upper.key_length = 0; - btree_page* page = BTR_find_page(tdbb, retrieval, &window, &idx, &lower, &upper); + temporary_key lowerKey, upperKey; + lowerKey.key_flags = 0; + lowerKey.key_length = 0; + upperKey.key_flags = 0; + upperKey.key_length = 0; + + temporary_key* lower = &lowerKey; + temporary_key* upper = &upperKey; + bool first = true; + USHORT forceInclFlag = 0; + + do + { + btree_page* page = BTR_find_page(tdbb, retrieval, &window, &idx, lower, upper, forceInclFlag, first); + first = false; + + const bool descending = (idx.idx_flags & idx_descending); + bool skipLowerKey = (retrieval->irb_generic & ~forceInclFlag) & irb_exclude_lower; + const bool partLower = (retrieval->irb_lower_count < idx.idx_count); + + // If there is a starting descriptor, search down index to starting position. + // This may involve sibling buckets if splits are in progress. If there + // isn't a starting descriptor, walk down the left side of the index. + USHORT prefix; + UCHAR* pointer; + if (retrieval->irb_lower_count) + { + while (!(pointer = find_node_start_point(page, lower, 0, &prefix, + idx.idx_flags & idx_descending, (retrieval->irb_generic & (irb_starting | irb_partial))))) + { + page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); + } - const bool descending = (idx.idx_flags & idx_descending); - bool skipLowerKey = (retrieval->irb_generic & irb_exclude_lower); - const bool partLower = (retrieval->irb_lower_count < idx.idx_count); + // Compute the number of matching characters in lower and upper bounds + if (retrieval->irb_upper_count) + { + prefix = IndexNode::computePrefix(upper->key_data, upper->key_length, + lower->key_data, lower->key_length); + } - // If there is a starting descriptor, search down index to starting position. - // This may involve sibling buckets if splits are in progress. If there - // isn't a starting descriptor, walk down the left side of the index. - USHORT prefix; - UCHAR* pointer; - if (retrieval->irb_lower_count) - { - while (!(pointer = find_node_start_point(page, &lower, 0, &prefix, - idx.idx_flags & idx_descending, (retrieval->irb_generic & (irb_starting | irb_partial))))) + if (skipLowerKey) + { + IndexNode node; + node.readNode(pointer, true); + checkForLowerKeySkip(skipLowerKey, partLower, node, *lower, idx, retrieval); + } + } + else { - page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); + pointer = page->btr_nodes + page->btr_jump_size; + prefix = 0; + skipLowerKey = false; } - // Compute the number of matching characters in lower and upper bounds + // if there is an upper bound, scan the index pages looking for it if (retrieval->irb_upper_count) { - prefix = IndexNode::computePrefix(upper.key_data, upper.key_length, - lower.key_data, lower.key_length); + while (scan(tdbb, pointer, bitmap, bitmap_and, &idx, retrieval, prefix, upper, + skipLowerKey, *lower, forceInclFlag)) + { + page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); + pointer = page->btr_nodes + page->btr_jump_size; + prefix = 0; + } } - - if (skipLowerKey) + else { + // if there isn't an upper bound, just walk the index to the end of the level + const UCHAR* endPointer = (UCHAR*) page + page->btr_length; + const bool ignoreNulls = + (retrieval->irb_generic & irb_ignore_null_value_key) && (idx.idx_count == 1); + IndexNode node; - node.readNode(pointer, true); + pointer = node.readNode(pointer, true); - if ((lower.key_length == node.prefix + node.length) || - ((lower.key_length <= node.prefix + node.length) && partLower)) + // Check if pointer is still valid + if (pointer > endPointer) + BUGCHECK(204); // msg 204 index inconsistent + + while (true) { - const UCHAR* p = node.data, *q = lower.key_data + node.prefix; - const UCHAR* const end = lower.key_data + lower.key_length; - while (q < end) + if (node.isEndLevel) + break; + + if (!node.isEndBucket) { - if (*p++ != *q++) + // If we're walking in a descending index and we need to ignore NULLs + // then stop at the first NULL we see (only for single segment!) + if (descending && ignoreNulls && node.prefix == 0 && + node.length >= 1 && node.data[0] == 255) { - skipLowerKey = false; break; } - } - if ((q >= end) && (p < node.data + node.length) && skipLowerKey && partLower) - { - // since key length always is multiplier of (STUFF_COUNT + 1) (for partial - // compound keys) and we passed lower key completely then p pointed - // us to the next segment number and we can use this fact to calculate - // how many segments is equal to lower key - const USHORT segnum = idx.idx_count - (UCHAR) (descending ? ((*p) ^ -1) : *p); - - if (segnum < retrieval->irb_lower_count) - skipLowerKey = false; - } - } - else - skipLowerKey = false; - } - } - else - { - pointer = page->btr_nodes + page->btr_jump_size; - prefix = 0; - skipLowerKey = false; - } + if (skipLowerKey) + checkForLowerKeySkip(skipLowerKey, partLower, node, *lower, idx, retrieval); - // if there is an upper bound, scan the index pages looking for it - if (retrieval->irb_upper_count) - { - while (scan(tdbb, pointer, bitmap, bitmap_and, &idx, retrieval, prefix, &upper, - skipLowerKey, lower)) - { - page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); - pointer = page->btr_nodes + page->btr_jump_size; - prefix = 0; - } - } - else - { - // if there isn't an upper bound, just walk the index to the end of the level - const UCHAR* endPointer = (UCHAR*) page + page->btr_length; - const bool ignoreNulls = - (retrieval->irb_generic & irb_ignore_null_value_key) && (idx.idx_count == 1); - - IndexNode node; - pointer = node.readNode(pointer, true); - - // Check if pointer is still valid - if (pointer > endPointer) - BUGCHECK(204); // msg 204 index inconsistent - - while (true) - { - if (node.isEndLevel) - break; + if (!skipLowerKey) + { + if (!bitmap_and || bitmap_and->test(node.recordNumber.getValue())) + RBM_SET(tdbb->getDefaultPool(), bitmap, node.recordNumber.getValue()); + } - if (!node.isEndBucket) - { - // If we're walking in a descending index and we need to ignore NULLs - // then stop at the first NULL we see (only for single segment!) - if (descending && ignoreNulls && node.prefix == 0 && - node.length >= 1 && node.data[0] == 255) - { - break; - } + pointer = node.readNode(pointer, true); - if (skipLowerKey) - checkForLowerKeySkip(skipLowerKey, partLower, node, lower, idx, retrieval); + // Check if pointer is still valid + if (pointer > endPointer) + BUGCHECK(204); // msg 204 index inconsistent - if (!skipLowerKey) - { - if (!bitmap_and || bitmap_and->test(node.recordNumber.getValue())) - RBM_SET(tdbb->getDefaultPool(), bitmap, node.recordNumber.getValue()); + continue; } + page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); + endPointer = (UCHAR*) page + page->btr_length; + pointer = page->btr_nodes + page->btr_jump_size; pointer = node.readNode(pointer, true); // Check if pointer is still valid if (pointer > endPointer) BUGCHECK(204); // msg 204 index inconsistent - - continue; } - - page = (btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); - endPointer = (UCHAR*) page + page->btr_length; - pointer = page->btr_nodes + page->btr_jump_size; - pointer = node.readNode(pointer, true); - - // Check if pointer is still valid - if (pointer > endPointer) - BUGCHECK(204); // msg 204 index inconsistent } - } - CCH_RELEASE(tdbb, &window); + CCH_RELEASE(tdbb, &window); + } while ((lower = lower->key_next.get()) && (upper = upper->key_next.get())); } UCHAR* BTR_find_leaf(btree_page* bucket, temporary_key* key, UCHAR* value, - USHORT* return_value, bool descending, bool retrieval) + USHORT* return_value, bool descending, int retrieval) { /************************************** * @@ -869,7 +867,9 @@ btree_page* BTR_find_page(thread_db* tdbb, WIN* window, index_desc* idx, temporary_key* lower, - temporary_key* upper) + temporary_key* upper, + USHORT& forceInclFlag, + bool makeKeys) { /************************************** * @@ -889,28 +889,43 @@ btree_page* BTR_find_page(thread_db* tdbb, // are looking for an equality if (retrieval->irb_key) { + fb_assert(makeKeys); copy_key(retrieval->irb_key, lower); copy_key(retrieval->irb_key, upper); } - else + else if (makeKeys) { idx_e errorCode = idx_e_ok; + const USHORT keyType = + (retrieval->irb_generic & irb_multi_starting) ? INTL_KEY_MULTI_STARTING : + (retrieval->irb_generic & irb_starting) ? INTL_KEY_PARTIAL : + (retrieval->irb_desc.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : + INTL_KEY_SORT; + + forceInclFlag &= ~(irb_force_lower | irb_force_upper); + if (retrieval->irb_upper_count) { + bool forceInclude = false; errorCode = BTR_make_key(tdbb, retrieval->irb_upper_count, retrieval->irb_value + retrieval->irb_desc.idx_count, - &retrieval->irb_desc, upper, - (retrieval->irb_generic & irb_starting) != 0); + retrieval->irb_scale, &retrieval->irb_desc, upper, + keyType, &forceInclude); + if (forceInclude) + forceInclFlag |= irb_force_upper; } if (errorCode == idx_e_ok) { if (retrieval->irb_lower_count) { + bool forceInclude = false; errorCode = BTR_make_key(tdbb, retrieval->irb_lower_count, - retrieval->irb_value, &retrieval->irb_desc, lower, - (retrieval->irb_generic & irb_starting) != 0); + retrieval->irb_value, retrieval->irb_scale, &retrieval->irb_desc, lower, + keyType, &forceInclude); + if (forceInclude) + forceInclFlag |= irb_force_lower; } } @@ -1090,7 +1105,11 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) window.win_page = root->irt_rpt[idx->idx_id].getRoot(); bucket = (btree_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_index); - key = ret_key; + key.key_length = ret_key.key_length; + memcpy(key.key_data, ret_key.key_data, ret_key.key_length); + key.key_flags = ret_key.key_flags; + key.key_nulls = ret_key.key_nulls; + key.key_next.reset(ret_key.key_next.release()); } // the original page was marked as not garbage-collectable, but @@ -1177,7 +1196,7 @@ void BTR_insert(thread_db* tdbb, WIN* root_window, index_insertion* insertion) idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* idx, - temporary_key* key, const bool fuzzy, USHORT count) + temporary_key* key, const USHORT keyType, USHORT count) { /************************************** * @@ -1214,11 +1233,6 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id const USHORT maxKeyLength = dbb->getMaxIndexKeyLength(); try { - - const USHORT keyType = fuzzy ? - INTL_KEY_PARTIAL : - ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT); - // Special case single segment indices if (idx->idx_count == 1) @@ -1241,7 +1255,8 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id // isNull = !EVL_field(relation, record, tail->idx_field, desc_ptr); - if (!isNull && desc_ptr->dsc_dtype == dtype_text) + if (!isNull && desc_ptr->dsc_dtype == dtype_text && + tail->idx_field < record->getFormat()->fmt_desc.getCount()) { // That's necessary for NO-PAD collations. INTL_adjust_text_descriptor(tdbb, desc_ptr); @@ -1253,7 +1268,7 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id key->key_flags |= key_empty; - compress(tdbb, desc_ptr, key, tail->idx_itype, isNull, descending, keyType); + compress(tdbb, desc_ptr, 0, key, tail->idx_itype, isNull, descending, keyType, nullptr); } else { @@ -1280,14 +1295,15 @@ idx_e BTR_key(thread_db* tdbb, jrd_rel* relation, Record* record, index_desc* id key->key_nulls |= 1 << n; else { - if (desc_ptr->dsc_dtype == dtype_text) + if (desc_ptr->dsc_dtype == dtype_text && + tail->idx_field < record->getFormat()->fmt_desc.getCount()) { // That's necessary for NO-PAD collations. INTL_adjust_text_descriptor(tdbb, desc_ptr); } } - compress(tdbb, desc_ptr, &temp, tail->idx_itype, isNull, descending, keyType); + compress(tdbb, desc_ptr, 0, &temp, tail->idx_itype, isNull, descending, keyType, nullptr); const UCHAR* q = temp.key_data; for (USHORT l = temp.key_length; l; --l, --stuff_count) @@ -1517,9 +1533,11 @@ bool BTR_lookup(thread_db* tdbb, jrd_rel* relation, USHORT id, index_desc* buffe idx_e BTR_make_key(thread_db* tdbb, USHORT count, const ValueExprNode* const* exprs, + const SSHORT* scale, const index_desc* idx, temporary_key* key, - bool fuzzy) + USHORT keyType, + bool* forceInclude) { /************************************** * @@ -1548,13 +1566,11 @@ idx_e BTR_make_key(thread_db* tdbb, key->key_flags = 0; key->key_nulls = 0; + const bool fuzzy = (keyType == INTL_KEY_PARTIAL || keyType == INTL_KEY_MULTI_STARTING); const bool descending = (idx->idx_flags & idx_descending); const index_desc::idx_repeat* tail = idx->idx_rpt; - const USHORT keyType = fuzzy ? - INTL_KEY_PARTIAL : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT); - const USHORT maxKeyLength = dbb->getMaxIndexKeyLength(); // If the index is a single segment index, don't sweat the compound stuff @@ -1567,10 +1583,13 @@ idx_e BTR_make_key(thread_db* tdbb, if (isNull) key->key_nulls = 1; - compress(tdbb, desc, key, tail->idx_itype, isNull, descending, keyType); + compress(tdbb, desc, scale ? *scale : 0, key, tail->idx_itype, isNull, descending, keyType, forceInclude); if (fuzzy && (key->key_flags & key_empty)) + { key->key_length = 0; + key->key_next.reset(); + } } else { @@ -1598,46 +1617,74 @@ idx_e BTR_make_key(thread_db* tdbb, temp.key_flags |= key_empty; - compress(tdbb, desc, &temp, tail->idx_itype, isNull, descending, + compress(tdbb, desc, scale ? *scale++ : 0, &temp, tail->idx_itype, isNull, descending, (n == count - 1 ? - keyType : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT))); + keyType : ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)), + forceInclude); if (!(temp.key_flags & key_empty)) is_key_empty = false; prior_length = (p - key->key_data); - const UCHAR* q = temp.key_data; - for (USHORT l = temp.key_length; l; --l, --stuff_count) + fb_assert(n == count - 1 || !temp.key_next); + + SSHORT save_stuff_count = stuff_count; + temporary_key* current_key = key; + temporary_key* temp_ptr = &temp; + + do { - if (stuff_count == 0) + const UCHAR* q = temp_ptr->key_data; + + for (USHORT l = temp_ptr->key_length; l; --l, --stuff_count) { - *p++ = idx->idx_count - n; - stuff_count = STUFF_COUNT; + if (stuff_count == 0) + { + *p++ = idx->idx_count - n; + stuff_count = STUFF_COUNT; - if (p - key->key_data >= maxKeyLength) + if (p - current_key->key_data >= maxKeyLength) + return idx_e_keytoobig; + } + + *p++ = *q++; + + if (p - current_key->key_data >= maxKeyLength) return idx_e_keytoobig; } - *p++ = *q++; + // AB: Fix bug SF #1242982 + // Equality search on first segment (integer) in compound indexes resulted + // in more scans on specific values (2^n, f.e. 131072) than needed. + if (!fuzzy && count != idx->idx_count && n == count - 1) + { + for (; stuff_count; --stuff_count) + { + *p++ = 0; - if (p - key->key_data >= maxKeyLength) - return idx_e_keytoobig; - } - } + if (p - current_key->key_data >= maxKeyLength) + return idx_e_keytoobig; + } + } - // AB: Fix bug SF #1242982 - // Equality search on first segment (integer) in compound indexes resulted - // in more scans on specific values (2^n, f.e. 131072) than needed. - if (!fuzzy && (n != idx->idx_count)) - { - for (; stuff_count; --stuff_count) - { - *p++ = 0; + current_key->key_length = p - current_key->key_data; - if (p - key->key_data >= maxKeyLength) - return idx_e_keytoobig; - } + if ((temp_ptr = temp_ptr->key_next.get())) + { + temporary_key* next_key = FB_NEW_POOL(*tdbb->getDefaultPool()) temporary_key(); + next_key->key_length = 0; + next_key->key_flags = key->key_flags; + next_key->key_nulls = key->key_nulls; + memcpy(next_key->key_data, key->key_data, prior_length); + + current_key->key_next = next_key; + current_key = next_key; + p = current_key->key_data + prior_length; + + stuff_count = save_stuff_count; + } + } while (temp_ptr); } // dimitr: If the search is fuzzy and the last segment is empty, @@ -1645,8 +1692,6 @@ idx_e BTR_make_key(thread_db* tdbb, // the rule that every string starts with an empty string. if (fuzzy && (temp.key_flags & key_empty)) key->key_length = prior_length; - else - key->key_length = (p - key->key_data); if (is_key_empty) { @@ -1707,7 +1752,7 @@ void BTR_make_null_key(thread_db* tdbb, const index_desc* idx, temporary_key* ke // If the index is a single segment index, don't sweat the compound stuff if ((idx->idx_count == 1) || (idx->idx_flags & idx_expressn)) { - compress(tdbb, &null_desc, key, tail->idx_itype, true, descending, false); + compress(tdbb, &null_desc, 0, key, tail->idx_itype, true, descending, INTL_KEY_SORT, nullptr); } else { @@ -1721,7 +1766,7 @@ void BTR_make_null_key(thread_db* tdbb, const index_desc* idx, temporary_key* ke for (; stuff_count; --stuff_count) *p++ = 0; - compress(tdbb, &null_desc, &temp, tail->idx_itype, true, descending, false); + compress(tdbb, &null_desc, 0, &temp, tail->idx_itype, true, descending, INTL_KEY_SORT, nullptr); const UCHAR* q = temp.key_data; for (USHORT l = temp.key_length; l; --l, --stuff_count) @@ -2252,26 +2297,32 @@ bool BTR_types_comparable(const dsc& target, const dsc& source) if (source.isNull() || DSC_EQUIV(&source, &target, true)) return true; - if (DTYPE_IS_TEXT(target.dsc_dtype)) + if (target.isText()) { // should we also check for the INTL stuff here? - return (DTYPE_IS_TEXT(source.dsc_dtype) || source.dsc_dtype == dtype_dbkey); + return source.isText() || source.isDbKey(); } - if (target.dsc_dtype == dtype_int64) - return (source.dsc_dtype <= dtype_long || source.dsc_dtype == dtype_int64); + if (target.isNumeric()) + return source.isText() || source.isNumeric(); - if (DTYPE_IS_NUMERIC(target.dsc_dtype)) - return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64); + if (target.isDate()) + { + // source.isDate() is already covered above in DSC_EQUIV + return source.isText() || source.isTimeStamp(); + } - if (target.dsc_dtype == dtype_sql_date) - return (source.dsc_dtype <= dtype_sql_date || source.dsc_dtype == dtype_timestamp); + if (target.isTime()) + { + // source.isTime() below covers both TZ and non-TZ time + return source.isText() || source.isTime() || source.isTimeStamp(); + } - if (DTYPE_IS_DATE(target.dsc_dtype)) - return (source.dsc_dtype <= dtype_timestamp); + if (target.isTimeStamp()) + return source.isText() || source.isDateTime(); - if (target.dsc_dtype == dtype_boolean) - return DTYPE_IS_TEXT(source.dsc_dtype) || source.dsc_dtype == dtype_boolean; + if (target.isBoolean()) + return source.isText() || source.isBoolean(); return false; } @@ -2411,9 +2462,11 @@ static ULONG add_node(thread_db* tdbb, static void compress(thread_db* tdbb, const dsc* desc, + const SSHORT matchScale, temporary_key* key, USHORT itype, - bool isNull, bool descending, USHORT key_type) + bool isNull, bool descending, USHORT key_type, + bool* forceInclude) { /************************************** * @@ -2425,29 +2478,6 @@ static void compress(thread_db* tdbb, * Compress a data value into an index key. * **************************************/ - union { - INT64_KEY temp_int64_key; - double temp_double; - ULONG temp_ulong; - SLONG temp_slong; - SINT64 temp_sint64; - UCHAR temp_char[sizeof(INT64_KEY)]; - } temp; - bool temp_is_negative = false; - bool int64_key_op = false; - - // For descending index and new index structure we insert 0xFE at the beginning. - // This is only done for values which begin with 0xFE (254) or 0xFF (255) and - // is needed to make a difference between a NULL state and a VALUE. - // Note! By descending index key is complemented after this compression routine. - // Further a NULL state is always returned as 1 byte 0xFF (descending index). - const UCHAR desc_end_value_prefix = 0x01; // ~0xFE - const UCHAR desc_end_value_check = 0x00; // ~0xFF; - - const Database* dbb = tdbb->getDatabase(); - - UCHAR* p = key->key_data; - if (isNull) { const UCHAR pad = 0; @@ -2457,84 +2487,171 @@ static void compress(thread_db* tdbb, if (descending) { // DESC NULLs are stored as 1 byte - *p++ = pad; - key->key_length = (p - key->key_data); + key->key_data[0] = pad; + key->key_length = 1; } else key->key_length = 0; // ASC NULLs are stored with no data + fb_assert(!key->key_next); return; } + // For descending index and new index structure we insert 0xFE at the beginning. + // This is only done for values which begin with 0xFE (254) or 0xFF (255) and + // is needed to make a difference between a NULL state and a VALUE. + // Note! By descending index key is complemented after this compression routine. + // Further a NULL state is always returned as 1 byte 0xFF (descending index). + const UCHAR desc_end_value_prefix = 0x01; // ~0xFE + const UCHAR desc_end_value_check = 0x00; // ~0xFF; + + const Database* dbb = tdbb->getDatabase(); + bool first_key = true; + VaryStr buffer; + size_t multiKeyLength; + UCHAR* ptr; + UCHAR* p = key->key_data; + SSHORT scale = matchScale ? matchScale : desc->dsc_scale; + if (itype == idx_string || itype == idx_byte_array || itype == idx_metadata || itype == idx_decimal || itype >= idx_first_intl_string) { - VaryStr buffer; - const UCHAR pad = (itype == idx_string) ? ' ' : 0; - UCHAR* ptr; - - size_t length; + temporary_key* root_key = key; + bool has_next; - if (itype == idx_decimal) + do { - Decimal128 dec = MOV_get_dec128(tdbb, desc); - length = dec.makeIndexKey(&buffer); - ptr = reinterpret_cast(buffer.vary_string); - } - else if (itype >= idx_first_intl_string || itype == idx_metadata) - { - DSC to; - - // convert to an international byte array - to.dsc_dtype = dtype_text; - to.dsc_flags = 0; - to.dsc_sub_type = 0; - to.dsc_scale = 0; - to.dsc_ttype() = ttype_sort_key; - to.dsc_length = MIN(MAX_KEY, sizeof(buffer)); - ptr = to.dsc_address = reinterpret_cast(buffer.vary_string); - length = INTL_string_to_key(tdbb, itype, desc, &to, key_type); - } - else - length = MOV_get_string(tdbb, desc, &ptr, &buffer, MAX_KEY); + size_t length; - if (length) - { - // clear key_empty flag, because length is >= 1 - key->key_flags &= ~key_empty; + has_next = false; + + if (first_key) + { + first_key = false; - if (length > sizeof(key->key_data)) - length = sizeof(key->key_data); + if (itype == idx_decimal) + { + Decimal128 dec = MOV_get_dec128(tdbb, desc); + length = dec.makeIndexKey(&buffer); + ptr = reinterpret_cast(buffer.vary_string); + } + else if (itype >= idx_first_intl_string || itype == idx_metadata) + { + DSC to; + + // convert to an international byte array + to.dsc_dtype = dtype_text; + to.dsc_flags = 0; + to.dsc_sub_type = 0; + to.dsc_scale = 0; + to.dsc_ttype() = ttype_sort_key; + to.dsc_length = MIN(MAX_COLUMN_SIZE, MAX_KEY * 4); + ptr = to.dsc_address = reinterpret_cast(buffer.vary_string); + multiKeyLength = length = INTL_string_to_key(tdbb, itype, desc, &to, key_type); + } + else + length = MOV_get_string(tdbb, desc, &ptr, &buffer, MAX_KEY); + } - if (descending && ((*ptr == desc_end_value_prefix) || (*ptr == desc_end_value_check))) + if (key_type == INTL_KEY_MULTI_STARTING && multiKeyLength != 0) { - *p++ = desc_end_value_prefix; - if ((length + 1) > sizeof(key->key_data)) - length = sizeof(key->key_data) - 1; + fb_assert(ptr < (UCHAR*) buffer.vary_string + multiKeyLength); + + length = ptr[0] + ptr[1] * 256; + ptr += 2; + + has_next = ptr + length < (UCHAR*) buffer.vary_string + multiKeyLength; + + if (descending) + { + if (has_next) + { + temporary_key* new_key = FB_NEW_POOL(*tdbb->getDefaultPool()) temporary_key(); + new_key->key_length = 0; + new_key->key_flags = 0; + new_key->key_nulls = 0; + new_key->key_next = key == root_key ? NULL : key; + + key = new_key; + } + else if (key != root_key) + { + root_key->key_next = key; + key = root_key; + } + + p = key->key_data; + } } - memcpy(p, ptr, length); - p += length; - } - else - { - // Leave key_empty flag, because the string is an empty string - if (descending && ((pad == desc_end_value_prefix) || (pad == desc_end_value_check))) - *p++ = desc_end_value_prefix; + const UCHAR pad = (itype == idx_string) ? ' ' : 0; - *p++ = pad; - } + if (length) + { + // clear key_empty flag, because length is >= 1 + key->key_flags &= ~key_empty; - while (p > key->key_data) - { - if (*--p != pad) - break; - } + if (length > sizeof(key->key_data)) + length = sizeof(key->key_data); + + if (descending && ((*ptr == desc_end_value_prefix) || (*ptr == desc_end_value_check))) + { + *p++ = desc_end_value_prefix; + if ((length + 1) > sizeof(key->key_data)) + length = sizeof(key->key_data) - 1; + } + + memcpy(p, ptr, length); + p += length; + } + else + { + // Leave key_empty flag, because the string is an empty string + if (descending && ((pad == desc_end_value_prefix) || (pad == desc_end_value_check))) + *p++ = desc_end_value_prefix; + + *p++ = pad; + } + + while (p > key->key_data) + { + if (*--p != pad) + break; + } + + key->key_length = p + 1 - key->key_data; + + if (has_next && !descending) + { + temporary_key* new_key = FB_NEW_POOL(*tdbb->getDefaultPool()) temporary_key(); + new_key->key_length = 0; + new_key->key_flags = 0; + new_key->key_nulls = 0; + key->key_next = new_key; + + key = new_key; + p = key->key_data; + } + + ptr += length; + } while (has_next); - key->key_length = p + 1 - key->key_data; return; } + p = key->key_data; + + union { + INT64_KEY temp_int64_key; + double temp_double; + ULONG temp_ulong; + SLONG temp_slong; + SINT64 temp_sint64; + UCHAR temp_char[sizeof(INT64_KEY)]; + } temp; + bool temp_is_negative = false; + bool int64_key_op = false; + // The index is numeric. // For idx_numeric... // Convert the value to a double precision number, @@ -2560,13 +2677,33 @@ static void compress(thread_db* tdbb, else if (itype == idx_numeric2) { int64_key_op = true; - temp.temp_int64_key = make_int64_key(MOV_get_int64(tdbb, desc, desc->dsc_scale), desc->dsc_scale); + SINT64 v = 0; + try + { + v = MOV_get_int64(tdbb, desc, scale); + } + catch (const Exception& ex) + { + ex.stuffException(tdbb->tdbb_status_vector); + const ISC_STATUS* st = tdbb->tdbb_status_vector->getErrors(); + if (!(fb_utils::containsErrorCode(st, isc_arith_except) || + fb_utils::containsErrorCode(st, isc_decfloat_invalid_operation))) + { + throw; + } + + tdbb->tdbb_status_vector->init(); + v = MOV_get_dec128(tdbb, desc).sign() < 0 ? MIN_SINT64 : MAX_SINT64; + if (forceInclude) + *forceInclude = true; + } + temp.temp_int64_key = make_int64_key(v, scale); temp_copy_length = sizeof(temp.temp_int64_key.d_part); temp_is_negative = (temp.temp_int64_key.d_part < 0); #ifdef DEBUG_INDEXKEY print_int64_key(*(const SINT64*) desc->dsc_address, - desc->dsc_scale, temp.temp_int64_key); + scale, temp.temp_int64_key); #endif } @@ -3443,9 +3580,9 @@ static ULONG fast_load(thread_db* tdbb, // Detect the case when set of duplicate keys contains more then one key // from primary record version. It breaks the unique constraint and must - // be rejected. Note, it is not always could be detected while sorting. - // Set to true when primary record version is found in current set of - // duplicate keys. + // be rejected. Note, it is not always could be detected while sorting. + // Set to true when primary record version is found in current set of + // duplicate keys. bool primarySeen = false; while (!error) @@ -4131,7 +4268,7 @@ static index_root_page* fetch_root(thread_db* tdbb, WIN* window, const jrd_rel* static UCHAR* find_node_start_point(btree_page* bucket, temporary_key* key, UCHAR* value, USHORT* return_value, bool descending, - bool retrieval, bool pointer_by_marker, + int retrieval, bool pointer_by_marker, RecordNumber find_record_number) { /************************************** @@ -4207,9 +4344,21 @@ static UCHAR* find_node_start_point(btree_page* bucket, temporary_key* key, { while (true) { - if (q == nodeEnd || (retrieval && p == key_end)) + if (q == nodeEnd) goto done; + if (retrieval && p == key_end) + { + if ((retrieval & irb_partial) && !(retrieval & irb_starting)) + { + // check segment + const bool sameSegment = ((p - STUFF_COUNT > key->key_data) && p[-(STUFF_COUNT + 1)] == *q); + if (sameSegment) + break; + } + goto done; + } + if (p == key_end || *p > *q) break; @@ -4269,7 +4418,7 @@ static UCHAR* find_node_start_point(btree_page* bucket, temporary_key* key, static UCHAR* find_area_start_point(btree_page* bucket, const temporary_key* key, UCHAR* value, USHORT* return_prefix, bool descending, - bool retrieval, RecordNumber find_record_number) + int retrieval, RecordNumber find_record_number) { /************************************** * @@ -4375,7 +4524,17 @@ static UCHAR* find_area_start_point(btree_page* bucket, const temporary_key* key if (retrieval && keyPointer == keyEnd) { - done = true; + if ((retrieval & irb_partial) && !(retrieval & irb_starting)) + { + // check segment + const bool sameSegment = ((keyPointer - STUFF_COUNT > key->key_data) && keyPointer[-(STUFF_COUNT + 1)] == *q); + if (!sameSegment) + done = true; + } + else + { + done = true; + } break; } @@ -4482,7 +4641,7 @@ static UCHAR* find_area_start_point(btree_page* bucket, const temporary_key* key static ULONG find_page(btree_page* bucket, const temporary_key* key, const index_desc* idx, RecordNumber find_record_number, - bool retrieval) + int retrieval) { /************************************** * @@ -6033,7 +6192,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re { bool notNull = false; const dsc* const desc = BTR_eval_expression(tdbb, idx, record, notNull); - value = DescPrinter(tdbb, notNull ? desc : NULL, MAX_KEY_STRING_LEN).get(); + value = DescPrinter(tdbb, notNull ? desc : NULL, MAX_KEY_STRING_LEN, CS_METADATA).get(); key += " = " + value; } else @@ -6052,7 +6211,7 @@ string print_key(thread_db* tdbb, jrd_rel* relation, index_desc* idx, Record* re dsc desc; const bool notNull = EVL_field(relation, record, field_id, &desc); - value = DescPrinter(tdbb, notNull ? &desc : NULL, MAX_KEY_STRING_LEN).get(); + value = DescPrinter(tdbb, notNull ? &desc : NULL, MAX_KEY_STRING_LEN, CS_METADATA).get(); key += " = " + value; if (i < idx->idx_count - 1) @@ -6281,7 +6440,7 @@ static contents remove_leaf_node(thread_db* tdbb, index_insertion* insertion, WI static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordBitmap* bitmap_and, index_desc* idx, const IndexRetrieval* retrieval, USHORT prefix, temporary_key* key, - bool& skipLowerKey, const temporary_key& lowerKey) + bool& skipLowerKey, const temporary_key& lowerKey, USHORT forceInclFlag) { /************************************** * @@ -6304,7 +6463,7 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB // stuff the key to the stuff boundary ULONG count; USHORT flag = retrieval->irb_generic; - bool partialEquality = false; + flag &= ~forceInclFlag; // clear exclude bits if needed if ((flag & irb_partial) && (flag & irb_equality) && !(flag & irb_starting) && !(flag & irb_descending)) @@ -6315,7 +6474,6 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB key->key_data[key->key_length + i] = 0; count += key->key_length; - partialEquality = true; } else count = key->key_length; @@ -6325,13 +6483,13 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB count -= key->key_length; const bool descending = (flag & irb_descending); + const bool equality = (flag & irb_equality); const bool ignoreNulls = (flag & irb_ignore_null_value_key) && (idx->idx_count == 1); bool done = false; bool ignore = false; const bool skipUpperKey = (flag & irb_exclude_upper); const bool partLower = (retrieval->irb_lower_count < idx->idx_count); const bool partUpper = (retrieval->irb_upper_count < idx->idx_count); - USHORT upperPrefix = prefix; // reset irb_equality flag passed for optimization flag &= ~(irb_equality | irb_ignore_null_value_key); @@ -6373,7 +6531,7 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB else if (node.prefix <= prefix) { prefix = node.prefix; - upperPrefix = prefix; + USHORT byteInSegment = prefix % (STUFF_COUNT + 1); p = key->key_data + prefix; const UCHAR* q = node.data; USHORT l = node.length; @@ -6381,49 +6539,52 @@ static bool scan(thread_db* tdbb, UCHAR* pointer, RecordBitmap** bitmap, RecordB { if (skipUpperKey && partUpper) { - if (upperPrefix >= key->key_length) + if (p >= end_key && byteInSegment == 0) { const USHORT segnum = idx->idx_count - (UCHAR)(descending ? ((*q) ^ -1) : *q) + 1; - if (segnum >= retrieval->irb_upper_count) + if (segnum > retrieval->irb_upper_count) + return false; + + if (segnum == retrieval->irb_upper_count && !descending) return false; } - if (*p == *q) - upperPrefix++; + if (++byteInSegment > STUFF_COUNT) + byteInSegment = 0; } if (p >= end_key) { if (flag) { - if (partialEquality) + // Check if current node bytes is from the same segment as + // last byte of the key. If not, we have equality at that + // segment. Else, for ascending index, node is greater than + // the key and scan should be stopped. + // For descending index, the node is less than the key and + // scan shoud be continued. + + if ((flag & irb_partial) && !(flag & irb_starting)) { - // node have no more data, it is equality - if (q >= node.data + node.length) - break; - - // node contains more bytes than a key, check numbers - // of last key segment and current node segment. - - fb_assert(!descending); - fb_assert(p - STUFF_COUNT - 1 >= key->key_data); - - const USHORT keySeg = idx->idx_count - p[-STUFF_COUNT - 1]; - const USHORT nodeSeg = idx->idx_count - *q; - - fb_assert(keySeg <= nodeSeg); + if ((p - STUFF_COUNT > key->key_data) && (p[-(STUFF_COUNT + 1)] == *q)) + { + if (descending) + break; - // If current segment at node is the same as last segment - // of the key then node > key. - if (keySeg == nodeSeg) return false; + } - // If node segment belongs to the key segments then key contains - // null or empty string and node contains some data. - if (nodeSeg < retrieval->irb_upper_count) - return false; + if (equality) + { + const USHORT nodeSeg = idx->idx_count - (UCHAR) (descending ? ((*q) ^ -1) : *q); + + // If node segment belongs to the key segments then key contains + // null or empty string and node contains some data. + if (nodeSeg < retrieval->irb_upper_count) + return false; + } } break; } diff --git a/src/jrd/btr.h b/src/jrd/btr.h index 47cc91c009e..40e93acd4d8 100644 --- a/src/jrd/btr.h +++ b/src/jrd/btr.h @@ -154,6 +154,7 @@ struct temporary_key UCHAR key_flags; USHORT key_nulls; // bitmap of encountered null segments, // USHORT is enough to store MAX_INDEX_SEGMENTS bits + Firebird::AutoPtr key_next; // next key (INTL_KEY_MULTI_STARTING) }; @@ -186,7 +187,7 @@ class IndexRetrieval IndexRetrieval(jrd_rel* relation, const index_desc* idx, USHORT count, temporary_key* key) : irb_relation(relation), irb_index(idx->idx_id), irb_generic(0), irb_lower_count(count), irb_upper_count(count), irb_key(key), - irb_name(NULL), irb_value(NULL) + irb_name(nullptr), irb_value(nullptr), irb_scale(nullptr) { memcpy(&irb_desc, idx, sizeof(irb_desc)); } @@ -196,7 +197,8 @@ class IndexRetrieval : irb_relation(relation), irb_index(idx->idx_id), irb_generic(0), irb_lower_count(0), irb_upper_count(0), irb_key(NULL), irb_name(FB_NEW_POOL(pool) MetaName(name)), - irb_value(FB_NEW_POOL(pool) ValueExprNode*[idx->idx_count * 2]) + irb_value(FB_NEW_POOL(pool) ValueExprNode*[idx->idx_count * 2]), + irb_scale(nullptr) { memcpy(&irb_desc, idx, sizeof(irb_desc)); } @@ -205,6 +207,7 @@ class IndexRetrieval { delete irb_name; delete[] irb_value; + delete[] irb_scale; } index_desc irb_desc; // Index descriptor @@ -214,8 +217,9 @@ class IndexRetrieval USHORT irb_lower_count; // Number of segments for retrieval USHORT irb_upper_count; // Number of segments for retrieval temporary_key* irb_key; // Key for equality retrieval - MetaName* irb_name; // Index name - ValueExprNode** irb_value; + MetaName* irb_name; // Index name + ValueExprNode** irb_value; // Matching value (for equality search) + SSHORT* irb_scale; // Scale for int64 key }; // Flag values for irb_generic @@ -227,6 +231,11 @@ const int irb_ignore_null_value_key = 8; // if lower bound is specified and upp const int irb_descending = 16; // Base index uses descending order const int irb_exclude_lower = 32; // exclude lower bound keys while scanning index const int irb_exclude_upper = 64; // exclude upper bound keys while scanning index +const int irb_multi_starting = 128; // Use INTL_KEY_MULTI_STARTING + +// Force include flags - always include appropriate key while scanning index +const int irb_force_lower = irb_exclude_lower; +const int irb_force_upper = irb_exclude_upper; typedef Firebird::HalfStaticArray SelectivityList; @@ -242,6 +251,12 @@ class BtrPageGCLock : public Lock void disablePageGC(thread_db* tdbb, const PageNumber &page); void enablePageGC(thread_db* tdbb); + // return true if lock is active + bool isActive() const + { + return lck_id != 0; + } + static bool isPageGCAllowed(thread_db* tdbb, const PageNumber& page); #ifdef DEBUG_LCK_LIST @@ -250,7 +265,7 @@ class BtrPageGCLock : public Lock { } - static bool checkPool(const Lock* lock, Firebird::MemoryPool* pool) + static bool checkPool(const Lock* lock, Firebird::MemoryPool* pool) { if (!pool || !lock) return false; @@ -313,7 +328,6 @@ class IndexErrorContext bool isLocationDefined; }; - } //namespace Jrd #endif // JRD_BTR_H diff --git a/src/jrd/btr_proto.h b/src/jrd/btr_proto.h index 71a38586fa5..1f04007f99c 100644 --- a/src/jrd/btr_proto.h +++ b/src/jrd/btr_proto.h @@ -36,17 +36,17 @@ bool BTR_delete_index(Jrd::thread_db*, Jrd::win*, USHORT); bool BTR_description(Jrd::thread_db*, Jrd::jrd_rel*, Ods::index_root_page*, Jrd::index_desc*, USHORT); DSC* BTR_eval_expression(Jrd::thread_db*, Jrd::index_desc*, Jrd::Record*, bool&); void BTR_evaluate(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::RecordBitmap**, Jrd::RecordBitmap*); -UCHAR* BTR_find_leaf(Ods::btree_page*, Jrd::temporary_key*, UCHAR*, USHORT*, bool, bool); +UCHAR* BTR_find_leaf(Ods::btree_page*, Jrd::temporary_key*, UCHAR*, USHORT*, bool, int); Ods::btree_page* BTR_find_page(Jrd::thread_db*, const Jrd::IndexRetrieval*, Jrd::win*, Jrd::index_desc*, - Jrd::temporary_key*, Jrd::temporary_key*); + Jrd::temporary_key*, Jrd::temporary_key*, USHORT&, bool = true); void BTR_insert(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); Jrd::idx_e BTR_key(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::Record*, Jrd::index_desc*, Jrd::temporary_key*, - const bool, USHORT = 0); + const USHORT, USHORT = 0); USHORT BTR_key_length(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::index_desc*); Ods::btree_page* BTR_left_handoff(Jrd::thread_db*, Jrd::win*, Ods::btree_page*, SSHORT); bool BTR_lookup(Jrd::thread_db*, Jrd::jrd_rel*, USHORT, Jrd::index_desc*, Jrd::RelationPages*); -Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const Jrd::index_desc*, - Jrd::temporary_key*, bool); +Jrd::idx_e BTR_make_key(Jrd::thread_db*, USHORT, const Jrd::ValueExprNode* const*, const SSHORT* scale, + const Jrd::index_desc*, Jrd::temporary_key*, USHORT, bool*); void BTR_make_null_key(Jrd::thread_db*, const Jrd::index_desc*, Jrd::temporary_key*); bool BTR_next_index(Jrd::thread_db*, Jrd::jrd_rel*, Jrd::jrd_tra*, Jrd::index_desc*, Jrd::win*); void BTR_remove(Jrd::thread_db*, Jrd::win*, Jrd::index_insertion*); diff --git a/src/jrd/build_no.h b/src/jrd/build_no.h index 1d4d49e60af..b8a86ed3642 100644 --- a/src/jrd/build_no.h +++ b/src/jrd/build_no.h @@ -3,16 +3,16 @@ *** DO NOT EDIT *** TO CHANGE ANY INFORMATION IN HERE PLEASE EDIT src/misc/writeBuildNum.sh - FORMAL BUILD NUMBER:2465 + FORMAL BUILD NUMBER:3205 */ -#define PRODUCT_VER_STRING "4.0.0.2465" -#define FILE_VER_STRING "WI-V4.0.0.2465" -#define LICENSE_VER_STRING "WI-V4.0.0.2465" -#define FILE_VER_NUMBER 4, 0, 0, 2465 +#define PRODUCT_VER_STRING "4.0.6.3205" +#define FILE_VER_STRING "WI-V4.0.6.3205" +#define LICENSE_VER_STRING "WI-V4.0.6.3205" +#define FILE_VER_NUMBER 4, 0, 6, 3205 #define FB_MAJOR_VER "4" #define FB_MINOR_VER "0" -#define FB_REV_NO "0" -#define FB_BUILD_NO "2465" +#define FB_REV_NO "6" +#define FB_BUILD_NO "3205" #define FB_BUILD_TYPE "V" -#define FB_BUILD_SUFFIX "Firebird 4.0 Release Candidate 1" +#define FB_BUILD_SUFFIX "Firebird 4.0" diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index 484d7ebd964..82a7d3bc8d5 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -523,8 +523,6 @@ bool CCH_exclusive_attachment(thread_db* tdbb, USHORT level, SSHORT wait_flag, S { try { - tdbb->checkCancelState(); - bool found = false; for (Jrd::Attachment* other_attachment = attachment->att_next; other_attachment; other_attachment = other_attachment->att_next) @@ -575,6 +573,7 @@ bool CCH_exclusive_attachment(thread_db* tdbb, USHORT level, SSHORT wait_flag, S if (remaining >= CCH_EXCLUSIVE_RETRY_INTERVAL) { SyncUnlockGuard unlock(exLock ? (*exGuard) : dsGuard); + tdbb->reschedule(); Thread::sleep(CCH_EXCLUSIVE_RETRY_INTERVAL * 1000); } @@ -1180,7 +1179,7 @@ void CCH_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_number) PIO_flush(tdbb, shadow->sdw_file); BackupManager* bm = dbb->dbb_backup_manager; - if (!bm->isShutDown()) + if (bm && !bm->isShutDown()) { BackupManager::StateReadGuard stateGuard(tdbb); const int backup_state = bm->getState(); @@ -1528,6 +1527,10 @@ void CCH_init2(thread_db* tdbb) Database* dbb = tdbb->getDatabase(); BufferControl* bcb = dbb->dbb_bcb; + // Avoid running CCH_init2() in 2 parallel threads + Firebird::MutexEnsureUnlock guard(bcb->bcb_threadStartup, FB_FUNCTION); + guard.enter(); + if (!(bcb->bcb_flags & BCB_exclusive) || (bcb->bcb_flags & (BCB_cache_writer | BCB_writer_start))) return; @@ -1548,6 +1551,7 @@ void CCH_init2(thread_db* tdbb) { // writer startup in progress bcb->bcb_flags |= BCB_writer_start; + guard.leave(); try { @@ -2979,6 +2983,7 @@ void BufferControl::cache_writer(BufferControl* bcb) attachment->att_user = &user; BackgroundContextHolder tdbb(dbb, attachment, &status_vector, FB_FUNCTION); + Jrd::Attachment::UseCountHolder use(attachment); try { @@ -3025,7 +3030,10 @@ void BufferControl::cache_writer(BufferControl* bcb) { BufferDesc* const bdb = get_buffer(tdbb, FREE_PAGE, SYNC_NONE, 1); if (bdb) + { write_buffer(tdbb, bdb, bdb->bdb_page, true, &status_vector, true); + attachment->mergeStats(); + } } // If there's more work to do voluntarily ask to be rescheduled. diff --git a/src/jrd/cch.h b/src/jrd/cch.h index f1a48d338d0..d08ed928316 100644 --- a/src/jrd/cch.h +++ b/src/jrd/cch.h @@ -132,7 +132,7 @@ class BufferControl : public pool_alloc SLONG bcb_dirty_count; // count of pages in dirty page btree Precedence* bcb_free; // Free precedence blocks - SSHORT bcb_flags; // see below + Firebird::AtomicCounter bcb_flags; // see below SSHORT bcb_free_minimum; // Threshold to activate cache writer ULONG bcb_count; // Number of buffers allocated ULONG bcb_inuse; // Number of buffers in use @@ -146,6 +146,9 @@ class BufferControl : public pool_alloc Firebird::SyncObject bcb_syncLRU; //Firebird::SyncObject bcb_syncPageWrite; + // If we make bcb_flags atomic this mutex will become unneeded: XCHG of bcb_flags is enough + Firebird::Mutex bcb_threadStartup; + typedef ThreadFinishSync BcbThreadSync; static void cache_writer(BufferControl* bcb); diff --git a/src/jrd/cvt.cpp b/src/jrd/cvt.cpp index 7eb84425471..dd89e24bb46 100644 --- a/src/jrd/cvt.cpp +++ b/src/jrd/cvt.cpp @@ -192,15 +192,12 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v * Functional description * Convert a numeric literal (string) to its binary value. * - * If the literal contains an exponent or is too large to fit - * in an int64, return a double, else if the literal is too - * large to fit in a long, return an int64, else return a long. - * - * The return value from the function is set to dtype_double, - * dtype_int64, or dtype_long depending on the conversion performed. - * The binary value (long, int64, or double) is stored at the - * address given by ptr. + * According to the literal passed (contains an exponent or not, + * what datatype fits) returns long, int64, int128, double or decfloat. * + * The return value from the function is set to dtype_decfloat, dtype_double, + * dtype_int128, dtype_int64 or dtype_long depending on the conversion performed. + * The binary value is stored at the address given by ptr. * **************************************/ dsc desc; @@ -218,6 +215,13 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v bool digit_seen = false, fraction = false, over = false; const UCHAR* p = string; + if (length > 2 && p[0] == '0' && p[1] == 'X') + { + *(Int128*) ptr = CVT_hex_to_int128(reinterpret_cast(p + 2), length - 2); + *scale = 0; + return dtype_int128; + } + const UCHAR* const end = p + length; for (; p < end; p++) { @@ -232,10 +236,10 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v if (!over) { - if (value >= NUMERIC_LIMIT) + if (static_cast(value) >= NUMERIC_LIMIT) { // possibility of an overflow - if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1)) + if ((static_cast(value) > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1)) over = true; } @@ -260,6 +264,8 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v sign = 1; else if (*p == 'e' || *p == 'E') break; + else if (*p == '\0') + break; else if (*p != ' ') CVT_conversion_error(&desc, ERR_post); } @@ -270,9 +276,7 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v if ((local_scale > MAX_SCHAR) || (local_scale < MIN_SCHAR)) over = true; - *scale = local_scale; - - if ((!over) && ((p < end) || // there is an exponent + if ((!over) && (((p < end) && *p) || // there is an exponent ((value < 0) && (sign != -1)))) // MAX_SINT64+1 wrapped around { // convert to double @@ -281,6 +285,8 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v return dtype_double; } + *scale = local_scale; + if (over) { thread_db* tdbb = JRD_get_thread_data(); @@ -576,10 +582,7 @@ SLONG EngineCallbacks::getLocalDate() thread_db* tdbb = JRD_get_thread_data(); if (tdbb && (tdbb->getType() == ThreadData::tddDBB) && tdbb->getRequest()) - { - fb_assert(!tdbb->getRequest()->req_gmt_timestamp.isEmpty()); - return tdbb->getRequest()->getLocalTimeStamp().value().timestamp_date; - } + return tdbb->getRequest()->getLocalTimeStamp().timestamp_date; return TimeZoneUtil::timeStampTzToTimeStamp( TimeZoneUtil::getCurrentSystemTimeStamp(), getSessionTimeZone()).timestamp_date; @@ -591,10 +594,7 @@ ISC_TIMESTAMP EngineCallbacks::getCurrentGmtTimeStamp() thread_db* tdbb = JRD_get_thread_data(); if (tdbb && (tdbb->getType() == ThreadData::tddDBB) && tdbb->getRequest()) - { - fb_assert(!tdbb->getRequest()->req_gmt_timestamp.isEmpty()); - return tdbb->getRequest()->req_gmt_timestamp.value(); - } + return tdbb->getRequest()->getGmtTimeStamp(); return TimeZoneUtil::timeStampTzToTimeStamp(TimeZoneUtil::getCurrentSystemTimeStamp(), TimeZoneUtil::GMT_ZONE); } diff --git a/src/jrd/cvt2.cpp b/src/jrd/cvt2.cpp index 835a5c65734..515adf4df7e 100644 --- a/src/jrd/cvt2.cpp +++ b/src/jrd/cvt2.cpp @@ -101,9 +101,9 @@ const BYTE CVT2_compare_priority[] = 10, // dtype_int64 - goes right after long 25, // dtype_dbkey - compares with nothing except itself 26, // dtype_boolean - compares with nothing except itself - 12, // dtype_int128 - go after quad - 16, // dec64 - go after dtype_d_float + 16, // dec64 - go after dtype_d_float 17, // dec128 - go after dec64 and before dtype_sql_date + 12, // dtype_int128 - go after quad 20, // dtype_sql_time_tz - go after dtype_sql_time 22, // dtype_timestamp_tz - go after dtype_timestamp 99, // dtype_ex_time_tz - should not be used here @@ -203,6 +203,39 @@ bool CVT2_get_binary_comparable_desc(dsc* result, const dsc* arg1, const dsc* ar } +static int cmp_numeric_string(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt) +{ +/************************************** + * + * c m p _ n u m e r i c _ s t r i n g + * + ************************************** + * + * Functional description + * Compare any numeric value with string. Return (-1, 0, 1) if ab. + * + **************************************/ + fb_assert(arg1->isNumeric()); + fb_assert(arg2->isText()); + + Decimal128 buffer; // enough to fit any required data + SSHORT scale = 0; + UCHAR* text = arg2->dsc_address; + if (arg2->dsc_dtype == dtype_varying) + text += sizeof(USHORT); + + dsc num2; + num2.dsc_dtype = CVT_get_numeric(text, TEXT_LEN(arg2), &scale, &buffer); + num2.dsc_address = (UCHAR*)&buffer; + num2.dsc_scale = scale; + num2.dsc_length = type_lengths[num2.dsc_dtype]; + num2.dsc_sub_type = 0; + num2.dsc_flags = 0; + + return CVT2_compare(arg1, &num2, decSt); +} + + int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt) { /************************************** @@ -520,13 +553,13 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_short: { - SSHORT scale; - if (arg2->dsc_dtype > dtype_varying) - scale = MIN(arg1->dsc_scale, arg2->dsc_scale); - else - scale = arg1->dsc_scale; + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + + SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale); const SLONG temp1 = CVT_get_long(arg1, scale, decSt, ERR_post); const SLONG temp2 = CVT_get_long(arg2, scale, decSt, ERR_post); + if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -538,13 +571,13 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt // Since longs may overflow when scaled, use int64 instead case dtype_int64: { - SSHORT scale; - if (arg2->dsc_dtype > dtype_varying) - scale = MIN(arg1->dsc_scale, arg2->dsc_scale); - else - scale = arg1->dsc_scale; + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + + SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale); const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post); const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post); + if (temp1 == temp2) return 0; if (temp1 > temp2) @@ -554,11 +587,10 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_quad: { - SSHORT scale; - if (arg2->dsc_dtype > dtype_varying) - scale = MIN(arg1->dsc_scale, arg2->dsc_scale); - else - scale = arg1->dsc_scale; + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + + SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale); const SQUAD temp1 = CVT_get_quad(arg1, scale, decSt, ERR_post); const SQUAD temp2 = CVT_get_quad(arg2, scale, decSt, ERR_post); return QUAD_COMPARE(&temp1, &temp2); @@ -566,6 +598,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_real: { + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + const float temp1 = (float) CVT_get_double(arg1, decSt, ERR_post); const float temp2 = (float) CVT_get_double(arg2, decSt, ERR_post); if (temp1 == temp2) @@ -577,6 +612,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_double: { + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + const double temp1 = CVT_get_double(arg1, decSt, ERR_post); const double temp2 = CVT_get_double(arg2, decSt, ERR_post); if (temp1 == temp2) @@ -588,6 +626,9 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_dec64: { + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + const Decimal64 temp1 = CVT_get_dec64(arg1, decSt, ERR_post); const Decimal64 temp2 = CVT_get_dec64(arg2, decSt, ERR_post); return temp1.compare(decSt, temp2); @@ -602,12 +643,10 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt case dtype_int128: { - SSHORT scale; - if (arg2->dsc_dtype > dtype_varying) - scale = MIN(arg1->dsc_scale, arg2->dsc_scale); - else - scale = arg1->dsc_scale; + if (arg2->isText()) + return cmp_numeric_string(arg1, arg2, decSt); + SSHORT scale = MIN(arg1->dsc_scale, arg2->dsc_scale); const Int128 temp1 = CVT_get_int128(arg1, scale, decSt, ERR_post); const Int128 temp2 = CVT_get_int128(arg2, scale, decSt, ERR_post); return temp1.compare(temp2); diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index d9dd3c205b1..e94c6be550e 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -486,6 +486,7 @@ static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool clear_cache(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool change_repl_state(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static string remove_icu_info_from_attributes(const string&, const string&); // ---------------------------------------------------------------- @@ -510,7 +511,7 @@ static bool validate_text_type (thread_db*, const TemporaryField*); static void check_partners(thread_db*, const USHORT); static string get_string(const dsc* desc); -static void setupSpecificCollationAttributes(thread_db*, jrd_tra*, const USHORT, const char*); +static void setupSpecificCollationAttributes(thread_db*, jrd_tra*, const USHORT, const char*, bool); static ISC_STATUS getErrorCodeByObjectType(int obj_type) { @@ -2646,10 +2647,9 @@ static bool grant_privileges(thread_db* tdbb, SSHORT phase, DeferredWork* work, switch (phase) { case 1: - case 2: return true; - case 3: + case 2: GRANT_privileges(tdbb, work->dfw_name, work->dfw_id, transaction); break; @@ -2810,6 +2810,10 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { tdbb->setTransaction(current_transaction); tdbb->setRequest(current_request); + + // Get rid of the expression statement. + idx.idx_expression_statement->release(tdbb); + throw; } @@ -2818,9 +2822,8 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity, transaction); - // Get rid of the pool containing the expression tree - - attachment->deletePool(new_pool); + // Get rid of the expression statement. + idx.idx_expression_statement->release(tdbb); } break; @@ -3495,18 +3498,18 @@ static bool create_index(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ } END_FOR - if (key_count != idx.idx_count) + if (!relation) { - ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_key_field_err) << Arg::Str(work->dfw_name)); - // Msg352: too few key columns found for index %s (incorrect column name?) + // The record was not found in RDB$INDICES. + // Apparently the index was dropped in the same transaction. + return false; } - if (!relation) + if (key_count != idx.idx_count) { ERR_post(Arg::Gds(isc_no_meta_update) << - Arg::Gds(isc_idx_create_err) << Arg::Str(work->dfw_name)); - // Msg308: can't create index %s + Arg::Gds(isc_key_field_err) << Arg::Str(work->dfw_name)); + // Msg352: too few key columns found for index %s (incorrect column name?) } // Make sure the relation info is all current @@ -3858,8 +3861,30 @@ static bool create_trigger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jr #define DEBUG_REBUILD_INTL(A) +static string remove_icu_info_from_attributes(const string& charsetName, const string& specificAttributes) +{ + Firebird::AutoPtr cs(FB_NEW charset); + memset(cs, 0, sizeof(*cs)); + + if (IntlManager::lookupCharSet(charsetName, cs)) + { + AutoPtr charSet(Jrd::CharSet::createInstance(*getDefaultMemoryPool(), 0, cs)); + IntlUtil::SpecificAttributesMap map; + if (IntlUtil::parseSpecificAttributes(charSet, specificAttributes.length(), + (const UCHAR*) specificAttributes.begin(), &map)) + { + map.remove("ICU-VERSION"); + map.remove("COLL-VERSION"); + return IntlUtil::generateSpecificAttributes(charSet, map); + } + } + + return specificAttributes; +} + + static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transaction, - const USHORT charSetId, const char* collationName) + const USHORT charSetId, const char* collationName, bool dropIcuInfo) { /************************************** * @@ -3893,6 +3918,9 @@ static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transacti } const string specificAttributes((const char*) buffer.begin(), length); + MetaName charsetName(CS.RDB$CHARACTER_SET_NAME); + string icuLessAttributes = dropIcuInfo ? + remove_icu_info_from_attributes(charsetName.c_str(), specificAttributes) : specificAttributes; string newSpecificAttributes; // ASF: If setupCollationAttributes fail we store the original @@ -3902,11 +3930,9 @@ static void setupSpecificCollationAttributes(thread_db* tdbb, jrd_tra* transacti fb_utils::exact_name(COLL.RDB$BASE_COLLATION_NAME.NULL ? COLL.RDB$COLLATION_NAME : COLL.RDB$BASE_COLLATION_NAME), fb_utils::exact_name(CS.RDB$CHARACTER_SET_NAME), - specificAttributes, newSpecificAttributes) && + icuLessAttributes, newSpecificAttributes) && newSpecificAttributes != specificAttributes) // if nothing changed, we do nothing { - DEBUG_REBUILD_INTL(fprintf(stderr, "Recreate collation %s\n", collationName)); - MODIFY COLL USING if (newSpecificAttributes.isEmpty()) COLL.RDB$SPECIFIC_ATTRIBUTES.NULL = TRUE; @@ -3942,7 +3968,14 @@ static bool create_collation(thread_db* tdbb, SSHORT phase, DeferredWork* work, { case 1: setupSpecificCollationAttributes(tdbb, transaction, TTYPE_TO_CHARSET(work->dfw_id), - work->dfw_name.c_str()); + work->dfw_name.c_str(), false); + + if (!(transaction->tra_flags & TRA_system) && // avoid run during database creation + !INTL_defined_type(tdbb, work->dfw_id)) + { + setupSpecificCollationAttributes(tdbb, transaction, TTYPE_TO_CHARSET(work->dfw_id), + work->dfw_name.c_str(), true); + } break; } @@ -3995,6 +4028,7 @@ void DFW_reset_icu(thread_db* tdbb) "join RDB$CHARACTER_SETS cs on coll.RDB$CHARACTER_SET_ID = cs.RDB$CHARACTER_SET_ID " "where coll.RDB$SPECIFIC_ATTRIBUTES like '%COLL-VERSION=%' " " and coalesce(ind.RDB$INDEX_INACTIVE, 0) = 0 " + " and coalesce(rel.RDB$RELATION_TYPE, 0) = 0 " // rel_persistent "group by ind.RDB$INDEX_NAME, rel.RDB$RELATION_ID, coll.RDB$BASE_COLLATION_NAME, " " coll.RDB$COLLATION_NAME, cs.RDB$CHARACTER_SET_NAME, coll.RDB$SPECIFIC_ATTRIBUTES"; @@ -4045,7 +4079,7 @@ void DFW_reset_icu(thread_db* tdbb) MetaName collName(rs->getMetaName(tdbb, 1)); const USHORT charSetId(rs->getSmallInt(tdbb, 2)); - setupSpecificCollationAttributes(tdbb, transaction, charSetId, collName.c_str()); + setupSpecificCollationAttributes(tdbb, transaction, charSetId, collName.c_str(), true); } } @@ -4516,9 +4550,9 @@ static void check_partners(thread_db* tdbb, const USHORT rel_id) jrd_rel *relation = (*relations)[rel_id]; fb_assert(relation); + relation->rel_flags |= REL_check_partners; LCK_lock(tdbb, relation->rel_partners_lock, LCK_EX, LCK_WAIT); LCK_release(tdbb, relation->rel_partners_lock); - relation->rel_flags |= REL_check_partners; } @@ -4884,6 +4918,7 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j case 4: relation = MET_lookup_relation_id(tdbb, work->dfw_id, true); if (!relation) { + fb_assert(false); return false; } @@ -4915,6 +4950,13 @@ static bool delete_relation(thread_db* tdbb, SSHORT phase, DeferredWork* work, j EXT_fini(relation, false); } + if (relation->isTemporary()) + { + // release pages, allocated for current GTT instance + AutoSetRestoreFlag tmpSpace(&tdbb->tdbb_flags, TDBB_use_db_page_space, false); + relation->delPages(tdbb); + } + RelationPages* const relPages = relation->getBasePages(); if (relPages->rel_index_root) { IDX_delete_indices(tdbb, relation, relPages); @@ -5707,6 +5749,7 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ FLD IN RDB$FIELDS WITH RFR.RDB$RELATION_NAME EQ work->dfw_name.c_str() AND RFR.RDB$FIELD_SOURCE EQ FLD.RDB$FIELD_NAME + SORTED BY RFR.RDB$FIELD_POSITION { // Update RFR to reflect new fields id @@ -5907,11 +5950,14 @@ static bool make_version(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_ AutoSetRestore2 autoRequest(tdbb, &thread_db::getRequest, &thread_db::setRequest, defaultRequest); - TimeZoneUtil::validateGmtTimeStamp(defaultRequest->req_gmt_timestamp); + defaultRequest->validateTimeStamp(); - TRA_attach_request(transaction, defaultRequest); - dsc* result = EVL_expr(tdbb, defaultRequest, defaultNode); - TRA_detach_request(defaultRequest); + dsc* result = nullptr; + { // scope + Firebird::Cleanup detach([&defaultRequest] {TRA_detach_request(defaultRequest);}); + TRA_attach_request(transaction, defaultRequest); + result = EVL_expr(tdbb, defaultRequest, defaultNode); + } if (result) { diff --git a/src/jrd/dpm.epp b/src/jrd/dpm.epp index d1ec7204530..7a4ebc3c25c 100644 --- a/src/jrd/dpm.epp +++ b/src/jrd/dpm.epp @@ -246,47 +246,51 @@ double DPM_cardinality(thread_db* tdbb, jrd_rel* relation, const Format* format) ULONG recordCount = 0, recordLength = 0; - const RelationPages* const relPages = relation->getPages(tdbb); - const vcl* const vector = relPages->rel_pages; - if (vector) + RelationPages* const relPages = relation->getPages(tdbb); + if (relPages->rel_pages) { - WIN window(relPages->rel_pg_space_id, (*vector)[0]); - - Ods::pointer_page* ppage = - (Ods::pointer_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_pointer); - if (!ppage) + bool done = false; + for (ULONG sequence = 0; !done; sequence++) { - BUGCHECK(243); - // msg 243 missing pointer page in DPM_data_pages - } + WIN window(relPages->rel_pg_space_id, -1); - const ULONG* page = ppage->ppg_page; - const ULONG* const end_page = page + ppage->ppg_count; - while (page < end_page) - { - if (*page) + const pointer_page* ppage = + get_pointer_page(tdbb, relation, relPages, &window, sequence, LCK_read); + if (!ppage) { - Ods::data_page* dpage = - (Ods::data_page*) CCH_HANDOFF(tdbb, &window, *page, LCK_read, pag_data); + BUGCHECK(243); + // msg 243 missing pointer page in DPM_data_pages + } - const data_page::dpg_repeat* index = dpage->dpg_rpt; - const data_page::dpg_repeat* const end = index + dpage->dpg_count; - for (; index < end; index++) + const UCHAR* bits = (UCHAR*)(ppage->ppg_page + dbb->dbb_dp_per_pp); + for (USHORT slot = 0; slot < ppage->ppg_count; slot++) + { + if (ppage->ppg_page[slot] && + !PPG_DP_BIT_TEST(bits, slot, ppg_dp_secondary) && + !PPG_DP_BIT_TEST(bits, slot, ppg_dp_empty)) { - if (index->dpg_offset) + Ods::data_page* dpage = + (Ods::data_page*) CCH_HANDOFF(tdbb, &window, ppage->ppg_page[slot], LCK_read, pag_data); + + const data_page::dpg_repeat* index = dpage->dpg_rpt; + const data_page::dpg_repeat* const end = index + dpage->dpg_count; + for (; index < end; index++) { - recordCount++; - recordLength += index->dpg_length - RHD_SIZE; + if (index->dpg_offset) + { + recordCount++; + recordLength += index->dpg_length - RHD_SIZE; + } } - } - break; + if (recordCount) + break; + } } - page++; + done = (recordCount != 0) || (ppage->ppg_header.pag_flags & ppg_eof); + CCH_RELEASE(tdbb, &window); } - - CCH_RELEASE(tdbb, &window); } // AB: If we have only 1 data-page then the cardinality calculation @@ -633,6 +637,7 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) * **************************************/ SET_TDBB(tdbb); + const Database* const dbb = tdbb->getDatabase(); #ifdef VIO_DEBUG VIO_trace(DEBUG_TRACE_ALL, @@ -654,12 +659,15 @@ ULONG DPM_data_pages(thread_db* tdbb, jrd_rel* relation) // msg 243 missing pointer page in DPM_data_pages } - const ULONG* page = ppage->ppg_page; - const ULONG* const end_page = page + ppage->ppg_count; - while (page < end_page) + const UCHAR* bits = (UCHAR*)(ppage->ppg_page + dbb->dbb_dp_per_pp); + for (USHORT slot = 0; slot < ppage->ppg_count; slot++) { - if (*page++) + if (ppage->ppg_page[slot] && + !PPG_DP_BIT_TEST(bits, slot, ppg_dp_secondary) && + !PPG_DP_BIT_TEST(bits, slot, ppg_dp_empty)) + { pages++; + } } if (ppage->ppg_header.pag_flags & ppg_eof) @@ -1343,26 +1351,27 @@ SINT64 DPM_gen_id(thread_db* tdbb, SLONG generator, bool initialize, SINT64 val) const USHORT offset = generator % dbb->dbb_page_manager.gensPerPage; WIN window(DB_PAGE_SPACE, -1); - vcl* vector = dbb->dbb_gen_id_pages; - if (!vector || (sequence >= vector->count()) || !((*vector)[sequence])) + ULONG pageNumber = dbb->getKnownPage(pag_ids, sequence); + if (!pageNumber) { DPM_scan_pages(tdbb); - if (!(vector = dbb->dbb_gen_id_pages) || - (sequence >= vector->count()) || !((*vector)[sequence])) + + pageNumber = dbb->getKnownPage(pag_ids, sequence); + if (!pageNumber) { generator_page* page = (generator_page*) DPM_allocate(tdbb, &window); page->gpg_header.pag_type = pag_ids; page->gpg_sequence = sequence; CCH_must_write(tdbb, &window); CCH_RELEASE(tdbb, &window); - DPM_pages(tdbb, 0, pag_ids, (ULONG) sequence, window.win_page.getPageNum()); - vector = dbb->dbb_gen_id_pages = - vcl::newVector(*dbb->dbb_permanent, dbb->dbb_gen_id_pages, sequence + 1); - (*vector)[sequence] = window.win_page.getPageNum(); + + pageNumber = window.win_page.getPageNum(); + dbb->setKnownPage(pag_ids, sequence, pageNumber); + DPM_pages(tdbb, 0, pag_ids, sequence, pageNumber); } } - window.win_page = (*vector)[sequence]; + window.win_page = pageNumber; window.win_flags = 0; // As a special exception that allows physical backups for read-only replicas, @@ -1473,7 +1482,7 @@ bool DPM_get(thread_db* tdbb, record_param* rpb, SSHORT lock_type) const bool pageOk = dpage->dpg_header.pag_type == pag_data && - !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_orphan)) && dpage->dpg_relation == rpb->rpb_relation->rel_id && dpage->dpg_sequence == dpSequence && (dpage->dpg_count > 0); @@ -1732,7 +1741,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage const bool pageOk = dpage->dpg_header.pag_type == pag_data && - !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_orphan)) && dpage->dpg_relation == rpb->rpb_relation->rel_id && dpage->dpg_sequence == dpSequence && (dpage->dpg_count > 0); @@ -1744,7 +1753,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage if (get_header(window, line, rpb) && !(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment))) { - if (sweeper && !rpb->rpb_b_page && rpb->rpb_transaction_nr <= oldest) + if (sweeper && !rpb->rpb_b_page && !(rpb->rpb_flags & rpb_deleted) && rpb->rpb_transaction_nr <= oldest) continue; rpb->rpb_number.compose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, @@ -1816,7 +1825,7 @@ bool DPM_next(thread_db* tdbb, record_param* rpb, USHORT lock_type, bool onepage if (get_header(window, line, rpb) && !(rpb->rpb_flags & (rpb_blob | rpb_chained | rpb_fragment))) { - if (sweeper && !rpb->rpb_b_page && rpb->rpb_transaction_nr <= oldest) + if (sweeper && !rpb->rpb_b_page && !(rpb->rpb_flags & rpb_deleted) && rpb->rpb_transaction_nr <= oldest) continue; rpb->rpb_number.compose(dbb->dbb_max_records, dbb->dbb_dp_per_pp, @@ -2034,6 +2043,9 @@ void DPM_scan_pages( thread_db* tdbb) CCH_RELEASE(tdbb, &window); + HalfStaticArray tipSeqList; + HalfStaticArray genSeqList; + AutoCacheRequest request(tdbb, irq_r_pages, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) X IN RDB$PAGES @@ -2041,33 +2053,41 @@ void DPM_scan_pages( thread_db* tdbb) relation = MET_relation(tdbb, X.RDB$RELATION_ID); relPages = relation->getBasePages(); sequence = X.RDB$PAGE_SEQUENCE; - MemoryPool* pool = dbb->dbb_permanent; + switch (X.RDB$PAGE_TYPE) { case pag_root: relPages->rel_index_root = X.RDB$PAGE_NUMBER; - continue; + break; case pag_pointer: - address = &relPages->rel_pages; - pool = relation->rel_pool; + relPages->rel_pages = vcl::newVector(*relation->rel_pool, relPages->rel_pages, sequence + 1); + (*relPages->rel_pages)[sequence] = X.RDB$PAGE_NUMBER; break; case pag_transactions: - address = &dbb->dbb_t_pages; + if (sequence >= tipSeqList.getCount()) + tipSeqList.resize(sequence + 1); + tipSeqList[sequence] = X.RDB$PAGE_NUMBER; break; case pag_ids: - address = &dbb->dbb_gen_id_pages; + if (sequence >= genSeqList.getCount()) + genSeqList.resize(sequence + 1); + genSeqList[sequence] = X.RDB$PAGE_NUMBER; break; default: CORRUPT(257); // msg 257 bad record in RDB$PAGES } - vector = *address = vcl::newVector(*pool, *address, sequence + 1); - (*vector)[sequence] = X.RDB$PAGE_NUMBER; } END_FOR + + if (const auto count = tipSeqList.getCount()) + dbb->copyKnownPages(pag_transactions, count, tipSeqList.begin()); + + if (const auto count = genSeqList.getCount()) + dbb->copyKnownPages(pag_ids, count, genSeqList.begin()); } @@ -2299,6 +2319,8 @@ void DPM_update( thread_db* tdbb, record_param* rpb, PageStack* stack, const jrd Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); + rpb->rpb_flags &= ~(rpb_fragment | rpb_incomplete | rpb_large | rpb_chained | rpb_gc_active | rpb_long_tranum); + #ifdef VIO_DEBUG jrd_rel* relation = rpb->rpb_relation; VIO_trace(DEBUG_WRITES, @@ -2457,7 +2479,7 @@ static void check_swept(thread_db* tdbb, record_param* rpb) { rhd* header = (rhd*) ((SCHAR*) dpage + index->dpg_offset); if (Ods::getTraNum(header) > transaction->tra_oldest || - (header->rhd_flags & (rpb_blob | rpb_chained | rpb_fragment)) || + (header->rhd_flags & (rpb_blob | rpb_chained | rpb_fragment | rpb_deleted)) || header->rhd_b_page) { CCH_RELEASE_TAIL(tdbb, window); @@ -2561,20 +2583,31 @@ static void delete_tail(thread_db* tdbb, rhdf* header, const USHORT page_space, if (!(header->rhdf_flags & rhd_blob)) { + USHORT flags = header->rhdf_flags; ULONG page_number = header->rhdf_f_page; - while (true) + fb_assert(flags & rhd_incomplete); + + while (flags & rhd_incomplete) { window.win_page = page_number; data_page* dpage = (data_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_data); - header = (rhdf*) ((UCHAR *) dpage + dpage->dpg_rpt[0].dpg_offset); - const USHORT flags = header->rhdf_flags; - page_number = header->rhdf_f_page; - CCH_RELEASE_TAIL(tdbb, &window); - PAG_release_page(tdbb, window.win_page, ZERO_PAGE_NUMBER); + if (dpage->dpg_header.pag_flags & dpg_orphan && + dpage->dpg_header.pag_flags & dpg_full && + dpage->dpg_count == 1) + { + header = (rhdf*) ((UCHAR *) dpage + dpage->dpg_rpt[0].dpg_offset); + flags = header->rhdf_flags; + page_number = header->rhdf_f_page; - if (!(flags & rhd_incomplete)) + CCH_RELEASE_TAIL(tdbb, &window); + PAG_release_page(tdbb, window.win_page, ZERO_PAGE_NUMBER); + } + else + { + fb_assert(false); break; + } } return; } @@ -3041,6 +3074,16 @@ static UCHAR* find_space(thread_db* tdbb, const SSHORT aligned_size = ROUNDUP(size, ODS_ALIGNMENT); data_page* page = (data_page*) rpb->getWindow(tdbb).win_buffer; + if ((page->dpg_count > 0) && (type == DPM_primary) && (page->dpg_header.pag_flags & dpg_secondary)) + { + // Attempt to put primary record on secondary data page - seems + // flags on PP is not correct. Fix flags and let caller to find + // space for record at another data page. + + mark_full(tdbb, rpb); + return NULL; + } + // Scan allocated lines looking for an empty slot, the high water mark, // and the amount of space potentially available on the page @@ -3311,7 +3354,7 @@ static rhd* locate_space(thread_db* tdbb, const bool pageOk = dpage->dpg_header.pag_type == pag_data && - !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_large | dpg_orphan)) && + !(dpage->dpg_header.pag_flags & (dpg_secondary | dpg_orphan)) && dpage->dpg_relation == rpb->rpb_relation->rel_id && //dpage->dpg_sequence == dpSequence && (dpage->dpg_count > 0); @@ -3668,11 +3711,15 @@ static void store_big_record(thread_db* tdbb, RelationPages* relPages = rpb->rpb_relation->getPages(tdbb); PageNumber prior(relPages->rel_pg_space_id, 0); signed char count = 0; - const USHORT max_data = dbb->dbb_page_size - (static_cast(sizeof(data_page)) + RHDF_SIZE); + + // The last fragment should have rhd header because rhd_incomplete flag won't be set for it. + // It's important for get_header() function which relies on rhd_incomplete flag to determine header size. + FB_SIZE_T header_size = RHD_SIZE; + USHORT max_data = dbb->dbb_page_size - (static_cast(sizeof(data_page)) + header_size); // Fill up data pages tail first until what's left fits on a single page. - while (size > max_data) + do { // Allocate and format data page and fragment header @@ -3681,14 +3728,23 @@ static void store_big_record(thread_db* tdbb, page->dpg_header.pag_flags = dpg_orphan | dpg_full; page->dpg_relation = rpb->rpb_relation->rel_id; page->dpg_count = 1; + + // Cast to (rhdf*) but use only rhd fields for the last fragment rhdf* header = (rhdf*) & page->dpg_rpt[1]; page->dpg_rpt[0].dpg_offset = (UCHAR *) header - (UCHAR *) page; - page->dpg_rpt[0].dpg_length = max_data + RHDF_SIZE; - header->rhdf_flags = (prior.getPageNum()) ? rhd_fragment | rhd_incomplete : rhd_fragment; - header->rhdf_f_page = prior.getPageNum(); + page->dpg_rpt[0].dpg_length = max_data + header_size; + header->rhdf_flags = rhd_fragment; + + if (prior.getPageNum()) + { + // This is not the last fragment + header->rhdf_flags |= rhd_incomplete; + header->rhdf_f_page = prior.getPageNum(); + } + USHORT length = max_data; size -= length; - UCHAR* out = header->rhdf_data + length; + UCHAR* out = (UCHAR *) header + page->dpg_rpt[0].dpg_length; // Move compressed data onto page @@ -3743,10 +3799,16 @@ static void store_big_record(thread_db* tdbb, CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); prior = rpb->getWindow(tdbb).win_page; - } + + // Other fragments except the last one should have rhdf header + header_size = RHDF_SIZE; + max_data = dbb->dbb_page_size - (static_cast(sizeof(data_page)) + header_size); + } while (size > max_data); // What's left fits on a page. Luckily, we don't have to store it ourselves. + stack.push(prior); + // rpb is already converted to UTC const Compressor dcc(*tdbb->getDefaultPool(), in - rpb->rpb_address, rpb->rpb_address); size = (ULONG) dcc.getPackedLength(); diff --git a/src/jrd/drq.h b/src/jrd/drq.h index e7dbcc785aa..2d3e662514a 100644 --- a/src/jrd/drq.h +++ b/src/jrd/drq.h @@ -79,6 +79,7 @@ enum drq_type_t drq_e_filters, // erase filters drq_e_func_args, // erase functions drq_e_funcs, // erase function arguments + drq_e_arg_prvs, // erase argument source's privileges drq_l_fld_src, // lookup a field source drq_e_gfields, // erase global fields drq_e_indices, // erase indices @@ -213,6 +214,7 @@ enum drq_type_t drq_e_fun_prv, // erase function privileges drq_s_fld_src, // store field source drq_e_prm_gfld, // erase parameter source + drq_e_prm_prvs, // erase parameter source's privileges drq_g_nxt_sec_id, // lookup next security class ID drq_f_nxt_gen, // find next generator name drq_g_nxt_gen, // generate next generator name diff --git a/src/jrd/err.cpp b/src/jrd/err.cpp index ffb4e874a96..641e9f894f3 100644 --- a/src/jrd/err.cpp +++ b/src/jrd/err.cpp @@ -214,7 +214,7 @@ void ERR_post_warning(const Arg::StatusVector& v) return; } - const ISC_STATUS* oldVector = statusVector->getErrors(); + const ISC_STATUS* oldVector = statusVector->getWarnings(); unsigned lenOld = fb_utils::statusLength(oldVector); // check for duplicated error code @@ -371,7 +371,8 @@ void ERR_warning(const Arg::StatusVector& v) FbStatusVector* s = tdbb->tdbb_status_vector; v.copyTo(s); - tdbb->getRequest()->req_flags |= req_warning; + if (jrd_req* request = tdbb->getRequest()) + request->req_flags |= req_warning; } diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 41bc9d09892..2a70ddab225 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -581,35 +581,13 @@ void EXE_execute_ddl_triggers(thread_db* tdbb, jrd_tra* transaction, bool preTri if (attachment->att_ddl_triggers) { - jrd_tra* const oldTransaction = tdbb->getTransaction(); - tdbb->setTransaction(transaction); - - try - { - TrigVector triggers; - TrigVector* triggersPtr = &triggers; + AutoSetRestore2 tempTrans(tdbb, + &thread_db::getTransaction, + &thread_db::setTransaction, + transaction); - for (TrigVector::iterator i = attachment->att_ddl_triggers->begin(); - i != attachment->att_ddl_triggers->end(); - ++i) - { - if ((i->type & (1LL << action)) && - ((preTriggers && (i->type & 0x1) == 0) || (!preTriggers && (i->type & 0x1) == 0x1))) - { - triggers.add() = *i; - } - } - - EXE_execute_triggers(tdbb, &triggersPtr, NULL, NULL, TRIGGER_DDL, - StmtNode::ALL_TRIGS); - - tdbb->setTransaction(oldTransaction); - } - catch (...) - { - tdbb->setTransaction(oldTransaction); - throw; - } + EXE_execute_triggers(tdbb, &attachment->att_ddl_triggers, NULL, NULL, TRIGGER_DDL, + preTriggers ? StmtNode::PRE_TRIG : StmtNode::POST_TRIG, action); } } @@ -693,7 +671,7 @@ void EXE_receive(thread_db* tdbb, // ASF: temporary blobs returned to the client should not be released // with the request, but in the transaction end. - if (top_level) + if (top_level || transaction->tra_temp_blobs_count) { for (int i = 0; i < format->fmt_count; ++i) { @@ -707,14 +685,21 @@ void EXE_receive(thread_db* tdbb, { BlobIndex* current = &transaction->tra_blobs->current(); - if (current->bli_request && + if (top_level && + current->bli_request && current->bli_request->req_blobs.locate(id->bid_temp_id())) { current->bli_request->req_blobs.fastRemove(); current->bli_request = NULL; } + + if (!current->bli_materialized && + (current->bli_blob_object->blb_flags & BLB_close_on_read)) + { + current->bli_blob_object->BLB_close(tdbb); + } } - else + else if (top_level) { transaction->checkBlob(tdbb, id, NULL, false); } @@ -786,6 +771,12 @@ void EXE_release(thread_db* tdbb, jrd_req* request) request->req_attachment = NULL; } + + if (request->req_timer) + { + request->req_timer->stop(); + request->req_timer = NULL; + } } @@ -906,7 +897,7 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction) request->req_records_affected.clear(); // Store request start time for timestamp work - TimeZoneUtil::validateGmtTimeStamp(request->req_gmt_timestamp); + request->validateTimeStamp(); // Set all invariants to not computed. const ULONG* const* ptr, * const* end; @@ -987,19 +978,12 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request) request->req_sorts.unlinkAll(); - if (request->req_proc_sav_point && (request->req_flags & req_proc_fetch)) - { - // Release savepoints used by this request - Savepoint::destroy(request->req_proc_sav_point); - fb_assert(!request->req_proc_sav_point); - } - TRA_release_request_snapshot(tdbb, request); TRA_detach_request(request); request->req_flags &= ~(req_active | req_proc_fetch | req_reserved); request->req_flags |= req_abort | req_stall; - request->req_gmt_timestamp.invalidate(); + request->invalidateTimeStamp(); request->req_caller = NULL; request->req_proc_inputs = NULL; request->req_proc_caller = NULL; @@ -1077,7 +1061,7 @@ static void execute_looper(thread_db* tdbb, { if (transaction->tra_save_point && transaction->tra_save_point->isSystem() && - transaction->tra_save_point->getNumber() == savNumber) + transaction->tra_save_point->getNumber() >= savNumber) { const auto savepoint = transaction->tra_save_point; // Forget about any undo for this verb @@ -1092,10 +1076,12 @@ static void execute_looper(thread_db* tdbb, void EXE_execute_triggers(thread_db* tdbb, - TrigVector** triggers, - record_param* old_rpb, - record_param* new_rpb, - TriggerAction trigger_action, StmtNode::WhichTrigger which_trig) + TrigVector** triggers, + record_param* old_rpb, + record_param* new_rpb, + TriggerAction trigger_action, + StmtNode::WhichTrigger which_trig, + int ddl_action) { /************************************** * @@ -1108,7 +1094,7 @@ void EXE_execute_triggers(thread_db* tdbb, * if any blow up. * **************************************/ - if (!*triggers) + if (!*triggers || (*triggers)->isEmpty()) return; SET_TDBB(tdbb); @@ -1116,7 +1102,7 @@ void EXE_execute_triggers(thread_db* tdbb, jrd_req* const request = tdbb->getRequest(); jrd_tra* const transaction = request ? request->req_transaction : tdbb->getTransaction(); - TrigVector* vector = *triggers; + RefPtr vector(*triggers); Record* const old_rec = old_rpb ? old_rpb->rpb_record : NULL; Record* const new_rec = new_rpb ? new_rpb->rpb_record : NULL; @@ -1138,7 +1124,7 @@ void EXE_execute_triggers(thread_db* tdbb, TimeStamp timestamp; if (request) - timestamp = request->req_gmt_timestamp; + timestamp = request->getGmtTimeStamp(); else TimeZoneUtil::validateGmtTimeStamp(timestamp); @@ -1148,6 +1134,20 @@ void EXE_execute_triggers(thread_db* tdbb, { for (TrigVector::iterator ptr = vector->begin(); ptr != vector->end(); ++ptr) { + if (trigger_action == TRIGGER_DDL && ddl_action) + { + // Skip triggers not matching our action + + fb_assert(which_trig == StmtNode::PRE_TRIG || which_trig == StmtNode::POST_TRIG); + const bool preTriggers = (which_trig == StmtNode::PRE_TRIG); + + const auto type = ptr->type & ~TRIGGER_TYPE_MASK; + const bool preTrigger = ((type & 1) == 0); + + if (!(type & (1LL << ddl_action)) || preTriggers != preTrigger) + continue; + } + ptr->compile(tdbb); trigger = ptr->statement->findRequest(tdbb); @@ -1186,7 +1186,7 @@ void EXE_execute_triggers(thread_db* tdbb, } } - trigger->req_gmt_timestamp = timestamp; + trigger->setGmtTimeStamp(timestamp.value()); trigger->req_trigger_action = trigger_action; TraceTrigExecute trace(tdbb, trigger, which_trig); @@ -1200,7 +1200,19 @@ void EXE_execute_triggers(thread_db* tdbb, &tdbb->getAttachment()->att_original_timezone, tdbb->getAttachment()->att_current_timezone); - EXE_start(tdbb, trigger, transaction); + if (trigger_action == TRIGGER_DISCONNECT) + { + if (!trigger->req_timer) + trigger->req_timer = FB_NEW_POOL(*tdbb->getAttachment()->att_pool) TimeoutTimer(); + + const unsigned int timeOut = tdbb->getDatabase()->dbb_config->getOnDisconnectTrigTimeout() * 1000; + trigger->req_timer->setup(timeOut, isc_cfg_stmt_timeout); + trigger->req_timer->start(); + thread_db::TimerGuard timerGuard(tdbb, trigger->req_timer, true); + EXE_start(tdbb, trigger, transaction); // Under timerGuard scope + } + else + EXE_start(tdbb, trigger, transaction); } const bool ok = (trigger->req_operation != jrd_req::req_unwind); @@ -1215,15 +1227,9 @@ void EXE_execute_triggers(thread_db* tdbb, trigger = NULL; } - - if (vector != *triggers) - MET_release_triggers(tdbb, &vector, true); } catch (const Firebird::Exception& ex) { - if (vector != *triggers) - MET_release_triggers(tdbb, &vector, true); - if (trigger) { EXE_unwind(tdbb, trigger); @@ -1231,6 +1237,14 @@ void EXE_execute_triggers(thread_db* tdbb, trigger->req_flags &= ~req_in_use; ex.stuffException(tdbb->tdbb_status_vector); + + if (trigger_action == TRIGGER_DISCONNECT && + !(tdbb->tdbb_flags & TDBB_stack_trace_done) && (tdbb->tdbb_flags & TDBB_sys_error)) + { + stuff_stack_trace(trigger); + tdbb->tdbb_flags |= TDBB_stack_trace_done; + } + trigger_failure(tdbb, trigger); } @@ -1239,10 +1253,9 @@ void EXE_execute_triggers(thread_db* tdbb, } -static void stuff_stack_trace(const jrd_req* request) +bool EXE_get_stack_trace(const jrd_req* request, string& sTrace) { - string sTrace; - + sTrace = ""; for (const jrd_req* req = request; req; req = req->req_caller) { const JrdStatement* const statement = req->getStatement(); @@ -1298,7 +1311,14 @@ static void stuff_stack_trace(const jrd_req* request) } } - if (sTrace.hasData()) + return sTrace.hasData(); +} + +static void stuff_stack_trace(const jrd_req* request) +{ + string sTrace; + + if (EXE_get_stack_trace(request, sTrace)) ERR_post_nothrow(Arg::Gds(isc_stack_trace) << Arg::Str(sTrace)); } @@ -1418,7 +1438,7 @@ const StmtNode* EXE_looper(thread_db* tdbb, jrd_req* request, const StmtNode* no TRA_release_request_snapshot(tdbb, request); request->req_flags &= ~(req_active | req_reserved); - request->req_gmt_timestamp.invalidate(); + request->invalidateTimeStamp(); release_blobs(tdbb, request); } diff --git a/src/jrd/exe.h b/src/jrd/exe.h index 26adac8ab1a..d3c9198ebbb 100644 --- a/src/jrd/exe.h +++ b/src/jrd/exe.h @@ -617,6 +617,7 @@ const int csb_validation = 64; // we're in a validation expression (RDB hack) const int csb_reuse_context = 128; // allow context reusage const int csb_subroutine = 256; // sub routine const int csb_reload = 512; // request's BLR should be loaded and parsed again +const int csb_computed_field = 1024; // computed field expression // CompilerScratch.csb_rpt[].csb_flags's values. const int csb_active = 1; // stream is active diff --git a/src/jrd/exe_proto.h b/src/jrd/exe_proto.h index ea3dedcc2ee..49c4635e93e 100644 --- a/src/jrd/exe_proto.h +++ b/src/jrd/exe_proto.h @@ -40,11 +40,13 @@ void EXE_assignment(Jrd::thread_db* tdbb, const Jrd::ValueExprNode* to, dsc* fro void EXE_execute_db_triggers(Jrd::thread_db*, Jrd::jrd_tra*, enum TriggerAction); void EXE_execute_ddl_triggers(Jrd::thread_db* tdbb, Jrd::jrd_tra* transaction, bool preTriggers, int action); +bool EXE_get_stack_trace(const Jrd::jrd_req* request, Firebird::string& sTrace); + const Jrd::StmtNode* EXE_looper(Jrd::thread_db* tdbb, Jrd::jrd_req* request, const Jrd::StmtNode* in_node); void EXE_execute_triggers(Jrd::thread_db*, Jrd::TrigVector**, Jrd::record_param*, Jrd::record_param*, - enum TriggerAction, Jrd::StmtNode::WhichTrigger); + enum TriggerAction, Jrd::StmtNode::WhichTrigger, int = 0); void EXE_receive(Jrd::thread_db*, Jrd::jrd_req*, USHORT, ULONG, void*, bool = false); void EXE_release(Jrd::thread_db*, Jrd::jrd_req*); diff --git a/src/jrd/extds/ExtDS.cpp b/src/jrd/extds/ExtDS.cpp index e45b5f363a8..88fa00827eb 100644 --- a/src/jrd/extds/ExtDS.cpp +++ b/src/jrd/extds/ExtDS.cpp @@ -115,6 +115,9 @@ Manager::~Manager() void Manager::addProvider(Provider* provider) { + // TODO: if\when usage of user providers will be implemented, + // need to check provider name for allowed chars (file system rules ?) + for (const Provider* prv = m_providers; prv; prv = prv->m_next) { if (prv->m_name == provider->m_name) { @@ -155,6 +158,15 @@ static void splitDataSourceName(thread_db* tdbb, const string& dataSource, else { FB_SIZE_T pos = dataSource.find("::"); + + // Check if it is part of IPv6 address, assume provider name can't contain square brackets + if (pos != string::npos && + dataSource.rfind("[", pos) != string::npos && + dataSource.find("]", pos) != string::npos) + { + pos = string::npos; + } + if (pos != string::npos) { prvName = dataSource.substr(0, pos); @@ -216,18 +228,21 @@ Connection* Manager::getConnection(thread_db* tdbb, const string& dataSource, if (!isCurrent) { + CryptHash ch(att->att_crypt_callback); hash = DefaultHash::hash(dbName.c_str(), dbName.length(), MAX_ULONG) + - DefaultHash::hash(dpb.getBuffer(), dpb.getBufferLength(), MAX_ULONG); + DefaultHash::hash(dpb.getBuffer(), dpb.getBufferLength(), MAX_ULONG) + + DefaultHash::hash(ch.getValue(), ch.getLength(), MAX_ULONG); while (true) { - conn = m_connPool->getConnection(tdbb, prv, hash, dbName, dpb); + conn = m_connPool->getConnection(tdbb, prv, hash, dbName, dpb, ch); if (!conn) break; if (conn->validate(tdbb)) { prv->bindConnection(tdbb, conn); + conn->resetRedirect(att->att_crypt_callback); break; } @@ -249,7 +264,7 @@ Connection* Manager::getConnection(thread_db* tdbb, const string& dataSource, } ConnectionsPool* Manager::getConnPool(bool create) -{ +{ if (!m_connPool && create) m_connPool = FB_NEW_POOL(manager->getPool()) ConnectionsPool(manager->getPool()); @@ -343,7 +358,7 @@ Connection* Provider::createConnection(thread_db* tdbb, const PathName& dbName, ClumpletReader& dpb, TraScope tra_scope) { Connection* conn = doCreateConnection(); - conn->setup(dbName, dpb); + conn->setup(dbName, dpb, tdbb->getAttachment()->att_crypt_callback); try { conn->attach(tdbb); @@ -379,6 +394,7 @@ Connection* Provider::getBoundConnection(Jrd::thread_db* tdbb, { Database* dbb = tdbb->getDatabase(); Attachment* att = tdbb->getAttachment(); + CryptHash ch(att->att_crypt_callback); MutexLockGuard guard(m_mutex, FB_FUNCTION); @@ -392,7 +408,7 @@ Connection* Provider::getBoundConnection(Jrd::thread_db* tdbb, if (conn->getBoundAtt() != att) break; - if (conn->isSameDatabase(dbName, dpb) && + if (conn->isSameDatabase(dbName, dpb, ch) && conn->isAvailable(tdbb, tra_scope)) { fb_assert(conn->getProvider() == this); @@ -402,6 +418,7 @@ Connection* Provider::getBoundConnection(Jrd::thread_db* tdbb, continue; #endif + conn->resetRedirect(att->att_crypt_callback); return conn; } } while (acc.getNext()); @@ -443,9 +460,9 @@ void Provider::jrdAttachmentEnd(thread_db* tdbb, Jrd::Attachment* att, bool forc void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool) { ConnectionsPool* connPool = conn.getConnPool(); + Attachment* att = conn.getBoundAtt(); { // m_mutex scope - Attachment* att = conn.getBoundAtt(); MutexLockGuard guard(m_mutex, FB_FUNCTION); bool found = false; @@ -466,7 +483,43 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool) m_connections.add(AttToConn(NULL, &conn)); } - if (!inPool || !connPool || !conn.isConnected() || !conn.resetSession(tdbb)) + FbLocalStatus resetError; + inPool = inPool && connPool && connPool->getMaxCount() && + conn.isConnected() && conn.hasValidCryptCallback(); + + if (inPool) + { + inPool = conn.resetSession(tdbb); + + // Check if reset of external session failed when parent (local) attachment + // is resetting or run ON DISCONNECT trigger. + + const auto status = tdbb->tdbb_status_vector; + if (!inPool && status->hasData()) + { + if (att->att_flags & ATT_resetting) + resetError.loadFrom(status); + else + { + auto req = tdbb->getRequest(); + while (req) + { + if (req->req_trigger_action == TRIGGER_DISCONNECT) + { + resetError.loadFrom(status); + break; + } + req = req->req_caller; + } + } + } + } + + if (inPool) + { + connPool->putConnection(tdbb, &conn); + } + else { { // scope MutexLockGuard guard(m_mutex, FB_FUNCTION); @@ -479,9 +532,8 @@ void Provider::releaseConnection(thread_db* tdbb, Connection& conn, bool inPool) connPool->delConnection(tdbb, &conn, false); Connection::deleteConnection(tdbb, &conn); + resetError.check(); } - else - connPool->putConnection(tdbb, &conn); } void Provider::clearConnections(thread_db* tdbb) @@ -540,12 +592,14 @@ Connection::Connection(Provider& prov) : { } -void Connection::setup(const PathName& dbName, const ClumpletReader& dpb) +void Connection::setup(const PathName& dbName, const ClumpletReader& dpb, ICryptKeyCallback* attCallback) { m_dbName = dbName; m_dpb.clear(); m_dpb.add(dpb.getBuffer(), dpb.getBufferLength()); + + m_cryptCallbackRedir.setRedirect(attCallback); } void Connection::deleteConnection(thread_db* tdbb, Connection* conn) @@ -563,7 +617,7 @@ Connection::~Connection() fb_assert(m_boundAtt == NULL); } -bool Connection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb) const +bool Connection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb, const CryptHash& hash) const { if (m_dbName != dbName) return false; @@ -572,7 +626,8 @@ bool Connection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb) con // but in different order const FB_SIZE_T len = m_dpb.getCount(); - return (len == dpb.getBufferLength()) && (memcmp(m_dpb.begin(), dpb.getBuffer(), len) == 0); + return (len == dpb.getBufferLength()) && (memcmp(m_dpb.begin(), dpb.getBuffer(), len) == 0) && + (m_cryptCallbackRedir == hash); } @@ -872,7 +927,7 @@ ConnectionsPool::Data* ConnectionsPool::removeOldest() } Connection* ConnectionsPool::getConnection(thread_db* tdbb, Provider* prv, ULONG hash, - const PathName& dbName, ClumpletReader& dpb) + const PathName& dbName, ClumpletReader& dpb, const CryptHash& ch) { MutexLockGuard guard(m_mutex, FB_FUNCTION); @@ -888,7 +943,7 @@ Connection* ConnectionsPool::getConnection(thread_db* tdbb, Provider* prv, ULONG break; Connection* conn = item->m_conn; - if (conn->getProvider() == prv && conn->isSameDatabase(dbName, dpb)) + if (conn->getProvider() == prv && conn->isSameDatabase(dbName, dpb, ch)) { m_idleArray.remove(pos); removeFromList(&m_idleList, item); @@ -907,7 +962,8 @@ void ConnectionsPool::putConnection(thread_db* tdbb, Connection* conn) fb_assert(conn->getConnPool() == this); Connection* oldConn = NULL; - bool startIdleTimer = false; + Firebird::RefPtr timer; + if (m_maxCount > 0) { MutexLockGuard guard(m_mutex, FB_FUNCTION); @@ -979,7 +1035,7 @@ void ConnectionsPool::putConnection(thread_db* tdbb, Connection* conn) if (!m_timer) m_timer = FB_NEW IdleTimer(*this); - startIdleTimer = true; + timer = m_timer; } #ifdef EDS_DEBUG @@ -998,8 +1054,10 @@ void ConnectionsPool::putConnection(thread_db* tdbb, Connection* conn) if (oldConn) oldConn->getProvider()->releaseConnection(tdbb, *oldConn, false); - if (startIdleTimer) - m_timer->start(); + // Note, m_timer could be cleared at this point - due to shutdown. + // Then m_idleList will be empty and start() will do nothing. + if (timer) + timer->start(); } void ConnectionsPool::addConnection(thread_db* tdbb, Connection* conn, ULONG hash) @@ -2231,7 +2289,7 @@ void Statement::setInParams(thread_db* tdbb, const MetaName* const* names, doSetInParams(tdbb, mapCount, m_sqlParamsMap.begin(), sqlParams); } - else + else doSetInParams(tdbb, count, NULL, (params ? params->items.begin() : NULL)); } @@ -2543,10 +2601,10 @@ void EngineCallbackGuard::init(thread_db* tdbb, Connection& conn, const char* fr { m_saveConnection = attachment->att_ext_connection; m_stable = attachment->getStable(); - m_stable->getMutex()->leave(); + m_stable->getSync()->leave(); - MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION); - MutexLockGuard guardMain(*m_stable->getMutex(), FB_FUNCTION); + Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION); + Jrd::AttSyncLockGuard guardMain(*m_stable->getSync(), FB_FUNCTION); if (m_stable->getHandle() == attachment) attachment->att_ext_connection = &conn; } @@ -2568,13 +2626,13 @@ EngineCallbackGuard::~EngineCallbackGuard() Jrd::Attachment* attachment = m_tdbb->getAttachment(); if (attachment && m_stable.hasData()) { - MutexLockGuard guardAsync(*m_stable->getMutex(true, true), FB_FUNCTION); - m_stable->getMutex()->enter(FB_FUNCTION); + Jrd::AttSyncLockGuard guardAsync(*m_stable->getSync(true, true), FB_FUNCTION); + m_stable->getSync()->enter(FB_FUNCTION); if (m_stable->getHandle() == attachment) attachment->att_ext_connection = m_saveConnection; else - m_stable->getMutex()->leave(); + m_stable->getSync()->leave(); } jrd_tra* transaction = m_tdbb->getTransaction(); @@ -2584,4 +2642,62 @@ EngineCallbackGuard::~EngineCallbackGuard() } } + +// CryptHash + +CryptHash::CryptHash(ICryptKeyCallback* callback) + : m_value(*getDefaultMemoryPool()) +{ + assign(callback); +} + +CryptHash::CryptHash() + : m_value(*getDefaultMemoryPool()) +{ } + +void CryptHash::assign(ICryptKeyCallback* callback) +{ + fb_assert(!isValid()); + + FbLocalStatus status; + + int len = callback->getHashLength(&status); + if (len > 0 && status.isSuccess()) + callback->getHashData(&status, m_value.getBuffer(len)); + + m_valid = (len >= 0) && status.isSuccess(); +} + +bool CryptHash::operator==(const CryptHash& h) const +{ + return isValid() && h.isValid() && m_value == h.m_value; +} + + +// CryptCallbackRedirector + +void CryptCallbackRedirector::setRedirect(Firebird::ICryptKeyCallback* originalCallback) +{ + m_hash.assign(originalCallback); + + if (m_hash.isValid()) + m_keyCallback = originalCallback; +} + +void CryptCallbackRedirector::resetRedirect(Firebird::ICryptKeyCallback* newCallback) +{ +#ifdef DEV_BUILD + CryptHash ch(newCallback); + fb_assert(isValid() && ch.isValid()); + fb_assert(m_hash == ch); +#endif + + m_keyCallback = newCallback; +} + +bool CryptCallbackRedirector::operator==(const CryptHash& ch) const +{ + return m_hash == ch; +} + } // namespace EDS diff --git a/src/jrd/extds/ExtDS.h b/src/jrd/extds/ExtDS.h index 0ed21201650..478405b9c78 100644 --- a/src/jrd/extds/ExtDS.h +++ b/src/jrd/extds/ExtDS.h @@ -63,6 +63,81 @@ enum TraScope { traTwoPhase }; + +// helper to work with ICryptKeyCallback +class CryptHash +{ +public: + explicit CryptHash(Firebird::ICryptKeyCallback* callback); + CryptHash(); + + void assign(Firebird::ICryptKeyCallback* callback); + + bool isValid() const + { + return m_valid; + } + + const UCHAR* getValue() const + { + fb_assert(isValid()); + + return m_value.begin(); + } + + int getLength() const + { + return isValid() ? m_value.getCount() : -1; + } + + bool operator==(const CryptHash& h) const; + +private: + Firebird::UCharBuffer m_value; + bool m_valid = false; +}; + + +class CryptCallbackRedirector : + public Firebird::VersionedIface> +{ + public: + CryptCallbackRedirector() = default; + + void setRedirect(Firebird::ICryptKeyCallback* originalCallback); + void resetRedirect(Firebird::ICryptKeyCallback* newCallback); + bool operator==(const CryptHash& h) const; + + bool isValid() const + { + return m_hash.isValid(); + } + + // ICryptKeyCallback implementation + unsigned int callback(unsigned int dataLength, const void* data, + unsigned int bufferLength, void* buffer) override + { + return m_keyCallback ? m_keyCallback->callback(dataLength, data, bufferLength, buffer) : 0; + } + + int getHashLength(Firebird::CheckStatusWrapper* status) override + { + return m_hash.getLength(); + } + + void getHashData(Firebird::CheckStatusWrapper* status, void* h) override + { + fb_assert(m_hash.isValid()); + if (m_hash.isValid()) + memcpy(h, m_hash.getValue(), m_hash.getLength()); + } + + private: + ICryptKeyCallback* m_keyCallback = nullptr; + CryptHash m_hash; + }; + + // Known built-in provider's names extern const char* FIREBIRD_PROVIDER_NAME; extern const char* INTERNAL_PROVIDER_NAME; @@ -187,8 +262,7 @@ class Provider : public Firebird::GlobalStorage } }; - typedef Firebird::BePlusTree + typedef Firebird::BePlusTree AttToConnMap; AttToConnMap m_connections; @@ -207,7 +281,7 @@ class ConnectionsPool // find and return cached connection or NULL Connection* getConnection(Jrd::thread_db* tdbb, Provider* prv, ULONG hash, const Firebird::PathName& dbName, - Firebird::ClumpletReader& dpb); + Firebird::ClumpletReader& dpb, const CryptHash& ch); // put unused connection into pool or destroy it void putConnection(Jrd::thread_db* tdbb, Connection* conn); @@ -416,7 +490,7 @@ class Connection : public Firebird::PermanentStorage virtual ~Connection(); static void deleteConnection(Jrd::thread_db* tdbb, Connection* conn); - void setup(const Firebird::PathName& dbName, const Firebird::ClumpletReader& dpb); + void setup(const Firebird::PathName& dbName, const Firebird::ClumpletReader& dpb, Firebird::ICryptKeyCallback* attCallback); void setBoundAtt(Jrd::Attachment* att) { m_boundAtt = att; } @@ -448,7 +522,7 @@ class Connection : public Firebird::PermanentStorage virtual bool validate(Jrd::thread_db* tdbb) = 0; virtual bool isSameDatabase(const Firebird::PathName& dbName, - Firebird::ClumpletReader& dpb) const; + Firebird::ClumpletReader& dpb, const CryptHash& ch) const; // only Internal provider is able to create "current" connections virtual bool isCurrent() const { return false; } @@ -496,6 +570,16 @@ class Connection : public Firebird::PermanentStorage // Clear specified flag void clearFeature(info_features value) { m_features[value] = false; } + void resetRedirect(Firebird::ICryptKeyCallback* originalCallback) + { + m_cryptCallbackRedir.resetRedirect(originalCallback); + } + + bool hasValidCryptCallback() const + { + return m_cryptCallbackRedir.isValid(); + } + protected: virtual Transaction* doCreateTransaction() = 0; virtual Statement* doCreateStatement() = 0; @@ -527,6 +611,8 @@ class Connection : public Firebird::PermanentStorage bool m_wrapErrors; bool m_broken; bool m_features[fb_feature_max]; + + CryptCallbackRedirector m_cryptCallbackRedir; }; class Transaction : public Firebird::PermanentStorage diff --git a/src/jrd/extds/InternalDS.cpp b/src/jrd/extds/InternalDS.cpp index 2abcea3b6ce..7023846bfac 100644 --- a/src/jrd/extds/InternalDS.cpp +++ b/src/jrd/extds/InternalDS.cpp @@ -127,24 +127,6 @@ InternalConnection::~InternalConnection() { } -// Status helper -class IntStatus : public Firebird::FbLocalStatus -{ -public: - explicit IntStatus(FbStatusVector *p) - : FbLocalStatus(), v(p) - {} - - ~IntStatus() - { - if (v) - fb_utils::copyStatus(v, &(*this)); - } - -private: - FbStatusVector *v; -}; - void InternalConnection::attach(thread_db* tdbb) { fb_assert(!m_attachment); @@ -175,6 +157,7 @@ void InternalConnection::attach(thread_db* tdbb) EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); m_provider.reset(attachment->getProvider()); m_provider->addRef(); + m_provider->setDbCryptCallback(&status, &m_cryptCallbackRedir); m_attachment.assignRefNoIncr(m_provider->attachDatabase(&status, m_dbName.c_str(), newDpb.getBufferLength(), newDpb.getBuffer())); } @@ -209,13 +192,16 @@ void InternalConnection::doDetach(thread_db* tdbb) FbLocalStatus status; RefPtr att = m_attachment; - m_attachment = NULL; + m_attachment = NULL; // release and nullify { // scope EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); att->detach(&status); } + if (!(status->getState() & IStatus::STATE_ERRORS)) + att.clear(); + if (status->getErrors()[1] == isc_att_shutdown || status->getErrors()[1] == isc_shutdown) { status->init(); @@ -285,13 +271,13 @@ bool InternalConnection::validate(thread_db* tdbb) return status.isSuccess(); } -bool InternalConnection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb) const +bool InternalConnection::isSameDatabase(const PathName& dbName, ClumpletReader& dpb, const CryptHash& ch) const { if (m_isCurrent) { const Attachment* att = m_attachment->getHandle(); - const MetaString& attUser = att->att_user->getUserName(); - const MetaString& attRole = att->att_user->getSqlRole(); + const MetaString& attUser = att->getUserName(); + const MetaString& attRole = att->getSqlRole(); MetaString str; @@ -310,7 +296,7 @@ bool InternalConnection::isSameDatabase(const PathName& dbName, ClumpletReader& } } - return Connection::isSameDatabase(dbName, dpb); + return Connection::isSameDatabase(dbName, dpb, ch); } Transaction* InternalConnection::doCreateTransaction() @@ -345,10 +331,9 @@ void InternalTransaction::doStart(FbStatusVector* status, thread_db* tdbb, Clump JAttachment* att = m_IntConnection.getJrdAtt(); EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); - IntStatus s(status); m_transaction.assignRefNoIncr( - att->startTransaction(&s, tpb.getBufferLength(), tpb.getBuffer())); + att->startTransaction(status, tpb.getBufferLength(), tpb.getBuffer())); if (m_transaction) m_transaction->getHandle()->tra_callback_count = localTran->tra_callback_count; @@ -369,18 +354,20 @@ void InternalTransaction::doCommit(FbStatusVector* status, thread_db* tdbb, bool if (m_scope == traCommon && m_IntConnection.isCurrent()) { if (!retain) { - m_transaction = NULL; + m_transaction = NULL; // release and nullify } } else { - IntStatus s(status); - EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); if (retain) - m_transaction->commitRetaining(&s); + m_transaction->commitRetaining(status); else - m_transaction->commit(&s); + { + m_transaction->commit(status); + if (!(status->getState() & IStatus::STATE_ERRORS)) + m_transaction.clear(); + } } } @@ -390,30 +377,51 @@ void InternalTransaction::doRollback(FbStatusVector* status, thread_db* tdbb, bo if (m_connection.isBroken()) { - m_transaction = NULL; + m_transaction.clear(); return; } if (m_scope == traCommon && m_IntConnection.isCurrent()) { if (!retain) { - m_transaction = NULL; + m_transaction = NULL; // release and nullify } + return; } - else - { - IntStatus s(status); + ISC_STATUS err = 0; + { EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); if (retain) - m_transaction->rollbackRetaining(&s); + m_transaction->rollbackRetaining(status); else - m_transaction->rollback(&s); + m_transaction->rollback(status); + + if (status->getState() & IStatus::STATE_ERRORS) + err = status->getErrors()[1]; + + if (err == isc_cancelled) + { + FbLocalStatus temp; + JAttachment* jAtt = m_IntConnection.getJrdAtt(); + jAtt->cancelOperation(&temp, fb_cancel_disable); + + status->init(); + if (retain) + m_transaction->rollbackRetaining(status); + else + m_transaction->rollback(status); + + err = (status->getState() & IStatus::STATE_ERRORS) ? + status->getErrors()[1] : 0; + + jAtt->cancelOperation(&temp, fb_cancel_enable); + } } - if ((status->getErrors()[1] == isc_att_shutdown || status->getErrors()[1] == isc_shutdown) && !retain) + if ((!err || err == isc_att_shutdown || err == isc_shutdown) && !retain) { - m_transaction = NULL; + m_transaction.clear(); status->init(); } } @@ -464,23 +472,31 @@ void InternalStatement::doPrepare(thread_db* tdbb, const string& sql) if (statement && statement->parentStatement) statement = statement->parentStatement; - if (statement && statement->triggerInvoker) - tran->getHandle()->tra_caller_name = CallerName(obj_trigger, - statement->triggerName, - statement->triggerInvoker->getUserName()); - else if (statement && (routine = statement->getRoutine()) && - routine->getName().identifier.hasData()) + if (statement) { - const MetaString& userName = routine->invoker ? routine->invoker->getUserName() : ""; - if (routine->getName().package.isEmpty()) + if (statement->triggerInvoker) { - tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), - routine->getName().identifier, userName); + tran->getHandle()->tra_caller_name = + CallerName(obj_trigger, statement->triggerName, statement->triggerInvoker->getUserName()); } - else + else if (statement->triggerName.hasData()) + { + tran->getHandle()->tra_caller_name = + CallerName(obj_trigger, statement->triggerName, ""); + } + else if ((routine = statement->getRoutine()) && routine->getName().identifier.hasData()) { - tran->getHandle()->tra_caller_name = CallerName(obj_package_header, - routine->getName().package, userName); + const MetaString& userName = routine->invoker ? routine->invoker->getUserName() : ""; + if (routine->getName().package.isEmpty()) + { + tran->getHandle()->tra_caller_name = CallerName(routine->getObjectType(), + routine->getName().identifier, userName); + } + else + { + tran->getHandle()->tra_caller_name = CallerName(obj_package_header, + routine->getName().package, userName); + } } } else @@ -618,7 +634,7 @@ void InternalStatement::doOpen(thread_db* tdbb) if (m_cursor) { m_cursor->close(&status); - m_cursor = NULL; + m_cursor.clear(); } fb_assert(m_inMetadata->getMessageLength() == m_in_buffer.getCount()); @@ -661,9 +677,11 @@ void InternalStatement::doClose(thread_db* tdbb, bool drop) EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); if (m_cursor) + { m_cursor->close(&status); + m_cursor.clear(); + } - m_cursor = NULL; if (status->getState() & IStatus::STATE_ERRORS) { raise(&status, tdbb, "JResultSet::close"); @@ -672,10 +690,12 @@ void InternalStatement::doClose(thread_db* tdbb, bool drop) if (drop) { if (m_request) + { m_request->free(&status); + m_request.clear(); + } m_allocated = false; - m_request = NULL; if (status->getState() & IStatus::STATE_ERRORS) { @@ -835,7 +855,7 @@ void InternalBlob::close(thread_db* tdbb) { EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); m_blob->close(&status); - m_blob = NULL; + m_blob.clear(); } if (status->getState() & IStatus::STATE_ERRORS) @@ -855,7 +875,7 @@ void InternalBlob::cancel(thread_db* tdbb) { EngineCallbackGuard guard(tdbb, m_connection, FB_FUNCTION); m_blob->cancel(&status); - m_blob = NULL; + m_blob.clear(); } if (status->getState() & IStatus::STATE_ERRORS) diff --git a/src/jrd/extds/InternalDS.h b/src/jrd/extds/InternalDS.h index 3ec99de2b4c..c51d54cab1b 100644 --- a/src/jrd/extds/InternalDS.h +++ b/src/jrd/extds/InternalDS.h @@ -74,7 +74,7 @@ class InternalConnection : public Connection virtual bool validate(Jrd::thread_db* tdbb); virtual bool isSameDatabase(const Firebird::PathName& dbName, - Firebird::ClumpletReader& dpb) const; + Firebird::ClumpletReader& dpb, const CryptHash& ch) const override; virtual bool isCurrent() const { return m_isCurrent; } diff --git a/src/jrd/extds/IscDS.cpp b/src/jrd/extds/IscDS.cpp index 10ab7f5c700..190e296cdfa 100644 --- a/src/jrd/extds/IscDS.cpp +++ b/src/jrd/extds/IscDS.cpp @@ -113,11 +113,17 @@ void IscConnection::attach(thread_db* tdbb) validatePassword(tdbb, m_dbName, newDpb); newDpb.insertInt(isc_dpb_ext_call_depth, attachment->att_ext_call_depth + 1); + if (newDpb.getBufferLength() > MAX_USHORT) + { + ERR_post(Arg::Gds(isc_imp_exc) << + Arg::Gds(isc_random) << Arg::Str("DPB size greater than 64KB")); + } + FbLocalStatus status; { EngineCallbackGuard guard(tdbb, *this, FB_FUNCTION); - ICryptKeyCallback* cb = tdbb->getAttachment()->att_crypt_callback; + ICryptKeyCallback* cb = &m_cryptCallbackRedir; try { m_iscProvider.fb_database_crypt_callback(&status, cb); @@ -158,37 +164,34 @@ void IscConnection::attach(thread_db* tdbb) memset(m_features, false, sizeof(m_features)); m_sqlDialect = 1; - const unsigned char* p = buff, *end = buff + sizeof(buff); - while (p < end) + for (ClumpletReader p(ClumpletReader::InfoResponse, buff, sizeof(buff)); !p.isEof(); p.moveNext()) { - const UCHAR item = *p++; - const USHORT len = m_iscProvider.isc_vax_integer(p, sizeof(USHORT)); - p += sizeof(USHORT); - - switch (item) + const UCHAR* b = p.getBytes(); + switch (p.getClumpTag()) { case isc_info_db_sql_dialect: - m_sqlDialect = m_iscProvider.isc_vax_integer(p, len); + m_sqlDialect = p.getInt(); break; case fb_info_features: - for (int i = 0; i < len; i++) + for (unsigned i = 0; i < p.getClumpLength(); i++) { - if (p[i] == 0) + if (b[i] == 0) ERR_post(Arg::Gds(isc_random) << Arg::Str("Bad provider feature value")); - if (p[i] < fb_feature_max) - setFeature(static_cast(p[i])); + if (b[i] < fb_feature_max) + setFeature(static_cast(b[i])); // else this provider supports unknown feature, ignore it. } break; case isc_info_error: + if (p.getClumpLength() > 1) { - const ULONG err = m_iscProvider.isc_vax_integer(p + 1, len - 1); + const ULONG err = m_iscProvider.isc_vax_integer(b + 1, p.getClumpLength() - 1); if (err == isc_infunk) { - if (*p == fb_info_features) + if (b[0] == fb_info_features) { // Used provider follow Firebird error reporting conventions but is not aware of // this info item. Assume Firebird 3 or earlier. @@ -198,19 +201,13 @@ void IscConnection::attach(thread_db* tdbb) } break; } - ERR_post(Arg::Gds(isc_random) << Arg::Str("Unexpected error in isc_database_info")); } + ERR_post(Arg::Gds(isc_random) << Arg::Str("Unexpected error in isc_database_info")); case isc_info_truncated: ERR_post(Arg::Gds(isc_random) << Arg::Str("Result truncation in isc_database_info")); - - case isc_info_end: - p = end; - break; } - p += len; } - } void IscConnection::doDetach(thread_db* tdbb) @@ -277,6 +274,7 @@ bool IscConnection::resetSession(thread_db* tdbb) return true; } + ERR_post_nothrow(&status); return false; } @@ -396,6 +394,22 @@ void IscTransaction::doRollback(FbStatusVector* status, thread_db* tdbb, bool re else m_iscProvider.isc_rollback_transaction(status, &m_handle); + if ((status->getState() & IStatus::STATE_ERRORS) && + (status->getErrors()[1] == isc_cancelled)) + { + FbLocalStatus temp; + FB_API_HANDLE db = m_iscConnection.getAPIHandle(); + m_iscProvider.fb_cancel_operation(&temp, &db, fb_cancel_disable); + + status->init(); + if (retain) + m_iscProvider.isc_rollback_retaining(status, &m_handle); + else + m_iscProvider.isc_rollback_transaction(status, &m_handle); + + m_iscProvider.fb_cancel_operation(&temp, &db, fb_cancel_enable); + } + if ((status->getState() & IStatus::STATE_ERRORS) && isConnectionBrokenError(status) && !retain) { diff --git a/src/jrd/filters.cpp b/src/jrd/filters.cpp index 1738af2cf5e..83f98b4750d 100644 --- a/src/jrd/filters.cpp +++ b/src/jrd/filters.cpp @@ -407,7 +407,7 @@ ISC_STATUS filter_format(USHORT action, BlobControl* control) d = desc; d.dsc_address = pBuff; - DescPrinter val(JRD_get_thread_data(), &d, 32); + DescPrinter val(JRD_get_thread_data(), &d, 32, CS_dynamic); str.printf(fmt2, fieldId, diff --git a/src/jrd/fun.epp b/src/jrd/fun.epp index 9c6522f35b3..786f65d90ab 100644 --- a/src/jrd/fun.epp +++ b/src/jrd/fun.epp @@ -292,7 +292,8 @@ enum UdfError static SSHORT blob_get_segment(blb*, UCHAR*, USHORT, USHORT*); static void blob_put_segment(blb*, const UCHAR*, USHORT); static SLONG blob_lseek(blb*, USHORT, SLONG); -static SLONG get_scalar_array(const Parameter*, DSC*, scalar_array_desc*, UCharStack&); +static ULONG get_scalar_array(thread_db* tdbb, const Parameter*, DSC*, + scalar_array_desc*, UCharStack&); static void invoke(thread_db* tdbb, const Function* function, const Parameter* return_ptr, @@ -436,8 +437,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra temp_desc = parameter->prm_desc; temp_desc.dsc_address = temp_ptr; - // CVC: There's a theoretical possibility of overflowing "length" here. - USHORT length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN); + ULONG length = FB_ALIGN(temp_desc.dsc_length, FB_DOUBLE_ALIGN); // If we've got a null argument, just pass zeros (got any better ideas?) @@ -446,7 +446,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra if (parameter->prm_fun_mechanism == FUN_value) { UCHAR* p = (UCHAR *) arg_ptr; - MOVE_CLEAR(p, (SLONG) length); + MOVE_CLEAR(p, length); p += length; arg_ptr = reinterpret_cast(p); continue; @@ -458,7 +458,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra } if (parameter->prm_fun_mechanism != FUN_ref_with_null) - MOVE_CLEAR(temp_ptr, (SLONG) length); + MOVE_CLEAR(temp_ptr, length); else { // Probably for arrays and blobs it's better to preserve the @@ -468,7 +468,7 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra case dtype_quad: case dtype_array: case dtype_blob: - MOVE_CLEAR(temp_ptr, (SLONG) length); + MOVE_CLEAR(temp_ptr, length); break; default: // FUN_ref_with_null, non-blob, non-array: we send null pointer. *arg_ptr++ = 0; @@ -478,7 +478,8 @@ void FUN_evaluate(thread_db* tdbb, const Function* function, const NestValueArra } else if (parameter->prm_fun_mechanism == FUN_scalar_array) { - length = get_scalar_array(parameter, input, (scalar_array_desc*)temp_ptr, array_stack); + length = get_scalar_array(tdbb, parameter, input, (scalar_array_desc*) temp_ptr, + array_stack); } else { @@ -975,10 +976,11 @@ static SSHORT blob_get_segment(blb* blob, UCHAR* buffer, USHORT length, USHORT* } -static SLONG get_scalar_array(const Parameter* arg, - DSC* value, - scalar_array_desc* scalar_desc, - UCharStack& stack) +static ULONG get_scalar_array(thread_db* tdbb, + const Parameter* arg, + DSC* value, + scalar_array_desc* scalar_desc, + UCharStack& stack) { /************************************** * @@ -992,17 +994,16 @@ static SLONG get_scalar_array(const Parameter* arg, * Return length of array desc. * **************************************/ - thread_db* tdbb = JRD_get_thread_data(); + MemoryPool& pool = *tdbb->getDefaultPool(); // Get first the array descriptor, then the array SLONG stuff[IAD_LEN(16) / 4]; Ods::InternalArrayDesc* array_desc = (Ods::InternalArrayDesc*) stuff; - blb* blob = blb::get_array(tdbb, tdbb->getRequest()->req_transaction, (bid*)value->dsc_address, - array_desc); + blb* blob = blb::get_array(tdbb, tdbb->getRequest()->req_transaction, + (bid*) value->dsc_address, array_desc); - fb_assert(array_desc->iad_total_length >= 0); // check before upcasting to size_t - UCHAR* data = FB_NEW_POOL(*getDefaultMemoryPool()) UCHAR[static_cast(array_desc->iad_total_length)]; + AutoPtr data(FB_NEW_POOL(pool) UCHAR[array_desc->iad_total_length]); blob->BLB_get_data(tdbb, data, array_desc->iad_total_length); const USHORT dimensions = array_desc->iad_dimensions; @@ -1012,39 +1013,29 @@ static SLONG get_scalar_array(const Parameter* arg, dsc from = array_desc->iad_rpt[0].iad_desc; if (to.dsc_dtype != from.dsc_dtype || - to.dsc_scale != from.dsc_scale || to.dsc_length != from.dsc_length) + to.dsc_scale != from.dsc_scale || + to.dsc_length != from.dsc_length) { - SLONG n = array_desc->iad_count; - UCHAR* const temp = FB_NEW_POOL(*getDefaultMemoryPool()) UCHAR[static_cast(to.dsc_length * n)]; + ULONG n = array_desc->iad_count; + AutoPtr temp(FB_NEW_POOL(pool) UCHAR[to.dsc_length * n]); to.dsc_address = temp; from.dsc_address = data; - // This loop may call ERR_post indirectly. - try - { - for (; n; --n, to.dsc_address += to.dsc_length, - from.dsc_address += array_desc->iad_element_length) - { - MOV_move(tdbb, &from, &to); - } - } - catch (const Exception&) + for (; n; --n, to.dsc_address += to.dsc_length, + from.dsc_address += array_desc->iad_element_length) { - delete[] data; - delete[] temp; - throw; + MOV_move(tdbb, &from, &to); } - delete[] data; - data = temp; + data = temp.release(); } // Fill out the scalar array descriptor - stack.push(data); scalar_desc->sad_desc = arg->prm_desc; scalar_desc->sad_desc.dsc_address = data; scalar_desc->sad_dimensions = dimensions; + stack.push(data.release()); const Ods::InternalArrayDesc::iad_repeat* tail1 = array_desc->iad_rpt; scalar_array_desc::sad_repeat* tail2 = scalar_desc->sad_rpt; @@ -1055,7 +1046,8 @@ static SLONG get_scalar_array(const Parameter* arg, tail2->sad_lower = tail1->iad_lower; } - return static_cast(sizeof(scalar_array_desc) + (dimensions - 1u) * sizeof(scalar_array_desc::sad_repeat)); + return static_cast(sizeof(scalar_array_desc) + + (dimensions - 1u) * sizeof(scalar_array_desc::sad_repeat)); } diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index c72c395b61a..0f52b56b2eb 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -209,7 +209,7 @@ bool IDX_check_master_types(thread_db* tdbb, index_desc& idx, jrd_rel* partner_r // get the description of the partner index const bool ok = BTR_description(tdbb, partner_relation, root, &partner_idx, idx.idx_primary_index); CCH_RELEASE(tdbb, &window); - + if (!ok) BUGCHECK(175); // msg 175 partner index description not found @@ -345,7 +345,7 @@ void IDX_create_index(thread_db* tdbb, // Checkout a garbage collect record block for fetching data. - AutoGCRecord gc_record(VIO_gc_record(tdbb, relation)); + AutoTempRecord gc_record(VIO_gc_record(tdbb, relation)); // Unless this is the only attachment or a database restore, worry about // preserving the page working sets of other attachments. @@ -406,7 +406,8 @@ void IDX_create_index(thread_db* tdbb, { Record* record = stack.pop(); - result = BTR_key(tdbb, relation, record, idx, &key, false); + result = BTR_key(tdbb, relation, record, idx, &key, + ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)); if (result == idx_e_ok) { @@ -749,7 +750,9 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going, { Record* const rec1 = stack1.object(); - idx_e result = BTR_key(tdbb, rpb->rpb_relation, rec1, &idx, &key1, false); + idx_e result = BTR_key(tdbb, rpb->rpb_relation, rec1, &idx, &key1, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)); + if (result != idx_e_ok) { if (result == idx_e_conversion) @@ -766,7 +769,9 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going, { Record* const rec2 = stack2.object(); - result = BTR_key(tdbb, rpb->rpb_relation, rec2, &idx, &key2, false); + result = BTR_key(tdbb, rpb->rpb_relation, rec2, &idx, &key2, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)); + if (result != idx_e_ok) { if (result == idx_e_conversion) @@ -789,7 +794,9 @@ void IDX_garbage_collect(thread_db* tdbb, record_param* rpb, RecordStack& going, { Record* const rec3 = stack3.object(); - result = BTR_key(tdbb, rpb->rpb_relation, rec3, &idx, &key2, false); + result = BTR_key(tdbb, rpb->rpb_relation, rec3, &idx, &key2, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)); + if (result != idx_e_ok) { if (result == idx_e_conversion) @@ -861,14 +868,16 @@ void IDX_modify(thread_db* tdbb, idx_e error_code; if ((error_code = BTR_key(tdbb, new_rpb->rpb_relation, - new_rpb->rpb_record, &idx, &key1, false))) + new_rpb->rpb_record, &idx, &key1, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)))) { CCH_RELEASE(tdbb, &window); context.raise(tdbb, error_code, new_rpb->rpb_record); } if ((error_code = BTR_key(tdbb, org_rpb->rpb_relation, - org_rpb->rpb_record, &idx, &key2, false))) + org_rpb->rpb_record, &idx, &key2, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)))) { CCH_RELEASE(tdbb, &window); context.raise(tdbb, error_code, org_rpb->rpb_record); @@ -935,14 +944,16 @@ void IDX_modify_check_constraints(thread_db* tdbb, idx_e error_code; if ((error_code = BTR_key(tdbb, new_rpb->rpb_relation, - new_rpb->rpb_record, &idx, &key1, false))) + new_rpb->rpb_record, &idx, &key1, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)))) { CCH_RELEASE(tdbb, &window); context.raise(tdbb, error_code, new_rpb->rpb_record); } if ((error_code = BTR_key(tdbb, org_rpb->rpb_relation, - org_rpb->rpb_record, &idx, &key2, false))) + org_rpb->rpb_record, &idx, &key2, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)))) { CCH_RELEASE(tdbb, &window); context.raise(tdbb, error_code, org_rpb->rpb_record); @@ -1081,7 +1092,8 @@ void IDX_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) IndexErrorContext context(rpb->rpb_relation, &idx); idx_e error_code; - if ( (error_code = BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, &idx, &key, false)) ) + if ((error_code = BTR_key(tdbb, rpb->rpb_relation, rpb->rpb_record, &idx, &key, + ((idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)))) { CCH_RELEASE(tdbb, &window); context.raise(tdbb, error_code, rpb->rpb_record); @@ -1106,7 +1118,7 @@ static bool cmpRecordKeys(thread_db* tdbb, ************************************** * * Functional description - * Compare indexed fields in two records. Records could belong to different + * Compare indexed fields in two records. Records could belong to different * relations but set of indexed fields to compare should be equal. * **************************************/ @@ -1231,11 +1243,11 @@ static idx_e check_duplicates(thread_db* tdbb, if (cmpRecordKeys(tdbb, rpb.rpb_record, relation_1, insertion_idx, record, relation_2, record_idx)) { - // When check foreign keys in snapshot or read consistency transaction, - // ensure that master record is visible in transaction context and still + // When check foreign keys in snapshot or read consistency transaction, + // ensure that master record is visible in transaction context and still // satisfy foreign key constraint. - if (is_fk && + if (is_fk && (!(transaction->tra_flags & TRA_read_committed) || (transaction->tra_flags & TRA_read_consistency))) { @@ -1430,7 +1442,12 @@ static idx_e check_partner_index(thread_db* tdbb, // tmpIndex.idx_flags |= idx_unique; tmpIndex.idx_flags = (tmpIndex.idx_flags & ~idx_unique) | (partner_idx.idx_flags & idx_unique); temporary_key key; - result = BTR_key(tdbb, relation, record, &tmpIndex, &key, starting, segment); + + const USHORT keyType = starting ? + INTL_KEY_PARTIAL : + (tmpIndex.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT; + + result = BTR_key(tdbb, relation, record, &tmpIndex, &key, keyType, segment); CCH_RELEASE(tdbb, &window); // now check for current duplicates diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index e056c283824..5d008be1037 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -192,7 +192,7 @@ void INF_blob_info(const blb* blob, else start_info = 0; - while (items < end_items && *items != isc_info_end) + while (items < end_items && *items != isc_info_end && info < end) { UCHAR item = *items++; @@ -229,7 +229,8 @@ void INF_blob_info(const blb* blob, return; } - *info++ = isc_info_end; + if (info < end) + *info++ = isc_info_end; if (start_info && (end - info >= 7)) { @@ -302,7 +303,7 @@ void INF_database_info(thread_db* tdbb, const Jrd::Attachment* const att = tdbb->getAttachment(); - while (items < end_items && *items != isc_info_end) + while (items < end_items && *items != isc_info_end && info < end) { UCHAR* p = buffer; UCHAR item = *items++; @@ -550,10 +551,8 @@ void INF_database_info(thread_db* tdbb, case fb_info_creation_timestamp_tz: length = INF_convert(dbb->dbb_creation_date.utc_timestamp.timestamp_date, p); - p += length; - length += INF_convert(dbb->dbb_creation_date.utc_timestamp.timestamp_time, p); - p += length; - length += INF_convert(dbb->dbb_creation_date.time_zone, p); + length += INF_convert(dbb->dbb_creation_date.utc_timestamp.timestamp_time, p + length); + length += INF_convert(dbb->dbb_creation_date.time_zone, p + length); break; case isc_info_no_reserve: @@ -620,11 +619,10 @@ void INF_database_info(thread_db* tdbb, case isc_info_user_names: // Assumes user names will be smaller than sizeof(buffer) - 1. - if (!(tdbb->getAttachment()->locksmith(tdbb, USER_MANAGEMENT))) + if (!tdbb->getAttachment()->locksmith(tdbb, USER_MANAGEMENT)) { - const UserId* user = tdbb->getAttachment()->att_user; - const char* userName = (user && user->getUserName().hasData()) ? - user->getUserName().c_str() : ""; + const auto attachment = tdbb->getAttachment(); + const char* userName = attachment->getUserName("").c_str(); const ULONG len = MIN(strlen(userName), MAX_UCHAR); *p++ = static_cast(len); memcpy(p, userName, len); @@ -636,16 +634,25 @@ void INF_database_info(thread_db* tdbb, } { + StrArray names; + SyncLockGuard sync(&dbb->dbb_sync, SYNC_SHARED, "INF_database_info"); for (const Jrd::Attachment* att = dbb->dbb_attachments; att; att = att->att_next) { - const UserId* user = att->att_user; + const UserId* const user = att->att_user; if (user) { const char* userName = user->getUserName().hasData() ? user->getUserName().c_str() : "(Firebird Worker Thread)"; + + FB_SIZE_T pos; + if (names.find(userName, pos)) + continue; + + names.insert(pos, userName); + p = buffer; const ULONG len = MIN(strlen(userName), MAX_UCHAR); *p++ = static_cast(len); @@ -770,28 +777,49 @@ void INF_database_info(thread_db* tdbb, break; case fb_info_page_contents: - if (tdbb->getAttachment()->locksmith(tdbb, READ_RAW_PAGES)) { - length = gds__vax_integer(items, 2); - items += 2; - const ULONG page_num = gds__vax_integer(items, length); - items += length; + bool validArgs = false; + ULONG pageNum; - win window(PageNumber(DB_PAGE_SPACE, page_num)); + if (end_items - items >= 2) + { + length = gds__vax_integer(items, 2); + items += 2; - Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_read, pag_undefined); - info = INF_put_item(item, dbb->dbb_page_size, page, info, end); - CCH_RELEASE_TAIL(tdbb, &window); + if (end_items - items >= length) + { + pageNum = gds__vax_integer(items, length); + items += length; + validArgs = true; + } + } - if (!info) - return; + if (!validArgs) + { + buffer[0] = item; + item = isc_info_error; + length = 1 + INF_convert(isc_inf_invalid_args, buffer + 1); + break; + } - continue; - } + if (tdbb->getAttachment()->locksmith(tdbb, READ_RAW_PAGES)) + { + win window(PageNumber(DB_PAGE_SPACE, pageNum)); - buffer[0] = item; - item = isc_info_error; - length = 1 + INF_convert(isc_adm_task_denied, buffer + 1); + Ods::pag* page = CCH_FETCH(tdbb, &window, LCK_read, pag_undefined); + info = INF_put_item(item, dbb->dbb_page_size, page, info, end); + CCH_RELEASE_TAIL(tdbb, &window); + + if (!info) + return; + + continue; + } + + buffer[0] = item; + item = isc_info_error; + length = 1 + INF_convert(isc_adm_task_denied, buffer + 1); + } break; case fb_info_pages_used: @@ -804,7 +832,7 @@ void INF_database_info(thread_db* tdbb, case fb_info_crypt_state: length = INF_convert(dbb->dbb_crypto_manager ? - dbb->dbb_crypto_manager->getCurrentState() : 0, buffer); + dbb->dbb_crypto_manager->getCurrentState(tdbb) : 0, buffer); break; case fb_info_crypt_key: @@ -869,6 +897,10 @@ void INF_database_info(thread_db* tdbb, length = INF_convert(att->getActualIdleTimeout(), buffer); break; + case fb_info_protocol_version: + length = INF_convert(0, buffer); + break; + case fb_info_features: { static const unsigned char features[] = ENGINE_FEATURES; @@ -909,6 +941,22 @@ void INF_database_info(thread_db* tdbb, length = p - buffer; break; + case fb_info_username: + { + const MetaString& user = att->getUserName(); + if (!(info = INF_put_item(item, user.length(), user.c_str(), info, end))) + return; + } + continue; + + case fb_info_sqlrole: + { + const MetaString& role = att->getSqlRole(); + if (!(info = INF_put_item(item, role.length(), role.c_str(), info, end))) + return; + } + continue; + default: buffer[0] = item; item = isc_info_error; @@ -920,7 +968,8 @@ void INF_database_info(thread_db* tdbb, return; } - *info++ = isc_info_end; + if (info < end) + *info++ = isc_info_end; } @@ -1000,7 +1049,7 @@ ULONG INF_request_info(const jrd_req* request, HalfStaticArray buffer; UCHAR* buffer_ptr = buffer.getBuffer(BUFFER_TINY); - while (items < end_items && *items != isc_info_end) + while (items < end_items && *items != isc_info_end && info < end) { UCHAR item = *items++; @@ -1108,7 +1157,8 @@ ULONG INF_request_info(const jrd_req* request, return 0; } - *info++ = isc_info_end; + if (info < end) + *info++ = isc_info_end; if (infoLengthPresent && (end - info >= 7)) { @@ -1158,7 +1208,7 @@ void INF_transaction_info(const jrd_tra* transaction, else start_info = 0; - while (items < end_items && *items != isc_info_end) + while (items < end_items && *items != isc_info_end && info < end) { UCHAR item = *items++; @@ -1246,7 +1296,8 @@ void INF_transaction_info(const jrd_tra* transaction, return; } - *info++ = isc_info_end; + if (info < end) + *info++ = isc_info_end; if (start_info && (end - info >= 7)) { diff --git a/src/jrd/intl.cpp b/src/jrd/intl.cpp index c9df5cd4027..7574713cf50 100644 --- a/src/jrd/intl.cpp +++ b/src/jrd/intl.cpp @@ -780,7 +780,7 @@ CsConvert INTL_convert_lookup(thread_db* tdbb, CHARSET_ID to_cs, CHARSET_ID from } -int INTL_convert_string(dsc* to, const dsc* from, Firebird::Callbacks* cb) +void INTL_convert_string(dsc* to, const dsc* from, Firebird::Callbacks* cb) { /************************************** * @@ -791,19 +791,9 @@ int INTL_convert_string(dsc* to, const dsc* from, Firebird::Callbacks* cb) * Functional description * Convert a string from one type to another * - * RETURNS: - * 0 if no error in conversion - * non-zero otherwise. - * CVC: Unfortunately, this function puts the source in the 2nd param, - * as opposed to the CVT routines, so const helps mitigating coding mistakes. - * **************************************/ - // Note: This function is called from outside the engine as - // well as inside - we likely can't get rid of JRD_get_thread_data here - thread_db* tdbb = JRD_get_thread_data(); - if (tdbb == NULL) // are we in the Engine? - return (1); // no, then can't access intl gah + const auto tdbb = JRD_get_thread_data(); fb_assert(to != NULL); fb_assert(from != NULL); @@ -813,7 +803,6 @@ int INTL_convert_string(dsc* to, const dsc* from, Firebird::Callbacks* cb) const CHARSET_ID to_cs = INTL_charset(tdbb, INTL_TTYPE(to)); UCHAR* p = to->dsc_address; - const UCHAR* start = p; // Must convert dtype(cstring,text,vary) and ttype(ascii,binary,..intl..) @@ -823,134 +812,94 @@ int INTL_convert_string(dsc* to, const dsc* from, Firebird::Callbacks* cb) tdbb->getAttachment()->att_dec_status, cb->err); const ULONG to_size = TEXT_LEN(to); - ULONG from_fill, to_fill; const UCHAR* q = from_ptr; CharSet* const toCharSet = INTL_charset_lookup(tdbb, to_cs); - ULONG toLength; - switch (to->dsc_dtype) - { - case dtype_text: - if (from_cs != to_cs && to_cs != CS_BINARY && to_cs != CS_NONE && from_cs != CS_NONE) - { - const ULONG to_len = INTL_convert_bytes(tdbb, to_cs, to->dsc_address, to_size, - from_cs, from_ptr, from_len, cb->err); - toLength = to_len; - to_fill = to_size - to_len; - from_fill = 0; // Convert_bytes handles source truncation - p += to_len; - } - else - { - // binary string can always be converted TO by byte-copy - - ULONG to_len = MIN(from_len, to_size); - if (!toCharSet->wellFormed(to_len, q)) - cb->err(Arg::Gds(isc_malformed_string)); - toLength = to_len; - from_fill = from_len - to_len; - to_fill = to_size - to_len; - if (to_len) - { - do - { - *p++ = *q++; - } while (--to_len); - } - } + UCHAR* const to_ptr = to->dsc_dtype == dtype_varying ? + reinterpret_cast(((vary*) p)->vary_string) : + p; - if (to_fill > 0) - pad_spaces(tdbb, to_cs, p, to_fill); - break; + ULONG to_fill; - case dtype_cstring: - if (from_cs != to_cs && to_cs != CS_BINARY && to_cs != CS_NONE && from_cs != CS_NONE) + if (from_cs != to_cs && to_cs != CS_BINARY && to_cs != CS_NONE && from_cs != CS_NONE) + { + ULONG to_len; + + try { - const ULONG to_len = INTL_convert_bytes(tdbb, to_cs, to->dsc_address, to_size, - from_cs, from_ptr, from_len, cb->err); - toLength = to_len; - to->dsc_address[to_len] = 0; - from_fill = 0; // Convert_bytes handles source truncation + to_len = INTL_convert_bytes(tdbb, to_cs, to_ptr, to_size, from_cs, from_ptr, from_len, cb->err); } - else + catch (const status_exception& e) { - // binary string can always be converted TO by byte-copy - - ULONG to_len = MIN(from_len, to_size); - if (!toCharSet->wellFormed(to_len, q)) - cb->err(Arg::Gds(isc_malformed_string)); - toLength = to_len; - from_fill = from_len - to_len; - if (to_len) + const auto status = e.value(); + + if (status[0] == isc_arg_gds && + status[1] == isc_arith_except && + status[2] == isc_arg_gds && + status[3] == isc_string_truncation && + status[4] == isc_arg_gds && + status[5] == isc_trunc_limits) { - do - { - *p++ = *q++; - } while (--to_len); + const auto fromCharSet = INTL_charset_lookup(tdbb, from_cs); + + // This should throw another exception with better information. + cb->validateLength(fromCharSet, from_cs, from_len, from_ptr, + to_size / toCharSet->maxBytesPerChar() * fromCharSet->maxBytesPerChar()); } - *p = 0; - } - break; - case dtype_varying: - if (from_cs != to_cs && to_cs != CS_BINARY && to_cs != CS_NONE && from_cs != CS_NONE) - { - UCHAR* vstr = reinterpret_cast(((vary*) to->dsc_address)->vary_string); - start = vstr; - ULONG to_len = INTL_convert_bytes(tdbb, to_cs, vstr, - to_size, from_cs, from_ptr, from_len, cb->err); + throw; + } - to_len = cb->validateLength(toCharSet, to_cs, to_len, vstr, to_size); + to_len = cb->validateLength(toCharSet, to_cs, to_len, to_ptr, to_size); - toLength = to_len; - ((vary*) to->dsc_address)->vary_length = to_len; - from_fill = 0; // Convert_bytes handles source truncation - } - else + switch (to->dsc_dtype) { - // binary string can always be converted TO by byte-copy - ULONG to_len = MIN(from_len, to_size); - if (!toCharSet->wellFormed(to_len, q)) - cb->err(Arg::Gds(isc_malformed_string)); + case dtype_text: + to_fill = to_size - to_len; + p += to_len; + break; - to_len = cb->validateLength(toCharSet, to_cs, to_len, q, to_size); + case dtype_cstring: + p[to_len] = 0; + break; - toLength = to_len; - from_fill = from_len - to_len; - ((vary*) p)->vary_length = to_len; - start = p = reinterpret_cast(((vary*) p)->vary_string); - if (to_len) - { - do - { - *p++ = *q++; - } while (--to_len); - } + case dtype_varying: + ((vary*) p)->vary_length = to_len; + break; } - break; } + else + { + // binary string can always be converted TO by byte-copy - const ULONG src_len = toCharSet->length(toLength, start, false); - const ULONG dest_len = (ULONG) to_size / toCharSet->maxBytesPerChar(); + if (!toCharSet->wellFormed(from_len, q)) + cb->err(Arg::Gds(isc_malformed_string)); - if (toCharSet->isMultiByte() && src_len > dest_len) - { - cb->err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << - Arg::Gds(isc_trunc_limits) << Arg::Num(dest_len) << Arg::Num(src_len)); - } + ULONG to_len = cb->validateLength(toCharSet, to_cs, from_len, q, to_size); - if (from_fill) - { - // Make sure remaining characters on From string are spaces - if (!allSpaces(INTL_charset_lookup(tdbb, from_cs), q, from_fill, 0)) + to_fill = to_size - to_len; + + if (to->dsc_dtype == dtype_varying) { - cb->err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_string_truncation) << - Arg::Gds(isc_trunc_limits) << Arg::Num(dest_len) << Arg::Num(src_len)); + ((vary*) p)->vary_length = to_len; + p = to_ptr; } + + if (to_len) + { + do + { + *p++ = *q++; + } while (--to_len); + } + + if (to->dsc_dtype == dtype_cstring) + *p = 0; } - return 0; + if (to->dsc_dtype == dtype_text && to_fill > 0) + pad_spaces(tdbb, to_cs, p, to_fill); } @@ -1272,6 +1221,7 @@ USHORT INTL_string_to_key(thread_db* tdbb, case ttype_binary: case ttype_ascii: case ttype_none: + fb_assert(key_type != INTL_KEY_MULTI_STARTING); while (len-- && destLen-- > 0) *dest++ = *src++; // strip off ending pad characters @@ -1286,6 +1236,7 @@ USHORT INTL_string_to_key(thread_db* tdbb, break; default: TextType* obj = INTL_texttype_lookup(tdbb, ttype); + fb_assert(key_type != INTL_KEY_MULTI_STARTING || (obj->getFlags() & TEXTTYPE_MULTI_STARTING_KEY)); outlen = obj->string_to_key(len, src, pByte->dsc_length, dest, key_type); break; } diff --git a/src/jrd/intl_classes.h b/src/jrd/intl_classes.h index e7279ab0d4b..714f40877ea 100644 --- a/src/jrd/intl_classes.h +++ b/src/jrd/intl_classes.h @@ -87,7 +87,10 @@ class UpcaseConverter : public PrevConverter UpcaseConverter(MemoryPool& pool, TextType* obj, const UCHAR*& str, SLONG& len) : PrevConverter(pool, obj, str, len) { - obj->str_to_upper(len, str, len, tempBuffer.getBuffer(len, false)); + const auto charSet = obj->getCharSet(); + const auto bufferSize = len / charSet->minBytesPerChar() * charSet->maxBytesPerChar(); + + len = obj->str_to_upper(len, str, bufferSize, tempBuffer.getBuffer(bufferSize, false)); str = tempBuffer.begin(); } diff --git a/src/jrd/intl_proto.h b/src/jrd/intl_proto.h index 58c3b479f89..ca1414edfa4 100644 --- a/src/jrd/intl_proto.h +++ b/src/jrd/intl_proto.h @@ -42,7 +42,7 @@ int INTL_compare(Jrd::thread_db*, const dsc*, const dsc*, ErrorFunction); ULONG INTL_convert_bytes(Jrd::thread_db*, CHARSET_ID, UCHAR*, const ULONG, CHARSET_ID, const BYTE*, const ULONG, ErrorFunction); Jrd::CsConvert INTL_convert_lookup(Jrd::thread_db*, CHARSET_ID, CHARSET_ID); -int INTL_convert_string(dsc*, const dsc*, Firebird::Callbacks* cb); +void INTL_convert_string(dsc*, const dsc*, Firebird::Callbacks* cb); bool INTL_data(const dsc*); bool INTL_data_or_binary(const dsc*); bool INTL_defined_type(Jrd::thread_db*, USHORT); diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index d500d0fb379..13eda17af2f 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -112,6 +112,7 @@ #include "../yvalve/why_proto.h" #include "../jrd/flags.h" #include "../jrd/Mapping.h" +#include "../jrd/ThreadCollect.h" #include "../jrd/Database.h" @@ -128,6 +129,7 @@ #include "../common/classes/ClumpletWriter.h" #include "../common/classes/RefMutex.h" #include "../common/classes/ParsedList.h" +#include "../common/classes/semaphore.h" #include "../common/utils_proto.h" #include "../jrd/DebugInterface.h" #include "../jrd/CryptoManager.h" @@ -432,7 +434,7 @@ class EngineFactory : public AutoIfaceunloadStarted()) { - Arg::Gds(isc_shutdown).raise(); + Arg::Gds(isc_att_shut_engine).raise(); } IPluginBase* p = FB_NEW JProvider(factoryParameter); @@ -465,7 +467,7 @@ void registerEngine(IPluginManager* iPlugin) } // namespace Jrd -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master) { CachedMasterInterface::set(master); registerEngine(PluginManagerInterfacePtr()); @@ -475,6 +477,16 @@ namespace { using Jrd::Attachment; + // Required to sync attachment shutdown threads with provider shutdown + GlobalPtr shutThreadCollect; + + struct AttShutParams + { + Semaphore thdStartedSem, startCallCompleteSem; + Thread::Handle thrHandle; + AttachmentsRefHolder* attachments; + }; + // Flag engineShutdown guarantees that no new attachment is created after setting it // and helps avoid more than 1 shutdown threads running simultaneously. bool engineShutdown = false; @@ -733,7 +745,7 @@ namespace try { if (!nolock) - sAtt->getMutex(async)->enter(from); + sAtt->getSync(async)->enter(from); Jrd::Attachment* attachment = sAtt->getHandle(); // Must be done after entering mutex @@ -764,7 +776,7 @@ namespace catch (const Firebird::Exception&) { if (!nolock) - sAtt->getMutex(async)->leave(); + sAtt->getSync(async)->leave(); throw; } } @@ -788,7 +800,7 @@ namespace } if (!nolock) - sAtt->getMutex(async)->leave(); + sAtt->getSync(async)->leave(); if (blocking) sAtt->getBlockingMutex()->leave(); @@ -850,10 +862,20 @@ namespace class DefaultCallback : public AutoIface > { public: - unsigned int callback(unsigned int, const void*, unsigned int, void*) + unsigned int callback(unsigned int, const void*, unsigned int, void*) override { return 0; } + + int getHashLength(Firebird::CheckStatusWrapper* status) override + { + return 0; + } + + void getHashData(Firebird::CheckStatusWrapper* status, void* h) override + { + fb_assert(false); + } }; DefaultCallback defCallback; @@ -959,7 +981,15 @@ void Trigger::release(thread_db* tdbb) extTrigger = NULL; } - if (sysTrigger || !statement || statement->isActive() || releaseInProgress) + // dimitr: We should never release triggers created by MET_parse_sys_trigger(). + // System triggers do have BLR, but it's not stored inside the trigger object. + // However, triggers backing RI constraints are also marked as system, + // but they are loaded in a regular way and their BLR is present here. + // This is why we cannot simply check for sysTrigger, sigh. + + const bool sysTableTrigger = (blr.isEmpty() && engine.isEmpty()); + + if (sysTableTrigger || !statement || statement->isActive() || releaseInProgress) return; AutoSetRestore autoProgressFlag(&releaseInProgress, true); @@ -1077,6 +1107,7 @@ namespace Jrd ULONG dpb_remote_flags; ReplicaMode dpb_replica_mode; bool dpb_set_db_replica; + bool dpb_clear_map; // here begin compound objects // for constructor to work properly dpb_user_name @@ -1112,7 +1143,7 @@ namespace Jrd memset(this, 0, reinterpret_cast(&this->dpb_user_name) - reinterpret_cast(this)); } - void get(const UCHAR*, USHORT, bool&); + void get(const UCHAR*, FB_SIZE_T, bool&); void setBuffers(RefPtr config) { @@ -1310,21 +1341,26 @@ static void check_single_maintenance(thread_db* tdbb); namespace { enum VdnResult {VDN_FAIL, VDN_OK/*, VDN_SECURITY*/}; + + const unsigned UNWIND_INTERNAL = 1; + const unsigned UNWIND_CREATE = 2; + const unsigned UNWIND_NEW = 4; } static VdnResult verifyDatabaseName(const PathName&, FbStatusVector*, bool); -static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, bool internalFlag); +static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, unsigned flags, + const char* filename, const DatabaseOptions& options, ICryptKeyCallback* callback); static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&, RefPtr, bool, const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*); static JAttachment* create_attachment(const PathName&, Database*, JProvider* provider, const DatabaseOptions&, bool newDb); static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*); -static void release_attachment(thread_db*, Attachment*); +static void release_attachment(thread_db*, Attachment*, XThreadEnsureUnlock* = nullptr); static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle, Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb); static void rollback(thread_db*, jrd_tra*, const bool); static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsigned flags = 0); static void getUserInfo(UserId&, const DatabaseOptions&, const char*, - const RefPtr*, bool, Mapping& mapping); + const RefPtr*, bool, Mapping& mapping, bool); static void waitForShutdown(Semaphore&); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); @@ -1340,7 +1376,7 @@ TraceFailedConnection::TraceFailedConnection(const char* filename, const Databas { Mapping mapping(Mapping::MAP_ERROR_HANDLER, NULL); mapping.setAuthBlock(m_options->dpb_auth_block); - getUserInfo(m_id, *m_options, m_filename, NULL, false, mapping); + getUserInfo(m_id, *m_options, m_filename, NULL, false, mapping, false); } @@ -1532,10 +1568,14 @@ static void trace_warning(thread_db* tdbb, FbStatusVector* userStatus, const cha } -static void trace_failed_attach(TraceManager* traceManager, const char* filename, - const DatabaseOptions& options, bool create, FbStatusVector* status) +// Report to Trace API that attachment has not been created +static void trace_failed_attach(const char* filename, const DatabaseOptions& options, + unsigned flags, FbStatusVector* status, ICryptKeyCallback* callback) { - // Report to Trace API that attachment has not been created + // Avoid uncontrolled recursion + if (options.dpb_map_attach) + return; + const char* origFilename = filename; if (options.dpb_org_filename.hasData()) origFilename = options.dpb_org_filename.c_str(); @@ -1546,26 +1586,16 @@ static void trace_failed_attach(TraceManager* traceManager, const char* filename ISC_STATUS s = status->getErrors()[1]; const ntrace_result_t result = (s == isc_login || s == isc_no_priv) ? ITracePlugin::RESULT_UNAUTHORIZED : ITracePlugin::RESULT_FAILED; - const char* func = create ? "JProvider::createDatabase" : "JProvider::attachDatabase"; + const char* func = flags & UNWIND_CREATE ? "JProvider::createDatabase" : "JProvider::attachDatabase"; - if (!traceManager) - { - TraceManager tempMgr(origFilename); - - if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH)) - tempMgr.event_attach(&conn, create, result); + // Perform actual trace + TraceManager tempMgr(origFilename, callback, flags & UNWIND_NEW); - if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR)) - tempMgr.event_error(&conn, &traceStatus, func); - } - else - { - if (traceManager->needs(ITraceFactory::TRACE_EVENT_ATTACH)) - traceManager->event_attach(&conn, create, result); + if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH)) + tempMgr.event_attach(&conn, flags & UNWIND_CREATE, result); - if (traceManager->needs(ITraceFactory::TRACE_EVENT_ERROR)) - traceManager->event_error(&conn, &traceStatus, func); - } + if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR)) + tempMgr.event_error(&conn, &traceStatus, func); } @@ -1624,6 +1654,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch PathName org_filename, expanded_name; bool is_alias = false; MutexEnsureUnlock guardDbInit(dbInitMutex, FB_FUNCTION); + LateRefGuard lateBlocking(FB_FUNCTION); Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); try @@ -1688,7 +1719,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch catch (const Exception& ex) { ex.stuffException(user_status); - trace_failed_attach(NULL, filename, options, false, user_status); + trace_failed_attach(filename, options, 0, user_status, cryptCallback); throw; } @@ -1696,13 +1727,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias); if (!is_alias && vdn == VDN_FAIL) { - trace_failed_attach(NULL, filename, options, false, tdbb->tdbb_status_vector); + trace_failed_attach(filename, options, 0, tdbb->tdbb_status_vector, cryptCallback); status_exception::raise(tdbb->tdbb_status_vector); } Database* dbb = NULL; Jrd::Attachment* attachment = NULL; - bool attachTraced = false; // Initialize special error handling try @@ -1738,6 +1768,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch } EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); + lateBlocking.lock(jAtt->getStable()->getBlockingMutex(), jAtt->getStable()); attachment->att_crypt_callback = getDefCryptCallback(cryptCallback); attachment->att_client_charset = attachment->att_charset = options.dpb_interp; @@ -1830,8 +1861,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Initialize TIP cache. We do this late to give SDW a chance to // work while we read states for all interesting transactions - dbb->dbb_tip_cache = FB_NEW_POOL(*dbb->dbb_permanent) TipCache(dbb); - dbb->dbb_tip_cache->initializeTpc(tdbb); + dbb->startTipCache(tdbb); // linger dbb->dbb_linger_seconds = MET_get_linger(tdbb); @@ -1926,6 +1956,12 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch break; } + // Clear old mapping cache data on request. + // Unfortunately have to do it w/o access rights check - to check access rights engine + // needs correct mapping which sometimes can't be guaranteed before cleaning cache. + if (options.dpb_clear_map) + Mapping::clearCache(dbb->dbb_filename.c_str(), Mapping::ALL_CACHE); + // Check for correct credentials supplied UserId userId; @@ -1937,7 +1973,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch try { mapping.setDb(filename, expanded_name.c_str(), jAtt); - getUserInfo(userId, options, filename, &config, false, mapping); + getUserInfo(userId, options, filename, &config, false, mapping, options.dpb_reset_icu); } catch(const Exception&) { @@ -1949,7 +1985,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch } userId.makeRoleName(options.dpb_sql_dialect); - UserId::sclInit(tdbb, false, userId); + userId.sclInit(tdbb, false); Monitoring::publishAttachment(tdbb); @@ -2021,11 +2057,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch if (!allow_access) { // Note we throw exception here when entering full-shutdown mode - Arg::Gds v(isc_shutdown); - v << Arg::Str(org_filename); - if (attachment->att_user && attachment->att_user->testFlag(USR_mapdown)) - v << Arg::Gds(isc_map_down); - ERR_post(v); + ERR_post(Arg::Gds(isc_shutdown) << org_filename); } } @@ -2062,6 +2094,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch // Can't allow garbage collection during database validation. + AutoSetRestoreFlag noCleanup(&attachment->att_flags, ATT_no_cleanup, true); VIO_fini(tdbb); if (!VAL_validate(tdbb, options.dpb_verify)) @@ -2072,6 +2105,10 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch { validateAccess(tdbb, attachment, USE_GFIX_UTILITY); DFW_reset_icu(tdbb); + + // force system privileges recheck for sysdba + fb_assert(attachment->att_user); // set by UserId::sclInit() + attachment->att_user->setFlag(USR_newrole); } if (options.dpb_journal.hasData()) @@ -2173,7 +2210,6 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch TraceConnectionImpl conn(attachment); attachment->att_trace_manager->event_attach(&conn, false, ITracePlugin::RESULT_SUCCESS); } - attachTraced = true; // Recover database after crash during backup difference file merge dbb->dbb_backup_manager->endBackup(tdbb, true); // true = do recovery @@ -2236,27 +2272,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch catch (const Exception& ex) { ex.stuffException(user_status); - if (attachTraced) - { - TraceManager* traceManager = attachment->att_trace_manager; - TraceConnectionImpl conn(attachment); - TraceStatusVectorImpl traceStatus(user_status, TraceStatusVectorImpl::TS_ERRORS); - - if (traceManager->needs(ITraceFactory::TRACE_EVENT_ERROR)) - traceManager->event_error(&conn, &traceStatus, "JProvider::attachDatabase"); - - if (traceManager->needs(ITraceFactory::TRACE_EVENT_DETACH)) - traceManager->event_detach(&conn, false); - } - else - { - trace_failed_attach(attachment && attachment->att_trace_manager && - attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL, - filename, options, false, user_status); - } - mapping.clearMainHandle(); - unwindAttach(tdbb, ex, user_status, existingId); + unwindAttach(tdbb, ex, user_status, existingId ? UNWIND_INTERNAL : 0, filename, options, cryptCallback); } } catch (const Exception& ex) @@ -2307,7 +2324,7 @@ void JBlob::getInfo(CheckStatusWrapper* user_status, } -void JBlob::cancel(CheckStatusWrapper* user_status) +void JBlob::deprecatedCancel(CheckStatusWrapper* user_status) { /************************************** * @@ -2323,6 +2340,14 @@ void JBlob::cancel(CheckStatusWrapper* user_status) } +void JBlob::cancel(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); + if (user_status->isEmpty()) + release(); +} + + void JBlob::freeEngineData(CheckStatusWrapper* user_status) { /************************************** @@ -2361,7 +2386,7 @@ void JBlob::freeEngineData(CheckStatusWrapper* user_status) } -void JEvents::cancel(CheckStatusWrapper* user_status) +void JEvents::deprecatedCancel(CheckStatusWrapper* user_status) { /************************************** * @@ -2377,6 +2402,14 @@ void JEvents::cancel(CheckStatusWrapper* user_status) } +void JEvents::cancel(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); + if (user_status->isEmpty()) + release(); +} + + void JEvents::freeEngineData(CheckStatusWrapper* user_status) { /************************************** @@ -2458,6 +2491,20 @@ void JAttachment::cancelOperation(CheckStatusWrapper* user_status, int option) void JBlob::close(CheckStatusWrapper* user_status) +{ + internalClose(user_status); + if (user_status->isEmpty()) + release(); +} + + +void JBlob::deprecatedClose(CheckStatusWrapper* user_status) +{ + internalClose(user_status); +} + + +void JBlob::internalClose(CheckStatusWrapper* user_status) { /************************************** * @@ -2497,6 +2544,20 @@ void JBlob::close(CheckStatusWrapper* user_status) void JTransaction::commit(CheckStatusWrapper* user_status) +{ + internalCommit(user_status); + if (user_status->isEmpty()) + release(); +} + + +void JTransaction::deprecatedCommit(CheckStatusWrapper* user_status) +{ + internalCommit(user_status); +} + + +void JTransaction::internalCommit(CheckStatusWrapper* user_status) { /************************************** * @@ -2739,6 +2800,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch bool is_alias = false; Firebird::RefPtr config; Mapping mapping(Mapping::MAP_THROW_NOT_FOUND, cryptCallback); + LateRefGuard lateBlocking(FB_FUNCTION); try { @@ -2784,7 +2846,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch // Check for correct credentials supplied mapping.setSecurityDbAlias(config->getSecurityDatabase(), nullptr); - getUserInfo(userId, options, filename, &config, true, mapping); + getUserInfo(userId, options, filename, &config, true, mapping, false); #ifdef WIN_NT guardDbInit.enter(); // Required to correctly expand name of just created database @@ -2806,7 +2868,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch catch (const Exception& ex) { ex.stuffException(user_status); - trace_failed_attach(NULL, filename, options, true, user_status); + trace_failed_attach(filename, options, UNWIND_CREATE, user_status, cryptCallback); throw; } @@ -2814,7 +2876,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias); if (!is_alias && vdn == VDN_FAIL) { - trace_failed_attach(NULL, filename, options, true, tdbb->tdbb_status_vector); + trace_failed_attach(filename, options, UNWIND_CREATE, tdbb->tdbb_status_vector, cryptCallback); status_exception::raise(tdbb->tdbb_status_vector); } @@ -2853,6 +2915,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch dbbGuard.lock(SYNC_EXCLUSIVE); EngineContextHolder tdbb(user_status, jAtt, FB_FUNCTION, AttachmentHolder::ATT_DONT_LOCK); + lateBlocking.lock(jAtt->getStable()->getBlockingMutex(), jAtt->getStable()); attachment->att_crypt_callback = getDefCryptCallback(cryptCallback); @@ -2980,7 +3043,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch INI_init(tdbb); PAG_init(tdbb); - UserId::sclInit(tdbb, true, userId); + userId.sclInit(tdbb, true); if (options.dpb_set_page_buffers) dbb->dbb_page_buffers = options.dpb_page_buffers; @@ -2999,6 +3062,9 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch else dbb->dbb_database_name = dbb->dbb_filename; + // Clear old mapping cache data (if present) + Mapping::clearCache(dbb->dbb_filename.c_str(), Mapping::ALL_CACHE); + // Initialize backup difference subsystem. This must be done before WAL and shadowing // is enabled because nbackup it is a lower level subsystem dbb->dbb_backup_manager = FB_NEW_POOL(*dbb->dbb_permanent) BackupManager(tdbb, @@ -3023,11 +3089,10 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch PAG_set_no_reserve(tdbb, options.dpb_no_reserve); fb_assert(attachment->att_user); // set by UserId::sclInit() - INI_format(attachment->att_user->getUserName().c_str(), - options.dpb_set_db_charset.c_str()); + INI_format(attachment->getUserName().c_str(), options.dpb_set_db_charset.c_str()); // If we have not allocated first TIP page, do it now. - if (!dbb->dbb_t_pages || !dbb->dbb_t_pages->count()) + if (!dbb->getKnownPagesCount(pag_transactions)) TRA_extend_tip(tdbb, 0); // There is no point to move database online at database creation since it is online by default. @@ -3108,13 +3173,14 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch config->notify(); // Initialize TIP cache - dbb->dbb_tip_cache = FB_NEW_POOL(*dbb->dbb_permanent) TipCache(dbb); - dbb->dbb_tip_cache->initializeTpc(tdbb); + dbb->startTipCache(tdbb); // Init complete - we can release dbInitMutex dbb->dbb_flags &= ~(DBB_new | DBB_creating); guardDbInit.leave(); + REPL_attach(tdbb, false); + // Report that we created attachment to Trace API attachment->att_trace_manager->activate(); if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ATTACH)) @@ -3130,12 +3196,8 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch catch (const Exception& ex) { ex.stuffException(user_status); - trace_failed_attach(attachment && attachment->att_trace_manager && - attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL, - filename, options, true, user_status); - mapping.clearMainHandle(); - unwindAttach(tdbb, ex, user_status, false); + unwindAttach(tdbb, ex, user_status, UNWIND_CREATE, filename, options, cryptCallback); } } catch (const Exception& ex) @@ -3201,18 +3263,8 @@ void JAttachment::executeDyn(CheckStatusWrapper* status, ITransaction* /*tra*/, } -void JAttachment::detach(CheckStatusWrapper* user_status) +void JAttachment::internalDetach(CheckStatusWrapper* user_status) { -/************************************** - * - * g d s _ $ d e t a c h - * - ************************************** - * - * Functional description - * Close down a database. - * - **************************************/ if (!att->getHandle()) return; // already detached @@ -3220,11 +3272,26 @@ void JAttachment::detach(CheckStatusWrapper* user_status) } +void JAttachment::deprecatedDetach(CheckStatusWrapper* user_status) +{ + internalDetach(user_status); +} + + +void JAttachment::detach(CheckStatusWrapper* user_status) +{ + internalDetach(user_status); + if (user_status->isEmpty()) + release(); +} + + void JAttachment::freeEngineData(CheckStatusWrapper* user_status, bool forceFree) { /************************************** * * f r e e E n g i n e D a t a + * former g d s _ $ d e t a c h * ************************************** * @@ -3245,15 +3312,15 @@ void JAttachment::freeEngineData(CheckStatusWrapper* user_status, bool forceFree unsigned flags = PURGE_LINGER; - if (engineShutdown || + if (engineShutdown) + flags |= PURGE_FORCE; + + if (forceFree || (dbb->dbb_ast_flags & DBB_shutdown) || (attachment->att_flags & ATT_shutdown)) { - flags |= PURGE_FORCE; - } - - if (forceFree) flags |= PURGE_NOCHECK; + } ISC_STATUS reason = 0; if (!forceFree) @@ -3295,6 +3362,20 @@ void JAttachment::freeEngineData(CheckStatusWrapper* user_status, bool forceFree void JAttachment::dropDatabase(CheckStatusWrapper* user_status) +{ + internalDropDatabase(user_status); + if (user_status->isEmpty()) + release(); +} + + +void JAttachment::deprecatedDropDatabase(CheckStatusWrapper* user_status) +{ + internalDropDatabase(user_status); +} + + +void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status) { /************************************** * @@ -3309,12 +3390,12 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) try { EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_LOCK_ASYNC); - Jrd::Attachment* attachment = getHandle(); + Attachment* attachment = getHandle(); Database* const dbb = tdbb->getDatabase(); try { - MutexEnsureUnlock guard(*(getStable()->getMutex()), FB_FUNCTION); + EnsureUnlock guard(*(getStable()->getSync()), FB_FUNCTION); if (!guard.tryEnter()) { status_exception::raise(Arg::Gds(isc_attachment_in_use)); @@ -3323,6 +3404,7 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) // Prepare to set ODS to 0 WIN window(HEADER_PAGE_NUMBER); Ods::header_page* header = NULL; + XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION); try { @@ -3348,6 +3430,13 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) ERR_post(Arg::Gds(isc_att_shutdown)); } + // try to block special threads before taking exclusive lock on database + if (!threadGuard.tryEnter()) + { + ERR_post(Arg::Gds(isc_no_meta_update) << + Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE")); + } + if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL)) { ERR_post(Arg::Gds(isc_lock_timeout) << @@ -3400,7 +3489,7 @@ void JAttachment::dropDatabase(CheckStatusWrapper* user_status) } // Unlink attachment from database - release_attachment(tdbb, attachment); + release_attachment(tdbb, attachment, &threadGuard); att = NULL; attachment = NULL; guard.leave(); @@ -3867,19 +3956,17 @@ JTransaction* JAttachment::reconnectTransaction(CheckStatusWrapper* user_status, } +void JRequest::deprecatedFree(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JRequest::free(CheckStatusWrapper* user_status) { -/************************************** - * - * g d s _ $ r e l e a s e _ r e q u e s t - * - ************************************** - * - * Functional description - * Release a request. - * - **************************************/ freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -3999,6 +4086,20 @@ void JTransaction::rollbackRetaining(CheckStatusWrapper* user_status) void JTransaction::rollback(CheckStatusWrapper* user_status) +{ + internalRollback(user_status); + if (user_status->isEmpty()) + release(); +} + + +void JTransaction::deprecatedRollback(CheckStatusWrapper* user_status) +{ + internalRollback(user_status); +} + + +void JTransaction::internalRollback(CheckStatusWrapper* user_status) { /************************************** * @@ -4037,6 +4138,20 @@ void JTransaction::rollback(CheckStatusWrapper* user_status) void JTransaction::disconnect(CheckStatusWrapper* user_status) +{ + internalDisconnect(user_status); + if (user_status->isEmpty()) + release(); +} + + +void JTransaction::deprecatedDisconnect(CheckStatusWrapper* user_status) +{ + internalDisconnect(user_status); +} + + +void JTransaction::internalDisconnect(CheckStatusWrapper* user_status) { try { @@ -4171,19 +4286,17 @@ JService* JProvider::attachServiceManager(CheckStatusWrapper* user_status, const } +void JService::deprecatedDetach(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JService::detach(CheckStatusWrapper* user_status) { -/************************************** - * - * g d s _ $ s e r v i c e _ d e t a c h - * - ************************************** - * - * Functional description - * Close down a service. - * - **************************************/ freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -4260,12 +4373,12 @@ void JService::query(CheckStatusWrapper* user_status, receiveItems, bufferLength, buffer); // If there is a status vector from a service thread, copy it into the thread status - const FbStatusVector* from = svc->getStatus(); - if (from->getState()) + Service::StatusAccessor status = svc->getStatusAccessor(); + if (status->getState()) { - fb_utils::copyStatus(user_status, from); + fb_utils::copyStatus(user_status, status); // Empty out the service status vector - svc->initStatus(); + status.init(); return; } } @@ -4280,6 +4393,28 @@ void JService::query(CheckStatusWrapper* user_status, } +void JService::cancel(CheckStatusWrapper* user_status) +{ + try + { + ThreadContextHolder tdbb(user_status); + + // Use class Validate here instead validateHandle() because + // global services list should be locked during cancel() call + Service::Validate guard(svc); + + svc->cancel(tdbb); + } + catch (const Exception& ex) + { + ex.stuffException(user_status); + return; + } + + successful_completion(user_status); +} + + void JService::start(CheckStatusWrapper* user_status, unsigned int spbLength, const unsigned char* spb) { /************************************** @@ -4305,9 +4440,10 @@ void JService::start(CheckStatusWrapper* user_status, unsigned int spbLength, co svc->start(spbLength, spb); - if (svc->getStatus()->getState() & IStatus::STATE_ERRORS) + UtilSvc::StatusAccessor status = svc->getStatusAccessor(); + if (status->getState() & IStatus::STATE_ERRORS) { - fb_utils::copyStatus(user_status, svc->getStatus()); + fb_utils::copyStatus(user_status, status); return; } } @@ -4452,61 +4588,66 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const **************************************/ try { - MutexLockGuard guard(shutdownMutex, FB_FUNCTION); - - if (engineShutdown) - { - return; - } { // scope - MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION); - engineShutdown = true; - } + MutexLockGuard guard(shutdownMutex, FB_FUNCTION); - ThreadContextHolder tdbb; + if (engineShutdown) + { + return; + } + { // scope + MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION); + engineShutdown = true; + } - EDS::Manager::shutdown(); + ThreadContextHolder tdbb; - ULONG attach_count, database_count, svc_count; - JRD_enum_attachments(NULL, attach_count, database_count, svc_count); + EDS::Manager::shutdown(); - if (attach_count > 0 || svc_count > 0) - { - gds__log("Shutting down the server with %d active connection(s) to %d database(s), " - "%d active service(s)", - attach_count, database_count, svc_count); - } + ULONG attach_count, database_count, svc_count; + JRD_enum_attachments(NULL, attach_count, database_count, svc_count); - if (reason == fb_shutrsn_exit_called) - { - // Starting threads may fail when task is going to close. - // This happens at least with some microsoft C runtimes. - // If people wish to have timeout, they should better call fb_shutdown() themselves. - // Therefore: - timeout = 0; - } + if (attach_count > 0 || svc_count > 0) + { + gds__log("Shutting down the server with %d active connection(s) to %d database(s), " + "%d active service(s)", + attach_count, database_count, svc_count); + } - if (timeout) - { - Semaphore shutdown_semaphore; + if (reason == fb_shutrsn_exit_called) + { + // Starting threads may fail when task is going to close. + // This happens at least with some microsoft C runtimes. + // If people wish to have timeout, they should better call fb_shutdown() themselves. + // Therefore: + timeout = 0; + } - Thread::Handle h; - Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h); + if (timeout) + { + Semaphore shutdown_semaphore; - if (!shutdown_semaphore.tryEnter(0, timeout)) - waitForShutdown(shutdown_semaphore); + Thread::Handle h; + Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h); - Thread::waitForCompletion(h); - } - else - { - shutdown_thread(NULL); + if (!shutdown_semaphore.tryEnter(0, timeout)) + waitForShutdown(shutdown_semaphore); + + Thread::waitForCompletion(h); + } + else + { + shutdown_thread(NULL); + } + + // Do not put it into separate shutdown thread - during shutdown of TraceManager + // PluginManager wants to lock a mutex, which is sometimes already locked in current thread + TraceManager::shutdown(); + Mapping::shutdownIpc(); } - // Do not put it into separate shutdown thread - during shutdown of TraceManager - // PluginManager wants to lock a mutex, which is sometimes already locked in current thread - TraceManager::shutdown(); - Mapping::shutdownIpc(); + // Wait for completion of all attacment shutdown threads + shutThreadCollect->join(); } catch (const Exception& ex) { @@ -4855,10 +4996,16 @@ void SysStableAttachment::initDone() { Jrd::Attachment* attachment = getHandle(); Database* dbb = attachment->att_database; - SyncLockGuard guard(&dbb->dbb_sys_attach, SYNC_EXCLUSIVE, "SysStableAttachment::initDone"); - attachment->att_next = dbb->dbb_sys_attachments; - dbb->dbb_sys_attachments = attachment; + { // scope + SyncLockGuard guard(&dbb->dbb_sys_attach, SYNC_EXCLUSIVE, "SysStableAttachment::initDone"); + + attachment->att_next = dbb->dbb_sys_attachments; + dbb->dbb_sys_attachments = attachment; + } + + // make system attachments traceable + attachment->att_trace_manager->activate(); } @@ -4879,8 +5026,8 @@ void SysStableAttachment::destroy(Attachment* attachment) } // Make Attachment::destroy() happy - MutexLockGuard async(*getMutex(true), FB_FUNCTION); - MutexLockGuard sync(*getMutex(), FB_FUNCTION); + AttSyncLockGuard async(*getSync(true), FB_FUNCTION); + AttSyncLockGuard sync(*getSync(), FB_FUNCTION); setInterface(NULL); Jrd::Attachment::destroy(attachment); @@ -5100,12 +5247,14 @@ IReplicator* JAttachment::createReplicator(CheckStatusWrapper* user_status) } catch (const Exception& ex) { - transliterateException(tdbb, ex, user_status, "JResultSet::fetchNext"); + transliterateException(tdbb, ex, user_status, "JAttachment::createReplicator"); + return nullptr; } } catch (const Exception& ex) { ex.stuffException(user_status); + return nullptr; } successful_completion(user_status); @@ -5352,20 +5501,30 @@ void JResultSet::freeEngineData(CheckStatusWrapper* user_status) successful_completion(user_status); } + StableAttachmentPart* JResultSet::getAttachment() { return statement->getAttachment(); } + IMessageMetadata* JResultSet::getMetadata(CheckStatusWrapper* user_status) { return statement->getOutputMetadata(user_status); } +void JResultSet::deprecatedClose(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JResultSet::close(CheckStatusWrapper* user_status) { freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -5397,9 +5556,17 @@ void JStatement::freeEngineData(CheckStatusWrapper* user_status) } +void JStatement::deprecatedFree(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JStatement::free(CheckStatusWrapper* user_status) { freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -5434,7 +5601,7 @@ JStatement* JAttachment::prepare(CheckStatusWrapper* user_status, ITransaction* // observation for now. StatementMetadata::buildInfoItems(items, flags); - statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, + statement = DSQL_prepare(tdbb, getHandle(), tra, stmtLength, sqlStmt, dialect, flags, &items, &buffer, false); rc = FB_NEW JStatement(statement, getStable(), buffer); rc->addRef(); @@ -5881,9 +6048,17 @@ int JBatch::release() } +void JBatch::deprecatedClose(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JBatch::close(CheckStatusWrapper* user_status) { freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -6205,6 +6380,48 @@ void JBatch::cancel(CheckStatusWrapper* status) } +void JBatch::getInfo(CheckStatusWrapper* user_status, + unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) +{ +/************************************** + * + * g d s _ $ b l o b _ i n f o + * + ************************************** + * + * Functional description + * Provide information on blob object. + * + **************************************/ + try + { + EngineContextHolder tdbb(user_status, this, FB_FUNCTION); + check_database(tdbb); + + try + { + DsqlBatch* b = getHandle(); + b->info(tdbb, itemsLength, items, bufferLength, buffer); + } + catch (const Exception& ex) + { + transliterateException(tdbb, ex, user_status, "JBatch::getInfo"); + return; + } + } + catch (const Exception& ex) + { + ex.stuffException(user_status); + return; + } + + successful_completion(user_status); +} + + + + JReplicator::JReplicator(Applier* appl, StableAttachmentPart* sa) : applier(appl), sAtt(sa) { } @@ -6233,14 +6450,12 @@ void JReplicator::freeEngineData(Firebird::CheckStatusWrapper* user_status) { try { - EngineContextHolder tdbb(user_status, this, FB_FUNCTION); - check_database(tdbb); + EngineContextHolder tdbb(user_status, this, FB_FUNCTION, AttachmentHolder::ATT_NO_SHUTDOWN_CHECK); try { - AutoPtr cleanupApplier(applier); - cleanupApplier->shutdown(tdbb); - fb_assert(!applier); + applier->shutdown(tdbb); + applier = nullptr; } catch (const Exception& ex) { @@ -6287,9 +6502,17 @@ void JReplicator::process(CheckStatusWrapper* status, unsigned length, const UCH } +void JReplicator::deprecatedClose(CheckStatusWrapper* user_status) +{ + freeEngineData(user_status); +} + + void JReplicator::close(CheckStatusWrapper* user_status) { freeEngineData(user_status); + if (user_status->isEmpty()) + release(); } @@ -6588,7 +6811,7 @@ namespace } } // anonymous -void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_client_SQL_dialect) +void DatabaseOptions::get(const UCHAR* dpb, FB_SIZE_T dpb_length, bool& invalid_client_SQL_dialect) { /************************************** * @@ -6985,6 +7208,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli rdr.getString(dpb_decfloat_traps); break; + case isc_dpb_clear_map: + dpb_clear_map = rdr.getBoolean(); + break; + default: break; } @@ -7258,11 +7485,17 @@ static JAttachment* create_attachment(const PathName& alias_name, static void check_single_maintenance(thread_db* tdbb) { - UCHAR spare_memory[RAW_HEADER_SIZE + PAGE_ALIGNMENT]; - UCHAR* header_page_buffer = FB_ALIGN(spare_memory, PAGE_ALIGNMENT); + Database* const dbb = tdbb->getDatabase(); + + const ULONG ioBlockSize = dbb->getIOBlockSize(); + const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize); + + HalfStaticArray temp; + UCHAR* header_page_buffer = temp.getAlignedBuffer(headerSize, ioBlockSize); + Ods::header_page* const header_page = reinterpret_cast(header_page_buffer); - PIO_header(tdbb, header_page_buffer, RAW_HEADER_SIZE); + PIO_header(tdbb, header_page_buffer, headerSize); if ((header_page->hdr_flags & Ods::hdr_shutdown_mask) == Ods::hdr_shutdown_single) { @@ -7344,7 +7577,7 @@ static void prepare_tra(thread_db* tdbb, jrd_tra* transaction, USHORT length, co } -void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment) +void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEnsureUnlock* dropGuard) { /************************************** * @@ -7367,10 +7600,7 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment) attachment->att_replicator = nullptr; while (attachment->att_repl_appliers.hasData()) - { - AutoPtr cleanupApplier(attachment->att_repl_appliers.pop()); - cleanupApplier->shutdown(tdbb); - } + attachment->att_repl_appliers.pop()->shutdown(tdbb); if (dbb->dbb_crypto_manager) dbb->dbb_crypto_manager->detach(tdbb, attachment); @@ -7421,9 +7651,27 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment) Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment"); + // dummy mutex is used to avoid races with crypto thread + XThreadMutex dummy_mutex; + XThreadEnsureUnlock dummyGuard(dummy_mutex, FB_FUNCTION); + // avoid races with special threads + // take into an account lock earlier taken in DROP DATABASE XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION); - threadGuard.enter(); + XThreadEnsureUnlock* activeThreadGuard = dropGuard; + if (!activeThreadGuard) + { + if (dbb->dbb_crypto_manager && + Thread::isCurrent(dbb->dbb_crypto_manager->getCryptThreadHandle())) + { + activeThreadGuard = &dummyGuard; + } + else + { + activeThreadGuard = &threadGuard; + } + activeThreadGuard->enter(); + } sync.lock(SYNC_EXCLUSIVE); @@ -7457,7 +7705,7 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment) } // Notify special threads - threadGuard.leave(); + activeThreadGuard->leave(); // Sync with special threads if (!other) @@ -7548,7 +7796,7 @@ static void setEngineReleaseDelay(Database* dbb) if (!dbb->dbb_plugin_config) return; - unsigned maxLinger = 0; + time_t maxLinger = 0; { // scope MutexLockGuard listGuardForLinger(databases_mutex, FB_FUNCTION); @@ -7710,8 +7958,6 @@ bool JRD_shutdown_database(Database* dbb, const unsigned flags) CCH_fini(tdbb); - dbb->shutdownGlobalObjects(); - { // scope MutexLockGuard listGuard2(databases_mutex, FB_FUNCTION); @@ -7867,6 +8113,12 @@ static void purge_transactions(thread_db* tdbb, Jrd::Attachment* attachment, con Database* const dbb = attachment->att_database; jrd_tra* const trans_dbk = attachment->att_dbkey_trans; + if (force_flag) + { + for (auto applier : attachment->att_repl_appliers) + applier->cleanupTransactions(tdbb); + } + unsigned int count = 0; jrd_tra* next; @@ -7917,8 +8169,8 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign **************************************/ SET_TDBB(tdbb); - Mutex* const attMutex = sAtt->getMutex(); - fb_assert(attMutex->locked()); + StableAttachmentPart::Sync* const attSync = sAtt->getSync(); + fb_assert(attSync->locked()); Jrd::Attachment* attachment = sAtt->getHandle(); @@ -7933,10 +8185,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign attachment->att_use_count--; { // scope - MutexUnlockGuard cout(*attMutex, FB_FUNCTION); + AttSyncUnlockGuard cout(*attSync, FB_FUNCTION); // !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when ATT_purge_started / sAtt->getHandle() changes) - fb_assert(!attMutex->locked()); + fb_assert(!attSync->locked()); Thread::yield(); Thread::sleep(1); } @@ -7960,10 +8212,10 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign attachment->att_use_count--; { // scope - MutexUnlockGuard cout(*attMutex, FB_FUNCTION); + AttSyncUnlockGuard cout(*attSync, FB_FUNCTION); // !!!!!!!!!!!!!!!!! - event? semaphore? condvar? (when --att_use_count) - fb_assert(!attMutex->locked()); + fb_assert(!attSync->locked()); Thread::yield(); Thread::sleep(1); } @@ -7974,7 +8226,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign attachment->att_use_count++; } - fb_assert(attMutex->locked()); + fb_assert(attSync->locked()); if (!attachment) return; @@ -7992,8 +8244,11 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign const TrigVector* const trig_disconnect = attachment->att_triggers[DB_TRIGGER_DISCONNECT]; + // ATT_resetting may be set here only in a case when running on disconnect triggers + // in ALTER SESSION RESET already failed and attachment was shut down. + // Trying them once again here makes no sense. if (!forcedPurge && - !(attachment->att_flags & ATT_no_db_triggers) && + !(attachment->att_flags & (ATT_no_db_triggers | ATT_resetting)) && trig_disconnect && !trig_disconnect->isEmpty()) { ThreadStatusGuard temp_status(tdbb); @@ -8009,15 +8264,32 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign transaction = TRA_start(tdbb, 0, NULL); attachment->att_flags = save_flags; + // Allow cancelling while ON DISCONNECT triggers are running + tdbb->tdbb_flags &= ~TDBB_detaching; + // run ON DISCONNECT triggers EXE_execute_db_triggers(tdbb, transaction, TRIGGER_DISCONNECT); + tdbb->tdbb_flags |= TDBB_detaching; + // and commit the transaction TRA_commit(tdbb, transaction, false); } catch (const Exception& ex) { attachment->att_flags = save_flags; + tdbb->tdbb_flags |= TDBB_detaching; + + if (attachment->att_trace_manager->needs(ITraceFactory::TRACE_EVENT_ERROR)) + { + FbLocalStatus status; + ex.stuffException(&status); + + TraceConnectionImpl conn(attachment); + TraceStatusVectorImpl traceStatus(&status, TraceStatusVectorImpl::TS_ERRORS); + + attachment->att_trace_manager->event_error(&conn, &traceStatus, FB_FUNCTION); + } string s; s.printf("Database: %s\n\tError at disconnect:", attachment->att_filename.c_str()); @@ -8079,13 +8351,13 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign attachment->att_trace_manager->event_detach(&conn, false); } - fb_assert(attMutex->locked()); - Mutex* asyncMutex = sAtt->getMutex(true, true); - MutexEnsureUnlock asyncGuard(*asyncMutex, FB_FUNCTION); + fb_assert(attSync->locked()); + StableAttachmentPart::Sync* attAsync = sAtt->getSync(true, true); + EnsureUnlock asyncGuard(*attAsync, FB_FUNCTION); { // scope - ensure correct order of taking both async and main mutexes - MutexUnlockGuard cout(*attMutex, FB_FUNCTION); - fb_assert(!attMutex->locked()); + AttSyncUnlockGuard cout(*attSync, FB_FUNCTION); + fb_assert(!attSync->locked()); asyncGuard.enter(); } @@ -8102,7 +8374,7 @@ static void purge_attachment(thread_db* tdbb, StableAttachmentPart* sAtt, unsign release_attachment(tdbb, attachment); asyncGuard.leave(); - MutexUnlockGuard cout(*attMutex, FB_FUNCTION); + AttSyncUnlockGuard cout(*attSync, FB_FUNCTION); MutexUnlockGuard coutBlocking(*sAtt->getBlockingMutex(), FB_FUNCTION); // Try to close database if there are no attachments @@ -8222,7 +8494,7 @@ static VdnResult verifyDatabaseName(const PathName& name, FbStatusVector* status **/ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char* aliasName, - const RefPtr* config, bool creating, Mapping& mapping) + const RefPtr* config, bool creating, Mapping& mapping, bool icuReset) { bool wheel = false; int id = -1, group = -1; // CVC: This var contained trash @@ -8288,6 +8560,8 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char if (wheel) { name = DBA_USER_NAME; + if (icuReset) + user.setFlag(USR_sysdba); } if (name.length() > USERNAME_LENGTH) @@ -8314,10 +8588,49 @@ static void getUserInfo(UserId& user, const DatabaseOptions& options, const char } } -static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, bool internalFlag) +static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* userStatus, unsigned flags, + const char* filename, const DatabaseOptions& options, ICryptKeyCallback* callback) { - transliterateException(tdbb, ex, userStatus, NULL); + FbLocalStatus savUserStatus; // Required to save status before transliterate + bool traced = false; + + // Trace almost completed attachment + try + { + const auto att = tdbb->getAttachment(); + TraceManager* traceManager = att ? att->att_trace_manager : nullptr; + if (att && traceManager && traceManager->isActive()) + { + TraceConnectionImpl conn(att); + TraceStatusVectorImpl traceStatus(userStatus, TraceStatusVectorImpl::TS_ERRORS); + + if (traceManager->needs(ITraceFactory::TRACE_EVENT_ATTACH)) + traceManager->event_attach(&conn, flags & UNWIND_CREATE, ITracePlugin::RESULT_FAILED); + + traced = true; + } + else + { + auto dbb = tdbb->getDatabase(); + if (dbb && (dbb->dbb_flags & DBB_new)) + { + // attach failed before completion of DBB initialization + // that's hardly recoverable error - avoid extra problems in mapping + flags |= UNWIND_NEW; + } + + savUserStatus.loadFrom(userStatus); + } + + const char* func = flags & UNWIND_CREATE ? "JProvider::createDatabase" : "JProvider::attachDatabase"; + transliterateException(tdbb, ex, userStatus, func); + } + catch (const Exception&) + { + // no-op + } + // Actual unwind try { const auto dbb = tdbb->getDatabase(); @@ -8327,6 +8640,10 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* u fb_assert(!dbb->locked()); ThreadStatusGuard temp_status(tdbb); + // In case when sweep attachment failed try to release appropriate lock + if (options.dpb_sweep) + dbb->clearSweepStarting(); + const auto attachment = tdbb->getAttachment(); if (attachment) @@ -8345,7 +8662,27 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* u if (sAtt->getHandle()) { attachment->att_flags |= flags; - release_attachment(tdbb, attachment); + try + { + release_attachment(tdbb, attachment); + } + catch (const Exception&) + { + // Minimum cleanup instead is needed to avoid repeated call + // of release_attachment() when decrementing reference counter of jAtt. + try + { + Attachment::destroy(attachment); + } + catch (const Exception&) + { + // Let's be absolutely minimalistic though + // this will almost for sure cause assertion in DEV_BUILD. + sAtt->cancel(); + attachment->setStable(NULL); + sAtt->manualUnlock(attachment->att_flags); + } + } } else { @@ -8354,7 +8691,7 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* u } JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS | - (internalFlag ? SHUT_DBB_OVERWRITE_CHECK : 0)); + (flags & UNWIND_INTERNAL ? SHUT_DBB_OVERWRITE_CHECK : 0)); } } catch (const Exception&) @@ -8362,7 +8699,18 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, FbStatusVector* u // no-op } - return; + // Trace attachment that failed before enough for normal trace context of it was established + if (!traced) + { + try + { + trace_failed_attach(filename, options, flags, &savUserStatus, callback); + } + catch (const Exception&) + { + // no-op + } + } } @@ -8382,7 +8730,7 @@ namespace { StableAttachmentPart* const sAtt = *iter; - MutexLockGuard guard(*(sAtt->getMutex(true)), FB_FUNCTION); + AttSyncLockGuard guard(*(sAtt->getSync(true)), FB_FUNCTION); Attachment* attachment = sAtt->getHandle(); if (attachment) @@ -8397,7 +8745,7 @@ namespace StableAttachmentPart* const sAtt = *iter; MutexLockGuard guardBlocking(*(sAtt->getBlockingMutex()), FB_FUNCTION); - MutexLockGuard guard(*(sAtt->getMutex()), FB_FUNCTION); + AttSyncLockGuard guard(*(sAtt->getSync()), FB_FUNCTION); Attachment* attachment = sAtt->getHandle(); if (attachment) @@ -8410,7 +8758,7 @@ namespace { // purge attachment, rollback any open transactions attachment->att_use_count++; - purge_attachment(tdbb, sAtt, PURGE_FORCE); + purge_attachment(tdbb, sAtt, engineShutdown ? PURGE_FORCE : PURGE_NOCHECK); } catch (const Exception& ex) { @@ -8434,22 +8782,37 @@ namespace ThreadModuleRef thdRef(attachmentShutdownThread, &engineShutdown); #endif + AttShutParams* params = static_cast(arg); + AttachmentsRefHolder* attachments = params->attachments; + try { - MutexLockGuard guard(shutdownMutex, FB_FUNCTION); - if (engineShutdown) - { - // Shutdown was done, all attachmnets are gone - return 0; - } + params->startCallCompleteSem.enter(); + } + catch (const Exception& ex) + { + iscLogException("attachmentShutdownThread", ex); + return 0; + } + + Thread::Handle th = params->thrHandle; + fb_assert(th); + + try + { + shutThreadCollect->running(th); + params->thdStartedSem.release(); - shutdownAttachments(static_cast(arg), isc_att_shut_db_down); + MutexLockGuard guard(shutdownMutex, FB_FUNCTION); + if (!engineShutdown) + shutdownAttachments(attachments, isc_att_shut_db_down); } catch (const Exception& ex) { iscLogException("attachmentShutdownThread", ex); } + shutThreadCollect->ending(th); return 0; } } // anonymous namespace @@ -8458,7 +8821,7 @@ namespace static void waitForShutdown(Semaphore& shutdown_semaphore) { const int pid = getpid(); - unsigned int timeout = 10000; // initial value, 10 sec + unsigned int timeout = 10; // initial value, 10 sec bool done = false; for (int i = 0; i < 5; i++) @@ -8647,7 +9010,7 @@ bool TimeoutTimer::expired() const return false; const SINT64 t = currTime(); - return t > m_start + m_value; + return t >= m_start + m_value - 1; } unsigned int TimeoutTimer::timeToExpire() const @@ -8732,11 +9095,8 @@ ISC_STATUS thread_db::getCancelState(ISC_STATUS* secondary) if (tdbb_flags & (TDBB_verb_cleanup | TDBB_dfw_cleanup | TDBB_detaching | TDBB_wait_cancel_disable)) return FB_SUCCESS; - if (attachment) + if (attachment && attachment->att_purge_tid != Thread::getId()) { - if (attachment->att_purge_tid == Thread::getId()) - return FB_SUCCESS; - if (attachment->att_flags & ATT_shutdown) { if (database->dbb_ast_flags & DBB_shutdown) @@ -8815,9 +9175,18 @@ void thread_db::reschedule() checkCancelState(); - { // checkout scope + StableAttachmentPart::Sync* sync = this->getAttachment()->getStable()->getSync(); + Database* dbb = this->getDatabase(); + + if (sync->hasContention()) + { + FB_UINT64 cnt = sync->getLockCounter(); + EngineCheckout cout(this, FB_FUNCTION); Thread::yield(); + + while (sync->hasContention() && (sync->getLockCounter() == cnt)) + Thread::sleep(1); } checkCancelState(); @@ -8828,6 +9197,22 @@ void thread_db::reschedule() tdbb_quantum = (tdbb_flags & TDBB_sweeper) ? SWEEP_QUANTUM : QUANTUM; } +ULONG thread_db::adjustWait(ULONG wait) const +{ + if ((wait == 0) || (tdbb_flags & TDBB_wait_cancel_disable) || !tdbb_reqTimer) + return wait; + + // This limit corresponds to the lock manager restriction (wait time is signed short) + static const ULONG MAX_WAIT_TIME = MAX_SSHORT; // seconds + + const unsigned int timeout = tdbb_reqTimer->timeToExpire(); // milliseconds + + const ULONG adjustedTimeout = + (timeout < MAX_WAIT_TIME * 1000) ? (timeout + 999) / 1000 : MAX_WAIT_TIME; + + return MIN(wait, adjustedTimeout); +} + // end thread_db methods @@ -9184,19 +9569,13 @@ void JRD_compile(thread_db* tdbb, JrdStatement* statement = request->getStatement(); - if (!ref_str) - { - fb_assert(statement->blr.isEmpty()); + if (ref_str) + statement->sqlText = ref_str; - // hvlad: if\when we implement request's cache in the future and - // CMP_compile2 will return us previously compiled request with - // non-empty req_blr, then we must replace assertion by the line below - // if (!statement->req_blr.isEmpty()) + fb_assert(statement->blr.isEmpty()); + if (attachment->getDebugOptions().getDsqlKeepBlr()) statement->blr.insert(0, blr, blr_length); - } - else - statement->sqlText = ref_str; *req_handle = request; } @@ -9258,13 +9637,20 @@ void JRD_shutdown_attachment(Attachment* attachment) fb_assert(attachment->att_flags & ATT_shutdown); MemoryPool& pool = *getDefaultMemoryPool(); - AttachmentsRefHolder* queue = FB_NEW_POOL(pool) AttachmentsRefHolder(pool); + AutoPtr queue(FB_NEW_POOL(pool) AttachmentsRefHolder(pool)); fb_assert(attachment->getStable()); attachment->getStable()->addRef(); queue->add(attachment->getStable()); - Thread::start(attachmentShutdownThread, queue, THREAD_high); + AttShutParams params; + params.attachments = queue; + Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle); + params.startCallCompleteSem.release(); + + queue.release(); + shutThreadCollect->houseKeeping(); + params.thdStartedSem.enter(); } catch (const Exception&) {} // no-op @@ -9312,8 +9698,17 @@ void JRD_shutdown_attachments(Database* dbb) } } - if (queue.hasData()) - Thread::start(attachmentShutdownThread, queue.release(), THREAD_high); + if (queue->hasData()) + { + AttShutParams params; + params.attachments = queue; + Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle); + params.startCallCompleteSem.release(); + + queue.release(); + shutThreadCollect->houseKeeping(); + params.thdStartedSem.enter(); + } } catch (const Exception&) {} // no-op @@ -9391,6 +9786,8 @@ void TrigVector::release() void TrigVector::release(thread_db* tdbb) { + fb_assert(useCount.value() > 0); + if (--useCount == 0) { decompile(tdbb); diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index ff8ad7c2686..4fd59f561dd 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -655,6 +655,10 @@ class thread_db : public Firebird::ThreadData return tdbb_reqTimer; } + // Returns minimum of passed wait timeout and time to expiration of reqTimer. + // Timer value is rounded to the upper whole second. + ULONG adjustWait(ULONG wait) const; + void registerBdb(BufferDesc* bdb) { if (tdbb_bdbs.isEmpty()) { @@ -1085,13 +1089,25 @@ namespace Jrd { fb_assert(optional || m_ref.hasData()); if (m_ref.hasData()) - m_ref->getMutex()->leave(); + m_ref->getSync()->leave(); + } + + EngineCheckout(Attachment* att, const char* from) + : m_tdbb(nullptr), m_from(from) + { + fb_assert(att); + + if (att && att->att_use_count) + { + m_ref = att->getStable(); + m_ref->getSync()->leave(); + } } ~EngineCheckout() { if (m_ref.hasData()) - m_ref->getMutex()->enter(m_from); + m_ref->getSync()->enter(m_from); // If we were signalled to cancel/shutdown, react as soon as possible. // We cannot throw immediately, but we can reschedule ourselves. diff --git a/src/jrd/lck.cpp b/src/jrd/lck.cpp index 380d40fd45b..224e8e899a6 100644 --- a/src/jrd/lck.cpp +++ b/src/jrd/lck.cpp @@ -56,7 +56,6 @@ using namespace Jrd; using namespace Firebird; -static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait); static void bug_lck(const TEXT*); static bool compatible(const Lock*, const Lock*, USHORT); static void enqueue(thread_db*, CheckStatusWrapper*, Lock*, USHORT, SSHORT); @@ -344,7 +343,6 @@ bool LCK_convert(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait) WaitCancelGuard guard(tdbb, lock, wait); FbLocalStatus statusVector; - wait = adjust_wait(tdbb, wait); const bool result = CONVERT(tdbb, &statusVector, lock, level, wait); if (!result) @@ -672,7 +670,6 @@ bool LCK_lock(thread_db* tdbb, Lock* lock, USHORT level, SSHORT wait) WaitCancelGuard guard(tdbb, lock, wait); FbLocalStatus statusVector; - wait = adjust_wait(tdbb, wait); ENQUEUE(tdbb, &statusVector, lock, level, wait); fb_assert(LCK_CHECK_LOCK(lock)); @@ -872,40 +869,6 @@ void LCK_write_data(thread_db* tdbb, Lock* lock, LOCK_DATA_T data) } -static SSHORT adjust_wait(thread_db* tdbb, SSHORT wait) -{ -/************************************** - * - * a d j u s t _ w a i t - * - ************************************** - * - * Functional description - * If wait is cancellable and if statement timer was started - calc new wait - * time to ensure it will not take longer than rest of timeout. - * - **************************************/ - if ((wait == LCK_NO_WAIT) || (tdbb->tdbb_flags & TDBB_wait_cancel_disable) || !tdbb->getTimeoutTimer()) - return wait; - - unsigned int tout = tdbb->getTimeoutTimer()->timeToExpire(); - if (tout > 0) - { - SSHORT t; - if (tout < 1000) - t = 1; - else if (tout < MAX_SSHORT * 1000) - t = (tout + 999) / 1000; - else - t = MAX_SSHORT; - - if ((wait == LCK_WAIT) || (-wait > t)) - return -t; - } - return wait; -} - - static void bug_lck(const TEXT* string) { /************************************** @@ -1525,7 +1488,7 @@ Lock::~Lock() { #ifdef DEBUG_LCK_LIST gds__log("DEBUG_LCK_LIST: Lock::~Lock(): this 0x%p, attachment 0x%p, lck_type %d, lck_next 0x%p, lck_prior 0x%p", - this, lck_attachment ? lck_attachment->getHandle() : NULL, + this, lck_attachment ? lck_attachment->getHandle() : NULL, (int) lck_type, lck_next, lck_prior); #endif diff --git a/src/jrd/license.h b/src/jrd/license.h index 1fbcff04d9f..c162f1d3bce 100644 --- a/src/jrd/license.h +++ b/src/jrd/license.h @@ -125,8 +125,8 @@ #if defined(__ppc__) || defined(__ppc64__) #define FB_PLATFORM "UP" // Darwin/PowerPC #endif -#if defined(ARM) -#define FB_PLATFORM "UA" +#if defined(ARM) || defined(__aarch64__) +#define FB_PLATFORM "UA" // Darwin/ARM #endif #endif diff --git a/src/jrd/met.epp b/src/jrd/met.epp index 93db683e870..32e86a6c4cf 100644 --- a/src/jrd/met.epp +++ b/src/jrd/met.epp @@ -350,9 +350,9 @@ void MET_update_partners(thread_db* tdbb) continue; // signal other processes + relation->rel_flags |= REL_check_partners; LCK_lock(tdbb, relation->rel_partners_lock, LCK_EX, LCK_WAIT); LCK_release(tdbb, relation->rel_partners_lock); - relation->rel_flags |= REL_check_partners; } } @@ -1923,6 +1923,7 @@ void MET_load_ddl_triggers(thread_db* tdbb) attachment->att_ddl_triggers = FB_NEW_POOL(*attachment->att_pool) TrigVector(*attachment->att_pool); + attachment->att_ddl_triggers->addRef(); AutoRequest trigger_request; @@ -2777,6 +2778,7 @@ jrd_prc* MET_lookup_procedure(thread_db* tdbb, const QualifiedName& name, bool n jrd_prc* procedure = *iter; if (procedure && !(procedure->flags & Routine::FLAG_OBSOLETE) && + !(procedure->flags & Routine::FLAG_CLEARED) && ((procedure->flags & Routine::FLAG_SCANNED) || noscan) && !(procedure->flags & Routine::FLAG_BEING_SCANNED) && !(procedure->flags & Routine::FLAG_BEING_ALTERED)) @@ -2845,6 +2847,7 @@ jrd_prc* MET_lookup_procedure_id(thread_db* tdbb, USHORT id, if (id < (USHORT) attachment->att_procedures.getCount() && (procedure = attachment->att_procedures[id]) && procedure->getId() == id && + !(procedure->flags & Routine::FLAG_CLEARED) && !(procedure->flags & Routine::FLAG_BEING_SCANNED) && ((procedure->flags & Routine::FLAG_SCANNED) || noscan) && !(procedure->flags & Routine::FLAG_BEING_ALTERED) && @@ -2973,9 +2976,13 @@ jrd_rel* MET_lookup_relation(thread_db* tdbb, const MetaName& name) if (check_relation != relation) { LCK_release(tdbb, check_relation->rel_existence_lock); - LCK_release(tdbb, check_relation->rel_partners_lock); + if (!(check_relation->rel_flags & REL_check_partners)) + { + check_relation->rel_flags |= REL_check_partners; + LCK_release(tdbb, check_relation->rel_partners_lock); + check_relation->rel_flags &= ~REL_check_partners; + } LCK_release(tdbb, check_relation->rel_rescan_lock); - check_relation->rel_flags &= ~REL_check_partners; check_relation->rel_flags |= REL_deleted; } } @@ -3056,9 +3063,13 @@ jrd_rel* MET_lookup_relation_id(thread_db* tdbb, SLONG id, bool return_deleted) if (check_relation != relation) { LCK_release(tdbb, check_relation->rel_existence_lock); - LCK_release(tdbb, check_relation->rel_partners_lock); + if (!(check_relation->rel_flags & REL_check_partners)) + { + check_relation->rel_flags |= REL_check_partners; + LCK_release(tdbb, check_relation->rel_partners_lock); + check_relation->rel_flags &= ~REL_check_partners; + } LCK_release(tdbb, check_relation->rel_rescan_lock); - check_relation->rel_flags &= ~REL_check_partners; check_relation->rel_flags |= REL_deleted; } } @@ -3336,7 +3347,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) try { procedure->flags |= (Routine::FLAG_BEING_SCANNED | flags); - procedure->flags &= ~Routine::FLAG_OBSOLETE; + procedure->flags &= ~(Routine::FLAG_OBSOLETE | Routine::FLAG_CLEARED); procedure->setId(id); attachment->att_procedures[id] = procedure; @@ -3400,6 +3411,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) procedure->invoker = attachment->getUserId(procedure->owner); procedure->setImplemented(true); + procedure->setDefined(true); procedure->getInputFields().resize(P.RDB$PROCEDURE_INPUTS); procedure->getOutputFields().resize(P.RDB$PROCEDURE_OUTPUTS); procedure->setDefaultCount(0); @@ -3524,12 +3536,15 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) dbb->dbb_extManager->makeProcedure(tdbb, csb, procedure, P.RDB$ENGINE_NAME, (P.RDB$ENTRYPOINT.NULL ? "" : P.RDB$ENTRYPOINT), body.begin()); + + if (!procedure->getExternal()) + procedure->setDefined(false); } else { try { - procedure->parseBlr(tdbb, csb, &P.RDB$PROCEDURE_BLR, + procedure->parseBlr(tdbb, csb, &P.RDB$PROCEDURE_BLR, P.RDB$DEBUG_INFO.NULL ? NULL : &P.RDB$DEBUG_INFO); } catch (const Exception& ex) @@ -3552,7 +3567,7 @@ jrd_prc* MET_procedure(thread_db* tdbb, USHORT id, bool noscan, USHORT flags) throw; } - fb_assert(procedure->getStatement()->procedure == procedure); + fb_assert(!procedure->isDefined() || procedure->getStatement()->procedure == procedure); } else { @@ -4009,6 +4024,7 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) field->fld_default_value = NULL; field->fld_validation = NULL; field->fld_not_null = NULL; + field->fld_generator_name = NULL; } array = NULL; @@ -4076,8 +4092,8 @@ void MET_scan_relation(thread_db* tdbb, jrd_rel* relation) DmlNode* nod = dependencies ? MET_get_dependencies(tdbb, relation, p, length, csb, NULL, NULL, NULL, - field->fld_name, obj_computed, 0, depTrans) : - PAR_blr(tdbb, relation, p, length, csb, NULL, NULL, false, 0); + field->fld_name, obj_computed, csb_computed_field, depTrans) : + PAR_blr(tdbb, relation, p, length, csb, NULL, NULL, false, csb_computed_field); field->fld_computation = static_cast(nod); } @@ -4431,7 +4447,7 @@ static int blocking_ast_relation(void* ast_object) if (relation->rel_use_count) relation->rel_flags |= REL_blocking; - else + else if (!(relation->rel_flags & REL_deleting)) { relation->rel_flags &= ~REL_blocking; relation->rel_flags |= REL_check_existence; @@ -4456,8 +4472,11 @@ static int partners_ast_relation(void* ast_object) AsyncContextHolder tdbb(dbb, FB_FUNCTION, relation->rel_partners_lock); - LCK_release(tdbb, relation->rel_partners_lock); - relation->rel_flags |= REL_check_partners; + if (!(relation->rel_flags & REL_check_partners)) + { + relation->rel_flags |= REL_check_partners; + LCK_release(tdbb, relation->rel_partners_lock); + } } catch (const Exception&) {} // no-op @@ -5030,28 +5049,36 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation) **************************************/ Attachment* attachment = tdbb->getAttachment(); - AutoCacheRequest request(tdbb, irq_foreign1, IRQ_REQUESTS); - frgn* references = &relation->rel_foreign_refs; - int index_number = 0; - - if (references->frgn_reference_ids) - { - delete references->frgn_reference_ids; - references->frgn_reference_ids = NULL; - } - if (references->frgn_relations) - { - delete references->frgn_relations; - references->frgn_relations = NULL; - } - if (references->frgn_indexes) + while (relation->rel_flags & REL_check_partners) { - delete references->frgn_indexes; - references->frgn_indexes = NULL; - } + relation->rel_flags &= ~REL_check_partners; + LCK_lock(tdbb, relation->rel_partners_lock, LCK_SR, LCK_WAIT); - FOR(REQUEST_HANDLE request) - IDX IN RDB$INDICES CROSS + if (relation->rel_flags & REL_check_partners) + continue; + + AutoCacheRequest request(tdbb, irq_foreign1, IRQ_REQUESTS); + frgn* references = &relation->rel_foreign_refs; + int index_number = 0; + + if (references->frgn_reference_ids) + { + delete references->frgn_reference_ids; + references->frgn_reference_ids = NULL; + } + if (references->frgn_relations) + { + delete references->frgn_relations; + references->frgn_relations = NULL; + } + if (references->frgn_indexes) + { + delete references->frgn_indexes; + references->frgn_indexes = NULL; + } + + FOR(REQUEST_HANDLE request) + IDX IN RDB$INDICES CROSS RC IN RDB$RELATION_CONSTRAINTS OVER RDB$INDEX_NAME CROSS IND IN RDB$INDICES WITH @@ -5061,99 +5088,97 @@ void scan_partners(thread_db* tdbb, jrd_rel* relation) IDX.RDB$INDEX_ID > 0 AND IND.RDB$INDEX_ID > 0 AND IND.RDB$UNIQUE_FLAG = 1 - { - //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. - const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? - relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); - - if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) { - // This seems a good candidate for vcl. - references->frgn_reference_ids = - vec::newVector(*relation->rel_pool, references->frgn_reference_ids, - index_number + 1); + //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. + const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? + relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); + + if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) + { + // This seems a good candidate for vcl. + references->frgn_reference_ids = + vec::newVector(*relation->rel_pool, references->frgn_reference_ids, + index_number + 1); - (*references->frgn_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1; + (*references->frgn_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1; - references->frgn_relations = - vec::newVector(*relation->rel_pool, references->frgn_relations, - index_number + 1); + references->frgn_relations = + vec::newVector(*relation->rel_pool, references->frgn_relations, + index_number + 1); - (*references->frgn_relations)[index_number] = partner_relation->rel_id; + (*references->frgn_relations)[index_number] = partner_relation->rel_id; - references->frgn_indexes = - vec::newVector(*relation->rel_pool, references->frgn_indexes, - index_number + 1); + references->frgn_indexes = + vec::newVector(*relation->rel_pool, references->frgn_indexes, + index_number + 1); - (*references->frgn_indexes)[index_number] = IND.RDB$INDEX_ID - 1; + (*references->frgn_indexes)[index_number] = IND.RDB$INDEX_ID - 1; - index_number++; + index_number++; + } } - } - END_FOR + END_FOR - // Prepare for rescan of primary dependencies on relation's primary key and stale vectors. + // Prepare for rescan of primary dependencies on relation's primary key and stale vectors. - request.reset(tdbb, irq_foreign2, IRQ_REQUESTS); - prim* dependencies = &relation->rel_primary_dpnds; - index_number = 0; + request.reset(tdbb, irq_foreign2, IRQ_REQUESTS); + prim* dependencies = &relation->rel_primary_dpnds; + index_number = 0; - if (dependencies->prim_reference_ids) - { - delete dependencies->prim_reference_ids; - dependencies->prim_reference_ids = NULL; - } - if (dependencies->prim_relations) - { - delete dependencies->prim_relations; - dependencies->prim_relations = NULL; - } - if (dependencies->prim_indexes) - { - delete dependencies->prim_indexes; - dependencies->prim_indexes = NULL; - } + if (dependencies->prim_reference_ids) + { + delete dependencies->prim_reference_ids; + dependencies->prim_reference_ids = NULL; + } + if (dependencies->prim_relations) + { + delete dependencies->prim_relations; + dependencies->prim_relations = NULL; + } + if (dependencies->prim_indexes) + { + delete dependencies->prim_indexes; + dependencies->prim_indexes = NULL; + } - FOR(REQUEST_HANDLE request) - IDX IN RDB$INDICES CROSS + FOR(REQUEST_HANDLE request) + IDX IN RDB$INDICES CROSS IND IN RDB$INDICES WITH IDX.RDB$UNIQUE_FLAG = 1 AND IDX.RDB$INDEX_ID > 0 AND IND.RDB$INDEX_ID > 0 AND IDX.RDB$RELATION_NAME EQ relation->rel_name.c_str() AND IND.RDB$FOREIGN_KEY EQ IDX.RDB$INDEX_NAME - { - //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. - const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? - relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); - - if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) { - dependencies->prim_reference_ids = - vec::newVector(*relation->rel_pool, dependencies->prim_reference_ids, - index_number + 1); + //// ASF: Hack fix for CORE-4304, until nasty interactions between dfw and met are not resolved. + const jrd_rel* partner_relation = relation->rel_name == IND.RDB$RELATION_NAME ? + relation : MET_lookup_relation(tdbb, IND.RDB$RELATION_NAME); + + if (partner_relation && !IDX.RDB$INDEX_INACTIVE && !IND.RDB$INDEX_INACTIVE) + { + dependencies->prim_reference_ids = + vec::newVector(*relation->rel_pool, dependencies->prim_reference_ids, + index_number + 1); - (*dependencies->prim_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1; + (*dependencies->prim_reference_ids)[index_number] = IDX.RDB$INDEX_ID - 1; - dependencies->prim_relations = - vec::newVector(*relation->rel_pool, dependencies->prim_relations, - index_number + 1); + dependencies->prim_relations = + vec::newVector(*relation->rel_pool, dependencies->prim_relations, + index_number + 1); - (*dependencies->prim_relations)[index_number] = partner_relation->rel_id; + (*dependencies->prim_relations)[index_number] = partner_relation->rel_id; - dependencies->prim_indexes = - vec::newVector(*relation->rel_pool, dependencies->prim_indexes, - index_number + 1); + dependencies->prim_indexes = + vec::newVector(*relation->rel_pool, dependencies->prim_indexes, + index_number + 1); - (*dependencies->prim_indexes)[index_number] = IND.RDB$INDEX_ID - 1; + (*dependencies->prim_indexes)[index_number] = IND.RDB$INDEX_ID - 1; - index_number++; + index_number++; + } } + END_FOR } - END_FOR - - LCK_lock(tdbb, relation->rel_partners_lock, LCK_SR, LCK_WAIT); - relation->rel_flags &= ~REL_check_partners; } diff --git a/src/jrd/mov.cpp b/src/jrd/mov.cpp index 8b2323d5aa4..1e8a618171c 100644 --- a/src/jrd/mov.cpp +++ b/src/jrd/mov.cpp @@ -488,7 +488,7 @@ Int128 MOV_get_int128(Jrd::thread_db* tdbb, const dsc* desc, SSHORT scale) namespace Jrd { -DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen) +DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen, USHORT charSetId) : maxLen(mLen) { const char* const NULL_KEY_STRING = "NULL"; @@ -501,8 +501,8 @@ DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen) fb_assert(!desc->isBlob()); - const bool isBinary = (desc->isText() && desc->getTextType() == ttype_binary); - value = MOV_make_string2(tdbb, desc, isBinary ? ttype_binary : ttype_dynamic); + const bool isBinary = (desc->isText() && desc->getCharSet() == CS_BINARY); + value = MOV_make_string2(tdbb, desc, isBinary ? CS_BINARY : charSetId); const char* const str = value.c_str(); @@ -510,7 +510,7 @@ DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen) { if (desc->dsc_dtype == dtype_text) { - const char* const pad = (desc->dsc_sub_type == ttype_binary) ? "\0" : " "; + const char* const pad = (desc->getCharSet() == CS_BINARY) ? "\0" : " "; value.rtrim(pad); } @@ -542,7 +542,7 @@ DescPrinter::DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen) value.resize(maxLen); - const CharSet* const cs = INTL_charset_lookup(tdbb, desc->getCharSet()); + const CharSet* const cs = INTL_charset_lookup(tdbb, charSetId); while (value.hasData() && !cs->wellFormed(value.length(), (const UCHAR*) value.c_str())) value.resize(value.length() - 1); diff --git a/src/jrd/mov_proto.h b/src/jrd/mov_proto.h index 816842a4b21..8edfd15923a 100644 --- a/src/jrd/mov_proto.h +++ b/src/jrd/mov_proto.h @@ -62,7 +62,7 @@ namespace Jrd class DescPrinter { public: - DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen); + DescPrinter(thread_db* tdbb, const dsc* desc, FB_SIZE_T mLen, USHORT charSetId); const Firebird::string& get() const { diff --git a/src/jrd/nbak.cpp b/src/jrd/nbak.cpp index 71ac449e499..7c52ad4076f 100644 --- a/src/jrd/nbak.cpp +++ b/src/jrd/nbak.cpp @@ -652,7 +652,7 @@ bool BackupManager::actualizeAlloc(thread_db* tdbb, bool haveGlobalLock) // For SuperServer this routine is really executed only at database startup when // it has exlock or when exclusive access to database is enabled if (!alloc_table) - alloc_table = FB_NEW_POOL(*database->dbb_permanent) AllocItemTree(database->dbb_permanent); + alloc_table = FB_NEW_POOL(*database->dbb_permanent) AllocItemTree(*database->dbb_permanent); while (true) { @@ -899,16 +899,18 @@ void BackupManager::setForcedWrites(const bool forceWrite, const bool notUseFSCa BackupManager::BackupManager(thread_db* tdbb, Database* _database, int ini_state) : dbCreating(false), database(_database), diff_file(NULL), alloc_table(NULL), - last_allocated_page(0), current_scn(0), diff_name(*_database->dbb_permanent), + last_allocated_page(0), temp_buffers_space(*database->dbb_permanent), + current_scn(0), diff_name(*database->dbb_permanent), explicit_diff_name(false), flushInProgress(false), shutDown(false), allocIsValid(false), master(false), stateBlocking(false), stateLock(FB_NEW_POOL(*database->dbb_permanent) NBackupStateLock(tdbb, *database->dbb_permanent, this)), allocLock(FB_NEW_POOL(*database->dbb_permanent) NBackupAllocLock(tdbb, *database->dbb_permanent, this)) { // Allocate various database page buffers needed for operation - temp_buffers_space = FB_NEW_POOL(*database->dbb_permanent) BYTE[database->dbb_page_size * 3 + PAGE_ALIGNMENT]; // Align it at sector boundary for faster IO (also guarantees correct alignment for ULONG later) - BYTE* temp_buffers = reinterpret_cast(FB_ALIGN(temp_buffers_space, PAGE_ALIGNMENT)); + UCHAR* temp_buffers = reinterpret_cast + (temp_buffers_space.getAlignedBuffer(database->dbb_page_size * 3, database->getIOBlockSize())); + memset(temp_buffers, 0, database->dbb_page_size * 3); backup_state = ini_state; @@ -925,7 +927,6 @@ BackupManager::~BackupManager() delete stateLock; delete allocLock; delete alloc_table; - delete[] temp_buffers_space; } void BackupManager::setDifference(thread_db* tdbb, const char* filename) diff --git a/src/jrd/nbak.h b/src/jrd/nbak.h index e9f58c6dd8a..44fdf8daf96 100644 --- a/src/jrd/nbak.h +++ b/src/jrd/nbak.h @@ -82,7 +82,7 @@ class AllocItem } }; -typedef Firebird::BePlusTree AllocItemTree; +typedef Firebird::BePlusTree AllocItemTree; // Class to synchronize access to backup state @@ -493,7 +493,7 @@ class BackupManager AllocItemTree* alloc_table; // Cached allocation table of pages in difference file USHORT backup_state; ULONG last_allocated_page; // Last physical page allocated in the difference file - BYTE *temp_buffers_space; + Firebird::Array temp_buffers_space; ULONG *alloc_buffer, *empty_buffer, *spare_buffer; ULONG current_scn; Firebird::PathName diff_name; diff --git a/src/jrd/ods.h b/src/jrd/ods.h index e91d796bdbf..66e371baac5 100644 --- a/src/jrd/ods.h +++ b/src/jrd/ods.h @@ -914,6 +914,11 @@ Firebird::string pagtype(UCHAR type); // alignment for raw page access const USHORT PAGE_ALIGNMENT = 1024; +// alignment and IO block size/offset multiplier for non-buffered file access +const ULONG DIRECT_IO_BLOCK_SIZE = 4096; + +static_assert(MIN_PAGE_SIZE >= DIRECT_IO_BLOCK_SIZE, "check DIRECT_IO_BLOCK_SIZE"); + // size of raw I/O operation for header page const USHORT RAW_HEADER_SIZE = 1024; // ROUNDUP(HDR_SIZE, PAGE_ALIGNMENT); //static_assert(RAW_HEADER_SIZE >= HDR_SIZE, "RAW_HEADER_SIZE is less than HDR_SIZE"); diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index cdf7e81e100..c70a6a91531 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -302,8 +302,6 @@ namespace { // Ideally, we should never get here. But just in case it happened, handle it. - fb_assert(false); - for (auto& subRiver : rivers) { const auto subRsb = subRiver->getRecordSource(); @@ -747,7 +745,9 @@ RecordSource* OPT_compile(thread_db* tdbb, CompilerScratch* csb, RseNode* rse, csb->csb_rpt[*i].activate(); } - fb_assert(opt->compileStreams.getCount() != 1 || csb->csb_rpt[opt->compileStreams[0]].csb_relation != 0); + StreamList joinStreams(opt->compileStreams); + + fb_assert(joinStreams.getCount() != 1 || csb->csb_rpt[joinStreams[0]].csb_relation != 0); while (true) { @@ -757,7 +757,7 @@ RecordSource* OPT_compile(thread_db* tdbb, CompilerScratch* csb, RseNode* rse, // currently active rivers. Where in the new cross river // a stream depends (index) on the active rivers. StreamList dependent_streams, free_streams; - find_index_relationship_streams(tdbb, opt, opt->compileStreams, dependent_streams, free_streams); + find_index_relationship_streams(tdbb, opt, joinStreams, dependent_streams, free_streams); // If we have dependent and free streams then we can't rely on // the sort node to be used for index navigation. @@ -770,7 +770,7 @@ RecordSource* OPT_compile(thread_db* tdbb, CompilerScratch* csb, RseNode* rse, if (dependent_streams.getCount()) { // copy free streams - opt->compileStreams.assign(free_streams); + joinStreams.assign(free_streams); // Make rivers from the dependent streams gen_join(tdbb, opt, dependent_streams, rivers, &sort, rse->rse_plan); @@ -796,7 +796,7 @@ RecordSource* OPT_compile(thread_db* tdbb, CompilerScratch* csb, RseNode* rse, } // attempt to form joins in decreasing order of desirability - gen_join(tdbb, opt, opt->compileStreams, rivers, &sort, rse->rse_plan); + gen_join(tdbb, opt, joinStreams, rivers, &sort, rse->rse_plan); // If there are multiple rivers, try some hashing or sort/merging while (gen_equi_join(tdbb, opt, rivers)) @@ -1013,10 +1013,15 @@ static void check_indices(const CompilerScratch::csb_repeat* csb_tail) // if there were no indices fetched at all but the // user specified some, error out using the first index specified - if (!csb_tail->csb_indices && plan->accessType && !tdbb->getAttachment()->isGbak()) + const bool isGbak = tdbb->getAttachment()->isGbak(); + + if (!csb_tail->csb_indices && plan->accessType) { // index %s cannot be used in the specified plan - ERR_post(Arg::Gds(isc_index_unused) << plan->accessType->items[0].indexName); + if (isGbak) + ERR_post_warning(Arg::Warning(isc_index_unused) << plan->accessType->items[0].indexName); + else + ERR_post(Arg::Gds(isc_index_unused) << plan->accessType->items[0].indexName); } // check to make sure that all indices are either used or marked not to be used, @@ -1036,7 +1041,10 @@ static void check_indices(const CompilerScratch::csb_repeat* csb_tail) index_name = ""; // index %s cannot be used in the specified plan - ERR_post(Arg::Gds(isc_index_unused) << Arg::Str(index_name)); + if (isGbak) + ERR_post_warning(Arg::Warning(isc_index_unused) << Arg::Str(index_name)); + else + ERR_post(Arg::Gds(isc_index_unused) << Arg::Str(index_name)); } ++idx; @@ -1490,14 +1498,15 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc * **************************************/ - // dimitr: Dumb protection against too many injected conjuncts (see CORE-5381). - // Don't produce more additional conjuncts than we originally had - // (i.e. this routine should never more than double the number of conjuncts). - // Ideally, we need two separate limits here: - // 1) number of injected conjuncts (affects required impure size) - // 2) number of input conjuncts (affects search time inside this routine) + // dimitr: Simplified protection against too many injected conjuncts (see CORE-5381). + // Two separate limits are applied here: + // 1) number of input conjuncts (affects search time inside this routine) + // 2) number of injected conjuncts (affects required impure size) + + constexpr unsigned MAX_CONJUNCTS_TO_PROCESS = 1024; + const unsigned MAX_CONJUNCTS_TO_INJECT = MAX(base_count, 256); - if (base_count * 2 > MAX_CONJUNCTS) + if (base_count > MAX_CONJUNCTS_TO_PROCESS) return 0; ObjectsArray classes; @@ -1584,7 +1593,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc { for (ValueExprNodeStack::iterator inner(outer); (++inner).hasData(); ) { - if (count < base_count) + if (count < MAX_CONJUNCTS_TO_INJECT) { AutoPtr cmpNode(FB_NEW_POOL(csb->csb_pool) ComparativeBoolNode(csb->csb_pool, blr_eql)); @@ -1645,7 +1654,7 @@ static USHORT distribute_equalities(BoolExprNodeStack& org_stack, CompilerScratc { for (ValueExprNodeStack::iterator temp(*eq_class); temp.hasData(); ++temp) { - if (!node_equality(node1, temp.object()) && count < base_count) + if (!node_equality(node1, temp.object()) && count < MAX_CONJUNCTS_TO_INJECT) { ValueExprNode* arg1; ValueExprNode* arg2; @@ -3198,10 +3207,12 @@ static BoolExprNode* make_inference_node(CompilerScratch* csb, BoolExprNode* boo // Share impure area for cached invariant value used to hold pre-compiled // pattern for new LIKE and CONTAINING algorithms. + // Cached pattern matcher also should be shared by both nodes, else new node + // could overwrite impure area at offset zero. See bug GH-7276. // Proper cloning of impure area for this node would require careful accounting // of new invariant dependencies - we avoid such hassles via using single // cached pattern value for all node clones. This is faster too. - if (newCmpNode->nodFlags & ExprNode::FLAG_INVARIANT) + if (newCmpNode->nodFlags & (ExprNode::FLAG_INVARIANT | ExprNode::FLAG_PATTERN_MATCHER_CACHE)) newCmpNode->impureOffset = cmpNode->impureOffset; // But substitute new values for some of the predicate arguments diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index 2e61e55d31d..1f437de1902 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -764,35 +764,26 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page, { if (!(file = seek_file(file, bdb, &offset, status_vector))) return false; + if ((bytes = os_utils::pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size) - break; + { + // os_utils::posix_fadvise(file->desc, offset, size, POSIX_FADV_NOREUSE); + return true; + } + + // pread() returned error if (bytes < 0 && !SYSCALL_INTERRUPTED(errno)) return unix_error("read", file, isc_io_read_err, status_vector); - if (bytes >= 0) - return block_size_error(file, offset + bytes, status_vector); - } - if (i == IO_RETRY) - { - if (bytes == 0) - { -#ifdef DEV_BUILD - fprintf(stderr, "PIO_read: an empty page read!\n"); - fflush(stderr); -#endif - } - else + // pread() returned not enough bytes + if (bytes >= 0) { -#ifdef DEV_BUILD - fprintf(stderr, "PIO_read: retry count exceeded\n"); - fflush(stderr); -#endif - unix_error("read_retry", file, isc_io_read_err); + if (!block_size_error(file, offset + bytes, status_vector)) + return false; } } - // os_utils::posix_fadvise(file->desc, offset, size, POSIX_FADV_NOREUSE); - return true; + return unix_error("read_retry", file, isc_io_read_err, status_vector); } @@ -825,15 +816,18 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page, { if (!(file = seek_file(file, bdb, &offset, status_vector))) return false; + if ((bytes = os_utils::pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size) - break; + { + // os_utils::posix_fadvise(file->desc, offset, size, POSIX_FADV_DONTNEED); + return true; + } + if (bytes < 0 && !SYSCALL_INTERRUPTED(errno)) return unix_error("write", file, isc_io_write_err, status_vector); } - - // os_utils::posix_fadvise(file->desc, offset, size, POSIX_FADV_DONTNEED); - return true; + return unix_error("write_retry", file, isc_io_write_err, status_vector); } diff --git a/src/jrd/os/win32/winnt.cpp b/src/jrd/os/win32/winnt.cpp index 5bc55c6fa22..85ce0e05ee8 100644 --- a/src/jrd/os/win32/winnt.cpp +++ b/src/jrd/os/win32/winnt.cpp @@ -290,10 +290,10 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons const DWORD ret = SetFilePointer(hFile, newSize.LowPart, &newSize.HighPart, FILE_BEGIN); if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { - nt_error("SetFilePointer", file, isc_io_write_err, 0); + nt_error("SetFilePointer", file, isc_io_write_err, NULL); } if (!SetEndOfFile(hFile)) { - nt_error("SetEndOfFile", file, isc_io_write_err, 0); + nt_error("SetEndOfFile", file, isc_io_write_err, NULL); } leftPages -= extendBy; @@ -374,7 +374,9 @@ void PIO_force_write(jrd_file* file, const bool forceWrite, const bool notUseFSC file->fil_flags &= ~FIL_no_fs_cache; } +#ifndef _USING_V110_SDK71_ SetFileCompletionNotificationModes(hFile, FILE_SKIP_SET_EVENT_ON_HANDLE); +#endif } } @@ -405,13 +407,16 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length) memset(&overlapped, 0, sizeof(OVERLAPPED)); overlapped.hEvent = ThreadSync::getThread(FB_FUNCTION)->getIOEvent(); - DWORD actual_length; - DWORD ret = ReadFile(desc, address, length, NULL, &overlapped); - if (!GetOverlappedResult(desc, &overlapped, &actual_length, TRUE) || - actual_length != (DWORD) length) + DWORD actual_length; + BOOL ret = ReadFile(desc, address, length, &actual_length, &overlapped); + if (!ret) { - nt_error("ReadFile", file, isc_io_read_err, 0); + if (GetLastError() == ERROR_IO_PENDING) + ret = GetOverlappedResult(desc, &overlapped, &actual_length, TRUE); } + + if (!ret || (length != actual_length)) + nt_error("ReadFile", file, isc_io_read_err, NULL); } // we need a class here only to return memory on shutdown and avoid @@ -471,9 +476,14 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu const DWORD to_write = (DWORD) write_pages * dbb->dbb_page_size; DWORD written; - DWORD ret = WriteFile(file->fil_desc, zero_buff, to_write, NULL, &overlapped); - if (!GetOverlappedResult(file->fil_desc, &overlapped, &written, TRUE) || - to_write != written) + BOOL ret = WriteFile(file->fil_desc, zero_buff, to_write, &written, &overlapped); + if (!ret) + { + if (GetLastError() == ERROR_IO_PENDING) + ret = GetOverlappedResult(file->fil_desc, &overlapped, &written, TRUE); + } + + if (!ret || (to_write != written)) { nt_error("WriteFile", file, isc_io_write_err, status_vector); break; @@ -548,7 +558,9 @@ jrd_file* PIO_open(thread_db* tdbb, } } +#ifndef _USING_V110_SDK71_ SetFileCompletionNotificationModes(desc, FILE_SKIP_SET_EVENT_ON_HANDLE); +#endif return setup_file(dbb, string, desc, readOnly, shareMode); } @@ -580,13 +592,16 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page, HANDLE desc = file->fil_desc; DWORD actual_length; - DWORD ret = ReadFile(desc, page, size, NULL, &overlapped); - if (!GetOverlappedResult(desc, &overlapped, &actual_length, TRUE) || - actual_length != size) + BOOL ret = ReadFile(desc, page, size, &actual_length, &overlapped); + if (!ret) { - return nt_error("ReadFile", file, isc_io_read_err, status_vector); + if (GetLastError() == ERROR_IO_PENDING) + ret = GetOverlappedResult(desc, &overlapped, &actual_length, TRUE); } + if (!ret || (size != actual_length)) + return nt_error("ReadFile", file, isc_io_read_err, status_vector); + return true; } @@ -755,12 +770,16 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page, HANDLE desc = file->fil_desc; DWORD actual_length; - DWORD ret = WriteFile(desc, page, size, NULL, &overlapped); - if (!GetOverlappedResult(desc, &overlapped, &actual_length, TRUE) || actual_length != size ) + BOOL ret = WriteFile(desc, page, size, &actual_length, &overlapped); + if (!ret) { - return nt_error("WriteFile", file, isc_io_write_err, status_vector); + if (GetLastError() == ERROR_IO_PENDING) + ret = GetOverlappedResult(desc, &overlapped, &actual_length, TRUE); } + if (!ret || (size != actual_length)) + return nt_error("WriteFile", file, isc_io_write_err, status_vector); + return true; } @@ -925,7 +944,10 @@ static bool nt_error(const TEXT* string, Arg::StatusVector status; status << Arg::Gds(isc_io_error) << Arg::Str(string) << Arg::Str(file->fil_string) << Arg::Gds(operation); - if (lastError != ERROR_SUCCESS) + + // Caller must already handle ERROR_IO_PENDING by calling GetOverlappedResult(). + // Since GetOverlappedResult() not clears last error - ignore it here. + if (lastError != ERROR_SUCCESS && lastError != ERROR_IO_PENDING) status << Arg::Windows(lastError); if (!status_vector) diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 771713c7fc4..ca4e993974d 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -1100,7 +1100,8 @@ void PAG_header(thread_db* tdbb, bool info) fb_assert(attachment); WIN window(HEADER_PAGE_NUMBER); - header_page* header = (header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header); + pag* page = CCH_FETCH(tdbb, &window, LCK_read, pag_header); + header_page* header = (header_page*) page; try { @@ -1220,6 +1221,30 @@ void PAG_header(thread_db* tdbb, bool info) fb_assert(false); } + // If database in backup lock state... + if (!info && dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal) + { + // refetch some data from the header, because it could be changed in the delta file + // (as initially PAG_init2 reads the header from the main file and these values + // may be outdated there) + for (const UCHAR* p = header->hdr_data; *p != HDR_end; p += 2u + p[1]) + { + switch (*p) + { + case HDR_sweep_interval: + fb_assert(p[1] == sizeof(SLONG)); + memcpy(&dbb->dbb_sweep_interval, p + 2, sizeof(SLONG)); + break; + + case HDR_repl_seq: + fb_assert(p[1] == sizeof(FB_UINT64)); + memcpy(&dbb->dbb_repl_sequence, p + 2, sizeof(FB_UINT64)); + break; + + } + } + } + } // try catch (const Exception&) { @@ -1261,10 +1286,13 @@ void PAG_header_init(thread_db* tdbb) // and unit of transfer is a multiple of physical disk // sector for raw disk access. - UCHAR temp_buffer[RAW_HEADER_SIZE + PAGE_ALIGNMENT]; - UCHAR* const temp_page = FB_ALIGN(temp_buffer, PAGE_ALIGNMENT); + const ULONG ioBlockSize = dbb->getIOBlockSize(); + const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize); + + HalfStaticArray temp; + UCHAR* const temp_page = temp.getAlignedBuffer(headerSize, ioBlockSize); - PIO_header(tdbb, temp_page, RAW_HEADER_SIZE); + PIO_header(tdbb, temp_page, headerSize); const header_page* header = (header_page*) temp_page; if (header->hdr_header.pag_type != pag_header || header->hdr_sequence) @@ -1377,8 +1405,7 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number) // the temporary page buffer for raw disk access. Array temp; - UCHAR* const temp_page = - FB_ALIGN(temp.getBuffer(dbb->dbb_page_size + PAGE_ALIGNMENT), PAGE_ALIGNMENT); + UCHAR* const temp_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize()); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); jrd_file* file = pageSpace->file; @@ -2603,7 +2630,7 @@ ULONG PAG_page_count(thread_db* tdbb) Database* const dbb = tdbb->getDatabase(); Array temp; page_inv_page* pip = reinterpret_cast - (FB_ALIGN(temp.getBuffer(dbb->dbb_page_size + PAGE_ALIGNMENT), PAGE_ALIGNMENT)); + (temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize())); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); fb_assert(pageSpace); diff --git a/src/jrd/par.cpp b/src/jrd/par.cpp index c0b47d81d91..d6bcaa0cef1 100644 --- a/src/jrd/par.cpp +++ b/src/jrd/par.cpp @@ -1694,17 +1694,7 @@ void PAR_warning(const Arg::StatusVector& v) * **************************************/ fb_assert(v.value()[0] == isc_arg_warning); - - thread_db* tdbb = JRD_get_thread_data(); - - // Make sure that the [1] position is 0 indicating that no error has occurred - Arg::Gds p(FB_SUCCESS); - - // Now place your warning messages - p.append(v); - - // Save into tdbb - p.copyTo(tdbb->tdbb_status_vector); + ERR_post_warning(v); } diff --git a/src/jrd/recsrc/BufferedStream.cpp b/src/jrd/recsrc/BufferedStream.cpp index 76a4cc58d7c..5bfad5b7fff 100644 --- a/src/jrd/recsrc/BufferedStream.cpp +++ b/src/jrd/recsrc/BufferedStream.cpp @@ -256,26 +256,29 @@ bool BufferedStream::getRecord(thread_db* tdbb) const VIO_record(tdbb, rpb, MET_current(tdbb, relation), tdbb->getDefaultPool()); } - Record* const record = rpb->rpb_record; - record->reset(); + const bool isNull = !EVL_field(relation, buffer_record, (USHORT) i, &from); - if (!EVL_field(relation, buffer_record, (USHORT) i, &from)) + if (map.map_type == FieldMap::REGULAR_FIELD) { - fb_assert(map.map_type == FieldMap::REGULAR_FIELD); - record->setNull(map.map_id); - continue; - } + Record* const record = rpb->rpb_record; + record->reset(); - switch (map.map_type) - { - case FieldMap::REGULAR_FIELD: + if (isNull) + record->setNull(map.map_id); + else { EVL_field(relation, record, map.map_id, &to); MOV_move(tdbb, &from, &to); record->clearNull(map.map_id); } - break; + continue; + } + + fb_assert(!isNull); + + switch (map.map_type) + { case FieldMap::TRANSACTION_ID: rpb->rpb_transaction_nr = *reinterpret_cast(from.dsc_address); break; diff --git a/src/jrd/recsrc/ConditionalStream.cpp b/src/jrd/recsrc/ConditionalStream.cpp index 91d3e854037..08344393b7b 100644 --- a/src/jrd/recsrc/ConditionalStream.cpp +++ b/src/jrd/recsrc/ConditionalStream.cpp @@ -53,9 +53,9 @@ void ConditionalStream::open(thread_db* tdbb) const jrd_req* const request = tdbb->getRequest(); Impure* const impure = request->getImpure(m_impure); - impure->irsb_flags = irsb_open; - impure->irsb_next = m_boolean->execute(tdbb, request) ? m_first : m_second; + + impure->irsb_flags = irsb_open; impure->irsb_next->open(tdbb); } @@ -71,7 +71,8 @@ void ConditionalStream::close(thread_db* tdbb) const { impure->irsb_flags &= ~irsb_open; - impure->irsb_next->close(tdbb); + if (impure->irsb_next) + impure->irsb_next->close(tdbb); } } diff --git a/src/jrd/recsrc/Cursor.cpp b/src/jrd/recsrc/Cursor.cpp index d8b44e516f6..0ce07dbe4e5 100644 --- a/src/jrd/recsrc/Cursor.cpp +++ b/src/jrd/recsrc/Cursor.cpp @@ -129,6 +129,9 @@ void Cursor::close(thread_db* tdbb) const bool Cursor::fetchNext(thread_db* tdbb) const { + if (m_scrollable) + return fetchRelative(tdbb, 1); + if (!validate(tdbb)) return false; @@ -142,43 +145,17 @@ bool Cursor::fetchNext(thread_db* tdbb) const } if (impure->irsb_state == EOS) - { - // error: cursor is past EOF - status_exception::raise(Arg::Gds(isc_stream_eof)); - } - else if (impure->irsb_state == BOS) - { - impure->irsb_position = 0; - } - else - { - impure->irsb_position++; - } + return false; - if (!m_scrollable) + if (!m_top->getRecord(tdbb)) { - if (!m_top->getRecord(tdbb)) - { - impure->irsb_state = EOS; - return false; - } - } - else - { - const BufferedStream* const buffer = static_cast(m_top); - buffer->locate(tdbb, impure->irsb_position); - - if (!buffer->getRecord(tdbb)) - { - impure->irsb_state = EOS; - return false; - } + impure->irsb_state = EOS; + return false; } request->req_records_selected++; request->req_records_affected.bumpFetched(); impure->irsb_state = POSITIONED; - return true; } @@ -190,47 +167,7 @@ bool Cursor::fetchPrior(thread_db* tdbb) const status_exception::raise(Arg::Gds(isc_invalid_fetch_option) << Arg::Str("PRIOR")); } - if (!validate(tdbb)) - return false; - - jrd_req* const request = tdbb->getRequest(); - Impure* const impure = request->getImpure(m_impure); - - if (!impure->irsb_active) - { - // error: invalid cursor state - status_exception::raise(Arg::Gds(isc_cursor_not_open)); - } - - const BufferedStream* const buffer = static_cast(m_top); - - if (impure->irsb_state == BOS) - { - // error: cursor is prior BOF - status_exception::raise(Arg::Gds(isc_stream_bof)); - } - else if (impure->irsb_state == EOS) - { - impure->irsb_position = buffer->getCount(tdbb) - 1; - } - else - { - impure->irsb_position--; - } - - buffer->locate(tdbb, impure->irsb_position); - - if (!buffer->getRecord(tdbb)) - { - impure->irsb_state = BOS; - return false; - } - - request->req_records_selected++; - request->req_records_affected.bumpFetched(); - impure->irsb_state = POSITIONED; - - return true; + return fetchRelative(tdbb, -1); } bool Cursor::fetchFirst(thread_db* tdbb) const @@ -283,12 +220,25 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const const auto buffer = static_cast(m_top); const auto count = buffer->getCount(tdbb); + const SINT64 position = (offset > 0) ? offset - 1 : count + offset; - impure->irsb_position = (offset > 0) ? offset - 1 : count + offset; + if (position < 0) + { + impure->irsb_state = BOS; + return false; + } + else if (position >= (SINT64) count) + { + impure->irsb_state = EOS; + return false; + } + + impure->irsb_position = position; buffer->locate(tdbb, impure->irsb_position); if (!buffer->getRecord(tdbb)) { + fb_assert(false); // this should not happen impure->irsb_state = (offset > 0) ? EOS : BOS; return false; } @@ -296,7 +246,6 @@ bool Cursor::fetchAbsolute(thread_db* tdbb, SINT64 offset) const request->req_records_selected++; request->req_records_affected.bumpFetched(); impure->irsb_state = POSITIONED; - return true; } @@ -321,36 +270,48 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const } if (!offset) - { return (impure->irsb_state == POSITIONED); - } const auto buffer = static_cast(m_top); const auto count = buffer->getCount(tdbb); + SINT64 position = impure->irsb_position; if (impure->irsb_state == BOS) { if (offset < 0) return false; - impure->irsb_position = offset - 1; + position = offset - 1; } else if (impure->irsb_state == EOS) { if (offset > 0) return false; - impure->irsb_position = count + offset; + position = count + offset; } else { - impure->irsb_position += offset; + position += offset; } + if (position < 0) + { + impure->irsb_state = BOS; + return false; + } + else if (position >= (SINT64) count) + { + impure->irsb_state = EOS; + return false; + } + + impure->irsb_position = position; buffer->locate(tdbb, impure->irsb_position); if (!buffer->getRecord(tdbb)) { + fb_assert(false); // this should not happen impure->irsb_state = (offset > 0) ? EOS : BOS; return false; } @@ -358,7 +319,6 @@ bool Cursor::fetchRelative(thread_db* tdbb, SINT64 offset) const request->req_records_selected++; request->req_records_affected.bumpFetched(); impure->irsb_state = POSITIONED; - return true; } diff --git a/src/jrd/recsrc/FullTableScan.cpp b/src/jrd/recsrc/FullTableScan.cpp index d8096fea15b..b46eeff9bb0 100644 --- a/src/jrd/recsrc/FullTableScan.cpp +++ b/src/jrd/recsrc/FullTableScan.cpp @@ -145,14 +145,10 @@ bool FullTableScan::getRecord(thread_db* tdbb) const return false; } - if (VIO_next_record(tdbb, rpb, request->req_transaction, request->req_pool, false)) - { - if (impure->irsb_upper.isValid() && rpb->rpb_number > impure->irsb_upper) - { - rpb->rpb_number.setValid(false); - return false; - } + const RecordNumber* upper = impure->irsb_upper.isValid() ? &impure->irsb_upper : nullptr; + if (VIO_next_record(tdbb, rpb, request->req_transaction, request->req_pool, false, upper)) + { rpb->rpb_number.setValid(true); return true; } diff --git a/src/jrd/recsrc/IndexTableScan.cpp b/src/jrd/recsrc/IndexTableScan.cpp index f281cc00242..ab4ee8c7c8a 100644 --- a/src/jrd/recsrc/IndexTableScan.cpp +++ b/src/jrd/recsrc/IndexTableScan.cpp @@ -71,6 +71,12 @@ void IndexTableScan::open(thread_db* tdbb) const RLCK_reserve_relation(tdbb, request->req_transaction, m_relation, false); rpb->rpb_number.setValue(BOF_NUMBER); + + fb_assert(!impure->irsb_nav_lower); + impure->irsb_nav_current_lower = impure->irsb_nav_lower = FB_NEW_POOL(*tdbb->getDefaultPool()) temporary_key; + + fb_assert(!impure->irsb_nav_upper); + impure->irsb_nav_current_upper = impure->irsb_nav_upper = FB_NEW_POOL(*tdbb->getDefaultPool()) temporary_key; } void IndexTableScan::close(thread_db* tdbb) const @@ -100,14 +106,28 @@ void IndexTableScan::close(thread_db* tdbb) const if (impure->irsb_nav_btr_gc_lock) { #ifdef DEBUG_LCK_LIST - if (!impure->irsb_nav_page) - gds__log("DEBUG_LCK_LIST: irsb_nav_btr_gc_lock && !irsb_nav_page"); + if (!impure->irsb_nav_page && impure->irsb_nav_btr_gc_lock->isActive()) + gds__log("DEBUG_LCK_LIST: irsb_nav_btr_gc_lock->isActive() && !irsb_nav_page"); #endif - impure->irsb_nav_btr_gc_lock->enablePageGC(tdbb); + if (impure->irsb_nav_btr_gc_lock->isActive()) + impure->irsb_nav_btr_gc_lock->enablePageGC(tdbb); + delete impure->irsb_nav_btr_gc_lock; impure->irsb_nav_btr_gc_lock = NULL; } impure->irsb_nav_page = 0; + + if (impure->irsb_nav_lower) + { + delete impure->irsb_nav_lower; + impure->irsb_nav_current_lower = impure->irsb_nav_lower = NULL; + } + + if (impure->irsb_nav_upper) + { + delete impure->irsb_nav_upper; + impure->irsb_nav_current_upper = impure->irsb_nav_upper = NULL; + } } #ifdef DEBUG_LCK_LIST // paranoid check @@ -115,7 +135,9 @@ void IndexTableScan::close(thread_db* tdbb) const { gds__log("DEBUG_LCK_LIST: irsb_nav_btr_gc_lock && !(irsb_flags & irsb_open)"); - impure->irsb_nav_btr_gc_lock->enablePageGC(tdbb); + if (impure->irsb_nav_btr_gc_lock->isActive()) + impure->irsb_nav_btr_gc_lock->enablePageGC(tdbb); + delete impure->irsb_nav_btr_gc_lock; impure->irsb_nav_btr_gc_lock = NULL; impure->irsb_nav_page = 0; @@ -143,120 +165,137 @@ bool IndexTableScan::getRecord(thread_db* tdbb) const setPage(tdbb, impure, NULL); } + // If this is the first time, start at the beginning + if (!impure->irsb_nav_page) + { + // initialize for a retrieval + if (!setupBitmaps(tdbb, impure)) + { + rpb->rpb_number.setValid(false); + return false; + } + } + index_desc* const idx = (index_desc*) ((SCHAR*) impure + m_offset); // find the last fetched position from the index const USHORT pageSpaceID = m_relation->getPages(tdbb)->rel_pg_space_id; win window(pageSpaceID, impure->irsb_nav_page); - UCHAR* nextPointer = getPosition(tdbb, impure, &window); - if (!nextPointer) - { - rpb->rpb_number.setValid(false); - return false; - } - - temporary_key key; - memcpy(key.key_data, impure->irsb_nav_data, impure->irsb_nav_length); - const IndexRetrieval* const retrieval = m_index->retrieval; const USHORT flags = retrieval->irb_generic & (irb_descending | irb_partial | irb_starting); - // set the upper (or lower) limit for navigational retrieval - temporary_key upper; - if (retrieval->irb_upper_count) - { - upper.key_length = impure->irsb_nav_upper_length; - memcpy(upper.key_data, impure->irsb_nav_data + m_length, upper.key_length); - } - - // Find the next interesting node. If necessary, skip to the next page. - RecordNumber number; - IndexNode node; - while (true) + do { - Ods::btree_page* page = (Ods::btree_page*) window.win_buffer; - - UCHAR* pointer = nextPointer; - if (pointer) + UCHAR* nextPointer = getPosition(tdbb, impure, &window); + if (!nextPointer) { - node.readNode(pointer, true); - number = node.recordNumber; + rpb->rpb_number.setValid(false); + return false; } - if (node.isEndLevel) - break; + temporary_key key; + memcpy(key.key_data, impure->irsb_nav_data, impure->irsb_nav_length); - if (node.isEndBucket) + // set the upper (or lower) limit for navigational retrieval + temporary_key upper; + if (retrieval->irb_upper_count) { - page = (Ods::btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); - nextPointer = page->btr_nodes + page->btr_jump_size; - continue; + upper.key_length = impure->irsb_nav_upper_length; + memcpy(upper.key_data, impure->irsb_nav_data + m_length, upper.key_length); } - // Build the current key value from the prefix and current node data. - memcpy(key.key_data + node.prefix, node.data, node.length); - key.key_length = node.length + node.prefix; - - // Make sure we haven't hit the upper (or lower) limit. - if (retrieval->irb_upper_count && - compareKeys(idx, key.key_data, key.key_length, &upper, flags) > 0) + // Find the next interesting node. If necessary, skip to the next page. + RecordNumber number; + IndexNode node; + while (true) { - break; - } + Ods::btree_page* page = (Ods::btree_page*) window.win_buffer; - // skip this record if: - // 1) there is an inversion tree for this index and this record - // is not in the bitmap for the inversion, or - // 2) the record has already been visited + UCHAR* pointer = nextPointer; + if (pointer) + { + node.readNode(pointer, true); + number = node.recordNumber; + } - if ((!(impure->irsb_flags & irsb_mustread) && - (!impure->irsb_nav_bitmap || - !RecordBitmap::test(*impure->irsb_nav_bitmap, number.getValue()))) || - RecordBitmap::test(impure->irsb_nav_records_visited, number.getValue())) - { - nextPointer = node.readNode(pointer, true); - continue; - } + if (node.isEndLevel) + break; - // reset the current navigational position in the index - rpb->rpb_number = number; - setPosition(tdbb, impure, rpb, &window, pointer, key); + if (node.isEndBucket) + { + page = (Ods::btree_page*) CCH_HANDOFF(tdbb, &window, page->btr_sibling, LCK_read, pag_index); + nextPointer = page->btr_nodes + page->btr_jump_size; + continue; + } - CCH_RELEASE(tdbb, &window); + // Build the current key value from the prefix and current node data. + memcpy(key.key_data + node.prefix, node.data, node.length); + key.key_length = node.length + node.prefix; - if (VIO_get(tdbb, rpb, request->req_transaction, request->req_pool)) - { - temporary_key value; + // Make sure we haven't hit the upper (or lower) limit. + if (retrieval->irb_upper_count && + compareKeys(idx, key.key_data, key.key_length, &upper, flags) > 0) + { + break; + } - const idx_e result = BTR_key(tdbb, m_relation, rpb->rpb_record, idx, &value, false); + // skip this record if: + // 1) there is an inversion tree for this index and this record + // is not in the bitmap for the inversion, or + // 2) the record has already been visited - if (result != idx_e_ok) + if ((!(impure->irsb_flags & irsb_mustread) && + (!impure->irsb_nav_bitmap || + !RecordBitmap::test(*impure->irsb_nav_bitmap, number.getValue()))) || + RecordBitmap::test(impure->irsb_nav_records_visited, number.getValue())) { - IndexErrorContext context(m_relation, idx); - context.raise(tdbb, result, rpb->rpb_record); + nextPointer = node.readNode(pointer, true); + continue; } - if (!compareKeys(idx, key.key_data, key.key_length, &value, 0)) + // reset the current navigational position in the index + rpb->rpb_number = number; + setPosition(tdbb, impure, rpb, &window, pointer, key); + + CCH_RELEASE(tdbb, &window); + + if (VIO_get(tdbb, rpb, request->req_transaction, request->req_pool)) { - // mark in the navigational bitmap that we have visited this record - RBM_SET(tdbb->getDefaultPool(), &impure->irsb_nav_records_visited, - rpb->rpb_number.getValue()); + temporary_key value; + + const idx_e result = BTR_key(tdbb, m_relation, rpb->rpb_record, idx, &value, + ((idx->idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT)); - rpb->rpb_number.setValid(true); - return true; + if (result != idx_e_ok) + { + IndexErrorContext context(m_relation, idx); + context.raise(tdbb, result, rpb->rpb_record); + } + + if (!compareKeys(idx, key.key_data, key.key_length, &value, 0)) + { + // mark in the navigational bitmap that we have visited this record + RBM_SET(tdbb->getDefaultPool(), &impure->irsb_nav_records_visited, + rpb->rpb_number.getValue()); + + rpb->rpb_number.setValid(true); + return true; + } } - } - nextPointer = getPosition(tdbb, impure, &window); - if (!nextPointer) - { - rpb->rpb_number.setValid(false); - return false; + nextPointer = getPosition(tdbb, impure, &window); + if (!nextPointer) + { + rpb->rpb_number.setValid(false); + return false; + } } - } - CCH_RELEASE(tdbb, &window); + CCH_RELEASE(tdbb, &window); + + advanceStream(tdbb, impure, &window); + } while (true); // bof or eof must have been set at this point rpb->rpb_number.setValid(false); @@ -461,14 +500,34 @@ bool IndexTableScan::findSavedNode(thread_db* tdbb, Impure* impure, win* window, } } +void IndexTableScan::advanceStream(thread_db* tdbb, Impure* impure, win* window) const +{ + impure->irsb_nav_current_lower = impure->irsb_nav_current_lower->key_next.get(); + impure->irsb_nav_current_upper = impure->irsb_nav_current_upper->key_next.get(); + setPage(tdbb, impure, NULL); + window->win_page = 0; +} + UCHAR* IndexTableScan::getPosition(thread_db* tdbb, Impure* impure, win* window) const { - // If this is the first time, start at the beginning - if (!window->win_page.getPageNum()) + while (impure->irsb_nav_current_lower) { - return openStream(tdbb, impure, window); + UCHAR* position = getStreamPosition(tdbb, impure, window); + + if (position) + return position; + + advanceStream(tdbb, impure, window); } + return NULL; +} + +UCHAR* IndexTableScan::getStreamPosition(thread_db* tdbb, Impure* impure, win* window) const +{ + if (!window->win_page.getPageNum()) + return openStream(tdbb, impure, window); + // Re-fetch page and get incarnation counter Ods::btree_page* page = (Ods::btree_page*) CCH_FETCH(tdbb, window, LCK_read, pag_index); @@ -505,18 +564,19 @@ UCHAR* IndexTableScan::getPosition(thread_db* tdbb, Impure* impure, win* window) UCHAR* IndexTableScan::openStream(thread_db* tdbb, Impure* impure, win* window) const { - // initialize for a retrieval - if (!setupBitmaps(tdbb, impure)) - return NULL; + temporary_key* lower = impure->irsb_nav_current_lower; + temporary_key* upper = impure->irsb_nav_current_upper; + const bool firstKeys = lower == impure->irsb_nav_lower; setPage(tdbb, impure, NULL); impure->irsb_nav_length = 0; + USHORT dummy = 0; // exclude upper/lower bits are not used here, + // i.e. additional forced include not needed // Find the starting leaf page const IndexRetrieval* const retrieval = m_index->retrieval; index_desc* const idx = (index_desc*) ((SCHAR*) impure + m_offset); - temporary_key lower, upper; - Ods::btree_page* page = BTR_find_page(tdbb, retrieval, window, idx, &lower, &upper); + Ods::btree_page* page = BTR_find_page(tdbb, retrieval, window, idx, lower, upper, dummy, firstKeys); setPage(tdbb, impure, window); // find the upper limit for the search @@ -526,12 +586,12 @@ UCHAR* IndexTableScan::openStream(thread_db* tdbb, Impure* impure, win* window) // If upper key length is greater than declared key length, we need // one "excess" byte for correct comparison. Without it there could // be false equality hits. - impure->irsb_nav_upper_length = MIN(m_length + 1, upper.key_length); - memcpy(impure->irsb_nav_data + m_length, upper.key_data, impure->irsb_nav_upper_length); + impure->irsb_nav_upper_length = MIN(m_length + 1, upper->key_length); + memcpy(impure->irsb_nav_data + m_length, upper->key_data, impure->irsb_nav_upper_length); } if (retrieval->irb_lower_count) - limit_ptr = &lower; + limit_ptr = lower; // If there is a starting descriptor, search down index to starting position. // This may involve sibling buckets if splits are in progress. If there @@ -587,6 +647,10 @@ void IndexTableScan::setPage(thread_db* tdbb, Impure* impure, win* window) const } impure->irsb_nav_page = newPage; + + // clear position as page was changed + impure->irsb_nav_incarnation = 0; + impure->irsb_nav_offset = 0; } } @@ -599,8 +663,10 @@ void IndexTableScan::setPosition(thread_db* tdbb, { // We can actually set position without having a data page // fetched; if not, just set the incarnation to the lowest possible - impure->irsb_nav_incarnation = CCH_get_incarnation(window); + // Note, setPage could clear position (incarnation and offset). + setPage(tdbb, impure, window); + impure->irsb_nav_incarnation = CCH_get_incarnation(window); impure->irsb_nav_number = rpb->rpb_number; // save the current key value diff --git a/src/jrd/recsrc/ProcedureScan.cpp b/src/jrd/recsrc/ProcedureScan.cpp index e80cd642f4e..b11ac840ef2 100644 --- a/src/jrd/recsrc/ProcedureScan.cpp +++ b/src/jrd/recsrc/ProcedureScan.cpp @@ -61,6 +61,12 @@ void ProcedureScan::open(thread_db* tdbb) const Arg::Gds(isc_proc_pack_not_implemented) << Arg::Str(m_procedure->getName().identifier) << Arg::Str(m_procedure->getName().package)); } + else if (!m_procedure->isDefined()) + { + status_exception::raise( + Arg::Gds(isc_prcnotdef) << Arg::Str(m_procedure->getName().toString()) << + Arg::Gds(isc_modnotfound)); + } const_cast(m_procedure)->checkReload(tdbb); @@ -108,7 +114,7 @@ void ProcedureScan::open(thread_db* tdbb) const try { - proc_request->req_gmt_timestamp = request->req_gmt_timestamp; + proc_request->setGmtTimeStamp(request->getGmtTimeStamp()); TraceProcExecute trace(tdbb, proc_request, request, m_targetList); diff --git a/src/jrd/recsrc/RecordSource.h b/src/jrd/recsrc/RecordSource.h index 7c4897822be..6e973ebedd7 100644 --- a/src/jrd/recsrc/RecordSource.h +++ b/src/jrd/recsrc/RecordSource.h @@ -205,6 +205,10 @@ namespace Jrd RecordBitmap** irsb_nav_bitmap; // bitmap for inversion tree RecordBitmap* irsb_nav_records_visited; // bitmap of records already retrieved BtrPageGCLock* irsb_nav_btr_gc_lock; // lock to prevent removal of currently walked index page + temporary_key* irsb_nav_lower; // lower (possible multiple) key + temporary_key* irsb_nav_upper; // upper (possible multiple) key + temporary_key* irsb_nav_current_lower; // current lower key + temporary_key* irsb_nav_current_upper; // current upper key USHORT irsb_nav_offset; // page offset of current index node USHORT irsb_nav_upper_length; // length of upper key value USHORT irsb_nav_length; // length of expanded key @@ -234,7 +238,9 @@ namespace Jrd private: int compareKeys(const index_desc*, const UCHAR*, USHORT, const temporary_key*, USHORT) const; bool findSavedNode(thread_db* tdbb, Impure* impure, win* window, UCHAR**) const; + void advanceStream(thread_db* tdbb, Impure* impure, win* window) const; UCHAR* getPosition(thread_db* tdbb, Impure* impure, win* window) const; + UCHAR* getStreamPosition(thread_db* tdbb, Impure* impure, win* window) const; UCHAR* openStream(thread_db* tdbb, Impure* impure, win* window) const; void setPage(thread_db* tdbb, Impure* impure, win* window) const; void setPosition(thread_db* tdbb, Impure* impure, record_param*, @@ -664,6 +670,15 @@ namespace Jrd return savedPosition; } + void restore() + { + if (!moved) + return; + + // Position the stream where we received it. + moveWithinPartition(0); + } + bool moveWithinPartition(SINT64 delta); bool moveWithinFrame(SINT64 delta); @@ -675,7 +690,7 @@ namespace Jrd FB_UINT64 frameStart; FB_UINT64 frameEnd; FB_UINT64 savedPosition; - bool moved; + bool moved = false; }; template @@ -790,6 +805,10 @@ namespace Jrd class WindowedStream : public RecordSource { public: + using Frame = WindowClause::Frame; + using FrameExtent = WindowClause::FrameExtent; + using Exclusion = WindowClause::Exclusion; + class WindowStream : public BaseAggWinStream { private: @@ -839,8 +858,8 @@ namespace Jrd WindowStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream, const NestValueArray* group, BaseBufferedStream* next, SortNode* order, MapNode* windowMap, - WindowClause::FrameExtent* frameExtent, - WindowClause::Exclusion exclusion); + FrameExtent* frameExtent, + Exclusion exclusion); public: void open(thread_db* tdbb) const; @@ -860,19 +879,19 @@ namespace Jrd private: const void getFrameValue(thread_db* tdbb, jrd_req* request, - const WindowClause::Frame* frame, impure_value_ex* impureValue) const; + const Frame* frame, impure_value_ex* impureValue) const; SINT64 locateFrameRange(thread_db* tdbb, jrd_req* request, Impure* impure, - const WindowClause::Frame* frame, const dsc* offsetDesc, SINT64 position) const; + const Frame* frame, const dsc* offsetDesc, SINT64 position) const; private: NestConst m_order; const MapNode* m_windowMap; - NestConst m_frameExtent; + NestConst m_frameExtent; Firebird::Array > m_arithNodes; NestValueArray m_aggSources, m_aggTargets; NestValueArray m_winPassSources, m_winPassTargets; - WindowClause::Exclusion m_exclusion; + Exclusion m_exclusion; UCHAR m_invariantOffsets; // 0x1 | 0x2 bitmask }; diff --git a/src/jrd/recsrc/SortedStream.cpp b/src/jrd/recsrc/SortedStream.cpp index d53873e4b22..9357d62f3a6 100644 --- a/src/jrd/recsrc/SortedStream.cpp +++ b/src/jrd/recsrc/SortedStream.cpp @@ -381,8 +381,9 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const if (!refetchStreams.exist(item.stream)) refetchStreams.add(item.stream); } - else // delay refetch until really necessary - rpb->rpb_runtime_flags |= RPB_refetch; + + // Ensure records are also refetched before update/delete + rpb->rpb_runtime_flags |= RPB_refetch; } continue; @@ -432,7 +433,9 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const const auto relation = rpb->rpb_relation; // Ensure the record is still in the most recent format - VIO_record(tdbb, rpb, MET_current(tdbb, relation), tdbb->getDefaultPool()); + const auto format = MET_current(tdbb, relation); + VIO_record(tdbb, rpb, format, tdbb->getDefaultPool()); + rpb->rpb_format_number = format->fmt_version; // Set all fields to NULL if the stream was originally marked as invalid if (!rpb->rpb_number.isValid()) @@ -448,34 +451,42 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const fb_assert(transaction); const auto selfTraNum = transaction->tra_number; + const auto orgTraNum = rpb->rpb_transaction_nr; + // Code underneath is a slightly customized version of VIO_refetch_record, // because in the case of deleted record followed by a commit we should // find the original version (or die trying). - const auto orgTraNum = rpb->rpb_transaction_nr; + auto temp = *rpb; + temp.rpb_record = nullptr; + AutoPtr cleanupRecord; // If the primary record version disappeared, we cannot proceed - if (!DPM_get(tdbb, rpb, LCK_read)) + if (!DPM_get(tdbb, &temp, LCK_read)) Arg::Gds(isc_no_cur_rec).raise(); - tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, rpb->rpb_relation->rel_id); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_RPT_READS, relation->rel_id); - if (VIO_chase_record_version(tdbb, rpb, transaction, tdbb->getDefaultPool(), false, false)) + if (VIO_chase_record_version(tdbb, &temp, transaction, tdbb->getDefaultPool(), false, false)) { - if (!(rpb->rpb_runtime_flags & RPB_undo_data)) - VIO_data(tdbb, rpb, tdbb->getDefaultPool()); + if (!(temp.rpb_runtime_flags & RPB_undo_data)) + VIO_data(tdbb, &temp, tdbb->getDefaultPool()); - if (rpb->rpb_transaction_nr == orgTraNum && orgTraNum != selfTraNum) + cleanupRecord = temp.rpb_record; + + VIO_copy_record(tdbb, &temp, rpb); + + if (temp.rpb_transaction_nr == orgTraNum && orgTraNum != selfTraNum) continue; // we surely see the original record version } - else if (!(rpb->rpb_flags & rpb_deleted)) + else if (!(temp.rpb_flags & rpb_deleted)) Arg::Gds(isc_no_cur_rec).raise(); - if (rpb->rpb_transaction_nr != selfTraNum) + if (temp.rpb_transaction_nr != selfTraNum) { // Ensure that somebody really touched this record - fb_assert(rpb->rpb_transaction_nr != orgTraNum); + fb_assert(temp.rpb_transaction_nr != orgTraNum); // and we discovered it in READ COMMITTED transaction fb_assert(transaction->tra_flags & TRA_read_committed); // and our transaction isn't READ CONSISTENCY one @@ -485,10 +496,10 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const // We have found a more recent record version. Unless it's a delete stub, // validate whether it's still suitable for the result set. - if (!(rpb->rpb_flags & rpb_deleted)) + if (!(temp.rpb_flags & rpb_deleted)) { - fb_assert(rpb->rpb_length != 0); - fb_assert(rpb->rpb_address != nullptr); + fb_assert(temp.rpb_length != 0); + fb_assert(temp.rpb_address != nullptr); // Record can be safely returned only if it has no fields // acting as sort keys or they haven't been changed @@ -509,7 +520,7 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const continue; const auto null1 = (*(data + item.flagOffset) == TRUE); - const auto null2 = !EVL_field(relation, rpb->rpb_record, item.fieldId, &from); + const auto null2 = !EVL_field(relation, temp.rpb_record, item.fieldId, &from); if (null1 != null2) { @@ -553,15 +564,12 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const // If it's our transaction who updated/deleted this record, punt. // We don't know how to find the original record version. - if (rpb->rpb_transaction_nr == selfTraNum) + if (temp.rpb_transaction_nr == selfTraNum) Arg::Gds(isc_no_cur_rec).raise(); // We have to find the original record version, sigh. // Scan version chain backwards until it's done. - auto temp = *rpb; - temp.rpb_record = nullptr; - RuntimeStatistics::Accumulator backversions(tdbb, relation, RuntimeStatistics::RECORD_BACKVERSION_READS); @@ -583,10 +591,11 @@ void SortedStream::mapData(thread_db* tdbb, jrd_req* request, UCHAR* data) const VIO_data(tdbb, &temp, tdbb->getDefaultPool()); + cleanupRecord.reset(temp.rpb_record); + ++backversions; } VIO_copy_record(tdbb, &temp, rpb); - delete temp.rpb_record; } } diff --git a/src/jrd/recsrc/WindowedStream.cpp b/src/jrd/recsrc/WindowedStream.cpp index d4e9412c03e..083d31f0cf2 100644 --- a/src/jrd/recsrc/WindowedStream.cpp +++ b/src/jrd/recsrc/WindowedStream.cpp @@ -28,6 +28,7 @@ #include "../jrd/exe_proto.h" #include "../jrd/par_proto.h" #include "RecordSource.h" +#include using namespace Firebird; using namespace Jrd; @@ -191,35 +192,27 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, // Process the unpartioned and unordered map, if existent. - for (ObjectsArray::iterator window = windows.begin(); - window != windows.end(); - ++window) + for (auto& window : windows) { // While here, verify not supported functions/clauses. - if (window->order) + if (window.order || window.frameExtent->unit == FrameExtent::Unit::ROWS) { - const NestConst* source = window->map->sourceList.begin(); - - for (const NestConst* const end = window->map->sourceList.end(); - source != end; - ++source) + for (const auto& source : window.map->sourceList) { - const AggNode* aggNode = nodeAs(*source); - - if (aggNode) + if (const auto aggNode = nodeAs(source)) { + const char* arg = nullptr; + if (aggNode->distinct) - { - status_exception::raise( - Arg::Gds(isc_wish_list) << - Arg::Gds(isc_random) << "DISTINCT is not supported in ordered windows"); - } + arg = "DISTINCT"; + else if (!(aggNode->getCapabilities() & AggNode::CAP_SUPPORTS_WINDOW_FRAME)) + arg = aggNode->aggInfo.name; - if (!(aggNode->getCapabilities() & AggNode::CAP_SUPPORTS_WINDOW_FRAME)) + if (arg) { string msg; - msg.printf("%s is not supported in ordered windows", aggNode->aggInfo.name); + msg.printf("%s is not supported in windows with ORDER BY or frame by ROWS clauses", arg); status_exception::raise( Arg::Gds(isc_wish_list) << @@ -229,15 +222,22 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, } } - if (!window->group && !window->order) + if (!window.group && !window.order) { - fb_assert(!m_joinedStream); - - m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window->stream, - NULL, FB_NEW_POOL(csb->csb_pool) BufferedStreamWindow(csb, m_next), - NULL, window->map, NULL, window->exclusion); + if (!m_joinedStream) + { + m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream, + nullptr, FB_NEW_POOL(csb->csb_pool) BufferedStreamWindow(csb, m_next), + nullptr, window.map, window.frameExtent, window.exclusion); + } + else + { + m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream, + nullptr, FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, m_joinedStream), + nullptr, window.map, window.frameExtent, window.exclusion); + } - OPT_gen_aggregate_distincts(tdbb, csb, window->map); + OPT_gen_aggregate_distincts(tdbb, csb, window.map); } } @@ -248,14 +248,8 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, StreamList streams; - for (ObjectsArray::iterator window = windows.begin(); - window != windows.end(); - ++window) + for (auto& window : windows) { - // Refresh the stream list based on the last m_joinedStream. - streams.clear(); - m_joinedStream->findUsedStreams(streams); - #if 0 //// FIXME: This causes problems, for example with FIRST_VALUE. //// I think it can be fixed with the help of SlidingWindow. @@ -263,10 +257,10 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, // between !{ following || unbounded preceding} and unbounded following if (window->frameExtent && - window->frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING && + window->frameExtent->frame2->bound == Frame::Bound::FOLLOWING && !window->frameExtent->frame2->value && - !(window->frameExtent->frame1->bound == WindowClause::Frame::Bound::FOLLOWING || - (window->frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING && + !(window->frameExtent->frame1->bound == Frame::Bound::FOLLOWING || + (window->frameExtent->frame1->bound == Frame::Bound::PRECEDING && !window->frameExtent->frame1->value))) { if (window->order) @@ -286,14 +280,14 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, } } - WindowClause::Frame* temp = window->frameExtent->frame1; + Frame* temp = window->frameExtent->frame1; window->frameExtent->frame1 = window->frameExtent->frame2; window->frameExtent->frame2 = temp; - window->frameExtent->frame1->bound = WindowClause::Frame::Bound::PRECEDING; + window->frameExtent->frame1->bound = Frame::Bound::PRECEDING; - if (window->frameExtent->frame2->bound == WindowClause::Frame::Bound::PRECEDING) - window->frameExtent->frame2->bound = WindowClause::Frame::Bound::FOLLOWING; + if (window->frameExtent->frame2->bound == Frame::Bound::PRECEDING) + window->frameExtent->frame2->bound = Frame::Bound::FOLLOWING; } #endif @@ -301,34 +295,38 @@ WindowedStream::WindowedStream(thread_db* tdbb, CompilerScratch* csb, SortNode* windowOrder; - if (window->group) + if (window.group) { windowOrder = FB_NEW_POOL(csb->csb_pool) SortNode(csb->csb_pool); - windowOrder->expressions.join(window->group->expressions); - windowOrder->direction.join(window->group->direction); - windowOrder->nullOrder.join(window->group->nullOrder); + windowOrder->expressions.join(window.group->expressions); + windowOrder->direction.join(window.group->direction); + windowOrder->nullOrder.join(window.group->nullOrder); - if (window->order) + if (window.order) { - windowOrder->expressions.join(window->order->expressions); - windowOrder->direction.join(window->order->direction); - windowOrder->nullOrder.join(window->order->nullOrder); + windowOrder->expressions.join(window.order->expressions); + windowOrder->direction.join(window.order->direction); + windowOrder->nullOrder.join(window.order->nullOrder); } } else - windowOrder = window->order; + windowOrder = window.order; if (windowOrder) { - SortedStream* sortedStream = OPT_gen_sort(tdbb, csb, streams, NULL, + // Refresh the stream list based on the last m_joinedStream. + streams.clear(); + m_joinedStream->findUsedStreams(streams); + + SortedStream* sortedStream = OPT_gen_sort(tdbb, csb, streams, nullptr, m_joinedStream, windowOrder, false, false); - m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window->stream, - (window->group ? &window->group->expressions : NULL), + m_joinedStream = FB_NEW_POOL(csb->csb_pool) WindowStream(tdbb, csb, window.stream, + (window.group ? &window.group->expressions : nullptr), FB_NEW_POOL(csb->csb_pool) BufferedStream(csb, sortedStream), - window->order, window->map, window->frameExtent, window->exclusion); + window.order, window.map, window.frameExtent, window.exclusion); - OPT_gen_aggregate_distincts(tdbb, csb, window->map); + OPT_gen_aggregate_distincts(tdbb, csb, window.map); } } } @@ -419,8 +417,8 @@ void WindowedStream::nullRecords(thread_db* tdbb) const WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb, StreamType stream, const NestValueArray* group, BaseBufferedStream* next, SortNode* order, MapNode* windowMap, - WindowClause::FrameExtent* frameExtent, - WindowClause::Exclusion exclusion) + FrameExtent* frameExtent, + Exclusion exclusion) : BaseAggWinStream(tdbb, csb, stream, group, NULL, false, next), m_order(order), m_windowMap(windowMap), @@ -470,12 +468,12 @@ WindowedStream::WindowStream::WindowStream(thread_db* tdbb, CompilerScratch* csb for (unsigned i = 0; i < 2; ++i) { - WindowClause::Frame* frame = i == 0 ? + Frame* frame = i == 0 ? m_frameExtent->frame1 : m_frameExtent->frame2; - if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && frame->value) + if (m_frameExtent->unit == FrameExtent::Unit::RANGE && frame->value) { - int direction = frame->bound == WindowClause::Frame::Bound::FOLLOWING ? 1 : -1; + int direction = frame->bound == Frame::Bound::FOLLOWING ? 1 : -1; if (m_order->direction[0] == ORDER_DESC) direction *= -1; @@ -605,37 +603,36 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const // Find the window start. - if (m_order && m_frameExtent->frame1->value && !(m_invariantOffsets & 0x1)) + if (m_frameExtent->frame1->value && !(m_invariantOffsets & 0x1)) getFrameValue(tdbb, request, m_frameExtent->frame1, &impure->startOffset); - if (!m_order) - impure->windowBlock.startPosition = impure->partitionBlock.startPosition; // {range | rows} between unbounded preceding and ... - else if (m_frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING && - !m_frameExtent->frame1->value) + // (no order by) range + if ((m_frameExtent->frame1->bound == Frame::Bound::PRECEDING && !m_frameExtent->frame1->value) || + (!m_order && m_frameExtent->unit == FrameExtent::Unit::RANGE)) { impure->windowBlock.startPosition = impure->partitionBlock.startPosition; } // rows between current row and ... - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS && - m_frameExtent->frame1->bound == WindowClause::Frame::Bound::CURRENT_ROW) + else if (m_frameExtent->unit == FrameExtent::Unit::ROWS && + m_frameExtent->frame1->bound == Frame::Bound::CURRENT_ROW) { impure->windowBlock.startPosition = position; } // rows between {preceding | following} and ... - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS && + else if (m_frameExtent->unit == FrameExtent::Unit::ROWS && m_frameExtent->frame1->value) { impure->windowBlock.startPosition = position + impure->startOffset.vlux_count; } // range between current row and ... - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && - m_frameExtent->frame1->bound == WindowClause::Frame::Bound::CURRENT_ROW) + else if (m_frameExtent->unit == FrameExtent::Unit::RANGE && + m_frameExtent->frame1->bound == Frame::Bound::CURRENT_ROW) { impure->windowBlock.startPosition = position; } // range between {preceding | following} and ... - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && + else if (m_frameExtent->unit == FrameExtent::Unit::RANGE && m_frameExtent->frame1->value) { impure->windowBlock.startPosition = locateFrameRange(tdbb, request, impure, @@ -649,32 +646,31 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const // Find the window end. - if (m_order && m_frameExtent->frame2->value && !(m_invariantOffsets & 0x2)) + if (m_frameExtent->frame2->value && !(m_invariantOffsets & 0x2)) getFrameValue(tdbb, request, m_frameExtent->frame2, &impure->endOffset); - if (!m_order) - impure->windowBlock.endPosition = impure->partitionBlock.endPosition; // {range | rows} between ... and unbounded following - else if (m_frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING && - !m_frameExtent->frame2->value) + // (no order by) range + if ((m_frameExtent->frame2->bound == Frame::Bound::FOLLOWING && !m_frameExtent->frame2->value) || + (!m_order && m_frameExtent->unit == FrameExtent::Unit::RANGE)) { impure->windowBlock.endPosition = impure->partitionBlock.endPosition; } // rows between ... and current row - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS && - m_frameExtent->frame2->bound == WindowClause::Frame::Bound::CURRENT_ROW) + else if (m_frameExtent->unit == FrameExtent::Unit::ROWS && + m_frameExtent->frame2->bound == Frame::Bound::CURRENT_ROW) { impure->windowBlock.endPosition = position; } // rows between ... and {preceding | following} - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS && + else if (m_frameExtent->unit == FrameExtent::Unit::ROWS && m_frameExtent->frame2->value) { impure->windowBlock.endPosition = position + impure->endOffset.vlux_count; } // range between ... and current row - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && - m_frameExtent->frame2->bound == WindowClause::Frame::Bound::CURRENT_ROW) + else if (m_frameExtent->unit == FrameExtent::Unit::RANGE && + m_frameExtent->frame2->bound == Frame::Bound::CURRENT_ROW) { SINT64 rangePos = position; cacheValues(tdbb, request, &m_order->expressions, impure->orderValues, @@ -700,7 +696,7 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const fb_assert(false); } // range between ... and {preceding | following} - else if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE && + else if (m_frameExtent->unit == FrameExtent::Unit::RANGE && m_frameExtent->frame2->value) { impure->windowBlock.endPosition = locateFrameRange(tdbb, request, impure, @@ -712,44 +708,38 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const return false; } - if (!m_order) + if ((m_frameExtent->frame1->bound == Frame::Bound::PRECEDING && !m_frameExtent->frame1->value && + m_frameExtent->frame2->bound == Frame::Bound::FOLLOWING && !m_frameExtent->frame2->value) || + (m_frameExtent->unit == FrameExtent::Unit::RANGE && !m_order)) + { impure->rangePending = MAX(0, impure->windowBlock.endPosition - position); - else if (m_order && m_frameExtent->unit == WindowClause::FrameExtent::Unit::RANGE) + } + else if (m_frameExtent->unit == FrameExtent::Unit::RANGE) { - if (m_frameExtent->frame1->bound == WindowClause::Frame::Bound::PRECEDING && - !m_frameExtent->frame1->value && - m_frameExtent->frame2->bound == WindowClause::Frame::Bound::FOLLOWING && - !m_frameExtent->frame2->value) - { - impure->rangePending = MAX(0, impure->windowBlock.endPosition - position); - } - else + SINT64 rangePos = position; + cacheValues(tdbb, request, &m_order->expressions, impure->orderValues, + DummyAdjustFunctor()); + + while (++rangePos <= impure->partitionBlock.endPosition) { - SINT64 rangePos = position; - cacheValues(tdbb, request, &m_order->expressions, impure->orderValues, - DummyAdjustFunctor()); + if (!m_next->getRecord(tdbb)) + fb_assert(false); - while (++rangePos <= impure->partitionBlock.endPosition) + if (lookForChange(tdbb, request, &m_order->expressions, m_order, + impure->orderValues)) { - if (!m_next->getRecord(tdbb)) - fb_assert(false); - - if (lookForChange(tdbb, request, &m_order->expressions, m_order, - impure->orderValues)) - { - break; - } + break; } - - impure->rangePending = rangePos - position - 1; } - m_next->locate(tdbb, position); - - if (!m_next->getRecord(tdbb)) - fb_assert(false); + impure->rangePending = rangePos - position - 1; } + m_next->locate(tdbb, position); + + if (!m_next->getRecord(tdbb)) + fb_assert(false); + //// TODO: There is no need to pass record by record when m_aggSources.isEmpty() if (!impure->windowBlock.isValid() || @@ -853,7 +843,7 @@ bool WindowedStream::WindowStream::getRecord(thread_db* tdbb) const record->clearNull(id); } - window.moveWithinPartition(0); + window.restore(); } } @@ -902,7 +892,7 @@ void WindowedStream::WindowStream::nullRecords(thread_db* tdbb) const } const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* request, - const WindowClause::Frame* frame, impure_value_ex* impureValue) const + const Frame* frame, impure_value_ex* impureValue) const { dsc* desc = EVL_expr(tdbb, request, frame->value); bool error = false; @@ -911,7 +901,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* error = true; else { - if (m_frameExtent->unit == WindowClause::FrameExtent::Unit::ROWS) + if (m_frameExtent->unit == FrameExtent::Unit::ROWS) { // Purposedly used 32-bit here. So long distance will complicate things for no gain. impureValue->vlux_count = MOV_get_long(tdbb, desc, 0); @@ -919,7 +909,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* if (impureValue->vlux_count < 0) error = true; - if (frame->bound == WindowClause::Frame::Bound::PRECEDING) + if (frame->bound == Frame::Bound::PRECEDING) impureValue->vlux_count = -impureValue->vlux_count; } else if (MOV_compare(tdbb, desc, &zeroDsc) < 0) @@ -937,7 +927,7 @@ const void WindowedStream::WindowStream::getFrameValue(thread_db* tdbb, jrd_req* } SINT64 WindowedStream::WindowStream::locateFrameRange(thread_db* tdbb, jrd_req* request, Impure* impure, - const WindowClause::Frame* frame, const dsc* offsetDesc, SINT64 position) const + const Frame* frame, const dsc* offsetDesc, SINT64 position) const { if (m_order->expressions.getCount() != 1) { @@ -983,7 +973,7 @@ SINT64 WindowedStream::WindowStream::locateFrameRange(thread_db* tdbb, jrd_req* --rangePos; } } - else if (frame->bound == WindowClause::Frame::Bound::FOLLOWING) + else if (frame->bound == Frame::Bound::FOLLOWING) { const int bound = frame == m_frameExtent->frame1 ? 0 : 1; @@ -1065,19 +1055,20 @@ SlidingWindow::SlidingWindow(thread_db* aTdbb, const BaseBufferedStream* aStream partitionStart(aPartitionStart), partitionEnd(aPartitionEnd), frameStart(aFrameStart), - frameEnd(aFrameEnd), - moved(false) + frameEnd(aFrameEnd) { savedPosition = stream->getPosition(request) - 1; } SlidingWindow::~SlidingWindow() { - if (!moved) - return; - - // Position the stream where we received it. - moveWithinPartition(0); +#ifdef DEV_BUILD +#if __cpp_lib_uncaught_exceptions >= 201411L + fb_assert(!moved || std::uncaught_exceptions()); +#else + fb_assert(!moved || std::uncaught_exception()); +#endif +#endif } // Move in the window without pass partition boundaries. @@ -1088,7 +1079,7 @@ bool SlidingWindow::moveWithinPartition(SINT64 delta) if (newPosition < partitionStart || newPosition > partitionEnd) return false; - moved = true; + moved = delta != 0; stream->locate(tdbb, newPosition); diff --git a/src/jrd/replication/Applier.cpp b/src/jrd/replication/Applier.cpp index 3b14b652b13..0589be24b3f 100644 --- a/src/jrd/replication/Applier.cpp +++ b/src/jrd/replication/Applier.cpp @@ -104,11 +104,17 @@ namespace UCHAR getByte() { + if (m_data >= m_end) + malformed(); + return *m_data++; } SSHORT getInt16() { + if (m_data + sizeof(SSHORT) > m_end) + malformed(); + SSHORT value; memcpy(&value, m_data, sizeof(SSHORT)); m_data += sizeof(SSHORT); @@ -117,6 +123,9 @@ namespace SLONG getInt32() { + if (m_data + sizeof(SLONG) > m_end) + malformed(); + SLONG value; memcpy(&value, m_data, sizeof(SLONG)); m_data += sizeof(SLONG); @@ -125,6 +134,9 @@ namespace SINT64 getInt64() { + if (m_data + sizeof(SINT64) > m_end) + malformed(); + SINT64 value; memcpy(&value, m_data, sizeof(SINT64)); m_data += sizeof(SINT64); @@ -140,6 +152,10 @@ namespace string getString() { const auto length = getInt32(); + + if (m_data + length > m_end) + malformed(); + const string str((const char*) m_data, length); m_data += length; return str; @@ -147,6 +163,9 @@ namespace const UCHAR* getBinary(ULONG length) { + if (m_data + length > m_end) + malformed(); + const auto ptr = m_data; m_data += length; return ptr; @@ -175,13 +194,19 @@ namespace const UCHAR* m_data; const UCHAR* const m_end; HalfStaticArray m_atoms; + + static void malformed() + { + raiseError("Replication block is malformed"); + } }; - class LocalThreadContext + class LocalThreadContext : Firebird::ContextPoolHolder { public: LocalThreadContext(thread_db* tdbb, jrd_tra* tra, jrd_req* req = NULL) - : m_tdbb(tdbb) + : Firebird::ContextPoolHolder(req ? req->req_pool : tdbb->getDefaultPool()), + m_tdbb(tdbb) { tdbb->setTransaction(tra); tdbb->setRequest(req); @@ -212,16 +237,30 @@ Applier* Applier::create(thread_db* tdbb) if (!attachment->locksmith(tdbb, REPLICATE_INTO_DATABASE)) status_exception::raise(Arg::Gds(isc_miss_prvlg) << "REPLICATE_INTO_DATABASE"); + jrd_req* request = nullptr; const auto req_pool = attachment->createPool(); - Jrd::ContextPoolHolder context(tdbb, req_pool); - AutoPtr csb(FB_NEW_POOL(*req_pool) CompilerScratch(*req_pool)); - const auto request = JrdStatement::makeRequest(tdbb, csb, true); - TimeZoneUtil::validateGmtTimeStamp(request->req_gmt_timestamp); - request->req_attachment = attachment; + try + { + Jrd::ContextPoolHolder context(tdbb, req_pool); + AutoPtr csb(FB_NEW_POOL(*req_pool) CompilerScratch(*req_pool)); + + request = JrdStatement::makeRequest(tdbb, csb, true); + request->validateTimeStamp(); + request->req_attachment = attachment; + } + catch (const Exception&) + { + if (request) + CMP_release(tdbb, request); + else + attachment->deletePool(req_pool); + + throw; + } - auto& att_pool = *attachment->att_pool; - const auto applier = FB_NEW_POOL(att_pool) Applier(att_pool, dbb->dbb_filename, request); + const auto applier = FB_NEW_POOL(*attachment->att_pool) + Applier(*attachment->att_pool, dbb->dbb_filename, request); attachment->att_repl_appliers.add(applier); return applier; @@ -229,23 +268,29 @@ Applier* Applier::create(thread_db* tdbb) void Applier::shutdown(thread_db* tdbb) { + const auto dbb = tdbb->getDatabase(); const auto attachment = tdbb->getAttachment(); - cleanupTransactions(tdbb); - - CMP_release(tdbb, m_request); + if (!(dbb->dbb_flags & DBB_bugcheck)) + { + cleanupTransactions(tdbb); + CMP_release(tdbb, m_request); + } m_request = NULL; m_record = NULL; m_bitmap->clear(); - attachment->att_repl_appliers.findAndRemove(this); + if (attachment) + attachment->att_repl_appliers.findAndRemove(this); if (m_interface) { m_interface->resetHandle(); m_interface = nullptr; } + + delete this; } void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) @@ -341,9 +386,13 @@ void Applier::process(thread_db* tdbb, ULONG length, const UCHAR* data) blob_id.bid_quad.bid_quad_high = reader.getInt32(); blob_id.bid_quad.bid_quad_low = reader.getInt32(); do { - const ULONG length = reader.getInt16(); + const ULONG length = (USHORT) reader.getInt16(); if (!length) + { + // Close our newly created blob + storeBlob(tdbb, traNum, &blob_id, 0, nullptr); break; + } const auto blob = reader.getBinary(length); storeBlob(tdbb, traNum, &blob_id, length, blob); } while (!reader.isEof()); @@ -470,7 +519,7 @@ void Applier::cleanupSavepoint(thread_db* tdbb, TraNumber traNum, bool undo) LocalThreadContext context(tdbb, transaction); - if (!transaction->tra_save_point) + if (!transaction->tra_save_point || transaction->tra_save_point->isRoot()) raiseError("Transaction %" SQUADFORMAT" has no savepoints to cleanup", traNum); if (undo) @@ -512,6 +561,8 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, rpb.rpb_length = length; record->copyDataFrom(data); + FbLocalStatus error; + try { doInsert(tdbb, &rpb, transaction); @@ -526,14 +577,55 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, throw; } + ex.stuffException(&error); fb_utils::init_status(tdbb->tdbb_status_vector); + + // The subsequent backout will delete the blobs we have stored before, + // so we have to copy them and adjust the references + for (USHORT id = 0; id < format->fmt_count; id++) + { + dsc desc; + if (DTYPE_IS_BLOB(format->fmt_desc[id].dsc_dtype) && + EVL_field(NULL, record, id, &desc)) + { + const auto blobId = (bid*) desc.dsc_address; + + if (!blobId->isEmpty()) + { + const auto numericId = blobId->get_permanent_number().getValue(); + const auto destination = blb::copy(tdbb, blobId); + transaction->tra_repl_blobs.put(numericId, destination.bid_temp_id()); + } + } + } + + // Undo this particular insert (without involving a savepoint) + VIO_backout(tdbb, &rpb, transaction); + + if (transaction->tra_save_point) + { + const auto action = transaction->tra_save_point->getAction(relation); + if (action && action->vct_records) + { + const auto recno = rpb.rpb_number.getValue(); + fb_assert(action->vct_records->test(recno)); + fb_assert(!action->vct_undo || !action->vct_undo->locate(recno)); + action->vct_records->clear(recno); + } + } } bool found = false; #ifdef RESOLVE_CONFLICTS + fb_assert(error[1] == isc_unique_key_violation || error[1] == isc_no_dup); + fb_assert(error[2] == isc_arg_string); + fb_assert(error[3] != 0); + + const char* idxName = reinterpret_cast(error[3]); + index_desc idx; - const auto indexed = lookupRecord(tdbb, relation, record, m_bitmap, idx); + const auto indexed = lookupRecord(tdbb, relation, record, m_bitmap, idx, idxName); AutoPtr cleanup; @@ -566,19 +658,21 @@ void Applier::insertRecord(thread_db* tdbb, TraNumber traNum, record_param newRpb; newRpb.rpb_relation = relation; - - newRpb.rpb_record = NULL; - AutoPtr newRecord(VIO_record(tdbb, &newRpb, format, m_request->req_pool)); - + newRpb.rpb_record = record; newRpb.rpb_format_number = format->fmt_version; - newRpb.rpb_address = newRecord->getData(); - newRpb.rpb_length = length; - newRecord->copyDataFrom(data); + newRpb.rpb_address = record->getData(); + newRpb.rpb_length = record->getLength(); doUpdate(tdbb, &rpb, &newRpb, transaction, NULL); } else { + fb_assert(rpb.rpb_record == record); + + rpb.rpb_format_number = format->fmt_version; + rpb.rpb_address = record->getData(); + rpb.rpb_length = record->getLength(); + doInsert(tdbb, &rpb, transaction); // second (paranoid) attempt } } @@ -828,15 +922,13 @@ void Applier::storeBlob(thread_db* tdbb, TraNumber traNum, bid* blobId, LocalThreadContext context(tdbb, transaction); - const auto orgBlobId = blobId->get_permanent_number().getValue(); - + ULONG tempBlobId; blb* blob = NULL; - ReplBlobMap::Accessor accessor(&transaction->tra_repl_blobs); - if (accessor.locate(orgBlobId)) - { - const auto tempBlobId = accessor.current()->second; + const auto numericId = blobId->get_permanent_number().getValue(); + if (transaction->tra_repl_blobs.get(numericId, tempBlobId)) + { if (transaction->tra_blobs->locate(tempBlobId)) { const auto current = &transaction->tra_blobs->current(); @@ -848,10 +940,12 @@ void Applier::storeBlob(thread_db* tdbb, TraNumber traNum, bid* blobId, { bid newBlobId; blob = blb::create(tdbb, transaction, &newBlobId); - transaction->tra_repl_blobs.put(orgBlobId, newBlobId.bid_temp_id()); + transaction->tra_repl_blobs.put(numericId, newBlobId.bid_temp_id()); } fb_assert(blob); + fb_assert(blob->blb_flags & BLB_temporary); + fb_assert(!(blob->blb_flags & BLB_closed)); if (length) blob->BLB_put_segment(tdbb, data, length); @@ -863,7 +957,7 @@ void Applier::executeSql(thread_db* tdbb, TraNumber traNum, unsigned charset, const string& sql, - const MetaName& owner) + const MetaName& ownerName) { jrd_tra* transaction = NULL; if (!m_txnMap.get(traNum, transaction)) @@ -877,11 +971,11 @@ void Applier::executeSql(thread_db* tdbb, const auto dialect = (dbb->dbb_flags & DBB_DB_SQL_dialect_3) ? SQL_DIALECT_V6 : SQL_DIALECT_V5; - UserId user(*attachment->att_user); - user.setUserName(owner); - AutoSetRestore autoCharset(&attachment->att_charset, charset); - AutoSetRestore autoOwner(&attachment->att_user, &user); + + UserId* const owner = attachment->getUserId(ownerName); + AutoSetRestore autoOwner(&attachment->att_ss_user, owner); + AutoSetRestore autoUser(&attachment->att_user, owner); DSQL_execute_immediate(tdbb, attachment, &transaction, 0, sql.c_str(), dialect, @@ -977,7 +1071,7 @@ bool Applier::compareKey(thread_db* tdbb, jrd_rel* relation, const index_desc& i bool Applier::lookupRecord(thread_db* tdbb, jrd_rel* relation, Record* record, RecordBitmap* bitmap, - index_desc& idx) + index_desc& idx, const char* idxName) { RecordBitmap::reset(bitmap); @@ -988,10 +1082,28 @@ bool Applier::lookupRecord(thread_db* tdbb, return false; } - if (lookupKey(tdbb, relation, idx)) + bool haveIdx = false; + if (idxName) + { + SLONG foundRelId; + IndexStatus idxStatus; + SLONG idx_id = MET_lookup_index_name(tdbb, idxName, &foundRelId, &idxStatus); + + fb_assert(idxStatus == MET_object_active); + fb_assert(foundRelId == relation->rel_id); + + haveIdx = (idxStatus == MET_object_active) && (foundRelId == relation->rel_id) && + BTR_lookup(tdbb, relation, idx_id, &idx, relation->getPages(tdbb)); + } + + if (!haveIdx) + haveIdx = lookupKey(tdbb, relation, idx); + + if (haveIdx) { temporary_key key; - const auto result = BTR_key(tdbb, relation, record, &idx, &key, false); + const auto result = BTR_key(tdbb, relation, record, &idx, &key, + (idx.idx_flags & idx_unique) ? INTL_KEY_UNIQUE : INTL_KEY_SORT); if (result != idx_e_ok) { IndexErrorContext context(relation, &idx); @@ -1099,13 +1211,13 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (!blobId->isEmpty()) { + ULONG tempBlobId; bool found = false; const auto numericId = blobId->get_permanent_number().getValue(); - ReplBlobMap::Accessor accessor(&transaction->tra_repl_blobs); - if (accessor.locate(numericId) && - transaction->tra_blobs->locate(accessor.current()->second)) + if (transaction->tra_repl_blobs.get(numericId, tempBlobId) && + transaction->tra_blobs->locate(tempBlobId)) { const auto current = &transaction->tra_blobs->current(); @@ -1120,7 +1232,6 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) current->bli_materialized = true; current->bli_blob_id = *blobId; transaction->tra_blobs->fastRemove(); - accessor.fastRemove(); found = true; } } @@ -1136,6 +1247,24 @@ void Applier::doInsert(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) } } + // Cleanup temporary blobs stored for this command beforehand but not materialized + + ReplBlobMap::ConstAccessor accessor(&transaction->tra_repl_blobs); + for (bool found = accessor.getFirst(); found; found = accessor.getNext()) + { + const auto tempBlobId = accessor.current()->second; + + if (transaction->tra_blobs->locate(tempBlobId)) + { + const auto current = &transaction->tra_blobs->current(); + + if (!current->bli_materialized) + current->bli_blob_object->BLB_cancel(tdbb); + } + } + + transaction->tra_repl_blobs.clear(); + Savepoint::ChangeMarker marker(transaction->tra_save_point); VIO_store(tdbb, rpb, transaction); @@ -1177,13 +1306,13 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR } else { + ULONG tempBlobId; bool found = false; const auto numericId = dstBlobId->get_permanent_number().getValue(); - ReplBlobMap::Accessor accessor(&transaction->tra_repl_blobs); - if (accessor.locate(numericId) && - transaction->tra_blobs->locate(accessor.current()->second)) + if (transaction->tra_repl_blobs.get(numericId, tempBlobId) && + transaction->tra_blobs->locate(tempBlobId)) { const auto current = &transaction->tra_blobs->current(); @@ -1198,7 +1327,6 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR current->bli_materialized = true; current->bli_blob_id = *dstBlobId; transaction->tra_blobs->fastRemove(); - accessor.fastRemove(); found = true; } } @@ -1215,6 +1343,24 @@ void Applier::doUpdate(thread_db* tdbb, record_param* orgRpb, record_param* newR } } + // Cleanup temporary blobs stored for this command beforehand but not materialized + + ReplBlobMap::ConstAccessor accessor(&transaction->tra_repl_blobs); + for (bool found = accessor.getFirst(); found; found = accessor.getNext()) + { + const auto tempBlobId = accessor.current()->second; + + if (transaction->tra_blobs->locate(tempBlobId)) + { + const auto current = &transaction->tra_blobs->current(); + + if (!current->bli_materialized) + current->bli_blob_object->BLB_cancel(tdbb); + } + } + + transaction->tra_repl_blobs.clear(); + Savepoint::ChangeMarker marker(transaction->tra_save_point); VIO_modify(tdbb, orgRpb, newRpb, transaction); diff --git a/src/jrd/replication/Applier.h b/src/jrd/replication/Applier.h index 83c10a2826b..5da220d27d4 100644 --- a/src/jrd/replication/Applier.h +++ b/src/jrd/replication/Applier.h @@ -134,7 +134,7 @@ namespace Jrd static Applier* create(thread_db* tdbb); void process(thread_db* tdbb, ULONG length, const UCHAR* data); - + void cleanupTransactions(thread_db* tdbb); void shutdown(thread_db* tdbb); Attachment* getAttachment() const @@ -159,7 +159,6 @@ namespace Jrd void prepareTransaction(thread_db* tdbb, TraNumber traNum); void commitTransaction(thread_db* tdbb, TraNumber traNum); void rollbackTransaction(thread_db* tdbb, TraNumber traNum, bool cleanup); - void cleanupTransactions(thread_db* tdbb); void startSavepoint(thread_db* tdbb, TraNumber traNum); void cleanupSavepoint(thread_db* tdbb, TraNumber traNum, bool undo); @@ -191,7 +190,7 @@ namespace Jrd Record* record1, Record* record2); bool lookupRecord(thread_db* tdbb, jrd_rel* relation, Record* record, RecordBitmap* bitmap, - index_desc& idx); + index_desc& idx, const char* idxName = nullptr); const Format* findFormat(thread_db* tdbb, jrd_rel* relation, ULONG length); diff --git a/src/jrd/replication/ChangeLog.cpp b/src/jrd/replication/ChangeLog.cpp index f066c0970cb..d054c87236b 100644 --- a/src/jrd/replication/ChangeLog.cpp +++ b/src/jrd/replication/ChangeLog.cpp @@ -79,8 +79,6 @@ namespace const char* PATHNAME_WILDCARD = "$(pathname)"; const char* ARCHPATHNAME_WILDCARD = "$(archivepathname)"; - SegmentHeader g_dummyHeader; - static THREAD_ENTRY_DECLARE archiver_thread(THREAD_ENTRY_PARAM arg) { ChangeLog* const log = static_cast(arg); @@ -97,12 +95,12 @@ namespace #endif } - void raiseIOError(const char* syscall, const char* filename) + void raiseIOError(const char* syscall, const char* filename, ISC_STATUS errcode) { Arg::Gds temp(isc_io_error); temp << Arg::Str(syscall); temp << Arg::Str(filename); - temp << SYS_ERR(ERRNO); + temp << SYS_ERR(errcode); temp.raise(); } } @@ -113,10 +111,12 @@ namespace ChangeLog::Segment::Segment(MemoryPool& pool, const PathName& filename, int handle) : m_filename(pool, filename), m_handle(handle) { + memset(&m_builtinHeader, 0, sizeof(SegmentHeader)); + struct stat stats; if (fstat(m_handle, &stats) < 0 || stats.st_size < (int) sizeof(SegmentHeader)) { - m_header = &g_dummyHeader; + m_header = &m_builtinHeader; return; } @@ -125,10 +125,11 @@ ChangeLog::Segment::Segment(MemoryPool& pool, const PathName& filename, int hand ChangeLog::Segment::~Segment() { - if (m_header != &g_dummyHeader) + if (m_header != &m_builtinHeader) unmapHeader(); - ::close(m_handle); + if (m_handle != -1) + ::close(m_handle); } void ChangeLog::Segment::init(FB_UINT64 sequence, const Guid& guid) @@ -168,8 +169,10 @@ bool ChangeLog::Segment::validate(const Guid& guid) const void ChangeLog::Segment::copyTo(const PathName& filename) const { + fb_assert(m_header != &m_builtinHeader); + if (os_utils::lseek(m_handle, 0, SEEK_SET) != 0) - raiseIOError("seek", m_filename.c_str()); + raiseIOError("seek", m_filename.c_str(), ERRNO); const auto totalLength = m_header->hdr_length; fb_assert(totalLength > sizeof(SegmentHeader)); @@ -188,16 +191,20 @@ void ChangeLog::Segment::copyTo(const PathName& filename) const if (::read(m_handle, data, length) != length) { + const ISC_STATUS errcode = ERRNO; + dstFile.release(); unlink(filename.c_str()); - raiseIOError("read", m_filename.c_str()); + raiseIOError("read", m_filename.c_str(), errcode); } if (::write(dstFile, data, length) != length) { + const ISC_STATUS errcode = ERRNO; + dstFile.release(); unlink(filename.c_str()); - raiseIOError("write", filename.c_str()); + raiseIOError("write", filename.c_str(), errcode); } } @@ -206,6 +213,7 @@ void ChangeLog::Segment::copyTo(const PathName& filename) const void ChangeLog::Segment::append(ULONG length, const UCHAR* data) { + fb_assert(m_header != &m_builtinHeader); fb_assert(m_header->hdr_state == SEGMENT_STATE_USED); fb_assert(length); @@ -225,10 +233,36 @@ void ChangeLog::Segment::setState(SegmentState state) const auto full = (state == SEGMENT_STATE_FULL); m_header->hdr_state = state; flush(full); + + if ((state == SEGMENT_STATE_FREE) && (m_header != &m_builtinHeader)) + closeFile(); +} + +void ChangeLog::Segment::closeFile() +{ + if (m_header == &m_builtinHeader) + { + fb_assert(m_handle == -1); + return; + } + + memcpy(&m_builtinHeader, m_header, sizeof(SegmentHeader)); + + unmapHeader(); + + if (m_handle != -1) + { + ::close(m_handle); + m_handle = -1; + } + + m_header = &m_builtinHeader; } void ChangeLog::Segment::truncate() { + fb_assert(m_header != &m_builtinHeader); + const auto length = m_header->hdr_length; unmapHeader(); @@ -314,8 +348,8 @@ ChangeLog::ChangeLog(MemoryPool& pool, const FB_UINT64 sequence, const Replication::Config* config) : PermanentStorage(pool), - m_dbId(dbId), m_config(config), - m_segments(pool), m_sequence(sequence), m_shutdown(false) + m_dbId(dbId), m_config(config), m_segments(pool), + m_sequence(sequence), m_generation(0), m_shutdown(false) { memcpy(&m_guid, &guid, sizeof(Guid)); @@ -423,7 +457,7 @@ void ChangeLog::lockState() { const auto state = m_sharedMemory->getHeader(); - if (m_segments.isEmpty() || state->segmentCount > m_segments.getCount()) + if (m_segments.isEmpty() || state->generation != m_generation) initSegments(); } catch (const Exception&) @@ -588,8 +622,17 @@ FB_UINT64 ChangeLog::write(ULONG length, const UCHAR* data, bool sync) if (segment->isEmpty()) state->timestamp = time(NULL); + fb_assert(segment->getSequence() == state->sequence); + segment->append(length, data); + if (segment->getLength() > m_config->segmentSize) + { + segment->setState(SEGMENT_STATE_FULL); + state->flushMark++; + m_workingSemaphore.release(); + } + if (sync) { if (m_config->groupFlushDelay) @@ -623,9 +666,7 @@ FB_UINT64 ChangeLog::write(ULONG length, const UCHAR* data, bool sync) } } - fb_assert(segment->getSequence() == state->sequence); - - return segment->getSequence(); + return state->sequence; } bool ChangeLog::archiveExecute(Segment* segment) @@ -803,19 +844,21 @@ void ChangeLog::bgArchiver() } } + Segment* lastSegment = nullptr; + while (!m_shutdown) { bool restart = false; for (const auto segment : m_segments) { - if (segment->getState() == SEGMENT_STATE_FULL) + if (segment != lastSegment && + segment->getState() == SEGMENT_STATE_FULL) { - if (archiveSegment(segment)) - { - restart = true; - break; - } + lastSegment = segment; + archiveSegment(segment); + restart = true; + break; } } @@ -851,7 +894,9 @@ void ChangeLog::initSegments() const auto state = m_sharedMemory->getHeader(); - for (auto iter = PathUtils::newDirIterator(getPool(), m_config->journalDirectory); + AutoPtr iter; + + for (iter = PathUtils::newDirIterator(getPool(), m_config->journalDirectory); *iter; ++(*iter)) { const auto filename = **iter; @@ -866,11 +911,23 @@ void ChangeLog::initSegments() if (segment->getSequence() > state->sequence) segment->setState(SEGMENT_STATE_FREE); + if (segment->getState() == SEGMENT_STATE_FREE) + { + segment->closeFile(); + + if (segment->getSequence() + m_config->segmentCount <= state->sequence) + { + const PathName& fname = segment->getPathName(); + unlink(fname.c_str()); + continue; + } + } + segment->addRef(); m_segments.add(segment.release()); } - state->segmentCount = (ULONG) m_segments.getCount(); + m_generation = state->generation; } void ChangeLog::clearSegments() @@ -882,7 +939,7 @@ void ChangeLog::clearSegments() ChangeLog::Segment* ChangeLog::createSegment() { const auto state = m_sharedMemory->getHeader(); - const auto sequence = ++state->sequence; + const auto sequence = state->sequence + 1; PathName filename; filename.printf(FILENAME_PATTERN, m_config->filePrefix.c_str(), sequence); @@ -890,7 +947,8 @@ ChangeLog::Segment* ChangeLog::createSegment() const auto fd = os_utils::openCreateSharedFile(filename.c_str(), O_EXCL | O_BINARY); - if (::write(fd, &g_dummyHeader, sizeof(SegmentHeader)) != sizeof(SegmentHeader)) + SegmentHeader dummyHeader = {0}; + if (::write(fd, &dummyHeader, sizeof(SegmentHeader)) != sizeof(SegmentHeader)) { ::close(fd); raiseError("Journal file %s write failed (error %d)", filename.c_str(), ERRNO); @@ -902,7 +960,8 @@ ChangeLog::Segment* ChangeLog::createSegment() segment->addRef(); m_segments.add(segment); - state->segmentCount++; + state->generation++; + state->sequence++; return segment; } @@ -925,17 +984,32 @@ ChangeLog::Segment* ChangeLog::reuseSegment(ChangeLog::Segment* segment) segment->release(); - // Rename the backing file + // Increase the sequence const auto state = m_sharedMemory->getHeader(); - const auto sequence = ++state->sequence; + const auto sequence = state->sequence + 1; + + // Attempt to rename the backing file PathName newname; newname.printf(FILENAME_PATTERN, m_config->filePrefix.c_str(), sequence); newname = m_config->journalDirectory + newname; + // If renaming fails, then we just create a new file. + // The old segment will be reused later in this case. if (::rename(orgname.c_str(), newname.c_str()) < 0) - raiseError("Journal file %s rename failed (error: %d)", orgname.c_str(), ERRNO); + { +#ifdef DEV_BUILD + const auto err = ERRNO; + + string warn; + warn.printf("Journal file %s rename to %s failed (error %d)", + orgname.c_str(), newname.c_str(), err); + + logPrimaryWarning(m_config->dbName, warn); +#endif + return createSegment(); + } // Re-open the segment using a new name and initialize it @@ -947,6 +1021,8 @@ ChangeLog::Segment* ChangeLog::reuseSegment(ChangeLog::Segment* segment) segment->addRef(); m_segments.add(segment); + state->generation++; + state->sequence++; return segment; } @@ -982,26 +1058,16 @@ ChangeLog::Segment* ChangeLog::getSegment(ULONG length) const auto state = m_sharedMemory->getHeader(); - if (activeSegment) + if (activeSegment && activeSegment->hasData() && m_config->archiveTimeout) { - if (activeSegment->getLength() + length > m_config->segmentSize) + const size_t deltaTimestamp = time(NULL) - state->timestamp; + + if (deltaTimestamp > m_config->archiveTimeout) { activeSegment->setState(SEGMENT_STATE_FULL); - state->flushMark++; activeSegment = NULL; m_workingSemaphore.release(); } - else if (activeSegment->hasData() && m_config->archiveTimeout) - { - const size_t deltaTimestamp = time(NULL) - state->timestamp; - - if (deltaTimestamp > m_config->archiveTimeout) - { - activeSegment->setState(SEGMENT_STATE_FULL); - activeSegment = NULL; - m_workingSemaphore.release(); - } - } } if (activeSegment) diff --git a/src/jrd/replication/ChangeLog.h b/src/jrd/replication/ChangeLog.h index 292e884dca0..8ade9d0303c 100644 --- a/src/jrd/replication/ChangeLog.h +++ b/src/jrd/replication/ChangeLog.h @@ -64,11 +64,11 @@ namespace Replication { ULONG version; // changelog version time_t timestamp; // timestamp of last write - ULONG segmentCount; // number of segments in use + ULONG generation; // segments reload marker ULONG flushMark; // last flush mark FB_UINT64 sequence; // sequence number of the last segment - ULONG pidLower; // Lower boundary mark in the PID array - ULONG pidUpper; // Upper boundary mark in the PID array + ULONG pidLower; // lower boundary mark in the PID array + ULONG pidUpper; // upper boundary mark in the PID array int pids[1]; // PIDs attached to the state }; @@ -181,6 +181,8 @@ namespace Replication return m_filename; } + void closeFile(); + private: void mapHeader(); void unmapHeader(); @@ -188,6 +190,7 @@ namespace Replication Firebird::PathName m_filename; int m_handle; SegmentHeader* m_header; + SegmentHeader m_builtinHeader; // used by free segments when there is no mapping #ifdef WIN_NT HANDLE m_mapping; @@ -243,6 +246,7 @@ namespace Replication Firebird::Mutex m_localMutex; Firebird::Guid m_guid; const FB_UINT64 m_sequence; + ULONG m_generation; Firebird::Semaphore m_startupSemaphore; Firebird::Semaphore m_cleanupSemaphore; diff --git a/src/jrd/replication/Config.cpp b/src/jrd/replication/Config.cpp index f15c3acaf73..f66aca063cb 100644 --- a/src/jrd/replication/Config.cpp +++ b/src/jrd/replication/Config.cpp @@ -299,7 +299,11 @@ Config* Config::get(const PathName& lookupName) if (config->journalDirectory.hasData() || config->syncReplicas.hasData()) { - // If log_directory is specified, then replication is enabled + // If either journal_directory or sync_replicas is specified, + // then replication is enabled + + if (config->dbName.isEmpty()) + config->dbName = lookupName; if (config->filePrefix.isEmpty()) { @@ -382,7 +386,6 @@ void Config::enumerate(Firebird::Array& replicas) { config->sourceDirectory = value.c_str(); PathUtils::ensureSeparator(config->sourceDirectory); - checkAccess(config->sourceDirectory, key); } else if (key == "source_guid") { @@ -423,3 +426,43 @@ void Config::enumerate(Firebird::Array& replicas) logReplicaStatus(dbName, &localStatus); } } + +bool Config::hasReplicas() +{ + try + { + const PathName filename = + fb_utils::getPrefix(IConfigManager::DIR_CONF, REPLICATION_CFGFILE); + + ConfigFile cfgFile(filename, ConfigFile::HAS_SUB_CONF | + ConfigFile::NATIVE_ORDER | + ConfigFile::CUSTOM_MACROS); + + bool hasDbs = false, hasSource = false; + + for (const auto& section : cfgFile.getParameters()) + { + if (section.name == "database" && section.value.hasData()) + hasDbs = true; + + if (!section.sub) + continue; + + for (const auto& el : section.sub->getParameters()) + { + if (el.name == "journal_source_directory" && el.value.hasData()) + { + hasSource = true; + break; + } + } + } + + if (hasDbs && hasSource) + return true; + } + catch (const Exception&) + {} // no-op + + return false; +} diff --git a/src/jrd/replication/Config.h b/src/jrd/replication/Config.h index 4be0722dd4f..a671774e1f5 100644 --- a/src/jrd/replication/Config.h +++ b/src/jrd/replication/Config.h @@ -38,6 +38,7 @@ namespace Replication static Config* get(const Firebird::PathName& dbName); static void enumerate(Firebird::Array& replicas); + static bool hasReplicas(); Firebird::PathName dbName; ULONG bufferSize; diff --git a/src/jrd/replication/Manager.cpp b/src/jrd/replication/Manager.cpp index ec5f004309c..33c965daad2 100644 --- a/src/jrd/replication/Manager.cpp +++ b/src/jrd/replication/Manager.cpp @@ -151,6 +151,7 @@ Manager::Manager(const string& dbId, } ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); + dpb.insertByte(isc_dpb_no_db_triggers, 1); if (login.hasData()) { @@ -185,12 +186,19 @@ Manager::Manager(const string& dbId, Manager::~Manager() { - for (auto& buffer : m_buffers) + fb_assert(m_shutdown); + fb_assert(m_queue.isEmpty()); + fb_assert(m_replicas.isEmpty()); + + for (auto buffer : m_buffers) delete buffer; } void Manager::shutdown() { + if (m_shutdown) + return; + m_shutdown = true; m_workingSemaphore.release(); @@ -198,23 +206,23 @@ void Manager::shutdown() MutexLockGuard guard(m_queueMutex, FB_FUNCTION); - for (auto& buffer : m_queue) + // Clear the processing queue + + for (auto buffer : m_queue) { if (buffer) - { releaseBuffer(buffer); - buffer = nullptr; - } } - // Detach from synchronous replicas + m_queue.clear(); - FbLocalStatus localStatus; + // Detach from synchronous replicas - for (auto& iter : m_replicas) + for (auto iter : m_replicas) { - iter->replicator->close(&localStatus); - iter->attachment->detach(&localStatus); + iter->replicator->release(); + iter->attachment->release(); + delete iter; } m_replicas.clear(); @@ -239,14 +247,17 @@ void Manager::releaseBuffer(UCharBuffer* buffer) MutexLockGuard guard(m_buffersMutex, FB_FUNCTION); - fb_assert(!m_buffers.exist(buffer)); - m_buffers.add(buffer); + if (!m_buffers.exist(buffer)) + m_buffers.add(buffer); } -void Manager::flush(UCharBuffer* buffer, bool sync) +void Manager::flush(UCharBuffer* buffer, bool sync, bool prepare) { + fb_assert(!m_shutdown); fb_assert(buffer && buffer->hasData()); + const auto prepareBuffer = prepare ? buffer : nullptr; + MutexLockGuard guard(m_queueMutex, FB_FUNCTION); // Add the current chunk to the queue @@ -256,10 +267,9 @@ void Manager::flush(UCharBuffer* buffer, bool sync) // If the background thread is lagging too far behind, // replicate packets synchronously rather than relying // on the background thread to catch up any time soon - if (!sync && m_queueSize > MAX_BG_WRITER_LAG) - sync = true; + const bool lagging = (m_queueSize > MAX_BG_WRITER_LAG); - if (sync) + if (sync || prepare || lagging) { const auto tdbb = JRD_get_thread_data(); const auto dbb = tdbb->getDatabase(); @@ -268,29 +278,54 @@ void Manager::flush(UCharBuffer* buffer, bool sync) { if (buffer) { - const auto length = (ULONG) buffer->getCount(); + auto length = (ULONG) buffer->getCount(); + fb_assert(length); + bool hasData = true; if (m_changeLog) { - const auto sequence = m_changeLog->write(length, buffer->begin(), true); + if (prepareBuffer == buffer) + { + // Remove the opPrepareTransaction command from the journal + fb_assert(buffer->back() == opPrepareTransaction); + + const auto block = (Block*) buffer->begin(); + block->length -= sizeof(UCHAR); + length -= sizeof(UCHAR); + hasData = (block->length != 0); + } + + if (hasData) + { + const auto sequence = m_changeLog->write(length, buffer->begin(), sync); - if (sequence != m_sequence) + if (sequence != m_sequence) + { + dbb->setReplSequence(tdbb, sequence); + m_sequence = sequence; + } + } + + if (prepareBuffer == buffer) { - dbb->setReplSequence(tdbb, sequence); - m_sequence = sequence; + const auto block = (Block*) buffer->begin(); + block->length += sizeof(UCHAR); + length += sizeof(UCHAR); } } - for (auto& iter : m_replicas) + for (auto iter : m_replicas) { - iter->status.check(); - iter->replicator->process(&iter->status, length, buffer->begin()); - iter->status.check(); + if (iter->status.isSuccess()) + iter->replicator->process(&iter->status, length, buffer->begin()); } m_queueSize -= length; releaseBuffer(buffer); - buffer = NULL; + buffer = nullptr; + + for (auto iter : m_replicas) + iter->status.check(); } } @@ -326,21 +361,17 @@ void Manager::bgWriter() fb_assert(length); if (m_changeLog) - { m_changeLog->write(length, buffer->begin(), false); - } - for (auto& iter : m_replicas) + for (auto iter : m_replicas) { if (iter->status.isSuccess()) - { iter->replicator->process(&iter->status, length, buffer->begin()); - } } m_queueSize -= length; releaseBuffer(buffer); - buffer = NULL; + buffer = nullptr; } } diff --git a/src/jrd/replication/Manager.h b/src/jrd/replication/Manager.h index c9364f85d18..d38a3d4883e 100644 --- a/src/jrd/replication/Manager.h +++ b/src/jrd/replication/Manager.h @@ -67,8 +67,7 @@ namespace Replication }; public: - Manager(const Firebird::string& dbId, - const Replication::Config* config); + Manager(const Firebird::string& dbId, const Replication::Config* config); ~Manager(); void shutdown(); @@ -76,7 +75,7 @@ namespace Replication Firebird::UCharBuffer* getBuffer(); void releaseBuffer(Firebird::UCharBuffer* buffer); - void flush(Firebird::UCharBuffer* buffer, bool sync); + void flush(Firebird::UCharBuffer* buffer, bool sync, bool prepare); void forceJournalSwitch() { @@ -114,7 +113,6 @@ namespace Replication volatile bool m_shutdown; volatile bool m_signalled; - Firebird::AtomicCounter m_waiters; Firebird::AutoPtr m_changeLog; Firebird::RWLock m_lock; diff --git a/src/jrd/replication/Publisher.cpp b/src/jrd/replication/Publisher.cpp index bc0cde35541..f21700946c9 100644 --- a/src/jrd/replication/Publisher.cpp +++ b/src/jrd/replication/Publisher.cpp @@ -21,6 +21,7 @@ */ #include "firebird.h" +#include "../jrd/ini.h" #include "../jrd/jrd.h" #include "../jrd/ods.h" #include "../jrd/req.h" @@ -44,10 +45,6 @@ using namespace Replication; namespace { - // Generator RDB$BACKUP_HISTORY, although defined as system, - // should be replicated similar to user-defined ones - const int BACKUP_HISTORY_GENERATOR = 9; - const char* NO_PLUGIN_ERROR = "Replication plugin %s is not found"; const char* STOP_ERROR = "Replication is stopped due to critical error(s)"; @@ -133,7 +130,7 @@ namespace auto& pool = *attachment->att_pool; const auto manager = dbb->replManager(true); const auto& guid = dbb->dbb_guid; - const auto& userName = attachment->att_user->getUserName(); + const auto& userName = attachment->getUserName(); attachment->att_replicator = FB_NEW Replicator(pool, manager, guid, userName); } @@ -243,12 +240,27 @@ namespace return transaction->tra_replicator; } - bool matchTable(thread_db* tdbb, const MetaName& tableName) + bool checkTable(thread_db* tdbb, jrd_rel* relation) { - const auto attachment = tdbb->getAttachment(); - const auto matcher = attachment->att_repl_matcher.get(); + if (relation->isTemporary()) + return false; + + if (!relation->isSystem()) + { + if (!relation->isReplicating(tdbb)) + return false; + + const auto attachment = tdbb->getAttachment(); + const auto matcher = attachment->att_repl_matcher.get(); + + if (matcher && !matcher->matchTable(relation->rel_name)) + return false; + } + // Do not replicate RDB$BACKUP_HISTORY as it describes physical-level things + else if (relation->rel_id == rel_backup_history) + return false; - return (!matcher || matcher->matchTable(tableName)); + return true; } Record* upgradeRecord(thread_db* tdbb, jrd_rel* relation, Record* record) @@ -497,18 +509,9 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) const auto relation = rpb->rpb_relation; fb_assert(relation); - if (relation->isTemporary()) + if (!checkTable(tdbb, relation)) return; - if (!relation->isSystem()) - { - if (!relation->isReplicating(tdbb)) - return; - - if (!matchTable(tdbb, relation->rel_name)) - return; - } - FbLocalStatus status; const auto replicator = getReplicator(tdbb, status, transaction); if (!replicator) @@ -520,6 +523,7 @@ void REPL_store(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) // This temporary auto-pointer is just to delete a temporary record AutoPtr cleanupRecord(record != rpb->rpb_record ? record : nullptr); AutoSetRestoreFlag noRecursion(&tdbb->tdbb_flags, TDBB_repl_in_progress, true); + AutoSetRestoreFlag noBlobCheck(&transaction->tra_flags, TRA_no_blob_check, true); ReplicatedRecordImpl replRecord(tdbb, relation, record); @@ -539,18 +543,9 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb, const auto relation = newRpb->rpb_relation; fb_assert(relation); - if (relation->isTemporary()) + if (!checkTable(tdbb, relation)) return; - if (!relation->isSystem()) - { - if (!relation->isReplicating(tdbb)) - return; - - if (!matchTable(tdbb, relation->rel_name)) - return; - } - FbLocalStatus status; const auto replicator = getReplicator(tdbb, status, transaction); if (!replicator) @@ -577,6 +572,7 @@ void REPL_modify(thread_db* tdbb, const record_param* orgRpb, } AutoSetRestoreFlag noRecursion(&tdbb->tdbb_flags, TDBB_repl_in_progress, true); + AutoSetRestoreFlag noBlobCheck(&transaction->tra_flags, TRA_no_blob_check, true); ReplicatedRecordImpl replOrgRecord(tdbb, relation, orgRecord); ReplicatedRecordImpl replNewRecord(tdbb, relation, newRecord); @@ -597,18 +593,9 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) const auto relation = rpb->rpb_relation; fb_assert(relation); - if (relation->isTemporary()) + if (!checkTable(tdbb, relation)) return; - if (!relation->isSystem()) - { - if (!relation->isReplicating(tdbb)) - return; - - if (!matchTable(tdbb, relation->rel_name)) - return; - } - FbLocalStatus status; const auto replicator = getReplicator(tdbb, status, transaction); if (!replicator) @@ -620,6 +607,7 @@ void REPL_erase(thread_db* tdbb, const record_param* rpb, jrd_tra* transaction) // This temporary auto-pointer is just to delete a temporary record AutoPtr cleanupRecord(record != rpb->rpb_record ? record : nullptr); AutoSetRestoreFlag noRecursion(&tdbb->tdbb_flags, TDBB_repl_in_progress, true); + AutoSetRestoreFlag noBlobCheck(&transaction->tra_flags, TRA_no_blob_check, true); ReplicatedRecordImpl replRecord(tdbb, relation, record); @@ -638,14 +626,11 @@ void REPL_gen_id(thread_db* tdbb, SLONG genId, SINT64 value) if (genId == 0) // special case: ignore RDB$GENERATORS return; - // Ignore other system generators, except RDB$BACKUP_HISTORY - if (genId != BACKUP_HISTORY_GENERATOR) + // Ignore other system generators + for (auto generator = generators; generator->gen_name; generator++) { - for (auto generator = generators; generator->gen_name; generator++) - { - if (generator->gen_id == genId) - return; - } + if (generator->gen_id == genId) + return; } const auto replicator = getReplicator(tdbb); @@ -661,6 +646,8 @@ void REPL_gen_id(thread_db* tdbb, SLONG genId, SINT64 value) attachment->att_generators.store(genId, genName); } + fb_assert(genName.hasData()); + AutoSetRestoreFlag noRecursion(&tdbb->tdbb_flags, TDBB_repl_in_progress, true); FbLocalStatus status; diff --git a/src/jrd/replication/Replicator.cpp b/src/jrd/replication/Replicator.cpp index b309aea5a77..09c1004d73c 100644 --- a/src/jrd/replication/Replicator.cpp +++ b/src/jrd/replication/Replicator.cpp @@ -64,7 +64,8 @@ void Replicator::flush(BatchBlock& block, FlushReason reason, ULONG flags) // Pass the buffer to the replication manager and setup the new one const auto sync = (reason == FLUSH_SYNC); - m_manager->flush(block.buffer, sync); + const auto prepare = (reason == FLUSH_PREPARE); + m_manager->flush(block.buffer, sync, prepare); memset(&block.header, 0, sizeof(Block)); block.header.traNumber = traNumber; @@ -79,8 +80,11 @@ void Replicator::storeBlob(Transaction* transaction, ISC_QUAD blobId) { FbLocalStatus localStatus; + // We need the blob exactly as stored, without possible transliteration to the connection charset + const UCHAR bpb[] = {isc_bpb_version1, isc_bpb_target_interp, 1, CS_NONE}; + BlobWrapper blob(&localStatus); - if (!blob.open(m_attachment, transaction->getInterface(), blobId)) + if (!blob.open(m_attachment, transaction->getInterface(), blobId, sizeof(bpb), bpb)) localStatus.raise(); UCharBuffer buffer; @@ -136,8 +140,6 @@ void Replicator::releaseTransaction(Transaction* transaction) { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); m_manager->releaseBuffer(txnData.buffer); @@ -157,8 +159,6 @@ IReplicatedTransaction* Replicator::startTransaction(CheckStatusWrapper* status, try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - MemoryPool& pool = getPool(); transaction = FB_NEW_POOL(pool) Transaction(this, trans); m_transactions.add(transaction); @@ -185,8 +185,6 @@ void Replicator::prepareTransaction(CheckStatusWrapper* status, Transaction* tra { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); txnData.putTag(opPrepareTransaction); @@ -203,8 +201,6 @@ void Replicator::commitTransaction(CheckStatusWrapper* status, Transaction* tran { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); // Assert this transaction being de-facto dirty @@ -237,8 +233,6 @@ void Replicator::rollbackTransaction(CheckStatusWrapper* status, Transaction* tr { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); if (txnData.flushes) @@ -257,8 +251,6 @@ void Replicator::startSavepoint(CheckStatusWrapper* status, Transaction* transac { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); txnData.putTag(opStartSavepoint); @@ -276,8 +268,6 @@ void Replicator::releaseSavepoint(CheckStatusWrapper* status, Transaction* trans { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); txnData.putTag(opReleaseSavepoint); @@ -295,8 +285,6 @@ void Replicator::rollbackSavepoint(CheckStatusWrapper* status, Transaction* tran { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); txnData.putTag(opRollbackSavepoint); @@ -326,14 +314,12 @@ void Replicator::insertRecord(CheckStatusWrapper* status, { const auto blobId = (ISC_QUAD*) field->getData(); - if (blobId) + if (blobId && !BlobWrapper::blobIsNull(*blobId)) storeBlob(transaction, *blobId); } } } - MutexLockGuard guard(m_mutex, FB_FUNCTION); - const auto length = record->getRawLength(); const auto data = record->getRawData(); @@ -373,14 +359,12 @@ void Replicator::updateRecord(CheckStatusWrapper* status, { const auto blobId = (ISC_QUAD*) field->getData(); - if (blobId) + if (blobId && !BlobWrapper::blobIsNull(*blobId)) storeBlob(transaction, *blobId); } } } - MutexLockGuard guard(m_mutex, FB_FUNCTION); - const auto orgLength = orgRecord->getRawLength(); const auto orgData = orgRecord->getRawData(); @@ -414,8 +398,6 @@ void Replicator::deleteRecord(CheckStatusWrapper* status, { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - const auto length = record->getRawLength(); const auto data = record->getRawData(); @@ -444,8 +426,6 @@ void Replicator::executeSqlIntl(CheckStatusWrapper* status, { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - auto& txnData = transaction->getData(); const auto atom = txnData.defineAtom(m_user); @@ -469,8 +449,6 @@ void Replicator::cleanupTransaction(CheckStatusWrapper* status, { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - BatchBlock block(getPool()); block.header.traNumber = number; block.buffer = m_manager->getBuffer(); @@ -490,8 +468,6 @@ void Replicator::setSequence(CheckStatusWrapper* status, { try { - MutexLockGuard guard(m_mutex, FB_FUNCTION); - for (auto& generator : m_generators) { if (generator.name == genName) diff --git a/src/jrd/replication/Replicator.h b/src/jrd/replication/Replicator.h index 2c8e79eb157..0cfefe75746 100644 --- a/src/jrd/replication/Replicator.h +++ b/src/jrd/replication/Replicator.h @@ -261,7 +261,6 @@ namespace Replication const Firebird::MetaString m_user; Firebird::Array m_transactions; GeneratorCache m_generators; - Firebird::Mutex m_mutex; Firebird::RefPtr m_attachment; void initialize(); diff --git a/src/jrd/replication/Utils.cpp b/src/jrd/replication/Utils.cpp index e891d582af7..bd4b6e60459 100644 --- a/src/jrd/replication/Utils.cpp +++ b/src/jrd/replication/Utils.cpp @@ -49,6 +49,7 @@ #include #include +#include using namespace Firebird; using namespace Replication; @@ -80,15 +81,17 @@ namespace char host[BUFFER_LARGE]; ISC_get_host(host, sizeof(host)); m_hostname = host; + m_error = false; #ifdef WIN_NT - m_mutex = CreateMutex(NULL, FALSE, "firebird_repl_mutex"); + m_mutex = CreateMutex(ISC_get_security_desc(), FALSE, "firebird_repl_mutex"); #endif } ~LogWriter() { #ifdef WIN_NT - CloseHandle(m_mutex); + if (m_mutex != INVALID_HANDLE_VALUE) + CloseHandle(m_mutex); #endif } @@ -107,6 +110,9 @@ namespace return; } + if (m_error) + m_error = false; + string dbname, text; if (database.hasData()) @@ -117,29 +123,38 @@ namespace dbname.c_str(), LOG_MSG_TYPES[type], message.c_str()); fseek(file, 0, SEEK_END); - fprintf(file, text.c_str()); + fputs(text.c_str(), file); fclose(file); unlock(); } + else if (!m_error && !m_error.exchange(true)) + { + gds__log("Failed to open log file \'%s\', errno %d", + m_filename.c_str(), errno); + } } private: bool lock(FILE* file) { + const bool ret = #ifdef WIN_NT - return (WaitForSingleObject(m_mutex, INFINITE) == WAIT_OBJECT_0); + (WaitForSingleObject(m_mutex, INFINITE) == WAIT_OBJECT_0); #else #ifdef HAVE_FLOCK - if (flock(fileno(file), LOCK_EX)) + flock(fileno(file), LOCK_EX) == 0; #else - if (os_utils::lockf(fileno(file), F_LOCK, 0)) + os_utils::lockf(fileno(file), F_LOCK, 0) == 0; #endif +#endif + + if (!ret && !m_error && !m_error.exchange(true)) { - return false; + gds__log("Failed to lock log file \'%s\', error %d", + m_filename.c_str(), ERRNO); } - return true; -#endif + return ret; } void unlock() @@ -154,6 +169,8 @@ namespace #ifdef WIN_NT HANDLE m_mutex; #endif + // used to not pollute firebird.log with too many messages + std::atomic_bool m_error; }; void logMessage(LogMsgSide side, LogMsgType type, @@ -219,6 +236,7 @@ namespace Replication #ifdef WIN_NT string params; params.printf("/c %s", command.c_str()); + SHELLEXECUTEINFO seInfo = {0}; seInfo.cbSize = sizeof(SHELLEXECUTEINFO); seInfo.fMask = SEE_MASK_NOCLOSEPROCESS; @@ -229,10 +247,17 @@ namespace Replication seInfo.lpDirectory = NULL; seInfo.nShow = SW_HIDE; seInfo.hInstApp = NULL; - ShellExecuteEx(&seInfo); - WaitForSingleObject(seInfo.hProcess, INFINITE); + + if (!ShellExecuteEx(&seInfo)) + return -1; + DWORD exitCode = 0; - GetExitCodeProcess(seInfo.hProcess, &exitCode); + if (seInfo.hProcess) + { + WaitForSingleObject(seInfo.hProcess, INFINITE); + GetExitCodeProcess(seInfo.hProcess, &exitCode); + CloseHandle(seInfo.hProcess); + } return (int) exitCode; #else return system(command.c_str()); diff --git a/src/jrd/req.h b/src/jrd/req.h index 9e82f4f90b8..0fc70aa02df 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -142,7 +142,7 @@ const unsigned int MAX_DIFFERENCES = 1024; // Max length of generated Difference // List of active blobs controlled by request -typedef Firebird::BePlusTree TempBlobIdTree; +typedef Firebird::BePlusTree TempBlobIdTree; // Affected rows counter class @@ -167,13 +167,156 @@ class AffectedRows class jrd_req : public pool_alloc { +private: + class TimeStampCache + { + public: + void invalidate() + { + gmtTimeStamp.invalidate(); + localTimeStampValid = localTimeValid = false; + } + + ISC_TIMESTAMP getLocalTimeStamp(USHORT currentTimeZone) const + { + fb_assert(!gmtTimeStamp.isEmpty()); + + if (!localTimeStampValid || timeZone != currentTimeZone) + update(currentTimeZone, true); + + return localTimeStamp; + } + + ISC_TIMESTAMP getGmtTimeStamp() const + { + fb_assert(!gmtTimeStamp.isEmpty()); + return gmtTimeStamp.value(); + } + + void setGmtTimeStamp(USHORT currentTimeZone, ISC_TIMESTAMP ts) + { + gmtTimeStamp = ts; + update(currentTimeZone, false); + } + + ISC_TIMESTAMP_TZ getTimeStampTz(USHORT currentTimeZone) const + { + fb_assert(!gmtTimeStamp.isEmpty()); + + ISC_TIMESTAMP_TZ timeStampTz; + timeStampTz.utc_timestamp = gmtTimeStamp.value(); + timeStampTz.time_zone = currentTimeZone; + return timeStampTz; + } + + ISC_TIME_TZ getTimeTz(USHORT currentTimeZone) const + { + fb_assert(!gmtTimeStamp.isEmpty()); + + ISC_TIME_TZ timeTz; + + if (timeZone != currentTimeZone) + update(currentTimeZone, false); + + if (localTimeValid) + { + timeTz.utc_time = localTime; + timeTz.time_zone = timeZone; + } + else + { + ISC_TIMESTAMP_TZ timeStamp; + timeStamp.utc_timestamp = gmtTimeStamp.value(); + timeStamp.time_zone = timeZone; + + timeTz = Firebird::TimeZoneUtil::timeStampTzToTimeTz(timeStamp); + + localTime = timeTz.utc_time; + localTimeValid = true; + } + + return timeTz; + } + + void validate(USHORT currentTimeZone) + { + if (gmtTimeStamp.isEmpty()) + { + Firebird::TimeZoneUtil::validateGmtTimeStamp(gmtTimeStamp); + update(currentTimeZone, false); + } + } + + private: + void update(USHORT currentTimeZone, bool updateLocalTimeStamp) const + { + if (updateLocalTimeStamp) + { + localTimeStamp = Firebird::TimeZoneUtil::timeStampTzToTimeStamp( + getTimeStampTz(currentTimeZone), currentTimeZone); + } + + localTimeStampValid = updateLocalTimeStamp; + timeZone = currentTimeZone; + localTimeValid = false; + } + + private: + Firebird::TimeStamp gmtTimeStamp; // Start time of request in GMT time zone + + mutable bool localTimeStampValid; // localTimeStamp calculation is expensive. So is it valid (calculated)? + mutable bool localTimeValid; // localTime calculation is expensive. So is it valid (calculated)? + // These are valid only when !gmtTimeStamp.isEmpty(), so no initialization is necessary. + mutable ISC_TIMESTAMP localTimeStamp; // Timestamp in timeZone's zone + mutable ISC_USHORT timeZone; // Timezone borrowed from the attachment when updated + mutable ISC_TIME localTime; // gmtTimeStamp converted to local time (WITH TZ) + }; + + // Fields to support read consistency in READ COMMITTED transactions + + struct SnapshotData + { + jrd_req* m_owner; + SnapshotHandle m_handle; + CommitNumber m_number; + + void init() + { + m_owner = nullptr; + m_handle = 0; + m_number = 0; + } + }; + + // Context data saved/restored with every new autonomous transaction + + struct AutoTranCtx + { + AutoTranCtx() + { + m_snapshot.init(); + }; + + AutoTranCtx(const jrd_req* request) : + m_transaction(request->req_transaction), + m_savepoints(request->req_savepoints), + m_proc_savepoints(request->req_proc_sav_point), + m_snapshot(request->req_snapshot) + {} + + jrd_tra* m_transaction = nullptr; + Savepoint* m_savepoints = nullptr; + Savepoint* m_proc_savepoints = nullptr; + SnapshotData m_snapshot; + }; + public: jrd_req(Attachment* attachment, /*const*/ JrdStatement* aStatement, Firebird::MemoryStats* parent_stats) : statement(aStatement), req_pool(statement->pool), req_memory_stats(parent_stats), - req_blobs(req_pool), + req_blobs(*req_pool), req_stats(*req_pool), req_base_stats(*req_pool), req_ext_stmt(NULL), @@ -181,10 +324,10 @@ class jrd_req : public pool_alloc req_ext_resultset(NULL), req_timeout(0), req_domain_validation(NULL), + req_auto_trans(*req_pool), req_sorts(*req_pool), req_rpb(*req_pool), - impureArea(*req_pool), - req_auto_trans(*req_pool) + impureArea(*req_pool) { fb_assert(statement); setAttachment(attachment); @@ -234,6 +377,7 @@ class jrd_req : public pool_alloc private: JrdStatement* const statement; mutable StmtNumber req_id; // request identifier + TimeStampCache req_timeStampCache; // time stamp cache public: MemoryPool* req_pool; @@ -268,7 +412,6 @@ class jrd_req : public pool_alloc ULONG req_flags; // misc request flags Savepoint* req_savepoints; // Looper savepoint list Savepoint* req_proc_sav_point; // procedure savepoint list - Firebird::TimeStamp req_gmt_timestamp; // Start time of request in GMT time zone unsigned int req_timeout; // query timeout in milliseconds, set by the dsql_req::setupTimer Firebird::RefPtr req_timer; // timeout timer, shared with dsql_req @@ -283,49 +426,15 @@ class jrd_req : public pool_alloc ULONG req_src_column; dsc* req_domain_validation; // Current VALUE for constraint validation + Firebird::Stack req_auto_trans; // Autonomous transactions SortOwner req_sorts; Firebird::Array req_rpb; // record parameter blocks Firebird::Array impureArea; // impure area USHORT charSetId; // "client" character set of the request TriggerAction req_trigger_action; // action that caused trigger to fire - - // Fields to support read consistency in READ COMMITTED transactions - struct snapshot_data - { - jrd_req* m_owner; - SnapshotHandle m_handle; - CommitNumber m_number; - - void init() - { - m_owner = nullptr; - m_handle = 0; - m_number = 0; - } - }; - - snapshot_data req_snapshot; - - // Context data saved\restored with every new autonomous transaction - struct auto_tran_ctx - { - auto_tran_ctx() : - m_transaction(nullptr) - { - m_snapshot.init(); - }; - - auto_tran_ctx(jrd_tra* const tran, const snapshot_data& snap) : - m_transaction(tran), - m_snapshot(snap) - { - }; - - jrd_tra* m_transaction; - snapshot_data m_snapshot; - }; - - Firebird::Stack req_auto_trans; // Autonomous transactions + SnapshotData req_snapshot; + StatusXcp req_last_xcp; // last known exception + bool req_batch_mode; enum req_s { req_evaluate, @@ -337,9 +446,6 @@ class jrd_req : public pool_alloc req_unwind } req_operation; // operation for next node - StatusXcp req_last_xcp; // last known exception - bool req_batch_mode; - template T* getImpure(unsigned offset) { return reinterpret_cast(&impureArea[offset]); @@ -353,37 +459,63 @@ class jrd_req : public pool_alloc req_base_stats.assign(req_stats); } - // Save transaction and snapshot context when switching to the autonomous transaction - void pushTransaction(jrd_tra* const transaction) + // Save context when switching to the autonomous transaction + void pushTransaction() { - req_auto_trans.push(auto_tran_ctx(transaction, req_snapshot)); + fb_assert(req_transaction); // must be attached + + req_auto_trans.push(this); + req_savepoints = nullptr; + req_proc_sav_point = nullptr; req_snapshot.init(); } - // Restore transaction and snapshot context + // Restore context jrd_tra* popTransaction() { - const auto_tran_ctx tmp = req_auto_trans.pop(); + fb_assert(!req_transaction); // must be detached + + const auto tmp = req_auto_trans.pop(); + req_savepoints = tmp.m_savepoints; + req_proc_sav_point = tmp.m_proc_savepoints; req_snapshot = tmp.m_snapshot; return tmp.m_transaction; } - Firebird::TimeStamp getLocalTimeStamp() const + void invalidateTimeStamp() { - ISC_TIMESTAMP_TZ timeStampTz; - timeStampTz.utc_timestamp = req_gmt_timestamp.value(); - timeStampTz.time_zone = Firebird::TimeZoneUtil::GMT_ZONE; + req_timeStampCache.invalidate(); + } - return Firebird::TimeZoneUtil::timeStampTzToTimeStamp(timeStampTz, req_attachment->att_current_timezone); + ISC_TIMESTAMP getLocalTimeStamp() const + { + return req_timeStampCache.getLocalTimeStamp(req_attachment->att_current_timezone); + } + + ISC_TIMESTAMP getGmtTimeStamp() const + { + return req_timeStampCache.getGmtTimeStamp(); + } + + void setGmtTimeStamp(ISC_TIMESTAMP ts) + { + req_timeStampCache.setGmtTimeStamp(req_attachment->att_current_timezone, ts); } ISC_TIMESTAMP_TZ getTimeStampTz() const { - ISC_TIMESTAMP_TZ timeStampTz; - timeStampTz.utc_timestamp = req_gmt_timestamp.value(); - timeStampTz.time_zone = req_attachment->att_current_timezone; - return timeStampTz; + return req_timeStampCache.getTimeStampTz(req_attachment->att_current_timezone); + } + + ISC_TIME_TZ getTimeTz() const + { + return req_timeStampCache.getTimeTz(req_attachment->att_current_timezone); + } + + void validateTimeStamp() + { + req_timeStampCache.validate(req_attachment->att_current_timezone); } }; diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 09d721f2ef9..0698fe3d6d9 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -228,6 +228,10 @@ void SCL_check_access(thread_db* tdbb, **************************************/ SET_TDBB(tdbb); + // Allow the replicator any access to database, its permissions are already validated + if (tdbb->tdbb_flags & TDBB_replicator) + return; + const MetaName& userName = s_class->sclClassUser.second; if (s_class && (s_class->scl_flags & SCL_corrupt)) @@ -286,6 +290,11 @@ void SCL_check_create_access(thread_db* tdbb, int type) * **************************************/ SET_TDBB(tdbb); + + // Allow the replicator any access to database, its permissions are already validated + if (tdbb->tdbb_flags & TDBB_replicator) + return; + Jrd::Attachment* const attachment = tdbb->getAttachment(); // Allow the locksmith any access to database @@ -915,11 +924,7 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* par_string) return NULL; Jrd::Attachment* const attachment = tdbb->getAttachment(); - - const UserId* effectiveUserId = attachment->getEffectiveUserId(); - MetaName userName; - if (effectiveUserId) - userName= effectiveUserId->getUserName(); + const MetaString& userName = attachment->getEffectiveUserName(); MetaNamePair key(string, userName); // Look for the class already known @@ -1050,44 +1055,61 @@ bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role) void UserId::findGrantedRoles(thread_db* tdbb) const { - SET_TDBB(tdbb); - Jrd::Attachment* const attachment = tdbb->getAttachment(); - - PreparedStatement::Builder sql; - MetaName usr_get_role; - string usr_get_priv; - sql << "with recursive role_tree as ( " - << " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges " - << " where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user = " << usr_user_name << " and rdb$user_type = 8 " - << " union all " - << " select rdb$role_name as nm, 1 as ur from rdb$roles " - << " where rdb$role_name = " << usr_sql_role_name - << " union all " - << " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p " - << " join role_tree t on t.nm = p.rdb$user " - << " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) " - << "select " << sql("r.rdb$role_name, ", usr_get_role) - << sql("r.rdb$system_privileges ", usr_get_priv) - << " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name "; - - AutoPreparedStatement stmt(attachment->prepareStatement(tdbb, attachment->getSysTransaction(), sql)); - AutoResultSet rs(stmt->executeQuery(tdbb, attachment->getSysTransaction())); - - usr_granted_roles.clear(); - usr_privileges.clearAll(); - - while (rs->fetch(tdbb)) + try { - if (!usr_granted_roles.exist(usr_get_role)) // SQL request can return duplicates + SET_TDBB(tdbb); + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + PreparedStatement::Builder sql; + MetaName usr_get_role; + string usr_get_priv; + sql << "with recursive role_tree as ( " + << " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges " + << " where rdb$privilege = 'M' and rdb$field_name = 'D'" + << " and (rdb$user = " << usr_user_name << " or rdb$user = 'PUBLIC')" + << " and rdb$user_type = 8 " + << " union all " + << " select rdb$role_name as nm, 1 as ur from rdb$roles " + << " where rdb$role_name = " << usr_sql_role_name + << " union all " + << " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p " + << " join role_tree t on t.nm = p.rdb$user " + << " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) " + << "select " << sql("r.rdb$role_name, ", usr_get_role) + << sql("r.rdb$system_privileges ", usr_get_priv) + << " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name "; + + AutoPreparedStatement stmt(attachment->prepareStatement(tdbb, attachment->getSysTransaction(), sql)); + AutoResultSet rs(stmt->executeQuery(tdbb, attachment->getSysTransaction())); + + usr_granted_roles.clear(); + usr_privileges.clearAll(); + + while (rs->fetch(tdbb)) { - usr_granted_roles.add(usr_get_role); - Privileges p; - p.load(usr_get_priv.c_str()); - usr_privileges |= p; + if (!usr_granted_roles.exist(usr_get_role)) // SQL request can return duplicates + { + usr_granted_roles.add(usr_get_role); + Privileges p; + p.load(usr_get_priv.c_str()); + usr_privileges |= p; + } } } + catch (const Exception& e) + { + if (!(usr_flags & USR_sysdba)) + throw; - usr_flags &= ~USR_newrole; + e.stuffException(tdbb->tdbb_status_vector); + if (!fb_utils::containsErrorCode(tdbb->tdbb_status_vector->getErrors(), isc_collation_not_installed)) + throw; + + usr_privileges.setAll(); + tdbb->tdbb_status_vector->init(); + } + + usr_flags &= ~(USR_newrole | USR_sysdba); } @@ -1099,7 +1121,7 @@ void UserId::setRoleTrusted() } -void UserId::sclInit(thread_db* tdbb, bool create, const UserId& tempId) +void UserId::sclInit(thread_db* tdbb, bool create) { /************************************** * @@ -1118,13 +1140,13 @@ void UserId::sclInit(thread_db* tdbb, bool create, const UserId& tempId) Database* const dbb = tdbb->getDatabase(); Jrd::Attachment* const attachment = tdbb->getAttachment(); - const TEXT* sql_role = tempId.getSqlRole().nullStr(); + const TEXT* sql_role = getSqlRole().nullStr(); // CVC: We'll verify the role and wipe it out when it doesn't exist - if (tempId.getUserName().hasData() && !create) + if (getUserName().hasData() && !create) { - const TEXT* login_name = tempId.getUserName().c_str(); + const TEXT* login_name = getUserName().c_str(); AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS); @@ -1141,17 +1163,17 @@ void UserId::sclInit(thread_db* tdbb, bool create, const UserId& tempId) if (!create && sql_role && *sql_role) { - if (!SCL_role_granted(tdbb, tempId, sql_role)) + if (!SCL_role_granted(tdbb, *this, sql_role)) sql_role = NULL; } if (!sql_role) - sql_role = tempId.getTrustedRole().nullStr(); + sql_role = getTrustedRole().nullStr(); MetaString role_name(sql_role ? sql_role : NULL_ROLE); MemoryPool& pool = *attachment->att_pool; - UserId* const user = FB_NEW_POOL(pool) UserId(pool, tempId); + UserId* const user = FB_NEW_POOL(pool) UserId(pool, *this); user->setSqlRole(role_name); user->usr_init_role = role_name; attachment->att_user = user; @@ -1771,7 +1793,11 @@ void UserId::makeRoleName(Firebird::MetaString& role, const int dialect) // Invoke utility twice: first to strip quotes, next to uppercase if needed // For unquoted string nothing bad happens fb_utils::dpbItemUpper(role); - fb_utils::dpbItemUpper(role); + { + Firebird::string tmp(role); + tmp.upper(); + role = tmp; + } break; case SQL_DIALECT_V6_TRANSITION: diff --git a/src/jrd/scl.h b/src/jrd/scl.h index 95f3b668628..15c81684a51 100644 --- a/src/jrd/scl.h +++ b/src/jrd/scl.h @@ -62,12 +62,7 @@ class SecurityClass } }; -typedef Firebird::BePlusTree< - SecurityClass*, - MetaNamePair, - Firebird::MemoryPool, - SecurityClass -> SecurityClassList; +typedef Firebird::BePlusTree SecurityClassList; const SecurityClass::flags_t SCL_select = 1; // SELECT access @@ -94,8 +89,7 @@ const SecurityClass::flags_t SCL_MODIFY_ANY = SCL_create | SCL_alter | SCL_contr const USHORT USR_mapdown = 1; // Mapping failed when getting context const USHORT USR_newrole = 2; // usr_granted_roles array needs refresh - -const USHORT USR_external = USR_mapdown; +const USHORT USR_sysdba = 4; // User detected as SYSDBA class UserId { @@ -318,7 +312,7 @@ class UserId return usr_privileges.test(sp); } - static void sclInit(thread_db* tdbb, bool create, const UserId& tempId); + void sclInit(thread_db* tdbb, bool create); void setUserName(const Firebird::MetaString& userName) { @@ -387,7 +381,7 @@ class UserId void setFlag(USHORT mask) { - usr_flags |= (mask & USR_external); + usr_flags |= mask; } static void makeRoleName(Firebird::MetaString& role, const int dialect); diff --git a/src/jrd/sdw.cpp b/src/jrd/sdw.cpp index 8b209f24093..d5d9d8d4d4f 100644 --- a/src/jrd/sdw.cpp +++ b/src/jrd/sdw.cpp @@ -186,98 +186,80 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha // and set up to release it in case of error. Align // the spare page buffer for raw disk access. - SCHAR* const spare_buffer = - FB_NEW_POOL(*tdbb->getDefaultPool()) char[dbb->dbb_page_size + PAGE_ALIGNMENT]; - // And why doesn't the code check that the allocation succeeds? + Array temp; + UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize()); + + // create the header using the spare_buffer + + header_page* header = (header_page*) spare_page; + header->hdr_header.pag_type = pag_header; + header->hdr_sequence = sequence; + header->hdr_page_size = dbb->dbb_page_size; + header->hdr_data[0] = HDR_end; + header->hdr_end = HDR_SIZE; + header->hdr_next_page = 0; + + // fool PIO_write into writing the scratch page into the correct place + BufferDesc temp_bdb(dbb->dbb_bcb); + temp_bdb.bdb_page = next->fil_min_page; + temp_bdb.bdb_buffer = (PAG) header; + header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum(); + // It's header, never encrypted + if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast(header), 0)) + return 0; - SCHAR* spare_page = FB_ALIGN(spare_buffer, PAGE_ALIGNMENT); + next->fil_fudge = 1; - try { + // Update the previous header page to point to new file -- + // we can use the same header page, suitably modified, + // because they all look pretty much the same at this point + + /******************* + Fix for bug 7925. drop_gdb wan not dropping secondary file in + multi-shadow files. The structure was not being filled with the + info. Commented some code so that the structure will always be filled. + + -Sudesh 07/06/95 + + The original code : + === + if (shadow_file == file) + copy_header(tdbb); + else + === + ************************/ - // create the header using the spare_buffer + // Temporarly reverting the change ------- Sudesh 07/07/95 ******* - header_page* header = (header_page*) spare_page; - header->hdr_header.pag_type = pag_header; - header->hdr_sequence = sequence; - header->hdr_page_size = dbb->dbb_page_size; + if (shadow_file == file) + { + copy_header(tdbb); + } + else + { + --start; header->hdr_data[0] = HDR_end; header->hdr_end = HDR_SIZE; header->hdr_next_page = 0; - // fool PIO_write into writing the scratch page into the correct place - BufferDesc temp_bdb(dbb->dbb_bcb); - temp_bdb.bdb_page = next->fil_min_page; - temp_bdb.bdb_buffer = (PAG) header; + PAG_add_header_entry(tdbb, header, HDR_file, static_cast(strlen(file_name)), + reinterpret_cast(file_name)); + PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start), + reinterpret_cast(&start)); + file->fil_fudge = 0; + temp_bdb.bdb_page = file->fil_min_page; header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum(); // It's header, never encrypted if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast(header), 0)) - { - delete[] spare_buffer; return 0; - } - next->fil_fudge = 1; - - // Update the previous header page to point to new file -- - // we can use the same header page, suitably modified, - // because they all look pretty much the same at this point - - /******************* - Fix for bug 7925. drop_gdb wan not dropping secondary file in - multi-shadow files. The structure was not being filled with the - info. Commented some code so that the structure will always be filled. - - -Sudesh 07/06/95 - - The original code : - === - if (shadow_file == file) - copy_header(tdbb); - else - === - ************************/ - - // Temporarly reverting the change ------- Sudesh 07/07/95 ******* - - if (shadow_file == file) - { - copy_header(tdbb); - } - else - { - --start; - header->hdr_data[0] = HDR_end; - header->hdr_end = HDR_SIZE; - header->hdr_next_page = 0; - - PAG_add_header_entry(tdbb, header, HDR_file, static_cast(strlen(file_name)), - reinterpret_cast(file_name)); - PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start), - reinterpret_cast(&start)); - file->fil_fudge = 0; - temp_bdb.bdb_page = file->fil_min_page; - header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum(); - // It's header, never encrypted - if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast(header), 0)) - { - delete[] spare_buffer; - return 0; - } - if (file->fil_min_page) { - file->fil_fudge = 1; - } - } if (file->fil_min_page) { file->fil_fudge = 1; } + } - delete[] spare_buffer; - - } // try - catch (const Firebird::Exception&) - { - delete[] spare_buffer; - throw; + if (file->fil_min_page) { + file->fil_fudge = 1; } return sequence; @@ -581,7 +563,11 @@ void SDW_get_shadows(thread_db* tdbb) // to prevent missing any new ones later on, although it does not // matter for the purposes of the current page being written - MET_get_shadow_files(tdbb, false); + // no use even trying to get shadow files in a case when we invoked from + // JRD_shutdown_database, i.e. there are no attachments to database + + if (tdbb->getAttachment()) + MET_get_shadow_files(tdbb, false); } @@ -1000,9 +986,9 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name, // catch errors: delete the shadow file if missing, and deallocate the spare buffer shadow = NULL; - SLONG* const spare_buffer = - FB_NEW_POOL(*tdbb->getDefaultPool()) SLONG[(dbb->dbb_page_size + PAGE_ALIGNMENT) / sizeof(SLONG)]; - UCHAR* spare_page = FB_ALIGN((UCHAR*) spare_buffer, PAGE_ALIGNMENT); + + Array temp; + UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize()); WIN window(DB_PAGE_SPACE, -1); jrd_file* shadow_file = 0; @@ -1083,8 +1069,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name, PAG_init2(tdbb, shadow_number); - delete[] spare_buffer; - } // try catch (const Firebird::Exception& ex) { @@ -1097,7 +1081,7 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name, PIO_close(shadow_file); delete shadow_file; } - delete[] spare_buffer; + if ((file_flags & FILE_manual) && !delete_files) { ERR_post(Arg::Gds(isc_shadow_missing) << Arg::Num(shadow_number)); } diff --git a/src/jrd/shut.cpp b/src/jrd/shut.cpp index 5764032b2e8..3801e7055db 100644 --- a/src/jrd/shut.cpp +++ b/src/jrd/shut.cpp @@ -26,6 +26,7 @@ #include "../jrd/scl.h" #include "../jrd/nbak.h" #include "../jrd/ods.h" +#include "../jrd/Mapping.h" #include "../jrd/cch_proto.h" #include "../jrd/cmp_proto.h" #include "../jrd/err_proto.h" @@ -222,6 +223,9 @@ void SHUT_database(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* guard) check_backup_state(tdbb); } + // Clear old mapping cache data (if present) + Mapping::clearCache(dbb->dbb_filename.c_str(), Mapping::ALL_CACHE); + attachment->att_flags |= ATT_shutdown_manager; // Database is being shutdown. First notification gives shutdown type and delay in seconds. @@ -229,14 +233,18 @@ void SHUT_database(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* guard) bool exclusive = notify_shutdown(tdbb, flag, delay, guard); bool successful = exclusive; - // Try to get exclusive database lock periodically up to specified delay. If we - // haven't gotten it report shutdown error for weaker forms. For forced shutdown - // keep notifying until successful. - SSHORT timeout = delay ? delay - 1 : 0; - if (!exclusive) + if (exclusive) { + // Ensure we have the proper DBB_shutdown_* flags in place + shutdown(tdbb, flag, false); + } + else + { + // Try to get exclusive database lock periodically up to specified delay. If we + // haven't gotten it report shutdown error for weaker forms. For forced shutdown + // keep notifying until successful. do { if (!(dbb->dbb_ast_flags & (DBB_shut_attach | DBB_shut_tran | DBB_shut_force))) @@ -401,6 +409,9 @@ void SHUT_online(thread_db* tdbb, SSHORT flag, Sync* guard) check_backup_state(tdbb); } + // Clear old mapping cache data (if present) + Mapping::clearCache(dbb->dbb_filename.c_str(), Mapping::ALL_CACHE); + // Reset shutdown flag on database header page WIN window(HEADER_PAGE_NUMBER); @@ -462,7 +473,6 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu * **************************************/ Database* const dbb = tdbb->getDatabase(); - StableAttachmentPart* const sAtt = tdbb->getAttachment()->getStable(); shutdown_data data; data.data_items.flag = flag; @@ -472,7 +482,7 @@ static bool notify_shutdown(thread_db* tdbb, SSHORT flag, SSHORT delay, Sync* gu { // scope // Checkout before calling AST function - MutexUnlockGuard uguard(*(sAtt->getMutex()), FB_FUNCTION); + EngineCheckout uguard(tdbb, FB_FUNCTION); // Notify local attachments SHUT_blocking_ast(tdbb, true); diff --git a/src/jrd/sort.cpp b/src/jrd/sort.cpp index 37f5f816407..88c2ece3353 100644 --- a/src/jrd/sort.cpp +++ b/src/jrd/sort.cpp @@ -713,6 +713,7 @@ void Sort::diddleKey(UCHAR* record, bool direction, bool duplicateHandling) for (sort_key_def* key = m_description.begin(), *end = m_description.end(); key < end; key++) { UCHAR* p = record + key->getSkdOffset(); + SORTP* lwp = (SORTP*) p; USHORT n = key->getSkdLength(); USHORT complement = key->skd_flags & SKD_descending; @@ -1956,7 +1957,7 @@ void Sort::orderAndSave(thread_db* tdbb) * scratch file as one big chunk * **************************************/ - EngineCheckout(tdbb, FB_FUNCTION); + EngineCheckout cout(tdbb, FB_FUNCTION); run_control* run = m_runs; run->run_records = 0; @@ -2052,7 +2053,7 @@ void Sort::sortBuffer(thread_db* tdbb) * been requested, detect and handle them. * **************************************/ - EngineCheckout(tdbb, FB_FUNCTION); + EngineCheckout cout(tdbb, FB_FUNCTION); // First, insert a pointer to the high key diff --git a/src/jrd/sort.h b/src/jrd/sort.h index 8e23e70ccc5..e3bbbb7779c 100644 --- a/src/jrd/sort.h +++ b/src/jrd/sort.h @@ -27,6 +27,7 @@ #include "../include/fb_blk.h" #include "../common/DecFloat.h" #include "../jrd/TempSpace.h" +#include "../jrd/align.h" namespace Jrd { diff --git a/src/jrd/svc.cpp b/src/jrd/svc.cpp index 5f3e7a2c1bf..541277f1bf7 100644 --- a/src/jrd/svc.cpp +++ b/src/jrd/svc.cpp @@ -74,6 +74,7 @@ #include "../utilities/nbackup/nbkswi.h" #include "../jrd/trace/traceswi.h" #include "../jrd/val_proto.h" +#include "../jrd/ThreadCollect.h" // Service threads #include "../burp/burp_proto.h" @@ -120,6 +121,7 @@ int main_gstat(Firebird::UtilSvc* uSvc); using namespace Firebird; +using namespace Jrd; const int SVC_user_dba = 2; const int SVC_user_any = 1; @@ -138,64 +140,9 @@ namespace { GlobalPtr globalServicesMutex; // All that we need to shutdown service threads when shutdown in progress - typedef Array AllServices; + typedef Array AllServices; GlobalPtr allServices; // protected by globalServicesMutex volatile bool svcShutdown = false; - - class ThreadCollect - { - public: - ThreadCollect(MemoryPool& p) - : threads(p) - { } - - void join() - { - // join threads to be sure they are gone when shutdown is complete - // no need locking something cause this is expected to run when services are closing - waitFor(threads); - } - - void add(const Thread::Handle& h) - { - // put thread into completion wait queue when it finished running - MutexLockGuard g(threadsMutex, FB_FUNCTION); - fb_assert(h); - threads.add(h); - } - - void houseKeeping() - { - if (!threads.hasData()) - return; - - // join finished threads - AllThreads t; - { // mutex scope - MutexLockGuard g(threadsMutex, FB_FUNCTION); - t.assign(threads); - threads.clear(); - } - - waitFor(t); - } - - private: - typedef Array AllThreads; - - static void waitFor(AllThreads& thr) - { - while (thr.hasData()) - { - Thread::Handle h(thr.pop()); - Thread::waitForCompletion(h); - } - } - - AllThreads threads; - Mutex threadsMutex; - }; - GlobalPtr threadCollect; void spbVersionError() @@ -207,8 +154,6 @@ namespace { } // anonymous namespace -using namespace Jrd; - namespace { const serv_entry services[] = { @@ -244,9 +189,9 @@ Service::Validate::Validate(Service* svc) { sharedGuard.enter(); - if (!svc->locateInAllServices()) + if (! (svc && svc->locateInAllServices())) { - // Service is so old that it's even missing in allServices array + // Service is null or so old that it's even missing in allServices array Arg::Gds(isc_bad_svc_handle).raise(); } @@ -571,19 +516,20 @@ void Service::putBytes(const UCHAR* bytes, FB_SIZE_T len) void Service::setServiceStatus(const ISC_STATUS* status_vector) { - if (checkForShutdown()) + if (checkForShutdown() || checkForFailedStart()) { return; } Arg::StatusVector passed(status_vector); + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); ERR_post_nothrow(passed, &svc_status); } void Service::setServiceStatus(const USHORT facility, const USHORT errcode, const MsgFormat::SafeArg& args) { - if (checkForShutdown()) + if (checkForShutdown() || checkForFailedStart()) { return; } @@ -601,6 +547,7 @@ void Service::setServiceStatus(const USHORT facility, const USHORT errcode, put_status_arg(status, args.getCell(loop)); } + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); ERR_post_nothrow(status, &svc_status); } @@ -636,14 +583,9 @@ void Service::hidePasswd(ArgvType&, int) // no action } -const FbStatusVector* Service::getStatus() +Service::StatusAccessor Service::getStatusAccessor() { - return &svc_status; -} - -void Service::initStatus() -{ - svc_status->init(); + return StatusAccessor(svc_status_mutex, &svc_status, this); } void Service::checkService() @@ -743,7 +685,8 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d svc_stdout_head(0), svc_stdout_tail(0), svc_service_run(NULL), svc_resp_alloc(getPool()), svc_resp_buf(0), svc_resp_ptr(0), svc_resp_buf_len(0), svc_resp_len(0), svc_flags(SVC_finished), svc_user_flag(0), svc_spb_version(0), - svc_do_shutdown(false), svc_shutdown_in_progress(false), svc_timeout(false), + svc_shutdown_server(false), svc_shutdown_request(false), + svc_shutdown_in_progress(false), svc_timeout(false), svc_username(getPool()), svc_sql_role(getPool()), svc_auth_block(getPool()), svc_expected_db(getPool()), svc_trusted_role(false), svc_utf8(false), svc_switches(getPool()), svc_perm_sw(getPool()), svc_address_path(getPool()), @@ -757,7 +700,7 @@ Service::Service(const TEXT* service_name, USHORT spb_length, const UCHAR* spb_d , svc_debug(false) #endif { - initStatus(); + svc_status->init(); { // scope // Account service block in global array @@ -919,10 +862,13 @@ void Service::detach() } // save it cause after call to finish() we can't access class members any more - const bool localDoShutdown = svc_do_shutdown; + const bool localDoShutdown = svc_shutdown_server; - TraceServiceImpl service(this); - svc_trace_manager->event_service_detach(&service, ITracePlugin::RESULT_SUCCESS); + if (svc_trace_manager->needs(ITraceFactory::TRACE_EVENT_SERVICE_DETACH)) + { + TraceServiceImpl service(this); + svc_trace_manager->event_service_detach(&service, ITracePlugin::RESULT_SUCCESS); + } // Mark service as detached. finish(SVC_detached); @@ -1002,7 +948,7 @@ ULONG Service::totalCount() bool Service::checkForShutdown() { - if (svcShutdown) + if (svcShutdown || svc_shutdown_request) { if (svc_shutdown_in_progress) { @@ -1018,6 +964,36 @@ bool Service::checkForShutdown() } +bool Service::checkForFailedStart() +{ + if ((svc_flags & SVC_evnt_fired) == 0) + { + // Service has not been started but we have got an error + svc_flags |= SVC_failed_start; + } + else if ((svc_flags & SVC_failed_start) != 0) + { + // Service has started with an error but we are trying to write one more error + return true; + } + + return false; +} + +void Service::cancel(thread_db* /*tdbb*/) +{ + svc_shutdown_request = true; + + // signal once + if (!(svc_flags & SVC_finished)) + svc_detach_sem.release(); + if (svc_stdin_size_requested) + svc_stdin_semaphore.release(); + + svc_sem_full.release(); +} + + void Service::shutdownServices() { svcShutdown = true; @@ -1140,7 +1116,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/, start_info = NULL; } - while (items < end_items2 && *items != isc_info_end) + while (items < end_items2 && *items != isc_info_end && info < end) { // if we attached to the "anonymous" service we allow only following queries: @@ -1210,7 +1186,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/, *info++ = item; if (svc_user_flag & SVC_user_dba) { - svc_do_shutdown = false; + svc_shutdown_server = false; } else need_admin_privs(status, "isc_info_svc_svr_online"); @@ -1220,7 +1196,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/, *info++ = item; if (svc_user_flag & SVC_user_dba) { - svc_do_shutdown = true; + svc_shutdown_server = true; } else need_admin_privs(status, "isc_info_svc_svr_offline"); @@ -1562,6 +1538,7 @@ ISC_STATUS Service::query2(thread_db* /*tdbb*/, throw; } + // no need locking svc_status_mutex - check single element of status vector return svc_status[1]; } @@ -1665,7 +1642,7 @@ void Service::query(USHORT send_item_length, *info++ = item; if (svc_user_flag & SVC_user_dba) { - svc_do_shutdown = false; + svc_shutdown_server = false; *info++ = 0; // Success } else @@ -1676,7 +1653,7 @@ void Service::query(USHORT send_item_length, *info++ = item; if (svc_user_flag & SVC_user_dba) { - svc_do_shutdown = true; + svc_shutdown_server = true; *info++ = 0; // Success } else @@ -1959,10 +1936,12 @@ THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg) RefPtr ref(svc->svc_existence); exit_code = svc->svc_service_run->serv_thd(svc); - threadCollect->add(svc->svc_thread); + Thread::Handle thrHandle = svc->svc_thread; svc->started(); - svc->svc_sem_full.release(); + svc->unblockQueryGet(); svc->finish(SVC_finished); + + threadCollect->ending(thrHandle); } catch (const Exception& ex) { @@ -1987,6 +1966,9 @@ void Service::start(USHORT spb_length, const UCHAR* spb_data) try { + if (!svcShutdown) + svc_shutdown_request = svc_shutdown_in_progress = false; + ClumpletReader spb(ClumpletReader::SpbStart, spb_data, spb_length); // The name of the service is the first element of the buffer @@ -2115,7 +2097,10 @@ void Service::start(USHORT spb_length, const UCHAR* spb_data) parseSwitches(); // The service block can be reused hence init a status vector. - initStatus(); + { + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); + svc_status->init(); + } if (serv->serv_thd) { @@ -2200,7 +2185,10 @@ void Service::readFbLog() { if (file != NULL) { - initStatus(); + { + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); + svc_status->init(); + } started(); svc_started = true; TEXT buffer[100]; @@ -2219,6 +2207,7 @@ void Service::readFbLog() if (!file || (file && ferror(file))) { + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); (Arg::Gds(isc_sys_request) << Arg::Str(file ? "fgets" : "fopen") << SYS_ERR(errno)).copyTo(&svc_status); if (!svc_started) @@ -2230,6 +2219,8 @@ void Service::readFbLog() catch (const Firebird::Exception& e) { setDataMode(false); + + MutexLockGuard g(svc_status_mutex, FB_FUNCTION); e.stuffException(&svc_status); } @@ -2279,7 +2270,7 @@ void Service::enqueue(const UCHAR* s, ULONG len) { if (checkForShutdown() || (svc_flags & SVC_detached)) { - svc_sem_full.release(); + unblockQueryGet(); return; } @@ -2291,13 +2282,13 @@ void Service::enqueue(const UCHAR* s, ULONG len) { if (flagFirst) { - svc_sem_full.release(); + unblockQueryGet(true); flagFirst = false; } svc_sem_empty.tryEnter(1, 0); if (checkForShutdown() || (svc_flags & SVC_detached)) { - svc_sem_full.release(); + unblockQueryGet(); return; } } @@ -2319,6 +2310,13 @@ void Service::enqueue(const UCHAR* s, ULONG len) s += cnt; len -= cnt; } + unblockQueryGet(); +} + + +void Service::unblockQueryGet(bool over) +{ + svc_output_overflow = over; svc_sem_full.release(); } @@ -2409,8 +2407,11 @@ void Service::get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, US buffer[(*return_length)++] = ch; } - if (!(flags & GET_LINE)) + if (svc_output_overflow || !(flags & GET_LINE)) + { + svc_output_overflow = false; svc_stdout_head = head; + } } if (flags & GET_LINE) @@ -2509,7 +2510,7 @@ ULONG Service::getBytes(UCHAR* buffer, ULONG size) svc_stdin_size_requested = size; svc_stdin_buffer = buffer; // Wakeup Service::query() if it waits for data from service - svc_sem_full.release(); + unblockQueryGet(); } // Wait for data from client @@ -2549,7 +2550,7 @@ void Service::finish(USHORT flag) if (svc_flags & SVC_finished) { - svc_sem_full.release(); + unblockQueryGet(); } else { @@ -2620,6 +2621,8 @@ bool Service::process_switches(ClumpletReader& spb, string& switches) string nbk_database, nbk_file, nbk_guid; int nbk_level = -1; + bool cleanHistory = false, keepHistory = false; + bool val_database = false; bool found = false; string::size_type userPos = string::npos; @@ -2690,6 +2693,30 @@ bool Service::process_switches(ClumpletReader& spb, string& switches) get_action_svc_string(spb, switches); break; + case isc_spb_nbk_clean_history: + if (cleanHistory) + { + (Arg::Gds(isc_unexp_spb_form) << Arg::Str("only one isc_spb_nbk_clean_history")).raise(); + } + if (!get_action_svc_parameter(spb.getClumpTag(), nbackup_action_in_sw_table, switches)) + { + return false; + } + cleanHistory = true; + break; + + case isc_spb_nbk_keep_days: + case isc_spb_nbk_keep_rows: + if (keepHistory) + { + (Arg::Gds(isc_unexp_spb_form) << Arg::Str("only one isc_spb_nbk_keep_days or isc_spb_nbk_keep_rows")).raise(); + } + switches += "-KEEP "; + get_action_svc_data(spb, switches, false); + switches += spb.getClumpTag() == isc_spb_nbk_keep_days ? "DAYS " : "ROWS "; + keepHistory = true; + break; + default: return false; } @@ -2884,7 +2911,7 @@ bool Service::process_switches(ClumpletReader& spb, string& switches) spb.getString(s); bool inStr = false; - for (FB_SIZE_T i = 0; i < s.length(); ++i) + for (FB_SIZE_T i = 0; i < s.length(); ) { if (s[i] == SVC_TRMNTR) { @@ -3187,6 +3214,16 @@ bool Service::process_switches(ClumpletReader& spb, string& switches) } else switches += nbk_guid; + + if (!cleanHistory && keepHistory) + { + (Arg::Gds(isc_missing_required_spb) << Arg::Str("isc_spb_nbk_clean_history")).raise(); + } + + if (cleanHistory && !keepHistory) + { + (Arg::Gds(isc_missing_required_spb) << Arg::Str("isc_spb_nbk_keep_days or isc_spb_nbk_keep_rows")).raise(); + } } switches += nbk_database; switches += nbk_file; diff --git a/src/jrd/svc.h b/src/jrd/svc.h index dd528101dcf..6eda12b6822 100644 --- a/src/jrd/svc.h +++ b/src/jrd/svc.h @@ -32,6 +32,7 @@ #include "../jrd/svc_undoc.h" #include "../common/ThreadStart.h" +#include "../common/classes/locks.h" #include "../common/classes/semaphore.h" #include "../common/classes/array.h" #include "../common/classes/SafeArg.h" @@ -98,6 +99,7 @@ const int SVC_finished = 0x10; //const int SVC_thd_running = 0x20; const int SVC_evnt_fired = 0x40; const int SVC_cmd_line = 0x80; +const int SVC_failed_start = 0x100; // forward decl. class thread_db; @@ -108,58 +110,60 @@ class Service : public Firebird::UtilSvc, public TypedHandle { public: // utilities interface with service // output to svc_stdout verbose info - virtual void outputVerbose(const char* text); + void outputVerbose(const char* text) override; // outpur error text - virtual void outputError(const char* text); + void outputError(const char* text) override; // output some data to service - virtual void outputData(const void* data, FB_SIZE_T len); + void outputData(const void* data, FB_SIZE_T len) override; // printf() to svc_stdout - virtual void printf(bool err, const SCHAR* format, ...); + void printf(bool err, const SCHAR* format, ...) override; // returns true - it's service :) - virtual bool isService(); + bool isService() override; // client thread started - virtual void started(); + void started() override; // put various info items in info buffer - virtual void putLine(char tag, const char* val); - virtual void putSLong(char tag, SLONG val); - virtual void putSInt64(char tag, SINT64 val); - virtual void putChar(char tag, char val); + void putLine(char tag, const char* val) override; + void putSLong(char tag, SLONG val) override; + void putSInt64(char tag, SINT64 val) override; + void putChar(char tag, char val) override; // put raw bytes to svc_stdout - virtual void putBytes(const UCHAR*, FB_SIZE_T); + void putBytes(const UCHAR*, FB_SIZE_T) override; // get raw bytes from svc_stdin - virtual ULONG getBytes(UCHAR*, ULONG); + ULONG getBytes(UCHAR*, ULONG) override; + +private: // append status_vector to service's status - virtual void setServiceStatus(const ISC_STATUS* status_vector); + void setServiceStatus(const ISC_STATUS* status_vector) override; // append error message to service's status - virtual void setServiceStatus(const USHORT facility, const USHORT errcode, const MsgFormat::SafeArg& args); + void setServiceStatus(const USHORT facility, const USHORT errcode, const MsgFormat::SafeArg& args) override; + +public: // no-op for services - virtual void hidePasswd(ArgvType&, int); + void hidePasswd(ArgvType&, int) override; // return service status - virtual const FbStatusVector* getStatus(); - // reset service status - virtual void initStatus(); + StatusAccessor getStatusAccessor() override; // no-op for services - virtual void checkService(); + void checkService() override; // add address path and utf8 flag (taken from spb) to dpb if present - virtual void fillDpb(Firebird::ClumpletWriter& dpb); + void fillDpb(Firebird::ClumpletWriter& dpb) override; // encoding for string parameters passed to utility - virtual bool utf8FileNames(); + bool utf8FileNames() override; // get database encryption key transfer callback routine - virtual Firebird::ICryptKeyCallback* getCryptCallback(); + Firebird::ICryptKeyCallback* getCryptCallback() override; - virtual TraceManager* getTraceManager() + TraceManager* getTraceManager() { return svc_trace_manager; } - virtual bool finished() + bool finished() override { return ((svc_flags & (SVC_finished | SVC_detached)) != 0) || checkForShutdown(); } // Get authentication block if present - virtual unsigned int getAuthBlock(const unsigned char** bytes); + unsigned int getAuthBlock(const unsigned char** bytes) override; public: // external interface with service // Attach - service ctor @@ -172,6 +176,8 @@ class Service : public Firebird::UtilSvc, public TypedHandle const UCHAR* recv_items, USHORT buffer_length, UCHAR* info); ISC_STATUS query2(thread_db* tdbb, USHORT send_item_length, const UCHAR* send_items, USHORT recv_item_length, const UCHAR* recv_items, USHORT buffer_length, UCHAR* info); + // Cancel wait in query service + void cancel(thread_db* tdbb); // Detach from service void detach(); // get service version @@ -239,6 +245,8 @@ class Service : public Firebird::UtilSvc, public TypedHandle void finish(USHORT flag); // Throws shutdown exception if global flag is set for it bool checkForShutdown(); + // Check for the existence of errors in the service that has not started + bool checkForFailedStart(); // Transfer data from svc_stdout into buffer void get(UCHAR* buffer, USHORT length, USHORT flags, USHORT timeout, USHORT* return_length); // Sends stdin for a service @@ -291,6 +299,7 @@ class Service : public Firebird::UtilSvc, public TypedHandle private: Firebird::FbLocalStatus svc_status; // status vector for running service + Firebird::Mutex svc_status_mutex; // protects svc_status from access in different threads Firebird::string svc_parsed_sw; // Here point elements of argv ULONG svc_stdout_head; ULONG svc_stdout_tail; @@ -305,7 +314,8 @@ class Service : public Firebird::UtilSvc, public TypedHandle USHORT svc_flags; USHORT svc_user_flag; USHORT svc_spb_version; - bool svc_do_shutdown; + bool svc_shutdown_server; + bool svc_shutdown_request; bool svc_shutdown_in_progress; bool svc_timeout; char svc_arg_conv[MsgFormat::SAFEARG_MAX_ARG * 2]; @@ -347,7 +357,11 @@ class Service : public Firebird::UtilSvc, public TypedHandle private: Firebird::Semaphore svc_sem_empty, svc_sem_full; + bool svc_output_overflow; + void unblockQueryGet(bool over = false); + +public: class Validate { public: @@ -355,6 +369,7 @@ class Service : public Firebird::UtilSvc, public TypedHandle Firebird::MutexEnsureUnlock sharedGuard; }; +private: class SafeMutexLock : private Validate { public: diff --git a/src/jrd/tpc.cpp b/src/jrd/tpc.cpp index edbb2612ac8..3e53e7957ef 100644 --- a/src/jrd/tpc.cpp +++ b/src/jrd/tpc.cpp @@ -31,6 +31,7 @@ #include "../jrd/ods_proto.h" #include "../jrd/tpc_proto.h" #include "../jrd/tra_proto.h" +#include "../jrd/replication/Publisher.h" #include "../common/isc_proto.h" #include @@ -109,7 +110,7 @@ bool TipCache::MemBlockInitializer::initialize(Firebird::SharedMemoryBase* sm, b } TipCache::TipCache(Database* dbb) - : m_tpcHeader(NULL), m_snapshots(NULL), m_transactionsPerBlock(0), + : m_tpcHeader(NULL), m_snapshots(NULL), m_transactionsPerBlock(0), m_lock(nullptr), globalTpcInitializer(this), snapshotsInitializer(this), memBlockInitializer(this), m_blocks_memory(*dbb->dbb_permanent) { @@ -122,18 +123,25 @@ TipCache::~TipCache() fb_assert(!m_snapshots); fb_assert(!m_tpcHeader); fb_assert(m_transactionsPerBlock == 0); + fb_assert((!m_lock.hasData()) || m_lock->lck_logical == LCK_none); + + // Avoid worse case + if (m_lock.hasData() && (m_lock->lck_logical != LCK_none)) + LCK_release(JRD_get_thread_data(), m_lock); } void TipCache::finalizeTpc(thread_db* tdbb) { + // check for finalizeTpc() called more than once + if (!m_lock.hasData()) + return; + // To avoid race conditions, this function might only // be called during database shutdown when AST delivery is already disabled // wait for all initializing processes (PR) - Lock lock(tdbb, 0, LCK_tpc_init); - - if (!LCK_lock(tdbb, &lock, LCK_SW, LCK_WAIT)) - ERR_bugcheck_msg("Unable to obtain TPC lock (SW)"); + if (!LCK_convert(tdbb, m_lock, LCK_SW, LCK_WAIT)) + ERR_bugcheck_msg("Unable to convert TPC lock (SW)"); // Release locks and deallocate all shared memory structures if (m_blocks_memory.getFirst()) @@ -145,16 +153,17 @@ void TipCache::finalizeTpc(thread_db* tdbb) } while (m_blocks_memory.getNext()); } + PathName nmSnap, nmHdr; if (m_snapshots) { - m_snapshots->removeMapFile(); + nmSnap = m_snapshots->getMapFileName(); delete m_snapshots; m_snapshots = NULL; } if (m_tpcHeader) { - m_tpcHeader->removeMapFile(); + nmHdr = m_tpcHeader->getMapFileName(); delete m_tpcHeader; m_tpcHeader = NULL; } @@ -162,7 +171,24 @@ void TipCache::finalizeTpc(thread_db* tdbb) m_blocks_memory.clear(); m_transactionsPerBlock = 0; - LCK_release(tdbb, &lock); + if (nmSnap.hasData() || nmHdr.hasData()) + { + if (LCK_lock(tdbb, m_lock, LCK_EX, LCK_NO_WAIT)) + { + if (nmSnap.hasData()) + SharedMemoryBase::unlinkFile(nmSnap.c_str()); + if (nmHdr.hasData()) + SharedMemoryBase::unlinkFile(nmHdr.c_str()); + + LCK_release(tdbb, m_lock); + } + else + tdbb->tdbb_status_vector->init(); + } + else + LCK_release(tdbb, m_lock); + + m_lock.reset(); } CommitNumber TipCache::cacheState(TraNumber number) @@ -205,17 +231,17 @@ void TipCache::initializeTpc(thread_db *tdbb) // Initialization can only be called on a TipCache that is not initialized fb_assert(!m_transactionsPerBlock); - // wait for finalizers (SW) locks - Lock lock(tdbb, 0, LCK_tpc_init); + m_lock = FB_NEW_RPT(*dbb->dbb_permanent, 0) Lock(tdbb, 0, LCK_tpc_init); - if (!LCK_lock(tdbb, &lock, LCK_PR, LCK_WAIT)) + // wait for finalizers (SW) locks + if (!LCK_lock(tdbb, m_lock, LCK_PR, LCK_WAIT)) ERR_bugcheck_msg("Unable to obtain TPC lock (PR)"); string fileName; + fileName.printf(TPC_HDR_FILE, dbb->getUniqueFileId().c_str()); try { - fileName.printf(TPC_HDR_FILE, dbb->getUniqueFileId().c_str()); m_tpcHeader = FB_NEW_POOL(*dbb->dbb_permanent) SharedMemory( fileName.c_str(), sizeof(GlobalTpcHeader), &globalTpcInitializer); } @@ -223,7 +249,7 @@ void TipCache::initializeTpc(thread_db *tdbb) { iscLogException("TPC: Cannot initialize the shared memory region (header)", ex); - LCK_release(tdbb, &lock); + LCK_convert(tdbb, m_lock, LCK_SR, LCK_WAIT); // never fails finalizeTpc(tdbb); throw; } @@ -240,14 +266,14 @@ void TipCache::initializeTpc(thread_db *tdbb) { iscLogException("TPC: Cannot initialize the shared memory region (snapshots)", ex); - LCK_release(tdbb, &lock); + LCK_convert(tdbb, m_lock, LCK_SR, LCK_WAIT); // never fails finalizeTpc(tdbb); throw; } fb_assert(m_snapshots->getHeader()->mhb_version == TPC_VERSION); - LCK_release(tdbb, &lock); + LCK_convert(tdbb, m_lock, LCK_SR, LCK_WAIT); // never fails } void TipCache::initTransactionsPerBlock(ULONG blockSize) @@ -337,23 +363,30 @@ TipCache::StatusBlockData::StatusBlockData(thread_db* tdbb, TipCache* tipCache, : blockNumber(blkNumber), memory(NULL), existenceLock(tdbb, sizeof(TpcBlockNumber), LCK_tpc_block, this, tpc_block_blocking_ast), - cache(tipCache) + cache(tipCache), + acceptAst(false) { Database* dbb = tdbb->getDatabase(); existenceLock.setKey(blockNumber); - if (!LCK_lock(tdbb, &existenceLock, LCK_SR, LCK_WAIT)) + if (!LCK_lock(tdbb, &existenceLock, LCK_PR, LCK_WAIT)) ERR_bugcheck_msg("Unable to obtain memory block lock"); - string fileName; - fileName.printf(TPC_BLOCK_FILE, dbb->getUniqueFileId().c_str(), blockNumber); + PathName fileName = makeSharedMemoryFileName(dbb, blockNumber, false); try { + // Here SharedMemory constructor is called with skipLock parameter set to true. + // Appropriate locking is performed by existenceLock using LM. + // This should be in sync with SharedMemoryBase::unlinkFile() call + // in TipCache::StatusBlockData::clear(). memory = FB_NEW_POOL(*dbb->dbb_permanent) Firebird::SharedMemory( fileName.c_str(), blockSize, &cache->memBlockInitializer, true); + + LCK_convert(tdbb, &existenceLock, LCK_SR, LCK_WAIT); // never fails + acceptAst = true; } catch (const Exception& ex) { @@ -365,6 +398,18 @@ TipCache::StatusBlockData::StatusBlockData(thread_db* tdbb, TipCache* tipCache, fb_assert(memory->getHeader()->mhb_version == TPC_VERSION); } +PathName TipCache::StatusBlockData::makeSharedMemoryFileName(Database* dbb, TpcBlockNumber n, bool fullPath) +{ + PathName fileName; + fileName.printf(TPC_BLOCK_FILE, dbb->getUniqueFileId().c_str(), n); + if (!fullPath) + return fileName; + + TEXT expanded_filename[MAXPATHLEN]; + iscPrefixLock(expanded_filename, fileName.c_str(), false); + return PathName(expanded_filename); +} + TipCache::StatusBlockData::~StatusBlockData() { thread_db* tdbb = JRD_get_thread_data(); @@ -374,13 +419,56 @@ TipCache::StatusBlockData::~StatusBlockData() void TipCache::StatusBlockData::clear(thread_db* tdbb) { // memory could be already released at tpc_block_blocking_ast + PathName fName; if (memory) { - memory->removeMapFile(); + // wait for all initializing processes (PR) + acceptAst = false; + + TraNumber oldest; + if (cache->m_tpcHeader) + oldest = cache->m_tpcHeader->getHeader()->oldest_transaction.load(std::memory_order_relaxed); + else + { + Database* dbb = tdbb->getDatabase(); + if (dbb->dbb_flags & DBB_shared) + oldest = dbb->dbb_oldest_transaction; + else + { + WIN window(HEADER_PAGE_NUMBER); + const Ods::header_page* header_page = (Ods::header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header); + oldest = Ods::getOIT(header_page); + CCH_RELEASE(tdbb, &window); + } + } + + if (blockNumber < oldest / cache->m_transactionsPerBlock && // old block => send AST + !LCK_convert(tdbb, &existenceLock, LCK_SW, LCK_WAIT)) + { + ERR_bugcheck_msg("Unable to convert TPC lock (SW)"); + } + + fName = memory->getMapFileName(); delete memory; memory = NULL; } + if (fName.hasData()) + { + // Here file is removed from SharedMemory created with skipLock parameter + // set to true. That means internal file lock is turned off. + // Appropriate locking is performed by existenceLock using LM. + // This should be in sync with SharedMemory constructor called + // in TipCache::StatusBlockData constructor. + if (LCK_lock(tdbb, &existenceLock, LCK_EX, LCK_NO_WAIT)) + SharedMemoryBase::unlinkFile(fName.c_str()); + else + { + tdbb->tdbb_status_vector->init(); + return; + } + } + LCK_release(tdbb, &existenceLock); } @@ -601,6 +689,7 @@ CommitNumber TipCache::snapshotState(thread_db* tdbb, TraNumber number) // to avoid more work in the future if (state == tra_active) { + REPL_trans_cleanup(tdbb, number); TRA_set_state(tdbb, 0, number, tra_dead); // This will update TIP cache return CN_DEAD; } @@ -629,25 +718,40 @@ int TipCache::tpc_block_blocking_ast(void* arg) { StatusBlockData* data = static_cast(arg); - Database* dbb = data->existenceLock.lck_dbb; - AsyncContextHolder tdbb(dbb, FB_FUNCTION); + try + { + Database* dbb = data->existenceLock.lck_dbb; + AsyncContextHolder tdbb(dbb, FB_FUNCTION); - TipCache* cache = data->cache; - TraNumber oldest = - cache->m_tpcHeader->getHeader()->oldest_transaction.load(std::memory_order_relaxed); + // Should we try to process AST? + if (!data->acceptAst) + return 0; - // Release shared memory - data->clear(tdbb); + TipCache* cache = data->cache; + TraNumber oldest = + cache->m_tpcHeader->getHeader()->oldest_transaction.load(std::memory_order_relaxed); - // Check if there is a bug in cleanup code and we were requested to - // release memory that might be in use - if (data->blockNumber >= oldest / cache->m_transactionsPerBlock) - ERR_bugcheck_msg("Incorrect attempt to release shared memory"); + // Is data block really old? + if (data->blockNumber >= oldest / cache->m_transactionsPerBlock) + return 0; + + // Release shared memory + if (data->memory) + { + delete data->memory; + data->memory = NULL; + } + LCK_release(tdbb, &data->existenceLock); + } + catch (const Exception&) + { } return 0; } + + void TipCache::releaseSharedMemory(thread_db* tdbb, TraNumber oldest_old, TraNumber oldest_new) { Database* dbb = tdbb->getDatabase(); @@ -664,20 +768,18 @@ void TipCache::releaseSharedMemory(thread_db* tdbb, TraNumber oldest_old, TraNum // Populate array of blocks that might be unmapped and deleted. // We scan for blocks to clean up in descending order, but delete them in // ascending order to ensure for robust operation. - string fileName; + PathName fileName; Firebird::HalfStaticArray blocksToCleanup; for (TpcBlockNumber cleanupCounter = lastInterestingBlockNumber - SAFETY_GAP_BLOCKS; cleanupCounter; cleanupCounter--) { TpcBlockNumber blockNumber = cleanupCounter - 1; - fileName.printf(TPC_BLOCK_FILE, dbb->getUniqueFileId().c_str(), blockNumber); - TEXT expanded_filename[MAXPATHLEN]; - iscPrefixLock(expanded_filename, fileName.c_str(), false); + PathName fileName = StatusBlockData::makeSharedMemoryFileName(dbb, blockNumber, true); struct stat st; // If file is not found -- look no further - if (stat(expanded_filename, &st) != 0) + if (stat(fileName.c_str(), &st) != 0) break; blocksToCleanup.add(blockNumber); @@ -708,6 +810,10 @@ void TipCache::releaseSharedMemory(thread_db* tdbb, TraNumber oldest_old, TraNum break; } + // Always delete file when EX lock is taken + PathName fileName = StatusBlockData::makeSharedMemoryFileName(dbb, blockNumber, true); + unlink(fileName.c_str()); + LCK_release(tdbb, &temp); } } diff --git a/src/jrd/tpc_proto.h b/src/jrd/tpc_proto.h index ff0c01471b8..e070e1fa69d 100644 --- a/src/jrd/tpc_proto.h +++ b/src/jrd/tpc_proto.h @@ -26,6 +26,7 @@ #include #include "../common/classes/array.h" +#include "../common/classes/fb_string.h" #include "../common/classes/SyncObject.h" namespace Ods { @@ -212,13 +213,16 @@ class TipCache Firebird::SharedMemory* memory; Lock existenceLock; TipCache* cache; + bool acceptAst; inline static TpcBlockNumber& generate(const void* /*sender*/, StatusBlockData* item) { return item->blockNumber; } - void clear(Jrd::thread_db* tdbb); + void clear(thread_db* tdbb); + + static Firebird::PathName makeSharedMemoryFileName(Database* dbb, TpcBlockNumber n, bool fullPath); }; class MemoryInitializer : public Firebird::IpcObject @@ -251,7 +255,7 @@ class TipCache bool initialize(Firebird::SharedMemoryBase* sm, bool initFlag); }; - typedef Firebird::BePlusTree BlocksMemoryMap; + typedef Firebird::BePlusTree BlocksMemoryMap; static const ULONG TPC_VERSION = 1; static const int SAFETY_GAP_BLOCKS = 1; @@ -260,6 +264,8 @@ class TipCache Firebird::SharedMemory* m_snapshots; // final ULONG m_transactionsPerBlock; // final. When set, we assume TPC has been initialized. + Firebird::AutoPtr m_lock; + GlobalTpcInitializer globalTpcInitializer; SnapshotsInitializer snapshotsInitializer; MemBlockInitializer memBlockInitializer; diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index 734b8b81731..c5d9a741070 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -238,6 +238,15 @@ void TRA_detach_request(Jrd::jrd_req* request) // Release stored looper savepoints Savepoint::destroy(request->req_savepoints); + fb_assert(!request->req_savepoints); + + // Release procedure savepoints used by this request + if (request->req_proc_sav_point) + { + fb_assert(request->req_flags & req_proc_fetch); + Savepoint::destroy(request->req_proc_sav_point); + fb_assert(!request->req_proc_sav_point); + } // Remove request from the doubly linked list if (request->req_tra_next) @@ -530,8 +539,8 @@ void TRA_commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_flag // Set the state on the inventory page to be committed - TRA_set_state(tdbb, transaction, transaction->tra_number, tra_committed); REPL_trans_commit(tdbb, transaction); + TRA_set_state(tdbb, transaction, transaction->tra_number, tra_committed); // Perform any post commit work @@ -581,24 +590,24 @@ void TRA_extend_tip(thread_db* tdbb, ULONG sequence) //, WIN* precedence_window) CCH_must_write(tdbb, &window); CCH_RELEASE(tdbb, &window); + const ULONG pageNumber = window.win_page.getPageNum(); + // Release prior page if (sequence) { CCH_MARK_MUST_WRITE(tdbb, &prior_window); - prior_tip->tip_next = window.win_page.getPageNum(); + prior_tip->tip_next = pageNumber; CCH_RELEASE(tdbb, &prior_window); } // Link into internal data structures - vcl* vector = dbb->dbb_t_pages = - vcl::newVector(*dbb->dbb_permanent, dbb->dbb_t_pages, sequence + 1); - (*vector)[sequence] = window.win_page.getPageNum(); + dbb->setKnownPage(pag_transactions, sequence, pageNumber); // Write into pages relation - DPM_pages(tdbb, 0, pag_transactions, sequence, window.win_page.getPageNum()); + DPM_pages(tdbb, 0, pag_transactions, sequence, pageNumber); } @@ -1235,6 +1244,8 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction, Jrd::TraceTr blb::release_array(transaction->tra_arrays); } + fb_assert(transaction->tra_temp_blobs_count == 0); + if (transaction->tra_pool) { // Iterate the doubly linked list of requests for transaction and null out the transaction references @@ -1455,8 +1466,8 @@ void TRA_rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining_fl return; } - TRA_set_state(tdbb, transaction, transaction->tra_number, state); REPL_trans_rollback(tdbb, transaction); + TRA_set_state(tdbb, transaction, transaction->tra_number, state); TRA_release_transaction(tdbb, transaction, &trace); } @@ -1687,7 +1698,11 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t Database* const dbb = tdbb->getDatabase(); Jrd::Attachment* const attachment = tdbb->getAttachment(); - if (dbb->dbb_ast_flags & DBB_shut_tran) + // Starting new transactions should be allowed for threads which + // are running purge_attachment() because it's needed for + // ON DISCONNECT triggers + if (dbb->dbb_ast_flags & DBB_shut_tran && + attachment->att_purge_tid != Thread::getId()) { ERR_post(Arg::Gds(isc_shutinprog) << Arg::Str(attachment->att_filename)); } @@ -1740,7 +1755,11 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const UCHAR* tpb, Jrd::jrd_t Database* dbb = tdbb->getDatabase(); Jrd::Attachment* attachment = tdbb->getAttachment(); - if (dbb->dbb_ast_flags & DBB_shut_tran) + // Starting new transactions should be allowed for threads which + // are running purge_attachment() because it's needed for + // ON DISCONNECT triggers + if (dbb->dbb_ast_flags & DBB_shut_tran && + attachment->att_purge_tid != Thread::getId()) { ERR_post(Arg::Gds(isc_shutinprog) << Arg::Str(attachment->att_filename)); } @@ -1992,8 +2011,8 @@ int TRA_wait(thread_db* tdbb, jrd_tra* trans, TraNumber number, jrd_tra::wait_t if (state == tra_active) { state = tra_dead; - TRA_set_state(tdbb, 0, number, tra_dead); REPL_trans_cleanup(tdbb, number); + TRA_set_state(tdbb, 0, number, tra_dead); } // If the transaction disappeared into limbo, died, for constructively @@ -2102,7 +2121,17 @@ static header_page* bump_transaction_id(thread_db* tdbb, WIN* window, bool dontW const bool new_tip = ((number % dbb->dbb_page_manager.transPerTIP) == 0); if (new_tip) - TRA_extend_tip(tdbb, (number / dbb->dbb_page_manager.transPerTIP)); //, window); + { + try + { + TRA_extend_tip(tdbb, (number / dbb->dbb_page_manager.transPerTIP)); //, window); + } + catch (Exception&) + { + CCH_RELEASE(tdbb, window); + throw; + } + } // Extend, if necessary, has apparently succeeded. Next, update header page @@ -2337,19 +2366,21 @@ static ULONG inventory_page(thread_db* tdbb, ULONG sequence) Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - WIN window(DB_PAGE_SPACE, -1); - vcl* vector = dbb->dbb_t_pages; - while (!vector || sequence >= vector->count()) + if (const ULONG pageno = dbb->getKnownPage(pag_transactions, sequence)) + return pageno; + + while (sequence >= dbb->getKnownPagesCount(pag_transactions)) { DPM_scan_pages(tdbb); - if ((vector = dbb->dbb_t_pages) && sequence < vector->count()) + const ULONG tipCount = dbb->getKnownPagesCount(pag_transactions); + if (sequence < tipCount) break; - if (!vector) + if (!tipCount) BUGCHECK(165); // msg 165 cannot find tip page - window.win_page = (*vector)[vector->count() - 1]; + WIN window(DB_PAGE_SPACE, dbb->getKnownPage(pag_transactions, tipCount - 1)); tx_inv_page* tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_transactions); const ULONG next = tip->tip_next; CCH_RELEASE(tdbb, &window); @@ -2359,10 +2390,10 @@ static ULONG inventory_page(thread_db* tdbb, ULONG sequence) // Type check it tip = (tx_inv_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_transactions); CCH_RELEASE(tdbb, &window); - DPM_pages(tdbb, 0, pag_transactions, vector->count(), window.win_page.getPageNum()); + DPM_pages(tdbb, 0, pag_transactions, tipCount, window.win_page.getPageNum()); } - return (*vector)[sequence]; + return dbb->getKnownPage(pag_transactions, sequence); } @@ -2619,13 +2650,13 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, bool commit, i if (!dbb->readOnly()) { - // Set the state on the inventory page - TRA_set_state(tdbb, transaction, old_number, state); - if (commit) REPL_trans_commit(tdbb, transaction); else REPL_trans_rollback(tdbb, transaction); + + // Set the state on the inventory page + TRA_set_state(tdbb, transaction, old_number, state); } if (dbb->dbb_config->getClearGTTAtRetaining()) release_temp_tables(tdbb, transaction); @@ -2679,11 +2710,6 @@ namespace { : dbb(d) { } - void waitForStartup() - { - sem.enter(); - } - static void runSweep(SweepParameter* par) { FbLocalStatus status; @@ -2706,7 +2732,6 @@ namespace { prov->setDbCryptCallback(&status, cryptCallback); status.check(); } - par->sem.release(); AutoDispose dpb(UtilInterfacePtr()->getXpbBuilder(&status, IXpbBuilder::DPB, nullptr, 0)); status.check(); @@ -2730,14 +2755,26 @@ namespace { ex.stuffException(&st); if (st->getErrors()[1] != isc_att_shutdown) iscLogException("Automatic sweep error", ex); + + if (dbb) + { + dbb->clearSweepStarting(); + SPTHR_DEBUG(fprintf(stderr, "called clearSweepStarting() dbb=%p par=%p\n", dbb, this)); + dbb = nullptr; + } + } + + static void cleanup(SweepParameter* par) + { + SPTHR_DEBUG(fprintf(stderr, "Cleanup dbb=%p par=%p\n", par->dbb, par)); + delete par; } private: - Semaphore sem; Database* dbb; }; - typedef ThreadFinishSync SweepSync; + typedef ThreadFinishSync SweepSync; InitInstance > sweepThreads; GlobalPtr swThrMutex; bool sweepDown = false; @@ -2809,10 +2846,9 @@ static void start_sweeper(thread_db* tdbb) } AutoPtr sweepSync(FB_NEW SweepSync(*getDefaultMemoryPool(), SweepParameter::runSweep)); - SweepParameter swPar(dbb); - sweepSync->run(&swPar); + SweepParameter* swPar = FB_NEW SweepParameter(dbb); + sweepSync->run(swPar); started = true; - swPar.waitForStartup(); sweepThreads().add(sweepSync.release()); } catch (const Exception&) @@ -3546,16 +3582,8 @@ static void transaction_start(thread_db* tdbb, jrd_tra* trans) if (!(trans->tra_flags & TRA_read_committed)) { - try - { - trans->tra_snapshot_handle = dbb->dbb_tip_cache->beginSnapshot( - tdbb, attachment->att_attachment_id, trans->tra_snapshot_number); - } - catch (const Firebird::Exception&) - { - LCK_release(tdbb, lock); - throw; - } + trans->tra_snapshot_handle = dbb->dbb_tip_cache->beginSnapshot( + tdbb, attachment->att_attachment_id, trans->tra_snapshot_number); } // Next task is to find the oldest active transaction on the system. This @@ -3734,6 +3762,8 @@ static void transaction_start(thread_db* tdbb, jrd_tra* trans) } catch (const Firebird::Exception&) { + LCK_release(tdbb, lock); + trans->tra_lock = nullptr; trans->unlinkFromAttachment(); throw; } @@ -3749,6 +3779,7 @@ jrd_tra::~jrd_tra() delete tra_user_management; delete tra_timezone_snapshot; delete tra_mapping_list; + delete tra_dbcreators_list; delete tra_gen_ids; if (!tra_outer) @@ -4029,6 +4060,7 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool if (tra_attachment->isGbak() || (tra_attachment->locksmith(tdbb, SELECT_ANY_OBJECT_IN_DATABASE)) || + (tra_flags & TRA_no_blob_check) || rel_id == 0) { return; @@ -4040,13 +4072,17 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool vec* vector = tra_attachment->att_relations; jrd_rel* blb_relation; - if (rel_id < vector->count() && (blb_relation = (*vector)[rel_id])) + if ((rel_id < vector->count() && (blb_relation = (*vector)[rel_id])) || + (blb_relation = MET_relation(tdbb, rel_id))) { - const MetaName security_name = fld ? + MetaName security_name = (fld && fld->fld_security_name.hasData()) ? fld->fld_security_name : blb_relation->rel_security_name; if (security_name.isEmpty()) + { MET_scan_relation(tdbb, blb_relation); + security_name = blb_relation->rel_security_name; + } SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str()); @@ -4133,7 +4169,7 @@ TraceSweepEvent::TraceSweepEvent(thread_db* tdbb) gds__log("Sweep is started by %s\n" "\tDatabase \"%s\" \n" "\tOIT %" SQUADFORMAT", OAT %" SQUADFORMAT", OST %" SQUADFORMAT", Next %" SQUADFORMAT, - att->att_user ? att->att_user->getUserName().c_str() : "", + att->getUserName("").c_str(), att->att_filename.c_str(), m_sweep_info.getOIT(), m_sweep_info.getOAT(), diff --git a/src/jrd/tra.h b/src/jrd/tra.h index 68d02ccc327..1b976a3fa44 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -103,8 +103,8 @@ struct BlobIndex { } }; -typedef Firebird::BePlusTree BlobIndexTree; -typedef Firebird::BePlusTree FetchedBlobIdTree; +typedef Firebird::BePlusTree BlobIndexTree; +typedef Firebird::BePlusTree FetchedBlobIdTree; // Transaction block @@ -149,6 +149,7 @@ typedef Firebird::GenericMap > const int DEFAULT_LOCK_TIMEOUT = -1; // infinite const char* const TRA_BLOB_SPACE = "fb_blob_"; const char* const TRA_UNDO_SPACE = "fb_undo_"; +const int MAX_TEMP_BLOBS = 1000; class jrd_tra : public pool_alloc { @@ -169,9 +170,9 @@ class jrd_tra : public pool_alloc : tra_attachment(attachment), tra_pool(p), tra_memory_stats(parent_stats), - tra_blobs_tree(p), + tra_blobs_tree(*p), tra_blobs(outer ? outer->tra_blobs : &tra_blobs_tree), - tra_fetched_blobs(p), + tra_fetched_blobs(*p), tra_repl_blobs(*p), tra_arrays(NULL), tra_deferred_job(NULL), @@ -285,6 +286,7 @@ class jrd_tra : public pool_alloc UCHAR tra_callback_count; // callback count for 'execute statement' SSHORT tra_lock_timeout; // in seconds, -1 means infinite, 0 means NOWAIT ULONG tra_next_blob_id; // ID of the previous blob or array created in this transaction + ULONG tra_temp_blobs_count; // Number of active temporary blobs const ISC_TIMESTAMP_TZ tra_timestamp; // transaction start time jrd_req* tra_requests; // Doubly linked list of requests active in this transaction MonitoringSnapshot* tra_mon_snapshot; // Database state snapshot (for monitoring purposes) @@ -358,15 +360,16 @@ class jrd_tra : public pool_alloc Record* const record = *iter; fb_assert(record); - if (!record->testFlags(REC_undo_active)) + if (!record->isTempActive()) { // initialize record for reuse - record->reset(format, REC_undo_active); + record->reset(format); + record->setTempActive(); return record; } } - Record* const record = FB_NEW_POOL(*tra_pool) Record(*tra_pool, format, REC_undo_active); + Record* const record = FB_NEW_POOL(*tra_pool) Record(*tra_pool, format, true); tra_undo_records.add(record); return record; @@ -426,6 +429,7 @@ const ULONG TRA_own_interface = 0x20000L; // tra_interface was created for int const ULONG TRA_read_consistency = 0x40000L; // ensure read consistency in this transaction const ULONG TRA_ex_restart = 0x80000L; // Exception was raised to restart request const ULONG TRA_replicating = 0x100000L; // transaction is allowed to be replicated +const ULONG TRA_no_blob_check = 0x200000L; // disable blob access checking // flags derived from TPB, see also transaction_options() at tra.cpp const ULONG TRA_OPTIONS_MASK = (TRA_degree3 | TRA_readonly | TRA_ignore_limbo | TRA_read_committed | diff --git a/src/jrd/trace/TraceConfigStorage.cpp b/src/jrd/trace/TraceConfigStorage.cpp index c46a3144fb9..eb59d75bcbe 100644 --- a/src/jrd/trace/TraceConfigStorage.cpp +++ b/src/jrd/trace/TraceConfigStorage.cpp @@ -87,12 +87,11 @@ void checkFileError(const char* filename, const char* operation, ISC_STATUS iscE ConfigStorage::ConfigStorage() : m_timer(FB_NEW TouchFile), m_sharedMemory(NULL), + m_filename(getPool()), m_recursive(0), m_mutexTID(0), - m_dirty(false), - m_nextIdx(0) + m_dirty(false) { - PathName filename; #ifdef WIN_NT DWORD sesID = 0; @@ -108,36 +107,23 @@ ConfigStorage::ConfigStorage() pfnProcessIdToSessionId(GetCurrentProcessId(), &sesID) == 0 || sesID == 0) { - filename.printf(TRACE_FILE); // TODO: it must be per engine instance + m_filename.printf(TRACE_FILE); // TODO: it must be per engine instance } else { - filename.printf("%s.%u", TRACE_FILE, sesID); + m_filename.printf("%s.%u", TRACE_FILE, sesID); } #else - filename.printf(TRACE_FILE); // TODO: it must be per engine instance + m_filename.printf(TRACE_FILE); // TODO: it must be per engine instance #endif - try - { - m_sharedMemory.reset(FB_NEW_POOL(getPool()) - SharedMemory(filename.c_str(), TraceCSHeader::TRACE_STORAGE_MIN_SIZE, this)); - } - catch (const Exception& ex) - { - iscLogException("ConfigStorage: Cannot initialize the shared memory region", ex); - throw; - } - - fb_assert(m_sharedMemory->getHeader()); - fb_assert(m_sharedMemory->getHeader()->mhb_version == TraceCSHeader::TRACE_STORAGE_VERSION); + initSharedFile(); StorageGuard guard(this); checkAudit(); TEXT fullName[MAXPATHLEN]; - iscPrefixLock(fullName, filename.c_str(), false); - + iscPrefixLock(fullName, m_filename.c_str(), false); m_timer->start(fullName); // do we still need a timer ? ++(m_sharedMemory->getHeader()->cnt_uses); @@ -148,6 +134,23 @@ ConfigStorage::~ConfigStorage() fb_assert(!m_timer); } +void ConfigStorage::initSharedFile() +{ + try + { + m_sharedMemory.reset(FB_NEW_POOL(getPool()) + SharedMemory(m_filename.c_str(), TraceCSHeader::TRACE_STORAGE_MIN_SIZE, this)); + + fb_assert(m_sharedMemory->getHeader()); + fb_assert(m_sharedMemory->getHeader()->mhb_version == TraceCSHeader::TRACE_STORAGE_VERSION); + } + catch (const Exception& ex) + { + iscLogException("ConfigStorage: Cannot initialize the shared memory region", ex); + throw; + } +} + void ConfigStorage::shutdown() { if (!m_timer) @@ -160,6 +163,7 @@ void ConfigStorage::shutdown() { StorageGuard guard(this); + fb_assert(m_sharedMemory->getHeader()->cnt_uses != 0); --(m_sharedMemory->getHeader()->cnt_uses); if (m_sharedMemory->getHeader()->cnt_uses == 0) { @@ -258,7 +262,7 @@ void ConfigStorage::checkAudit() } p[len] = 0; } - else + else { gds__log("Audit configuration file \"%s\" is empty", configFileName.c_str()); return; @@ -299,6 +303,20 @@ void ConfigStorage::acquire() fb_assert(m_mutexTID == 0); m_mutexTID = currTID; + while (m_sharedMemory->getHeader()->isDeleted()) + { + // Shared memory must be empty at this point + fb_assert(m_sharedMemory->getHeader()->cnt_uses == 0); + + m_sharedMemory->mutexUnlock(); + m_sharedMemory.reset(); + + Thread::yield(); + + initSharedFile(); + m_sharedMemory->mutexLock(); + } + TraceCSHeader* header = m_sharedMemory->getHeader(); if (header->mem_allocated > m_sharedMemory->sh_mem_length_mapped) { @@ -443,7 +461,7 @@ struct SlotByOffset static ULONG generate(const SlotByOffset& i) { return i.offset; } }; -typedef SortedArray, ULONG, SlotByOffset> +typedef SortedArray, ULONG, SlotByOffset> SlotsByOffsetArray; @@ -458,13 +476,20 @@ void ConfigStorage::compact() ULONG check_used, check_size; check_used = check_size = sizeof(TraceCSHeader); + // Track undeleted slots from dead processes + Firebird::SortedArray> deadProcesses; + // collect used slots, sort them by offset for (TraceCSHeader::Slot* slot = header->slots; slot < header->slots + header->slots_cnt; slot++) { - if (!slot->used && slot->ses_pid != pid && + if (slot->used && slot->ses_pid != pid && + ((slot->ses_flags & trs_system) == 0) && // System sessions are shared for multiple connections so they may live without the original process !ISC_check_process_existence(slot->ses_pid)) { - header->cnt_uses--; // Process that created trace session disappeared, count it out + // A SUPER server may shut down, but its Storage shared memory continues to live due to an embedded user session. + // The process might allocate multiple slots, so count them carefully. + deadProcesses.add(slot->ses_pid); + markDeleted(slot); } @@ -477,6 +502,11 @@ void ConfigStorage::compact() data.add(item); } + // Process that created storages disappeared, count it out + fb_assert(header->cnt_uses > deadProcesses.getCount()); + header->cnt_uses -= deadProcesses.getCount(); + deadProcesses.clear(); + fb_assert(check_used == header->mem_used); fb_assert(check_size == header->mem_offset); @@ -632,10 +662,10 @@ bool ConfigStorage::validate() ULONG ConfigStorage::getSessionSize(const TraceSession& session) { ULONG ret = 1; // tagEnd - const ULONG sz = 1 + sizeof(ULONG); // sizeof tag + sizeof len + const ULONG sz = 1 + sizeof(ULONG); // sizeof tag + sizeof len ULONG len = session.ses_name.length(); - if (len) + if (len) ret += sz + len; if ((len = session.ses_auth.getCount())) @@ -732,19 +762,14 @@ bool ConfigStorage::getSession(Firebird::TraceSession& session, GET_FLAGS getFla return readSession(slot, session, getFlag); } -void ConfigStorage::restart() -{ - m_nextIdx = 0; -} - -bool ConfigStorage::getNextSession(TraceSession& session, GET_FLAGS getFlag) +bool ConfigStorage::getNextSession(TraceSession& session, GET_FLAGS getFlag, ULONG& nextIdx) { TraceCSHeader* header = m_sharedMemory->getHeader(); - while (m_nextIdx < header->slots_cnt) + while (nextIdx < header->slots_cnt) { - TraceCSHeader::Slot* slot = header->slots + m_nextIdx; - m_nextIdx++; + TraceCSHeader::Slot* slot = header->slots + nextIdx; + nextIdx++; if (slot->used) return readSession(slot, session, getFlag); @@ -883,6 +908,31 @@ void ConfigStorage::updateFlags(TraceSession& session) slot->ses_flags = session.ses_flags; } +bool ConfigStorage::Accessor::getNext(TraceSession& session, GET_FLAGS getFlag) +{ + if (m_guard) + return m_storage->getNextSession(session, getFlag, m_nextIdx); + + StorageGuard guard(m_storage); + + // Restore position, if required: find index of slot with session ID greater than m_sesId. + if (m_change_number != m_storage->getChangeNumber()) + { + if (m_storage->findSession(m_sesId, m_nextIdx)) + m_nextIdx++; + + m_change_number = m_storage->getChangeNumber(); + } + + if (m_storage->getNextSession(session, getFlag, m_nextIdx)) + { + m_sesId = session.ses_id; + return true; + } + + return false; +} + void ConfigStorage::Writer::write(ITEM tag, ULONG len, const void* data) { if (m_mem + 1 > m_end) diff --git a/src/jrd/trace/TraceConfigStorage.h b/src/jrd/trace/TraceConfigStorage.h index 19c985c785b..0903d43a683 100644 --- a/src/jrd/trace/TraceConfigStorage.h +++ b/src/jrd/trace/TraceConfigStorage.h @@ -44,11 +44,13 @@ namespace Jrd { Slots are sorted by session id. Slot for new session is always last slot. When session is removed its slot is marked as unused. - Unused slot could be reused: slot itself moved at last position in slots array, + Unused slot could be reused: slot itself moved at last position in slots array, higher slots are moved down on its former place, slot data is not moved. Slot is reused with best-fit algorithm. */ +class StorageGuard; + struct TraceCSHeader : public Firebird::MemoryHeader { static const USHORT TRACE_STORAGE_VERSION = 2; @@ -78,7 +80,7 @@ struct TraceCSHeader : public Firebird::MemoryHeader Slot slots[TRACE_STORAGE_MAX_SLOTS]; }; -static_assert(sizeof(TraceCSHeader) < TraceCSHeader::TRACE_STORAGE_MIN_SIZE, +static_assert(sizeof(TraceCSHeader) < TraceCSHeader::TRACE_STORAGE_MIN_SIZE, "TraceCSHeader not fits TRACE_STORAGE_MIN_SIZE"); @@ -97,9 +99,6 @@ class ConfigStorage FB_FINAL : public Firebird::GlobalStorage, public Firebird:: // get session by sesion id bool getSession(Firebird::TraceSession& session, GET_FLAGS getFlag); - void restart(); - bool getNextSession(Firebird::TraceSession& session, GET_FLAGS getFlag); - ULONG getChangeNumber() const { return m_sharedMemory && m_sharedMemory->getHeader() ? m_sharedMemory->getHeader()->change_number : 0; } @@ -110,10 +109,41 @@ class ConfigStorage FB_FINAL : public Firebird::GlobalStorage, public Firebird:: Firebird::Mutex m_localMutex; + class Accessor + { + public: + // Use when storage is not locked by caller + explicit Accessor(ConfigStorage* storage) : + m_storage(storage), + m_guard(nullptr) + {} + + // Use when storage is locked by caller + explicit Accessor(StorageGuard* guard); + + void restart() + { + m_change_number = 0; + m_sesId = 0; + m_nextIdx = 0; + } + + bool getNext(Firebird::TraceSession& session, GET_FLAGS getFlag); + + private: + ConfigStorage* const m_storage; + StorageGuard* const m_guard; + ULONG m_change_number = 0; + ULONG m_sesId = 0; // last seen session ID + ULONG m_nextIdx = 0; // slot index next after last seen one + }; + private: void mutexBug(int osErrorCode, const char* text); bool initialize(Firebird::SharedMemoryBase*, bool); + void initSharedFile(); + void checkAudit(); class TouchFile FB_FINAL : @@ -166,7 +196,7 @@ class ConfigStorage FB_FINAL : public Firebird::GlobalStorage, public Firebird:: ULONG allocSlot(ULONG slotSize); void markDeleted(TraceCSHeader::Slot * slot); - // remove unused space between slots data + // remove unused space between slots data void compact(); bool validate(); @@ -175,6 +205,10 @@ class ConfigStorage FB_FINAL : public Firebird::GlobalStorage, public Firebird:: bool findSession(ULONG sesId, ULONG& idx); bool readSession(TraceCSHeader::Slot* slot, Firebird::TraceSession& session, GET_FLAGS getFlag); + // Search for used slot starting from nextIdx and increments nextIdx to point to the next slot + // returns false, if used slot was not found + bool getNextSession(Firebird::TraceSession& session, GET_FLAGS getFlag, ULONG& nextIdx); + class Reader { public: @@ -207,10 +241,10 @@ class ConfigStorage FB_FINAL : public Firebird::GlobalStorage, public Firebird:: }; Firebird::AutoPtr > m_sharedMemory; + Firebird::PathName m_filename; int m_recursive; ThreadId m_mutexTID; bool m_dirty; - ULONG m_nextIdx; // getNextSession() iterator index }; @@ -258,10 +292,22 @@ class StorageGuard : public Firebird::MutexLockGuard { m_storage->release(); } + + ConfigStorage* getStorage() + { + return m_storage; + } + private: ConfigStorage* m_storage; }; + +inline ConfigStorage::Accessor::Accessor(StorageGuard* guard) : + m_storage(guard->getStorage()), + m_guard(guard) +{} + } #endif diff --git a/src/jrd/trace/TraceDSQLHelpers.h b/src/jrd/trace/TraceDSQLHelpers.h index cb4a1769752..edeb62b4d51 100644 --- a/src/jrd/trace/TraceDSQLHelpers.h +++ b/src/jrd/trace/TraceDSQLHelpers.h @@ -39,14 +39,14 @@ class TraceDSQLPrepare { public: TraceDSQLPrepare(Attachment* attachment, jrd_tra* transaction, - FB_SIZE_T string_length, const TEXT* string) + FB_SIZE_T string_length, const TEXT* string, bool isInternal) : m_attachment(attachment), m_transaction(transaction), m_request(NULL), m_string_len(string_length), m_string(string) { - m_need_trace = TraceManager::need_dsql_prepare(m_attachment); + m_need_trace = !isInternal && TraceManager::need_dsql_prepare(m_attachment); if (!m_need_trace) return; @@ -131,12 +131,12 @@ class TraceDSQLExecute fb_assert(!m_request->req_fetch_baseline); m_request->req_fetch_baseline = NULL; + MemoryPool* pool = MemoryPool::getContextPool(); jrd_req* jrd_request = m_request->req_request; if (jrd_request) - { - MemoryPool* pool = MemoryPool::getContextPool(); m_request->req_fetch_baseline = FB_NEW_POOL(*pool) RuntimeStatistics(*pool, jrd_request->req_stats); - } + else + m_request->req_fetch_baseline = FB_NEW_POOL(*pool) RuntimeStatistics(*pool, m_attachment->att_stats); } void finish(bool have_cursor, ntrace_result_t result) @@ -152,7 +152,7 @@ class TraceDSQLExecute } TraceRuntimeStats stats(m_attachment, m_request->req_fetch_baseline, - m_request->req_request ? &m_request->req_request->req_stats : NULL, + m_request->req_request ? &m_request->req_request->req_stats : &m_attachment->att_stats, fb_utils::query_performance_counter() - m_start_clock, m_request->req_fetch_rowcount); diff --git a/src/jrd/trace/TraceLog.cpp b/src/jrd/trace/TraceLog.cpp index b32bdc7d9d0..5a00b489def 100644 --- a/src/jrd/trace/TraceLog.cpp +++ b/src/jrd/trace/TraceLog.cpp @@ -235,10 +235,24 @@ void TraceLog::extend(FB_SIZE_T size) const FB_SIZE_T toMoveR = oldSize - header->readPos; char* data = reinterpret_cast (header); + const FB_SIZE_T deltaSize = newSize - oldSize; + if (toMoveW < toMoveR) { - memcpy(data + oldSize, data + sizeof(TraceLogHeader), toMoveW); - header->writePos = oldSize + toMoveW; + if (toMoveW <= deltaSize) + { + memcpy(data + oldSize, data + sizeof(TraceLogHeader), toMoveW); + header->writePos = oldSize + toMoveW; + + if (header->writePos == header->allocated) + header->writePos = sizeof(TraceLogHeader); + } + else + { + memcpy(data + oldSize, data + sizeof(TraceLogHeader), deltaSize); + memcpy(data + sizeof(TraceLogHeader), data + sizeof(TraceLogHeader) + deltaSize, toMoveW - deltaSize); + header->writePos -= deltaSize; + } } else { diff --git a/src/jrd/trace/TraceManager.cpp b/src/jrd/trace/TraceManager.cpp index 38e27c70e0f..806a8c4800d 100644 --- a/src/jrd/trace/TraceManager.cpp +++ b/src/jrd/trace/TraceManager.cpp @@ -104,12 +104,14 @@ TraceManager::TraceManager(Service* in_svc) : init(); } -TraceManager::TraceManager(const char* in_filename) : +TraceManager::TraceManager(const char* in_filename, ICryptKeyCallback* cb, bool failed) : attachment(NULL), service(NULL), filename(in_filename), + callback(cb), trace_sessions(*getDefaultMemoryPool()), - active(true) + active(true), + failedAttach(failed) { init(); } @@ -184,18 +186,22 @@ void TraceManager::update_sessions() { // scope ConfigStorage* storage = getStorage(); + // don't attach going attachment to the new trace sessions, it allows + // to avoid problems later - when mapping uses this going attachment + const bool noNewSessions = attachment && (attachment->att_purge_tid); + StorageGuard guard(storage); - storage->restart(); + ConfigStorage::Accessor acc(&guard); TraceSession session(pool); - while (storage->getNextSession(session, ConfigStorage::FLAGS)) + while (acc.getNext(session, ConfigStorage::FLAGS)) { if ((session.ses_flags & trs_active) && !(session.ses_flags & trs_log_full)) { FB_SIZE_T pos; if (trace_sessions.find(session.ses_id, pos)) liveSessions.add(session.ses_id); - else + else if (!noNewSessions) { storage->getSession(session, ConfigStorage::ALL); newSessions.add(FB_NEW_POOL(pool) TraceSession(pool, session)); @@ -222,6 +228,8 @@ void TraceManager::update_sessions() } // add new sessions + new_needs = trace_needs; + trace_needs = 0; while (newSessions.hasData()) { TraceSession* s = newSessions.pop(); @@ -234,6 +242,10 @@ void TraceManager::update_sessions() { trace_needs = 0; } + else + { + trace_needs = new_needs; + } } void TraceManager::update_session(const TraceSession& session) @@ -262,10 +274,10 @@ void TraceManager::update_session(const TraceSession& session) if ((!attachment->att_user) || (attachment->att_flags & ATT_mapping)) return; - curr_user = attachment->att_user->getUserName().c_str(); + curr_user = attachment->getUserName().c_str(); if (session.ses_auth.hasData()) - { // scope + { AutoSetRestoreFlag autoRestore(&attachment->att_flags, ATT_mapping, true); Database* dbb = attachment->att_database; @@ -275,8 +287,12 @@ void TraceManager::update_session(const TraceSession& session) mapping.setAuthBlock(session.ses_auth); mapping.setSqlRole(session.ses_role); mapping.setSecurityDbAlias(dbb->dbb_config->getSecurityDatabase(), dbb->dbb_filename.c_str()); + + fb_assert(attachment->getInterface()); mapping.setDb(attachment->att_filename.c_str(), dbb->dbb_filename.c_str(), attachment->getInterface()); + + EngineCheckout guard(attachment, FB_FUNCTION); mapResult = mapping.mapUser(s_user, t_role); } } @@ -300,6 +316,27 @@ void TraceManager::update_session(const TraceSession& session) mapResult = mapping.mapUser(s_user, t_role); } } + else if (filename) + { + if (session.ses_auth.hasData()) + { + Mapping mapping(Mapping::MAP_NO_FLAGS, callback); + mapping.needSystemPrivileges(priv); + mapping.setAuthBlock(session.ses_auth); + mapping.setSqlRole(session.ses_role); + + RefPtr config; + PathName org_filename(filename), expanded_name; + if (! expandDatabaseName(org_filename, expanded_name, &config)) + expanded_name = filename; + + mapping.setSecurityDbAlias(config->getSecurityDatabase(), expanded_name.c_str()); + if (!failedAttach) + mapping.setDb(filename, expanded_name.c_str(), nullptr); + + mapResult = mapping.mapUser(s_user, t_role); + } + } else { // failed attachment attempts traced by admin trace only @@ -319,7 +356,7 @@ void TraceManager::update_session(const TraceSession& session) t_role.upper(); if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE && - s_user != curr_user && (!priv.test(TRACE_ANY_ATTACHMENT))) + (!curr_user || s_user != curr_user) && (!priv.test(TRACE_ANY_ATTACHMENT))) { return; } @@ -344,7 +381,7 @@ void TraceManager::update_session(const TraceSession& session) sesInfo.ses_id = session.ses_id; trace_sessions.add(sesInfo); - trace_needs |= info->factory->trace_needs(); + new_needs |= info->factory->trace_needs(); } else if (status->getState() & IStatus::STATE_ERRORS) { @@ -395,10 +432,20 @@ void TraceManager::event_dsql_execute(Attachment* att, jrd_tra* transaction, TraceConnectionImpl conn(att); TraceTransactionImpl tran(transaction); - att->att_trace_manager->event_dsql_execute(&conn, transaction ? &tran : NULL, statement, + att->att_trace_manager->event_dsql_execute(&conn, transaction ? &tran : NULL, statement, started, req_result); } +void TraceManager::event_dsql_restart(Attachment* att, jrd_tra* transaction, + const dsql_req* statement, int number) +{ + TraceConnectionImpl conn(att); + TraceTransactionImpl tran(transaction); + TraceSQLStatementImpl stmt(statement, NULL); + + att->att_trace_manager->event_dsql_restart(&conn, transaction ? &tran : NULL, &stmt, + (unsigned) number); +} #define EXECUTE_HOOKS(METHOD, PARAMS) \ FB_SIZE_T i = 0; \ @@ -494,6 +541,12 @@ void TraceManager::event_dsql_execute(ITraceDatabaseConnection* connection, ITra (connection, transaction, statement, started, req_result)); } +void TraceManager::event_dsql_restart(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, + ITraceSQLStatement* statement, unsigned number) +{ + EXECUTE_HOOKS(trace_dsql_restart, + (connection, transaction, statement, number)); +} void TraceManager::event_blr_compile(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceBLRStatement* statement, diff --git a/src/jrd/trace/TraceManager.h b/src/jrd/trace/TraceManager.h index 0c581caa19c..bacaebc5ece 100644 --- a/src/jrd/trace/TraceManager.h +++ b/src/jrd/trace/TraceManager.h @@ -44,6 +44,7 @@ namespace Jrd { class Database; class Attachment; class jrd_tra; +class dsql_req; class Service; class TraceManager @@ -52,7 +53,7 @@ class TraceManager /* Initializes plugins. */ explicit TraceManager(Attachment* in_att); explicit TraceManager(Service* in_svc); - explicit TraceManager(const char* in_filename); + TraceManager(const char* in_filename, Firebird::ICryptKeyCallback* callback, bool failedAttach); /* Finalize plugins. Called when database is closed by the engine */ ~TraceManager(); @@ -157,13 +158,17 @@ class TraceManager static void event_dsql_execute(Attachment* att, jrd_tra* transaction, Firebird::ITraceSQLStatement* statement, bool started, ntrace_result_t req_result); + static void event_dsql_restart(Attachment* att, jrd_tra* transaction, const dsql_req* statement, + int number); + static void shutdown(); private: Attachment* attachment; Service* service; const char* filename; - NotificationNeeds trace_needs; + NotificationNeeds trace_needs, new_needs; + Firebird::ICryptKeyCallback* callback; // This structure should be POD-like to be stored in Array struct FactoryInfo @@ -242,10 +247,13 @@ class TraceManager Firebird::ITraceSQLStatement* statement, bool started, ntrace_result_t req_result); + void event_dsql_restart(Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, Firebird::ITraceSQLStatement* statement, + unsigned number); + static Firebird::GlobalPtr storageInstance; ULONG changeNumber; - bool active; + bool active, failedAttach; }; } diff --git a/src/jrd/trace/TraceObjects.cpp b/src/jrd/trace/TraceObjects.cpp index 4d4a7e2e60c..64ac68d7785 100644 --- a/src/jrd/trace/TraceObjects.cpp +++ b/src/jrd/trace/TraceObjects.cpp @@ -83,14 +83,12 @@ const char* TraceConnectionImpl::getDatabaseName() const char* TraceConnectionImpl::getUserName() { - const UserId* user = m_att->att_user; - return user ? user->getUserName().c_str() : NULL; + return m_att->getUserName().nullStr(); } const char* TraceConnectionImpl::getRoleName() { - const UserId* user = m_att->att_user; - return user ? user->getSqlRole().c_str() : NULL; + return m_att->getSqlRole().nullStr(); } const char* TraceConnectionImpl::getCharSet() diff --git a/src/jrd/trace/TraceService.cpp b/src/jrd/trace/TraceService.cpp index 03e1a7a78fc..a0840a70e4b 100644 --- a/src/jrd/trace/TraceService.cpp +++ b/src/jrd/trace/TraceService.cpp @@ -210,7 +210,7 @@ bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags) session.ses_flags |= setFlags; session.ses_flags &= ~clearFlags; - if (saveFlags != session.ses_flags) + if (saveFlags != session.ses_flags) storage->updateFlags(session); return true; @@ -228,13 +228,15 @@ void TraceSvcJrd::listSessions() { m_svc.started(); - ConfigStorage* storage = TraceManager::getStorage(); - StorageGuard guard(storage); + // Writing into service when storage is locked could lead to deadlock, + // therefore don't use StorageGuard here. - storage->restart(); + ConfigStorage* storage = TraceManager::getStorage(); + ConfigStorage::Accessor acc(storage); TraceSession session(*getDefaultMemoryPool()); - while (storage->getNextSession(session, ConfigStorage::ALL)) + + while (acc.getNext(session, ConfigStorage::ALL)) { if (checkPrivileges(session)) { @@ -401,8 +403,10 @@ int TRACE_main(UtilSvc* arg) { StaticStatusVector status; e.stuffException(status); - svc->initStatus(); - svc->setServiceStatus(status.begin()); + + UtilSvc::StatusAccessor sa = svc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); exit_code = FB_FAILURE; } diff --git a/src/jrd/types.h b/src/jrd/types.h index 558a712720c..f65d684e6af 100644 --- a/src/jrd/types.h +++ b/src/jrd/types.h @@ -43,8 +43,8 @@ TYPE("INT64", blr_int64, nam_f_type) TYPE("BOOLEAN", blr_bool, nam_f_type) TYPE("DECFLOAT(16)", blr_dec64, nam_f_type) TYPE("DECFLOAT(34)", blr_dec128, nam_f_type) -TYPE("TIMESTAMP WITH TIMEZONE", blr_timestamp_tz, nam_f_type) -TYPE("TIME WITH TIMEZONE", blr_sql_time_tz, nam_f_type) +TYPE("TIMESTAMP WITH TIME ZONE", blr_timestamp_tz, nam_f_type) +TYPE("TIME WITH TIME ZONE", blr_sql_time_tz, nam_f_type) TYPE("INT128", blr_int128, nam_f_type) TYPE("BINARY", 0, nam_f_sub_type) diff --git a/src/jrd/val.h b/src/jrd/val.h index 349f9c29a16..91e024f0c54 100644 --- a/src/jrd/val.h +++ b/src/jrd/val.h @@ -31,9 +31,9 @@ #include "../include/fb_blk.h" #include "../common/classes/array.h" +#include "../jrd/intl_classes.h" #include "../jrd/MetaName.h" #include "../jrd/QualifiedName.h" - #include "../jrd/RecordNumber.h" #include "../common/dsc.h" @@ -57,7 +57,6 @@ class ArrayField; class blb; class jrd_req; class jrd_tra; -class PatternMatcher; // Various structures in the impure area @@ -68,9 +67,25 @@ struct impure_state struct impure_value { + struct PatternMatcherCache : pool_alloc_rpt + { + PatternMatcherCache(ULONG aKeySize) + : keySize(aKeySize) + { + } + + ULONG keySize; + USHORT ttype; + USHORT patternLen; + Firebird::AutoPtr matcher; + USHORT escapeLen; + UCHAR key[1]; + }; + dsc vlu_desc; USHORT vlu_flags; // Computed/invariant flags VaryingString* vlu_string; + union { UCHAR vlu_uchar; @@ -91,8 +106,9 @@ struct impure_value GDS_DATE vlu_sql_date; bid vlu_bid; - // Pre-compiled invariant object for nod_like and other string functions + // Pre-compiled invariant object for pattern matcher functions Jrd::PatternMatcher* vlu_invariant; + PatternMatcherCache* vlu_patternMatcherCache; } vlu_misc; void make_long(const SLONG val, const signed char scale = 0); diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 64c459a717b..97dd82b4119 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -725,6 +725,7 @@ static int validate(Firebird::UtilSvc* svc) { dpb.insertString(isc_dpb_trusted_auth, userName); } + dpb.insertTag(isc_dpb_no_garbage_collect); PathName expandedFilename; if (expandDatabaseName(dbName, expandedFilename, NULL)) @@ -735,12 +736,11 @@ static int validate(Firebird::UtilSvc* svc) FbLocalStatus status; AutoPlugin jProv(JProvider::getInstance()); - RefPtr jAtt; - jAtt.assignRefNoIncr(jProv->attachDatabase(&status, expandedFilename.c_str(), dpb.getBufferLength(), dpb.getBuffer())); + RefPtr jAtt(jProv->attachDatabase(&status, expandedFilename.c_str(), dpb.getBufferLength(), dpb.getBuffer())); if (status->getState() & IStatus::STATE_ERRORS) { - svc->setServiceStatus(status->getErrors()); + svc->getStatusAccessor().setServiceStatus(status->getErrors()); return FB_FAILURE; } @@ -770,7 +770,7 @@ static int validate(Firebird::UtilSvc* svc) { att->att_use_count--; ex.stuffException(&status); - svc->setServiceStatus(status->getErrors()); + svc->getStatusAccessor().setServiceStatus(status->getErrors()); ret_code = FB_FAILURE; } @@ -782,7 +782,7 @@ static int validate(Firebird::UtilSvc* svc) int VAL_service(Firebird::UtilSvc* svc) { - svc->initStatus(); + svc->getStatusAccessor().init(); int exit_code = FB_SUCCESS; @@ -794,7 +794,7 @@ int VAL_service(Firebird::UtilSvc* svc) { FbLocalStatus status; ex.stuffException(&status); - svc->setServiceStatus(status->getErrors()); + svc->getStatusAccessor().setServiceStatus(status->getErrors()); exit_code = FB_FAILURE; } @@ -1871,21 +1871,19 @@ void Validation::walk_generators() WIN window(DB_PAGE_SPACE, -1); - vcl* vector = dbb->dbb_gen_id_pages; - if (vector) + if (const auto idsCount = dbb->getKnownPagesCount(pag_ids)) { - vcl::iterator ptr, end; - for (ptr = vector->begin(), end = vector->end(); ptr < end; ++ptr) + for (ULONG sequence = 0; sequence < idsCount; sequence++) { - if (*ptr) + if (const auto pageNumber = dbb->getKnownPage(pag_ids, sequence)) { #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) - fprintf(stdout, "walk_generator: page %d\n", *ptr); + fprintf(stdout, "walk_generator: page %d\n", pageNumber); #endif // It doesn't make a difference generator_page or pointer_page because it's not used. generator_page* page = NULL; - fetch_page(true, *ptr, pag_ids, &window, &page); + fetch_page(true, pageNumber, pag_ids, &window, &page); release_page(&window); } } @@ -3174,8 +3172,7 @@ Validation::RTN Validation::walk_tip(TraNumber transaction) **************************************/ Database* dbb = vdr_tdbb->getDatabase(); - const vcl* vector = dbb->dbb_t_pages; - if (!vector) + if (!dbb->getKnownPagesCount(pag_transactions)) return corrupt(VAL_TIP_LOST, 0); tx_inv_page* page = 0; @@ -3183,25 +3180,28 @@ Validation::RTN Validation::walk_tip(TraNumber transaction) for (ULONG sequence = 0; sequence <= pages; sequence++) { - if (!(*vector)[sequence] || sequence >= vector->count()) + auto pageNumber = dbb->getKnownPage(pag_transactions, sequence); + if (!pageNumber) { corrupt(VAL_TIP_LOST_SEQUENCE, 0, sequence); if (!(vdr_flags & VDR_repair)) continue; TRA_extend_tip(vdr_tdbb, sequence); - vector = dbb->dbb_t_pages; vdr_fixed++; + + pageNumber = dbb->getKnownPage(pag_transactions, sequence); } WIN window(DB_PAGE_SPACE, -1); - fetch_page(true, (*vector)[sequence], pag_transactions, &window, &page); + fetch_page(true, pageNumber, pag_transactions, &window, &page); #ifdef DEBUG_VAL_VERBOSE if (VAL_debug_level) - fprintf(stdout, "walk_tip: page %d next %d\n", (*vector)[sequence], page->tip_next); + fprintf(stdout, "walk_tip: page %d next %d\n", pageNumber, page->tip_next); #endif - if (page->tip_next && page->tip_next != (*vector)[sequence + 1]) + const auto next = dbb->getKnownPage(pag_transactions, sequence + 1); + if (page->tip_next && page->tip_next != next) { corrupt(VAL_TIP_CONFUSED, 0, sequence); } diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 83f570e947e..2f46ac43ae9 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -98,7 +98,6 @@ static void check_class(thread_db*, jrd_tra*, record_param*, record_param*, USHO static bool check_nullify_source(thread_db*, record_param*, record_param*, int, int = -1); static void check_owner(thread_db*, jrd_tra*, record_param*, record_param*, USHORT); static void check_repl_state(thread_db*, jrd_tra*, record_param*, record_param*, USHORT); -static bool check_user(thread_db*, const dsc*); static int check_precommitted(const jrd_tra*, const record_param*); static void check_rel_field_class(thread_db*, record_param*, jrd_tra*); static void delete_record(thread_db*, record_param*, ULONG, MemoryPool*); @@ -225,13 +224,13 @@ static bool assert_gc_enabled(const jrd_tra* transaction, const jrd_rel* relatio inline void check_gbak_cheating_insupd(thread_db* tdbb, const jrd_rel* relation, const char* op) { const Attachment* const attachment = tdbb->getAttachment(); - const jrd_tra* const transaction = tdbb->getTransaction(); + const jrd_req* const request = tdbb->getRequest(); - // It doesn't matter that we use protect_system_table_upd() that's for deletions and updates - // but this code is for insertions and updates, because we use force = true. - if (relation->isSystem() && attachment->isGbak() && !(attachment->att_flags & ATT_creator)) + if (relation->isSystem() && attachment->isGbak() && !(attachment->att_flags & ATT_creator) && + !request->hasInternalStatement()) { - protect_system_table_delupd(tdbb, relation, op, true); + status_exception::raise(Arg::Gds(isc_protect_sys_tab) << + Arg::Str(op) << Arg::Str(relation->rel_name)); } } @@ -351,7 +350,7 @@ inline void clearRecordStack(RecordStack& stack) { Record* r = stack.pop(); // records from undo log must not be deleted - if (!r->testFlags(REC_undo_active)) + if (!r->isTempActive()) delete r; } } @@ -453,8 +452,8 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) Record* data = NULL; Record* old_data = NULL; - AutoGCRecord gc_rec1; - AutoGCRecord gc_rec2; + AutoTempRecord gc_rec1; + AutoTempRecord gc_rec2; bool samePage; bool deleted; @@ -667,8 +666,6 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) else { // There is cleanup to be done. Bring the old version forward first - - rpb->rpb_flags &= ~(rpb_fragment | rpb_incomplete | rpb_chained | rpb_gc_active | rpb_long_tranum); DPM_update(tdbb, rpb, 0, transaction); delete_tail(tdbb, &temp2, rpb->rpb_page, 0, 0); } @@ -1406,6 +1403,8 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) const ULONG back_page = rpb->rpb_b_page; const USHORT back_line = rpb->rpb_b_line; const USHORT save_flags = rpb->rpb_flags; + const ULONG save_f_page = rpb->rpb_f_page; + const USHORT save_f_line = rpb->rpb_f_line; while (rpb->rpb_flags & rpb_incomplete) { @@ -1417,6 +1416,8 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) rpb->rpb_b_page = back_page; rpb->rpb_b_line = back_line; rpb->rpb_flags = save_flags; + rpb->rpb_f_page = save_f_page; + rpb->rpb_f_line = save_f_line; } CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); @@ -1463,7 +1464,7 @@ static bool check_prepare_result(int prepare_result, jrd_tra* transaction, jrd_r ************************************** * * Functional description - * Called by VIO_modify and VIO_erase. Raise update conflict error if not in + * Called by VIO_modify and VIO_erase. Raise update conflict error if not in * read consistency transaction or lock error happens or if request is already * in update conflict mode. In latter case set TRA_ex_restart flag to correctly * handle request restart. @@ -1474,17 +1475,17 @@ static bool check_prepare_result(int prepare_result, jrd_tra* transaction, jrd_r jrd_req* top_request = request->req_snapshot.m_owner; - const bool restart_ready = top_request && + const bool restart_ready = top_request && (top_request->req_flags & req_restart_ready); // Second update conflict when request is already in update conflict mode - // means we have some (indirect) UPDATE\DELETE in WHERE clause of primary + // means we have some (indirect) UPDATE\DELETE in WHERE clause of primary // cursor. In this case all we can do is restart whole request immediately. - const bool secondary = top_request && - (top_request->req_flags & req_update_conflict) && + const bool secondary = top_request && + (top_request->req_flags & req_update_conflict) && (prepare_result != PREPARE_LOCKERR); - if (!(transaction->tra_flags & TRA_read_consistency) || prepare_result == PREPARE_LOCKERR || + if (!(transaction->tra_flags & TRA_read_consistency) || prepare_result == PREPARE_LOCKERR || secondary || !restart_ready) { if (secondary) @@ -1550,9 +1551,6 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) fb_assert(!(rpb->rpb_runtime_flags & RPB_undo_read)); } - // deleting tx has updated/inserted this record before - tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id); - // Special case system transaction if (transaction->tra_flags & TRA_system) @@ -1583,7 +1581,6 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) { case rel_database: case rel_log: - case rel_backup_history: case rel_global_auth_mapping: protect_system_table_delupd(tdbb, relation, "DELETE", true); break; @@ -1603,7 +1600,6 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_pages: case rel_formats: case rel_trans: - case rel_rcon: case rel_refc: case rel_ccon: case rel_msgs: @@ -1680,6 +1676,10 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_funs: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_fun_name, &desc); + + if (EVL_field(0, rpb->rpb_record, f_fun_pkg_name, &desc2)) + MOV_get_metaname(tdbb, &desc2, package_name); + EVL_field(0, rpb->rpb_record, f_fun_id, &desc2); id = MOV_get_long(tdbb, &desc2, 0); @@ -1844,10 +1844,16 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) case rel_priv: protect_system_table_delupd(tdbb, relation, "DELETE"); EVL_field(0, rpb->rpb_record, f_file_name, &desc); - if (!(tdbb->getRequest()->getStatement()->flags & JrdStatement::FLAG_INTERNAL)) + if (!tdbb->getRequest()->hasInternalStatement()) { EVL_field(0, rpb->rpb_record, f_prv_grantor, &desc); - if (!check_user(tdbb, &desc)) + MetaName grantor; + MOV_get_metaname(tdbb, &desc, grantor); + + const auto attachment = tdbb->getAttachment(); + const MetaString& currentUser = attachment->getUserName(); + + if (grantor != currentUser) { ERR_post(Arg::Gds(isc_no_priv) << Arg::Str("REVOKE") << Arg::Str("TABLE") << @@ -1860,6 +1866,27 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) DFW_post_work(transaction, dfw_grant, &desc, id); break; + case rel_rcon: + protect_system_table_delupd(tdbb, relation, "DELETE"); + + // ensure relation partners is known + EVL_field(0, rpb->rpb_record, f_rcon_rname, &desc); + { + MetaName relation_name; + MOV_get_metaname(tdbb, &desc, relation_name); + r2 = MET_lookup_relation(tdbb, relation_name); + fb_assert(r2); + + if (r2) + MET_scan_partners(tdbb, r2); + } + break; + + case rel_backup_history: + if (!tdbb->getAttachment()->locksmith(tdbb, USE_NBACKUP_UTILITY)) + protect_system_table_delupd(tdbb, relation, "DELETE", true); + break; + case rel_pub_tables: protect_system_table_delupd(tdbb, relation, "DELETE"); DFW_post_work(transaction, dfw_change_repl_state, "", 1); @@ -1877,6 +1904,9 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // If the page can be updated simply, we can skip the remaining crud + Database* dbb = tdbb->getDatabase(); + const bool backVersion = (rpb->rpb_b_page != 0); + record_param temp; temp.rpb_transaction_nr = transaction->tra_number; temp.rpb_address = NULL; @@ -1892,10 +1922,17 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (transaction->tra_save_point && transaction->tra_save_point->isChanging()) verb_post(tdbb, transaction, rpb, rpb->rpb_undo); + // We have INSERT + DELETE or UPDATE + DELETE in the same transaction. + // UPDATE has already notified GC, while INSERT has not. Check for + // backversion allows to avoid second notification in case of UPDATE. + + if ((dbb->dbb_flags & DBB_gc_background) && !rpb->rpb_relation->isTemporary() && !backVersion) + notify_garbage_collector(tdbb, rpb, transaction->tra_number); + + tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id); return true; } - const bool backVersion = (rpb->rpb_b_page != 0); const TraNumber tid_fetch = rpb->rpb_transaction_nr; if (DPM_chain(tdbb, rpb, &temp)) { @@ -1949,6 +1986,8 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) if (transaction->tra_save_point && transaction->tra_save_point->isChanging()) verb_post(tdbb, transaction, rpb, 0); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id); + // for an autocommit transaction, mark a commit as necessary if (transaction->tra_flags & TRA_autocommit) @@ -1956,7 +1995,6 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) // VIO_erase - Database* dbb = tdbb->getDatabase(); if (backVersion && !(tdbb->getAttachment()->att_flags & ATT_no_cleanup) && (dbb->dbb_flags & DBB_gc_cooperative)) { @@ -2031,27 +2069,35 @@ static void delete_version_chain(thread_db* tdbb, record_param* rpb, bool delete rpb->rpb_f_page, rpb->rpb_f_line); #endif + // It's possible to get rpb_page == 0 from VIO_intermediate_gc via + // staying_chain_rpb. This case happens there when the staying record + // stack has 1 item at the moment this rpb is created. So return to + // avoid an error on DPM_fetch below. + if (!rpb->rpb_page) + return; + ULONG prior_page = 0; - if (!delete_head) + // Note that the page number of the oldest version in the chain should + // be stored in rpb->rpb_page before exiting this function because + // VIO_intermediate_gc will use it as a prior page number. + while (rpb->rpb_b_page != 0 || delete_head) { - prior_page = rpb->rpb_page; - rpb->rpb_page = rpb->rpb_b_page; - rpb->rpb_line = rpb->rpb_b_line; - } + if (!delete_head) + { + prior_page = rpb->rpb_page; + rpb->rpb_page = rpb->rpb_b_page; + rpb->rpb_line = rpb->rpb_b_line; + } + else + delete_head = false; - while (rpb->rpb_page != 0) - { if (!DPM_fetch(tdbb, rpb, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version record_param temp_rpb = *rpb; DPM_delete(tdbb, &temp_rpb, prior_page); delete_tail(tdbb, &temp_rpb, temp_rpb.rpb_page, 0, 0); - - prior_page = rpb->rpb_page; - rpb->rpb_page = rpb->rpb_b_page; - rpb->rpb_line = rpb->rpb_b_line; } } @@ -2405,10 +2451,11 @@ Record* VIO_gc_record(thread_db* tdbb, jrd_rel* relation) Record* const record = *iter; fb_assert(record); - if (!record->testFlags(REC_gc_active)) + if (!record->isTempActive()) { // initialize record for reuse - record->reset(format, REC_gc_active); + record->reset(format); + record->setTempActive(); return record; } } @@ -2416,7 +2463,7 @@ Record* VIO_gc_record(thread_db* tdbb, jrd_rel* relation) // Allocate a garbage collect record block if all are active Record* const record = FB_NEW_POOL(*relation->rel_pool) - Record(*relation->rel_pool, format, REC_gc_active); + Record(*relation->rel_pool, format, true); relation->rel_gc_records.add(record); return record; } @@ -2821,7 +2868,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j if (org_rpb->rpb_runtime_flags & (RPB_refetch | RPB_undo_read)) { const bool undo_read = (org_rpb->rpb_runtime_flags & RPB_undo_read); - AutoGCRecord old_record; + AutoTempRecord old_record; if (undo_read) { old_record = VIO_gc_record(tdbb, relation); @@ -2932,18 +2979,20 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j break; case rel_procedures: - if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_prc_source)) - protect_system_table_delupd(tdbb, relation, "UPDATE"); - EVL_field(0, org_rpb->rpb_record, f_prc_name, &desc1); if (EVL_field(0, org_rpb->rpb_record, f_prc_pkg_name, &desc2)) - { MOV_get_metaname(tdbb, &desc2, package_name); - SCL_check_package(tdbb, &desc2, SCL_alter); - } + + if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_prc_source)) + protect_system_table_delupd(tdbb, relation, "UPDATE"); else - SCL_check_procedure(tdbb, &desc1, SCL_alter); + { + if (package_name.hasData()) + SCL_check_package(tdbb, &desc2, SCL_alter); + else + SCL_check_procedure(tdbb, &desc1, SCL_alter); + } check_class(tdbb, transaction, org_rpb, new_rpb, f_prc_class); check_owner(tdbb, transaction, org_rpb, new_rpb, f_prc_owner); @@ -2958,15 +3007,16 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j case rel_funs: EVL_field(0, org_rpb->rpb_record, f_fun_name, &desc1); + + if (EVL_field(0, org_rpb->rpb_record, f_fun_pkg_name, &desc2)) + MOV_get_metaname(tdbb, &desc2, package_name); + if (!check_nullify_source(tdbb, org_rpb, new_rpb, f_fun_source)) protect_system_table_delupd(tdbb, relation, "UPDATE"); else { - if (EVL_field(0, org_rpb->rpb_record, f_fun_pkg_name, &desc2)) - { - MOV_get_metaname(tdbb, &desc2, package_name); + if (package_name.hasData()) SCL_check_package(tdbb, &desc2, SCL_alter); - } else SCL_check_function(tdbb, &desc1, SCL_alter); } @@ -3206,7 +3256,7 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j const bool backVersion = (org_rpb->rpb_b_page != 0); record_param temp; PageStack stack; - int prepare_result = prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb, + int prepare_result = prepare_update(tdbb, transaction, org_rpb->rpb_transaction_nr, org_rpb, &temp, new_rpb, stack, false); if (!check_prepare_result(prepare_result, transaction, tdbb->getRequest(), org_rpb)) return false; @@ -3224,6 +3274,8 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j org_rpb->rpb_flags &= ~(rpb_delta | rpb_uk_modified); org_rpb->rpb_flags |= new_rpb->rpb_flags & (rpb_delta | rpb_uk_modified); + stack.merge(new_rpb->rpb_record->getPrecedence()); + replace_record(tdbb, org_rpb, &stack, transaction); if (!(transaction->tra_flags & TRA_system) && @@ -3266,7 +3318,8 @@ bool VIO_next_record(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPool* pool, - bool onepage) + bool onepage, + const RecordNumber* upper) { /************************************** * @@ -3301,9 +3354,14 @@ bool VIO_next_record(thread_db* tdbb, rpb->rpb_f_page, rpb->rpb_f_line); #endif - do { + do + { if (!DPM_next(tdbb, rpb, lock_type, onepage)) + return false; + + if (upper && rpb->rpb_number > *upper) { + CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } } while (!VIO_chase_record_version(tdbb, rpb, transaction, pool, false, false)); @@ -3704,7 +3762,7 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) EVL_field(0, rpb->rpb_record, f_trg_rname, &desc); // check if this request go through without checking permissions - if (!(request->getStatement()->flags & JrdStatement::FLAG_IGNORE_PERM)) + if (!(request->getStatement()->flags & (JrdStatement::FLAG_IGNORE_PERM | JrdStatement::FLAG_INTERNAL))) SCL_check_relation(tdbb, &desc, SCL_control | SCL_alter); if (EVL_field(0, rpb->rpb_record, f_trg_rname, &desc2)) @@ -4311,11 +4369,11 @@ static void check_owner(thread_db* tdbb, if (!MOV_compare(tdbb, &desc1, &desc2)) return; - const Jrd::Attachment* const attachment = tdbb->getAttachment(); + const auto attachment = tdbb->getAttachment(); + const MetaString& name = attachment->getEffectiveUserName(); - if (attachment->att_user) + if (name.hasData()) { - const MetaName name(attachment->att_user->getUserName()); desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); if (!MOV_compare(tdbb, &desc1, &desc2)) @@ -4363,38 +4421,6 @@ static void check_repl_state(thread_db* tdbb, } -static bool check_user(thread_db* tdbb, const dsc* desc) -{ -/************************************** - * - * c h e c k _ u s e r - * - ************************************** - * - * Functional description - * Validate string against current user name. - * - **************************************/ - SET_TDBB(tdbb); - - const TEXT* p = (TEXT *) desc->dsc_address; - const TEXT* const end = p + desc->dsc_length; - const UserId* user = tdbb->getAttachment()->att_user; - const TEXT* q = user ? user->getUserName().c_str() : ""; - - // It is OK to not internationalize this function for v4.00 as - // User names are limited to 7-bit ASCII for v4.00 - - for (; p < end && *p != ' '; p++, q++) - { - if (UPPER7(*p) != UPPER7(*q)) - return false; - } - - return *q ? false : true; -} - - static void delete_record(thread_db* tdbb, record_param* rpb, ULONG prior_page, MemoryPool* pool) { /************************************** @@ -4798,6 +4824,7 @@ void Database::garbage_collector(Database* dbb) attachment->att_user = &user; BackgroundContextHolder tdbb(dbb, attachment, &status_vector, FB_FUNCTION); + Jrd::Attachment::UseCountHolder use(attachment); tdbb->markAsSweeper(); record_param rpb; @@ -4985,6 +5012,8 @@ void Database::garbage_collector(Database* dbb) CCH_flush(tdbb, FLUSH_SWEEP, 0); flush = false; + + attachment->mergeStats(); } dbb->dbb_flags &= ~DBB_gc_active; @@ -5109,7 +5138,7 @@ static UndoDataRet get_undo_data(thread_db* tdbb, jrd_tra* transaction, rpb->rpb_runtime_flags |= RPB_undo_data; CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - AutoUndoRecord undoRecord(undo.setupRecord(transaction)); + AutoTempRecord undoRecord(undo.setupRecord(transaction)); Record* const record = VIO_record(tdbb, rpb, undoRecord->getFormat(), pool); record->copyFrom(undoRecord); @@ -5992,7 +6021,7 @@ static void purge(thread_db* tdbb, record_param* rpb) // the record. record_param temp = *rpb; - AutoGCRecord gc_rec(VIO_gc_record(tdbb, relation)); + AutoTempRecord gc_rec(VIO_gc_record(tdbb, relation)); Record* record = rpb->rpb_record = gc_rec; VIO_data(tdbb, rpb, relation->rel_pool); @@ -6068,7 +6097,6 @@ static void replace_record(thread_db* tdbb, #endif record_param temp = *rpb; - rpb->rpb_flags &= ~(rpb_fragment | rpb_incomplete | rpb_chained | rpb_gc_active | rpb_long_tranum); DPM_update(tdbb, rpb, stack, transaction); delete_tail(tdbb, &temp, rpb->rpb_page, 0, 0); @@ -6221,10 +6249,11 @@ static void set_owner_name(thread_db* tdbb, Record* record, USHORT field_id) if (!EVL_field(0, record, field_id, &desc1)) { - const Jrd::UserId* const user = tdbb->getAttachment()->att_user; - if (user) + const auto attachment = tdbb->getAttachment(); + const MetaString& name = attachment->getEffectiveUserName(); + + if (name.hasData()) { - const MetaName name(user->getUserName()); dsc desc2; desc2.makeText((USHORT) name.length(), CS_METADATA, (UCHAR*) name.c_str()); MOV_move(tdbb, &desc2, &desc1); @@ -6341,7 +6370,7 @@ void VIO_update_in_place(thread_db* tdbb, // becomes meaningless. What we need to do is replace the old "delta" record // with an old "complete" record, update in placement, then delete the old delta record - AutoGCRecord gc_rec; + AutoTempRecord gc_rec; record_param temp2; const Record* prior = org_rpb->rpb_prior; diff --git a/src/jrd/vio_proto.h b/src/jrd/vio_proto.h index e37eaa229fe..44fdd4e5c0e 100644 --- a/src/jrd/vio_proto.h +++ b/src/jrd/vio_proto.h @@ -52,7 +52,8 @@ bool VIO_get_current(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*, void VIO_init(Jrd::thread_db*); bool VIO_writelock(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*); bool VIO_modify(Jrd::thread_db*, Jrd::record_param*, Jrd::record_param*, Jrd::jrd_tra*); -bool VIO_next_record(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*, MemoryPool*, bool); +bool VIO_next_record(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*, MemoryPool*, bool, + const RecordNumber* = nullptr); Jrd::Record* VIO_record(Jrd::thread_db*, Jrd::record_param*, const Jrd::Format*, MemoryPool*); bool VIO_refetch_record(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*, bool, bool); void VIO_store(Jrd::thread_db*, Jrd::record_param*, Jrd::jrd_tra*); diff --git a/src/lock/lock.cpp b/src/lock/lock.cpp index dd0a56016b1..cdde101b6da 100644 --- a/src/lock/lock.cpp +++ b/src/lock/lock.cpp @@ -143,6 +143,8 @@ const SLONG HASH_MIN_SLOTS = 101; const SLONG HASH_MAX_SLOTS = 65521; const USHORT HISTORY_BLOCKS = 256; +const ULONG MAX_TABLE_LENGTH = SLONG_MAX; + // SRQ_ABS_PTR uses this macro. #define SRQ_BASE ((UCHAR*) m_sharedMemory->getHeader()) @@ -300,6 +302,9 @@ bool LockManager::init_shared_file(CheckStatusWrapper* statusVector) SharedMemory* tmp = FB_NEW_POOL(getPool()) SharedMemory(name.c_str(), m_memorySize, this); // initialize will reset m_sharedMemory fb_assert(m_sharedMemory == tmp); + + if (!check_shared_memory(statusVector)) + return false; } catch (const Exception& ex) { @@ -1183,14 +1188,14 @@ bool LockManager::Extent::initialize(bool) void LockManager::Extent::mutexBug(int, const char*) { } -bool LockManager::createExtent(CheckStatusWrapper* statusVector) +bool LockManager::createExtent(CheckStatusWrapper* statusVector, ULONG memorySize) { PathName name; get_shared_file_name(name, (ULONG) m_extents.getCount()); Extent& extent = m_extents.add(); - if (!extent.mapFile(statusVector, name.c_str(), m_memorySize)) + if (!extent.mapFile(statusVector, name.c_str(), memorySize ? memorySize : m_memorySize)) { m_extents.pop(); logError("LockManager::createExtent() mapFile", local_status); @@ -1223,17 +1228,33 @@ UCHAR* LockManager::alloc(USHORT size, CheckStatusWrapper* statusVector) size = FB_ALIGN(size, FB_ALIGNMENT); ASSERT_ACQUIRED; ULONG block = m_sharedMemory->getHeader()->lhb_used; + ULONG memorySize = m_memorySize; // Make sure we haven't overflowed the lock table. If so, bump the size of the table. if (m_sharedMemory->getHeader()->lhb_used + size > m_sharedMemory->getHeader()->lhb_length) { + // New table size shouldn't exceed max table length + if (m_sharedMemory->getHeader()->lhb_length + memorySize > MAX_TABLE_LENGTH) + { + if (m_sharedMemory->getHeader()->lhb_used + size <= MAX_TABLE_LENGTH) + memorySize = MAX_TABLE_LENGTH - m_sharedMemory->getHeader()->lhb_length; + else + { + // Return an error if can't alloc enough memory + (Arg::Gds(isc_lockmanerr) << + Arg::Gds(isc_random) << Arg::Str("lock table size exceeds limit") << + Arg::StatusVector(statusVector)).copyTo(statusVector); + + return NULL; + } + } #ifdef USE_SHMEM_EXT // round up so next object starts at beginning of next extent block = m_sharedMemory->getHeader()->lhb_used = m_sharedMemory->getHeader()->lhb_length; - if (createExtent(*statusVector)) + if (createExtent(*statusVector, memorySize)) { - m_sharedMemory->getHeader()->lhb_length += m_memorySize; + m_sharedMemory->getHeader()->lhb_length += memorySize; } else #elif (defined HAVE_OBJECT_MAP) @@ -1241,7 +1262,7 @@ UCHAR* LockManager::alloc(USHORT size, CheckStatusWrapper* statusVector) // Post remapping notifications remap_local_owners(); // Remap the shared memory region - const ULONG new_length = m_sharedMemory->sh_mem_length_mapped + m_memorySize; + const ULONG new_length = m_sharedMemory->sh_mem_length_mapped + memorySize; if (m_sharedMemory->remapFile(statusVector, new_length, true)) { ASSERT_ACQUIRED; @@ -1381,7 +1402,19 @@ void LockManager::blocking_action(thread_db* tdbb, SRQ_PTR blocking_owner_offset { // checkout scope LockTableCheckout checkout(this, FB_FUNCTION); EngineCheckout cout(tdbb, FB_FUNCTION, true); - (*routine)(arg); + + try + { + (*routine)(arg); + } + catch (const Exception& ex) + { + iscLogException("Exception from AST routine - this should never happen", ex); + } + catch (...) + { + gds__log("Unknown C++ exception from AST routine - this should never happen"); + } } owner = (own*) SRQ_ABS_PTR(blocking_owner_offset); @@ -1611,20 +1644,18 @@ void LockManager::bug(CheckStatusWrapper* statusVector, const TEXT* string) } -SRQ_PTR LockManager::create_owner(CheckStatusWrapper* statusVector, - LOCK_OWNER_T owner_id, - UCHAR owner_type) +bool LockManager::check_shared_memory(CheckStatusWrapper* statusVector) { -/************************************** +/******************************************** * - * c r e a t e _ o w n e r + * c h e c k _ s h a r e d _ m e m o r y * - ************************************** + ******************************************** * * Functional description - * Create an owner block. + * Check version of shared memory. * - **************************************/ + ********************************************/ if (m_sharedMemory->getHeader()->mhb_type != SharedMemoryBase::SRAM_LOCK_MANAGER || m_sharedMemory->getHeader()->mhb_header_version != MemoryHeader::HEADER_VERSION || m_sharedMemory->getHeader()->mhb_version != LHB_VERSION) @@ -1636,9 +1667,30 @@ SRQ_PTR LockManager::create_owner(CheckStatusWrapper* statusVector, m_sharedMemory->getHeader()->mhb_version, SharedMemoryBase::SRAM_LOCK_MANAGER, MemoryHeader::HEADER_VERSION, LHB_VERSION); bug(statusVector, bug_buffer); - return 0; + return false; } + return true; +} + + +SRQ_PTR LockManager::create_owner(CheckStatusWrapper* statusVector, + LOCK_OWNER_T owner_id, + UCHAR owner_type) +{ +/************************************** + * + * c r e a t e _ o w n e r + * + ************************************** + * + * Functional description + * Create an owner block. + * + **************************************/ + if (!check_shared_memory(statusVector)) + return 0; + // Allocate a process block, if required if (!m_processOffset) @@ -3716,7 +3768,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai ASSERT_ACQUIRED; ++(m_sharedMemory->getHeader()->lhb_waits); - const SLONG scan_interval = m_sharedMemory->getHeader()->lhb_scan_interval; + const ULONG scan_interval = m_sharedMemory->getHeader()->lhb_scan_interval; // lrq_count will be off if we wait for a pending request CHECK(!(request->lrq_flags & LRQ_pending)); @@ -3765,7 +3817,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai // out the time when the lock request will timeout const time_t lock_timeout = (lck_wait < 0) ? current_time + (-lck_wait) : 0; - time_t deadlock_timeout = current_time + scan_interval; + time_t deadlock_timeout = current_time + tdbb->adjustWait(scan_interval); // Wait in a loop until the lock becomes available @@ -3890,7 +3942,7 @@ void LockManager::wait_for_request(thread_db* tdbb, lrq* request, SSHORT lck_wai // We're going to do some real work - reset when we next want to // do a deadlock scan - deadlock_timeout = current_time + scan_interval; + deadlock_timeout = current_time + tdbb->adjustWait(scan_interval); // Handle lock event first if (ret == FB_SUCCESS) diff --git a/src/lock/lock_proto.h b/src/lock/lock_proto.h index 5682e0d4c64..b107d50e73b 100644 --- a/src/lock/lock_proto.h +++ b/src/lock/lock_proto.h @@ -461,6 +461,7 @@ class LockManager final : public Firebird::GlobalStorage, public Firebird::IpcOb void wait_for_request(thread_db*, lrq*, SSHORT); bool init_shared_file(Firebird::CheckStatusWrapper*); void get_shared_file_name(Firebird::PathName&, ULONG extend = 0) const; + bool check_shared_memory(Firebird::CheckStatusWrapper* statusVector); static void blocking_action_thread(LockManager* lockMgr) { @@ -552,7 +553,7 @@ class LockManager final : public Firebird::GlobalStorage, public Firebird::IpcOb SRQ_PTR REL_PTR(const void* item); void* ABS_PTR(SRQ_PTR item); - bool createExtent(); + bool createExtent(ULONG memorySize = 0); #endif }; diff --git a/src/misc/def_awk.c b/src/misc/def_awk.c index c7df1910821..3e428be73ce 100644 --- a/src/misc/def_awk.c +++ b/src/misc/def_awk.c @@ -18,7 +18,7 @@ int main() toks[2] = NULL; for (n = 0; n < 3; ++n) { - toks[n] = strtok(p, " \t\n\r"); + toks[n] = strtok(p, " \t\n\r,"); p = NULL; if (!toks[n]) break; @@ -29,7 +29,12 @@ int main() continue; /* skip unknown statements */ - if (strcmp(toks[0], "#define") != 0) + char* name = NULL; + if (strcmp(toks[0], "#define") == 0) // #define isc_info_end 1 + name = toks[1]; + else if (strcmp(toks[1], "=") == 0) // isc_info_db_id = 4 + name = toks[0]; + if (! name) continue; /* skip unknown constants */ @@ -43,11 +48,11 @@ int main() /* output correct constant */ if (*toks[2] == '-') - printf("\t%s = %s;\n", toks[1], toks[2]); + printf("\t%s = %s;\n", name, toks[2]); else if (strncmp(toks[2], "0x", 2) == 0) - printf("\t%s = $%s;\n", toks[1], toks[2] + 2); + printf("\t%s = $%s;\n", name, toks[2] + 2); else - printf("\t%s = byte(%s);\n", toks[1], toks[2]); + printf("\t%s = byte(%s);\n", name, toks[2]); } return 0; diff --git a/src/misc/pascal/Pascal.implementation.pas b/src/misc/pascal/Pascal.implementation.pas index a73393adbf6..d44ac7ab3a0 100644 --- a/src/misc/pascal/Pascal.implementation.pas +++ b/src/misc/pascal/Pascal.implementation.pas @@ -26,11 +26,14 @@ class procedure FbException.catchException(status: IStatus; e: Exception); statusVector: array[0..4] of NativeIntPtr; msg: AnsiString; begin + if (not Assigned(status)) then + Exit; + if (e.inheritsFrom(FbException)) then status.setErrors(FbException(e).getStatus.getErrors) else begin - msg := e.message; + msg := AnsiString(e.message); statusVector[0] := NativeIntPtr(isc_arg_gds); statusVector[1] := NativeIntPtr(isc_random); @@ -41,3 +44,21 @@ class procedure FbException.catchException(status: IStatus; e: Exception); status.setErrors(@statusVector); end end; + +class procedure FbException.setVersionError(status: IStatus; interfaceName: AnsiString; + currentVersion, expectedVersion: NativeInt); +var + statusVector: array[0..8] of NativeIntPtr; +begin + statusVector[0] := NativeIntPtr(isc_arg_gds); + statusVector[1] := NativeIntPtr(isc_interface_version_too_old); + statusVector[2] := NativeIntPtr(isc_arg_number); + statusVector[3] := NativeIntPtr(expectedVersion); + statusVector[4] := NativeIntPtr(isc_arg_number); + statusVector[5] := NativeIntPtr(currentVersion); + statusVector[6] := NativeIntPtr(isc_arg_string); + statusVector[7] := NativeIntPtr(PAnsiChar(interfaceName)); + statusVector[8] := NativeIntPtr(isc_arg_end); + + status.setErrors(@statusVector); +end; diff --git a/src/misc/pascal/Pascal.interface.pas b/src/misc/pascal/Pascal.interface.pas index 637655bfea3..1cf8653696c 100644 --- a/src/misc/pascal/Pascal.interface.pas +++ b/src/misc/pascal/Pascal.interface.pas @@ -7,6 +7,8 @@ FbException = class(Exception) class procedure checkException(status: IStatus); class procedure catchException(status: IStatus; e: Exception); + class procedure setVersionError(status: IStatus; interfaceName: AnsiString; + currentVersion, expectedVersion: NativeInt); private status: IStatus; diff --git a/src/misc/pascal/fb_get_master_interface.pas b/src/misc/pascal/fb_get_master_interface.pas index 08fe06cac44..759ee4c2b59 100644 --- a/src/misc/pascal/fb_get_master_interface.pas +++ b/src/misc/pascal/fb_get_master_interface.pas @@ -1,3 +1,6 @@ +{$IFNDEF NO_FBCLIENT} function fb_get_master_interface : IMaster; cdecl; external 'fbclient'; +{$ENDIF} const + FB_UsedInYValve = FALSE; diff --git a/src/misc/src_bundle.sh b/src/misc/src_bundle.sh index d4e48c5d064..e97743ae4d0 100755 --- a/src/misc/src_bundle.sh +++ b/src/misc/src_bundle.sh @@ -36,7 +36,7 @@ popd >/dev/null 2>&1 # What and where to bundle MODULE=$SRCROOT/temp/src -MEMBERS="builds doc examples extern lang_helpers src CHANGELOG.md Makefile.in acx_pthread.m4 autogen.sh binreloc.m4 configure.ac CMakeLists.txt README.md travis.sh .travis.yml" +MEMBERS="builds doc examples extern lang_helpers src CHANGELOG.md Makefile.in acx_pthread.m4 autogen.sh binreloc.m4 configure.ac CMakeLists.txt README.md" # Cleanup rm -rf $MODULE diff --git a/src/misc/writeBuildNum.sh b/src/misc/writeBuildNum.sh index 5b07bf85cb2..16230b0fd59 100755 --- a/src/misc/writeBuildNum.sh +++ b/src/misc/writeBuildNum.sh @@ -8,8 +8,8 @@ BuildVersion="$Id: writeBuildNum.sh,v 1.28732 2010/05/29 13:12:08 fsg Exp $" BuildType=V MajorVer=4 MinorVer=0 -RevNo=0 -BuildNum=2465 +RevNo=6 +BuildNum=3205 NowAt=`pwd` cd `dirname $0` @@ -20,8 +20,8 @@ Root=`dirname $Root` if [ "$SPECIAL_BUILD_SUFFIX" = "" ]; then # Normal builds -SuffixKind="Release Candidate" -SuffixVer="1" +SuffixKind="" +SuffixVer="" BuildSuffix="Firebird 4.0" [ "$SuffixKind" = "" ] || BuildSuffix="$BuildSuffix $SuffixKind" [ "$SuffixVer" = "" ] || BuildSuffix="$BuildSuffix $SuffixVer" diff --git a/src/msgs/facilities2.sql b/src/msgs/facilities2.sql index 00b10036da8..16b78c5b5bc 100644 --- a/src/msgs/facilities2.sql +++ b/src/msgs/facilities2.sql @@ -1,7 +1,7 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2021-03-18 11:20:00', 'JRD', 0, 954) +('2021-05-11 14:10:00', 'JRD', 0, 957) ('2015-03-17 18:33:00', 'QLI', 1, 533) ('2018-03-17 12:00:00', 'GFIX', 3, 136) ('1996-11-07 13:39:40', 'GPRE', 4, 1) @@ -9,7 +9,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2018-06-22 11:46:00', 'DYN', 8, 309) ('1996-11-07 13:39:40', 'INSTALL', 10, 1) ('1996-11-07 13:38:41', 'TEST', 11, 4) -('2021-02-04 11:21:00', 'GBAK', 12, 405) +('2021-09-13 15:40:00', 'GBAK', 12, 406) ('2019-04-13 21:10:00', 'SQLERR', 13, 1047) ('1996-11-07 13:38:42', 'SQLWARN', 14, 613) ('2018-02-27 14:50:31', 'JRD_BUGCHK', 15, 307) @@ -18,7 +18,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM ('2019-10-19 12:52:29', 'GSTAT', 21, 63) ('2021-02-04 10:32:00', 'FBSVCMGR', 22, 62) ('2009-07-18 12:12:12', 'UTL', 23, 2) -('2020-12-20 15:40:00', 'NBACKUP', 24, 82) +('2022-09-28 14:05:00', 'NBACKUP', 24, 89) ('2009-07-20 07:55:48', 'FBTRACEMGR', 25, 41) ('2015-07-27 00:00:00', 'JAYBIRD', 26, 1) ('2020-11-27 00:00:00', 'R2DBC_FIREBIRD', 27, 1) diff --git a/src/msgs/messages2.sql b/src/msgs/messages2.sql index 9306bcfb385..7abe265c4c6 100644 --- a/src/msgs/messages2.sql +++ b/src/msgs/messages2.sql @@ -619,8 +619,8 @@ without specifying a character set.', NULL); ('no_update', 'several', 'dfw.epp', NULL, 0, 520, NULL, 'cannot update', NULL, NULL); ('cursor_already_open', NULL, 'exe.epp', NULL, 0, 521, NULL, 'Cursor is already open', NULL, NULL); ('stack_trace', 'looper', 'exe.epp', NULL, 0, 522, NULL, '@1', NULL, NULL); -('ctx_var_not_found', NULL, 'functions.cpp', NULL, 0, 523, NULL, 'Context variable @1 is not found in namespace @2', NULL, NULL); -('ctx_namespace_invalid', NULL, 'functions.cpp', NULL, 0, 524, NULL, 'Invalid namespace name @1 passed to @2', NULL, NULL); +('ctx_var_not_found', NULL, 'functions.cpp', NULL, 0, 523, NULL, 'Context variable ''@1'' is not found in namespace ''@2''', NULL, NULL); +('ctx_namespace_invalid', NULL, 'functions.cpp', NULL, 0, 524, NULL, 'Invalid namespace name ''@1'' passed to @2', NULL, NULL); ('ctx_too_big', NULL, 'functions.cpp', NULL, 0, 525, NULL, 'Too many context variables', NULL, NULL); ('ctx_bad_argument', NULL, 'functions.cpp', NULL, 0, 526, NULL, 'Invalid argument passed to @1', NULL, NULL); ('identifier_too_long', NULL, 'par.cpp', NULL, 0, 527, NULL, 'BLR syntax error. Identifier @1... is too long', NULL, NULL); @@ -771,7 +771,7 @@ Data source : @4', NULL, NULL) ('sysf_fp_overflow', 'evlStdMath', 'SysFunction.cpp', NULL, 0, 661, NULL, 'Floating point overflow in built-in function @1', NULL, NULL); ('udf_fp_overflow', 'FUN_evaluate', 'fun.epp', NULL, 0, 662, NULL, 'Floating point overflow in result from UDF @1', NULL, NULL); ('udf_fp_nan', 'FUN_evaluate', 'fun.epp', NULL, 0, 663, NULL, 'Invalid floating point value returned by UDF @1', NULL, NULL); -('instance_conflict', 'ISC_map_file', 'isc_sync.cpp', NULL, 0, 664, NULL, 'Database is probably already opened by another engine instance in another Windows session', NULL, NULL); +('instance_conflict', 'ISC_map_file', 'isc_sync.cpp', NULL, 0, 664, NULL, 'Shared memory area is probably already created by another engine instance in another Windows session', NULL, NULL); ('out_of_temp_space', 'setupFile', 'TempSpace.cpp', NULL, 0, 665, NULL, 'No free space found in temporary directories', NULL, NULL); ('eds_expl_tran_ctrl', NULL, '', NULL, 0, 666, NULL, 'Explicit transaction control is not allowed', NULL, NULL) ('no_trusted_spb', NULL, 'svc.cpp', NULL, 0, 667, NULL, 'Use of TRUSTED switches in spb_command_line is prohibited', NULL, NULL) @@ -905,7 +905,7 @@ Data source : @4', NULL, NULL) ('no_cursor', 'DSQL_open', 'dsql.cpp', NULL, 0, 795, NULL, 'Cannot open cursor for non-SELECT statement', NULL, NULL); ('dsql_window_incompat_frames', NULL, 'ExprNodes.cpp', NULL, 0, 796, NULL, 'If specifies @1, then shall not specify @2', NULL, NULL); ('dsql_window_range_multi_key', NULL, 'ExprNodes.cpp', NULL, 0, 797, NULL, 'RANGE based window with {PRECEDING | FOLLOWING} cannot have ORDER BY with more than one value', NULL, NULL); -('dsql_window_range_inv_key_type', NULL, 'ExprNodes.cpp', NULL, 0, 798, NULL, 'RANGE based window must have an ORDER BY key of numerical, date, time or timestamp types', NULL, NULL); +('dsql_window_range_inv_key_type', NULL, 'ExprNodes.cpp', NULL, 0, 798, NULL, 'RANGE based window with PRECEDING/FOLLOWING must have a single ORDER BY key of numerical, date, time or timestamp types', NULL, NULL); ('dsql_window_frame_value_inv_type', NULL, 'ExprNodes.cpp', NULL, 0, 799, NULL, 'Window RANGE/ROWS PRECEDING/FOLLOWING value must be of a numerical type', NULL, NULL); ('window_frame_value_invalid', NULL, 'ExprNodes.cpp', NULL, 0, 800, NULL, 'Invalid PRECEDING or FOLLOWING offset in window function: cannot be negative', NULL, NULL); ('dsql_window_not_found', NULL, 'ExprNodes.cpp', NULL, 0, 801, NULL, 'Window @1 not found', NULL, NULL); @@ -924,7 +924,7 @@ Data source : @4', NULL, NULL) ('overriding_without_identity', NULL, 'StmtNodes.cpp', NULL, 0, 814, NULL, 'OVERRIDING clause can be used only when an identity column is present in the INSERT''s field list for table/view @1', NULL, NULL); ('overriding_system_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 815, NULL, 'OVERRIDING SYSTEM VALUE can be used only for identity column defined as ''GENERATED ALWAYS'' in INSERT for table/view @1', NULL, NULL); ('overriding_user_invalid', NULL, 'StmtNodes.cpp', NULL, 0, 816, NULL, 'OVERRIDING USER VALUE can be used only for identity column defined as ''GENERATED BY DEFAULT'' in INSERT for table/view @1', NULL, NULL); -('overriding_system_missing', NULL, 'StmtNodes.cpp', NULL, 0, 817, NULL, 'OVERRIDING SYSTEM VALUE should be used to override the value of an identity column defined as ''GENERATED ALWAYS'' in table/view @1', NULL, NULL); +('overriding_missing', NULL, 'StmtNodes.cpp', NULL, 0, 817, NULL, 'OVERRIDING clause should be used when an identity column defined as ''GENERATED ALWAYS'' is present in the INSERT''s field list for table table/view @1', NULL, NULL); ('decprecision_err', NULL, 'dsql parse.y', NULL, 0, 818, NULL, 'DecFloat precision must be 16 or 34', NULL, NULL); ('decfloat_divide_by_zero', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 819, NULL, 'Decimal float divide by zero. The code attempted to divide a DECFLOAT value by zero.', NULL, NULL); ('decfloat_inexact_result', 'DecimalContext::checkForExceptions', 'DecFloat.cpp', NULL, 0, 820, NULL, 'Decimal float inexact result. The result of an operation cannot be represented as a decimal fraction.', NULL, NULL); @@ -965,7 +965,7 @@ Data source : @4', NULL, NULL) ('big_segment', NULL, NULL, NULL, 0, 855, NULL, 'Segment size (@1) should not exceed 65535 (64K - 1) when using segmented blob', NULL, NULL); ('batch_policy', NULL, NULL, NULL, 0, 856, NULL, 'Invalid blob policy in the batch for @1() call', NULL, NULL); ('batch_defbpb', NULL, NULL, NULL, 0, 857, NULL, 'Can''t change default BPB after adding any data to batch', NULL, NULL); -('batch_align', NULL, 'interface.cpp', NULL, 0, 858, NULL, 'Unexpected info buffer structure querying for default blob alignment', NULL, NULL); +('batch_align', NULL, 'interface.cpp', NULL, 0, 858, NULL, 'Unexpected info buffer structure querying for server batch parameters', NULL, NULL); ('multi_segment_dup', 'getMultiPartConnectParameter', 'server.cpp', NULL, 0, 859, NULL, 'Duplicated segment @1 in multisegment connect block parameter', NULL, NULL); ('non_plugin_protocol', NULL, 'server.cpp', NULL, 0, 860, NULL, 'Plugin not supported by network protocol', NULL, NULL); ('message_format', NULL, 'server.cpp', NULL, 0, 861, NULL, 'Error parsing message format', NULL, NULL); @@ -1061,6 +1061,9 @@ Data source : @4', NULL, NULL) ('repl_error', 'checkStatus', 'Publisher.cpp', NULL, 0, 951, NULL, 'Replication error', NULL, NULL); ('ses_reset_failed', NULL, 'Attachment.cpp', NULL, 0, 952, NULL, 'Reset of user session failed. Connection is shut down.', NULL, NULL); ('block_size', NULL, 'unix.cpp', NULL, 0, 953, NULL, 'File size is less than expected', NULL, NULL); +('tom_key_length', NULL, 'SysFunction.cpp', NULL, 0, 954, NULL, 'Invalid key length @1, need >@2', NULL, NULL); +('inf_invalid_args', NULL, NULL, NULL, 0, 955, NULL, 'Invalid information arguments', NULL, NULL); +('sysf_invalid_null_empty', NULL, 'SysFunction.cpp', NULL, 0, 956, NULL, 'Empty or NULL parameter @1 is not accepted', NULL, NULL); -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); @@ -2577,6 +2580,7 @@ ERROR: Backup incomplete', NULL, NULL); (NULL, 'get_pub_table', 'restore.epp', NULL, 12, 402, NULL, 'publication for table', NULL, NULL); ('gbak_opt_replica', 'burp_usage', 'burp.c', NULL, 12, 403, NULL, ' @1REPLICA "none", "read_only" or "read_write" replica mode', NULL, NULL); ('gbak_replica_req', 'BURP_gbak', 'burp.c', NULL, 12, 404, NULL, '"none", "read_only" or "read_write" required', NULL, NULL); +(NULL, 'get_blob', 'restore.epp', NULL, 12, 405, NULL, 'could not access batch parameters', NULL, NULL); -- SQLERR (NULL, NULL, NULL, NULL, 13, 1, NULL, 'Firebird error', NULL, NULL); (NULL, NULL, NULL, NULL, 13, 74, NULL, 'Rollback not performed', NULL, NULL); @@ -3589,7 +3593,7 @@ Analyzing database pages ...', NULL, NULL); ('nbackup_lostguid_l0bk', 'NBackup::restore_database', 'nbackup.cpp', NULL, 24, 67, NULL, 'Cannot get backup guid clumplet from L0 backup', NULL, NULL) (NULL, 'nbackup', 'nbackup.cpp', NULL, 24, 68, NULL, 'Physical Backup Manager version @1', NULL, NULL) (NULL, 'restore_database', 'nbackup.cpp', NULL, 24, 69, NULL, 'Enter name of the backup file of level @1 ("." - do not restore further):', NULL, NULL) -(NULL, 'usage', 'nbackup.cpp', NULL, 24, 70, NULL, ' -D(IRECT) [ON | OFF] Use or not direct I/O when backing up database', NULL, NULL) +(NULL, 'usage', 'nbackup.cpp', NULL, 24, 70, NULL, ' -D(IRECT) Use or not direct I/O when backing up database', NULL, NULL) ('nbackup_switchd_parameter', 'main', 'nbackup.cpp', NULL, 24, 71, NULL, 'Wrong parameter @1 for switch -D, need ON or OFF', NULL, NULL) (NULL, 'usage', 'nbackup.cpp', NULL, 24, 72, NULL, 'special options are:', NULL, NULL) ('nbackup_user_stop', 'checkCtrlC()', 'nbackup.cpp', NULL, 24, 73, NULL, 'Terminated due to user request', NULL, NULL) @@ -3601,6 +3605,13 @@ Analyzing database pages ...', NULL, NULL); (NULL, 'usage', 'nbackup.cpp', NULL, 24, 79, NULL, ' -INPLACE option could corrupt the database that has changed since previous restore.', NULL, NULL) (NULL, 'usage', 'nbackup.cpp', NULL, 24, 80, NULL, ' -SEQ(UENCE) Preserve original replication sequence', NULL, NULL) ('nbackup_seq_misuse', 'nbackup', 'nbackup.cpp', NULL, 24, 81, NULL, 'Switch -SEQ(UENCE) can be used only with -FIXUP or -RESTORE', NULL, NULL) +(NULL, 'usage', 'nbackup.cpp', NULL, 24, 82, NULL, ' -CLEAN_HIST(ORY) Clean old records from backup history', NULL, NULL) +(NULL, 'usage', 'nbackup.cpp', NULL, 24, 83, NULL, ' -K(EEP) <(R)OWS | (D)AYS> How many recent rows (or days back from today) should be kept in the history', NULL, NULL) +('nbackup_wrong_param', 'nbackup', 'nbackup.cpp', NULL, 24, 84, NULL, 'Wrong parameter value for switch @1', NULL, NULL) +('nbackup_clean_hist_misuse', 'nbackup', 'nbackup.cpp', NULL, 24, 85, NULL, 'Switch -CLEAN_HISTORY can be used only with -BACKUP', NULL, NULL) +('nbackup_clean_hist_missed', 'nbackup', 'nbackup.cpp', NULL, 24, 86, NULL, '-KEEP can be used only with -CLEAN_HISTORY', NULL, NULL) +('nbackup_keep_hist_missed', 'nbackup', 'nbackup.cpp', NULL, 24, 87, NULL, '-KEEP is required with -CLEAN_HISTORY', NULL, NULL) +('nbackup_second_keep_switch', 'nbackup', 'nbackup.cpp', NULL, 24, 88, NULL, '-KEEP can be used one time only', NULL, NULL) -- FBTRACEMGR -- All messages use the new format. (NULL, 'usage', 'TraceCmdLine.cpp', NULL, 25, 1, NULL, 'Firebird Trace Manager version @1', NULL, NULL) diff --git a/src/msgs/msg.sql b/src/msgs/msg.sql index 85c536df3ff..0b26526e9cc 100644 --- a/src/msgs/msg.sql +++ b/src/msgs/msg.sql @@ -29,7 +29,7 @@ CREATE DOMAIN SQL_STATE AS CHAR(5); CREATE DOMAIN SQL_SUBCLASS AS CHAR(3); CREATE DOMAIN SYMBOL AS VARCHAR(32); CREATE DOMAIN TEMPLATE AS BLOB SUB_TYPE 0 SEGMENT SIZE 256; -CREATE DOMAIN TEXT AS VARCHAR(138); +CREATE DOMAIN TEXT AS VARCHAR(150); CREATE DOMAIN TRANSLATOR AS VARCHAR(32); CREATE DOMAIN TRANS_DATE AS TIMESTAMP; CREATE DOMAIN TRANS_NOTES AS BLOB SUB_TYPE 0 SEGMENT SIZE 0; diff --git a/src/msgs/system_errors2.sql b/src/msgs/system_errors2.sql index c594b750764..07a2bfc927d 100644 --- a/src/msgs/system_errors2.sql +++ b/src/msgs/system_errors2.sql @@ -823,7 +823,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-902, '42', '000', 0, 814, 'overriding_without_identity', NULL, NULL) (-902, '42', '000', 0, 815, 'overriding_system_invalid', NULL, NULL) (-902, '42', '000', 0, 816, 'overriding_user_invalid', NULL, NULL) -(-902, '42', '000', 0, 817, 'overriding_system_missing', NULL, NULL) +(-902, '42', '000', 0, 817, 'overriding_missing', NULL, NULL) (-842, 'HY', '104', 0, 818, 'decprecision_err', NULL, NULL) (-901, '22', '012', 0, 819, 'decfloat_divide_by_zero', NULL, NULL) (-901, '22', '000', 0, 820, 'decfloat_inexact_result', NULL, NULL) @@ -960,6 +960,9 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-902, 'HY', '000', 0, 951, 'repl_error', NULL, NULL) (-902, '08', '003', 0, 952, 'ses_reset_failed', NULL, NULL) (-902, 'XX', '000', 0, 953, 'block_size', NULL, NULL) +(-901, '22', '023', 0, 954, 'tom_key_length', NULL, NULL) +(-901, 'HY', '000', 0, 955, 'inf_invalid_args', NULL, 'WARNING') +(-901, '22', '023', 0, 956, 'sysf_invalid_null_empty', NULL, NULL) -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) @@ -1010,7 +1013,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA (-502, '24', '000', 7, 20, 'dsql_cursor_exists', NULL, NULL) (-502, '34', '000', 7, 21, 'dsql_cursor_rel_ambiguous', NULL, NULL) (-502, '34', '000', 7, 22, 'dsql_cursor_rel_not_found', NULL, NULL) -(-502, '24', '000', 7, 23, 'dsql_cursor_not_open', NULL, NULL) +(-504, '24', '000', 7, 23, 'dsql_cursor_not_open', NULL, NULL) (-607, 'HY', '004', 7, 24, 'dsql_type_not_supp_ext_tab', NULL, NULL) (-804, '0A', '000', 7, 25, 'dsql_feature_not_supported_ods', NULL, NULL) (-660, '22', '000', 7, 26, 'primary_key_required', NULL, NULL) @@ -1454,6 +1457,11 @@ COMMIT WORK; (-901, '54', '023', 24, 75, 'nbackup_deco_parse', NULL, NULL) (-901, '00', '000', 24, 77, 'nbackup_lostrec_guid_db', NULL, NULL) (-901, '00', '000', 24, 81, 'nbackup_seq_misuse', NULL, NULL) +(-901, '00', '000', 24, 84, 'nbackup_wrong_param', NULL, NULL) +(-901, '00', '000', 24, 85, 'nbackup_clean_hist_misuse', NULL, NULL) +(-901, '00', '000', 24, 86, 'nbackup_clean_hist_missed', NULL, NULL) +(-901, '00', '000', 24, 87, 'nbackup_keep_hist_missed', NULL, NULL) +(-901, '00', '000', 24, 88, 'nbackup_second_keep_switch', NULL, NULL) -- FBTRACEMGR (-901, '00', '000', 25, 30, 'trace_conflict_acts', NULL, NULL) (-901, '00', '000', 25, 31, 'trace_act_notfound', NULL, NULL) diff --git a/src/plugins/crypt/chacha/ChaCha.cpp b/src/plugins/crypt/chacha/ChaCha.cpp index cc6c20eb605..2748a821916 100644 --- a/src/plugins/crypt/chacha/ChaCha.cpp +++ b/src/plugins/crypt/chacha/ChaCha.cpp @@ -36,13 +36,16 @@ using namespace Firebird; namespace { -void tomCheck(int err, const char* text) +void tomCheck(int err, const char* text, int specErr = CRYPT_OK, const char* specText = nullptr) { if (err == CRYPT_OK) return; string buf; - buf.printf("TomCrypt library error %s: %s", text, error_to_string(err)); + if (specText && (err == specErr)) + buf = specText; + else + buf.printf("TomCrypt library error %s: %s", text, error_to_string(err)); (Arg::Gds(isc_random) << buf).raise(); } @@ -76,7 +79,8 @@ class Cipher : public GlobalStorage { unsigned char* t = static_cast(to); const unsigned char* f = static_cast(from); - tomCheck(chacha_crypt(&chacha, f, length, t), "processing CHACHA#20"); + tomCheck(chacha_crypt(&chacha, f, length, t), "processing CHACHA#20", + CRYPT_OVERFLOW, "Connection broken - internal chacha overflow. Reattach to server to proceed."); } private: @@ -84,97 +88,111 @@ class Cipher : public GlobalStorage }; -class ChaCha FB_FINAL : public StdPlugin > +template +class ChaCha FB_FINAL : public StdPlugin, CheckStatusWrapper> > { public: explicit ChaCha(IPluginConfig*) - : en(NULL), de(NULL), iv(getPool()) - { } + : en(NULL), de(NULL), iv(this->getPool()) + { + if (IV_SIZE == 16) + { + GenerateRandomBytes(iv.getBuffer(16), 12); + iv[12] = iv[13] = iv[14] = iv[15] = 0; + } + else + GenerateRandomBytes(iv.getBuffer(8), 8); + } // ICryptPlugin implementation - const char* getKnownTypes(CheckStatusWrapper* status); - void setKey(CheckStatusWrapper* status, ICryptKey* key); - void encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to); - void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to); - const unsigned char* getSpecificData(CheckStatusWrapper* status, const char* type, unsigned* len); - void setSpecificData(CheckStatusWrapper* status, const char* type, unsigned len, const unsigned char* data); - -private: - Cipher* createCypher(unsigned int l, const void* key); - AutoPtr en, de; - UCharBuffer iv; -}; + const char* getKnownTypes(CheckStatusWrapper* status) + { + return "Symmetric"; + } -void ChaCha::setKey(CheckStatusWrapper* status, ICryptKey* key) -{ - status->init(); - try + void setKey(CheckStatusWrapper* status, ICryptKey* key) { - unsigned int l; - const void* k = key->getEncryptKey(&l); - en = createCypher(l, k); + try + { + unsigned int l; + const void* k = key->getEncryptKey(&l); + en = createCypher(l, k); - k = key->getDecryptKey(&l); - de = createCypher(l, k); + k = key->getDecryptKey(&l); + de = createCypher(l, k); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } } - catch (const Exception& ex) + + void encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) { - ex.stuffException(status); + try + { + en->transform(length, from, to); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } } -} -void ChaCha::encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) -{ - status->init(); - en->transform(length, from, to); -} + void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) + { + try + { + de->transform(length, from, to); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } + } -void ChaCha::decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) -{ - status->init(); - de->transform(length, from, to); -} + const unsigned char* getSpecificData(CheckStatusWrapper* status, const char* type, unsigned* len) + { + *len = IV_SIZE; -Cipher* ChaCha::createCypher(unsigned int l, const void* key) -{ - if (l < 16) - (Arg::Gds(isc_random) << "Key too short").raise(); + //WIRECRYPT_DEBUG(fprintf(stderr, "getSpecificData %d\n", *len)); + return iv.begin(); + } - hash_state md; - tomCheck(sha256_init(&md), "initializing sha256"); - tomCheck(sha256_process(&md, static_cast(key), l), "processing original key in sha256"); - unsigned char stretched[32]; - tomCheck(sha256_done(&md, stretched), "getting stretched key from sha256"); + void setSpecificData(CheckStatusWrapper* status, const char* type, unsigned len, const unsigned char* data) + { + //WIRECRYPT_DEBUG(fprintf(stderr, "setSpecificData %d\n", len)); + memcpy(iv.getBuffer(len), data, len); + } - return FB_NEW Cipher(stretched, iv.getCount(), iv.begin()); -} +private: + Cipher* createCypher(unsigned int l, const void* key) + { + if (l < 16) + (Arg::Gds(isc_random) << "Key too short").raise(); -const char* ChaCha::getKnownTypes(CheckStatusWrapper* status) -{ - status->init(); - return "Symmetric"; -} + hash_state md; + tomCheck(sha256_init(&md), "initializing sha256"); + tomCheck(sha256_process(&md, static_cast(key), l), "processing original key in sha256"); + unsigned char stretched[32]; + tomCheck(sha256_done(&md, stretched), "getting stretched key from sha256"); -const unsigned char* ChaCha::getSpecificData(CheckStatusWrapper* status, const char*, unsigned* len) -{ - *len = 16; - GenerateRandomBytes(iv.getBuffer(*len), 12); - iv[12] = iv[13] = iv[14] = iv[15] = 0; - return iv.begin(); -} + return FB_NEW Cipher(stretched, iv.getCount(), iv.begin()); + } -void ChaCha::setSpecificData(CheckStatusWrapper* status, const char*, unsigned len, const unsigned char* data) -{ - memcpy(iv.getBuffer(len), data, len); -} + AutoPtr en, de; + UCharBuffer iv; +}; -SimpleFactory factory; +SimpleFactory > factory; +SimpleFactory > factory64; } // anonymous namespace -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) { CachedMasterInterface::set(master); PluginManagerInterfacePtr()->registerPluginFactory(IPluginManager::TYPE_WIRE_CRYPT, "ChaCha", &factory); + PluginManagerInterfacePtr()->registerPluginFactory(IPluginManager::TYPE_WIRE_CRYPT, "ChaCha64", &factory64); getUnloadDetector()->registerMe(); } diff --git a/src/plugins/udr_engine/UdrEngine.cpp b/src/plugins/udr_engine/UdrEngine.cpp index bfd6e1624d6..2b29e8e594a 100644 --- a/src/plugins/udr_engine/UdrEngine.cpp +++ b/src/plugins/udr_engine/UdrEngine.cpp @@ -32,6 +32,7 @@ #include "../common/os/mod_loader.h" #include "../common/os/path_utils.h" #include "../common/classes/ImplementHelper.h" +#include "../common/classes/GetPlugins.h" #include "../common/StatusHolder.h" @@ -714,7 +715,7 @@ class IExternalEngineFactoryImpl : public SimpleFactory { } factory; -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master) { CachedMasterInterface::set(master); diff --git a/src/remote/SockAddr.h b/src/remote/SockAddr.h index 624c9df5de0..ba1379a234f 100644 --- a/src/remote/SockAddr.h +++ b/src/remote/SockAddr.h @@ -106,10 +106,12 @@ class SockAddr #define AF_INET6_POSIX 10 #define AF_INET6_WINDOWS 23 +#define AF_INET6_FREEBSD 28 #define AF_INET6_DARWIN 30 #if AF_INET6 == AF_INET6_POSIX #elif AF_INET6 == AF_INET6_WINDOWS +#elif AF_INET6 == AF_INET6_FREEBSD #elif AF_INET6 == AF_INET6_DARWIN #else #error Unknown value of AF_INET6 ! @@ -125,6 +127,7 @@ inline void SockAddr::checkAndFixFamily() case AF_INET6_POSIX: case AF_INET6_WINDOWS: + case AF_INET6_FREEBSD: case AF_INET6_DARWIN: data.sock.sa_family = AF_INET6; fb_assert(len == sizeof(sockaddr_in6)); diff --git a/src/remote/client/interface.cpp b/src/remote/client/interface.cpp index fc5fda7952d..bc18992f6c2 100644 --- a/src/remote/client/interface.cpp +++ b/src/remote/client/interface.cpp @@ -65,6 +65,7 @@ #include "../common/StatementMetadata.h" #include "../common/IntlParametersBlock.h" #include "../common/status.h" +#include "../common/db_alias.h" #include "../auth/SecurityDatabase/LegacyClient.h" #include "../auth/SecureRemotePassword/client/SrpClient.h" @@ -87,10 +88,6 @@ #include "../remote/os/win32/xnet_proto.h" #endif -#ifdef WIN_NT -#define sleep(seconds) Sleep ((seconds) * 1000) -#endif // WIN_NT - const char* const PROTOCOL_INET = "inet"; const char* const PROTOCOL_INET4 = "inet4"; @@ -131,10 +128,10 @@ namespace { status_exception::raise(Arg::Gds(isc_imp_exc) << Arg::Gds(isc_blktoobig)); } - class SaveString + class UsePreallocatedBuffer { public: - SaveString(cstring& toSave, ULONG newLength, UCHAR* newBuffer) + UsePreallocatedBuffer(cstring& toSave, ULONG newLength, UCHAR* newBuffer) : ptr(&toSave), oldValue(*ptr) { @@ -142,15 +139,50 @@ namespace { ptr->cstr_allocated = newLength; } - ~SaveString() + ~UsePreallocatedBuffer() { *ptr = oldValue; } - private: + protected: cstring* ptr; + private: cstring oldValue; }; + + class UseStandardBuffer : public UsePreallocatedBuffer + { + public: + UseStandardBuffer(cstring& toSave) + : UsePreallocatedBuffer(toSave,0, nullptr) + { } + + ~UseStandardBuffer() + { + ptr->free(); + } + }; + + class ClientPortsCleanup : public PortsCleanup + { + public: + ClientPortsCleanup() : + PortsCleanup() + {} + + explicit ClientPortsCleanup(MemoryPool& p) : + PortsCleanup(p) + {} + + void closePort(rem_port* port) override; + + void delay() override + { + Thread::sleep(50); + } + }; + + GlobalPtr outPorts; } namespace Remote { @@ -173,6 +205,8 @@ class Blob FB_FINAL : public RefCntIface > void cancel(CheckStatusWrapper* status) override; void close(CheckStatusWrapper* status) override; int seek(CheckStatusWrapper* status, int mode, int offset) override; // returns position + void deprecatedCancel(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; public: explicit Blob(Rbl* handle) @@ -183,6 +217,8 @@ class Blob FB_FINAL : public RefCntIface > private: void freeClientData(CheckStatusWrapper* status, bool force = false); + void internalCancel(Firebird::CheckStatusWrapper* status); + void internalClose(Firebird::CheckStatusWrapper* status); Rbl* blob; }; @@ -223,6 +259,9 @@ class Transaction FB_FINAL : public RefCntIface outputFormat; @@ -324,9 +368,11 @@ int ResultSet::release() class Batch FB_FINAL : public RefCntIface > { public: + static const ULONG DEFER_BATCH_LIMIT = 64; + Batch(Statement* s, IMessageMetadata* inFmt, unsigned parLength, const unsigned char* par); - // IResultSet implementation + // IBatch implementation int release() override; void add(Firebird::CheckStatusWrapper* status, unsigned count, const void* inBuffer) override; void addBlob(Firebird::CheckStatusWrapper* status, unsigned length, const void* inBuffer, ISC_QUAD* blobId, @@ -340,11 +386,24 @@ class Batch FB_FINAL : public RefCntIface void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par) override; Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status) override; void close(Firebird::CheckStatusWrapper* status) override; + void deprecatedClose(Firebird::CheckStatusWrapper* status) override; + void getInfo(CheckStatusWrapper* status, + unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) override; private: void freeClientData(CheckStatusWrapper* status, bool force = false); + void internalClose(Firebird::CheckStatusWrapper* status); void releaseStatement(); - void setBlobAlignment(); + void setServerInfo(); + + void cleanup() + { + if (blobPolicy != BLOB_NONE) + blobStream = blobStreamBuffer; + sizePointer = nullptr; + messageStream = 0; + } void genBlobId(ISC_QUAD* blobId) { @@ -372,7 +431,7 @@ class Batch FB_FINAL : public RefCntIface if (step == messageBufferSize) { // direct packet sent - sendMessagePacket(step, ptr); + sendMessagePacket(step, ptr, false); } else { @@ -381,7 +440,7 @@ class Batch FB_FINAL : public RefCntIface messageStream += step; if (messageStream == messageBufferSize) { - sendMessagePacket(messageBufferSize, messageStreamBuffer); + sendMessagePacket(messageBufferSize, messageStreamBuffer, false); messageStream = 0; } } @@ -394,14 +453,14 @@ class Batch FB_FINAL : public RefCntIface // working with blob stream buffer void newBlob() { - setBlobAlignment(); + setServerInfo(); alignBlobBuffer(blobAlign); fb_assert(blobStream - blobStreamBuffer <= blobBufferSize); ULONG space = blobBufferSize - (blobStream - blobStreamBuffer); if (space < Rsr::BatchStream::SIZEOF_BLOB_HEAD) { - sendBlobPacket(blobStream - blobStreamBuffer, blobStreamBuffer); + sendBlobPacket(blobStream - blobStreamBuffer, blobStreamBuffer, false); blobStream = blobStreamBuffer; } } @@ -410,12 +469,12 @@ class Batch FB_FINAL : public RefCntIface { fb_assert(alignment); - FB_UINT64 zeroFill = 0; - UCHAR* newPointer = FB_ALIGN(blobStream, alignment); ULONG align = FB_ALIGN(blobStream, alignment) - blobStream; - putBlobData(align, &zeroFill); if (bs) *bs += align; + + FB_UINT64 zeroFill = 0; + putBlobData(align, &zeroFill); } void putBlobData(ULONG size, const void* p) @@ -431,7 +490,7 @@ class Batch FB_FINAL : public RefCntIface if (step == blobBufferSize) { // direct packet sent - sendBlobPacket(blobBufferSize, ptr); + sendBlobPacket(blobBufferSize, ptr, false); } else { @@ -440,9 +499,9 @@ class Batch FB_FINAL : public RefCntIface blobStream += step; if (blobStream - blobStreamBuffer == blobBufferSize) { - sendBlobPacket(blobBufferSize, blobStreamBuffer); + sendBlobPacket(blobBufferSize, blobStreamBuffer, false); blobStream = blobStreamBuffer; - sizePointer = NULL; + sizePointer = nullptr; } } @@ -463,15 +522,16 @@ class Batch FB_FINAL : public RefCntIface { newBlob(); - ISC_QUAD zero = {0, 0}; - putBlobData(sizeof zero, &zero); + ISC_QUAD quadZero = {0, 0}; + putBlobData(sizeof quadZero, &quadZero); setSizePointer(); - ULONG z2 = 0; - putBlobData(sizeof z2, &z2); - putBlobData(sizeof z2, &z2); + ULONG longZero = 0; + putBlobData(sizeof longZero, &longZero); + putBlobData(sizeof longZero, &longZero); } *sizePointer += size; + if (segmented) { if (size > MAX_USHORT) @@ -480,11 +540,14 @@ class Batch FB_FINAL : public RefCntIface << Arg::Gds(isc_big_segment) << Arg::Num(size)).raise(); } - alignBlobBuffer(BLOB_SEGHDR_ALIGN, sizePointer); *sizePointer += sizeof(USHORT); + + alignBlobBuffer(BLOB_SEGHDR_ALIGN, sizePointer); + USHORT segSize = size; putBlobData(sizeof segSize, &segSize); } + putBlobData(size, ptr); } @@ -492,27 +555,29 @@ class Batch FB_FINAL : public RefCntIface { if (blobPolicy != BLOB_NONE) { - setBlobAlignment(); + setServerInfo(); alignBlobBuffer(blobAlign); ULONG size = blobStream - blobStreamBuffer; if (size) { - sendBlobPacket(size, blobStreamBuffer); + sendBlobPacket(size, blobStreamBuffer, messageStream == 0); blobStream = blobStreamBuffer; } } if (messageStream) { - sendMessagePacket(messageStream, messageStreamBuffer); + sendMessagePacket(messageStream, messageStreamBuffer, true); messageStream = 0; } batchActive = false; + blobCount = messageCount = 0; } - void sendBlobPacket(unsigned size, const UCHAR* ptr); - void sendMessagePacket(unsigned size, const UCHAR* ptr); + void sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash); + void sendMessagePacket(unsigned size, const UCHAR* ptr, bool flash); + void sendDeferredPacket(IStatus* status, rem_port* port, PACKET* packet, bool flash); Firebird::AutoPtr messageStreamBuffer, blobStreamBuffer; ULONG messageStream; @@ -527,6 +592,8 @@ class Batch FB_FINAL : public RefCntIface UCHAR blobPolicy; bool segmented, defSegmented, batchActive; + ULONG messageCount, blobCount, serverSize, blobHeadSize; + public: bool tmpStatement; }; @@ -554,12 +621,14 @@ class Replicator FB_FINAL : public RefCntIface void RProvider::shutdown(CheckStatusWrapper* status, unsigned int /*timeout*/, const int /*reason*/) { status->init(); + + try + { + outPorts->closePorts(); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } } void RProvider::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback) @@ -994,7 +1085,7 @@ void registerRedirector(Firebird::IPluginManager* iPlugin) } // namespace Remote /* -extern "C" void FB_PLUGIN_ENTRY_POINT(IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(IMaster* master) { IPluginManager* pi = master->getPluginManager(); registerRedirector(pi); @@ -1014,15 +1105,16 @@ static void batch_gds_receive(rem_port*, struct rmtque *, USHORT); static void batch_dsql_fetch(rem_port*, struct rmtque *, USHORT); static void clear_queue(rem_port*); static void clear_stmt_que(rem_port*, Rsr*); -static void disconnect(rem_port*); +static void finalize(rem_port* port); +static void disconnect(rem_port*, bool rmRef = true); static void enqueue_receive(rem_port*, t_rmtque_fn, Rdb*, void*, Rrq::rrq_repeat*); static void dequeue_receive(rem_port*); static THREAD_ENTRY_DECLARE event_thread(THREAD_ENTRY_PARAM); static Rvnt* find_event(rem_port*, SLONG); -static bool get_new_dpb(ClumpletWriter&, const ParametersSet&); +static bool get_new_dpb(ClumpletWriter&, const ParametersSet&, bool); static void info(CheckStatusWrapper*, Rdb*, P_OP, USHORT, USHORT, USHORT, const UCHAR*, USHORT, const UCHAR*, ULONG, UCHAR*); -static void init(CheckStatusWrapper*, ClntAuthBlock&, rem_port*, P_OP, PathName&, +static bool init(CheckStatusWrapper*, ClntAuthBlock&, rem_port*, P_OP, PathName&, ClumpletWriter&, IntlParametersBlock&, ICryptKeyCallback* cryptCallback); static Rtr* make_transaction(Rdb*, USHORT); static void mov_dsql_message(const UCHAR*, const rem_fmt*, UCHAR*, const rem_fmt*); @@ -1069,6 +1161,9 @@ inline static void reset(IStatus* status) throw() inline static void defer_packet(rem_port* port, PACKET* packet, bool sent = false) { + fb_assert(port->port_flags & PORT_lazy); + fb_assert(port->port_deferred_packets); + // hvlad: passed packet often is rdb->rdb_packet and therefore can be // changed inside clear_queue. To not confuse caller we must preserve // packet content @@ -1105,16 +1200,17 @@ IAttachment* RProvider::attach(CheckStatusWrapper* status, const char* filename, ClumpletWriter newDpb(ClumpletReader::dpbList, MAX_DPB_SIZE, dpb, dpb_length); unsigned flags = ANALYZE_MOUNTS; - if (get_new_dpb(newDpb, dpbParam)) + if (get_new_dpb(newDpb, dpbParam, loopback)) flags |= ANALYZE_USER_VFY; if (loopback) flags |= ANALYZE_LOOPBACK; PathName expanded_name(filename); - PathName node_name; + resolveAlias(filename, expanded_name, nullptr); ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam); + PathName node_name; rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback); if (!port) @@ -1133,7 +1229,8 @@ IAttachment* RProvider::attach(CheckStatusWrapper* status, const char* filename, IntlDpb intl; HANDSHAKE_DEBUG(fprintf(stderr, "Cli: call init for DB='%s'\n", expanded_name.c_str())); - init(status, cBlock, port, op_attach, expanded_name, newDpb, intl, cryptCallback); + if (!init(status, cBlock, port, op_attach, expanded_name, newDpb, intl, cryptCallback)) + return NULL; Attachment* a = FB_NEW Attachment(port->port_context, filename); a->addRef(); @@ -1263,7 +1360,7 @@ void Blob::freeClientData(CheckStatusWrapper* status, bool force) } -void Blob::cancel(CheckStatusWrapper* status) +void Blob::internalCancel(CheckStatusWrapper* status) { /************************************** * @@ -1280,7 +1377,21 @@ void Blob::cancel(CheckStatusWrapper* status) } -void Blob::close(CheckStatusWrapper* status) +void Blob::cancel(CheckStatusWrapper* status) +{ + internalCancel(status); + if (status->isEmpty()) + release(); +} + + +void Blob::deprecatedCancel(CheckStatusWrapper* status) +{ + internalCancel(status); +} + + +void Blob::internalClose(CheckStatusWrapper* status) { /************************************** * @@ -1319,6 +1430,20 @@ void Blob::close(CheckStatusWrapper* status) } +void Blob::close(CheckStatusWrapper* status) +{ + internalClose(status); + if (status->isEmpty()) + release(); +} + + +void Blob::deprecatedClose(CheckStatusWrapper* status) +{ + internalClose(status); +} + + void Events::freeClientData(CheckStatusWrapper* status, bool force) { /************************************** @@ -1401,7 +1526,7 @@ void Events::freeClientData(CheckStatusWrapper* status, bool force) } -void Events::cancel(CheckStatusWrapper* status) +void Events::internalCancel(CheckStatusWrapper* status) { /************************************** * @@ -1418,7 +1543,21 @@ void Events::cancel(CheckStatusWrapper* status) } -void Transaction::commit(CheckStatusWrapper* status) +void Events::cancel(CheckStatusWrapper* status) +{ + internalCancel(status); + if (status->isEmpty()) + release(); +} + + +void Events::deprecatedCancel(CheckStatusWrapper* status) +{ + internalCancel(status); +} + + +void Transaction::internalCommit(CheckStatusWrapper* status) { /************************************** * @@ -1453,6 +1592,20 @@ void Transaction::commit(CheckStatusWrapper* status) } +void Transaction::commit(CheckStatusWrapper* status) +{ + internalCommit(status); + if (status->isEmpty()) + release(); +} + + +void Transaction::deprecatedCommit(CheckStatusWrapper* status) +{ + internalCommit(status); +} + + void Transaction::commitRetaining(CheckStatusWrapper* status) { /************************************** @@ -1727,16 +1880,17 @@ Firebird::IAttachment* RProvider::create(CheckStatusWrapper* status, const char* reinterpret_cast(dpb), dpb_length); unsigned flags = ANALYZE_MOUNTS; - if (get_new_dpb(newDpb, dpbParam)) + if (get_new_dpb(newDpb, dpbParam, loopback)) flags |= ANALYZE_USER_VFY; if (loopback) flags |= ANALYZE_LOOPBACK; PathName expanded_name(filename); - PathName node_name; + resolveAlias(filename, expanded_name, nullptr); ClntAuthBlock cBlock(&expanded_name, &newDpb, &dpbParam); + PathName node_name; rem_port* port = analyze(cBlock, expanded_name, flags, newDpb, dpbParam, node_name, NULL, cryptCallback); if (!port) @@ -1756,7 +1910,8 @@ Firebird::IAttachment* RProvider::create(CheckStatusWrapper* status, const char* add_working_directory(newDpb, node_name); IntlDpb intl; - init(status, cBlock, port, op_create, expanded_name, newDpb, intl, cryptCallback); + if (!init(status, cBlock, port, op_create, expanded_name, newDpb, intl, cryptCallback)) + return NULL; Firebird::IAttachment* a = FB_NEW Attachment(rdb, filename); a->addRef(); @@ -1827,7 +1982,11 @@ void Attachment::getInfo(CheckStatusWrapper* status, HalfStaticArray temp; CHECK_HANDLE(rdb, isc_bad_db_handle); + rem_port* port = rdb->rdb_port; + USHORT protocol = memchr(items, fb_info_protocol_version, item_length) ? port->port_protocol : 0; + protocol &= FB_PROTOCOL_MASK; + RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); UCHAR* temp_buffer = temp.getBuffer(buffer_length); @@ -1841,7 +2000,8 @@ void Attachment::getInfo(CheckStatusWrapper* status, MERGE_database_info(temp_buffer, buffer, buffer_length, DbImplementation::current.backwardCompatibleImplementation(), 3, 1, reinterpret_cast(version.c_str()), - reinterpret_cast(port->port_host->str_data)); + reinterpret_cast(port->port_host->str_data), + protocol); } catch (const Exception& ex) { @@ -1916,7 +2076,7 @@ void Attachment::freeClientData(CheckStatusWrapper* status, bool force) try { - if (!(port->port_flags & PORT_rdb_shutdown)) + if (!(port->port_flags & (PORT_rdb_shutdown | PORT_detached))) { release_object(status, rdb, op_detach, rdb->rdb_id); } @@ -1972,7 +2132,7 @@ void Attachment::freeClientData(CheckStatusWrapper* status, bool force) } -void Attachment::detach(CheckStatusWrapper* status) +void Attachment::internalDetach(CheckStatusWrapper* status) { /************************************** * @@ -1989,7 +2149,21 @@ void Attachment::detach(CheckStatusWrapper* status) } -void Attachment::dropDatabase(CheckStatusWrapper* status) +void Attachment::detach(CheckStatusWrapper* status) +{ + internalDetach(status); + if (status->isEmpty()) + release(); +} + + +void Attachment::deprecatedDetach(CheckStatusWrapper* status) +{ + internalDetach(status); +} + + +void Attachment::internalDropDatabase(CheckStatusWrapper* status) { /************************************** * @@ -2047,6 +2221,20 @@ void Attachment::dropDatabase(CheckStatusWrapper* status) } +void Attachment::dropDatabase(CheckStatusWrapper* status) +{ + internalDropDatabase(status); + if (status->isEmpty()) + release(); +} + + +void Attachment::deprecatedDropDatabase(CheckStatusWrapper* status) +{ + internalDropDatabase(status); +} + + SLONG Attachment::getSingleInfo(CheckStatusWrapper* status, UCHAR infoItem) { UCHAR buff[16]; @@ -2265,8 +2453,15 @@ Batch* Statement::createBatch(CheckStatusWrapper* status, IMessageMetadata* inMe batch->p_batch_pb.cstr_length = parLength; batch->p_batch_pb.cstr_address = par; - send_partial_packet(port, packet); - defer_packet(port, packet, true); + if (port->port_flags & PORT_lazy) + { + send_partial_packet(port, packet); + defer_packet(port, packet, true); + } + else { + send_and_receive(status, rdb, packet); + } + message->msg_address = NULL; Batch* b = FB_NEW Batch(this, inMetadata, parLength, par); @@ -2286,7 +2481,9 @@ Batch::Batch(Statement* s, IMessageMetadata* inFmt, unsigned parLength, const un : messageStream(0), blobStream(nullptr), sizePointer(nullptr), messageSize(0), alignedSize(0), blobBufferSize(0), messageBufferSize(0), flags(0), stmt(s), format(inFmt), blobAlign(0), blobPolicy(BLOB_NONE), - segmented(false), defSegmented(false), batchActive(false), tmpStatement(false) + segmented(false), defSegmented(false), batchActive(false), + messageCount(0), blobCount(0), serverSize(0), blobHeadSize(0), + tmpStatement(false) { LocalStatus ls; CheckStatusWrapper st(&ls); @@ -2385,7 +2582,7 @@ void Batch::add(CheckStatusWrapper* status, unsigned count, const void* inBuffer } -void Batch::sendMessagePacket(unsigned count, const UCHAR* ptr) +void Batch::sendMessagePacket(unsigned count, const UCHAR* ptr, bool flash) { Rsr* statement = stmt->getStatement(); CHECK_HANDLE(statement, isc_bad_req_handle); @@ -2401,8 +2598,8 @@ void Batch::sendMessagePacket(unsigned count, const UCHAR* ptr) batch->p_batch_data.cstr_address = const_cast(ptr); statement->rsr_batch_size = alignedSize; - send_partial_packet(port, packet); - defer_packet(port, packet, true); + sendDeferredPacket(nullptr, port, packet, flash); + messageCount += count; } @@ -2529,13 +2726,13 @@ void Batch::addBlobStream(CheckStatusWrapper* status, unsigned length, const voi } -void Batch::sendBlobPacket(unsigned size, const UCHAR* ptr) +void Batch::sendBlobPacket(unsigned size, const UCHAR* ptr, bool flash) { Rsr* statement = stmt->getStatement(); Rdb* rdb = statement->rsr_rdb; rem_port* port = rdb->rdb_port; - setBlobAlignment(); + setServerInfo(); fb_assert(!(size % blobAlign)); PACKET* packet = &rdb->rdb_packet; @@ -2545,8 +2742,45 @@ void Batch::sendBlobPacket(unsigned size, const UCHAR* ptr) batch->p_batch_blob_data.cstr_address = const_cast(ptr); batch->p_batch_blob_data.cstr_length = size; - send_partial_packet(port, packet); - defer_packet(port, packet, true); + sendDeferredPacket(nullptr, port, packet, flash); + + blobCount += size; +} + + +void Batch::sendDeferredPacket(IStatus* status, rem_port* port, PACKET* packet, bool flash) +{ + if (port->port_flags & PORT_lazy) + { + send_partial_packet(port, packet); + defer_packet(port, packet, true); + + if ((port->port_protocol >= PROTOCOL_VERSION17) && + ((port->port_deferred_packets->getCount() >= DEFER_BATCH_LIMIT) || flash)) + { + packet->p_operation = op_batch_sync; + send_packet(port, packet); + receive_packet(port, packet); + + LocalStatus warning; + port->checkResponse(&warning, packet, false); + Rsr* statement = stmt->getStatement(); + if (statement->haveException()) + { + cleanup(); + statement->raiseException(); + } + } + } + else if (status) + { + send_and_receive(status, port->port_context, packet); + } + else + { + LocalStatus local; + send_and_receive(&local, port->port_context, packet); + } } @@ -2580,8 +2814,7 @@ void Batch::setDefaultBpb(CheckStatusWrapper* status, unsigned parLength, const batch->p_batch_blob_bpb.cstr_address = par; batch->p_batch_blob_bpb.cstr_length = parLength; - send_partial_packet(port, packet); - defer_packet(port, packet, true); + sendDeferredPacket(status, port, packet, true); } catch (const Exception& ex) { @@ -2594,7 +2827,7 @@ unsigned Batch::getBlobAlignment(CheckStatusWrapper* status) { try { - setBlobAlignment(); + setServerInfo(); } catch (const Exception& ex) { @@ -2605,7 +2838,7 @@ unsigned Batch::getBlobAlignment(CheckStatusWrapper* status) } -void Batch::setBlobAlignment() +void Batch::setServerInfo() { if (blobAlign) return; @@ -2623,21 +2856,71 @@ void Batch::setBlobAlignment() rem_port* port = rdb->rdb_port; RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); - // Perform info call to server LocalStatus ls; CheckStatusWrapper s(&ls); - UCHAR item = isc_info_sql_stmt_blob_align; - UCHAR buffer[16]; - info(&s, rdb, op_info_sql, statement->rsr_id, 0, - 1, &item, 0, 0, sizeof(buffer), buffer); + + if (port->port_protocol < PROTOCOL_VERSION17) + { + UCHAR item = isc_info_sql_stmt_blob_align; + UCHAR buffer[16]; + info(&s, rdb, op_info_sql, statement->rsr_id, 0, + 1, &item, 0, 0, sizeof(buffer), buffer); + check(&s); + + // Extract from buffer + if (buffer[0] != item) + Arg::Gds(isc_batch_align).raise(); + + int len = gds__vax_integer(&buffer[1], 2); + statement->rsr_batch_stream.alignment = blobAlign = gds__vax_integer(&buffer[3], len); + + if (!blobAlign) + Arg::Gds(isc_batch_align).raise(); + + return; + } + + // Perform info call to server + UCHAR items[] = {IBatch::INF_BLOB_ALIGNMENT, IBatch::INF_BUFFER_BYTES_SIZE, IBatch::INF_BLOB_HEADER}; + UCHAR buffer[64]; + info(&s, rdb, op_info_batch, statement->rsr_id, 0, + sizeof(items), items, 0, 0, sizeof(buffer), buffer); check(&s); // Extract from buffer - if (buffer[0] != item) - Arg::Gds(isc_batch_align).raise(); + ClumpletReader out(ClumpletReader::InfoResponse, buffer, sizeof(buffer)); + for (out.rewind(); !out.isEof(); out.moveNext()) + { + UCHAR item = out.getClumpTag(); + if (item == isc_info_end) + break; + + switch(item) + { + case IBatch::INF_BLOB_ALIGNMENT: + statement->rsr_batch_stream.alignment = blobAlign = out.getInt(); + break; + case IBatch::INF_BUFFER_BYTES_SIZE: + serverSize = out.getInt(); + break; + case IBatch::INF_BLOB_HEADER: + blobHeadSize = out.getInt(); + break; + case isc_info_error: + (Arg::Gds(isc_batch_align) << Arg::Gds(out.getInt())).raise(); + case isc_info_truncated: + (Arg::Gds(isc_batch_align) << Arg::Gds(isc_random) << "truncated").raise(); + default: + { + string msg; + msg.printf("Wrong info item %u", item); + (Arg::Gds(isc_batch_align) << Arg::Gds(isc_random) << msg).raise(); + } + } + } - int len = gds__vax_integer(&buffer[1], 2); - statement->rsr_batch_stream.alignment = blobAlign = gds__vax_integer(&buffer[3], len); + if (! (blobAlign && serverSize && blobHeadSize)) + Arg::Gds(isc_batch_align).raise(); } @@ -2678,8 +2961,7 @@ void Batch::registerBlob(CheckStatusWrapper* status, const ISC_QUAD* existingBlo batch->p_batch_exist_id = *existingBlob; batch->p_batch_blob_id = *blobId; - send_partial_packet(port, packet); - defer_packet(port, packet, true); + sendDeferredPacket(status, port, packet, true); } catch (const Exception& ex) { @@ -2735,7 +3017,12 @@ IBatchCompletionState* Batch::execute(CheckStatusWrapper* status, ITransaction* statement->rsr_batch_cs = nullptr; if (packet->p_operation == op_batch_cs) + { + // when working with 4.0.0 server we could not raise it in advance... + statement->clearException(); + return cs.release(); + } REMOTE_check_response(status, rdb, packet); } @@ -2765,10 +3052,7 @@ void Batch::cancel(CheckStatusWrapper* status) RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); // Cleanup local data - if (blobPolicy != BLOB_NONE) - blobStream = blobStreamBuffer; - sizePointer = nullptr; - messageStream = 0; + cleanup(); batchActive = false; // Prepare packet @@ -2839,13 +3123,98 @@ void Batch::freeClientData(CheckStatusWrapper* status, bool force) } -void Batch::close(CheckStatusWrapper* status) +void Batch::internalClose(CheckStatusWrapper* status) { reset(status); freeClientData(status); } +void Batch::close(CheckStatusWrapper* status) +{ + internalClose(status); + if (status->isEmpty()) + release(); +} + + +void Batch::deprecatedClose(CheckStatusWrapper* status) +{ + internalClose(status); +} + + +void Batch::getInfo(CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) +{ + try + { + ClumpletReader it(ClumpletReader::InfoItems, items, itemsLength); + ClumpletWriter out(ClumpletReader::InfoResponse, bufferLength - 1); // place for isc_info_end / isc_info_truncated + + for (it.rewind(); !it.isEof(); it.moveNext()) + { + UCHAR item = it.getClumpTag(); + if (item == isc_info_end) + break; + + try + { + switch(item) + { + case IBatch::INF_BUFFER_BYTES_SIZE: + setServerInfo(); + if (serverSize) + out.insertInt(item, serverSize); + break; + case IBatch::INF_DATA_BYTES_SIZE: + out.insertInt(item, (messageCount + messageStream) * alignedSize); + break; + case IBatch::INF_BLOBS_BYTES_SIZE: + if (blobStream) + out.insertInt(item, blobCount + (blobStream - blobStreamBuffer)); + break; + case IBatch::INF_BLOB_ALIGNMENT: + setServerInfo(); + out.insertInt(item, blobAlign); + break; + case IBatch::INF_BLOB_HEADER: + setServerInfo(); + out.insertInt(item, blobHeadSize); + break; + default: + out.insertInt(isc_info_error, isc_infunk); + break; + } + } + catch(const fatal_exception&) + { + // here it's sooner of all caused by writer overflow but anyway check that + if (out.hasOverflow()) + { + memcpy(buffer, out.getBuffer(), out.getBufferLength()); + buffer += out.getBufferLength(); + *buffer++ = isc_info_truncated; + if (out.getBufferLength() <= bufferLength - 2) + *buffer++ = isc_info_end; + return; + } + else + throw; + } + } + + memcpy(buffer, out.getBuffer(), out.getBufferLength()); + buffer += out.getBufferLength(); + *buffer++ = isc_info_end; + } + catch (const Exception& ex) + { + ex.stuffException(status); + } +} + + void Batch::releaseStatement() { if (tmpStatement) @@ -2930,13 +3299,27 @@ void Replicator::process(CheckStatusWrapper* status, unsigned length, const unsi } -void Replicator::close(CheckStatusWrapper* status) +void Replicator::internalClose(CheckStatusWrapper* status) { reset(status); freeClientData(status); } +void Replicator::close(CheckStatusWrapper* status) +{ + internalClose(status); + if (status->isEmpty()) + release(); +} + + +void Replicator::deprecatedClose(CheckStatusWrapper* status) +{ + internalClose(status); +} + + void Replicator::freeClientData(CheckStatusWrapper* status, bool force) { try @@ -3274,9 +3657,21 @@ ResultSet* Statement::openCursor(CheckStatusWrapper* status, Firebird::ITransact sqldata->p_sqldata_out_message_number = 0; // out_msg_type sqldata->p_sqldata_timeout = statement->rsr_timeout; - send_partial_packet(port, packet); - defer_packet(port, packet, true); - message->msg_address = NULL; + { + Firebird::Cleanup msgClean([&message] { + message->msg_address = NULL; + }); + + if (statement->rsr_flags.test(Rsr::DEFER_EXECUTE)) + { + send_partial_packet(port, packet); + defer_packet(port, packet, true); + } + else + { + send_and_receive(status, rdb, packet); + } + } ResultSet* rs = FB_NEW ResultSet(this, outFormat); rs->addRef(); @@ -3587,7 +3982,7 @@ void Statement::freeClientData(CheckStatusWrapper* status, bool force) } -void Statement::free(CheckStatusWrapper* status) +void Statement::internalFree(CheckStatusWrapper* status) { /************************************** * @@ -3605,6 +4000,20 @@ void Statement::free(CheckStatusWrapper* status) } +void Statement::free(CheckStatusWrapper* status) +{ + internalFree(status); + if (status->isEmpty()) + release(); +} + + +void Statement::deprecatedFree(CheckStatusWrapper* status) +{ + internalFree(status); +} + + Statement* Attachment::createStatement(CheckStatusWrapper* status, unsigned dialect) { reset(status); @@ -3751,7 +4160,7 @@ Statement* Attachment::prepare(CheckStatusWrapper* status, ITransaction* apiTra, } P_RESP* response = &packet->p_resp; - SaveString temp(response->p_resp_data, buffer.getCount(), buffer.begin()); + UsePreallocatedBuffer temp(response->p_resp_data, buffer.getCount(), buffer.begin()); try { @@ -4592,7 +5001,7 @@ void ResultSet::freeClientData(CheckStatusWrapper* status, bool force) } -void ResultSet::close(CheckStatusWrapper* status) +void ResultSet::internalClose(CheckStatusWrapper* status) { /************************************** * @@ -4610,6 +5019,20 @@ void ResultSet::close(CheckStatusWrapper* status) } +void ResultSet::close(CheckStatusWrapper* status) +{ + internalClose(status); + if (status->isEmpty()) + release(); +} + + +void ResultSet::deprecatedClose(CheckStatusWrapper* status) +{ + internalClose(status); +} + + void ResultSet::releaseStatement() { if (tmpStatement) @@ -4655,7 +5078,7 @@ int Blob::getSegment(CheckStatusWrapper* status, unsigned int bufferLength, void PACKET* packet = &rdb->rdb_packet; P_SGMT* segment = &packet->p_sgmt; P_RESP* response = &packet->p_resp; - SaveString temp(response->p_resp_data, bufferLength, bufferPtr); + UsePreallocatedBuffer temp(response->p_resp_data, bufferLength, bufferPtr); // Handle a blob that has been created rather than opened (this should yield an error) @@ -5493,7 +5916,7 @@ void Request::freeClientData(CheckStatusWrapper* status, bool force) } -void Request::free(CheckStatusWrapper* status) +void Request::internalFree(CheckStatusWrapper* status) { /************************************** * @@ -5510,6 +5933,20 @@ void Request::free(CheckStatusWrapper* status) } +void Request::free(CheckStatusWrapper* status) +{ + internalFree(status); + if (status->isEmpty()) + release(); +} + + +void Request::deprecatedFree(CheckStatusWrapper* status) +{ + internalFree(status); +} + + void Request::getInfo(CheckStatusWrapper* status, int level, unsigned int itemsLength, const unsigned char* items, unsigned int bufferLength, unsigned char* buffer) @@ -5677,7 +6114,7 @@ void Transaction::freeClientData(CheckStatusWrapper* status, bool force) } -void Transaction::rollback(CheckStatusWrapper* status) +void Transaction::internalRollback(CheckStatusWrapper* status) { /************************************** * @@ -5694,7 +6131,21 @@ void Transaction::rollback(CheckStatusWrapper* status) } -void Transaction::disconnect(CheckStatusWrapper* status) +void Transaction::rollback(CheckStatusWrapper* status) +{ + internalRollback(status); + if (status->isEmpty()) + release(); +} + + +void Transaction::deprecatedRollback(CheckStatusWrapper* status) +{ + internalRollback(status); +} + + +void Transaction::internalDisconnect(CheckStatusWrapper* status) { try { @@ -5714,6 +6165,20 @@ void Transaction::disconnect(CheckStatusWrapper* status) } +void Transaction::disconnect(CheckStatusWrapper* status) +{ + internalDisconnect(status); + if (status->isEmpty()) + release(); +} + + +void Transaction::deprecatedDisconnect(CheckStatusWrapper* status) +{ + internalDisconnect(status); +} + + int Blob::seek(CheckStatusWrapper* status, int mode, int offset) { /************************************** @@ -5845,7 +6310,7 @@ Firebird::IService* RProvider::attachSvc(CheckStatusWrapper* status, const char* PathName node_name, expanded_name(service); ClumpletWriter newSpb(ClumpletReader::spbList, MAX_DPB_SIZE, spb, spbLength); - const bool user_verification = get_new_dpb(newSpb, spbParam); + const bool user_verification = get_new_dpb(newSpb, spbParam, loopback); ClntAuthBlock cBlock(NULL, &newSpb, &spbParam); unsigned flags = 0; @@ -5874,7 +6339,8 @@ Firebird::IService* RProvider::attachSvc(CheckStatusWrapper* status, const char* add_other_params(port, newSpb, spbParam); IntlSpb intl; - init(status, cBlock, port, op_service_attach, expanded_name, newSpb, intl, cryptCallback); + if (!init(status, cBlock, port, op_service_attach, expanded_name, newSpb, intl, cryptCallback)) + return NULL; Firebird::IService* s = FB_NEW Service(rdb); s->addRef(); @@ -5946,14 +6412,17 @@ void Service::freeClientData(CheckStatusWrapper* status, bool force) rem_port* port = rdb->rdb_port; RemotePortGuard portGuard(port, FB_FUNCTION); - try + if (!(port->port_flags & PORT_detached)) { - release_object(status, rdb, op_service_detach, rdb->rdb_id); - } - catch (const Exception&) - { - if (!force) - throw; + try + { + release_object(status, rdb, op_service_detach, rdb->rdb_id); + } + catch (const Exception&) + { + if (!force) + throw; + } } disconnect(port); rdb = NULL; @@ -5965,7 +6434,7 @@ void Service::freeClientData(CheckStatusWrapper* status, bool force) } -void Service::detach(CheckStatusWrapper* status) +void Service::internalDetach(CheckStatusWrapper* status) { /************************************** * @@ -5982,6 +6451,20 @@ void Service::detach(CheckStatusWrapper* status) } +void Service::detach(CheckStatusWrapper* status) +{ + internalDetach(status); + if (status->isEmpty()) + release(); +} + + +void Service::deprecatedDetach(CheckStatusWrapper* status) +{ + internalDetach(status); +} + + void Service::query(CheckStatusWrapper* status, unsigned int sendLength, const unsigned char* sendItems, unsigned int receiveLength, const unsigned char* receiveItems, @@ -6018,6 +6501,28 @@ void Service::query(CheckStatusWrapper* status, } +void Service::cancel(CheckStatusWrapper* status) +{ + try + { + reset(status); + + // Check and validate handles, etc. + CHECK_HANDLE(rdb, isc_bad_svc_handle); +/* + rem_port* port = rdb->rdb_port; + RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION); +*/ + + Arg::Gds(isc_wish_list).raise(); + } + catch (const Exception& ex) + { + ex.stuffException(status); + } +} + + void Service::start(CheckStatusWrapper* status, unsigned int spbLength, const unsigned char* spb) { @@ -6657,117 +7162,184 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned * **************************************/ - rem_port* port = NULL; - int inet_af = AF_UNSPEC; - cBlock.loadClnt(pb, &parSet); - authenticateStep0(cBlock); + pb.deleteWithTag(parSet.auth_block); bool needFile = !(flags & ANALYZE_EMP_NAME); + const PathName save_attach_name(attach_name); -#ifdef WIN_NT - if (ISC_analyze_protocol(PROTOCOL_XNET, attach_name, node_name, NULL, needFile)) - port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, cBlock.getConfig(), ref_db_name); - else if (ISC_analyze_protocol(PROTOCOL_WNET, attach_name, node_name, WNET_SEPARATOR, needFile) || - ISC_analyze_pclan(attach_name, node_name)) - { - if (node_name.isEmpty()) - node_name = WNET_LOCALHOST; - else - { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); - } - - port = WNET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, - cBlock.getConfig(), ref_db_name); - } - else +#ifdef TRUSTED_AUTH + bool legacySSP = false; + Auth::setLegacySSP(legacySSP); #endif - if (ISC_analyze_protocol(PROTOCOL_INET4, attach_name, node_name, INET_SEPARATOR, needFile)) - inet_af = AF_INET; - else if (ISC_analyze_protocol(PROTOCOL_INET6, attach_name, node_name, INET_SEPARATOR, needFile)) - inet_af = AF_INET6; - - if (inet_af != AF_UNSPEC || - ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR, needFile) || - ISC_analyze_tcp(attach_name, node_name, needFile)) + rem_port* port; + while (true) { - if (node_name.isEmpty()) - node_name = INET_LOCALHOST; - else - { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); - } + port = NULL; + int inet_af = AF_UNSPEC; - port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb, inet_af); - } + authenticateStep0(cBlock); + const NoCaseString savePluginName(cBlock.plugins.name()); - // We have a local connection string. If it's a file on a network share, - // try to connect to the corresponding host remotely. - if (flags & ANALYZE_MOUNTS) - { -#ifdef WIN_NT - if (!port) + try { - PathName expanded_name = attach_name; - ISC_expand_share(expanded_name); - - if (ISC_analyze_pclan(expanded_name, node_name)) +#ifdef WIN_NT + if (ISC_analyze_protocol(PROTOCOL_XNET, attach_name, node_name, NULL, needFile)) + port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, cBlock.getConfig(), ref_db_name); + else if (ISC_analyze_protocol(PROTOCOL_WNET, attach_name, node_name, WNET_SEPARATOR, needFile) || + ISC_analyze_pclan(attach_name, node_name)) { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); + if (node_name.isEmpty()) + node_name = WNET_LOCALHOST; + else + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); + } - port = WNET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, + port = WNET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, cBlock.getConfig(), ref_db_name); } - } + else #endif -#ifndef NO_NFS - if (!port) - { - PathName expanded_name = attach_name; - if (ISC_analyze_nfs(expanded_name, node_name)) + if (ISC_analyze_protocol(PROTOCOL_INET4, attach_name, node_name, INET_SEPARATOR, needFile)) + inet_af = AF_INET; + else if (ISC_analyze_protocol(PROTOCOL_INET6, attach_name, node_name, INET_SEPARATOR, needFile)) + inet_af = AF_INET6; + + if (inet_af != AF_UNSPEC || + ISC_analyze_protocol(PROTOCOL_INET, attach_name, node_name, INET_SEPARATOR, needFile) || + ISC_analyze_tcp(attach_name, node_name, needFile)) { - ISC_unescape(node_name); - ISC_utf8ToSystem(node_name); + if (node_name.isEmpty()) + node_name = INET_LOCALHOST; + else + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); + } - port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb); + port = INET_analyze(&cBlock, attach_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb, inet_af); } - } + + // We have a local connection string. If it's a file on a network share, + // try to connect to the corresponding host remotely. + if (flags & ANALYZE_MOUNTS) + { +#ifdef WIN_NT + if (!port) + { + PathName expanded_name = attach_name; + ISC_expand_share(expanded_name); + + if (ISC_analyze_pclan(expanded_name, node_name)) + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); + + port = WNET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, + cBlock.getConfig(), ref_db_name); + } + } #endif - } - if ((flags & ANALYZE_LOOPBACK) && !port) - { - // We have a local connection string. - // If we are in loopback mode attempt connect to a localhost. +#ifndef NO_NFS + if (!port) + { + PathName expanded_name = attach_name; + if (ISC_analyze_nfs(expanded_name, node_name)) + { + ISC_unescape(node_name); + ISC_utf8ToSystem(node_name); - if (node_name.isEmpty()) - { -#ifdef WIN_NT - if (!port) - { - port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, - cBlock.getConfig(), ref_db_name); + port = INET_analyze(&cBlock, expanded_name, node_name.c_str(), flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb); + } + } +#endif } - if (!port) + if ((flags & ANALYZE_LOOPBACK) && !port) { - port = WNET_analyze(&cBlock, attach_name, WNET_LOCALHOST, flags & ANALYZE_USER_VFY, - cBlock.getConfig(), ref_db_name); - } + // We have a local connection string. + // If we are in loopback mode attempt connect to a localhost. + + if (node_name.isEmpty()) + { +#ifdef WIN_NT + if (!port) + { + port = XNET_analyze(&cBlock, attach_name, flags & ANALYZE_USER_VFY, + cBlock.getConfig(), ref_db_name); + } + + if (!port) + { + port = WNET_analyze(&cBlock, attach_name, WNET_LOCALHOST, flags & ANALYZE_USER_VFY, + cBlock.getConfig(), ref_db_name); + } #endif - if (!port) + if (!port) + { + port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_USER_VFY, pb, + cBlock.getConfig(), ref_db_name, cryptCb); + } + } + } + +#ifdef TRUSTED_AUTH + if (port && !legacySSP) { - port = INET_analyze(&cBlock, attach_name, INET_LOCALHOST, flags & ANALYZE_USER_VFY, pb, - cBlock.getConfig(), ref_db_name, cryptCb); + const PACKET& const packet = port->port_context->rdb_packet; + if (port->port_protocol < PROTOCOL_VERSION13 && packet.p_operation == op_accept) + { + // old server supports legacy SSP only + legacySSP = true; + } + else if (port->port_protocol >= PROTOCOL_VERSION13 && packet.p_operation == op_accept_data) + { + // more recent server reports if it supports non-legacy SSP + legacySSP = !(packet.p_acpd.p_acpt_type & pflag_win_sspi_nego); + } + else + break; + + Auth::setLegacySSP(legacySSP); + + if (legacySSP && savePluginName == "WIN_SSPI") + { + // reinitialize Win_SSPI plugin and send new data + attach_name = save_attach_name; + + cBlock.plugins.set(savePluginName.c_str()); + + disconnect(port, false); + continue; + } } +#endif + + break; + } + catch (const Exception&) + { +#ifdef TRUSTED_AUTH + const char* const pluginName = cBlock.plugins.name(); + if (legacySSP || !pluginName || fb_utils::stricmp(pluginName, "WIN_SSPI") != 0) + throw; + + // Retry connect with failed plugin only and using legacy security package + legacySSP = true; + Auth::setLegacySSP(legacySSP); + attach_name = save_attach_name; + + cBlock.plugins.set(pluginName); +#else + throw; +#endif } } @@ -6780,10 +7352,11 @@ static rem_port* analyze(ClntAuthBlock& cBlock, PathName& attach_name, unsigned } catch (const Exception&) { - disconnect(port); + disconnect(port, false); throw; } + outPorts->registerPort(port); return port; } @@ -6873,6 +7446,9 @@ static void batch_dsql_fetch(rem_port* port, // we need to clear the queue const bool clear_queue = (id != statement->rsr_id || port->port_type == rem_port::XNET); + // Avoid damaging preallocated buffer for response data + UseStandardBuffer guard(packet->p_resp.p_resp_data); + statement->rsr_flags.set(Rsr::FETCHED); while (true) { @@ -7018,6 +7594,9 @@ static void batch_gds_receive(rem_port* port, clear_queue = true; } + // Avoid damaging preallocated buffer for response data + UseStandardBuffer guard(packet->p_resp.p_resp_data); + // Receive the whole batch of records, until end-of-batch is seen while (true) @@ -7139,19 +7718,30 @@ static void clear_queue(rem_port* port) } -static void disconnect( rem_port* port) +static void finalize(rem_port* port) { /************************************** * - * d i s c o n n e c t + * f i n a l i z e * ************************************** * * Functional description - * Disconnect a port and free its memory. + * Disconnect remote port. * **************************************/ + // no need to do something if port already detached + if (port->port_flags & PORT_detached) + return; + + // Avoid async send during finalize + RefMutexGuard guard(*port->port_write_sync, FB_FUNCTION); + + // recheck with mutex taken + if (port->port_flags & PORT_detached) + return; + // Send a disconnect to the server so that it // gracefully terminates. @@ -7192,6 +7782,29 @@ static void disconnect( rem_port* port) // Cleanup the queue delete port->port_deferred_packets; + port->port_deferred_packets = nullptr; + port->port_flags &= ~PORT_lazy; + + port->port_flags |= PORT_detached; +} + +static void disconnect(rem_port* port, bool rmRef) +{ +/************************************** + * + * d i s c o n n e c t + * + ************************************** + * + * Functional description + * Disconnect a port and free its memory. + * + **************************************/ + + finalize(port); + + Rdb* rdb = port->port_context; + port->port_context = nullptr; // Clear context reference for the associated event handler // to avoid SEGV during shutdown @@ -7208,6 +7821,11 @@ static void disconnect( rem_port* port) port->port_flags |= PORT_disconnect; port->disconnect(); delete rdb; + + // Remove from active ports + + if (rmRef) + outPorts->unRegisterPort(port); } @@ -7329,7 +7947,7 @@ static Rvnt* find_event( rem_port* port, SLONG id) } -static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par) +static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par, bool loopback) { /************************************** * @@ -7343,7 +7961,7 @@ static bool get_new_dpb(ClumpletWriter& dpb, const ParametersSet& par) * **************************************/ bool redirection = Config::getRedirection(); - if (((!redirection) && dpb.find(par.address_path)) || dpb.find(par.map_attach)) + if (((loopback || !redirection) && dpb.find(par.address_path)) || dpb.find(par.map_attach)) { status_exception::raise(Arg::Gds(isc_unavailable)); } @@ -7396,7 +8014,7 @@ static void info(CheckStatusWrapper* status, // Set up for the response packet. P_RESP* response = &packet->p_resp; - SaveString temp(response->p_resp_data, buffer_length, buffer); + UsePreallocatedBuffer temp(response->p_resp_data, buffer_length, buffer); receive_response(status, rdb, packet); } @@ -7608,7 +8226,7 @@ static void authReceiveResponse(bool havePacket, ClntAuthBlock& cBlock, rem_port (Arg::Gds(isc_login) << Arg::StatusVector(&s)).raise(); } -static void init(CheckStatusWrapper* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op, PathName& file_name, +static bool init(CheckStatusWrapper* status, ClntAuthBlock& cBlock, rem_port* port, P_OP op, PathName& file_name, ClumpletWriter& dpb, IntlParametersBlock& intlParametersBlock, ICryptKeyCallback* cryptCallback) { /************************************** @@ -7658,12 +8276,23 @@ static void init(CheckStatusWrapper* status, ClntAuthBlock& cBlock, rem_port* po send_packet(port, packet); authReceiveResponse(false, cBlock, port, rdb, status, packet, true); + return true; } - catch (const Exception&) + catch (const Exception& ex) + { + // report primary init error + ex.stuffException(status); + } + + try { disconnect(port); - throw; } + catch (const Exception&) + { + // ignore secondary error + } + return false; } @@ -7892,6 +8521,10 @@ static void receive_packet_with_callback(rem_port* port, PACKET* packet) case op_crypt_key_callback: { P_CRYPT_CALLBACK* cc = &packet->p_cc; + Cleanup ccData([&cc]() { + cc->p_cc_data.cstr_length = 0; + cc->p_cc_data.cstr_address = nullptr; + }); if (port->port_client_crypt_callback) { @@ -7951,8 +8584,6 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet) // Receive responses for all deferred packets that were already sent - Rdb* rdb = port->port_context; - if (port->port_deferred_packets) { while (port->port_deferred_packets->getCount()) @@ -7962,17 +8593,30 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet) break; OBJCT stmt_id = 0; - bool bCheckResponse = false, bFreeStmt = false; + bool bCheckResponse = false, bFreeStmt = false, bAssign = false; - if (p->packet.p_operation == op_execute) + switch (p->packet.p_operation) { + case op_execute: stmt_id = p->packet.p_sqldata.p_sqldata_statement; bCheckResponse = true; - } - else if (p->packet.p_operation == op_free_statement) - { + bAssign = true; + break; + + case op_batch_msg: + stmt_id = p->packet.p_batch_msg.p_batch_statement; + bCheckResponse = true; + break; + + case op_batch_create: + stmt_id = p->packet.p_batch_create.p_batch_statement; + bCheckResponse = true; + break; + + case op_free_statement: stmt_id = p->packet.p_sqlfree.p_sqlfree_statement; bFreeStmt = (p->packet.p_sqlfree.p_sqlfree_option == DSQL_drop); + break; } receive_packet_with_callback(port, &p->packet); @@ -7983,9 +8627,9 @@ static void receive_packet_noqueue(rem_port* port, PACKET* packet) if (bCheckResponse) { - bool bAssign = true; try { + Rdb* rdb = port->port_context; LocalStatus ls; CheckStatusWrapper status(&ls); REMOTE_check_response(&status, rdb, &p->packet); @@ -8417,6 +9061,15 @@ static void send_packet(rem_port* port, PACKET* packet) RefMutexGuard guard(*port->port_write_sync, FB_FUNCTION); + if (port->port_flags & PORT_detached || port->port_state == rem_port::BROKEN) + { + (Arg::Gds(isc_net_write_err) +#ifdef DEV_BUILD + << Arg::Gds(isc_random) << "port detached" +#endif + ).raise(); + } + // Send packets that were deferred if (port->port_deferred_packets) @@ -8467,19 +9120,31 @@ static void send_partial_packet(rem_port* port, PACKET* packet) RefMutexGuard guard(*port->port_write_sync, FB_FUNCTION); + if (port->port_flags & PORT_detached || port->port_state == rem_port::BROKEN) + { + (Arg::Gds(isc_net_write_err) +#ifdef DEV_BUILD + << Arg::Gds(isc_random) << "port detached" +#endif + ).raise(); + } + // Send packets that were deferred - for (rem_que_packet* p = port->port_deferred_packets->begin(); - p < port->port_deferred_packets->end(); p++) + if (port->port_deferred_packets) { - if (!p->sent) + for (rem_que_packet* p = port->port_deferred_packets->begin(); + p < port->port_deferred_packets->end(); p++) { - if (!port->send_partial(&p->packet)) + if (!p->sent) { - (Arg::Gds(isc_net_write_err) << - Arg::Gds(isc_random) << "send_partial_packet/send_partial").raise(); + if (!port->send_partial(&p->packet)) + { + (Arg::Gds(isc_net_write_err) << + Arg::Gds(isc_random) << "send_partial_packet/send_partial").raise(); + } + p->sent = true; } - p->sent = true; } } @@ -8559,8 +9224,7 @@ static void svcstart(CheckStatusWrapper* status, // Set up for the response packet. P_RESP* response = &packet->p_resp; - SaveString temp(response->p_resp_data, 0, NULL); - response->p_resp_data.cstr_length = 0; + UseStandardBuffer temp(response->p_resp_data); receive_response(status, rdb, packet); } @@ -8680,6 +9344,20 @@ static void cleanDpb(Firebird::ClumpletWriter& dpb, const ParametersSet* tags) } //namespace Remote +void ClientPortsCleanup::closePort(rem_port* port) +{ + RefMutexEnsureUnlock guard(*port->port_sync, FB_FUNCTION); + + if (port->port_flags & PORT_disconnect) + return; + + if (guard.tryEnter()) + Remote::finalize(port); + else + PortsCleanup::closePort(port); +} + + RmtAuthBlock::RmtAuthBlock(const Firebird::AuthReader::AuthBlock& aBlock) : buffer(*getDefaultMemoryPool(), aBlock), rdr(*getDefaultMemoryPool(), buffer), @@ -9061,3 +9739,16 @@ unsigned ClntAuthBlock::ClientCrypt::callback(unsigned dlen, const void* data, u // no luck with suggested data return 0; } + +int ClntAuthBlock::ClientCrypt::getHashLength(Firebird::CheckStatusWrapper* status) +{ + getHashData(status, nullptr); + + return -1; +} + +void ClntAuthBlock::ClientCrypt::getHashData(Firebird::CheckStatusWrapper* status, void*) +{ + ISC_STATUS err[] = {isc_arg_gds, isc_wish_list}; + status->setErrors2(FB_NELEM(err), err); +} diff --git a/src/remote/inet.cpp b/src/remote/inet.cpp index 43b6f68123b..f55f512f358 100644 --- a/src/remote/inet.cpp +++ b/src/remote/inet.cpp @@ -715,7 +715,8 @@ rem_port* INET_analyze(ClntAuthBlock* cBlock, REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_lazy_send, 4), REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_lazy_send, 5), REMOTE_PROTOCOL(PROTOCOL_VERSION15, ptype_lazy_send, 6), - REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_lazy_send, 7) + REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_lazy_send, 7), + REMOTE_PROTOCOL(PROTOCOL_VERSION17, ptype_lazy_send, 8) }; fb_assert(FB_NELEM(protocols_to_try) <= FB_NELEM(cnct->p_cnct_versions)); cnct->p_cnct_count = FB_NELEM(protocols_to_try); @@ -1074,7 +1075,7 @@ static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pa * binds the socket and calls listen(). * For multi-client server (SuperServer or SuperClassic) return listener * port. - * For classic server - accept incoming connections and fork worker + * For Classic server - accept incoming connections and fork worker * processes, return NULL at exit; * On error throw exception. * @@ -1088,27 +1089,28 @@ static rem_port* listener_socket(rem_port* port, USHORT flag, const addrinfo* pa if (n == -1) gds__log("setsockopt: error setting IPV6_V6ONLY to %d", ipv6_v6only); +#ifndef WIN_NT + // dimitr: on Windows, lack of SO_REUSEADDR works the same way as it was specified on POSIX, + // i.e. it allows binding to a port in a TIME_WAIT/FIN_WAIT state. If this option + // is turned on explicitly, then a port can be re-bound regardless of its state, + // e.g. while it's listening. This is surely not what we want. + // We set this options for any kind of listener, including standalone Classic. + + int optval = TRUE; + n = setsockopt(port->port_handle, SOL_SOCKET, SO_REUSEADDR, + (SCHAR*) &optval, sizeof(optval)); + if (n == -1) + { + inet_error(true, port, "setsockopt REUSE", isc_net_connect_listen_err, INET_ERRNO); + } +#endif + if (flag & SRVR_multi_client) { struct linger lingerInfo; lingerInfo.l_onoff = 0; lingerInfo.l_linger = 0; -#ifndef WIN_NT - // dimitr: on Windows, lack of SO_REUSEADDR works the same way as it was specified on POSIX, - // i.e. it allows binding to a port in a TIME_WAIT/FIN_WAIT state. If this option - // is turned on explicitly, then a port can be re-bound regardless of its state, - // e.g. while it's listening. This is surely not what we want. - - int optval = TRUE; - n = setsockopt(port->port_handle, SOL_SOCKET, SO_REUSEADDR, - (SCHAR*) &optval, sizeof(optval)); - if (n == -1) - { - inet_error(true, port, "setsockopt REUSE", isc_net_connect_listen_err, INET_ERRNO); - } -#endif - // Get any values for SO_LINGER so that they can be reset during // disconnect. SO_LINGER should be set by default on the socket @@ -1849,8 +1851,9 @@ static void force_close(rem_port* port) if (port->port_state != rem_port::PENDING) return; - port->port_state = rem_port::BROKEN; + RefMutexGuard guard(*port->port_write_sync, FB_FUNCTION); + port->port_state = rem_port::BROKEN; if (port->port_handle != INVALID_SOCKET) { shutdown(port->port_handle, 2); diff --git a/src/remote/merge.cpp b/src/remote/merge.cpp index c9b2093623c..9eacfef5024 100644 --- a/src/remote/merge.cpp +++ b/src/remote/merge.cpp @@ -47,7 +47,8 @@ USHORT MERGE_database_info(const UCHAR* const in, USHORT class_, USHORT base_level, const UCHAR* version, - const UCHAR* id) + const UCHAR* id, + USHORT protocol) { /************************************** * @@ -98,6 +99,23 @@ USHORT MERGE_database_info(const UCHAR* const in, switch (input.getClumpTag()) { case isc_info_end: + if (protocol) + { + --out; + if (out + (1 + 2 + 2 + 1) <= end) + { + PUT(out, (UCHAR)fb_info_protocol_version); + PUT_WORD(out, 2u); + PUT_WORD(out, protocol); + protocol = 0; + + PUT(out, (UCHAR)isc_info_end); + } + else + PUT(out, (UCHAR)isc_info_truncated); + } + // fall down... + case isc_info_truncated: return out - start; @@ -142,6 +160,10 @@ USHORT MERGE_database_info(const UCHAR* const in, PUT(out, (UCHAR) base_level); break; + case fb_info_protocol_version: + --out; + break; + default: { USHORT length = input.getClumpLength(); diff --git a/src/remote/merge_proto.h b/src/remote/merge_proto.h index 4f0e5d2a9a0..2991f6e8c44 100644 --- a/src/remote/merge_proto.h +++ b/src/remote/merge_proto.h @@ -25,7 +25,7 @@ #define REMOTE_MERGE_PROTO_H USHORT MERGE_database_info(const UCHAR*, UCHAR*, USHORT, USHORT, - USHORT, USHORT, const UCHAR*, const UCHAR*); //, ULONG); + USHORT, USHORT, const UCHAR*, const UCHAR*, USHORT); #endif // REMOTE_MERGE_PROTO_H diff --git a/src/remote/os/win32/wnet.cpp b/src/remote/os/win32/wnet.cpp index 104314abb3d..d8d08a6b992 100644 --- a/src/remote/os/win32/wnet.cpp +++ b/src/remote/os/win32/wnet.cpp @@ -173,7 +173,8 @@ rem_port* WNET_analyze(ClntAuthBlock* cBlock, REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_batch_send, 4), REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_batch_send, 5), REMOTE_PROTOCOL(PROTOCOL_VERSION15, ptype_batch_send, 6), - REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_batch_send, 7) + REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_batch_send, 7), + REMOTE_PROTOCOL(PROTOCOL_VERSION17, ptype_batch_send, 8) }; fb_assert(FB_NELEM(protocols_to_try) <= FB_NELEM(cnct->p_cnct_versions)); cnct->p_cnct_count = FB_NELEM(protocols_to_try); diff --git a/src/remote/os/win32/xnet.cpp b/src/remote/os/win32/xnet.cpp index f1862e7936d..af8d48c7d64 100644 --- a/src/remote/os/win32/xnet.cpp +++ b/src/remote/os/win32/xnet.cpp @@ -305,7 +305,8 @@ rem_port* XNET_analyze(ClntAuthBlock* cBlock, REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_batch_send, 4), REMOTE_PROTOCOL(PROTOCOL_VERSION14, ptype_batch_send, 5), REMOTE_PROTOCOL(PROTOCOL_VERSION15, ptype_batch_send, 6), - REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_batch_send, 7) + REMOTE_PROTOCOL(PROTOCOL_VERSION16, ptype_batch_send, 7), + REMOTE_PROTOCOL(PROTOCOL_VERSION17, ptype_batch_send, 8) }; fb_assert(FB_NELEM(protocols_to_try) <= FB_NELEM(cnct->p_cnct_versions)); cnct->p_cnct_count = FB_NELEM(protocols_to_try); diff --git a/src/remote/protocol.cpp b/src/remote/protocol.cpp index baacfb51c07..4b04c93c802 100644 --- a/src/remote/protocol.cpp +++ b/src/remote/protocol.cpp @@ -100,7 +100,6 @@ enum SQL_STMT_TYPE }; static bool alloc_cstring(RemoteXdr*, CSTRING*); -static void free_cstring(RemoteXdr*, CSTRING*); static void reset_statement(RemoteXdr*, SSHORT); static bool_t xdr_cstring(RemoteXdr*, CSTRING*); static bool_t xdr_response(RemoteXdr*, CSTRING*); @@ -504,6 +503,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) case op_info_transaction: case op_service_info: case op_info_sql: + case op_info_batch: info = &p->p_info; MAP(xdr_short, reinterpret_cast(info->p_info_object)); MAP(xdr_short, reinterpret_cast(info->p_info_incarnation)); @@ -882,6 +882,8 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) ULONG count = b->p_batch_messages; ULONG size = statement->rsr_batch_size; + if (!size) + statement->rsr_batch_size = size = FB_ALIGN(statement->rsr_format->fmt_length, FB_ALIGNMENT); if (xdrs->x_op == XDR_DECODE) { b->p_batch_data.cstr_length = (count ? count : 1) * size; @@ -990,10 +992,9 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) // Process status vectors ULONG pos = 0u; - LocalStatus to; DEB_RBATCH(fprintf(stderr, "BatRem: xdr sv %d\n", b->p_batch_vectors)); - for (unsigned i = 0; i < b->p_batch_vectors; ++i, ++pos) + for (unsigned i = 0; i < b->p_batch_vectors; ++pos) { DynamicStatusVector s; DynamicStatusVector* ptr = NULL; @@ -1005,6 +1006,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) if (pos == IBatchCompletionState::NO_MORE_ERRORS) return P_FALSE(xdrs, p); + LocalStatus to; statement->rsr_batch_ics->getStatus(&status_vector, &to, pos); if (status_vector.getState() & IStatus::STATE_ERRORS) continue; @@ -1021,17 +1023,19 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) if (xdrs->x_op == XDR_DECODE) { Firebird::Arg::StatusVector sv(ptr->value()); + LocalStatus to; sv.copyTo(&to); delete ptr; statement->rsr_batch_cs->regErrorAt(pos, &to); } + ++i; } // Process status-less errors pos = 0u; DEB_RBATCH(fprintf(stderr, "BatRem: xdr err %d\n", b->p_batch_errors)); - for (unsigned i = 0; i < b->p_batch_errors; ++i, ++pos) + for (unsigned i = 0; i < b->p_batch_errors; ++pos) { if (xdrs->x_op == XDR_ENCODE) { @@ -1040,6 +1044,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) if (pos == IBatchCompletionState::NO_MORE_ERRORS) return P_FALSE(xdrs, p); + LocalStatus to; statement->rsr_batch_ics->getStatus(&status_vector, &to, pos); if (!(status_vector.getState() & IStatus::STATE_ERRORS)) continue; @@ -1051,6 +1056,7 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) { statement->rsr_batch_cs->regErrorAt(pos, nullptr); } + ++i; } return P_TRUE(xdrs, p); @@ -1068,6 +1074,11 @@ bool_t xdr_protocol(RemoteXdr* xdrs, PACKET* p) return P_TRUE(xdrs, p); } + case op_batch_sync: + { + return P_TRUE(xdrs, p); + } + case op_batch_set_bpb: { P_BATCH_SETBPB* b = &p->p_batch_setbpb; @@ -1230,7 +1241,7 @@ static bool alloc_cstring(RemoteXdr* xdrs, CSTRING* cstring) if (cstring->cstr_length > cstring->cstr_allocated && cstring->cstr_allocated) { - free_cstring(xdrs, cstring); + cstring->free(xdrs); } if (!cstring->cstr_address) @@ -1251,7 +1262,7 @@ static bool alloc_cstring(RemoteXdr* xdrs, CSTRING* cstring) } -static void free_cstring( RemoteXdr* xdrs, CSTRING* cstring) +void CSTRING::free(RemoteXdr* xdrs) { /************************************** * @@ -1264,14 +1275,15 @@ static void free_cstring( RemoteXdr* xdrs, CSTRING* cstring) * **************************************/ - if (cstring->cstr_allocated) + if (cstr_allocated) { - delete[] cstring->cstr_address; - DEBUG_XDR_FREE(xdrs, cstring, cstring->cstr_address, cstring->cstr_allocated); + delete[] cstr_address; + if (xdrs) + DEBUG_XDR_FREE(xdrs, this, cstr_address, cstr_allocated); } - cstring->cstr_address = NULL; - cstring->cstr_allocated = 0; + cstr_address = NULL; + cstr_allocated = 0; } @@ -1376,7 +1388,7 @@ static bool_t xdr_cstring_with_limit( RemoteXdr* xdrs, CSTRING* cstring, ULONG l return TRUE; case XDR_FREE: - free_cstring(xdrs, cstring); + cstring->free(xdrs); return TRUE; } @@ -1485,7 +1497,7 @@ static bool_t xdr_longs( RemoteXdr* xdrs, CSTRING* cstring) break; case XDR_FREE: - free_cstring(xdrs, cstring); + cstring->free(xdrs); return TRUE; } @@ -2183,6 +2195,11 @@ static bool_t xdr_trrq_message( RemoteXdr* xdrs, USHORT msg_type) rem_port* port = xdrs->x_public; Rpr* procedure = port->port_rpr; + // normally that never happens + fb_assert(procedure); + if (!procedure) + return false; + if (msg_type == 1) return xdr_message(xdrs, procedure->rpr_out_msg, procedure->rpr_out_format); diff --git a/src/remote/protocol.h b/src/remote/protocol.h index 9f7b56f0520..e9e6db4568f 100644 --- a/src/remote/protocol.h +++ b/src/remote/protocol.h @@ -93,6 +93,11 @@ const USHORT PROTOCOL_VERSION15 = (FB_PROTOCOL_FLAG | 15); const USHORT PROTOCOL_VERSION16 = (FB_PROTOCOL_FLAG | 16); const USHORT PROTOCOL_STMT_TOUT = PROTOCOL_VERSION16; +// Protocol 17: +// - supports op_batch_sync, op_info_batch + +const USHORT PROTOCOL_VERSION17 = (FB_PROTOCOL_FLAG | 17); + // Architecture types enum P_ARCH @@ -125,7 +130,8 @@ const USHORT ptype_lazy_send = 5; // Deferred packets delivery const USHORT ptype_MASK = 0xFF; // Mask - up to 255 types of protocol // // upper byte is used for protocol flags -const USHORT pflag_compress = 0x100; // Turn on compression if possible +const USHORT pflag_compress = 0x100; // Turn on compression if possible +const USHORT pflag_win_sspi_nego = 0x200; // Win_SSPI supports Negotiate security package // Generic object id @@ -289,6 +295,8 @@ enum P_OP op_repl_req = 108, op_batch_cancel = 109, + op_batch_sync = 110, + op_info_batch = 111, op_max }; @@ -296,11 +304,15 @@ enum P_OP // Count String Structure +struct RemoteXdr; + typedef struct cstring { ULONG cstr_length; ULONG cstr_allocated; UCHAR* cstr_address; + + void free(RemoteXdr* xdrs = nullptr); } CSTRING; // CVC: Only used in p_blob, p_sgmt & p_ddl, to validate constness. diff --git a/src/remote/remote.cpp b/src/remote/remote.cpp index 4e353455fa2..a3e0d32af68 100644 --- a/src/remote/remote.cpp +++ b/src/remote/remote.cpp @@ -763,6 +763,10 @@ bool_t REMOTE_getbytes (RemoteXdr* xdrs, SCHAR* buff, unsigned bytecount) void PortsCleanup::registerPort(rem_port* port) { Firebird::MutexLockGuard guard(m_mutex, FB_FUNCTION); + + if (closing) + return; + if (!m_ports) { Firebird::MemoryPool& pool = *getDefaultMemoryPool(); @@ -776,6 +780,9 @@ void PortsCleanup::unRegisterPort(rem_port* port) { Firebird::MutexLockGuard guard(m_mutex, FB_FUNCTION); + if (closing) + return; + if (m_ports) { FB_SIZE_T i; @@ -788,14 +795,23 @@ void PortsCleanup::unRegisterPort(rem_port* port) void PortsCleanup::closePorts() { + if (m_ports) + delay(); + Firebird::MutexLockGuard guard(m_mutex, FB_FUNCTION); + Firebird::AutoSetRestore cl(&closing, true); + + { // scope + Firebird::MutexUnlockGuard g2(m_mutex, FB_FUNCTION); + Thread::yield(); + } if (m_ports) { rem_port* const* ptr = m_ports->begin(); const rem_port* const* end = m_ports->end(); for (; ptr < end; ptr++) { - (*ptr)->force_close(); + closePort(*ptr); } delete m_ports; @@ -803,6 +819,15 @@ void PortsCleanup::closePorts() } } +void PortsCleanup::closePort(rem_port* port) +{ + port->force_close(); +} + +void PortsCleanup::delay() +{ +} + ServerAuthBase::~ServerAuthBase() { } @@ -1215,12 +1240,15 @@ bool rem_port::tryKeyType(const KnownServerKey& srvKey, InternalCryptKey* cryptK for (unsigned n = 0; n < clientPlugins.getCount(); ++n) { Firebird::PathName p(clientPlugins[n]); + WIRECRYPT_DEBUG(fprintf(stderr, "tryKeyType, client plugin %s\n", p.c_str())); if (srvKey.plugins.find(" " + p + " ") != Firebird::PathName::npos) { + WIRECRYPT_DEBUG(fprintf(stderr, "tryKeyType, server listed plugin %s\n", p.c_str())); Firebird::GetPlugins cp(Firebird::IPluginManager::TYPE_WIRE_CRYPT, p.c_str()); if (cp.hasData()) { + WIRECRYPT_DEBUG(fprintf(stderr, "tryKeyType, client loaded plugin %s\n", p.c_str())); Firebird::LocalStatus st; Firebird::CheckStatusWrapper statusWrapper(&st); diff --git a/src/remote/remote.h b/src/remote/remote.h index 1a6ce84f161..e587e080fae 100644 --- a/src/remote/remote.h +++ b/src/remote/remote.h @@ -849,6 +849,8 @@ class ClntAuthBlock FB_FINAL : // Firebird::ICryptKeyCallback implementation unsigned callback(unsigned dataLength, const void* data, unsigned bufferLength, void* buffer); + int getHashLength(Firebird::CheckStatusWrapper* status); + void getHashData(Firebird::CheckStatusWrapper* status, void* hash); private: Firebird::GetPlugins pluginItr; @@ -985,7 +987,7 @@ const USHORT PORT_rdb_shutdown = 0x0200; // Database is shut down const USHORT PORT_connecting = 0x0400; // Aux connection waits for a channel to be activated by client //const USHORT PORT_z_data = 0x0800; // Zlib incoming buffer has data left after decompression const USHORT PORT_compressed = 0x1000; // Compress outgoing stream (does not affect incoming) -const USHORT PORT_released = 0x2000; // release(), complementary to the first addRef() in constructor, was called +const USHORT PORT_released = 0x2000; // release(), complementary to the first addRef() in constructor, was called // forward decl class RemotePortGuard; @@ -1368,6 +1370,7 @@ struct rem_port : public Firebird::GlobalStorage, public Firebird::RefCounted void batch_exec(P_BATCH_EXEC*, PACKET*); void batch_rls(P_BATCH_FREE_CANCEL*, PACKET*); void batch_cancel(P_BATCH_FREE_CANCEL*, PACKET*); + void batch_sync(PACKET*); void batch_bpb(P_BATCH_SETBPB*, PACKET*); void replicate(P_REPLICATE*, PACKET*); @@ -1470,26 +1473,31 @@ class PortsCleanup public: PortsCleanup() : m_ports(NULL), - m_mutex() + m_mutex(), + closing(false) {} explicit PortsCleanup(MemoryPool&) : m_ports(NULL), - m_mutex() + m_mutex(), + closing(false) {} - ~PortsCleanup() + virtual ~PortsCleanup() {} void registerPort(rem_port*); void unRegisterPort(rem_port*); void closePorts(); + virtual void closePort(rem_port*); + virtual void delay(); private: typedef Firebird::SortedArray PortsArray; PortsArray* m_ports; Firebird::Mutex m_mutex; + bool closing; }; #endif // REMOTE_REMOTE_H diff --git a/src/remote/server/ReplServer.cpp b/src/remote/server/ReplServer.cpp index 49a75451b42..323de00aae2 100644 --- a/src/remote/server/ReplServer.cpp +++ b/src/remote/server/ReplServer.cpp @@ -75,8 +75,24 @@ namespace const USHORT CTL_VERSION1 = 1; const USHORT CTL_CURRENT_VERSION = CTL_VERSION1; - volatile bool* shutdownPtr = NULL; + volatile bool shutdownFlag = false; AtomicCounter activeThreads; + Semaphore shutdownSemaphore; + + int shutdownHandler(const int, const int, void*) + { + if (!shutdownFlag && activeThreads.value()) + { + shutdownFlag = true; + shutdownSemaphore.release(activeThreads.value() + 1); + + do { + Thread::sleep(10); + } while (activeThreads.value()); + } + + return 0; + } struct ActiveTransaction { @@ -147,7 +163,7 @@ namespace #ifdef WIN_NT string name; name.printf("firebird_replctl_%s", guidStr); - m_mutex = CreateMutex(NULL, FALSE, name.c_str()); + m_mutex = CreateMutex(ISC_get_security_desc(), FALSE, name.c_str()); if (WaitForSingleObject(m_mutex, INFINITE) != WAIT_OBJECT_0) #else // POSIX #ifdef HAVE_FLOCK @@ -332,9 +348,9 @@ namespace public: explicit Target(const Replication::Config* config) : m_config(config), - m_lastError(getPool()), m_attachment(nullptr), m_replicator(nullptr), - m_sequence(0), m_connected(false) + m_sequence(0), m_connected(false), + m_lastError(getPool()), m_errorSequence(0), m_errorOffset(0) { } @@ -366,6 +382,7 @@ namespace ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE); + dpb.insertByte(isc_dpb_no_db_triggers, 1); dpb.insertString(isc_dpb_user_name, DBA_USER_NAME); dpb.insertString(isc_dpb_config, ParsedList::getNonLoopbackProviders(m_config->dbName)); @@ -373,17 +390,20 @@ namespace DispatcherPtr provider; FbLocalStatus localStatus; - m_attachment = + const auto att = provider->attachDatabase(&localStatus, m_config->dbName.c_str(), - dpb.getBufferLength(), dpb.getBuffer()); + dpb.getBufferLength(), dpb.getBuffer()); localStatus.check(); + m_attachment.assignRefNoIncr(att); - m_replicator = m_attachment->createReplicator(&localStatus); + const auto repl = m_attachment->createReplicator(&localStatus); localStatus.check(); + m_replicator.assignRefNoIncr(repl); fb_assert(!m_sequence); - const auto transaction = m_attachment->startTransaction(&localStatus, 0, NULL); + RefPtr transaction(REF_NO_INCR, + m_attachment->startTransaction(&localStatus, 0, NULL)); localStatus.check(); const char* sql = @@ -397,9 +417,6 @@ namespace NULL, NULL, result.getMetadata(), result.getData()); localStatus.check(); - transaction->commit(&localStatus); - localStatus.check(); - m_sequence = result->sequence; #endif m_connected = true; @@ -409,28 +426,22 @@ namespace void shutdown() { - if (m_attachment) - { -#ifndef NO_DATABASE - FbLocalStatus localStatus; - m_replicator->close(&localStatus); - m_attachment->detach(&localStatus); -#endif - m_replicator = NULL; - m_attachment = NULL; - m_sequence = 0; - } - + m_replicator = nullptr; + m_attachment = nullptr; + m_sequence = 0; m_connected = false; } - bool replicate(FbLocalStatus& status, ULONG length, const UCHAR* data) + void replicate(FB_UINT64 sequence, ULONG offset, ULONG length, const UCHAR* data) { #ifdef NO_DATABASE return true; #else - m_replicator->process(&status, length, data); - return status.isSuccess(); + fb_assert(m_replicator); + + FbLocalStatus localStatus; + m_replicator->process(&localStatus, length, data); + checkCompletion(localStatus, sequence, offset); #endif } @@ -446,13 +457,37 @@ namespace void logError(const string& message) { - if (message != m_lastError) + if (m_config->verboseLogging || message != m_lastError) { - logReplicaError(m_config->dbName, message); + string error = message; + + if (m_errorSequence) + { + string position; + position.printf("\n\tAt segment %" UQUADFORMAT ", offset %u", + m_errorSequence, m_errorOffset); + error += position; + } + + logReplicaError(m_config->dbName, error); m_lastError = message; } } + void checkCompletion(const FbLocalStatus& status, FB_UINT64 sequence, ULONG offset) + { + if (!status.isSuccess()) + { + m_errorSequence = sequence; + m_errorOffset = offset; + status.raise(); + } + + m_lastError.clear(); + m_errorSequence = 0; + m_errorOffset = 0; + } + void verbose(const char* msg, ...) const { if (m_config->verboseLogging) @@ -470,11 +505,13 @@ namespace private: AutoPtr m_config; - string m_lastError; - IAttachment* m_attachment; - IReplicator* m_replicator; + RefPtr m_attachment; + RefPtr m_replicator; FB_UINT64 m_sequence; bool m_connected; + string m_lastError; + FB_UINT64 m_errorSequence; + ULONG m_errorOffset; }; typedef Array TargetList; @@ -523,19 +560,10 @@ namespace (SINT64) finish.value().timestamp_time / 10; const SINT64 delta = finishMsec - startMsec; + const double seconds = (double) delta / 1000; string value; - - if (delta < 1000) // less than 1 second - value.printf("%u ms", (unsigned) delta); - else if (delta < 60 * 1000) // less than 1 minute - value.printf("%u second(s)", (unsigned) (delta / 1000)); - else if (delta < 60 * 60 * 1000) // less than 1 hour - value.printf("%u minute(s)", (unsigned) (delta / 1000 / 60)); - else if (delta < 24 * 60 * 60 * 1000) // less than 1 day - value.printf("%u hour(s)", (unsigned) (delta / 1000 / 60 / 60)); - else - value.printf("%u day(s)", (unsigned) (delta / 1000 / 60 / 60 / 24)); + value.printf("%.3lfs", seconds); return value; } @@ -568,19 +596,22 @@ namespace return true; } - bool replicate(FbLocalStatus& status, FB_UINT64 sequence, - Target* target, TransactionList& transactions, - ULONG offset, ULONG length, const UCHAR* data, - bool rewind) + enum ActionType { REPLICATE, REPLAY, FAST_FORWARD }; + + void replicate(Target* target, + TransactionList& transactions, + FB_UINT64 sequence, ULONG offset, + ULONG length, const UCHAR* data, + ActionType action) { const Block* const header = (Block*) data; const auto traNumber = header->traNumber; - if (!rewind || !traNumber || transactions.exist(traNumber)) + if (action == REPLICATE || + (action == REPLAY && (!traNumber || transactions.exist(traNumber)))) { - if (!target->replicate(status, length, data)) - return false; + target->replicate(sequence, offset, length, data); } if (header->flags & BLOCK_END_TRANS) @@ -591,7 +622,7 @@ namespace if (transactions.find(traNumber, pos)) transactions.remove(pos); } - else if (!rewind) + else if (action != REPLAY) { transactions.clear(); } @@ -600,19 +631,15 @@ namespace { fb_assert(traNumber); - if (!rewind && !transactions.exist(traNumber)) + if (action != REPLAY && !transactions.exist(traNumber)) transactions.add(ActiveTransaction(traNumber, sequence)); } - - return true; } - enum ProcessStatus { PROCESS_SUSPEND, PROCESS_CONTINUE, PROCESS_ERROR }; + enum ProcessStatus { PROCESS_SUSPEND, PROCESS_CONTINUE, PROCESS_ERROR, PROCESS_SHUTDOWN }; ProcessStatus process_archive(MemoryPool& pool, Target* target) { - FbLocalStatus localStatus; - ProcessQueue queue(pool); ProcessStatus ret = PROCESS_SUSPEND; @@ -623,9 +650,14 @@ namespace { // First pass: create the processing queue - for (auto iter = PathUtils::newDirIterator(pool, config->sourceDirectory); + AutoPtr iter; + + for (iter = PathUtils::newDirIterator(pool, config->sourceDirectory); *iter; ++(*iter)) { + if (shutdownFlag) + return PROCESS_SHUTDOWN; + const auto filename = **iter; #ifdef PRESERVE_LOG @@ -718,12 +750,11 @@ namespace if (queue.isEmpty()) { - target->verbose("No new segments found, suspending for %u seconds", - config->applyIdleTimeout); + target->verbose("No new segments found, suspending"); return ret; } - target->verbose("Added %u segment(s) to the processing queue", (ULONG) queue.getCount()); + target->verbose("Added %u segment(s) to the queue", (ULONG) queue.getCount()); // Second pass: replicate the chain of contiguous segments @@ -733,10 +764,13 @@ namespace const FB_UINT64 max_sequence = queue.back()->header.hdr_sequence; FB_UINT64 next_sequence = 0; const bool restart = target->isShutdown(); + auto action = REPLICATE; - for (Segment** iter = queue.begin(); iter != queue.end(); ++iter) + for (auto segment : queue) { - Segment* const segment = *iter; + if (shutdownFlag) + return PROCESS_SHUTDOWN; + const FB_UINT64 sequence = segment->header.hdr_sequence; const Guid& guid = segment->header.hdr_guid; @@ -748,29 +782,55 @@ namespace const FB_UINT64 db_sequence = target->initReplica(); const FB_UINT64 last_db_sequence = control.getDbSequence(); - if (sequence <= db_sequence) - { - target->verbose("Deleting segment %" UQUADFORMAT " due to fast forward", sequence); - segment->remove(); - continue; - } - if (db_sequence != last_db_sequence) { - target->verbose("Resetting replication to continue from segment %" UQUADFORMAT, db_sequence + 1); - control.saveDbSequence(db_sequence); - transactions.clear(); - control.saveComplete(db_sequence, transactions); - last_sequence = db_sequence; - last_offset = 0; + if (sequence == db_sequence + 1) + { + if (const auto oldest = findOldest(transactions)) + { + const TraNumber oldest_trans = oldest->tra_id; + const FB_UINT64 oldest_sequence = oldest ? oldest->sequence : 0; + target->verbose("Resetting replication to continue from segment %" UQUADFORMAT + " (new OAT: %" UQUADFORMAT " in segment %" UQUADFORMAT ")", + db_sequence + 1, oldest_trans, oldest_sequence); + } + else + { + target->verbose("Resetting replication to continue from segment %" UQUADFORMAT, + db_sequence + 1); + } + + control.saveDbSequence(db_sequence); + return PROCESS_SHUTDOWN; // this enforces restart from OAT + } + + if (action != FAST_FORWARD) + { + if (segment != queue.front()) + { + fb_assert(false); + return PROCESS_SHUTDOWN; + } + + if (db_sequence > max_sequence) + { + target->verbose("Database sequence has been changed to %" UQUADFORMAT + ", waiting for appropriate segment", db_sequence); + return PROCESS_SUSPEND; + } + + target->verbose("Database sequence has been changed to %" UQUADFORMAT + ", preparing for replication reset", db_sequence); + + action = FAST_FORWARD; + } } // If no new segments appeared since our last attempt, // then there's no point in replaying the whole sequence - if (max_sequence == last_sequence) + if (max_sequence == last_sequence && !last_offset) { - target->verbose("No new segments found, suspending for %u seconds", - config->applyIdleTimeout); + target->verbose("No new segments found, suspending"); return ret; } @@ -826,6 +886,9 @@ namespace ULONG totalLength = sizeof(SegmentHeader); while (totalLength < segment->header.hdr_length) { + if (shutdownFlag) + return PROCESS_SHUTDOWN; + Block header; if (read(file, &header, sizeof(Block)) != sizeof(Block)) raiseError("Journal file %s read failed (error %d)", segment->filename.c_str(), ERRNO); @@ -835,8 +898,10 @@ namespace if (blockLength) { - const bool rewind = (sequence < last_sequence || + const bool replay = (sequence < last_sequence || (sequence == last_sequence && (!last_offset || totalLength < last_offset))); + if (action != FAST_FORWARD) + action = replay ? REPLAY : REPLICATE; UCHAR* const data = buffer.getBuffer(length); memcpy(data, &header, sizeof(Block)); @@ -844,22 +909,7 @@ namespace if (read(file, data + sizeof(Block), blockLength) != blockLength) raiseError("Journal file %s read failed (error %d)", segment->filename.c_str(), ERRNO); - const bool success = - replicate(localStatus, sequence, - target, transactions, - totalLength, length, data, - rewind); - - if (!success) - { - oldest = findOldest(transactions); - oldest_sequence = oldest ? oldest->sequence : 0; - - target->verbose("Segment %" UQUADFORMAT " replication failure at offset %u", - sequence, totalLength); - - localStatus.raise(); - } + replicate(target, transactions, sequence, totalLength, length, data, action); } totalLength += length; @@ -878,20 +928,23 @@ namespace oldest_sequence = oldest ? oldest->sequence : 0; next_sequence = sequence + 1; - string extra; + string actionName, extra; + actionName = (action == FAST_FORWARD) ? "scanned" : + (action == REPLAY) ? "replayed" : "replicated"; + if (oldest) { const TraNumber oldest_trans = oldest->tra_id; - extra.printf("preserving the file due to %u active transaction(s) (oldest: %" UQUADFORMAT " in segment %" UQUADFORMAT ")", - (unsigned) transactions.getCount(), oldest_trans, oldest_sequence); + extra.printf("preserving (OAT: %" UQUADFORMAT " in segment %" UQUADFORMAT ")", + oldest_trans, oldest_sequence); } else { - extra += "deleting the file"; + extra = "deleting"; } - target->verbose("Segment %" UQUADFORMAT " (%u bytes) is replicated in %s, %s", - sequence, totalLength, interval.c_str(), extra.c_str()); + target->verbose("Segment %" UQUADFORMAT " (%u bytes) is %s in %s, %s", + sequence, totalLength, actionName.c_str(), interval.c_str(), extra.c_str()); if (!oldest_sequence) segment->remove(); @@ -913,8 +966,8 @@ namespace break; target->verbose("Deleting segment %" UQUADFORMAT " as no longer needed", sequence); - segment->remove(); + } while (pos < queue.getCount()); } } @@ -924,14 +977,13 @@ namespace } catch (const Exception& ex) { - LocalStatus localStatus; - CheckStatusWrapper statusWrapper(&localStatus); - ex.stuffException(&statusWrapper); + FbLocalStatus localStatus; + ex.stuffException(&localStatus); string message; char temp[BUFFER_LARGE]; - const ISC_STATUS* statusPtr = localStatus.getErrors(); + const ISC_STATUS* statusPtr = localStatus->getErrors(); while (fb_interpret(temp, sizeof(temp), &statusPtr)) { if (!message.isEmpty()) @@ -942,8 +994,7 @@ namespace target->logError(message); - target->verbose("Suspending for %u seconds", - config->applyErrorTimeout); + target->verbose("Disconnecting and suspending"); ret = PROCESS_ERROR; } @@ -956,18 +1007,17 @@ namespace THREAD_ENTRY_DECLARE process_thread(THREAD_ENTRY_PARAM arg) { - fb_assert(shutdownPtr); - AutoPtr target(static_cast(arg)); const auto config = target->getConfig(); + const auto dbName = config->dbName.c_str(); - target->verbose("Started replication thread"); + AutoMemoryPool workingPool(MemoryPool::createPool()); + ContextPoolHolder threadContext(workingPool); - while (!*shutdownPtr) - { - AutoMemoryPool workingPool(MemoryPool::createPool()); - ContextPoolHolder threadContext(workingPool); + target->verbose("Started replication for database %s", dbName); + while (!shutdownFlag) + { const ProcessStatus ret = process_archive(*workingPool, target); if (ret == PROCESS_CONTINUE) @@ -975,42 +1025,43 @@ namespace target->shutdown(); - if (!*shutdownPtr) + if (ret != PROCESS_SHUTDOWN) { const ULONG timeout = (ret == PROCESS_SUSPEND) ? config->applyIdleTimeout : config->applyErrorTimeout; - Thread::sleep(timeout * 1000); + shutdownSemaphore.tryEnter(timeout); } } - target->verbose("Finished replication thread"); - + target->verbose("Finished replication for database %s", dbName); --activeThreads; return 0; } } -bool REPL_server(CheckStatusWrapper* status, bool wait, bool* aShutdownPtr) +bool REPL_server(CheckStatusWrapper* status, bool wait) { try { - shutdownPtr = aShutdownPtr; + fb_shutdown_callback(0, shutdownHandler, fb_shut_preproviders, 0); TargetList targets; readConfig(targets); for (auto target : targets) { - ++activeThreads; Thread::start((ThreadEntryPoint*) process_thread, target, THREAD_medium, NULL); + ++activeThreads; } if (wait) { + shutdownSemaphore.enter(); + do { - Thread::sleep(100); + Thread::sleep(10); } while (activeThreads.value()); } } diff --git a/src/remote/server/ReplServer.h b/src/remote/server/ReplServer.h index 85007b9b978..81ae22b19bc 100644 --- a/src/remote/server/ReplServer.h +++ b/src/remote/server/ReplServer.h @@ -23,6 +23,6 @@ #ifndef UTIL_REPL_SERVER_H #define UTIL_REPL_SERVER_H -bool REPL_server(Firebird::CheckStatusWrapper*, bool, bool*); +bool REPL_server(Firebird::CheckStatusWrapper*, bool); #endif // UTIL_REPL_SERVER_H diff --git a/src/remote/server/os/posix/inet_server.cpp b/src/remote/server/os/posix/inet_server.cpp index 24633600331..c067b5adacc 100644 --- a/src/remote/server/os/posix/inet_server.cpp +++ b/src/remote/server/os/posix/inet_server.cpp @@ -41,6 +41,7 @@ #include "../common/config/config.h" #include "../common/os/fbsyslog.h" #include "../common/os/os_utils.h" +#include "../common/status.h" #include #ifdef HAVE_SYS_TYPES_H @@ -92,6 +93,7 @@ #include "../auth/SecurityDatabase/LegacyServer.h" #include "../auth/trusted/AuthSspi.h" #include "../auth/SecureRemotePassword/server/SrpServer.h" +#include "../jrd/replication/Config.h" #ifdef HAVE_SYS_SIGNAL_H #include @@ -114,12 +116,11 @@ const char* TEMP_DIR = "/tmp"; static void set_signal(int, void (*)(int)); static void signal_handler(int); +static void shutdown_handler(int); static TEXT protocol[128]; static int INET_SERVER_start = 0; -static bool serverClosing = false; - #if defined(HAVE_SETRLIMIT) && defined(HAVE_GETRLIMIT) #define FB_RAISE_LIMITS 1 static void raiseLimit(int resource); @@ -132,12 +133,15 @@ static void logSecurityDatabaseError(const char* path, ISC_STATUS* status) if (fb_utils::containsErrorCode(status, isc_io_error)) return; - const int SHUTDOWN_TIMEOUT = 5000; // 5 sec - - gds__log_status(path, status); - gds__put_error(path); - gds__print_status(status); Firebird::Syslog::Record(Firebird::Syslog::Error, "Security database error"); + gds__log_status(path, status); + if (isatty(2)) + { + gds__put_error(path); + gds__print_status(status); + } + + const int SHUTDOWN_TIMEOUT = 5000; // 5 sec fb_shutdown(SHUTDOWN_TIMEOUT, fb_shutrsn_exit_called); exit(STARTUP_ERROR); } @@ -183,6 +187,8 @@ int CLIB_ROUTINE main( int argc, char** argv) bool standaloneClassic = false; bool super = false; + int replPid = 0; + // It's very easy to detect that we are spawned - just check fd 0 to be a socket. const int channel = 0; struct STAT stat0; @@ -293,6 +299,7 @@ int CLIB_ROUTINE main( int argc, char** argv) INET_SERVER_flag |= SRVR_multi_client; super = true; } + { // scope Firebird::MasterInterfacePtr master; master->serverMode(super ? 1 : 0); @@ -306,6 +313,13 @@ int CLIB_ROUTINE main( int argc, char** argv) // activate paths set with -e family of switches ISC_set_prefix(0, 0); + // set shutdown signals handler for listener + if (standaloneClassic) + { + set_signal(SIGTERM, shutdown_handler); + set_signal(SIGINT, shutdown_handler); + } + // ignore some signals set_signal(SIGPIPE, signal_handler); set_signal(SIGUSR1, signal_handler); @@ -332,6 +346,16 @@ int CLIB_ROUTINE main( int argc, char** argv) raiseLimit(RLIMIT_CORE); } +#ifdef LINUX + // instruct kernel to include shared memory regions into core dump + FILE* coreproc = fopen("/proc/self/coredump_filter", "r+"); + if (coreproc) + { + fprintf(coreproc, "0x3f\n"); + fclose(coreproc); + } +#endif + #if (defined SOLARIS || defined HPUX || defined LINUX) if (super) { @@ -407,18 +431,90 @@ int CLIB_ROUTINE main( int argc, char** argv) if (super || standaloneClassic) { + if (standaloneClassic && Replication::Config::hasReplicas()) + { + // Start the replication server now (in the forked process), + // because INET_connect() never returns for the standalone Classic + + if ((replPid = fork()) <= 0) + { + try + { + if (replPid) // failed fork attempt + Firebird::system_error::raise("fork", replPid); + + // We've been forked successfully + Firebird::FbLocalStatus localStatus; + if (!REPL_server(&localStatus, true)) + localStatus.check(); + } + catch (const Firebird::Exception& ex) + { + const char* const errorMsg = "Replication server startup error"; + iscLogException(errorMsg, ex); + Firebird::Syslog::Record(Firebird::Syslog::Error, errorMsg); + } + + if (!replPid) + { + fb_shutdown(10000, fb_shutrsn_exit_called); + return FINI_OK; + } + } + } + + // Start the network listener + try { port = INET_connect(protocol, 0, INET_SERVER_flag, 0, NULL); } catch (const Firebird::Exception& ex) { - iscLogException("startup:INET_connect:", ex); - Firebird::StaticStatusVector st; - ex.stuffException(st); - gds__print_status(st.begin()); + iscLogException("INET server startup error", ex); exit(STARTUP_ERROR); } + + // If INET_connect() returns NULL for the standalone classic, then game is over. + // Signal the forked replication server process to terminate and then exit. + + if (!port && replPid > 0) // this implies standaloneClassic being true + { + if (!kill(replPid, SIGTERM)) + { + int status = 0; + + // Wait up to one second for the replicator process to finish gracefully + for (unsigned n = 0; n < 10; n++) + { + Thread::sleep(100); // milliseconds + + const auto res = waitpid(replPid, &status, WNOHANG); + + if (res == replPid) // process is terminated + break; + + if (res < 0 && !SYSCALL_INTERRUPTED(errno)) // error + break; + + // continue waiting otherwise + } + + // Force terminating the replicator process if it's still alive + if (!WIFEXITED(status)) + kill(replPid, SIGKILL); + } + + fb_shutdown(10000, fb_shutrsn_exit_called); + return FINI_OK; + } + } + + // set default handlers for child processes + if (standaloneClassic) + { + signal(SIGTERM, SIG_DFL); + signal(SIGINT, SIG_DFL); } if (classic) @@ -464,21 +560,20 @@ int CLIB_ROUTINE main( int argc, char** argv) logSecurityDatabaseError(path, status); } } - } // end scope - - fb_shutdown_callback(NULL, closePort, fb_shut_exit, port); - Firebird::LocalStatus localStatus; - Firebird::CheckStatusWrapper statusWrapper(&localStatus); + // Start replication server - if (!REPL_server(&statusWrapper, false, &serverClosing)) - { - const char* errorMsg = "Replication server initialization error"; - gds__log_status(errorMsg, localStatus.getErrors()); - Firebird::Syslog::Record(Firebird::Syslog::Error, errorMsg); - exit(STARTUP_ERROR); + Firebird::FbLocalStatus localStatus; + if (!REPL_server(&localStatus, false)) + { + const char* const errorMsg = "Replication server startup error"; + iscLogStatus(errorMsg, localStatus->getErrors()); + Firebird::Syslog::Record(Firebird::Syslog::Error, errorMsg); + } } + fb_shutdown_callback(NULL, closePort, fb_shut_exit, port); + SRVR_multi_thread(port, INET_SERVER_flag); // perform atexit shutdown here when all globals in embedded library are active @@ -546,6 +641,25 @@ static void signal_handler(int) ++INET_SERVER_start; } +static void shutdown_handler(int shutdown_signal_code) +{ +/************************************** + * + * s h u t d o w n _ h a n d l e r + * + ************************************** + * + * Functional description + * Forward shutdown signal to all child processes. + * + **************************************/ + + signal(shutdown_signal_code, SIG_IGN); + + kill(-1 * getpid(), shutdown_signal_code); + + exit(FINI_OK); +} #ifdef FB_RAISE_LIMITS static void raiseLimit(int resource) diff --git a/src/remote/server/os/win32/srvr_w32.cpp b/src/remote/server/os/win32/srvr_w32.cpp index 9770d1586c2..029f63c728c 100644 --- a/src/remote/server/os/win32/srvr_w32.cpp +++ b/src/remote/server/os/win32/srvr_w32.cpp @@ -557,7 +557,6 @@ static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM) * **************************************/ ThreadCounter counter; - FbLocalStatus localStatus; if (server_flag & SRVR_inet) { @@ -595,7 +594,13 @@ static THREAD_ENTRY_DECLARE start_connections_thread(THREAD_ENTRY_PARAM) } } - REPL_server(&localStatus, false, &server_shutdown); + FbLocalStatus localStatus; + if (!REPL_server(&localStatus, false)) + { + const char* errorMsg = "Replication server initialization error"; + iscLogStatus(errorMsg, localStatus->getErrors()); + Syslog::Record(Syslog::Error, errorMsg); + } return 0; } diff --git a/src/remote/server/server.cpp b/src/remote/server/server.cpp index a4fcc826a2e..fb45abcf441 100644 --- a/src/remote/server/server.cpp +++ b/src/remote/server/server.cpp @@ -167,6 +167,19 @@ class NetworkCallback : public VersionedIfacesetErrors2(FB_NELEM(err), err); + } + private: rem_port* port; Semaphore sem; @@ -256,6 +269,43 @@ class CryptKeyCallback : public VersionedIfacegetHashLength(status); + + if (!networkCallback.isStopped()) + { + ISC_STATUS err[] = {isc_arg_gds, isc_wish_list}; + status->setErrors2(FB_NELEM(err), err); + + return -1; + } + + return 0; + } + + void getHashData(Firebird::CheckStatusWrapper* status, void* h) override + { + Reference r(*port); + loadClientKey(); + + if (keyCallback) + { + keyCallback->getHashData(status, h); + return; + } + + if (!networkCallback.isStopped()) + { + ISC_STATUS err[] = {isc_arg_gds, isc_wish_list}; + status->setErrors2(FB_NELEM(err), err); + } + } + private: rem_port* port; NetworkCallback networkCallback; @@ -632,7 +682,10 @@ class ServerAuth : public GlobalStorage, public ServerAuthBase } // if we asked for more data but received nothing switch to next plugin - const bool forceNext = (flags & AUTH_CONTINUE) && (!authPort->port_srv_auth_block->hasDataForPlugin()); + const bool forceNext = (flags & AUTH_CONTINUE) && + (!authPort->port_srv_auth_block->hasDataForPlugin()) && + (!authPort->port_srv_auth_block->authCompleted()); + HANDSHAKE_DEBUG(fprintf(stderr, "Srv: authenticate: ServerAuth calls plug %s\n", forceNext ? "forced-NEXT" : authItr->name())); int authResult = forceNext ? IAuth::AUTH_CONTINUE : @@ -661,6 +714,11 @@ class ServerAuth : public GlobalStorage, public ServerAuthBase authServer = NULL; continue; + case IAuth::AUTH_SUCCESS_WITH_DATA: + HANDSHAKE_DEBUG(fprintf(stderr, "Srv: authenticate: success with data\n")); + fb_assert(!authPort->port_srv_auth_block->authCompleted()); + // fall thru + case IAuth::AUTH_MORE_DATA: HANDSHAKE_DEBUG(fprintf(stderr, "Srv: authenticate: plugin wants more data\n")); if (authPort->port_protocol < PROTOCOL_VERSION11) @@ -714,6 +772,13 @@ class ServerAuth : public GlobalStorage, public ServerAuthBase if (send->p_acpt.p_acpt_type & pflag_compress) authPort->port_flags |= PORT_compressed; memset(&send->p_auth_cont, 0, sizeof send->p_auth_cont); + + if (authResult == IAuth::AUTH_SUCCESS_WITH_DATA) + { + authPort->port_srv_auth_block->authCompleted(true); + HANDSHAKE_DEBUG(fprintf(stderr, "Srv: authenticate: success with data, completed\n")); + } + return false; case IAuth::AUTH_FAILED: @@ -730,8 +795,13 @@ class ServerAuth : public GlobalStorage, public ServerAuthBase if (st.hasData()) { - if (st.getErrors()[1] == isc_missing_data_structures) + switch (st.getErrors()[1]) + { + case isc_missing_data_structures: + case isc_login: status_exception::raise(&st); + break; + } iscLogStatus("Authentication error", &st); Arg::Gds loginError(isc_login_error); @@ -1083,6 +1153,8 @@ class CryptKeyTypeManager : public PermanentStorage CheckStatusWrapper st(&ls); for (GetPlugins cpItr(IPluginManager::TYPE_WIRE_CRYPT); cpItr.hasData(); cpItr.next()) { + WIRECRYPT_DEBUG(fprintf(stderr, "CryptKeyTypeManager %s\n", cpItr.name())); + const char* list = cpItr.plugin()->getKnownTypes(&st); check(&st); fb_assert(list); @@ -1918,7 +1990,7 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) { if ((protocol->p_cnct_version == PROTOCOL_VERSION10 || (protocol->p_cnct_version >= PROTOCOL_VERSION11 && - protocol->p_cnct_version <= PROTOCOL_VERSION16)) && + protocol->p_cnct_version <= PROTOCOL_VERSION17)) && (protocol->p_cnct_architecture == arch_generic || protocol->p_cnct_architecture == ARCHITECTURE) && protocol->p_cnct_weight >= weight) @@ -1938,6 +2010,9 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) send->p_acpd.p_acpt_version = port->port_protocol = version; send->p_acpd.p_acpt_architecture = architecture; send->p_acpd.p_acpt_type = type | (compress ? pflag_compress : 0); +#ifdef TRUSTED_AUTH + send->p_acpd.p_acpt_type |= pflag_win_sspi_nego; +#endif send->p_acpd.p_acpt_authenticated = 0; send->p_acpt.p_acpt_version = port->port_protocol = version; @@ -1982,13 +2057,15 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) { ConnectAuth* cnctAuth = FB_NEW ConnectAuth(port, id); port->port_srv_auth = cnctAuth; - if (port->port_srv_auth->authenticate(send, ServerAuth::AUTH_COND_ACCEPT)) + + if (cnctAuth->authenticate(send, ServerAuth::AUTH_COND_ACCEPT)) { - delete port->port_srv_auth; + delete cnctAuth; port->port_srv_auth = NULL; } + else + cnctAuth->useResponse = true; - cnctAuth->useResponse = true; return true; } @@ -2024,9 +2101,9 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) HANDSHAKE_DEBUG(fprintf(stderr, "Srv: accept_connection: calls createPluginsItr\n")); port->port_srv_auth_block->createPluginsItr(); - if (port->port_srv_auth_block->plugins) // We have all required data and iterator was created + AuthServerPlugins* const plugins = port->port_srv_auth_block->plugins; + if (plugins && plugins->hasData()) // We have all required data and iterator was created { - AuthServerPlugins* const plugins = port->port_srv_auth_block->plugins; NoCaseString clientPluginName(port->port_srv_auth_block->getPluginName()); // If there is plugin matching client's one it will be HANDSHAKE_DEBUG(fprintf(stderr, "Srv: accept_connection: client plugin='%s' server='%s'\n", @@ -2098,19 +2175,25 @@ static bool accept_connection(rem_port* port, P_CNCT* connect, PACKET* send) HANDSHAKE_DEBUG(fprintf(stderr, "!accepted, sending reject\n")); if (status.getState() & Firebird::IStatus::STATE_ERRORS) { - if (status.getErrors()[1] != isc_missing_data_structures) + switch (status.getErrors()[1]) { - iscLogStatus("Authentication error", &status); - Arg::Gds loginError(isc_login_error); + case isc_missing_data_structures: + case isc_login: + port->send_response(send, 0, 0, &status, false); + break; + + default: + { + iscLogStatus("Authentication error", &status); + Arg::Gds loginError(isc_login_error); #ifdef DEV_BUILD - loginError << Arg::StatusVector(&status); + loginError << Arg::StatusVector(&status); #endif - LocalStatus tmp; - loginError.copyTo(&tmp); - port->send_response(send, 0, 0, &tmp, false); + LocalStatus tmp; + loginError.copyTo(&tmp); + port->send_response(send, 0, 0, &tmp, false); + } } - else - port->send_response(send, 0, 0, &status, false); } else port->send(send); @@ -2679,23 +2762,28 @@ static void cancel_operation(rem_port* port, USHORT kind) if ((port->port_flags & (PORT_async | PORT_disconnect)) || !(port->port_context)) return; - ServAttachment iface; + ServAttachment dbIface; + ServService svcIface; { RefMutexGuard portGuard(*port->port_cancel_sync, FB_FUNCTION); - Rdb* rdb; - if ((port->port_flags & PORT_disconnect) || !(rdb = port->port_context)) + Rdb* rdb = port->port_context; + if ((port->port_flags & PORT_disconnect) || !rdb) return; - iface = rdb->rdb_iface; + if (rdb->rdb_svc) + svcIface = rdb->rdb_svc->svc_iface; + else + dbIface = rdb->rdb_iface; } - if (iface) - { - LocalStatus ls; - CheckStatusWrapper status_vector(&ls); - iface->cancelOperation(&status_vector, kind); - } + LocalStatus ls; + CheckStatusWrapper status_vector(&ls); + + if (dbIface) + dbIface->cancelOperation(&status_vector, kind); + else if (svcIface && kind == fb_cancel_raise) + svcIface->cancel(&status_vector); } @@ -2746,11 +2834,11 @@ static USHORT check_statement_type( Rsr* statement) if (!(local_status.getState() & Firebird::IStatus::STATE_ERRORS)) { - for (const UCHAR* info = buffer; (*info != isc_info_end) && !done;) + for (ClumpletReader p(ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { - const USHORT l = (USHORT) gds__vax_integer(info + 1, 2); - const USHORT type = (USHORT) gds__vax_integer(info + 3, l); - switch (*info) + const USHORT type = (USHORT) p.getInt(); + + switch (p.getClumpTag()) { case isc_info_sql_stmt_type: switch (type) @@ -2765,17 +2853,12 @@ static USHORT check_statement_type( Rsr* statement) break; } break; + case isc_info_sql_batch_fetch: if (type == 0) ret |= STMT_NO_BATCH; break; - case isc_info_error: - case isc_info_truncated: - done = true; - break; - } - info += 3 + l; } } @@ -3001,6 +3084,8 @@ void rem_port::disconnect(PACKET* sendL, PACKET* receiveL) if (rdb->rdb_svc.hasData() && rdb->rdb_svc->svc_iface) { + RefMutexGuard portGuard(*port_cancel_sync, FB_FUNCTION); + rdb->rdb_svc->svc_iface->detach(&status_vector); rdb->rdb_svc->svc_iface = NULL; } @@ -3484,6 +3569,10 @@ void rem_port::batch_create(P_BATCH_CREATE* batch, PACKET* sendL) getHandle(statement, batch->p_batch_statement); statement->checkIface(); + // Check for previously opened batch for the statement + if (statement->rsr_batch) + Arg::Gds(isc_batch_open).raise(); + const ULONG blr_length = batch->p_batch_blr.cstr_length; const UCHAR* blr = batch->p_batch_blr.cstr_address; if (!blr) @@ -3717,6 +3806,16 @@ void rem_port::batch_cancel(P_BATCH_FREE_CANCEL* batch, PACKET* sendL) } +void rem_port::batch_sync(PACKET* sendL) +{ + LocalStatus ls; + CheckStatusWrapper status_vector(&ls); + + // no need checking protocol version if client is using batch_sync, just return synced response + this->send_response(sendL, 0, 0, &status_vector, false); +} + + void rem_port::replicate(P_REPLICATE* repl, PACKET* sendL) { LocalStatus ls; @@ -3730,7 +3829,11 @@ void rem_port::replicate(P_REPLICATE* repl, PACKET* sendL) } if (!this->port_replicator) + { this->port_replicator = rdb->rdb_iface->createReplicator(&status_vector); + check(&status_vector); + fb_assert(this->port_replicator); + } if (repl->p_repl_data.cstr_length) { @@ -3818,7 +3921,8 @@ ISC_STATUS rem_port::execute_statement(P_OP op, P_SQLDATA* sqldata, PACKET* send if (statement->rsr_cursor || statement->rsr_batch) { - Arg::Gds(isc_dsql_cursor_open_err).raise(); + (Arg::Gds(isc_sqlerr) << Arg::Num(-502) << + Arg::Gds(isc_dsql_cursor_open_err)).raise(); } InternalMessageBuffer iMsgBuffer(sqldata->p_sqldata_blr.cstr_length, @@ -3947,7 +4051,8 @@ ISC_STATUS rem_port::fetch(P_SQLDATA * sqldata, PACKET* sendL) sqldata->p_sqldata_blr.cstr_address, msg_length, NULL); if (!msgBuffer.metadata) - Arg::Gds(isc_dsql_cursor_open_err).raise(); + (Arg::Gds(isc_sqlerr) << Arg::Num(-502) << + Arg::Gds(isc_dsql_cursor_open_err)).raise(); statement->rsr_cursor->setDelayedOutputFormat(&status_vector, msgBuffer.metadata); check(&status_vector); @@ -4330,7 +4435,6 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL) // Make sure there is a suitable temporary blob buffer Array buf; UCHAR* const buffer = buffer_length ? buf.getBuffer(buffer_length) : NULL; - memset(buffer, 0, buffer_length); HalfStaticArray info; UCHAR* info_buffer = NULL; @@ -4381,11 +4485,14 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL) { string version; versionInfo(version); + USHORT protocol = memchr(stuff->p_info_items.cstr_address, fb_info_protocol_version, + stuff->p_info_items.cstr_length) ? port_protocol & FB_PROTOCOL_MASK : 0; info_db_len = MERGE_database_info(temp_buffer, //temp buffer, buffer_length, DbImplementation::current.backwardCompatibleImplementation(), 4, 1, reinterpret_cast(version.c_str()), - reinterpret_cast(this->port_host->str_data)); + reinterpret_cast(this->port_host->str_data), + protocol); } break; @@ -4418,6 +4525,15 @@ void rem_port::info(P_OP op, P_INFO* stuff, PACKET* sendL) statement->rsr_iface->getInfo(&status_vector, info_len, info_buffer, buffer_length, buffer); break; + + case op_info_batch: + getHandle(statement, stuff->p_info_object); + statement->checkIface(); + statement->checkBatch(); + + statement->rsr_batch->getInfo(&status_vector, info_len, info_buffer, + buffer_length, buffer); + break; } // Send a response that includes the segment. @@ -4898,6 +5014,7 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p case op_info_transaction: case op_service_info: case op_info_sql: + case op_info_batch: port->info(op, &receive->p_info, sendL); break; @@ -4992,6 +5109,10 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p port->batch_cancel(&receive->p_batch_free_cancel, sendL); break; + case op_batch_sync: + port->batch_sync(sendL); + break; + case op_batch_blob_stream: port->batch_blob_stream(&receive->p_batch_blob, sendL); break; @@ -5019,8 +5140,11 @@ static bool process_packet(rem_port* port, PACKET* sendL, PACKET* receive, rem_p { if (!port->port_parent) { - if (!Worker::isShuttingDown() && !(port->port_flags & (PORT_rdb_shutdown | PORT_detached))) + if (!Worker::isShuttingDown() && !(port->port_flags & (PORT_rdb_shutdown | PORT_detached)) && + ((port->port_server_flags & (SRVR_server | SRVR_multi_client)) != SRVR_server)) + { gds__log("SERVER/process_packet: broken port, server exiting"); + } port->disconnect(sendL, receive); return false; } @@ -6037,12 +6161,15 @@ ISC_STATUS rem_port::service_end(P_RLSE* /*release*/, PACKET* sendL) if (bad_service(&status_vector, rdb)) return this->send_response(sendL, 0, 0, &status_vector, false); - rdb->rdb_svc->svc_iface->detach(&status_vector); + { // scope + RefMutexGuard portGuard(*port_cancel_sync, FB_FUNCTION); + rdb->rdb_svc->svc_iface->detach(&status_vector); - if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) - { - port_flags |= PORT_detached; - rdb->rdb_svc->svc_iface = NULL; + if (!(status_vector.getState() & Firebird::IStatus::STATE_ERRORS)) + { + port_flags |= PORT_detached; + rdb->rdb_svc->svc_iface = NULL; + } } return this->send_response(sendL, 0, 0, &status_vector, false); @@ -6130,12 +6257,15 @@ void rem_port::start_crypt(P_CRYPT * crypt, PACKET* sendL) { ICryptKey* key = NULL; PathName keyName(crypt->p_key.cstr_address, crypt->p_key.cstr_length); - for (unsigned k = 0; k < port_crypt_keys.getCount(); ++k) + if (getPortConfig()->getWireCrypt(WC_SERVER) != WIRE_CRYPT_DISABLED) { - if (keyName == port_crypt_keys[k]->keyName) + for (unsigned k = 0; k < port_crypt_keys.getCount(); ++k) { - key = port_crypt_keys[k]; - break; + if (keyName == port_crypt_keys[k]->keyName) + { + key = port_crypt_keys[k]; + break; + } } } @@ -7210,7 +7340,7 @@ bool SrvAuthBlock::extractNewKeys(CSTRING* to, ULONG flags) for (CryptKeyTypeManager::SpecificPlugins sp(knownCryptKeyTypes().getSpecific(t)); sp.hasData(); sp.next()) { PathName plugin = sp.get(); - GetPlugins cp(IPluginManager::TYPE_WIRE_CRYPT); + GetPlugins cp(IPluginManager::TYPE_WIRE_CRYPT, plugin.c_str()); fb_assert(cp.hasData()); if (cp.hasData()) { diff --git a/src/utilities/fbsvcmgr/fbsvcmgr.cpp b/src/utilities/fbsvcmgr/fbsvcmgr.cpp index a93d3679244..12dee74849f 100644 --- a/src/utilities/fbsvcmgr/fbsvcmgr.cpp +++ b/src/utilities/fbsvcmgr/fbsvcmgr.cpp @@ -554,6 +554,9 @@ const SvcSwitches nbackOptions[] = {"nbk_guid", putStringArgument, 0, isc_spb_nbk_guid, 0}, {"nbk_no_triggers", putOption, 0, isc_spb_nbk_no_triggers, 0}, {"nbk_direct", putStringArgument, 0, isc_spb_nbk_direct, 0}, + {"nbk_clean_history", putSingleTag, 0, isc_spb_nbk_clean_history, 0}, + {"nbk_keep_days", putIntArgument, 0, isc_spb_nbk_keep_days, 0}, + {"nbk_keep_rows", putIntArgument, 0, isc_spb_nbk_keep_rows, 0}, {0, 0, 0, 0, 0} }; diff --git a/src/utilities/fbtracemgr/traceMgrMain.cpp b/src/utilities/fbtracemgr/traceMgrMain.cpp index 1eb6d639bfb..bcf46e17978 100644 --- a/src/utilities/fbtracemgr/traceMgrMain.cpp +++ b/src/utilities/fbtracemgr/traceMgrMain.cpp @@ -61,6 +61,8 @@ class TraceSvcUtil : public TraceSvcIntf virtual void setActive(ULONG id, bool active); virtual void listSessions(); + os_utils::CtrlCHandler ctrlCHandler; + private: void runService(size_t spbSize, const UCHAR* spb); @@ -202,8 +204,6 @@ void TraceSvcUtil::listSessions() void TraceSvcUtil::runService(size_t spbSize, const UCHAR* spb) { - os_utils::CtrlCHandler ctrlCHandler; - ISC_STATUS_ARRAY status; if (isc_service_start(status, &m_svcHandle, 0, @@ -234,6 +234,9 @@ void TraceSvcUtil::runService(size_t spbSize, const UCHAR* spb) sizeof(query), query, sizeof(results) - 1, results)) { + if (ctrlCHandler.getTerminated()) + break; + status_exception::raise(status); } @@ -321,20 +324,23 @@ int CLIB_ROUTINE main(int argc, char* argv[]) fb_utils::FbShutdown appShutdown(fb_shutrsn_app_stopped); AutoPtr uSvc(UtilSvc::createStandalone(argc, argv)); + TraceSvcUtil traceUtil; + try { - TraceSvcUtil traceUtil; - fbtrace(uSvc, &traceUtil); } catch (const Firebird::Exception& ex) { - Firebird::StaticStatusVector temp; + if (!traceUtil.ctrlCHandler.getTerminated()) + { + Firebird::StaticStatusVector temp; - ex.stuffException(temp); - isc_print_status(temp.begin()); + ex.stuffException(temp); + isc_print_status(temp.begin()); - return FINI_ERROR; + return FINI_ERROR; + } } return FINI_OK; diff --git a/src/utilities/gsec/gsec.cpp b/src/utilities/gsec/gsec.cpp index d7150af14ee..e7225fe5d96 100644 --- a/src/utilities/gsec/gsec.cpp +++ b/src/utilities/gsec/gsec.cpp @@ -91,8 +91,10 @@ int GSEC_main(Firebird::UtilSvc* uSvc) { Firebird::StaticStatusVector status; e.stuffException(status); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); exit_code = FB_FAILURE; } @@ -686,7 +688,7 @@ int gsec(Firebird::UtilSvc* uSvc) if (ret && status[1]) { - uSvc->setServiceStatus(status); + uSvc->getStatusAccessor().setServiceStatus(status); } if (sHandle) @@ -719,8 +721,10 @@ int gsec(Firebird::UtilSvc* uSvc) tdsec->tsec_throw = false; GSEC_print_status(status.begin()); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); exit_code = FINI_ERROR; } @@ -1589,10 +1593,11 @@ void GSEC_error(USHORT errcode, const ISC_STATUS* status_vector) static const SafeArg dummy; tsec* tdsec = tsec::getSpecific(); - tdsec->utilSvc->setServiceStatus(GSEC_MSG_FAC, errcode, dummy); + auto sa = tdsec->utilSvc->getStatusAccessor(); + sa.setServiceStatus(GSEC_MSG_FAC, errcode, dummy); if (status_vector) { - tdsec->utilSvc->setServiceStatus(status_vector); + sa.setServiceStatus(status_vector); } tdsec->utilSvc->started(); diff --git a/src/utilities/gstat/dba.epp b/src/utilities/gstat/dba.epp index 17e842c735b..a1ff5701a1c 100644 --- a/src/utilities/gstat/dba.epp +++ b/src/utilities/gstat/dba.epp @@ -359,8 +359,11 @@ int main_gstat(Firebird::UtilSvc* uSvc) { Firebird::StaticStatusVector status; e.stuffException(status); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); + exit_code = FB_FAILURE; } @@ -452,10 +455,14 @@ int gstat(Firebird::UtilSvc* uSvc) const Switches::in_sw_tab_t* in_sw_tab = switches.findSwitch(str); if (!in_sw_tab) { - if (!str[1]) - str = "-*NONE*"; - dba_print(true, 20, SafeArg() << (str + 1)); // msg 20: unknown switch "%s" - print_help(); + if (!tddba->uSvc->isService()) // normally service manager doesn't pass illegal switches + { + if (!str[1]) + str = "-*NONE*"; + dba_print(true, 20, SafeArg() << (str + 1)); // msg 20: unknown switch "%s" + print_help(); + } + dba_error(1); // msg 1: found unknown switch break; // redundant } @@ -613,14 +620,12 @@ int gstat(Firebird::UtilSvc* uSvc) dba_fil* current = db_open(fileName.c_str(), fileName.length()); - SCHAR temp[RAW_HEADER_SIZE]; - tddba->page_size = sizeof(temp); + alignas(DIRECT_IO_BLOCK_SIZE) SCHAR temp[MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE)]; + tddba->page_size = MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE); tddba->global_buffer = (pag*) temp; tddba->page_number = -1; const header_page* header = (const header_page*) db_read((SLONG) 0); - uSvc->started(); - if (!Ods::isSupported(header)) { const int oversion = (header->hdr_ods_version & ~ODS_FIREBIRD_FLAG); @@ -628,6 +633,9 @@ int gstat(Firebird::UtilSvc* uSvc) // msg 3: Wrong ODS version, expected %d, encountered %d? } + // it's important for provider auto-select to mark as 'started' after possible network error + uSvc->started(); + char file_name[1024]; fileName.copyTo(file_name, sizeof(file_name)); dba_print(false, 6, SafeArg() << file_name); // msg 6: \nDatabase \"@1\"\n @@ -639,9 +647,14 @@ int gstat(Firebird::UtilSvc* uSvc) tddba->page_size = header->hdr_page_size; tddba->dp_per_pp = Ods::dataPagesPerPP(tddba->page_size); tddba->max_records = Ods::maxRecsPerDP(tddba->page_size); - tddba->buffer1 = (pag*) alloc(tddba->page_size); - tddba->buffer2 = (pag*) alloc(tddba->page_size); - tddba->global_buffer = (pag*) alloc(tddba->page_size); + { // scope + char* buff = alloc(tddba->page_size * 3 + DIRECT_IO_BLOCK_SIZE); + buff = FB_ALIGN(buff, DIRECT_IO_BLOCK_SIZE); + + tddba->buffer1 = (pag*) buff; + tddba->buffer2 = (pag*) (buff + tddba->page_size); + tddba->global_buffer = (pag*) (buff + tddba->page_size * 2); + } tddba->page_number = -1; // gather continuation files @@ -1143,13 +1156,14 @@ int gstat(Firebird::UtilSvc* uSvc) { ex.stuffException(permStatus); fb_utils::copyStatus(status_vector, ISC_STATUS_LENGTH, permStatus.value(), permStatus.length()); + tddba->exit_code = FB_FAILURE; } // free mem if (status_vector[1]) { - tddba->uSvc->setServiceStatus(status_vector); + tddba->uSvc->getStatusAccessor().setServiceStatus(status_vector); if (!tddba->uSvc->isService()) { const ISC_STATUS* vector = status_vector; @@ -1210,8 +1224,9 @@ int gstat(Firebird::UtilSvc* uSvc) if ((exit_code != FINI_OK) && uSvc->isService() && tddba->dba_status[1]) { - uSvc->initStatus(); - uSvc->setServiceStatus(tddba->dba_status); + Firebird::UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(tddba->dba_status); } return exit_code; @@ -1886,7 +1901,7 @@ static dba_fil* db_open(const char* file_name, USHORT file_length) if (fil->fil_desc == INVALID_HANDLE_VALUE) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); // msg 29: Can't open database file %s db_error(GetLastError()); } @@ -1950,7 +1965,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc) int lastError = GetLastError(); if (lastError != NO_ERROR) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); // msg 30: Can't read a database page db_error(lastError); } @@ -1963,7 +1978,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc) reinterpret_cast(&actual_length), NULL)) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); // msg 30: Can't read a database page db_error(GetLastError()); } @@ -2071,7 +2086,7 @@ static dba_fil* db_open(const char* file_name, USHORT file_length) if ((fil->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); // msg 29: Can't open database file %s db_error(errno); } @@ -2126,7 +2141,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc) const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) tddba->page_size); if (os_utils::lseek (fil->fil_desc, offset, 0) == -1) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); // msg 30: Can't read a database page db_error(errno); } @@ -2137,7 +2152,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc) const int l = read(fil->fil_desc, p, length); if (l < 0) { - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); // msg 30: Can't read a database page db_error(errno); } @@ -2179,7 +2194,7 @@ static void dba_error(USHORT errcode, const SafeArg& arg) tdba* tddba = tdba::getSpecific(); tddba->page_number = -1; - tddba->uSvc->setServiceStatus(GSTAT_MSG_FAC, errcode, arg); + tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, errcode, arg); if (!tddba->uSvc->isService()) { dba_print(true, errcode, arg); diff --git a/src/utilities/guard/guard.cpp b/src/utilities/guard/guard.cpp index f65a6167e80..d77cb4dbd24 100644 --- a/src/utilities/guard/guard.cpp +++ b/src/utilities/guard/guard.cpp @@ -93,6 +93,7 @@ int CLIB_ROUTINE main( int argc, char **argv) const TEXT* prog_name = argv[0]; const TEXT* pidfilename = 0; int guard_exit_code = 0; + int timeout_term = 3; const TEXT* const* const end = argc + argv; argv++; @@ -117,9 +118,13 @@ int CLIB_ROUTINE main( int argc, char **argv) case 'P': pidfilename = *argv++; break; + case 'T': + timeout_term = atoi(*argv++); + break; default: fprintf(stderr, - "Usage: %s [-signore | -onetime | -forever (default)] [-daemon] [-pidfile filename]\n", + "Usage: %s [-signore | -onetime | -forever (default)] [-daemon] [-pidfile filename] " + "[-timeout seconds (default 3)]\n", prog_name); exit(-1); break; @@ -231,7 +236,7 @@ int CLIB_ROUTINE main( int argc, char **argv) { if (shutdown_child) { - ret_code = UTIL_shutdown_child(child_pid, 3, 1); + ret_code = UTIL_shutdown_child(child_pid, timeout_term, 1); if (ret_code < 0) { gds__log("%s: error while shutting down %s (%d)\n", diff --git a/src/utilities/nbackup/nbackup.cpp b/src/utilities/nbackup/nbackup.cpp index b2a5a621ad6..cefaeb4e216 100644 --- a/src/utilities/nbackup/nbackup.cpp +++ b/src/utilities/nbackup/nbackup.cpp @@ -273,14 +273,18 @@ struct inc_header class NBackup { public: + enum CLEAN_HISTORY_KIND { NONE, DAYS, ROWS }; + NBackup(UtilSvc* _uSvc, const PathName& _database, const string& _username, const string& _role, - const string& _password, bool _run_db_triggers, bool _direct_io, const string& _deco) + const string& _password, bool _run_db_triggers, bool _direct_io, const string& _deco, + CLEAN_HISTORY_KIND cleanHistKind, int keepHistValue) : uSvc(_uSvc), newdb(0), trans(0), database(_database), username(_username), role(_role), password(_password), run_db_triggers(_run_db_triggers), direct_io(_direct_io), dbase(INVALID_HANDLE_VALUE), backup(INVALID_HANDLE_VALUE), - decompress(_deco), childId(0), db_size_pages(0), - m_odsNumber(0), m_silent(false), m_printed(false) + decompress(_deco), m_cleanHistKind(cleanHistKind), m_keepHistValue(keepHistValue), + childId(0), db_size_pages(0), + m_odsNumber(0), m_silent(false), m_printed(false), m_flash_map(false) { // Recognition of local prefix allows to work with // database using TCP/IP loopback while reading file locally. @@ -336,6 +340,8 @@ class NBackup FILE_HANDLE dbase; FILE_HANDLE backup; string decompress; + const CLEAN_HISTORY_KIND m_cleanHistKind; + const int m_keepHistValue; #ifdef WIN_NT HANDLE childId; HANDLE childStdErr; @@ -346,6 +352,7 @@ class NBackup USHORT m_odsNumber; bool m_silent; // are we already handling an exception? bool m_printed; // pr_error() was called to print status vector + bool m_flash_map; // clear mapping cache on attach // IO functions FB_SIZE_T read_file(FILE_HANDLE &file, void *buffer, FB_SIZE_T bufsize); @@ -362,6 +369,7 @@ class NBackup void attach_database(); void detach_database(); string to_system(const PathName& from); + void cleanHistory(); // Create/open database and backup void open_database_write(bool exclusive = false); @@ -577,11 +585,16 @@ void NBackup::create_database() void NBackup::close_database() { + if (dbase == INVALID_HANDLE_VALUE) + return; + #ifdef WIN_NT CloseHandle(dbase); #else close(dbase); #endif + + dbase = INVALID_HANDLE_VALUE; } string NBackup::to_system(const PathName& from) @@ -794,6 +807,10 @@ void NBackup::close_backup() { if (bakname == "stdout") return; + + if (backup == INVALID_HANDLE_VALUE) + return; + #ifdef WIN_NT CloseHandle(backup); if (childId != 0) @@ -818,6 +835,7 @@ void NBackup::close_backup() childId = 0; } #endif + backup = INVALID_HANDLE_VALUE; } void NBackup::fixup_database(bool repl_seq, bool set_readonly) @@ -923,7 +941,7 @@ void NBackup::print_child_stderr() DWORD bytesRead; while (true) { - // Check if pipe have data to read. This is necessary to avoid hung if + // Check if pipe have data to read. This is necessary to avoid hung if // pipe is empty. Ignore read error as ReadFile set bytesRead to zero // in this case and it is enough for our usage. const BOOL ret = PeekNamedPipe(childStdErr, NULL, 1, NULL, &bytesRead, NULL); @@ -947,7 +965,7 @@ void NBackup::print_child_stderr() if (*pEndL == '\n') pEndL++; } - else + else { pEndL = strchr(p, '\n'); if (pEndL) @@ -1009,6 +1027,9 @@ void NBackup::attach_database() if (!run_db_triggers) dpb.insertByte(isc_dpb_no_db_triggers, 1); + if (m_flash_map) + dpb.insertByte(isc_dpb_clear_map, 1); + if (m_silent) { ISC_STATUS_ARRAY temp; @@ -1054,6 +1075,31 @@ void NBackup::internal_lock_database() pr_error(status, "begin backup: commit"); } +void NBackup::cleanHistory() +{ + if (m_cleanHistKind == NONE) + return; + + string sql; + if (m_cleanHistKind == DAYS) + { + sql.printf( + "DELETE FROM RDB$BACKUP_HISTORY WHERE RDB$TIMESTAMP < DATEADD(1 - %i DAY TO CURRENT_DATE)", + m_keepHistValue); + } + else + { + sql.printf( + "DELETE FROM RDB$BACKUP_HISTORY WHERE RDB$TIMESTAMP <= " + "(SELECT RDB$TIMESTAMP FROM RDB$BACKUP_HISTORY ORDER BY RDB$TIMESTAMP DESC " + "OFFSET %i ROWS FETCH FIRST 1 ROW ONLY)", + m_keepHistValue); + } + + if (isc_dsql_execute_immediate(status, &newdb, &trans, 0, sql.c_str(), SQL_DIALECT_CURRENT, NULL)) + pr_error(status, "execute history delete"); +} + void NBackup::get_database_size() { db_size_pages = 0; @@ -1241,7 +1287,7 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname) default: pr_error(status, "fetch history query"); } - isc_dsql_free_statement(status, &stmt, DSQL_close); + isc_dsql_free_statement(status, &stmt, DSQL_drop); if (isc_commit_transaction(status, &trans)) pr_error(status, "commit history query"); } @@ -1295,12 +1341,14 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname) open_database_scan(); // Read database header - char unaligned_header_buffer[RAW_HEADER_SIZE + SECTOR_ALIGNMENT]; + const ULONG ioBlockSize = direct_io ? DIRECT_IO_BLOCK_SIZE : PAGE_ALIGNMENT; + const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize); - auto header = reinterpret_cast( - FB_ALIGN(unaligned_header_buffer, SECTOR_ALIGNMENT)); + Array header_buffer; + Ods::header_page* header = reinterpret_cast + (header_buffer.getAlignedBuffer(headerSize, ioBlockSize)); - if (read_file(dbase, header, RAW_HEADER_SIZE) != RAW_HEADER_SIZE) + if (read_file(dbase, header, headerSize) != headerSize) status_exception::raise(Arg::Gds(isc_nbackup_err_eofhdrdb) << dbname.c_str() << Arg::Num(1)); if (!Ods::isSupported(header)) @@ -1316,11 +1364,9 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname) if ((header->hdr_flags & Ods::hdr_backup_mask) != Ods::hdr_nbak_stalled) status_exception::raise(Arg::Gds(isc_nbackup_db_notlock) << Arg::Num(header->hdr_flags)); - Array unaligned_page_buffer; - { // scope - UCHAR* buf = unaligned_page_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT); - page_buff = reinterpret_cast(FB_ALIGN(buf, SECTOR_ALIGNMENT)); - } // end scope + Array page_buffer; + Ods::pag* page_buff = reinterpret_cast + (page_buffer.getAlignedBuffer(header->hdr_page_size, ioBlockSize)); ULONG db_size = db_size_pages; seek_file(dbase, 0); @@ -1383,12 +1429,10 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname) ULONG scnsSlot = 0; const ULONG pagesPerSCN = Ods::pagesPerSCN(header->hdr_page_size); - Array unaligned_scns_buffer; - Ods::scns_page* scns = NULL, *scns_buf = NULL; - { // scope - UCHAR* buf = unaligned_scns_buffer.getBuffer(header->hdr_page_size + SECTOR_ALIGNMENT); - scns_buf = reinterpret_cast(FB_ALIGN(buf, SECTOR_ALIGNMENT)); - } + Array scns_buffer; + Ods::scns_page* scns = NULL; + Ods::scns_page* scns_buf = reinterpret_cast + (scns_buffer.getAlignedBuffer(header->hdr_page_size, ioBlockSize)); while (true) { @@ -1558,6 +1602,9 @@ void NBackup::backup_database(int level, Guid& guid, const PathName& fname) in_sqlda->sqlvar[3].sqlind = &null_flag; if (isc_dsql_execute(status, &trans, &stmt, 1, in_sqlda)) pr_error(status, "execute history insert"); + + cleanHistory(); + isc_dsql_free_statement(status, &stmt, DSQL_drop); if (isc_commit_transaction(status, &trans)) pr_error(status, "commit history insert"); @@ -1672,6 +1719,14 @@ void NBackup::restore_database(const BackupFiles& files, bool repl_seq, bool inc { close_database(); fixup_database(repl_seq, inc_rest); + + m_silent = true; + m_flash_map = true; + run_db_triggers = false; + + attach_database(); + detach_database(); + return; } if (!inc_rest || curLevel) @@ -1819,8 +1874,11 @@ int NBACKUP_main(UtilSvc* uSvc) StaticStatusVector status; e.stuffException(status); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + + UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); + exit_code = FB_FAILURE; } catch (const Exception& e) @@ -1830,8 +1888,11 @@ int NBACKUP_main(UtilSvc* uSvc) StaticStatusVector status; e.stuffException(status); - uSvc->initStatus(); - uSvc->setServiceStatus(status.begin()); + + UtilSvc::StatusAccessor sa = uSvc->getStatusAccessor(); + sa.init(); + sa.setServiceStatus(status.begin()); + exit_code = FB_FAILURE; } @@ -1861,6 +1922,9 @@ void nbackup(UtilSvc* uSvc) Guid guid; bool print_size = false, version = false, inc_rest = false, repl_seq = false; string onOff; + bool cleanHistory = false; + NBackup::CLEAN_HISTORY_KIND cleanHistKind = NBackup::CLEAN_HISTORY_KIND::NONE; + int keepHistValue = 0; const Switches switches(nbackup_action_in_sw_table, FB_NELEM(nbackup_action_in_sw_table), false, true); @@ -2044,6 +2108,37 @@ void nbackup(UtilSvc* uSvc) repl_seq = true; break; + case IN_SW_NBK_CLEAN_HISTORY: + cleanHistory = true; + break; + + case IN_SW_NBK_KEEP: + if (cleanHistKind != NBackup::CLEAN_HISTORY_KIND::NONE) + usage(uSvc, isc_nbackup_second_keep_switch); + + if (++itr >= argc) + missingParameterForSwitch(uSvc, argv[itr - 1]); + + keepHistValue = atoi(argv[itr]); + if (keepHistValue < 1) + usage(uSvc, isc_nbackup_wrong_param, argv[itr - 1]); + + if (++itr >= argc) + missingParameterForSwitch(uSvc, argv[itr - 1]); + + { // scope + string keepUnit = argv[itr]; + keepUnit.upper(); + + if (string("DAYS").find(keepUnit) == 0) + cleanHistKind = NBackup::CLEAN_HISTORY_KIND::DAYS; + else if (string("ROWS").find(keepUnit) == 0) + cleanHistKind = NBackup::CLEAN_HISTORY_KIND::ROWS; + else + usage(uSvc, isc_nbackup_wrong_param, argv[itr - 2]); + } + break; + default: usage(uSvc, isc_nbackup_unknown_switch, argv[itr]); break; @@ -2074,7 +2169,22 @@ void nbackup(UtilSvc* uSvc) usage(uSvc, isc_nbackup_seq_misuse); } - NBackup nbk(uSvc, database, username, role, password, run_db_triggers, direct_io, decompress); + if (cleanHistory) + { + // CLEAN_HISTORY could be used with BACKUP only + if (op != nbBackup) + usage(uSvc, isc_nbackup_clean_hist_misuse); + + if (cleanHistKind == NBackup::CLEAN_HISTORY_KIND::NONE) + usage(uSvc, isc_nbackup_keep_hist_missed); + } + else if (cleanHistKind != NBackup::CLEAN_HISTORY_KIND::NONE) + { + usage(uSvc, isc_nbackup_clean_hist_missed); + } + + NBackup nbk(uSvc, database, username, role, password, run_db_triggers, direct_io, + decompress, cleanHistKind, keepHistValue); try { switch (op) diff --git a/src/utilities/nbackup/nbkswi.h b/src/utilities/nbackup/nbkswi.h index 8daa971c974..363aa217073 100644 --- a/src/utilities/nbackup/nbkswi.h +++ b/src/utilities/nbackup/nbkswi.h @@ -49,6 +49,8 @@ const int IN_SW_NBK_DECOMPRESS = 14; const int IN_SW_NBK_ROLE = 15; const int IN_SW_NBK_INPLACE = 16; const int IN_SW_NBK_SEQUENCE = 17; +const int IN_SW_NBK_CLEAN_HISTORY = 18; +const int IN_SW_NBK_KEEP = 19; static const struct Switches::in_sw_tab_t nbackup_in_sw_table [] = @@ -75,6 +77,8 @@ static const struct Switches::in_sw_tab_t nbackup_action_in_sw_table [] = {IN_SW_NBK_SIZE, 0, "SIZE", 0, 0, 0, false, false, 17, 1, NULL, nboSpecial}, {IN_SW_NBK_DECOMPRESS, 0, "DECOMPRESS", 0, 0, 0, false, false, 74, 2, NULL, nboSpecial}, {IN_SW_NBK_SEQUENCE, 0, "SEQUENCE", 0, 0, 0, false, false, 80, 3, NULL, nboSpecial}, + {IN_SW_NBK_CLEAN_HISTORY, isc_spb_nbk_clean_history, "CLEAN_HISTORY", 0, 0, 0, false, false, 82, 10, NULL, nboSpecial}, + {IN_SW_NBK_KEEP, 0, "KEEP", 0, 0, 0, false, false, 83, 1, NULL, nboSpecial}, {IN_SW_NBK_NODBTRIG, 0, "T", 0, 0, 0, false, false, 0, 1, NULL, nboGeneral}, {IN_SW_NBK_NODBTRIG, 0, "NODBTRIGGERS", 0, 0, 0, false, false, 16, 3, NULL, nboGeneral}, {IN_SW_NBK_USER_NAME, 0, "USER", 0, 0, 0, false, false, 13, 1, NULL, nboGeneral}, diff --git a/src/utilities/ntrace/PluginLogWriter.cpp b/src/utilities/ntrace/PluginLogWriter.cpp index 3a4e830f170..1a09af23a62 100644 --- a/src/utilities/ntrace/PluginLogWriter.cpp +++ b/src/utilities/ntrace/PluginLogWriter.cpp @@ -26,7 +26,10 @@ */ #include "PluginLogWriter.h" +#include "../common/isc_proto.h" #include "../common/classes/init.h" +#include "../common/ThreadStart.h" +#include "../common/file_params.h" #include "../common/classes/RefMutex.h" #include "../common/os/os_utils.h" @@ -50,18 +53,36 @@ void strerror_r(int err, char* buf, size_t bufSize) } #endif +void getMappedFileName(PathName& file, PathName& mapFile) +{ + const ULONG hash = file.hash(0xFFFFFFFF); + mapFile.printf("%s_%08x", FB_TRACE_LOG_MUTEX, hash); +} + PluginLogWriter::PluginLogWriter(const char* fileName, size_t maxSize) : m_fileName(*getDefaultMemoryPool()), m_fileHandle(-1), - m_maxSize(maxSize) + m_maxSize(maxSize), + m_sharedMemory(NULL) { m_fileName = fileName; -#ifdef WIN_NT - PathName mutexName("fb_mutex_"); - mutexName.append(m_fileName); + PathName logFile(fileName); + PathName mapFile; + getMappedFileName(logFile, mapFile); - checkMutex("init", ISC_mutex_init(&m_mutex, mutexName.c_str())); + try + { + m_sharedMemory.reset(FB_NEW_POOL(getPool()) + SharedMemory(mapFile.c_str(), sizeof(PluginLogWriterHeader), this)); + } + catch (const Exception& ex) + { + iscLogException("PluginLogWriter: Cannot initialize the shared memory region", ex); + throw; + } + +#ifdef WIN_NT Guard guard(this); #endif @@ -75,10 +96,6 @@ PluginLogWriter::~PluginLogWriter() if (m_fileHandle != -1) ::close(m_fileHandle); - -#ifdef WIN_NT - ISC_mutex_fini(&m_mutex); -#endif } SINT64 PluginLogWriter::seekToEnd() @@ -122,6 +139,8 @@ FB_SIZE_T PluginLogWriter::write(const void* buf, FB_SIZE_T size) #ifdef WIN_NT Guard guard(this); +#else + Guard guard(m_maxSize ? this : 0); #endif if (m_fileHandle < 0) @@ -136,23 +155,41 @@ FB_SIZE_T PluginLogWriter::write(const void* buf, FB_SIZE_T size) if (m_maxSize && (fileSize > m_maxSize)) { - const TimeStamp stamp(TimeStamp::getCurrentTimeStamp()); - struct tm times; - stamp.decode(×); - PathName newName; - const FB_SIZE_T last_dot_pos = m_fileName.rfind("."); - if (last_dot_pos > 0) - { - PathName log_name = m_fileName.substr(0, last_dot_pos); - PathName log_ext = m_fileName.substr(last_dot_pos + 1, m_fileName.length()); - newName.printf("%s.%04d-%02d-%02dT%02d-%02d-%02d.%s", log_name.c_str(), times.tm_year + 1900, - times.tm_mon + 1, times.tm_mday, times.tm_hour, times.tm_min, times.tm_sec, log_ext.c_str()); - } - else + + while (true) { - newName.printf("%s.%04d-%02d-%02dT%02d-%02d-%02d", m_fileName.c_str(), times.tm_year + 1900, - times.tm_mon + 1, times.tm_mday, times.tm_hour, times.tm_min, times.tm_sec); + const TimeStamp stamp(TimeStamp::getCurrentTimeStamp()); + struct tm times; + int fractions; + stamp.decode(×, &fractions); + + const FB_SIZE_T last_dot_pos = m_fileName.rfind("."); + if (last_dot_pos > 0) + { + PathName log_name = m_fileName.substr(0, last_dot_pos); + PathName log_ext = m_fileName.substr(last_dot_pos + 1, m_fileName.length()); + newName.printf("%s.%04d-%02d-%02dT%02d-%02d-%02d.%04d.%s", log_name.c_str(), times.tm_year + 1900, + times.tm_mon + 1, times.tm_mday, times.tm_hour, times.tm_min, times.tm_sec, fractions, log_ext.c_str()); + } + else + { + newName.printf("%s.%04d-%02d-%02dT%02d-%02d-%02d.%04d", m_fileName.c_str(), times.tm_year + 1900, + times.tm_mon + 1, times.tm_mday, times.tm_hour, times.tm_min, times.tm_sec, fractions); + } + + // Check if the file with the given name exists. If it doesn't, break the loop. + struct stat st; + + if (stat(newName.c_str(), &st)) + { + // errno == ENOENT is expected here. But if it's another error, we can still + // break the loop and try to rename the file. For example, if there is a + // problem with permissions, it will be caught on MoveFile/rename call. + break; + } + + Thread::sleep(10); } #ifdef WIN_NT @@ -221,31 +258,28 @@ void PluginLogWriter::checkErrno(const char* operation) operation, m_fileName.c_str(), strErr); } -#ifdef WIN_NT -void PluginLogWriter::checkMutex(const TEXT* string, int state) +void PluginLogWriter::mutexBug(int state, const TEXT* string) { - if (state) - { - TEXT msg[BUFFER_TINY]; + TEXT msg[BUFFER_TINY]; - sprintf(msg, "PluginLogWriter: mutex %s error, status = %d", string, state); - gds__log(msg); + sprintf(msg, "PluginLogWriter: mutex %s error, status = %d", string, state); + fb_utils::logAndDie(msg); +} - fprintf(stderr, "%s\n", msg); - exit(FINI_ERROR); - } +bool PluginLogWriter::initialize(SharedMemoryBase* sm, bool init) +{ + return true; } void PluginLogWriter::lock() { - checkMutex("lock", ISC_mutex_lock(&m_mutex)); + m_sharedMemory->mutexLock(); } void PluginLogWriter::unlock() { - checkMutex("unlock", ISC_mutex_unlock(&m_mutex)); + m_sharedMemory->mutexUnlock(); } -#endif // WIN_NT const unsigned int IDLE_TIMEOUT = 30; // seconds diff --git a/src/utilities/ntrace/PluginLogWriter.h b/src/utilities/ntrace/PluginLogWriter.h index 7624775d40b..ea1be063491 100644 --- a/src/utilities/ntrace/PluginLogWriter.h +++ b/src/utilities/ntrace/PluginLogWriter.h @@ -48,8 +48,14 @@ #include +// Empty header. We need it to get shared mutex using SharedMemory +struct PluginLogWriterHeader : public Firebird::MemoryHeader +{ +}; + class PluginLogWriter FB_FINAL : - public Firebird::RefCntIface > + public Firebird::RefCntIface >, + public Firebird::IpcObject { public: PluginLogWriter(const char* fileName, size_t maxSize); @@ -73,34 +79,37 @@ class PluginLogWriter FB_FINAL : // same file simultaneously, therefore we used our fastMutex for this // purposes. On Posix's platforms we honour O_APPEND flag which works // better as in this case syncronization is performed by OS kernel itself. -#ifdef WIN_NT - static void checkMutex(const TEXT*, int); + // Mutex on Posix is needed to rotate log file. + + void mutexBug(int osErrorCode, const char* text); + bool initialize(Firebird::SharedMemoryBase*, bool); + void lock(); void unlock(); - struct Firebird::mtx m_mutex; - class Guard { public: - explicit Guard(PluginLogWriter* log) : m_log(*log) + explicit Guard(PluginLogWriter* log) : m_log(log) { - m_log.lock(); + if (m_log) + m_log->lock(); } ~Guard() { - m_log.unlock(); + if (m_log) + m_log->unlock(); } private: - PluginLogWriter& m_log; + PluginLogWriter* m_log; }; -#endif Firebird::PathName m_fileName; int m_fileHandle; size_t m_maxSize; + Firebird::AutoPtr > m_sharedMemory; typedef Firebird::TimerImpl IdleTimer; Firebird::RefPtr m_idleTimer; diff --git a/src/utilities/ntrace/TraceConfiguration.cpp b/src/utilities/ntrace/TraceConfiguration.cpp index 7daabd31269..3958c6399e6 100644 --- a/src/utilities/ntrace/TraceConfiguration.cpp +++ b/src/utilities/ntrace/TraceConfiguration.cpp @@ -28,6 +28,8 @@ #include "TraceConfiguration.h" #include "../../common/SimilarToRegex.h" #include "../../common/isc_f_proto.h" +#include "../../common/db_alias.h" +#include "../../common/os/path_utils.h" using namespace Firebird; @@ -45,6 +47,7 @@ void TraceCfgReader::readTraceConfiguration(const char* text, if (!found && el->name == #NAME) { \ Firebird::PathName temp; \ expandPattern(el, temp); \ + PathUtils::fixupSeparators(temp.begin()); \ m_config.NAME = temp.c_str(); \ found = true; \ } @@ -69,7 +72,8 @@ void TraceCfgReader::readTraceConfiguration(const char* text, void TraceCfgReader::readConfig() { - ConfigFile cfgFile(ConfigFile::USE_TEXT, m_text, ConfigFile::HAS_SUB_CONF | ConfigFile::NATIVE_ORDER); + ConfigFile cfgFile(ConfigFile::USE_TEXT, m_text, ConfigFile::HAS_SUB_CONF | ConfigFile::NATIVE_ORDER + | ConfigFile::REGEXP_SUPPORT); m_subpatterns[0].start = 0; m_subpatterns[0].end = m_databaseName.length(); diff --git a/src/utilities/ntrace/TracePluginImpl.cpp b/src/utilities/ntrace/TracePluginImpl.cpp index a3564e96b91..aa0a7d078b9 100644 --- a/src/utilities/ntrace/TracePluginImpl.cpp +++ b/src/utilities/ntrace/TracePluginImpl.cpp @@ -94,10 +94,10 @@ TracePluginImpl::TracePluginImpl(IPluginBase* plugin, logWriter(initInfo->getLogWriter()), config(configuration), record(*getDefaultMemoryPool()), - connections(getDefaultMemoryPool()), - transactions(getDefaultMemoryPool()), - statements(getDefaultMemoryPool()), - services(getDefaultMemoryPool()), + connections(*getDefaultMemoryPool()), + transactions(*getDefaultMemoryPool()), + statements(*getDefaultMemoryPool()), + services(*getDefaultMemoryPool()), include_codes(*getDefaultMemoryPool()), exclude_codes(*getDefaultMemoryPool()) { @@ -1586,7 +1586,7 @@ void TracePluginImpl::register_sql_statement(ITraceSQLStatement* statement) stmt_data.description = FB_NEW_POOL(*getDefaultMemoryPool()) string(*getDefaultMemoryPool()); if (stmt_data.id) { - stmt_data.description->printf(NEWLINE "Statement %d:", stmt_data.id); + stmt_data.description->printf(NEWLINE "Statement %" SQUADFORMAT":", stmt_data.id); } string temp(*getDefaultMemoryPool()); @@ -1685,8 +1685,10 @@ void TracePluginImpl::log_event_dsql_free(ITraceDatabaseConnection* connection, void TracePluginImpl::log_event_dsql_execute(ITraceDatabaseConnection* connection, ITraceTransaction* transaction, ITraceSQLStatement* statement, - bool started, ntrace_result_t req_result) + bool started, unsigned number, ntrace_result_t req_result) { + const bool restart = started && (number > 0); + if (started && !config.log_statement_start) return; @@ -1698,6 +1700,13 @@ void TracePluginImpl::log_event_dsql_execute(ITraceDatabaseConnection* connectio if (config.time_threshold && info && info->pin_time < config.time_threshold) return; + if (restart) + { + string temp; + temp.printf("Restarted %d time(s)" NEWLINE, number); + record.append(temp); + } + ITraceParams *params = statement->getInputs(); if (params && params->getCount()) { @@ -1716,26 +1725,31 @@ void TracePluginImpl::log_event_dsql_execute(ITraceDatabaseConnection* connectio appendTableCounts(info); } - const char* event_type; + string event_type; + + if (restart) + event_type = "EXECUTE_STATEMENT_RESTART"; + else if (started) + event_type = "EXECUTE_STATEMENT_START"; + else + event_type = "EXECUTE_STATEMENT_FINISH"; + switch (req_result) { case ITracePlugin::RESULT_SUCCESS: - event_type = started ? "EXECUTE_STATEMENT_START" : - "EXECUTE_STATEMENT_FINISH"; break; case ITracePlugin::RESULT_FAILED: - event_type = started ? "FAILED EXECUTE_STATEMENT_START" : - "FAILED EXECUTE_STATEMENT_FINISH"; + event_type.insert(0, "FAILED "); break; case ITracePlugin::RESULT_UNAUTHORIZED: - event_type = started ? "UNAUTHORIZED EXECUTE_STATEMENT_START" : - "UNAUTHORIZED EXECUTE_STATEMENT_FINISH"; + event_type.insert(0, "UNAUTHORIZED "); break; default: event_type = "Unknown event at executing statement"; break; } - logRecordStmt(event_type, connection, transaction, statement, true); + + logRecordStmt(event_type.c_str(), connection, transaction, statement, true); } @@ -1934,7 +1948,7 @@ void TracePluginImpl::register_service(ITraceServiceConnection* service) if (!username.isEmpty()) { const char* role = service->getRoleName(); - if (role && *role) + if (role && *role) { username.append(":"); username.append(role); @@ -2520,7 +2534,23 @@ FB_BOOLEAN TracePluginImpl::trace_dsql_execute(ITraceDatabaseConnection* connect { try { - log_event_dsql_execute(connection, transaction, statement, started, req_result); + log_event_dsql_execute(connection, transaction, statement, started, 0, req_result); + return true; + } + catch (const Firebird::Exception& ex) + { + marshal_exception(ex); + return false; + } +} + +FB_BOOLEAN TracePluginImpl::trace_dsql_restart(ITraceDatabaseConnection* connection, + ITraceTransaction* transaction, ITraceSQLStatement* statement, unsigned number) +{ + try + { + log_event_dsql_execute(connection, transaction, statement, true, number, + ITracePlugin::RESULT_SUCCESS); return true; } catch (const Firebird::Exception& ex) diff --git a/src/utilities/ntrace/TracePluginImpl.h b/src/utilities/ntrace/TracePluginImpl.h index 95ebbfb2f36..de28ad946a1 100644 --- a/src/utilities/ntrace/TracePluginImpl.h +++ b/src/utilities/ntrace/TracePluginImpl.h @@ -67,8 +67,7 @@ class TracePluginImpl FB_FINAL : } }; - typedef Firebird::BePlusTree - ConnectionsTree; + typedef Firebird::BePlusTree ConnectionsTree; // Data for tracked (active) transactions struct TransactionData @@ -89,8 +88,7 @@ class TracePluginImpl FB_FINAL : } }; - typedef Firebird::BePlusTree - TransactionsTree; + typedef Firebird::BePlusTree TransactionsTree; // Data for tracked (active) statements struct StatementData @@ -104,8 +102,7 @@ class TracePluginImpl FB_FINAL : } }; - typedef Firebird::BePlusTree - StatementsTree; + typedef Firebird::BePlusTree StatementsTree; typedef void* ServiceId; struct ServiceData @@ -127,8 +124,7 @@ class TracePluginImpl FB_FINAL : } }; - typedef Firebird::BePlusTree - ServicesTree; + typedef Firebird::BePlusTree ServicesTree; TracePluginImpl(Firebird::IPluginBase* factory, const TracePluginConfig& configuration, Firebird::ITraceInitInfo* initInfo); @@ -242,7 +238,7 @@ class TracePluginImpl FB_FINAL : Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceSQLStatement* statement, unsigned short option); void log_event_dsql_execute( Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, - Firebird::ITraceSQLStatement* statement, bool started, unsigned req_result); + Firebird::ITraceSQLStatement* statement, bool started, unsigned number, unsigned req_result); void log_event_blr_compile( Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, @@ -303,6 +299,8 @@ class TracePluginImpl FB_FINAL : unsigned option); FB_BOOLEAN trace_dsql_execute(Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, Firebird::ITraceSQLStatement* statement, FB_BOOLEAN started, unsigned req_result); + FB_BOOLEAN trace_dsql_restart(Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, + Firebird::ITraceSQLStatement* statement, unsigned number); // BLR requests FB_BOOLEAN trace_blr_compile(Firebird::ITraceDatabaseConnection* connection, Firebird::ITraceTransaction* transaction, diff --git a/src/utilities/ntrace/traceplugin.cpp b/src/utilities/ntrace/traceplugin.cpp index 39cde971451..6fe0c013b42 100644 --- a/src/utilities/ntrace/traceplugin.cpp +++ b/src/utilities/ntrace/traceplugin.cpp @@ -115,7 +115,7 @@ void registerTrace(Firebird::IPluginManager* iPlugin) } -extern "C" void FB_EXPORTED FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) +extern "C" FB_DLL_EXPORT void FB_PLUGIN_ENTRY_POINT(Firebird::IMaster* master) { Firebird::CachedMasterInterface::set(master); registerTrace(Firebird::PluginManagerInterfacePtr()); diff --git a/src/yvalve/DistributedTransaction.cpp b/src/yvalve/DistributedTransaction.cpp index 936db41ddbb..b55a86c83b9 100644 --- a/src/yvalve/DistributedTransaction.cpp +++ b/src/yvalve/DistributedTransaction.cpp @@ -32,6 +32,7 @@ #include "../yvalve/MasterImplementation.h" #include "../common/classes/rwlock.h" +#include "../common/classes/ClumpletReader.h" #include "firebird/impl/inf_pub.h" #include "../common/isc_proto.h" #include "../jrd/acl.h" @@ -61,8 +62,15 @@ class DTransaction FB_FINAL : public RefCntIface SubArray; typedef HalfStaticArray TdrBuffer; SubArray sub; @@ -97,39 +105,29 @@ bool DTransaction::buildPrepareInfo(CheckStatusWrapper* status, TdrBuffer& tdr, // limit MAX_SSHORT is chosen cause for old API larger buffer cause problems UCHAR* buf = bigBuffer.getBuffer(MAX_SSHORT); from->getInfo(status, sizeof(PREPARE_TR_INFO), PREPARE_TR_INFO, bigBuffer.getCount(), buf); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return false; - UCHAR* const end = bigBuffer.end(); - - while (buf < end) + for (ClumpletReader p(ClumpletReader::InfoResponse, buf, bigBuffer.getCount()); !p.isEof(); p.moveNext()) { - UCHAR item = buf[0]; - ++buf; - const USHORT length = (USHORT) gds__vax_integer(buf, 2); + const USHORT length = (USHORT) p.getClumpLength(); // Prevent information out of sync. UCHAR lengthByte = length > MAX_UCHAR ? MAX_UCHAR : length; - buf += 2; - switch(item) + switch(p.getClumpTag()) { case isc_info_tra_id: tdr.add(TDR_TRANSACTION_ID); tdr.add(lengthByte); - tdr.add(buf, lengthByte); + tdr.add(p.getBytes(), lengthByte); break; case fb_info_tra_dbpath: tdr.add(TDR_DATABASE_PATH); tdr.add(lengthByte); - tdr.add(buf, lengthByte); + tdr.add(p.getBytes(), lengthByte); break; - - case isc_info_end: - return true; } - - buf += length; } return true; @@ -178,7 +176,7 @@ void DTransaction::getInfo(CheckStatusWrapper* status, if (sub[i]) { sub[i]->getInfo(status, itemsLength, items, bufferLength, buffer); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) { return; } @@ -232,7 +230,7 @@ void DTransaction::prepare(CheckStatusWrapper* status, { sub[i]->prepare(status, msgLength, message); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; } } @@ -245,14 +243,14 @@ void DTransaction::prepare(CheckStatusWrapper* status, } } -void DTransaction::commit(CheckStatusWrapper* status) +void DTransaction::internalCommit(CheckStatusWrapper* status) { try { status->init(); prepare(status, 0, NULL); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) { return; } @@ -265,7 +263,7 @@ void DTransaction::commit(CheckStatusWrapper* status) if (sub[i]) { sub[i]->commit(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; sub[i] = NULL; @@ -295,12 +293,10 @@ void DTransaction::commitRetaining(CheckStatusWrapper* status) if (sub[i]) { sub[i]->commitRetaining(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; } } - - limbo = true; // ASF: why do retaining marks limbo? } catch (const Exception& ex) { @@ -308,7 +304,7 @@ void DTransaction::commitRetaining(CheckStatusWrapper* status) } } -void DTransaction::rollback(CheckStatusWrapper* status) +void DTransaction::internalRollback(CheckStatusWrapper* status) { try { @@ -322,7 +318,7 @@ void DTransaction::rollback(CheckStatusWrapper* status) if (sub[i]) { sub[i]->rollback(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; sub[i] = NULL; @@ -349,12 +345,10 @@ void DTransaction::rollbackRetaining(CheckStatusWrapper* status) if (sub[i]) { sub[i]->rollbackRetaining(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; } } - - limbo = true; // ASF: why do retaining marks limbo? } catch (const Exception& ex) { @@ -362,7 +356,7 @@ void DTransaction::rollbackRetaining(CheckStatusWrapper* status) } } -void DTransaction::disconnect(CheckStatusWrapper* status) +void DTransaction::internalDisconnect(CheckStatusWrapper* status) { try { @@ -378,7 +372,7 @@ void DTransaction::disconnect(CheckStatusWrapper* status) if (sub[i]) { sub[i]->disconnect(status); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return; sub[i] = NULL; @@ -391,6 +385,43 @@ void DTransaction::disconnect(CheckStatusWrapper* status) } } +void DTransaction::deprecatedCommit(CheckStatusWrapper* status) +{ + internalCommit(status); +} + +void DTransaction::deprecatedRollback(CheckStatusWrapper* status) +{ + internalRollback(status); +} + +void DTransaction::deprecatedDisconnect(CheckStatusWrapper* status) +{ + internalDisconnect(status); +} + +void DTransaction::disconnect(CheckStatusWrapper* status) +{ + internalDisconnect(status); + if (status->isEmpty()) + release(); +} + +void DTransaction::rollback(CheckStatusWrapper* status) +{ + internalRollback(status); + if (status->isEmpty()) + release(); +} + +void DTransaction::commit(CheckStatusWrapper* status) +{ + internalCommit(status); + if (status->isEmpty()) + release(); +} + + // To do: check the maximum allowed dbs in a two phase commit. // Q: what is the maximum? DTransaction* DTransaction::join(CheckStatusWrapper* status, ITransaction* transaction) @@ -528,7 +559,7 @@ YTransaction* DtcStart::start(CheckStatusWrapper* status) RefPtr dtransaction(FB_NEW DTransaction); unsigned cnt = components.getCount(); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) status_exception::raise(status); if (cnt == 0) (Arg::Gds(isc_random) << "No attachments to start distributed transaction provided").raise(); @@ -536,11 +567,11 @@ YTransaction* DtcStart::start(CheckStatusWrapper* status) for (unsigned i = 0; i < cnt; ++i) { ITransaction* started = components[i].att->startTransaction(status, components[i].tpbLen, components[i].tpb); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) status_exception::raise(status); dtransaction->join(status, started); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) { started->release(); status_exception::raise(status); @@ -570,12 +601,12 @@ YTransaction* Dtc::join(CheckStatusWrapper* status, ITransaction* one, ITransact RefPtr dtransaction(FB_NEW DTransaction); dtransaction->join(status, one); - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return NULL; dtransaction->join(status, two); /* We must not return NULL - first transaction is available only inside dtransaction - if (status->getState() & Firebird::IStatus::STATE_ERRORS) + if (status->getState() & IStatus::STATE_ERRORS) return NULL; */ diff --git a/src/yvalve/MasterImplementation.cpp b/src/yvalve/MasterImplementation.cpp index 3ed955e69c7..29eaf528c08 100644 --- a/src/yvalve/MasterImplementation.cpp +++ b/src/yvalve/MasterImplementation.cpp @@ -145,7 +145,7 @@ FB_BOOLEAN MasterImplementation::getProcessExiting() return true; #ifdef WIN_NT - // Sometime, when user process exits not calling fb_shutdown and timer thread should + // Sometime, when user process exits not calling fb_shutdown and timer thread should // be terminated already, wait for its handle with zero timeout returns WAIT_TIMEOUT. // Usage of small non-zero timeout seems fixed such cases. @@ -219,10 +219,10 @@ void TimerEntry::cleanup() ISC_UINT64 curTime() { - ISC_UINT64 rc = fb_utils::query_performance_counter(); + double rc = fb_utils::query_performance_counter(); rc *= 1000000; rc /= fb_utils::query_performance_frequency(); - return rc; + return ISC_UINT64(rc); } TimerEntry* getTimer(ITimer* timer) @@ -404,6 +404,11 @@ Mutex& pauseTimer() return timerPause; } +bool timerThreadStopped() +{ + return stopTimerThread.value() != 0; +} + } // namespace Why diff --git a/src/yvalve/MasterImplementation.h b/src/yvalve/MasterImplementation.h index 416a1f070c7..08f3121cc93 100644 --- a/src/yvalve/MasterImplementation.h +++ b/src/yvalve/MasterImplementation.h @@ -72,6 +72,8 @@ namespace Why void shutdownTimers(); Firebird::Mutex& pauseTimer(); + + bool timerThreadStopped(); } // namespace Why #endif // YVALVE_MASTER_IMPLEMENTATION_H diff --git a/src/yvalve/PluginManager.cpp b/src/yvalve/PluginManager.cpp index 2dcb9c561bb..3ad196156df 100644 --- a/src/yvalve/PluginManager.cpp +++ b/src/yvalve/PluginManager.cpp @@ -30,11 +30,13 @@ #include "../yvalve/why_proto.h" #include "../common/os/path_utils.h" +#include "../common/os/fbsyslog.h" #include "../common/StatusArg.h" #include "../common/isc_proto.h" #include "../common/classes/fb_string.h" #include "../common/classes/init.h" #include "../common/classes/semaphore.h" +#include "../common/classes/RefMutex.h" #include "../common/config/config.h" #include "../common/config/config_file.h" #include "../common/utils_proto.h" @@ -42,6 +44,8 @@ #include "../common/classes/GenericMap.h" #include "../common/db_alias.h" #include "../common/dllinst.h" +#include "../common/file_params.h" +#include "../common/status.h" #include "../yvalve/config/os/config_root.h" @@ -246,8 +250,7 @@ namespace IConfig* findPluginConfig(ConfigFile* pluginLoaderConfig, const PathName& confName) { - LocalStatus ls; - CheckStatusWrapper s(&ls); + FbLocalStatus ls; if (pluginLoaderConfig) { @@ -266,26 +269,39 @@ namespace } } - IConfig* rc = PluginManagerInterfacePtr()->getConfig(&s, confName.nullStr()); - check(&s); + IConfig* rc = PluginManagerInterfacePtr()->getConfig(&ls, confName.nullStr()); + check(&ls); return rc; } // Plugins registered when loading plugin module. - // This is POD object - no dtor, only simple data types inside. struct RegisteredPlugin { RegisteredPlugin(IPluginFactory* f, const char* nm, unsigned int t) : factory(f), name(nm), type(t) { } + RegisteredPlugin(MemoryPool& p, IPluginFactory* f, const char* nm, unsigned int t) + : factory(f), name(p), type(t) + { + name = nm; + } + RegisteredPlugin() - : factory(NULL), name(NULL), type(0) + : factory(NULL), name(), type(0) + { } + + RegisteredPlugin(MemoryPool& p) + : factory(NULL), name(p), type(0) + { } + + RegisteredPlugin(MemoryPool& p, const RegisteredPlugin& from) + : factory(from.factory), name(p, from.name), type(from.type) { } IPluginFactory* factory; - const char* name; + PathName name; unsigned int type; }; @@ -396,7 +412,7 @@ namespace PathName name; Firebird::AutoPtr module; Firebird::IPluginModule* cleanup; - HalfStaticArray regPlugins; + ObjectsArray regPlugins; PluginModule* next; PluginModule** prev; }; @@ -440,7 +456,7 @@ namespace const PathName& pplugName) : module(pmodule), regPlugin(preg), pluginLoaderConfig(pconfig), confName(getPool(), pconfName), plugName(getPool(), pplugName), - delay(DEFAULT_DELAY) + processingDelayedDelete(false), delay(DEFAULT_DELAY) { if (pluginLoaderConfig.hasData()) { @@ -457,7 +473,7 @@ namespace #ifdef DEBUG_PLUGINS RegisteredPlugin& r(module->getPlugin(regPlugin)); fprintf(stderr, " ConfiguredPlugin %s module %s registered as %s type %d order %d\n", - plugName.c_str(), module->getName(), r.name, r.type, regPlugin); + plugName.c_str(), module->getName(), r.name.c_str(), r.type, regPlugin); #endif } @@ -501,6 +517,8 @@ namespace { } int release(); + static void processDelayedDelete(); + private: ~ConfiguredPlugin() {} void destroy(); @@ -510,6 +528,7 @@ namespace RefPtr pluginLoaderConfig; PathName confName; PathName plugName; + bool processingDelayedDelete; static const FB_UINT64 DEFAULT_DELAY = 1000000 * 60; // 1 min FB_UINT64 delay; @@ -572,12 +591,11 @@ namespace ~FactoryParameter() { #ifdef DEBUG_PLUGINS - fprintf(stderr, "~FactoryParameter places configuredPlugin %s in unload query for %d seconds\n", + fprintf(stderr, "~FactoryParameter places configuredPlugin %s in unload query for %lld seconds\n", configuredPlugin->getPlugName(), configuredPlugin->getReleaseDelay() / 1000000); #endif - LocalStatus ls; - CheckStatusWrapper s(&ls); - TimerInterfacePtr()->start(&s, configuredPlugin, configuredPlugin->getReleaseDelay()); + FbLocalStatus ls; + TimerInterfacePtr()->start(&ls, configuredPlugin, configuredPlugin->getReleaseDelay()); // errors are ignored here - configuredPlugin will be released at once } @@ -590,18 +608,17 @@ namespace FactoryParameter* par = FB_NEW FactoryParameter(this, firebirdConf); par->addRef(); - LocalStatus ls; - CheckStatusWrapper s(&ls); - IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(&s, par); + FbLocalStatus ls; + IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(&ls, par); - if (!(s.getState() & Firebird::IStatus::STATE_ERRORS)) + if (plugin && !(ls->getState() & Firebird::IStatus::STATE_ERRORS)) { plugin->setOwner(par); return plugin; } par->release(); - check(&s); + check(&ls); return NULL; } @@ -683,6 +700,9 @@ namespace #endif } + typedef HalfStaticArray DelayedDelete; + static GlobalPtr delayedDelete; + int ConfiguredPlugin::release() { int x = --refCounter; @@ -698,6 +718,15 @@ namespace if (refCounter != 0) return 1; + if (Why::timerThreadStopped() && !processingDelayedDelete && delayedDelete) + { + // delay delete + addRef(); + delayedDelete->push(this); + + return 1; + } + destroy(); } @@ -710,6 +739,26 @@ namespace return 1; } + void ConfiguredPlugin::processDelayedDelete() + { + DelayedDelete& dd(delayedDelete); + MutexEnsureUnlock g(plugins->mutex, FB_FUNCTION); + g.enter(); + for (unsigned n = 0; n < dd.getCount(); ++n) + { + ConfiguredPlugin* ptr = dd[n]; + if (ptr) + { + g.leave(); + ptr->processingDelayedDelete = true; + ptr->release(); + g.enter(); + } + dd[n] = nullptr; + } + delayedDelete->clear(); + } + PluginModule* modules = NULL; PluginModule* current = NULL; @@ -764,6 +813,10 @@ namespace plugConfigFile = curModule; changeExtension(plugConfigFile, "conf"); + + PathUtils::fixupSeparators(curModule); + PathUtils::fixupSeparators(regName); + PathUtils::fixupSeparators(plugConfigFile); } }; @@ -808,8 +861,7 @@ namespace { namesList.assign(pnamesList); namesList.alltrim(" \t"); - Firebird::LocalStatus s; - Firebird::CheckStatusWrapper statusWrapper(&s); + FbLocalStatus statusWrapper; next(&statusWrapper); check(&statusWrapper); } @@ -940,6 +992,9 @@ namespace current = rc; startModule(masterInterface); current = NULL; +#ifdef DARWIN // Plugin unload disabled in MacOS - GH-7112 + rc->addRef(); +#endif return rc; } @@ -1003,26 +1058,55 @@ PluginManager::PluginManager() void PluginManager::registerPluginFactory(unsigned int interfaceType, const char* defaultName, IPluginFactory* factory) { - MutexLockGuard g(plugins->mutex, FB_FUNCTION); - - if (!current) + try { - // not good time to call this function - ignore request - gds__log("Unexpected call to register plugin %s, type %d - ignored\n", defaultName, interfaceType); - return; - } + MutexLockGuard g(plugins->mutex, FB_FUNCTION); - unsigned int r = current->addPlugin(RegisteredPlugin(factory, defaultName, interfaceType)); + if (!current) + { + // not good time to call this function - ignore request + gds__log("Unexpected call to register plugin %s, type %d - ignored\n", defaultName, interfaceType); + return; + } + + unsigned int r = current->addPlugin(RegisteredPlugin(factory, defaultName, interfaceType)); + + if (current == builtin) + { + PathName plugConfigFile = fb_utils::getPrefix(IConfigManager::DIR_PLUGINS, defaultName); + changeExtension(plugConfigFile, "conf"); - if (current == builtin) + ConfiguredPlugin* p = FB_NEW ConfiguredPlugin(RefPtr(builtin), r, + findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName); + p->addRef(); // Will never be unloaded + plugins->put(MapKey(interfaceType, defaultName), p); + } + } + catch(const Exception& ex) { - PathName plugConfigFile = fb_utils::getPrefix(IConfigManager::DIR_PLUGINS, defaultName); - changeExtension(plugConfigFile, "conf"); + // looks like something gone seriously wrong - therefore add more error handling here + try + { + FbLocalStatus ls; + ex.stuffException(&ls); + char text[256]; + UtilInterfacePtr()->formatStatus(text, sizeof(text), &ls); + Syslog::Record(Syslog::Error, text); - ConfiguredPlugin* p = FB_NEW ConfiguredPlugin(RefPtr(builtin), r, - findInPluginsConf("Plugin", defaultName), plugConfigFile, defaultName); - p->addRef(); // Will never be unloaded - plugins->put(MapKey(interfaceType, defaultName), p); + iscLogException("Plugin registration error", ex); + } + catch(const BadAlloc&) + { + Syslog::Record(Syslog::Error, "Plugin registration error - out of memory"); + } + catch(...) + { + Syslog::Record(Syslog::Error, "Double fault during plugin registration"); + } + +#ifdef DEV_BUILD + abort(); +#endif } } @@ -1165,6 +1249,10 @@ void PluginManager::threadDetach() modules->threadDetach(); } +void PluginManager::deleteDelayed() +{ + ConfiguredPlugin::processDelayedDelete(); +} } // namespace Firebird diff --git a/src/yvalve/PluginManager.h b/src/yvalve/PluginManager.h index 3b901a98a3d..495e3a0a35f 100644 --- a/src/yvalve/PluginManager.h +++ b/src/yvalve/PluginManager.h @@ -55,6 +55,7 @@ class PluginManager : public AutoIface, public YObject typedef YAttachment YRef; static const unsigned DF_RELEASE = 0x1; + static const unsigned DF_KEEP_NEXT = 0x2; explicit YHelper(NextInterface* aNext, const char* m = NULL) : @@ -160,7 +158,10 @@ class YHelper : public Firebird::RefCntIface, public YObject void destroy2(unsigned dstrFlags) { - next = NULL; + if (dstrFlags & DF_KEEP_NEXT) + next.clear(); + else + next = NULL; if (dstrFlags & DF_RELEASE) { @@ -213,6 +214,7 @@ class YEvents FB_FINAL : // IEvents implementation void cancel(Firebird::CheckStatusWrapper* status); + void deprecatedCancel(Firebird::CheckStatusWrapper* status); public: AtomicAttPtr attachment; @@ -245,6 +247,7 @@ class YRequest FB_FINAL : unsigned int msgType, unsigned int length, const void* message); void unwind(Firebird::CheckStatusWrapper* status, int level); void free(Firebird::CheckStatusWrapper* status); + void deprecatedFree(Firebird::CheckStatusWrapper* status); public: AtomicAttPtr attachment; @@ -275,6 +278,9 @@ class YTransaction FB_FINAL : Firebird::ITransaction* join(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction); Firebird::ITransaction* validate(Firebird::CheckStatusWrapper* status, Firebird::IAttachment* testAtt); YTransaction* enterDtc(Firebird::CheckStatusWrapper* status); + void deprecatedCommit(Firebird::CheckStatusWrapper* status); + void deprecatedRollback(Firebird::CheckStatusWrapper* status); + void deprecatedDisconnect(Firebird::CheckStatusWrapper* status); void addCleanupHandler(Firebird::CheckStatusWrapper* status, CleanupCallback* callback); void selfCheck(); @@ -324,6 +330,8 @@ class YBlob FB_FINAL : void cancel(Firebird::CheckStatusWrapper* status); void close(Firebird::CheckStatusWrapper* status); int seek(Firebird::CheckStatusWrapper* status, int mode, int offset); + void deprecatedCancel(Firebird::CheckStatusWrapper* status); + void deprecatedClose(Firebird::CheckStatusWrapper* status); public: AtomicAttPtr attachment; @@ -353,6 +361,7 @@ class YResultSet FB_FINAL : FB_BOOLEAN isBof(Firebird::CheckStatusWrapper* status); Firebird::IMessageMetadata* getMetadata(Firebird::CheckStatusWrapper* status); void close(Firebird::CheckStatusWrapper* status); + void deprecatedClose(Firebird::CheckStatusWrapper* status); void setDelayedOutputFormat(Firebird::CheckStatusWrapper* status, Firebird::IMessageMetadata* format); public: @@ -384,6 +393,9 @@ class YBatch FB_FINAL : void cancel(Firebird::CheckStatusWrapper* status); void setDefaultBpb(Firebird::CheckStatusWrapper* status, unsigned parLength, const unsigned char* par); void close(Firebird::CheckStatusWrapper* status); + void deprecatedClose(Firebird::CheckStatusWrapper* status); + void getInfo(Firebird::CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer); public: AtomicAttPtr attachment; @@ -403,6 +415,7 @@ class YReplicator FB_FINAL : // IReplicator implementation void process(Firebird::CheckStatusWrapper* status, unsigned length, const unsigned char* data); void close(Firebird::CheckStatusWrapper* status); + void deprecatedClose(Firebird::CheckStatusWrapper* status); public: AtomicAttPtr attachment; @@ -451,6 +464,7 @@ class YStatement FB_FINAL : unsigned int flags); void setCursorName(Firebird::CheckStatusWrapper* status, const char* name); void free(Firebird::CheckStatusWrapper* status); + void deprecatedFree(Firebird::CheckStatusWrapper* status); unsigned getFlags(Firebird::CheckStatusWrapper* status); unsigned int getTimeout(Firebird::CheckStatusWrapper* status); @@ -540,6 +554,8 @@ class YAttachment FB_FINAL : void ping(Firebird::CheckStatusWrapper* status); void detach(Firebird::CheckStatusWrapper* status); void dropDatabase(Firebird::CheckStatusWrapper* status); + void deprecatedDetach(Firebird::CheckStatusWrapper* status); + void deprecatedDropDatabase(Firebird::CheckStatusWrapper* status); void addCleanupHandler(Firebird::CheckStatusWrapper* status, CleanupCallback* callback); YTransaction* getTransaction(Firebird::ITransaction* tra); @@ -578,7 +594,7 @@ class YService FB_FINAL : public: static const ISC_STATUS ERROR_CODE = isc_bad_svc_handle; - YService(Firebird::IProvider* aProvider, Firebird::IService* aNext, bool utf8); + YService(Firebird::IProvider* aProvider, Firebird::IService* aNext, bool utf8, Dispatcher* yProvider); ~YService(); void shutdown(); @@ -587,12 +603,14 @@ class YService FB_FINAL : // IService implementation void detach(Firebird::CheckStatusWrapper* status); + void deprecatedDetach(Firebird::CheckStatusWrapper* status); void query(Firebird::CheckStatusWrapper* status, unsigned int sendLength, const unsigned char* sendItems, unsigned int receiveLength, const unsigned char* receiveItems, unsigned int bufferLength, unsigned char* buffer); void start(Firebird::CheckStatusWrapper* status, unsigned int spbLength, const unsigned char* spb); + void cancel(Firebird::CheckStatusWrapper* status); public: typedef Firebird::IService NextInterface; @@ -601,6 +619,11 @@ class YService FB_FINAL : private: Firebird::IProvider* provider; bool utf8Connection; // Client talks to us using UTF8, else - system default charset + +public: + Firebird::RefPtr alternativeHandle; + Firebird::ClumpletWriter attachSpb; + Firebird::RefPtr ownProvider; }; class Dispatcher FB_FINAL : @@ -625,6 +648,12 @@ class Dispatcher FB_FINAL : void destroy(unsigned) { } +public: + Firebird::IService* internalServiceAttach(Firebird::CheckStatusWrapper* status, + const Firebird::PathName& svcName, Firebird::ClumpletReader& spb, + std::function start, + Firebird::IProvider** retProvider); + private: YAttachment* attachOrCreateDatabase(Firebird::CheckStatusWrapper* status, bool createFlag, const char* filename, unsigned int dpbLength, const unsigned char* dpb); diff --git a/src/yvalve/gds.cpp b/src/yvalve/gds.cpp index 56fe5ba7881..e3c7373bd45 100644 --- a/src/yvalve/gds.cpp +++ b/src/yvalve/gds.cpp @@ -261,6 +261,7 @@ const int op_partition_args = 26; const int op_subproc_decl = 27; const int op_subfunc_decl = 28; const int op_window_win = 29; +const int op_erase = 30; // special due to optional blr_marks after blr_erase static const UCHAR // generic print formats @@ -347,7 +348,8 @@ static const UCHAR relation_field[] = { op_line, op_indent, op_byte, op_literal, op_line, op_indent, op_byte, op_literal, op_pad, op_line, 0}, store3[] = { op_line, op_byte, op_line, op_verb, op_verb, op_verb, 0}, - marks[] = { op_byte, op_literal, op_line, op_verb, 0}; + marks[] = { op_byte, op_literal, op_line, op_verb, 0}, + erase[] = { op_erase, 0}; #include "../jrd/blp.h" @@ -902,7 +904,7 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize, } if (!found) { - sprintf(s, "unknown ISC error %ld", code); // TXNN + sprintf(s, "unknown ISC error %ld", (SLONG) code); // TXNN } } } @@ -927,11 +929,11 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize, break; case isc_arg_dos: - sprintf(s, "unknown dos error %ld", code); // TXNN + sprintf(s, "unknown dos error %ld", (SLONG) code); // TXNN break; case isc_arg_next_mach: - sprintf(s, "next/mach error %ld", code); // AP + sprintf(s, "next/mach error %ld", (SLONG) code); // AP break; case isc_arg_win32: @@ -943,7 +945,7 @@ static SLONG safe_interpret(char* const s, const FB_SIZE_T bufsize, s, bufsize, NULL)) #endif { - sprintf(s, "unknown Win32 error %ld", code); // TXNN + sprintf(s, "unknown Win32 error %ld", (SLONG) code); // TXNN } break; @@ -1011,80 +1013,122 @@ const int SECS_PER_HOUR = 60 * 60; const int SECS_PER_DAY = SECS_PER_HOUR * 24; #ifdef WIN_NT -class CleanupTraceHandles + +namespace { + +class LogFileHandles { public: - ~CleanupTraceHandles() + LogFileHandles(Firebird::MemoryPool&) + { + mutex_handle = CreateMutex(ISC_get_security_desc(), FALSE, "firebird_trace_mutex"); + } + + ~LogFileHandles() { - CloseHandle(trace_mutex_handle); - trace_mutex_handle = INVALID_HANDLE_VALUE; + if (mutex_handle != INVALID_HANDLE_VALUE) + CloseHandle(mutex_handle); + + mutex_handle = INVALID_HANDLE_VALUE; - if (trace_file_handle != INVALID_HANDLE_VALUE) - CloseHandle(trace_file_handle); + if (file_handle != INVALID_HANDLE_VALUE) + CloseHandle(file_handle); - trace_file_handle = INVALID_HANDLE_VALUE; + file_handle = INVALID_HANDLE_VALUE; } + void trace_raw(const char* text, unsigned int length); + +private: // This is machine-global. Can be made instance-global. // For as long you don't trace two instances in parallel this shouldn't matter. - static HANDLE trace_mutex_handle; - static HANDLE trace_file_handle; -}; - -HANDLE CleanupTraceHandles::trace_mutex_handle = CreateMutex(NULL, FALSE, "firebird_trace_mutex"); -HANDLE CleanupTraceHandles::trace_file_handle = INVALID_HANDLE_VALUE; + static HANDLE mutex_handle; + static HANDLE file_handle; -CleanupTraceHandles cleanupHandles; - -#endif + friend class LogGuard; +}; -void API_ROUTINE gds__trace_raw(const char* text, unsigned int length) +void LogFileHandles::trace_raw(const char* text, unsigned int length) { -/************************************** - * - * g d s _ t r a c e _ r a w - * - ************************************** - * - * Functional description - * Write trace event to a log file - * - **************************************/ - if (!length) - length = static_cast(strlen(text)); -#ifdef WIN_NT - // Note: thread-safe code - // Nickolay Samofatov, 12 Sept 2003. Windows opens files extremely slowly. // Slowly enough to make such trace useless. Thus we cache file handle ! - WaitForSingleObject(CleanupTraceHandles::trace_mutex_handle, INFINITE); + while (true) { - if (CleanupTraceHandles::trace_file_handle == INVALID_HANDLE_VALUE) + if (file_handle == INVALID_HANDLE_VALUE) { Firebird::PathName name = fb_utils::getPrefix(Firebird::IConfigManager::DIR_LOG, LOGFILE); + // We do not care to close this file. // It will be closed automatically when our process terminates. - CleanupTraceHandles::trace_file_handle = CreateFile(name.c_str(), GENERIC_WRITE, + file_handle = CreateFile(name.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (CleanupTraceHandles::trace_file_handle == INVALID_HANDLE_VALUE) + + if (file_handle == INVALID_HANDLE_VALUE) break; } + + SetFilePointer(file_handle, 0, NULL, FILE_END); + DWORD bytesWritten; - SetFilePointer(CleanupTraceHandles::trace_file_handle, 0, NULL, FILE_END); - WriteFile(CleanupTraceHandles::trace_file_handle, text, length, &bytesWritten, NULL); + WriteFile(file_handle, text, length, &bytesWritten, NULL); + if (bytesWritten != length) { // Handle the case when file was deleted by another process on Win9x // On WinNT we are not going to notice that fact :( - CloseHandle(CleanupTraceHandles::trace_file_handle); - CleanupTraceHandles::trace_file_handle = INVALID_HANDLE_VALUE; + CloseHandle(file_handle); + file_handle = INVALID_HANDLE_VALUE; continue; } break; } - ReleaseMutex(CleanupTraceHandles::trace_mutex_handle); +} + +Firebird::InitInstance logFileHandles; + +HANDLE LogFileHandles::mutex_handle = INVALID_HANDLE_VALUE; +HANDLE LogFileHandles::file_handle = INVALID_HANDLE_VALUE; + + +class LogGuard +{ +public: + LogGuard() + { + WaitForSingleObject(logFileHandles().mutex_handle, INFINITE); + } + + ~LogGuard() + { + ReleaseMutex(logFileHandles().mutex_handle); + } +}; + +} // namespace + +#endif + +void API_ROUTINE gds__trace_raw(const char* text, unsigned int length) +{ +/************************************** + * + * g d s _ t r a c e _ r a w + * + ************************************** + * + * Functional description + * Write trace event to a log file + * + **************************************/ + if (!length) + length = static_cast(strlen(text)); +#ifdef WIN_NT + // Note: thread-safe code + + LogGuard guard; + logFileHandles().trace_raw(text, length); #else Firebird::PathName name = fb_utils::getPrefix(Firebird::IConfigManager::DIR_LOG, LOGFILE); int file = os_utils::open(name.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0660); @@ -1218,7 +1262,7 @@ void API_ROUTINE gds__log(const TEXT* text, ...) Firebird::PathName name = fb_utils::getPrefix(Firebird::IConfigManager::DIR_LOG, LOGFILE); #ifdef WIN_NT - WaitForSingleObject(CleanupTraceHandles::trace_mutex_handle, INFINITE); + LogGuard guard; #endif FILE* file = os_utils::fopen(name.c_str(), "a"); if (file != NULL) @@ -1250,9 +1294,6 @@ void API_ROUTINE gds__log(const TEXT* text, ...) // This will release file lock set in posix case fclose(file); } -#ifdef WIN_NT - ReleaseMutex(CleanupTraceHandles::trace_mutex_handle); -#endif } #ifdef NOT_USED_OR_REPLACED @@ -1284,7 +1325,7 @@ void gds__print_pool(MemoryPool* pool, const TEXT* text, ...) const int oldmask = umask(0111); #ifdef WIN_NT - WaitForSingleObject(CleanupTraceHandles::trace_mutex_handle, INFINITE); + LogGuard guard; #endif FILE* file = os_utils::fopen(name.c_str(), "a"); if (file != NULL) @@ -1299,9 +1340,6 @@ void gds__print_pool(MemoryPool* pool, const TEXT* text, ...) fprintf(file, "\n"); fclose(file); } -#ifdef WIN_NT - ReleaseMutex(CleanupTraceHandles::trace_mutex_handle); -#endif umask(oldmask); @@ -2841,7 +2879,7 @@ static SCHAR blr_print_char(gds_ctl* control) else if (control->ctl_language) blr_format(control, "chr(%d),", (int) v); else - blr_format(control, "%d,", (int) c); + blr_format(control, "%d,", (int) v); return c; } @@ -3747,6 +3785,21 @@ static void blr_print_verb(gds_ctl* control, SSHORT level) break; } + case op_erase: + blr_print_byte(control); + if (control->ctl_blr_reader.peekByte() == blr_marks) + { + offset = blr_print_line(control, offset); + blr_indent(control, level); + blr_print_blr(control, control->ctl_blr_reader.getByte()); + n = blr_print_byte(control); + + while (n-- > 0) + blr_print_char(control); + } + offset = blr_print_line(control, offset); + break; + default: fb_assert(false); break; @@ -3839,13 +3892,13 @@ static void sanitize(Firebird::string& locale) } -void FB_EXPORTED gds__default_printer(void* /*arg*/, SSHORT offset, const TEXT* line) +void API_ROUTINE_VARARG gds__default_printer(void* /*arg*/, SSHORT offset, const TEXT* line) { printf("%4d %s\n", offset, line); } -void FB_EXPORTED gds__trace_printer(void* /*arg*/, SSHORT offset, const TEXT* line) +void API_ROUTINE_VARARG gds__trace_printer(void* /*arg*/, SSHORT offset, const TEXT* line) { // Assume that line is not too long char buffer[PRETTY_BUFFER_SIZE + 10]; diff --git a/src/yvalve/gds_proto.h b/src/yvalve/gds_proto.h index 384cce4be1a..8f1e91fe046 100644 --- a/src/yvalve/gds_proto.h +++ b/src/yvalve/gds_proto.h @@ -134,8 +134,10 @@ SINT64 API_ROUTINE isc_portable_integer(const UCHAR*, SSHORT); void gds__cleanup(); void gds__ulstr(char* buffer, FB_UINT64 value, const int minlen, const char filler); -void FB_EXPORTED gds__default_printer(void*, SSHORT, const TEXT*); -void FB_EXPORTED gds__trace_printer(void*, SSHORT, const TEXT*); +// These functions uses cdecl convention in Windows, so use API_ROUTINE_VARARG instead of API_ROUTINE (stdcall). +void API_ROUTINE_VARARG gds__default_printer(void*, SSHORT, const TEXT*); +void API_ROUTINE_VARARG gds__trace_printer(void*, SSHORT, const TEXT*); + #ifdef NOT_USED_OR_REPLACED void gds__print_pool(Firebird::MemoryPool*, const TEXT*, ...); #endif diff --git a/src/yvalve/preparse.cpp b/src/yvalve/preparse.cpp index f2e702dc98f..0dd8ba01543 100644 --- a/src/yvalve/preparse.cpp +++ b/src/yvalve/preparse.cpp @@ -166,7 +166,7 @@ bool PREPARSE_execute(CheckStatusWrapper* status, Why::YAttachment** ptrAtt, { if (stmt.isEmpty()) { - Arg::Gds(isc_command_end_err).raise(); + return false; // let others care } bool hasUser = true; diff --git a/src/yvalve/utl.cpp b/src/yvalve/utl.cpp index 3f099358295..673b9e24578 100644 --- a/src/yvalve/utl.cpp +++ b/src/yvalve/utl.cpp @@ -458,29 +458,23 @@ void UtilInterface::getFbVersion(CheckStatusWrapper* status, IAttachment* att, if (status->getState() & Firebird::IStatus::STATE_ERRORS) return; - const UCHAR* p = buf; - redo = false; + ClumpletReader p(ClumpletReader::InfoResponse, buf, buf_len); - while (!redo && *p != isc_info_end && p < buf + buf_len) + for (redo = false; !(redo || p.isEof()); p.moveNext()) { - const UCHAR item = *p++; - const USHORT len = static_cast(gds__vax_integer(p, 2)); - - p += 2; - - switch (item) + switch (p.getClumpTag()) { case isc_info_firebird_version: - versions = (TEXT*) p; + versions = (TEXT*) p.getBytes(); break; case isc_info_implementation: - implementations = (TEXT*) p; + implementations = (TEXT*) p.getBytes(); break; case fb_info_implementation: - dbis = p; - if (dbis[0] * 6 + 1 > len) + dbis = p.getBytes(); + if (dbis[0] * 6u + 1u > p.getClumpLength()) { // fb_info_implementation value appears incorrect dbis = NULL; @@ -493,13 +487,13 @@ void UtilInterface::getFbVersion(CheckStatusWrapper* status, IAttachment* att, case isc_info_truncated: redo = true; + // fall down... + case isc_info_end: break; default: (Arg::Gds(isc_random) << "Invalid info item").raise(); } - - p += len; } // Our buffer wasn't large enough to hold all the information, @@ -916,8 +910,14 @@ class XpbBuilder FB_FINAL : public DisposeIface(buffer); - UCHAR item; - while ((item = *p++) != isc_info_end) + for (ClumpletReader p(ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { - const USHORT l = gds__vax_integer(p, 2); - p += 2; - const SLONG n = gds__vax_integer(p, l); - p += l; + UCHAR item = p.getClumpTag(); + if (item == isc_info_end) + break; + switch (item) { case isc_info_blob_max_segment: if (max_seg) - *max_seg = n; + *max_seg = p.getInt(); break; case isc_info_blob_num_segments: if (seg_count) - *seg_count = n; + *seg_count = p.getInt(); break; case isc_info_blob_total_length: if (size) - *size = n; + *size = p.getInt(); break; default: @@ -2970,16 +2968,10 @@ static void get_ods_version(CheckStatusWrapper* status, IAttachment* att, if (status->getState() & Firebird::IStatus::STATE_ERRORS) return; - const UCHAR* p = buffer; - UCHAR item; - - while ((item = *p++) != isc_info_end) + for (ClumpletReader p(ClumpletReader::InfoResponse, buffer, sizeof(buffer)); !p.isEof(); p.moveNext()) { - const USHORT l = static_cast(gds__vax_integer(p, 2)); - p += 2; - const USHORT n = static_cast(gds__vax_integer(p, l)); - p += l; - switch (item) + const USHORT n = static_cast(p.getInt()); + switch (p.getClumpTag()) { case isc_info_ods_version: *ods_version = n; @@ -2989,6 +2981,9 @@ static void get_ods_version(CheckStatusWrapper* status, IAttachment* att, *ods_minor_version = n; break; + case isc_info_end: + break; + default: (Arg::Gds(isc_random) << "Invalid info item").raise(); } @@ -3241,7 +3236,7 @@ void makeKey() int err = pthread_key_create(&key, ThreadCleanup::destructor); if (err) { - Firebird::system_call_failed("pthread_key_create", err); + Firebird::system_call_failed::raise("pthread_key_create", err); } keySet = true; } @@ -3251,13 +3246,13 @@ void ThreadCleanup::initThreadCleanup() int err = pthread_once(&keyOnce, makeKey); if (err) { - Firebird::system_call_failed("pthread_once", err); + Firebird::system_call_failed::raise("pthread_once", err); } err = pthread_setspecific(key, &key); if (err) { - Firebird::system_call_failed("pthread_setspecific", err); + Firebird::system_call_failed::raise("pthread_setspecific", err); } } @@ -3281,7 +3276,7 @@ class FiniThreadCleanup { int err = pthread_key_delete(key); if (err) - Firebird::system_call_failed("pthread_key_delete", err); + gds__log("pthread_key_delete failed with error %d", err); } } }; diff --git a/src/yvalve/why.cpp b/src/yvalve/why.cpp index f615b72c520..45861cd0064 100644 --- a/src/yvalve/why.cpp +++ b/src/yvalve/why.cpp @@ -28,7 +28,10 @@ */ #include "firebird.h" + +#define FB_UsedInYValve true #include "firebird/Interface.h" + #include "memory_routines.h" #include "gen/iberror.h" #include "gen/msg_facs.h" @@ -75,6 +78,8 @@ #include #endif +#include + using namespace Firebird; using namespace Why; @@ -82,7 +87,6 @@ using namespace Why; static void badHandle(ISC_STATUS code); static bool isNetworkError(const IStatus* status); static void nullCheck(const FB_API_HANDLE* ptr, ISC_STATUS code); -//static void saveErrorString(ISC_STATUS* status); static void badSqldaVersion(const short version); static int sqldaTruncateString(char* buffer, FB_SIZE_T size, const char* s); static void sqldaDescribeParameters(XSQLDA* sqlda, IMessageMetadata* parameters); @@ -1240,13 +1244,16 @@ namespace Why void checkCursorOpened() const { if (!statement || !statement->cursor) - Arg::Gds(isc_dsql_cursor_not_open).raise(); + (Arg::Gds(isc_sqlerr) << Arg::Num(-504) << + Arg::Gds(isc_dsql_cursor_err) << + Arg::Gds(isc_dsql_cursor_not_open)).raise(); } void checkCursorClosed() const { if (statement && statement->cursor) - Arg::Gds(isc_dsql_cursor_open_err).raise(); + (Arg::Gds(isc_sqlerr) << Arg::Num(-502) << + Arg::Gds(isc_dsql_cursor_open_err)).raise(); } IStatement* getInterface() @@ -1324,6 +1331,27 @@ namespace Why bool shutdownMode; }; + + template + void done(CheckStatusWrapper* status, YEntry& entry, Y* y, std::function newClose, std::function oldClose) + { + if (entry.next()) + newClose(); + + if (!(status->getState() & IStatus::STATE_ERRORS)) + y->destroy(Y::DF_RELEASE | Y::DF_KEEP_NEXT); + + else if (status->getErrors()[1] == isc_interface_version_too_old) + { + status->init(); + if (entry.next()) + oldClose(); + + if (!(status->getState() & IStatus::STATE_ERRORS)) + y->destroy(Y::DF_RELEASE); + } + } + } // namespace Why struct TEB @@ -1565,7 +1593,7 @@ ISC_STATUS API_ROUTINE isc_attach_database(ISC_STATUS* userStatus, SSHORT fileLe return status[1]; YAttachment* attachment = dispatcher->attachDatabase(&statusWrapper, pathName.c_str(), - dpbLength, reinterpret_cast(dpb)); + static_cast(dpbLength), reinterpret_cast(dpb)); if (status.getState() & IStatus::STATE_ERRORS) return status[1]; @@ -2306,9 +2334,6 @@ ISC_STATUS API_ROUTINE isc_dsql_exec_immed2(ISC_STATUS* userStatus, isc_db_handl try { - if (!sqlStmt) - Arg::Gds(isc_command_end_err).raise(); - FB_BOOLEAN stmtIsCrDb = FB_FALSE; YAttachment* att = utilInterface.executeCreateDatabase(&statusWrapper, stmtLength, sqlStmt, dialect, &stmtIsCrDb); @@ -3673,15 +3698,6 @@ ISC_STATUS API_ROUTINE isc_unwind_request(ISC_STATUS* userStatus, isc_req_handle // Shutdown firebird. int API_ROUTINE fb_shutdown(unsigned int timeout, const int reason) { - if (reason == fb_shutrsn_emergency) - { - shutdownStarted = true; - abortShutdown(); - } - - if (shutdownStarted) - return FB_SUCCESS; - StatusVector status(NULL); CheckStatusWrapper statusWrapper(&status); @@ -3901,14 +3917,11 @@ void YEvents::cancel(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->cancel(status); - - if (status->getErrors()[1] == isc_att_shutdown) - status->init(); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{ + entry.next()->cancel(status); + if (status->getErrors()[1] == isc_att_shutdown) + status->init(); + }, [&]{entry.next()->deprecatedCancel(status);}); } catch (const Exception& e) { @@ -3916,6 +3929,11 @@ void YEvents::cancel(CheckStatusWrapper* status) } } +void YEvents::deprecatedCancel(CheckStatusWrapper* status) +{ + cancel(status); +} + //------------------------------------- @@ -4046,11 +4064,7 @@ void YRequest::free(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->free(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->free(status);}, [&]{entry.next()->deprecatedFree(status);}); } catch (const Exception& e) { @@ -4058,6 +4072,11 @@ void YRequest::free(CheckStatusWrapper* status) } } +void YRequest::deprecatedFree(CheckStatusWrapper* status) +{ + free(status); +} + //------------------------------------- @@ -4141,11 +4160,7 @@ void YBlob::cancel(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->cancel(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->cancel(status);}, [&]{entry.next()->deprecatedCancel(status);}); } catch (const Exception& e) { @@ -4153,17 +4168,18 @@ void YBlob::cancel(CheckStatusWrapper* status) } } +void YBlob::deprecatedCancel(CheckStatusWrapper* status) +{ + cancel(status); +} + void YBlob::close(CheckStatusWrapper* status) { try { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->close(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->close(status);}, [&]{entry.next()->deprecatedClose(status);}); } catch (const Exception& e) { @@ -4171,6 +4187,11 @@ void YBlob::close(CheckStatusWrapper* status) } } +void YBlob::deprecatedClose(CheckStatusWrapper* status) +{ + close(status); +} + int YBlob::seek(CheckStatusWrapper* status, int mode, int offset) { try @@ -4438,11 +4459,7 @@ void YStatement::free(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->free(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->free(status);}, [&]{entry.next()->deprecatedFree(status);}); } catch (const Exception& e) { @@ -4450,6 +4467,12 @@ void YStatement::free(CheckStatusWrapper* status) } } +void YStatement::deprecatedFree(CheckStatusWrapper* status) +{ + free(status); +} + + YBatch* YStatement::createBatch(CheckStatusWrapper* status, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) { @@ -4847,17 +4870,14 @@ IMessageMetadata* YResultSet::getMetadata(CheckStatusWrapper* status) return NULL; } + void YResultSet::close(CheckStatusWrapper* status) { try { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->close(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->close(status);}, [&]{entry.next()->deprecatedClose(status);}); } catch (const Exception& e) { @@ -4865,6 +4885,12 @@ void YResultSet::close(CheckStatusWrapper* status) } } +void YResultSet::deprecatedClose(CheckStatusWrapper* status) +{ + close(status); +} + + //------------------------------------- @@ -5043,11 +5069,29 @@ void YBatch::close(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->close(status); + done(status, entry, this, [&]{entry.next()->close(status);}, [&]{entry.next()->deprecatedClose(status);}); + } + catch (const Exception& e) + { + e.stuffException(status); + } +} - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + +void YBatch::deprecatedClose(CheckStatusWrapper* status) +{ + close(status); +} + + +void YBatch::getInfo(CheckStatusWrapper* status, unsigned int itemsLength, const unsigned char* items, + unsigned int bufferLength, unsigned char* buffer) +{ + try + { + YEntry entry(status, this); + + entry.next()->getInfo(status, itemsLength, items, bufferLength, buffer); } catch (const Exception& e) { @@ -5091,11 +5135,7 @@ void YReplicator::close(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->close(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->close(status);}, [&]{entry.next()->deprecatedClose(status);}); } catch (const Exception& e) { @@ -5104,6 +5144,12 @@ void YReplicator::close(CheckStatusWrapper* status) } +void YReplicator::deprecatedClose(CheckStatusWrapper* status) +{ + close(status); +} + + //------------------------------------- @@ -5142,8 +5188,8 @@ void YTransaction::destroy(unsigned dstrFlags) // can't release cursors by itself. See also CORE-6067. const bool releaseCursors = handle; - childBlobs.destroy(dstrFlags & ~DF_RELEASE); - childCursors.destroy(releaseCursors ? dstrFlags : dstrFlags & ~DF_RELEASE); + childBlobs.destroy(dstrFlags & ~(DF_RELEASE | DF_KEEP_NEXT)); + childCursors.destroy((releaseCursors ? dstrFlags : dstrFlags & ~DF_RELEASE) & ~DF_KEEP_NEXT); YAttachment* att = attachment.release(); if (att) @@ -5166,7 +5212,8 @@ void YTransaction::getInfo(CheckStatusWrapper* status, unsigned int itemsLength, fb_utils::getDbPathInfo(itemsLength, items, bufferLength, buffer, newItemsBuffer, attachment.get()->dbPath); - entry.next()->getInfo(status, itemsLength, items, bufferLength, buffer); + if (itemsLength) + entry.next()->getInfo(status, itemsLength, items, bufferLength, buffer); } catch (const Exception& e) { @@ -5195,10 +5242,7 @@ void YTransaction::commit(CheckStatusWrapper* status) { YEntry entry(status, this); - entry.next()->commit(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->commit(status);}, [&]{entry.next()->deprecatedCommit(status);}); } catch (const Exception& e) { @@ -5226,13 +5270,11 @@ void YTransaction::rollback(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->rollback(status); - if (isNetworkError(status)) - status->init(); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{ + entry.next()->rollback(status); + if (isNetworkError(status)) + status->init(); + }, [&]{entry.next()->deprecatedRollback(status);}); } catch (const Exception& e) { @@ -5283,6 +5325,22 @@ void YTransaction::disconnect(CheckStatusWrapper* status) } } +void YTransaction::deprecatedCommit(CheckStatusWrapper* status) +{ + commit(status); +} + +void YTransaction::deprecatedRollback(CheckStatusWrapper* status) +{ + rollback(status); +} + +void YTransaction::deprecatedDisconnect(CheckStatusWrapper* status) +{ + disconnect(status); +} + + void YTransaction::addCleanupHandler(CheckStatusWrapper* status, CleanupCallback* callback) { try @@ -5346,8 +5404,6 @@ YTransaction* YTransaction::enterDtc(CheckStatusWrapper* status) YEntry entry(status, this); YTransaction* copy = FB_NEW YTransaction(this); - // copy is created with zero handle - copy->addRef(); copy->addRef(); next->addRef(); // We use NoIncr in YTransaction ctor @@ -5412,12 +5468,13 @@ void YAttachment::destroy(unsigned dstrFlags) cleanupHandlers.clear(); - childRequests.destroy(dstrFlags & ~DF_RELEASE); - childStatements.destroy(dstrFlags & ~DF_RELEASE); - childIscStatements.destroy(dstrFlags & ~DF_RELEASE); - childBlobs.destroy(dstrFlags & ~DF_RELEASE); - childEvents.destroy(dstrFlags & ~DF_RELEASE); - childTransactions.destroy(dstrFlags & ~DF_RELEASE); + unsigned childFlags = dstrFlags & ~(DF_KEEP_NEXT | DF_RELEASE); + childRequests.destroy(childFlags); + childStatements.destroy(childFlags); + childIscStatements.destroy(childFlags); + childBlobs.destroy(childFlags); + childEvents.destroy(childFlags); + childTransactions.destroy(childFlags); removeHandle(&attachments, handle); @@ -5455,9 +5512,6 @@ YStatement* YAttachment::prepare(CheckStatusWrapper* status, ITransaction* trans { YEntry entry(status, this); - if (!sqlStmt) - Arg::Gds(isc_command_end_err).raise(); - NextTransaction trans; if (transaction) getNextTransaction(status, transaction, trans); @@ -5872,14 +5926,11 @@ void YAttachment::detach(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_NONE); - if (entry.next()) - entry.next()->detach(status); - - if (isNetworkError(status)) - status->init(); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{ + entry.next()->detach(status); + if (isNetworkError(status)) + status->init(); + }, [&]{entry.next()->deprecatedDetach(status);}); } catch (const Exception& e) { @@ -5887,16 +5938,18 @@ void YAttachment::detach(CheckStatusWrapper* status) } } +void YAttachment::deprecatedDetach(CheckStatusWrapper* status) +{ + detach(status); +} + void YAttachment::dropDatabase(CheckStatusWrapper* status) { try { YEntry entry(status, this); - entry.next()->dropDatabase(status); - - if (!(status->getState() & IStatus::STATE_ERRORS)) - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->dropDatabase(status);}, [&]{entry.next()->deprecatedDropDatabase(status);}); } catch (const Exception& e) { @@ -5904,6 +5957,11 @@ void YAttachment::dropDatabase(CheckStatusWrapper* status) } } +void YAttachment::deprecatedDropDatabase(CheckStatusWrapper* status) +{ + dropDatabase(status); +} + void YAttachment::addCleanupHandler(CheckStatusWrapper* status, CleanupCallback* callback) { try @@ -6067,12 +6125,13 @@ YReplicator* YAttachment::createReplicator(CheckStatusWrapper* status) //------------------------------------- -YService::YService(IProvider* aProvider, IService* aNext, bool utf8) +YService::YService(IProvider* aProvider, IService* aNext, bool utf8, Dispatcher* yProvider) : YHelper(aNext), provider(aProvider), - utf8Connection(utf8) + utf8Connection(utf8), + attachSpb(getPool(), ClumpletReader::spbList, MAX_DPB_SIZE, nullptr, 0), + ownProvider(yProvider) { - provider->addRef(); makeHandle(&services, this, handle); } @@ -6110,10 +6169,7 @@ void YService::detach(CheckStatusWrapper* status) { YEntry entry(status, this, CHECK_WARN_ZERO_HANDLE); - if (entry.next()) - entry.next()->detach(status); - - destroy(DF_RELEASE); + done(status, entry, this, [&]{entry.next()->detach(status);}, [&]{entry.next()->deprecatedDetach(status);}); } catch (const Exception& e) { @@ -6121,6 +6177,11 @@ void YService::detach(CheckStatusWrapper* status) } } +void YService::deprecatedDetach(CheckStatusWrapper* status) +{ + detach(status); +} + void YService::query(CheckStatusWrapper* status, unsigned int sendLength, const unsigned char* sendItems, unsigned int receiveLength, const unsigned char* receiveItems, unsigned int bufferLength, unsigned char* buffer) @@ -6128,8 +6189,21 @@ void YService::query(CheckStatusWrapper* status, unsigned int sendLength, const try { YEntry entry(status, this); - entry.next()->query(status, sendLength, sendItems, - receiveLength, receiveItems, bufferLength, buffer); + (alternativeHandle ? alternativeHandle.getPtr() : entry.next())-> + query(status, sendLength, sendItems, receiveLength, receiveItems, bufferLength, buffer); + } + catch (const Exception& e) + { + e.stuffException(status); + } +} + +void YService::cancel(CheckStatusWrapper* status) +{ + try + { + YEntry entry(status, this); + entry.next()->cancel(status); } catch (const Exception& e) { @@ -6149,6 +6223,43 @@ void YService::start(CheckStatusWrapper* status, unsigned int spbLength, const u YEntry entry(status, this); entry.next()->start(status, spb.getBufferLength(), spb.getBuffer()); + + const ISC_STATUS retryList[] = {isc_wrong_ods, isc_badodsver, isc_gstat_wrong_ods, 0}; + + for (const ISC_STATUS* code = retryList; *code; ++code) + { + if (fb_utils::containsErrorCode(status->getErrors(), *code)) + { + FbLocalStatus st; + if (alternativeHandle) // first of all try already found provider + { + alternativeHandle->start(&st, spb.getBufferLength(), spb.getBuffer()); + if (st.isSuccess()) + { + status->init(); + return; + } + st->clearException(); + } + + // we are not going to attach network providers, therefore const svcName is OK + alternativeHandle = ownProvider->internalServiceAttach(&st, "service_mgr", attachSpb, + [&spb](CheckStatusWrapper* st, IService* service) + { + service->start(st, spb.getBufferLength(), spb.getBuffer()); + }, nullptr); + if (st.isSuccess()) + { + status->init(); + return; + } + + // can't help any more... + break; + } + } + + alternativeHandle = nullptr; } catch (const Exception& e) { @@ -6192,11 +6303,18 @@ YAttachment* Dispatcher::attachOrCreateDatabase(CheckStatusWrapper* status, bool // Take care about DPB setLogin(newDpb, false); - if (!utfData) + + if (!newDpb.find(isc_dpb_session_time_zone)) { - IntlDpb().toUtf8(newDpb); + const char* defaultTimeZone = Config::getDefaultTimeZone(); + + if (defaultTimeZone && defaultTimeZone[0]) + newDpb.insertString(isc_dpb_session_time_zone, defaultTimeZone); } + if (!utfData) + IntlDpb().toUtf8(newDpb); + // Take care about filename PathName orgFilename(filename); if (utfData) @@ -6282,6 +6400,7 @@ YAttachment* Dispatcher::attachOrCreateDatabase(CheckStatusWrapper* status, bool case isc_lock_dir_access: case isc_no_priv: case isc_wrong_ods: + case isc_lockmanerr: currentStatus = &tempCheckStatusWrapper; // fall down... case isc_unavailable: @@ -6336,89 +6455,141 @@ YService* Dispatcher::attachServiceManager(CheckStatusWrapper* status, const cha IntlSpb().toUtf8(spbWriter); } - // Build correct config - RefPtr config(Config::getDefaultConfig()); - if (spbWriter.find(isc_spb_config)) + IProvider* p; + service = internalServiceAttach(status, svcName, spbWriter, + [](CheckStatusWrapper*, IService*){ }, &p); + + if (!(status->getState() & IStatus::STATE_ERRORS)) { - string spb_config; - spbWriter.getString(spb_config); - Config::merge(config, &spb_config); + YService* r = FB_NEW YService(p, service, utfData, this); + r->addRef(); + r->attachSpb.reset(spbWriter); + return r; + } + } + catch (const Exception& e) + { + if (service) + { + StatusVector temp(NULL); + CheckStatusWrapper tempCheckStatusWrapper(&temp); + service->detach(&tempCheckStatusWrapper); } - StatusVector temp(NULL); - CheckStatusWrapper tempCheckStatusWrapper(&temp); - CheckStatusWrapper* currentStatus = status; + e.stuffException(status); + } - for (GetPlugins providerIterator(IPluginManager::TYPE_PROVIDER, config); - providerIterator.hasData(); - providerIterator.next()) + return NULL; +} + +// Attach and probably start a service through the first available subsystem. +IService* Dispatcher::internalServiceAttach(CheckStatusWrapper* status, const PathName& svcName, + ClumpletReader& spb, std::function start, + IProvider** retProvider) +{ + IService* service = NULL; + + // Build correct config + RefPtr config(Config::getDefaultConfig()); + if (spb.find(isc_spb_config)) + { + string spb_config; + spb.getString(spb_config); + Config::merge(config, &spb_config); + } + + FbLocalStatus temp1, temp2; + CheckStatusWrapper* currentStatus = &temp1; + + for (GetPlugins providerIterator(IPluginManager::TYPE_PROVIDER, config); + providerIterator.hasData(); + providerIterator.next()) + { + IProvider* p = providerIterator.plugin(); + + if (cryptCallback) { - IProvider* p = providerIterator.plugin(); + p->setDbCryptCallback(currentStatus, cryptCallback); + if (currentStatus->getState() & IStatus::STATE_ERRORS) + continue; + } - if (cryptCallback) - { - p->setDbCryptCallback(currentStatus, cryptCallback); - if (currentStatus->getState() & IStatus::STATE_ERRORS) - continue; - } + service = p->attachServiceManager(currentStatus, svcName.c_str(), + spb.getBufferLength(), spb.getBuffer()); - service = p->attachServiceManager(currentStatus, svcName.c_str(), - spbWriter.getBufferLength(), spbWriter.getBuffer()); + if (!(currentStatus->getState() & IStatus::STATE_ERRORS)) + { + start(currentStatus, service); if (!(currentStatus->getState() & IStatus::STATE_ERRORS)) { - if (status != currentStatus) + fb_utils::copyStatus(status, currentStatus); + if (retProvider) { - status->setErrors(currentStatus->getErrors()); - status->setWarnings(currentStatus->getWarnings()); + p->addRef(); + *retProvider = p; } - YService* r = FB_NEW YService(p, service, utfData); - r->addRef(); - return r; - } - switch (currentStatus->getErrors()[1]) - { - case isc_service_att_err: - currentStatus = &tempCheckStatusWrapper; - // fall down... - case isc_unavailable: - break; - - default: - return NULL; + return service; } - - currentStatus->init(); } - if (!(status->getState() & IStatus::STATE_ERRORS)) + switch (currentStatus->getErrors()[1]) { - (Arg::Gds(isc_service_att_err) << - Arg::Gds(isc_no_providers)).copyTo(status); + case isc_service_att_err: + currentStatus = &temp2; + // fall down... + case isc_unavailable: + case isc_wrong_ods: + case isc_badodsver: + case isc_gstat_wrong_ods: + break; + + default: + fb_utils::copyStatus(status, &temp1); + return NULL; } + + currentStatus->init(); } - catch (const Exception& e) - { - if (service) - { - StatusVector temp(NULL); - CheckStatusWrapper tempCheckStatusWrapper(&temp); - service->detach(&tempCheckStatusWrapper); - } - e.stuffException(status); + fb_utils::copyStatus(status, &temp1); + if (!(status->getState() & IStatus::STATE_ERRORS)) + { + (Arg::Gds(isc_service_att_err) << + Arg::Gds(isc_no_providers)).copyTo(status); } return NULL; } +static std::atomic shutdownWaiters(0); +static const SLONG SHUTDOWN_COMPLETE = 1; +static const SLONG SHUTDOWN_STEP = 2; + void Dispatcher::shutdown(CheckStatusWrapper* userStatus, unsigned int timeout, const int reason) { + // set "process exiting" state + if (reason == fb_shutrsn_emergency) + abortShutdown(); + // can't syncronize with already killed threads, just exit if (MasterInterfacePtr()->getProcessExiting()) return; + // wait for other threads that were waiting for shutdown + // that should not take too long due to shutdown started bit + Cleanup cleanShutCnt([&] { + shutdownWaiters -= SHUTDOWN_STEP; + while (shutdownWaiters > SHUTDOWN_STEP - 1) + Thread::yield(); + }); + + // atomically increase shutdownWaiters & check for SHUTDOWN_STARTED + SLONG state = (shutdownWaiters += SHUTDOWN_STEP); + if (state & SHUTDOWN_COMPLETE) + return; + try { DispatcherEntry entry(userStatus, true); @@ -6520,7 +6691,10 @@ void Dispatcher::shutdown(CheckStatusWrapper* userStatus, unsigned int timeout, } if (hasThreads) + { + PluginManager::deleteDelayed(); continue; + } Stack attStack; { @@ -6550,6 +6724,7 @@ void Dispatcher::shutdown(CheckStatusWrapper* userStatus, unsigned int timeout, attachment->release(); } + PluginManager::deleteDelayed(); } // ... and wait for all providers to go away @@ -6572,6 +6747,9 @@ void Dispatcher::shutdown(CheckStatusWrapper* userStatus, unsigned int timeout, e.stuffException(userStatus); iscLogStatus(NULL, userStatus); } + + // no more attempts to run shutdown code even in case of error + shutdownWaiters |= SHUTDOWN_COMPLETE; } void Dispatcher::setDbCryptCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback) diff --git a/travis.sh b/travis.sh deleted file mode 100755 index e2abb0209f3..00000000000 --- a/travis.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -dummy_output() { - while true; do - sleep 9m - echo "dummy output" - done -} - -skip_tests() { - SKIP=skip.txt - echo bugs.core_0870 >> $SKIP -} - -set -e -#set -x -eval "$1"