diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml new file mode 100644 index 0000000..6b42bd7 --- /dev/null +++ b/.github/workflows/build-wheels.yml @@ -0,0 +1,233 @@ +name: Build macOS wheels + +on: + push: + branches: [main] + tags: ["v*"] + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + build: + strategy: + fail-fast: false + matrix: + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + + runs-on: macos-14 + name: "arm64 — Python ${{ matrix.python-version }}" + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache-dependency-path: dpi_bridge/go.sum + + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Decode DPI headers + env: + DPI_HEADERS_TAR_B64: ${{ secrets.DPI_HEADERS_TAR_B64 }} + run: | + mkdir -p dpi_include + echo "$DPI_HEADERS_TAR_B64" | base64 -d | tar xzf - -C dpi_include/ + + - name: Build Go bridge library + run: | + cd dpi_bridge && go build -buildmode=c-shared -o libdmdpi.dylib . + install_name_tool -id @rpath/libdmdpi.dylib libdmdpi.dylib + + - name: Install build tools + run: pip install build delocate + + - name: Build wheel + env: + MACOSX_DEPLOYMENT_TARGET: "14.0" + _PYTHON_HOST_PLATFORM: "macosx-14.0-arm64" + run: DMPYTHON_SKIP_GO_BUILD=1 python -m build --wheel + + - name: Delocate wheel + run: | + mkdir -p dist_fixed + DYLD_LIBRARY_PATH=dpi_bridge delocate-wheel -w dist_fixed dist/*.whl -v + + - name: Verify wheel + run: | + python -m venv /tmp/test_venv + /tmp/test_venv/bin/pip install dist_fixed/*.whl + /tmp/test_venv/bin/python -c "import dmPython; print('dmPython version:', dmPython.version)" + + - name: Check DM secrets availability + id: dm_ready + if: ${{ matrix.python-version == '3.10' }} + env: + DM_TEST_HOST: ${{ secrets.DM_TEST_HOST }} + DM_TEST_PORT: ${{ secrets.DM_TEST_PORT }} + DM_TEST_USER: ${{ secrets.DM_TEST_USER }} + DM_TEST_PASSWORD: ${{ secrets.DM_TEST_PASSWORD }} + run: | + if [ -n "$DM_TEST_HOST" ] && [ -n "$DM_TEST_PORT" ] && [ -n "$DM_TEST_USER" ] && [ -n "$DM_TEST_PASSWORD" ]; then + echo "available=true" >> "$GITHUB_OUTPUT" + else + echo "available=false" >> "$GITHUB_OUTPUT" + fi + + - name: Build extension for optional integration tests + if: ${{ matrix.python-version == '3.10' && steps.dm_ready.outputs.available == 'true' }} + run: DMPYTHON_SKIP_GO_BUILD=1 python setup.py build_ext --inplace + + - name: Run optional DM integration tests + if: ${{ matrix.python-version == '3.10' && steps.dm_ready.outputs.available == 'true' }} + env: + DYLD_LIBRARY_PATH: ${{ github.workspace }}/dpi_bridge + DM_TEST_HOST: ${{ secrets.DM_TEST_HOST }} + DM_TEST_PORT: ${{ secrets.DM_TEST_PORT }} + DM_TEST_USER: ${{ secrets.DM_TEST_USER }} + DM_TEST_PASSWORD: ${{ secrets.DM_TEST_PASSWORD }} + DM_TEST_BOUNDARY_SIZES: ${{ secrets.DM_TEST_BOUNDARY_SIZES }} + DM_TEST_STRESS_ROWS: ${{ secrets.DM_TEST_STRESS_ROWS }} + DM_TEST_STRESS_WORKERS: ${{ secrets.DM_TEST_STRESS_WORKERS }} + DM_TEST_CHURN_LOOPS: ${{ secrets.DM_TEST_CHURN_LOOPS }} + DM_TEST_GC_LOOPS: ${{ secrets.DM_TEST_GC_LOOPS }} + run: | + python -m pip install pytest pytest-timeout pytest-cov + python -m pytest -q -m requires_dm tests --cov=. --cov-report=term-missing --cov-report=xml:coverage.xml + + - name: Upload optional integration coverage + if: ${{ matrix.python-version == '3.10' && steps.dm_ready.outputs.available == 'true' }} + uses: actions/upload-artifact@v4 + with: + name: coverage-wheel-baseline-py${{ matrix.python-version }} + path: coverage.xml + + - name: Skip optional integration tests (missing DM secrets) + if: ${{ matrix.python-version == '3.10' && steps.dm_ready.outputs.available != 'true' }} + run: | + echo "::notice::SKIP_DM_INTEGRATION: DM_TEST_HOST/PORT/USER/PASSWORD secrets are not fully configured." + + - uses: actions/upload-artifact@v4 + with: + name: wheel-arm64-py${{ matrix.python-version }} + path: dist_fixed/*.whl + + release: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: macos-14 + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: dist_fixed + pattern: wheel-* + merge-multiple: true + + - name: Validate wheel set and generate release metadata + env: + TAG_NAME: ${{ github.ref_name }} + run: | + python - <<'PY' + import glob + import json + import os + import re + import subprocess + import sys + + wheels = sorted(glob.glob("dist_fixed/*.whl")) + if len(wheels) != 5: + print(f"Expected 5 wheels, got {len(wheels)}") + print("\n".join(wheels)) + sys.exit(1) + + expected_tags = {"cp39-cp39", "cp310-cp310", "cp311-cp311", "cp312-cp312", "cp313-cp313"} + found_tags = set() + for wheel in wheels: + name = os.path.basename(wheel) + if "arm64.whl" not in name: + print(f"Non-arm64 wheel found: {name}") + sys.exit(1) + match = re.search(r"-(cp\d{2,3}-cp\d{2,3})-macosx_.*_arm64\.whl$", name) + if not match: + print(f"Unrecognized wheel naming pattern: {name}") + sys.exit(1) + found_tags.add(match.group(1)) + if found_tags != expected_tags: + print(f"Wheel tag mismatch. expected={sorted(expected_tags)} found={sorted(found_tags)}") + sys.exit(1) + + with open("dist_fixed/build-metadata.json", "w", encoding="utf-8") as f: + json.dump( + { + "tag": os.environ["TAG_NAME"], + "commit": os.environ.get("GITHUB_SHA", ""), + "workflow": os.environ.get("GITHUB_WORKFLOW", ""), + "run_id": os.environ.get("GITHUB_RUN_ID", ""), + "run_attempt": os.environ.get("GITHUB_RUN_ATTEMPT", ""), + "wheels": [os.path.basename(w) for w in wheels], + }, + f, + ensure_ascii=False, + indent=2, + ) + + subprocess.check_call("shasum -a 256 dist_fixed/*.whl > dist_fixed/checksums.txt", shell=True) + PY + + - name: Upsert GitHub Release + env: + GH_TOKEN: ${{ github.token }} + TAG_NAME: ${{ github.ref_name }} + run: | + if gh release view "$TAG_NAME" >/dev/null 2>&1; then + echo "Release $TAG_NAME already exists, uploading artifacts with --clobber" + gh release upload "$TAG_NAME" dist_fixed/*.whl dist_fixed/checksums.txt dist_fixed/build-metadata.json --clobber + else + echo "Creating release $TAG_NAME" + gh release create "$TAG_NAME" --generate-notes dist_fixed/*.whl dist_fixed/checksums.txt dist_fixed/build-metadata.json + fi + + - name: Verify release assets completeness + env: + GH_TOKEN: ${{ github.token }} + TAG_NAME: ${{ github.ref_name }} + run: | + python - <<'PY' + import json + import os + import re + import subprocess + import sys + + tag = os.environ["TAG_NAME"] + raw = subprocess.check_output( + ["gh", "release", "view", tag, "--json", "assets"], + text=True, + ) + assets = [a["name"] for a in json.loads(raw)["assets"]] + expected_tags = {"cp39-cp39", "cp310-cp310", "cp311-cp311", "cp312-cp312", "cp313-cp313"} + found_tags = set() + for name in assets: + m = re.search(r"-(cp\d{2,3}-cp\d{2,3})-macosx_.*_arm64\.whl$", name) + if m: + found_tags.add(m.group(1)) + missing_tags = sorted(expected_tags - found_tags) + required_files = {"checksums.txt", "build-metadata.json"} + missing_files = sorted(f for f in required_files if f not in assets) + if missing_tags or missing_files: + print("Release assets are incomplete.") + print(f"missing wheel tags: {missing_tags}") + print(f"missing files: {missing_files}") + print(f"assets: {assets}") + sys.exit(1) + print("Release assets verified:", assets) + PY diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..6fc4de9 --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,167 @@ +name: Integration Tests + +on: + pull_request: + branches: [main] + workflow_dispatch: + schedule: + - cron: "0 18 * * *" + +jobs: + pr-lightweight: + if: github.event_name == 'pull_request' + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache-dependency-path: dpi_bridge/go.sum + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Check DM secrets availability + id: dm_ready + run: | + if [ -n "${{ secrets.DM_TEST_HOST }}" ] && [ -n "${{ secrets.DM_TEST_PORT }}" ] && [ -n "${{ secrets.DM_TEST_USER }}" ] && [ -n "${{ secrets.DM_TEST_PASSWORD }}" ]; then + echo "available=true" >> "$GITHUB_OUTPUT" + else + echo "available=false" >> "$GITHUB_OUTPUT" + fi + + - name: Decode DPI headers + if: steps.dm_ready.outputs.available == 'true' + env: + DPI_HEADERS_TAR_B64: ${{ secrets.DPI_HEADERS_TAR_B64 }} + run: | + mkdir -p dpi_include + echo "$DPI_HEADERS_TAR_B64" | base64 -d | tar xzf - -C dpi_include/ + + - name: Build Go bridge library + if: steps.dm_ready.outputs.available == 'true' + run: | + cd dpi_bridge && go build -buildmode=c-shared -o libdmdpi.dylib . + install_name_tool -id @rpath/libdmdpi.dylib libdmdpi.dylib + + - name: Build extension and run P0/P1 + if: steps.dm_ready.outputs.available == 'true' + env: + DYLD_LIBRARY_PATH: ${{ github.workspace }}/dpi_bridge + DM_TEST_HOST: ${{ secrets.DM_TEST_HOST }} + DM_TEST_PORT: ${{ secrets.DM_TEST_PORT }} + DM_TEST_USER: ${{ secrets.DM_TEST_USER }} + DM_TEST_PASSWORD: ${{ secrets.DM_TEST_PASSWORD }} + DM_TEST_BOUNDARY_SIZES: ${{ secrets.DM_TEST_BOUNDARY_SIZES }} + run: | + python -m pip install pytest pytest-timeout pytest-cov + python setup.py build_ext --inplace + python -m pytest -q tests/integration -m "p0_stability or p1_contract" --junitxml=pytest-pr.xml --cov=. --cov-report=term-missing --cov-report=xml:coverage.xml + + - name: Upload coverage report (PR) + if: steps.dm_ready.outputs.available == 'true' + uses: actions/upload-artifact@v4 + with: + name: coverage-pr + path: | + coverage.xml + pytest-pr.xml + + - name: Skip lightweight integration tests + if: steps.dm_ready.outputs.available != 'true' + run: | + echo "::notice::SKIP_DM_INTEGRATION: PR integration tests are skipped because DM secrets are not configured." + + full-regression: + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache-dependency-path: dpi_bridge/go.sum + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Check DM secrets availability + id: dm_ready + run: | + if [ -n "${{ secrets.DM_TEST_HOST }}" ] && [ -n "${{ secrets.DM_TEST_PORT }}" ] && [ -n "${{ secrets.DM_TEST_USER }}" ] && [ -n "${{ secrets.DM_TEST_PASSWORD }}" ]; then + echo "available=true" >> "$GITHUB_OUTPUT" + else + echo "available=false" >> "$GITHUB_OUTPUT" + fi + + - name: Decode DPI headers + if: steps.dm_ready.outputs.available == 'true' + env: + DPI_HEADERS_TAR_B64: ${{ secrets.DPI_HEADERS_TAR_B64 }} + run: | + mkdir -p dpi_include + echo "$DPI_HEADERS_TAR_B64" | base64 -d | tar xzf - -C dpi_include/ + + - name: Build Go bridge library + if: steps.dm_ready.outputs.available == 'true' + run: | + cd dpi_bridge && go build -buildmode=c-shared -o libdmdpi.dylib . + install_name_tool -id @rpath/libdmdpi.dylib libdmdpi.dylib + + - name: Build extension and run P0/P1/P2 + if: steps.dm_ready.outputs.available == 'true' + env: + DYLD_LIBRARY_PATH: ${{ github.workspace }}/dpi_bridge + DM_TEST_HOST: ${{ secrets.DM_TEST_HOST }} + DM_TEST_PORT: ${{ secrets.DM_TEST_PORT }} + DM_TEST_USER: ${{ secrets.DM_TEST_USER }} + DM_TEST_PASSWORD: ${{ secrets.DM_TEST_PASSWORD }} + DM_TEST_BOUNDARY_SIZES: ${{ secrets.DM_TEST_BOUNDARY_SIZES }} + DM_TEST_STRESS_ROWS: ${{ secrets.DM_TEST_STRESS_ROWS }} + DM_TEST_STRESS_WORKERS: ${{ secrets.DM_TEST_STRESS_WORKERS }} + DM_TEST_CHURN_LOOPS: ${{ secrets.DM_TEST_CHURN_LOOPS }} + DM_TEST_GC_LOOPS: ${{ secrets.DM_TEST_GC_LOOPS }} + run: | + python -m pip install pytest pytest-timeout pytest-cov + python setup.py build_ext --inplace + start_ts=$(date +%s) + python -m pytest -q tests/integration -m "p0_stability or p1_contract or p2_scale" --junitxml=pytest-full.xml --cov=. --cov-report=term-missing --cov-report=xml:coverage.xml + end_ts=$(date +%s) + duration=$((end_ts - start_ts)) + python - </dmPython.git +cd dmPython + +# Build the Go bridge + C extension +python setup.py build_ext --inplace + +# Or build a wheel +pip install build +python -m build --wheel +``` + +### Test + +```bash +# Verify the extension loads +python -c "import dmPython; print(dmPython.version)" +``` + +## Pull Request Process + +1. Fork the repository and create a feature branch from `main`. +2. Make your changes with clear, focused commits. +3. Ensure the project builds successfully. +4. Open a pull request against `main` with a clear description of the change. + +## Code Style + +- **C code**: Follow the existing style in the repository. No reformatting of unchanged code. +- **Go code** (`dpi_bridge/`): Use `gofmt`. +- **Python code**: Follow PEP 8. + +## Reporting Issues + +When reporting a bug, please include: + +- macOS version and architecture (`uname -m`) +- Python version (`python --version`) +- dmPython version (`python -c "import dmPython; print(dmPython.version)"`) +- Dameng database version (if applicable) +- Steps to reproduce the issue + +## License + +By contributing, you agree that your contributions will be licensed under the [Mulan PSL v2](http://license.coscl.org.cn/MulanPSL2). diff --git a/ChangeLogs.md b/ChangeLogs.md deleted file mode 100644 index 5816a85..0000000 --- a/ChangeLogs.md +++ /dev/null @@ -1,128 +0,0 @@ -## dmPython - -此包为Python连接达梦数据库的原生驱动。dmPython whl包下载地址:https://pypi.org/project/dmPythpn/。使用方法详见安装目录下的《DM8_dmPython 使用手册》 - -## Extensions - -- 支持sqlalchemy和django框架 - -## Change Logs - -**dmPython v2.5.30(2025-9-3)** - -- 修复了多线程并发释放连接的问题 - -**dmPython v2.5.29(2025-7-31)** - -- 增加了parse_type连接参数 - -**dmPython v2.5.28(2025-7-21)** - -- 修复了dmPython查询空间数据的问题 - -**dmPython v2.5.27(2025-6-17)** - -- 修复了dmPython没有对连接参数长度进行检查的问题 - -**dmPython v2.5.26(2025-4-23)** - -- 修复了dmPython使用executemany函数插入数据时,当字符类型数据中存在当前编码无法识别字符时会发生中断的问题 - -**dmPython v2.5.25(2025-4-15)** - -- 修复了dmPython查询大字段时,内存持续增长的问题 - -**dmPython v2.5.24(2025-4-11)** - -- 修复了dmPython.connect函数没有对输入参数user,password,server,schema长度进行判断的问题 - -**dmPython v2.5.23(2025-4-11)** - -- 修复了Connection.shutdown函数没有对输入参数长度进行判断的问题 - -**dmPython v2.5.22(2025-2-25)** - -- 兼容了Oracle在Number类型scale大于0并且为整数时,会输出其小数形式的处理方式 - -**dmPython v2.5.21(2025-2-19)** - -- 增加了对dmPython.CURSOR类型绑定参数执行的支持 - -**dmPython v2.5.20(2025-1-20)** - -- 修复了使用ipv6地址连接达梦数据库失败的问题。 -- 修复了当输入参数列中有大字段类型是,获取输出参数失败的问题。 - -**dmPython v2.5.19(2025-1-6)** - -- 修复了bit列值为null时,returning into输出参数报错的问题 - -**dmPython v2.5.18(2024-12-31)** - -- 增加了连接参数dmsvc_path,指定dm_svc.conf路径 - -**dmPython v2.5.17(2024-12-26)** - -- 更改了密码策略,不允许使用默认密码 - -**dmPython v2.5.16(2024-11-22)** - -- 修复了returning into输出参数类型为blob时,会导致程序奔溃的问题 -- 修复了dmPython读取bfile有父目录引用时,报错不正常的问题 -- 增加了dmPython安装时可以使用drivers目录作为DM_HOME目录的支持 - -**dmPython v2.5.15(2024-11-20)** - -- 修复了dmPython删除不存在的bfile目录时,会导致程序奔溃的问题 -- 修复了dmPython的callproc和callfunc函数中的sql注入问题 -- 兼容了dm7版本的dpi - -**dmPython v2.5.14(2024-11-19)** - -- 修复了当update和delete语句影响行数为0时,returing into输出参数会导致程序奔溃的问题 - -**dmPython v2.5.13(2024-11-14)** - -- 修复了DM_HOME的搜索逻辑,会优先在当前目录搜索需要的动态库,然后才会去父目录搜索 -- 增加了在使用繁体中文时,使用不支持繁体中文编码的时的报错 - -**dmPython v2.5.12(2024-11-13)** - -- 修复了dmPython使用编码方式PG_ISO_8859_11,PG_KOI8R、PG_SQL_ASCII连接数据库报错的问题 - -**dmPython v2.5.11(2024-9-20)** - -- 修复了绑定参数输入blobl或clob数据时,程序奔溃的问题 -- 消除了Python3.12版本安装dmPython时的警告 - -**dmPython v2.5.10(2024-9-20)** - -- 修复了returning into输出参数返回多行结果时,无法输出空数据的问题 - -**dmPython v2.5.9(2024-8-29)** - -- 增加了对多租户连接参数的支持 -- 修复了游标读取bfile数据后,退出程序时报错资源清理出错的问题 - -**dmPython v2.5.8(2024-7-3)** - -- 修复了多线程下更新blob和clob数据会发生阻塞的问题 -- 增加了对nls_numeric_characters参数的支持,支持以字符串格式返回非标准时间类型 -- 修复了超长数据插入时的字符串截断问题 - -**dmPython v2.5.7(2024-4-15)** - -- 适配dpi prepare本地化的修复,调整了一些函数的使用顺序 -- 增加了returning into输出参数支持返回多行结果的支持 - -**dmPython v2.5.6(2023-12-7)** - -- 修复了获取变长字符串类型时,相关描述信息不准确的问题 - -**dmPython v2.5.5(2023-11-8)** - -- 增加了对Python3.12版本的支持 - -**dmPython v2.5.4(2023-10-25)** - -- 修复了数据库推荐类型为varchar,传入参数类型为int,数据类型转换失败的错误 \ No newline at end of file diff --git a/LICENSE b/LICENSE index e2b7bf8..e2cccfa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,12 +1,12 @@ -Copyright (c) [2017] [Dameng] +Copyright (c) 2017-2026 Dameng -[dmPython] is licensed under Mulan PSL v2. +dmPython is licensed under Mulan PSL v2. You can use this software according to the terms and conditions of the Mulan PSL v2. You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2 -THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIDN, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the Mulan PSL v2 for more details. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..7b0aa13 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,9 @@ +include LICENSE README.md setup.py pyproject.toml docs/README_zh.md +recursive-include src/native *.c *.h +recursive-include dpi_bridge *.go +include dpi_bridge/go.mod dpi_bridge/go.sum +exclude dpi_bridge/libdmdpi.dylib dpi_bridge/libdmdpi.h +prune build +prune .venv +prune .dm_home +prune .claude diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f546a5 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +.PHONY: go-bridge wheel wheel-delocated universal2 clean test-install dpi-headers-secret release-preflight + +# Go bridge library +GO_BRIDGE_DIR = dpi_bridge +DYLIB = $(GO_BRIDGE_DIR)/libdmdpi.dylib + +# Detect architecture +ARCH := $(shell uname -m) + +go-bridge: $(DYLIB) + +$(DYLIB): $(wildcard $(GO_BRIDGE_DIR)/*.go) $(GO_BRIDGE_DIR)/go.mod + cd $(GO_BRIDGE_DIR) && go build -buildmode=c-shared -o libdmdpi.dylib . + install_name_tool -id @rpath/libdmdpi.dylib $(DYLIB) + +# Build wheel (triggers Go build automatically via setup.py) +wheel: + python -m build --wheel + +# Build + delocate for production wheel +wheel-delocated: wheel + mkdir -p dist_fixed + DYLD_LIBRARY_PATH=$(GO_BRIDGE_DIR) delocate-wheel -w dist_fixed dist/*.whl -v + +# Build universal2 wheel (ARM64 + x86_64) +universal2: + # Build ARM64 Go bridge + cd $(GO_BRIDGE_DIR) && CGO_ENABLED=1 GOARCH=arm64 go build -buildmode=c-shared -o libdmdpi_arm64.dylib . + # Build x86_64 Go bridge + cd $(GO_BRIDGE_DIR) && CGO_ENABLED=1 GOARCH=amd64 go build -buildmode=c-shared -o libdmdpi_amd64.dylib . + # Create universal binary + lipo -create $(GO_BRIDGE_DIR)/libdmdpi_arm64.dylib $(GO_BRIDGE_DIR)/libdmdpi_amd64.dylib -output $(DYLIB) + install_name_tool -id @rpath/libdmdpi.dylib $(DYLIB) + # Build wheel with pre-built library + DMPYTHON_SKIP_GO_BUILD=1 python -m build --wheel + mkdir -p dist_fixed + DYLD_LIBRARY_PATH=$(GO_BRIDGE_DIR) delocate-wheel -w dist_fixed dist/*.whl -v + # Clean up arch-specific dylibs + rm -f $(GO_BRIDGE_DIR)/libdmdpi_arm64.dylib $(GO_BRIDGE_DIR)/libdmdpi_amd64.dylib + +# Test install in a temporary venv +test-install: + @echo "Creating temporary venv..." + python -m venv /tmp/dmpython_test_venv + /tmp/dmpython_test_venv/bin/pip install dist_fixed/*.whl + /tmp/dmpython_test_venv/bin/python -c "import dmPython; print('dmPython version:', dmPython.version); print('OK')" + @echo "Test passed! Cleaning up..." + rm -rf /tmp/dmpython_test_venv + +# Release preflight checks (optional: make release-preflight TAG=v2.5.31) +release-preflight: + ./scripts/release_preflight.sh $(TAG) + +# Package DPI headers as base64 for GitHub Secret +dpi-headers-secret: + @tar czf - -C dpi_include . | base64 | pbcopy + @echo "Base64 copied to clipboard. Paste as GitHub secret DPI_HEADERS_TAR_B64" + +# Clean build artifacts +clean: + rm -rf build/ dist/ dist_fixed/ *.egg-info + rm -f $(GO_BRIDGE_DIR)/libdmdpi.dylib $(GO_BRIDGE_DIR)/libdmdpi.h + rm -f $(GO_BRIDGE_DIR)/libdmdpi_arm64.dylib $(GO_BRIDGE_DIR)/libdmdpi_amd64.dylib + rm -f dmPython*.so diff --git a/README.md b/README.md index 454aaae..30c3a8e 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,108 @@ -# dmpython +[![CI](https://github.com/skhe/dmPython/actions/workflows/build-wheels.yml/badge.svg)](https://github.com/skhe/dmPython/actions/workflows/build-wheels.yml) +[![License: MulanPSL-2.0](https://img.shields.io/badge/license-MulanPSL--2.0-blue.svg)](http://license.coscl.org.cn/MulanPSL2) +[![Python versions](https://img.shields.io/badge/python-3.9--3.13-blue.svg)]() +[![macOS ARM64](https://img.shields.io/badge/platform-macOS%20ARM64-lightgrey.svg)]() -该仓库主要提供了支持python连接达梦数据库的python库 +# dmPython-macOS -## 主要功能 +A Python DB-API 2.0 driver for the [Dameng (DM8)](https://www.dameng.com/) database — **macOS ARM64 edition** with a built-in Go bridge. -支持使用python连接达梦数据库,通过python接口操作数据库,进行一系列数据库中例如创表、删表、对于数据增删改查等功能,对于数据内容进行展示。 +This is a community fork of the [official dmPython](https://github.com/DamengDB/dmPython) driver. The upstream project relies on a proprietary C library (`libdmdpi`) that is not available for macOS. This fork replaces it with a Go-based DPI bridge (`dpi_bridge/`), enabling native macOS ARM64 support without requiring a full Dameng installation. -## 使用方法 +## Installation -dmPython源码依赖DM安装目录或者drivers目录(driver目录为DM的驱动目录)中提供的dpi头文件,安装前需要检查环境中是否存在DM安装或者drivers目录,并设置DM_HOME目录: export DM_HOME=/opt/dmdbms 或者export DM_HOME=/drivers 具体路径以实际环境为准,DM_HOME路径下面必须有include目录或者dpi/include目录 +Download a pre-built wheel from [GitHub Releases](https://github.com/skhe/dmPython/releases): -在Windows操作系统下安装dmPython只需要直接执行exe文件即可。Windows操作系统下生成exe文件操作如下: 1.进入到dmPython源码所在目录(setup.py文件所在路径) 2.执行命令:python setup.py bdist_wininst 3.在dist目录下会生成相关安装文件 +```bash +pip install dmPython_macOS-2.5.32-cp312-cp312-macosx_14_0_arm64.whl +``` -LINUX安装方法: 1.进入到dmPython源码所在目录(setup.py文件所在路径) 2.执行命令:python setup.py bdist_rpm 3.在dist目录下会生成相关rpm包 4.在Linux操作系统下使用rpm包安装dmPython。安装和卸载命令参考如下: 安装:rpm -ivh dmPython-2.1-7.1-py33-1.x86_64.rpm --nodeps 卸载:rpm -e dmPython-2.1-1.x86_64 +## Quick Start -windows和linux也可以直接使用源码安装,操作如下: 1.进入到dmPython源码所在目录(setup.py文件所在路径) 2.执行命令:python setup.py install +```python +import dmPython -其他可能有帮助的信息 +conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5236, +) -windows平台生成安装包(exe) python setup.py bdist_wininst +cursor = conn.cursor() +cursor.execute("SELECT * FROM SYSOBJECTS WHERE ROWNUM <= 5") -LINUX平台生成安装包(rprm) python setup.py bdist_rpm +for row in cursor.fetchall(): + print(row) -若安装过程中出现依赖问题,则: -rpm -ivh file.rpm --nodeps -linux安装命令: rpm -ivh dmPython-1.1-7.1-py26-1.x86_64.rpm --nodeps +cursor.close() +conn.close() +``` -linux卸载命令: rpm -e dmPython-1.1-1.x86_64 +## Documentation -源码直接安装(不分平台) python setup.py install +- GitHub Pages: https://skhe.github.io/dmPython/ +- Local preview: -64位平台安装时,需增加DM64宏: 安装脚本setup.py中全局变量defineMacros使用defineMacros = [('DM64', None),];否则,使用defineMacros = []。 +```bash +pip install mkdocs +mkdocs serve +``` -平台执行上述命令时,需先进行如下准备工作: 定义环境变量DM_HOME,WINDOWS平台需要将其添加到环境变量PATH中,linux则不需要: 指定为DM安装目录bin的上层目录,如DM_HOME=C:\dmdbms 或者 export DM_HOME=/opt/dmdbms +## Building from Source -==============================》 WIN平台可能遇到如下问题: Unable to find vcvarsall.bat +**Prerequisites:** -解决方案如下: 进入当前使用python安装目录中Lib/distutils,找到文件msvc9compiler.py,使用UE或者其他文本编辑器将其打开。 在文件msvc9compiler.py中找到: vc_env = query_vcvarsall(VSERSION,plat_spec) +- Go 1.21+ (to compile the DPI bridge) +- Python 3.9 – 3.13 +- DPI header files — place them in `./dpi_include/` or set `DM_HOME` -根据使用本机安装的VS的版本号,对应安装目录(如:C:\Program Files\Microsoft Visual Studio 10.0),则改为: vc_env = query_vcvarsall(10,plat_spec) +```bash +# Clone the repository +git clone https://github.com/skhe/dmPython.git +cd dmPython -==============================》 WIN平台执行import dmPython时,可能会遇到如下问题: +# Build the wheel +python -m build --wheel -import dmPython Traceback (most recent call last): File "", line 1, in ImportError: DLL load failed: 找不到指定的模块 +# Or build the extension in-place for development +python setup.py build_ext --inplace +``` -此时因为dmPython找不到动态库dpi(linux为libdmdpi.so,windows为dmdpi.dll、dmdpi.lib),需要到dpi所在目录执行或者配置环境变量指向dpi所在目录; 若有安装DM,直接配置环境变量指向bin目录或者指向drivers/dpi。 +To skip the Go build step (if you already have `libdmdpi.dylib`): -linux为例:export LD_LIBRARY_PATH=/opt/dmdbms/bin或者export LD_LIBRARY_PATH=/drivers/dpi +```bash +DMPYTHON_SKIP_GO_BUILD=1 python -m build --wheel +``` -==============================》 用户python使用过程中遇到undefined symbol:PyUnicodeUCS2_Format 此问题为编译dmPython的环境的UCS编码与执行环境不匹配导致,常见的有以下两种情况: 1.在不同的操作系统环境中编译和使用dmPython 2.编译或安装dmPython的python程序本身UCS编码与当前操作系统不一致导致 这两种情况都与dmPython源码无关,检查当前环境即可 解决: 第一种直接在同一台机子上编译和使用即可 第二种一般是使用源码安装了python,然后再用python去编译或安装dmPython,因此需要检查在使用源码安装python时,使用的编码与操作系统是否一致,源码安装python参考命令如下: ./configure --prefix=$YOUR_PATH --enable-unicode=ucs4 --enable-unicode选项指定成与操作系统一致的编码即可 +## Project Structure + +``` +dmPython/ +├── setup.py # Build script +├── pyproject.toml # Project metadata +├── docs/ # Project docs (zh README, technical notes) +├── scripts/ # Local/ops scripts +├── src/native/ # C extension sources and headers +├── dpi_bridge/ # Go-based DPI bridge (replaces proprietary libdmdpi) +│ ├── main.go +│ ├── go.mod / go.sum +│ └── ... +├── dpi_include/ # DPI header files (not distributed, see README) +├── src/native/py_Dameng.c/h # Module entry, type registration, exception hierarchy +├── src/native/strct.h # Core struct definitions (Environment, Connection, Cursor) +├── src/native/Connection.c # Connection management +├── src/native/Cursor.c # Cursor operations, SQL execution +├── src/native/var.c # Variable management core +├── src/native/v*.c # Type-specific variable handlers +├── src/native/ex*.c # External object interfaces (LOB, BFILE, Object) +└── .github/workflows/ # CI: builds macOS ARM64 wheels for Python 3.9–3.13 +``` + +## License + +Licensed under [Mulan PSL v2](http://license.coscl.org.cn/MulanPSL2). + +--- + +[中文文档 (docs/README_zh.md)](docs/README_zh.md) diff --git a/docs/README_zh.md b/docs/README_zh.md new file mode 100644 index 0000000..2f632a3 --- /dev/null +++ b/docs/README_zh.md @@ -0,0 +1,117 @@ +[![CI](https://github.com/skhe/dmPython/actions/workflows/build-wheels.yml/badge.svg)](https://github.com/skhe/dmPython/actions/workflows/build-wheels.yml) +[![License: MulanPSL-2.0](https://img.shields.io/badge/license-MulanPSL--2.0-blue.svg)](http://license.coscl.org.cn/MulanPSL2) +[![Python versions](https://img.shields.io/badge/python-3.9--3.13-blue.svg)]() +[![macOS ARM64](https://img.shields.io/badge/platform-macOS%20ARM64-lightgrey.svg)]() + +# dmPython-macOS + +dmPython 是达梦数据库(DM8)的原生 Python 驱动程序,遵循 [Python DB API 2.0](https://www.python.org/dev/peps/pep-0249/) 规范。通过 C 扩展模块和 DPI(Dameng Programming Interface)库与达梦数据库通信。 + +本项目是 [官方 dmPython](https://github.com/DamengDB/dmPython) 的社区 fork。上游项目依赖的专有 C 库 `libdmdpi` 不提供 macOS 版本,本 fork 使用 Go 编写的 DPI 桥接库(`dpi_bridge/`)替代,实现原生 macOS ARM64 支持,无需安装完整的达梦数据库。 + +**当前版本:** 2.5.32 + +## 特性 + +- 遵循 Python DB API 2.0 规范 +- 支持 Python 3.9 – 3.13 +- 支持 SQLAlchemy 和 Django 框架 +- 支持 BLOB/CLOB、BFILE、对象类型等丰富的数据类型 +- 支持元组游标和字典游标两种模式 +- macOS ARM64 原生支持(通过 Go DPI 桥接库) + +## 安装 + +从 [GitHub Releases](https://github.com/skhe/dmPython/releases) 下载预编译 wheel: + +```bash +pip install dmPython_macOS-2.5.32-cp312-cp312-macosx_14_0_arm64.whl +``` + +## 快速开始 + +```python +import dmPython + +# 建立连接 +conn = dmPython.connect(user='SYSDBA', password='SYSDBA001', server='localhost', port=5236) + +# 创建游标并执行 SQL +cursor = conn.cursor() +cursor.execute("SELECT * FROM SYSOBJECTS WHERE ROWNUM <= 5") + +# 获取结果 +rows = cursor.fetchall() +for row in rows: + print(row) + +# 关闭连接 +cursor.close() +conn.close() +``` + +## 从源码构建 + +**前置条件:** + +- Go 1.21+(编译 DPI 桥接库) +- Python 3.9 – 3.13 +- DPI 头文件 — 放入 `./dpi_include/` 目录或设置 `DM_HOME` 环境变量 + +```bash +# 克隆仓库 +git clone https://github.com/skhe/dmPython.git +cd dmPython + +# 构建 wheel +python -m build --wheel + +# 或在本地构建扩展(开发用) +python setup.py build_ext --inplace +``` + +跳过 Go 构建步骤(已有 `libdmdpi.dylib` 时): + +```bash +DMPYTHON_SKIP_GO_BUILD=1 python -m build --wheel +``` + +### 调试追踪 + +在 `setup.py` 中取消以下注释,重新编译后会在当前目录生成 `dmPython_trace.log`: + +```python +define_macros.append(('TRACE', None)) +``` + +## 项目结构 + +``` +dmPython/ +├── setup.py # 构建脚本 +├── pyproject.toml # 项目元数据 +├── docs/ # 项目文档(中文 README、技术报告) +├── scripts/ # 本地/运维脚本 +├── src/native/ # C 扩展源码与头文件 +├── dpi_bridge/ # Go DPI 桥接库(替代专有 libdmdpi) +│ ├── main.go +│ ├── go.mod / go.sum +│ └── ... +├── dpi_include/ # DPI 头文件(不随源码分发,见 README) +├── src/native/py_Dameng.c/h # 模块入口,类型注册,异常层次 +├── src/native/strct.h # 核心结构定义 (Environment, Connection, Cursor) +├── src/native/Connection.c # 连接管理 +├── src/native/Cursor.c # 游标操作,SQL 执行 +├── src/native/var.c # 变量管理核心 +├── src/native/v*.c # 各类型变量处理器 +├── src/native/ex*.c # 外部对象接口 (LOB, BFILE, Object) +└── .github/workflows/ # CI:构建 macOS ARM64 wheels (Python 3.9–3.13) +``` + +## 许可证 + +本项目采用 [木兰宽松许可证 第2版(Mulan PSL v2)](http://license.coscl.org.cn/MulanPSL2) 授权。 + +--- + +[English README (README.md)](../README.md) diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..bf2161d --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,283 @@ +# API 参考 + +本页根据扩展源码 `src/native/py_Dameng.c`、`src/native/Connection.c`、`src/native/Cursor.c` 汇总公开接口。 + +## 模块级对象 + +### DB-API 元信息 + +- `dmPython.apilevel = "2.0"` +- `dmPython.threadsafety = 1` +- `dmPython.paramstyle = "qmark"` +- `dmPython.version` +- `dmPython.buildtime` + +### 连接入口 + +- `dmPython.connect(...)` +- `dmPython.Connect(...)` + +两者均为 `Connection` 类型构造入口。 + +### `connect()` 参数 + +```python +dmPython.connect( + user=None, + password=None, + dsn=None, + host=None, + server=None, + port=None, + access_mode=None, + autoCommit=None, + connection_timeout=None, + login_timeout=None, + txn_isolation=None, + app_name=None, + compress_msg=None, + use_stmt_pool=None, + ssl_path=None, + ssl_pwd=None, + mpp_login=None, + ukey_name=None, + ukey_pin=None, + rwseparate=None, + rwseparate_percent=None, + cursor_rollback_behavior=None, + lang_id=None, + local_code=None, + cursorclass=None, + schema=None, + shake_crypto=None, + catalog=None, + dmsvc_path=None, + parse_type=None, +) +``` + +说明: + +- `host` 与 `server` 互斥(只允许设置一个)。 +- `user` 支持 `user/password@server:port[/schema][?catalog=...]` 形式。 +- 常量参数建议使用模块常量(如 `DSQL_AUTOCOMMIT_ON`、`ISO_LEVEL_READ_COMMITTED`)。 + +### 模块函数 + +- `DateFromTicks(ticks)` +- `TimeFromTicks(ticks)` +- `TimestampFromTicks(ticks)` +- `StringFromBytes(bs)` + +### 日期时间类型别名 + +- `Date` +- `Time` +- `Timestamp` +- `DATETIME` + +### 游标类型常量 + +- `TupleCursor` +- `DictCursor` + +用于 `connect(cursorclass=...)`。 + +## Connection + +### 方法 + +- `cursor()` +- `commit()` +- `rollback()` +- `close()` +- `disconnect()`(`close()` 别名) +- `debug(debug_type=dmPython.DEBUG_OPEN)` +- `shutdown(shutdown_type=dmPython.SHUTDOWN_DEFAULT)` +- `explain(statement)` +- `ping(reconnect=0)` +- `__enter__()` +- `__exit__(exc_type, exc_value, exc_traceback)` + +### 成员属性(只读) + +- `dsn` +- `server_status` +- `warning` + +### 计算属性(含可写项) + +可读写: + +- `access_mode` +- `async_enable` +- `auto_ipd` +- `local_code` +- `lang_id` +- `app_name` +- `txn_isolation` +- `compress_msg` +- `rwseparate` +- `rwseparate_percent` +- `use_stmt_pool` +- `ssl_path` +- `mpp_login` +- `autoCommit` +- `autocommit` +- `connection_dead` +- `connection_timeout` +- `login_timeout` +- `packet_size` +- `port` + +只读: + +- `server_code` +- `current_schema` +- `str_case_sensitive` +- `max_row_size` +- `current_catalog` +- `trx_state` +- `server_version` +- `cursor_rollback_behavior` +- `user` +- `server` +- `inst_name` +- `version` +- `max_identifier_length` +- `outputtypehandler` +- `stmtcachesize` + +以上属性多数存在同名 `DSQL_ATTR_*` 别名,例如: + +- `connection.autoCommit` <=> `connection.DSQL_ATTR_AUTOCOMMIT` +- `connection.port` <=> `connection.DSQL_ATTR_LOGIN_PORT` + +## Cursor + +### 方法 + +- `execute(statement, params=None, **kwargs)` +- `executedirect(statement)` +- `fetchall()` +- `fetchone()` +- `fetchmany(rows=arraysize)` +- `prepare(statement)` +- `parse(statement)`(当前实现返回 `NotSupportedError`) +- `setinputsizes(*args, **kwargs)` +- `executemany(statement, seq_of_params)` +- `callproc(name, params=None)` +- `callfunc(name, params=None)` +- `setoutputsize(size, column=-1)` +- `var(typ, size=0, arraysize=cursor.arraysize, inconverter=None, outconverter=None, typename=None, encoding_errors=None, bypass_decode=False, encodingErrors=None)` +- `arrayvar(...)`(当前实现返回 `NotSupportedError`) +- `bindnames()`(当前实现返回 `NotSupportedError`) +- `close()` +- `next()` +- `nextset()` +- `__enter__()` +- `__exit__(exc_type, exc_value, exc_traceback)` + +### 成员属性 + +- `arraysize`(可写) +- `bindarraysize`(可写) +- `rowcount`(只读) +- `rownumber`(只读) +- `with_rows`(只读) +- `statement`(只读) +- `connection`(只读) +- `column_names`(只读) +- `lastrowid`(只读) +- `execid`(只读) +- `_isClosed`(内部) +- `_statement`(内部) +- `output_stream`(可写) +- `description`(只读计算属性) + +## 异常层次 + +- `Warning` +- `Error` + - `InterfaceError` + - `DatabaseError` + - `DataError` + - `OperationalError` + - `IntegrityError` + - `InternalError` + - `ProgrammingError` + - `NotSupportedError` + +此外还提供 `DmError` 对象(包含 `code`、`offset`、`message`、`context`)。 + +## 常量 + +### 调试与关库 + +- `DEBUG_CLOSE` +- `DEBUG_OPEN` +- `DEBUG_SWITCH` +- `DEBUG_SIMPLE` +- `SHUTDOWN_DEFAULT` +- `SHUTDOWN_ABORT` +- `SHUTDOWN_IMMEDIATE` +- `SHUTDOWN_TRANSACTIONAL` +- `SHUTDOWN_NORMAL` + +### 事务与访问模式 + +- `ISO_LEVEL_READ_DEFAULT` +- `ISO_LEVEL_READ_UNCOMMITTED` +- `ISO_LEVEL_READ_COMMITTED` +- `ISO_LEVEL_REPEATABLE_READ` +- `ISO_LEVEL_SERIALIZABLE` +- `DSQL_MODE_READ_ONLY` +- `DSQL_MODE_READ_WRITE` +- `DSQL_AUTOCOMMIT_ON` +- `DSQL_AUTOCOMMIT_OFF` + +### 编码与语言 + +- `PG_UTF8` +- `PG_GBK` +- `PG_BIG5` +- `PG_ISO_8859_9` +- `PG_EUC_JP` +- `PG_EUC_KR` +- `PG_KOI8R` +- `PG_ISO_8859_1` +- `PG_SQL_ASCII` +- `PG_GB18030` +- `PG_ISO_8859_11` +- `LANGUAGE_CN` +- `LANGUAGE_EN` +- `LANGUAGE_CNT_HK`(条件编译) + +### 其他连接行为 + +- `DSQL_TRUE` +- `DSQL_FALSE` +- `DSQL_RWSEPARATE_ON` +- `DSQL_RWSEPARATE_OFF` +- `DSQL_TRX_ACTIVE` +- `DSQL_TRX_COMPLETE` +- `DSQL_MPP_LOGIN_GLOBAL` +- `DSQL_MPP_LOGIN_LOCAL` +- `DSQL_CB_CLOSE` +- `DSQL_CB_PRESERVE` + +### 数据类型对象 + +模块还导出一组数据类型对象,可用于绑定/类型判断: + +- `INTERVAL`, `YEAR_MONTH_INTERVAL` +- `BLOB`, `CLOB`, `LOB` +- `BFILE`, `exBFILE` +- `LONG_BINARY`, `LONG_STRING` +- `DATE`, `TIME`, `TIMESTAMP` +- `CURSOR` +- `STRING`, `FIXED_STRING`, `BINARY`, `FIXED_BINARY` +- `OBJECTVAR`, `objectvar` +- `NUMBER`, `DOUBLE`, `REAL`, `BOOLEAN`, `DECIMAL` +- `TIME_WITH_TIMEZONE`, `TIMESTAMP_WITH_TIMEZONE` +- `BIGINT`, `ROWID` diff --git a/docs/ci/docs-pages.workflow.yml b/docs/ci/docs-pages.workflow.yml new file mode 100644 index 0000000..9fd4634 --- /dev/null +++ b/docs/ci/docs-pages.workflow.yml @@ -0,0 +1,57 @@ +name: Docs + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: docs-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install docs dependencies + run: | + python -m pip install --upgrade pip + pip install mkdocs + + - name: Build docs + run: mkdocs build --strict + + - name: Setup Pages + if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} + uses: actions/configure-pages@v5 + + - name: Upload Pages artifact + if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} + uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/docs/examples/basic-crud.md b/docs/examples/basic-crud.md new file mode 100644 index 0000000..b1f8a7c --- /dev/null +++ b/docs/examples/basic-crud.md @@ -0,0 +1,60 @@ +# 基本增删改查 + +## 运行方式 + +```bash +python docs/examples/scripts/basic_crud.py +``` + +## 示例代码 + +```python +# docs/examples/scripts/basic_crud.py +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + table = "SKH70_BASIC_CRUD" + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, name VARCHAR(100), score INT)") + + cur.execute(f"INSERT INTO {table}(id, name, score) VALUES (?, ?, ?)", (1, "alice", 88)) + conn.commit() + + cur.execute(f"SELECT id, name, score FROM {table} WHERE id = ?", (1,)) + print("after insert:", cur.fetchone()) + + cur.execute(f"UPDATE {table} SET score = ? WHERE id = ?", (95, 1)) + conn.commit() + + cur.execute(f"SELECT id, name, score FROM {table} WHERE id = ?", (1,)) + print("after update:", cur.fetchone()) + + cur.execute(f"DELETE FROM {table} WHERE id = ?", (1,)) + conn.commit() + + cur.execute(f"SELECT COUNT(*) FROM {table}") + print("after delete:", cur.fetchone()) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() +``` diff --git a/docs/examples/bulk-insert.md b/docs/examples/bulk-insert.md new file mode 100644 index 0000000..2fc656e --- /dev/null +++ b/docs/examples/bulk-insert.md @@ -0,0 +1,50 @@ +# 批量插入 + +## 运行方式 + +```bash +python docs/examples/scripts/bulk_insert.py +``` + +## 示例代码 + +```python +# docs/examples/scripts/bulk_insert.py +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + table = "SKH70_BULK" + rows = [(i, f"user_{i}", i * 10) for i in range(1, 1001)] + + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, name VARCHAR(100), score INT)") + + cur.executemany(f"INSERT INTO {table}(id, name, score) VALUES (?, ?, ?)", rows) + conn.commit() + + cur.execute(f"SELECT COUNT(*) FROM {table}") + print("inserted rows:", cur.fetchone()[0]) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() +``` diff --git a/docs/examples/connection-pool.md b/docs/examples/connection-pool.md new file mode 100644 index 0000000..6a8607c --- /dev/null +++ b/docs/examples/connection-pool.md @@ -0,0 +1,82 @@ +# 连接池 + +驱动本身没有独立 `SessionPool` 类型时,可以在应用层实现简单连接池。 + +## 运行方式 + +```bash +python docs/examples/scripts/connection_pool.py +``` + +## 示例代码 + +```python +# docs/examples/scripts/connection_pool.py +import os +from contextlib import contextmanager +from queue import LifoQueue + +import dmPython + + +class SimpleConnectionPool: + def __init__(self, min_size: int = 1, max_size: int = 5): + self.min_size = min_size + self.max_size = max_size + self._created = 0 + self._idle = LifoQueue(maxsize=max_size) + for _ in range(min_size): + self._idle.put(self._new_conn()) + + def _conn_params(self): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + def _new_conn(self): + self._created += 1 + return dmPython.connect(**self._conn_params()) + + @contextmanager + def acquire(self): + conn = None + try: + if not self._idle.empty(): + conn = self._idle.get() + elif self._created < self.max_size: + conn = self._new_conn() + else: + conn = self._idle.get() + yield conn + finally: + if conn is not None: + self._idle.put(conn) + + def closeall(self): + while not self._idle.empty(): + conn = self._idle.get() + conn.close() + + +def main() -> None: + pool = SimpleConnectionPool(min_size=2, max_size=4) + + with pool.acquire() as conn: + with conn.cursor() as cur: + cur.execute("SELECT 1") + print("conn-1:", cur.fetchone()) + + with pool.acquire() as conn: + with conn.cursor() as cur: + cur.execute("SELECT 2") + print("conn-2:", cur.fetchone()) + + pool.closeall() + + +if __name__ == "__main__": + main() +``` diff --git a/docs/examples/lob-handling.md b/docs/examples/lob-handling.md new file mode 100644 index 0000000..27e83cb --- /dev/null +++ b/docs/examples/lob-handling.md @@ -0,0 +1,62 @@ +# LOB 大对象操作 + +## 运行方式 + +```bash +python docs/examples/scripts/lob_handling.py +``` + +## 示例代码 + +```python +# docs/examples/scripts/lob_handling.py +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def _read_lob(val): + if hasattr(val, "read"): + return val.read() + return val + + +def main() -> None: + table = "SKH70_LOB" + text = "达梦 LOB 示例" * 500 + data = b"DMLOB" * 500 + + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, c CLOB, b BLOB)") + + cur.execute(f"INSERT INTO {table}(id, c, b) VALUES (?, ?, ?)", (1, text, data)) + conn.commit() + + cur.execute(f"SELECT c, b FROM {table} WHERE id = ?", (1,)) + c_val, b_val = cur.fetchone() + + c_content = _read_lob(c_val) + b_content = _read_lob(b_val) + print("clob length:", len(c_content)) + print("blob length:", len(b_content)) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() +``` diff --git a/docs/examples/scripts/basic_crud.py b/docs/examples/scripts/basic_crud.py new file mode 100644 index 0000000..0618333 --- /dev/null +++ b/docs/examples/scripts/basic_crud.py @@ -0,0 +1,47 @@ +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + table = "SKH70_BASIC_CRUD" + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, name VARCHAR(100), score INT)") + + cur.execute(f"INSERT INTO {table}(id, name, score) VALUES (?, ?, ?)", (1, "alice", 88)) + conn.commit() + + cur.execute(f"SELECT id, name, score FROM {table} WHERE id = ?", (1,)) + print("after insert:", cur.fetchone()) + + cur.execute(f"UPDATE {table} SET score = ? WHERE id = ?", (95, 1)) + conn.commit() + + cur.execute(f"SELECT id, name, score FROM {table} WHERE id = ?", (1,)) + print("after update:", cur.fetchone()) + + cur.execute(f"DELETE FROM {table} WHERE id = ?", (1,)) + conn.commit() + + cur.execute(f"SELECT COUNT(*) FROM {table}") + print("after delete:", cur.fetchone()) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() diff --git a/docs/examples/scripts/bulk_insert.py b/docs/examples/scripts/bulk_insert.py new file mode 100644 index 0000000..7b52450 --- /dev/null +++ b/docs/examples/scripts/bulk_insert.py @@ -0,0 +1,37 @@ +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + table = "SKH70_BULK" + rows = [(i, f"user_{i}", i * 10) for i in range(1, 1001)] + + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, name VARCHAR(100), score INT)") + + cur.executemany(f"INSERT INTO {table}(id, name, score) VALUES (?, ?, ?)", rows) + conn.commit() + + cur.execute(f"SELECT COUNT(*) FROM {table}") + print("inserted rows:", cur.fetchone()[0]) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() diff --git a/docs/examples/scripts/connection_pool.py b/docs/examples/scripts/connection_pool.py new file mode 100644 index 0000000..94cea83 --- /dev/null +++ b/docs/examples/scripts/connection_pool.py @@ -0,0 +1,67 @@ +import os +from contextlib import contextmanager +from queue import LifoQueue + +import dmPython + + +class SimpleConnectionPool: + def __init__(self, min_size: int = 1, max_size: int = 5): + self.min_size = min_size + self.max_size = max_size + self._created = 0 + self._idle = LifoQueue(maxsize=max_size) + for _ in range(min_size): + self._idle.put(self._new_conn()) + + def _conn_params(self): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + def _new_conn(self): + self._created += 1 + return dmPython.connect(**self._conn_params()) + + @contextmanager + def acquire(self): + conn = None + try: + if not self._idle.empty(): + conn = self._idle.get() + elif self._created < self.max_size: + conn = self._new_conn() + else: + conn = self._idle.get() + yield conn + finally: + if conn is not None: + self._idle.put(conn) + + def closeall(self): + while not self._idle.empty(): + conn = self._idle.get() + conn.close() + + +def main() -> None: + pool = SimpleConnectionPool(min_size=2, max_size=4) + + with pool.acquire() as conn: + with conn.cursor() as cur: + cur.execute("SELECT 1") + print("conn-1:", cur.fetchone()) + + with pool.acquire() as conn: + with conn.cursor() as cur: + cur.execute("SELECT 2") + print("conn-2:", cur.fetchone()) + + pool.closeall() + + +if __name__ == "__main__": + main() diff --git a/docs/examples/scripts/lob_handling.py b/docs/examples/scripts/lob_handling.py new file mode 100644 index 0000000..c623538 --- /dev/null +++ b/docs/examples/scripts/lob_handling.py @@ -0,0 +1,49 @@ +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def _read_lob(val): + if hasattr(val, "read"): + return val.read() + return val + + +def main() -> None: + table = "SKH70_LOB" + text = "达梦 LOB 示例" * 500 + data = b"DMLOB" * 500 + + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute(f"DROP TABLE IF EXISTS {table}") + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, c CLOB, b BLOB)") + + cur.execute(f"INSERT INTO {table}(id, c, b) VALUES (?, ?, ?)", (1, text, data)) + conn.commit() + + cur.execute(f"SELECT c, b FROM {table} WHERE id = ?", (1,)) + c_val, b_val = cur.fetchone() + + c_content = _read_lob(c_val) + b_content = _read_lob(b_val) + print("clob length:", len(c_content)) + print("blob length:", len(b_content)) + + cur.execute(f"DROP TABLE IF EXISTS {table}") + conn.commit() + cur.close() + conn.close() + + +if __name__ == "__main__": + main() diff --git a/docs/examples/scripts/stored_proc.py b/docs/examples/scripts/stored_proc.py new file mode 100644 index 0000000..badcad1 --- /dev/null +++ b/docs/examples/scripts/stored_proc.py @@ -0,0 +1,51 @@ +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute( + """ +CREATE OR REPLACE PROCEDURE SKH70_PROC(p_in INT, p_out OUT INT) +AS +BEGIN + p_out := p_in * 2; +END; +""" + ) + + cur.execute( + """ +CREATE OR REPLACE FUNCTION SKH70_FUNC(p_in INT) +RETURN INT +AS +BEGIN + RETURN p_in + 100; +END; +""" + ) + conn.commit() + + proc_result = cur.callproc("SKH70_PROC", [21, None]) + func_result = cur.callfunc("SKH70_FUNC", [23]) + + print("callproc:", proc_result) + print("callfunc:", func_result) + + cur.close() + conn.close() + + +if __name__ == "__main__": + main() diff --git a/docs/examples/stored-proc.md b/docs/examples/stored-proc.md new file mode 100644 index 0000000..fe31e8b --- /dev/null +++ b/docs/examples/stored-proc.md @@ -0,0 +1,64 @@ +# 存储过程 + +## 运行方式 + +```bash +python docs/examples/scripts/stored_proc.py +``` + +## 示例代码 + +```python +# docs/examples/scripts/stored_proc.py +import os +import dmPython + + +def conn_params(): + return { + "server": os.getenv("DM_HOST", "localhost"), + "port": int(os.getenv("DM_PORT", "5236")), + "user": os.getenv("DM_USER", "SYSDBA"), + "password": os.getenv("DM_PASSWORD", "SYSDBA001"), + } + + +def main() -> None: + conn = dmPython.connect(**conn_params()) + cur = conn.cursor() + + cur.execute( + """ +CREATE OR REPLACE PROCEDURE SKH70_PROC(p_in INT, p_out OUT INT) +AS +BEGIN + p_out := p_in * 2; +END; +""" + ) + + cur.execute( + """ +CREATE OR REPLACE FUNCTION SKH70_FUNC(p_in INT) +RETURN INT +AS +BEGIN + RETURN p_in + 100; +END; +""" + ) + conn.commit() + + proc_result = cur.callproc("SKH70_PROC", [21, None]) + func_result = cur.callfunc("SKH70_FUNC", [23]) + + print("callproc:", proc_result) + print("callfunc:", func_result) + + cur.close() + conn.close() + + +if __name__ == "__main__": + main() +``` diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..fb1c840 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,25 @@ +# FAQ + +## 1. `host` 和 `server` 有什么区别? + +`connect()` 同时提供了 `host` 与 `server` 参数,两者语义相近,但不能同时设置。 + +## 2. `connect()` 最简参数是什么? + +至少应提供可用凭据和目标地址,常见是:`user`、`password`、`server`、`port`。 + +## 3. 支持字典游标吗? + +支持。连接时传 `cursorclass=dmPython.DictCursor`,查询结果按列名映射为字典。 + +## 4. 为什么 `Cursor.parse()` 报 `NotSupportedError`? + +这是当前实现状态,不是调用方式问题。可使用 `prepare()` 或直接 `execute()`。 + +## 5. 如何查看连接是否失效? + +可读 `connection.connection_dead` 或调用 `connection.ping(reconnect=1)`。 + +## 6. 如何调试服务端日志开关? + +使用 `connection.debug()`,参数可选 `DEBUG_OPEN/DEBUG_CLOSE/DEBUG_SWITCH/DEBUG_SIMPLE`。 diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..0946287 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,34 @@ +# dmPython-macOS 文档 + +这是一套面向 `dmPython-macOS` 的完整使用文档,覆盖: + +- 安装与环境准备 +- 快速开始 +- 完整 API 参考(`connect()`、`Connection`、`Cursor`、异常、常量) +- 可独立运行示例(CRUD、批量、LOB、存储过程、连接池) +- 从官方 `dmPython` 迁移到 macOS 版本的指南 + +## 文档导航 + +- [安装指南](installation.md) +- [快速开始](quickstart.md) +- [API 参考](api-reference.md) +- 示例 + - [基本增删改查](examples/basic-crud.md) + - [批量插入](examples/bulk-insert.md) + - [LOB 大对象操作](examples/lob-handling.md) + - [存储过程](examples/stored-proc.md) + - [连接池](examples/connection-pool.md) +- [迁移指南](migration.md) +- [常见问题](faq.md) + +## 约定 + +本文示例默认通过环境变量读取连接参数: + +- `DM_HOST` +- `DM_PORT` +- `DM_USER` +- `DM_PASSWORD` + +示例默认使用 `DM_PORT=5236`、`DM_USER=SYSDBA`、`DM_PASSWORD=SYSDBA001`。 diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..fcbca17 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,52 @@ +# 安装指南 + +## 支持矩阵 + +- Python: 3.9 - 3.13 +- 平台(本仓库发布目标): macOS ARM64 + +> 说明:本项目是官方 `dmPython` 的 macOS ARM64 社区 fork。Linux/Windows 生产环境请优先评估官方发布版本。 + +## 方式一:安装预编译 wheel(推荐) + +从 GitHub Releases 下载后安装: + +```bash +pip install dmPython_macOS--cp312-cp312-macosx_14_0_arm64.whl +``` + +## 方式二:从源码构建 + +前置条件: + +- Go 1.21+ +- Python 3.9+ +- DPI 头文件(放在 `dpi_include/` 或设置 `DM_HOME`) + +```bash +git clone https://github.com/skhe/dmPython.git +cd dmPython +python -m build --wheel +``` + +本地开发构建扩展: + +```bash +python setup.py build_ext --inplace +``` + +如果本地已有 `libdmdpi.dylib`,可跳过 Go 构建: + +```bash +DMPYTHON_SKIP_GO_BUILD=1 python -m build --wheel +``` + +## 安装验证 + +```bash +python - <<'PY' +import dmPython +print("version:", dmPython.version) +print("buildtime:", dmPython.buildtime) +PY +``` diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 0000000..384806e --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,50 @@ +# 从官方 dmPython 迁移到 macOS 版本 + +## 目标读者 + +- 当前使用官方 `dmPython`,希望在 macOS ARM64 运行 +- 代码层面尽量保持 DB-API 使用方式不变 + +## 兼容性结论 + +在多数业务代码里,迁移只需要替换安装来源,`import dmPython` 与 `connect()/cursor()/execute()` 调用方式保持一致。 + +## 迁移步骤 + +1. 卸载旧包并安装 macOS wheel + +```bash +pip uninstall -y dmPython dmPython-macOS +pip install dmPython_macOS--cp312-cp312-macosx_14_0_arm64.whl +``` + +2. 验证运行时版本 + +```bash +python - <<'PY' +import dmPython +print(dmPython.version) +print(dmPython.buildtime) +PY +``` + +3. 回归关键路径 + +- 建连与断连 +- 事务提交/回滚 +- 批量写入 +- LOB 读写 +- 存储过程调用 + +## 差异与注意事项 + +- 平台定位:本 fork 的发布目标是 macOS ARM64。 +- 底层实现:使用 Go DPI bridge 替代上游依赖的专有 `libdmdpi`。 +- 连接池:驱动本身不提供独立 `SessionPool` 对象,建议应用层连接池(见 [连接池示例](examples/connection-pool.md))。 +- 未支持接口:`Cursor.parse()`、`Cursor.arrayvar()`、`Cursor.bindnames()` 当前返回 `NotSupportedError`。 + +## 常见迁移问题 + +- `ImportError`:确认 wheel Python ABI 与本地 Python 版本匹配。 +- 建连失败:确认 `server/port/user/password`、网络连通性、数据库监听配置。 +- 字符编码问题:检查 `local_code`、`lang_id` 参数设置。 diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 0000000..9300189 --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,37 @@ +# 快速开始 + +## 最小可运行示例 + +```python +import dmPython + +conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5236, +) + +cur = conn.cursor() +cur.execute("SELECT 1") +print(cur.fetchone()) + +cur.close() +conn.close() +``` + +## 使用上下文管理器 + +```python +import dmPython + +with dmPython.connect(user="SYSDBA", password="SYSDBA001", server="localhost", port=5236) as conn: + with conn.cursor() as cur: + cur.execute("SELECT SYSTIMESTAMP") + print(cur.fetchone()) +``` + +## 下一步 + +- 查看 [API 参考](api-reference.md) +- 查看 [示例目录](examples/basic-crud.md) diff --git a/docs/release-checklist.md b/docs/release-checklist.md new file mode 100644 index 0000000..3d31ed7 --- /dev/null +++ b/docs/release-checklist.md @@ -0,0 +1,28 @@ +# Release Checklist + +## 1. Preflight +- [ ] Run `./scripts/release_preflight.sh vX.Y.Z` +- [ ] Confirm workflow lint and actionlint checks are green +- [ ] Confirm version consistency (`pyproject.toml`, `setup.py`, `src/native/py_Dameng.h`, `dmPython.version`) +- [ ] Confirm third-party patch checks pass (`scripts/check_third_party_patch.py`) + +## 2. Regression +- [ ] Run `DYLD_LIBRARY_PATH=/Users/skhe/projects/dmPython/dpi_bridge python3 -m pytest -q -m requires_dm tests` +- [ ] Confirm P0/P1/P2 integration markers are green +- [ ] Confirm no `Segmentation fault` / no `139/-11` exits + +## 3. Tag & CI +- [ ] Push release tag `vX.Y.Z` +- [ ] Confirm `Build macOS wheels` workflow succeeds for all Python targets (`cp39/cp310/cp311/cp312/cp313`) +- [ ] Confirm release step is idempotent (re-run does not fail) + +## 4. Release Assets +- [ ] Confirm 5 arm64 wheel assets exist on release page +- [ ] Confirm `checksums.txt` is attached +- [ ] Confirm `build-metadata.json` is attached +- [ ] Spot-check one wheel install and `import dmPython` + +## 5. Post-release +- [ ] Update `CHANGELOG.md` if needed +- [ ] Verify release notes and links are correct +- [ ] Record any incidents/fixes back into `PATCHES.md` or docs diff --git a/dpi_bridge/dpi_bind.go b/dpi_bridge/dpi_bind.go new file mode 100644 index 0000000..43b8cea --- /dev/null +++ b/dpi_bridge/dpi_bind.go @@ -0,0 +1,156 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +//export dpi_bind_param +func dpi_bind_param(hstmt C.dhstmt, iparam C.udint2, paramType C.sdint2, + ctype C.sdint2, dtype C.sdint2, precision C.ulength, + scale C.sdint2, buf C.dpointer, bufLen C.slength, indPtr *C.slength) C.DPIRETURN { + + return dpi_bind_param2(hstmt, iparam, paramType, ctype, dtype, precision, scale, buf, bufLen, indPtr, nil) +} + +//export dpi_bind_param2 +func dpi_bind_param2(hstmt C.dhstmt, iparam C.udint2, paramType C.sdint2, + ctype C.sdint2, dtype C.sdint2, precision C.ulength, + scale C.sdint2, buf C.dpointer, bufLen C.slength, + indPtr *C.slength, actLenPtr *C.slength) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + idx := int(iparam) + if idx < 1 { + stmt.lastErr = &diagInfo{errorCode: -1, message: fmt.Sprintf("Invalid parameter index: %d", iparam)} + return DSQL_ERROR + } + + stmt.paramBindings[idx] = bindParamInfo{ + paramType: int16(paramType), + cType: int16(ctype), + sqlType: int16(dtype), + precision: uint64(precision), + scale: int16(scale), + dataPtr: unsafe.Pointer(buf), + bufLen: int64(bufLen), + indPtr: indPtr, + actLenPtr: actLenPtr, + } + + return DSQL_SUCCESS +} + +//export dpi_number_params +func dpi_number_params(hstmt C.dhstmt, paramCnt *C.udint2) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if paramCnt != nil { + *paramCnt = C.udint2(stmt.paramCount) + } + return DSQL_SUCCESS +} + +//export dpi_desc_param +func dpi_desc_param(hstmt C.dhstmt, iparam C.udint2, + sqlType *C.sdint2, prec *C.ulength, scale *C.sdint2, nullable *C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + idx := int(iparam) - 1 + if idx < 0 || idx >= len(stmt.params) { + stmt.lastErr = &diagInfo{errorCode: -1, message: fmt.Sprintf("Parameter index %d out of range", iparam)} + return DSQL_ERROR + } + + p := &stmt.params[idx] + if sqlType != nil { + *sqlType = C.sdint2(p.sqlType) + } + if prec != nil { + *prec = C.ulength(p.precision) + } + if scale != nil { + *scale = C.sdint2(p.scale) + } + if nullable != nil { + *nullable = C.sdint2(p.nullable) + } + + return DSQL_SUCCESS +} + +//export dpi_unbind_params +func dpi_unbind_params(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + stmt.paramBindings = make(map[int]bindParamInfo) + return DSQL_SUCCESS +} + +//export dpi_put_data +func dpi_put_data(hstmt C.dhstmt, val C.dpointer, valLen C.slength) C.DPIRETURN { + // data-at-exec: not fully implemented yet + return DSQL_SUCCESS +} + +//export dpi_param_data +func dpi_param_data(hstmt C.dhstmt, valPtr *C.dpointer) C.DPIRETURN { + // data-at-exec: not fully implemented yet + return DSQL_NO_DATA +} + +//export dpi_exec_add_batch +func dpi_exec_add_batch(hstmt C.dhstmt) C.DPIRETURN { + // Batch execution: placeholder + return DSQL_SUCCESS +} + +//export dpi_exec_batch +func dpi_exec_batch(hstmt C.dhstmt) C.DPIRETURN { + // Batch execution: placeholder + return DSQL_SUCCESS +} diff --git a/dpi_bridge/dpi_conn.go b/dpi_bridge/dpi_conn.go new file mode 100644 index 0000000..710d3c5 --- /dev/null +++ b/dpi_bridge/dpi_conn.go @@ -0,0 +1,491 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +typedef dhandle dhobj; +typedef dhandle dhobjdesc; +typedef dhandle dhbfile; +*/ +import "C" +import ( + "context" + "database/sql" + "database/sql/driver" + "fmt" + "strconv" + "strings" + "sync" + "unsafe" + + dm "gitee.com/chunanyong/dm" +) + +// connHandle represents a DPI connection. +type connHandle struct { + mu sync.Mutex + env *envHandle + conn *dm.DmConnection // actual Go driver connection + db *sql.DB // holds the sql.DB for lifecycle management + tx driver.Tx // active transaction (nil if none) + + // Connection parameters (set before login) + host string + port int + user string + password string + schema string + autocommit bool + loginTimeout int + connTimeout int + txnIsolation int + + // Post-login info + serverVersion string + serverCode int32 + + // Diagnostics + lastErr *diagInfo +} + +func newConnHandle(env *envHandle) *connHandle { + return &connHandle{ + env: env, + port: DSQL_DEAFAULT_TCPIP_PORT, + autocommit: false, + serverCode: PG_UTF8, + } +} + +//export dpi_alloc_con +func dpi_alloc_con(henv C.dhenv, pcon *C.dhcon) C.DPIRETURN { + if pcon == nil { + return DSQL_ERROR + } + env, err := getEnvHandle(henv) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn := newConnHandle(env) + id := allocHandle(conn) + *pcon = C.dhcon(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_con +func dpi_free_con(hcon C.dhcon) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + if conn.db != nil { + conn.db.Close() + conn.db = nil + conn.conn = nil + } + conn.mu.Unlock() + + id := ptrToHandle(unsafe.Pointer(hcon)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_set_con_attr +func dpi_set_con_attr(hcon C.dhcon, attrID C.sdint4, val C.dpointer, valLen C.sdint4) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + attr := int32(attrID) + intVal := int(uintptr(val)) + + switch attr { + case DSQL_ATTR_LOGIN_PORT: + conn.port = intVal + case DSQL_ATTR_AUTOCOMMIT: + conn.autocommit = (intVal != 0) + // If already connected, apply autocommit + if conn.conn != nil { + conn.conn.Exec("SET TRANSACTION AUTOCOMMIT " + map[bool]string{true: "ON", false: "OFF"}[conn.autocommit], nil) + } + case DSQL_ATTR_LOGIN_TIMEOUT: + conn.loginTimeout = intVal + case DSQL_ATTR_CONNECTION_TIMEOUT: + conn.connTimeout = intVal + case DSQL_ATTR_TXN_ISOLATION: + conn.txnIsolation = intVal + case DSQL_ATTR_LOGIN_SERVER: + if valLen > 0 { + conn.host = C.GoStringN((*C.char)(val), C.int(valLen)) + } else { + conn.host = C.GoString((*C.char)(val)) + } + case DSQL_ATTR_LOGIN_USER: + if valLen > 0 { + conn.user = C.GoStringN((*C.char)(val), C.int(valLen)) + } else { + conn.user = C.GoString((*C.char)(val)) + } + case DSQL_ATTR_CURRENT_SCHEMA: + if valLen > 0 { + conn.schema = C.GoStringN((*C.char)(val), C.int(valLen)) + } else { + conn.schema = C.GoString((*C.char)(val)) + } + case DSQL_ATTR_APP_NAME, + DSQL_ATTR_SSL_PATH, DSQL_ATTR_SSL_PWD, + DSQL_ATTR_UKEY_NAME, DSQL_ATTR_UKEY_PIN, + DSQL_ATTR_COMPRESS_MSG, DSQL_ATTR_USE_STMT_POOL, + DSQL_ATTR_MPP_LOGIN, DSQL_ATTR_RWSEPARATE, + DSQL_ATTR_RWSEPARATE_PERCENT, DSQL_ATTR_CURSOR_ROLLBACK_BEHAVIOR, + DSQL_ATTR_OSAUTH_TYPE, DSQL_ATTR_DDL_AUTOCOMMIT, + DSQL_ATTR_COMPATIBLE_MODE, DSQL_ATTR_SHAKE_CRYPTO, + DSQL_ATTR_NLS_NUMERIC_CHARACTERS, DSQL_ATTR_DM_SVC_PATH, + DSQL_ATTR_ACCESS_MODE, DSQL_ATTR_PACKET_SIZE, + DSQL_ATTR_CURRENT_CATALOG: + // Accept but ignore these for now + default: + // Unknown attribute — ignore silently + } + return DSQL_SUCCESS +} + +//export dpi_get_con_attr +func dpi_get_con_attr(hcon C.dhcon, attrID C.sdint4, val C.dpointer, bufLen C.sdint4, valLen *C.sdint4) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + attr := int32(attrID) + + switch attr { + case DSQL_ATTR_LOCAL_CODE: + *(*C.sdint4)(val) = C.sdint4(conn.env.localCode) + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_LANG_ID: + *(*C.sdint4)(val) = C.sdint4(conn.env.langID) + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_SERVER_CODE: + *(*C.sdint4)(val) = C.sdint4(conn.serverCode) + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_AUTOCOMMIT: + v := C.udint4(0) + if conn.autocommit { + v = 1 + } + *(*C.udint4)(val) = v + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_TXN_ISOLATION: + *(*C.sdint4)(val) = C.sdint4(conn.txnIsolation) + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_CONNECTION_DEAD: + dead := C.sdint4(0) // DSQL_CD_FALSE + if conn.conn == nil { + dead = 1 // DSQL_CD_TRUE + } else if conn.db != nil { + if err := conn.db.Ping(); err != nil { + dead = 1 + } + } + *(*C.sdint4)(val) = dead + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_SERVER_VERSION: + ver := conn.serverVersion + if ver == "" { + ver = "DM Database Server 64 V8" + } + n := cStringLen((*C.sdbyte)(val), int(bufLen), ver) + if valLen != nil { + *valLen = C.sdint4(n) + } + case DSQL_ATTR_INSTANCE_NAME: + name := "DAMENG" + n := cStringLen((*C.sdbyte)(val), int(bufLen), name) + if valLen != nil { + *valLen = C.sdint4(n) + } + case DSQL_ATTR_CURRENT_SCHEMA: + schema := conn.schema + if schema == "" { + schema = strings.ToUpper(conn.user) + } + n := cStringLen((*C.sdbyte)(val), int(bufLen), schema) + if valLen != nil { + *valLen = C.sdint4(n) + } + case DSQL_ATTR_TRX_STATE: + // 0 = complete, 1 = active + state := C.sdint4(0) + if conn.tx != nil { + state = 1 + } + *(*C.sdint4)(val) = state + if valLen != nil { + *valLen = 4 + } + default: + // Return zero/empty for unknown attributes + *(*C.sdint4)(val) = 0 + if valLen != nil { + *valLen = 4 + } + } + return DSQL_SUCCESS +} + +//export dpi_login +func dpi_login(hcon C.dhcon, svr *C.sdbyte, user *C.sdbyte, pwd *C.sdbyte) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + server := C.GoString((*C.char)(unsafe.Pointer(svr))) + username := C.GoString((*C.char)(unsafe.Pointer(user))) + password := C.GoString((*C.char)(unsafe.Pointer(pwd))) + + // Parse server string: may be "host:port" or "host" or "host/catalog" + host := server + port := conn.port + catalog := "" + + // Check for catalog (host/catalog format) + if idx := strings.Index(host, "/"); idx >= 0 { + catalog = host[idx+1:] + host = host[:idx] + } + + // Check for port in host + if idx := strings.LastIndex(host, ":"); idx >= 0 { + if p, err := strconv.Atoi(host[idx+1:]); err == nil { + port = p + host = host[:idx] + } + } + + if host == "" { + host = "localhost" + } + + conn.user = username + conn.password = password + conn.host = host + conn.port = port + + // Build DSN for Go driver + dsn := fmt.Sprintf("dm://%s:%s@%s:%d", + username, password, host, port) + if catalog != "" { + dsn += "/" + catalog + } + + // Set autoCommit in query params + params := []string{} + if conn.autocommit { + params = append(params, "autoCommit=true") + } else { + params = append(params, "autoCommit=false") + } + if conn.loginTimeout > 0 { + params = append(params, fmt.Sprintf("loginTimeout=%d", conn.loginTimeout)) + } + if conn.connTimeout > 0 { + params = append(params, fmt.Sprintf("socketTimeout=%d", conn.connTimeout*1000)) + } + if len(params) > 0 { + dsn += "?" + strings.Join(params, "&") + } + + db, dbErr := sql.Open("dm", dsn) + if dbErr != nil { + conn.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Failed to open connection: %v", dbErr), + } + return DSQL_ERROR + } + + // Force a real connection + ctx := context.Background() + rawConn, dbErr := db.Conn(ctx) + if dbErr != nil { + db.Close() + conn.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Failed to connect: %v", dbErr), + } + return DSQL_ERROR + } + + // Extract the underlying DmConnection + var dmConn *dm.DmConnection + dbErr = rawConn.Raw(func(driverConn interface{}) error { + var ok bool + dmConn, ok = driverConn.(*dm.DmConnection) + if !ok { + return fmt.Errorf("unexpected driver connection type: %T", driverConn) + } + return nil + }) + rawConn.Close() + if dbErr != nil { + db.Close() + conn.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Failed to get DM connection: %v", dbErr), + } + return DSQL_ERROR + } + + conn.db = db + conn.conn = dmConn + + // Try to get server version + var version string + row := db.QueryRow("SELECT BANNER FROM V$VERSION") + if row.Scan(&version) == nil { + conn.serverVersion = version + } + + // Get server encoding + var serverCode int32 + row = db.QueryRow("SELECT UNICODE") + if row.Scan(&serverCode) == nil { + if serverCode == 1 { + conn.serverCode = PG_UTF8 + } + } + + return DSQL_SUCCESS +} + +//export dpi_loginW +func dpi_loginW(hcon C.dhcon, svr *C.sdbyte, user *C.sdbyte, pwd *C.sdbyte) C.DPIRETURN { + // For now, treat W variant the same as non-W since we handle UTF-8 throughout + return dpi_login(hcon, svr, user, pwd) +} + +//export dpi_logout +func dpi_logout(hcon C.dhcon) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + if conn.tx != nil { + conn.tx.Rollback() + conn.tx = nil + } + if conn.db != nil { + conn.db.Close() + conn.db = nil + conn.conn = nil + } + return DSQL_SUCCESS +} + +//export dpi_commit +func dpi_commit(hcon C.dhcon) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + if conn.db == nil { + conn.lastErr = &diagInfo{errorCode: -1, message: "Not connected"} + return DSQL_ERROR + } + + _, dbErr := conn.db.Exec("COMMIT") + if dbErr != nil { + conn.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Commit failed: %v", dbErr), + } + return DSQL_ERROR + } + conn.tx = nil + return DSQL_SUCCESS +} + +//export dpi_rollback +func dpi_rollback(hcon C.dhcon) C.DPIRETURN { + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + conn.mu.Lock() + defer conn.mu.Unlock() + + if conn.db == nil { + conn.lastErr = &diagInfo{errorCode: -1, message: "Not connected"} + return DSQL_ERROR + } + + _, dbErr := conn.db.Exec("ROLLBACK") + if dbErr != nil { + conn.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Rollback failed: %v", dbErr), + } + return DSQL_ERROR + } + conn.tx = nil + return DSQL_SUCCESS +} + +//export dpi_end_tran +func dpi_end_tran(hndlType C.sdint2, hndl C.dhandle, txnType C.sdint2) C.DPIRETURN { + if int16(txnType) == DSQL_COMMIT { + return dpi_commit(C.dhcon(hndl)) + } + return dpi_rollback(C.dhcon(hndl)) +} + +// setConnDiag sets diagnostic info on a connection handle. +func setConnDiag(conn *connHandle, code int32, msg string) { + conn.lastErr = &diagInfo{errorCode: code, message: msg} +} diff --git a/dpi_bridge/dpi_desc.go b/dpi_bridge/dpi_desc.go new file mode 100644 index 0000000..e374d86 --- /dev/null +++ b/dpi_bridge/dpi_desc.go @@ -0,0 +1,307 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +*/ +import "C" +import ( + "unsafe" +) + +//export dpi_get_desc_field +func dpi_get_desc_field(hdesc C.dhdesc, recNum C.udint2, field C.sdint2, + val C.dpointer, valLen C.sdint4, strLen *C.sdint4) C.DPIRETURN { + + desc, err := getDescHandle(hdesc) + if err != nil { + return DSQL_INVALID_HANDLE + } + + if desc.stmt == nil { + return DSQL_ERROR + } + + desc.stmt.mu.Lock() + defer desc.stmt.mu.Unlock() + + fieldID := int16(field) + idx := int(recNum) - 1 // 1-based + + if desc.descType == 0 { + // Row descriptor + return getRowDescField(desc.stmt, idx, fieldID, val, valLen, strLen) + } + // Param descriptor + return getParamDescField(desc.stmt, idx, fieldID, val, valLen, strLen) +} + +//export dpi_get_desc_fieldW +func dpi_get_desc_fieldW(hdesc C.dhdesc, recNum C.udint2, field C.sdint2, + val C.dpointer, valLen C.sdint4, strLen *C.sdint4) C.DPIRETURN { + return dpi_get_desc_field(hdesc, recNum, field, val, valLen, strLen) +} + +//export dpi_set_desc_field +func dpi_set_desc_field(hdesc C.dhdesc, recNum C.udint2, field C.sdint2, + val C.dpointer, valLen C.sdint4) C.DPIRETURN { + // Accept but do nothing for now + return DSQL_SUCCESS +} + +//export dpi_set_desc_fieldW +func dpi_set_desc_fieldW(hdesc C.dhdesc, recNum C.udint2, field C.sdint2, + val C.dpointer, valLen C.sdint4) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_get_desc_rec +func dpi_get_desc_rec(hdesc C.dhdesc, recNum C.udint2, + nameBuf *C.sdbyte, nameBufLen C.sdint2, nameLen *C.sdint2, + typePtr *C.sdint2, subType *C.sdint2, length *C.slength, + prec *C.sdint2, scale *C.sdint2, nullable *C.sdint2) C.DPIRETURN { + + desc, err := getDescHandle(hdesc) + if err != nil { + return DSQL_INVALID_HANDLE + } + if desc.stmt == nil { + return DSQL_ERROR + } + + desc.stmt.mu.Lock() + defer desc.stmt.mu.Unlock() + + idx := int(recNum) - 1 + + if desc.descType == 0 { + // Row descriptor + if idx < 0 || idx >= len(desc.stmt.columns) { + return DSQL_ERROR + } + col := &desc.stmt.columns[idx] + if nameBuf != nil { + n := cStringLen(nameBuf, int(nameBufLen), col.name) + if nameLen != nil { + *nameLen = C.sdint2(n) + } + } + if typePtr != nil { + *typePtr = C.sdint2(col.sqlType) + } + if subType != nil { + *subType = 0 + } + if length != nil { + *length = C.slength(col.precision) + } + if prec != nil { + *prec = C.sdint2(col.precision) + } + if scale != nil { + *scale = C.sdint2(col.scale) + } + if nullable != nil { + *nullable = C.sdint2(col.nullable) + } + } else { + // Param descriptor + if idx < 0 || idx >= len(desc.stmt.params) { + return DSQL_ERROR + } + p := &desc.stmt.params[idx] + if nameBuf != nil { + n := cStringLen(nameBuf, int(nameBufLen), p.name) + if nameLen != nil { + *nameLen = C.sdint2(n) + } + } + if typePtr != nil { + *typePtr = C.sdint2(p.sqlType) + } + if subType != nil { + *subType = 0 + } + if length != nil { + *length = C.slength(p.precision) + } + if prec != nil { + *prec = C.sdint2(p.precision) + } + if scale != nil { + *scale = C.sdint2(p.scale) + } + if nullable != nil { + *nullable = C.sdint2(p.nullable) + } + } + + return DSQL_SUCCESS +} + +//export dpi_get_desc_recW +func dpi_get_desc_recW(hdesc C.dhdesc, recNum C.udint2, + nameBuf *C.sdbyte, nameBufLen C.sdint2, nameLen *C.sdint2, + typePtr *C.sdint2, subType *C.sdint2, length *C.slength, + prec *C.sdint2, scale *C.sdint2, nullable *C.sdint2) C.DPIRETURN { + return dpi_get_desc_rec(hdesc, recNum, nameBuf, nameBufLen, nameLen, typePtr, subType, length, prec, scale, nullable) +} + +//export dpi_set_desc_rec +func dpi_set_desc_rec(hdesc C.dhdesc, recNum C.udint2, typeVal C.sdint2, subType C.sdint2, + length C.slength, prec C.sdint2, scale C.sdint2, + dataPtr C.dpointer, strLen *C.slength, indPtr *C.slength) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_copy_desc +func dpi_copy_desc(srcDesc C.dhdesc, targetDesc C.dhdesc) C.DPIRETURN { + return DSQL_SUCCESS +} + +func getRowDescField(stmt *stmtHandle, idx int, fieldID int16, val C.dpointer, valLen C.sdint4, strLen *C.sdint4) C.DPIRETURN { + switch fieldID { + case DSQL_DESC_COUNT: + *(*C.sdint2)(val) = C.sdint2(stmt.columnCount) + return DSQL_SUCCESS + + case DSQL_DESC_DISPLAY_SIZE: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.slength)(val) = C.slength(stmt.columns[idx].displaySize) + return DSQL_SUCCESS + + case DSQL_DESC_TYPE: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.sdint2)(val) = C.sdint2(stmt.columns[idx].sqlType) + return DSQL_SUCCESS + + case DSQL_DESC_LENGTH: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.ulength)(val) = C.ulength(stmt.columns[idx].precision) + return DSQL_SUCCESS + + case DSQL_DESC_PRECISION: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.sdint2)(val) = C.sdint2(stmt.columns[idx].precision) + return DSQL_SUCCESS + + case DSQL_DESC_SCALE: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.sdint2)(val) = C.sdint2(stmt.columns[idx].scale) + return DSQL_SUCCESS + + case DSQL_DESC_NULLABLE: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + *(*C.sdint2)(val) = C.sdint2(stmt.columns[idx].nullable) + return DSQL_SUCCESS + + case DSQL_DESC_NAME: + if idx < 0 || idx >= len(stmt.columns) { + return DSQL_ERROR + } + n := cStringLen((*C.sdbyte)(val), int(valLen), stmt.columns[idx].name) + if strLen != nil { + *strLen = C.sdint4(n) + } + return DSQL_SUCCESS + + case DSQL_DESC_OBJ_DESCRIPTOR: + // Return nil object descriptor + *(*C.dpointer)(val) = nil + return DSQL_SUCCESS + + default: + // Return zero for unknown fields + *(*C.sdint4)(val) = 0 + if strLen != nil { + *strLen = C.sdint4(unsafe.Sizeof(C.sdint4(0))) + } + return DSQL_SUCCESS + } +} + +func getParamDescField(stmt *stmtHandle, idx int, fieldID int16, val C.dpointer, valLen C.sdint4, strLen *C.sdint4) C.DPIRETURN { + switch fieldID { + case DSQL_DESC_COUNT: + *(*C.sdint2)(val) = C.sdint2(stmt.paramCount) + return DSQL_SUCCESS + + case DSQL_DESC_PARAMETER_TYPE: + if idx < 0 || idx >= len(stmt.params) { + // Default to INPUT + *(*C.sdint2)(val) = C.sdint2(DSQL_PARAM_INPUT) + return DSQL_SUCCESS + } + *(*C.sdint2)(val) = C.sdint2(stmt.params[idx].paramType) + return DSQL_SUCCESS + + case DSQL_DESC_TYPE: + if idx < 0 || idx >= len(stmt.params) { + *(*C.sdint2)(val) = C.sdint2(DSQL_VARCHAR) + return DSQL_SUCCESS + } + *(*C.sdint2)(val) = C.sdint2(stmt.params[idx].sqlType) + return DSQL_SUCCESS + + case DSQL_DESC_NAME: + if idx < 0 || idx >= len(stmt.params) { + if val != nil { + *(*C.sdbyte)(val) = 0 + } + if strLen != nil { + *strLen = 0 + } + return DSQL_SUCCESS + } + n := cStringLen((*C.sdbyte)(val), int(valLen), stmt.params[idx].name) + if strLen != nil { + *strLen = C.sdint4(n) + } + return DSQL_SUCCESS + + case DSQL_DESC_BIND_PARAMETER_TYPE: + // Default to INPUT + *(*C.sdint2)(val) = C.sdint2(DSQL_PARAM_INPUT) + if idx >= 0 && idx < len(stmt.params) { + *(*C.sdint2)(val) = C.sdint2(stmt.params[idx].paramType) + } + return DSQL_SUCCESS + + case DSQL_DESC_OBJ_DESCRIPTOR: + *(*C.dpointer)(val) = nil + return DSQL_SUCCESS + + default: + *(*C.sdint4)(val) = 0 + return DSQL_SUCCESS + } +} diff --git a/dpi_bridge/dpi_diag.go b/dpi_bridge/dpi_diag.go new file mode 100644 index 0000000..731dd8d --- /dev/null +++ b/dpi_bridge/dpi_diag.go @@ -0,0 +1,254 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +*/ +import "C" +import ( + "strings" + "unsafe" +) + +// getDiagFromHandle retrieves diagnostic info from any handle type. +func getDiagFromHandle(hndlType int16, hndl C.dhandle) *diagInfo { + id := ptrToHandle(unsafe.Pointer(hndl)) + obj, ok := getHandle(id) + if !ok { + return nil + } + + switch h := obj.(type) { + case *envHandle: + return h.lastErr + case *connHandle: + return h.lastErr + case *stmtHandle: + return h.lastErr + case *descHandle: + return h.lastErr + } + return nil +} + +//export dpi_get_diag_rec +func dpi_get_diag_rec(hndlType C.sdint2, hndl C.dhandle, recNum C.sdint2, + errCode *C.sdint4, errMsg *C.sdbyte, bufSz C.sdint2, msgLen *C.sdint2) C.DPIRETURN { + + if recNum != 1 { + return DSQL_NO_DATA + } + + diag := getDiagFromHandle(int16(hndlType), hndl) + if diag == nil { + return DSQL_NO_DATA + } + + if errCode != nil { + *errCode = C.sdint4(diag.errorCode) + } + + if errMsg != nil && bufSz > 0 { + n := cStringLen(errMsg, int(bufSz), diag.message) + if msgLen != nil { + *msgLen = C.sdint2(n) + } + } else if msgLen != nil { + *msgLen = C.sdint2(len(diag.message)) + } + + return DSQL_SUCCESS +} + +//export dpi_get_diag_recW +func dpi_get_diag_recW(hndlType C.sdint2, hndl C.dhandle, recNum C.sdint2, + errCode *C.sdint4, errMsg *C.sdbyte, bufSz C.sdint2, msgLen *C.sdint2) C.DPIRETURN { + return dpi_get_diag_rec(hndlType, hndl, recNum, errCode, errMsg, bufSz, msgLen) +} + +//export dpi_get_diag_field +func dpi_get_diag_field(hndlType C.sdint2, hndl C.dhandle, recNum C.sdint2, + diagID C.sdint2, diagInfo2 C.dpointer, bufLen C.slength, infoLen *C.slength) C.DPIRETURN { + field := int16(diagID) + + switch field { + case DSQL_DIAG_DYNAMIC_FUNCTION_CODE: + // Determine statement type from the SQL text + funcCode := int32(0) // INVALID + id := ptrToHandle(unsafe.Pointer(hndl)) + obj, ok := getHandle(id) + if ok { + if stmt, ok := obj.(*stmtHandle); ok { + stmt.mu.Lock() + funcCode = inferFuncCode(stmt.sql) + stmt.mu.Unlock() + } + } + if diagInfo2 != nil { + *(*C.sdint4)(unsafe.Pointer(diagInfo2)) = C.sdint4(funcCode) + } + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.sdint4(0))) + } + return DSQL_SUCCESS + + case DSQL_DIAG_ROW_COUNT: + // Get row count from statement handle + id := ptrToHandle(unsafe.Pointer(hndl)) + obj, ok := getHandle(id) + if !ok { + return DSQL_INVALID_HANDLE + } + if stmt, ok := obj.(*stmtHandle); ok { + stmt.mu.Lock() + *(*C.sdint8)(diagInfo2) = C.sdint8(stmt.rowsAffected) + stmt.mu.Unlock() + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.sdint8(0))) + } + } + return DSQL_SUCCESS + + case DSQL_DIAG_NUMBER: + diag := getDiagFromHandle(int16(hndlType), hndl) + count := C.sdint4(0) + if diag != nil { + count = 1 + } + *(*C.sdint4)(diagInfo2) = count + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.sdint4(0))) + } + return DSQL_SUCCESS + + case DSQL_DIAG_ERROR_CODE: + if recNum < 1 { + return DSQL_NO_DATA + } + diag := getDiagFromHandle(int16(hndlType), hndl) + if diag == nil { + return DSQL_NO_DATA + } + *(*C.sdint4)(diagInfo2) = C.sdint4(diag.errorCode) + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.sdint4(0))) + } + return DSQL_SUCCESS + + case DSQL_DIAG_MESSAGE_TEXT: + if recNum < 1 { + return DSQL_NO_DATA + } + diag := getDiagFromHandle(int16(hndlType), hndl) + if diag == nil { + return DSQL_NO_DATA + } + n := cStringLen((*C.sdbyte)(diagInfo2), int(bufLen), diag.message) + if infoLen != nil { + *infoLen = C.slength(n) + } + return DSQL_SUCCESS + + case DSQL_DIAG_ROWID: + // Return empty ROWID + if diagInfo2 != nil { + *(*C.sdbyte)(diagInfo2) = 0 + } + if infoLen != nil { + *infoLen = 0 + } + return DSQL_SUCCESS + + case DSQL_DIAG_EXECID: + // Return 0 exec ID (caller passes udint4*) + if diagInfo2 != nil { + *(*C.udint4)(unsafe.Pointer(diagInfo2)) = 0 + } + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.udint4(0))) + } + return DSQL_SUCCESS + + case DSQL_DIAG_EXPLAIN: + // Return empty explain + if diagInfo2 != nil && bufLen > 0 { + *(*C.sdbyte)(diagInfo2) = 0 + } + if infoLen != nil { + *infoLen = 0 + } + return DSQL_SUCCESS + + case DSQL_DIAG_SERVER_STAT: + if diagInfo2 != nil { + *(*C.sdint4)(diagInfo2) = 0 + } + if infoLen != nil { + *infoLen = C.slength(unsafe.Sizeof(C.sdint4(0))) + } + return DSQL_SUCCESS + + default: + return DSQL_ERROR + } +} + +//export dpi_get_diag_fieldW +func dpi_get_diag_fieldW(hndlType C.sdint2, hndl C.dhandle, recNum C.sdint2, + diagID C.sdint2, diagInfo2 C.dpointer, bufLen C.slength, infoLen *C.slength) C.DPIRETURN { + return dpi_get_diag_field(hndlType, hndl, recNum, diagID, diagInfo2, bufLen, infoLen) +} + +// inferFuncCode determines the statement type code from the SQL text. +func inferFuncCode(sqlStr string) int32 { + s := strings.TrimSpace(sqlStr) + if len(s) == 0 { + return DSQL_DIAG_FUNC_CODE_INVALID + } + // Find the first keyword + upper := strings.ToUpper(s) + // Remove leading parentheses + for strings.HasPrefix(upper, "(") { + upper = strings.TrimSpace(upper[1:]) + } + + switch { + case strings.HasPrefix(upper, "SELECT"): + return DSQL_DIAG_FUNC_CODE_SELECT + case strings.HasPrefix(upper, "INSERT"): + return DSQL_DIAG_FUNC_CODE_INSERT + case strings.HasPrefix(upper, "UPDATE"): + return DSQL_DIAG_FUNC_CODE_UPDATE + case strings.HasPrefix(upper, "DELETE"): + return DSQL_DIAG_FUNC_CODE_DELETE + case strings.HasPrefix(upper, "MERGE"): + return DSQL_DIAG_FUNC_CODE_MERGE + case strings.HasPrefix(upper, "CALL") || strings.HasPrefix(upper, "EXEC"): + return DSQL_DIAG_FUNC_CODE_CALL + case strings.HasPrefix(upper, "CREATE TABLE"): + return DSQL_DIAG_FUNC_CODE_CREATE_TAB + case strings.HasPrefix(upper, "DROP TABLE"): + return DSQL_DIAG_FUNC_CODE_DROP_TAB + case strings.HasPrefix(upper, "SET SCHEMA"): + return DSQL_DIAG_FUNC_CODE_SET_CURRENT_SCHEMA + default: + return DSQL_DIAG_FUNC_CODE_INVALID + } +} diff --git a/dpi_bridge/dpi_env.go b/dpi_bridge/dpi_env.go new file mode 100644 index 0000000..2fb3540 --- /dev/null +++ b/dpi_bridge/dpi_env.go @@ -0,0 +1,128 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +*/ +import "C" +import ( + "sync" + "unsafe" +) + +// envHandle represents a DPI environment. +type envHandle struct { + mu sync.Mutex + localCode int32 // PG_UTF8 etc. + langID int32 // LANGUAGE_CN etc. + lastErr *diagInfo +} + +// diagInfo stores diagnostic information for error reporting. +type diagInfo struct { + errorCode int32 + message string +} + +func newEnvHandle() *envHandle { + return &envHandle{ + localCode: PG_UTF8, + langID: LANGUAGE_EN, + } +} + +//export dpi_module_init +func dpi_module_init() C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_module_deinit +func dpi_module_deinit() C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_alloc_env +func dpi_alloc_env(penv *C.dhenv) C.DPIRETURN { + if penv == nil { + return DSQL_ERROR + } + env := newEnvHandle() + id := allocHandle(env) + *penv = C.dhenv(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_env +func dpi_free_env(henv C.dhenv) C.DPIRETURN { + id := ptrToHandle(unsafe.Pointer(henv)) + if freeHandle(id) { + return DSQL_SUCCESS + } + return DSQL_INVALID_HANDLE +} + +//export dpi_set_env_attr +func dpi_set_env_attr(henv C.dhenv, attrID C.sdint4, val C.dpointer, valLen C.sdint4) C.DPIRETURN { + env, err := getEnvHandle(henv) + if err != nil { + return DSQL_INVALID_HANDLE + } + env.mu.Lock() + defer env.mu.Unlock() + + intVal := int32(uintptr(val)) + + switch int32(attrID) { + case DSQL_ATTR_LOCAL_CODE: + env.localCode = intVal + case DSQL_ATTR_LANG_ID: + env.langID = intVal + default: + // Unknown attribute — ignore silently + } + return DSQL_SUCCESS +} + +//export dpi_get_env_attr +func dpi_get_env_attr(henv C.dhenv, attrID C.sdint4, val C.dpointer, bufLen C.sdint4, valLen *C.sdint4) C.DPIRETURN { + env, err := getEnvHandle(henv) + if err != nil { + return DSQL_INVALID_HANDLE + } + env.mu.Lock() + defer env.mu.Unlock() + + switch int32(attrID) { + case DSQL_ATTR_LOCAL_CODE: + *(*C.sdint4)(val) = C.sdint4(env.localCode) + if valLen != nil { + *valLen = C.sdint4(unsafe.Sizeof(C.sdint4(0))) + } + case DSQL_ATTR_LANG_ID: + *(*C.sdint4)(val) = C.sdint4(env.langID) + if valLen != nil { + *valLen = C.sdint4(unsafe.Sizeof(C.sdint4(0))) + } + default: + return DSQL_ERROR + } + return DSQL_SUCCESS +} diff --git a/dpi_bridge/dpi_fetch.go b/dpi_bridge/dpi_fetch.go new file mode 100644 index 0000000..ea3ea69 --- /dev/null +++ b/dpi_bridge/dpi_fetch.go @@ -0,0 +1,1236 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; + +typedef struct { + sdint2 year; + udint2 month; + udint2 day; + udint2 hour; + udint2 minute; + udint2 second; + udint4 fraction; +} dpi_timestamp_t; + +typedef struct { + sdint2 year; + udint2 month; + udint2 day; +} dpi_date_t; + +typedef struct { + udint2 hour; + udint2 minute; + udint2 second; +} dpi_time_t; + +#define DPI_MAX_NUMERIC_LEN 16 +typedef struct { + udbyte precision; + signed char scale; + udbyte sign; + udbyte val[DPI_MAX_NUMERIC_LEN]; +} dpi_numeric_t; +*/ +import "C" +import ( + "database/sql" + "encoding/binary" + "fmt" + "math" + "math/big" + "strconv" + "strings" + "time" + "unsafe" +) + +//export dpi_number_columns +func dpi_number_columns(hstmt C.dhstmt, colCnt *C.sdint2) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if colCnt != nil { + *colCnt = C.sdint2(stmt.columnCount) + } + return DSQL_SUCCESS +} + +//export dpi_desc_column +func dpi_desc_column(hstmt C.dhstmt, icol C.sdint2, name *C.sdbyte, bufLen C.sdint2, + nameLen *C.sdint2, sqltype *C.sdint2, colSz *C.ulength, + decDigits *C.sdint2, nullable *C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + idx := int(icol) - 1 // icol is 1-based + if idx < 0 || idx >= len(stmt.columns) { + stmt.lastErr = &diagInfo{errorCode: -1, message: fmt.Sprintf("Column index %d out of range", icol)} + return DSQL_ERROR + } + + col := &stmt.columns[idx] + + if name != nil && bufLen > 0 { + n := cStringLen(name, int(bufLen), col.name) + if nameLen != nil { + *nameLen = C.sdint2(n) + } + } else if nameLen != nil { + *nameLen = C.sdint2(len(col.name)) + } + + if sqltype != nil { + *sqltype = C.sdint2(col.sqlType) + } + if colSz != nil { + *colSz = C.ulength(col.precision) + } + if decDigits != nil { + *decDigits = C.sdint2(col.scale) + } + if nullable != nil { + *nullable = C.sdint2(col.nullable) + } + + return DSQL_SUCCESS +} + +//export dpi_desc_columnW +func dpi_desc_columnW(hstmt C.dhstmt, icol C.sdint2, name *C.sdbyte, bufLen C.sdint2, + nameLen *C.sdint2, sqltype *C.sdint2, colSz *C.ulength, + decDigits *C.sdint2, nullable *C.sdint2) C.DPIRETURN { + return dpi_desc_column(hstmt, icol, name, bufLen, nameLen, sqltype, colSz, decDigits, nullable) +} + +//export dpi_col_attr +func dpi_col_attr(hstmt C.dhstmt, icol C.udint2, fldID C.udint2, + chrAttr C.dpointer, bufLen C.sdint2, chrAttrLen *C.sdint2, + numAttr *C.slength) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + idx := int(icol) - 1 + if idx < 0 || idx >= len(stmt.columns) { + if int16(fldID) == DSQL_COLUMN_COUNT { + if numAttr != nil { + *numAttr = C.slength(stmt.columnCount) + } + return DSQL_SUCCESS + } + return DSQL_ERROR + } + + col := &stmt.columns[idx] + field := int16(fldID) + + switch field { + case DSQL_COLUMN_COUNT: + if numAttr != nil { + *numAttr = C.slength(stmt.columnCount) + } + case DSQL_COLUMN_NAME: + if chrAttr != nil { + n := cStringLen((*C.sdbyte)(chrAttr), int(bufLen), col.name) + if chrAttrLen != nil { + *chrAttrLen = C.sdint2(n) + } + } + case DSQL_COLUMN_TYPE: + if numAttr != nil { + *numAttr = C.slength(col.sqlType) + } + case DSQL_COLUMN_LENGTH: + if numAttr != nil { + *numAttr = C.slength(col.precision) + } + case DSQL_COLUMN_PRECISION: + if numAttr != nil { + *numAttr = C.slength(col.precision) + } + case DSQL_COLUMN_SCALE: + if numAttr != nil { + *numAttr = C.slength(col.scale) + } + case DSQL_COLUMN_DISPLAY_SIZE: + if numAttr != nil { + *numAttr = C.slength(col.displaySize) + } + case DSQL_COLUMN_NULLABLE: + if numAttr != nil { + *numAttr = C.slength(col.nullable) + } + case DSQL_COLUMN_TABLE_NAME: + if chrAttr != nil { + n := cStringLen((*C.sdbyte)(chrAttr), int(bufLen), col.tableName) + if chrAttrLen != nil { + *chrAttrLen = C.sdint2(n) + } + } + default: + if numAttr != nil { + *numAttr = 0 + } + } + + return DSQL_SUCCESS +} + +//export dpi_col_attrW +func dpi_col_attrW(hstmt C.dhstmt, icol C.udint2, fldID C.udint2, + chrAttr C.dpointer, bufLen C.sdint2, chrAttrLen *C.sdint2, + numAttr *C.slength) C.DPIRETURN { + return dpi_col_attr(hstmt, icol, fldID, chrAttr, bufLen, chrAttrLen, numAttr) +} + +//export dpi_bind_col +func dpi_bind_col(hstmt C.dhstmt, icol C.udint2, ctype C.sdint2, + val C.dpointer, bufLen C.slength, ind *C.slength) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + stmt.colBindings[int(icol)] = bindColInfo{ + cType: int16(ctype), + dataPtr: unsafe.Pointer(val), + bufLen: int64(bufLen), + indPtr: ind, + } + return DSQL_SUCCESS +} + +//export dpi_bind_col2 +func dpi_bind_col2(hstmt C.dhstmt, icol C.udint2, ctype C.sdint2, + val C.dpointer, bufLen C.slength, ind *C.slength, actLen *C.slength) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + stmt.colBindings[int(icol)] = bindColInfo{ + cType: int16(ctype), + dataPtr: unsafe.Pointer(val), + bufLen: int64(bufLen), + indPtr: ind, + actLenPtr: actLen, + } + return DSQL_SUCCESS +} + +//export dpi_unbind_columns +func dpi_unbind_columns(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + stmt.colBindings = make(map[int]bindColInfo) + return DSQL_SUCCESS +} + +//export dpi_fetch +func dpi_fetch(hstmt C.dhstmt, rowNum *C.ulength) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if stmt.cachedRows == nil || stmt.fetchPos >= len(stmt.cachedRows) { + if rowNum != nil { + *rowNum = 0 + } + return DSQL_NO_DATA + } + + // Calculate per-element sizes for each bound column + type colElemInfo struct { + elemSize uintptr // size of one element in the buffer + indStride uintptr // stride for indicator array (sizeof(slength)) + } + colElems := make(map[int]colElemInfo) + for colIdx, bind := range stmt.colBindings { + elemSz := cTypeSize(bind.cType) + if elemSz == 0 { + // For variable-length types, bufLen is already the per-element size + // (var->bufferSize from dmPython, total buffer = allocatedElements * bufferSize) + elemSz = uintptr(bind.bufLen) + } + colElems[colIdx] = colElemInfo{ + elemSize: elemSz, + indStride: unsafe.Sizeof(C.slength(0)), + } + } + + // Fetch up to rowArraySize rows from cache + fetched := uint64(0) + numCols := int(stmt.columnCount) + for fetched < stmt.rowArraySize && stmt.fetchPos < len(stmt.cachedRows) { + row := stmt.cachedRows[stmt.fetchPos] + stmt.currentRow = row + + // Write values to bound column buffers at the correct array offset + for colIdx := 1; colIdx <= numCols; colIdx++ { + bind, ok := stmt.colBindings[colIdx] + if !ok { + continue + } + ei := colElems[colIdx] + // Create an offset binding for this row + rowBind := bind + if fetched > 0 && ei.elemSize > 0 { + rowBind.dataPtr = unsafe.Pointer(uintptr(bind.dataPtr) + uintptr(fetched)*ei.elemSize) + if bind.indPtr != nil { + rowBind.indPtr = (*C.slength)(unsafe.Pointer(uintptr(unsafe.Pointer(bind.indPtr)) + uintptr(fetched)*ei.indStride)) + } + if bind.actLenPtr != nil { + rowBind.actLenPtr = (*C.slength)(unsafe.Pointer(uintptr(unsafe.Pointer(bind.actLenPtr)) + uintptr(fetched)*ei.indStride)) + } + } + writeValueToBinding(row[colIdx-1], rowBind, stmt.columns[colIdx-1].sqlType) + } + + stmt.fetchPos++ + fetched++ + + // For array fetch, set row status + if stmt.rowStatusPtr != nil { + statusArr := (*[1 << 20]C.udint2)(stmt.rowStatusPtr) + statusArr[fetched-1] = 0 // DSQL_ROW_SUCCESS + } + } + + stmt.rowsFetched = int64(fetched) + + // Set rows fetched pointer + if stmt.rowsFetchedPtr != nil { + *(*C.ulength)(stmt.rowsFetchedPtr) = C.ulength(fetched) + } + + if rowNum != nil { + *rowNum = C.ulength(fetched) + } + + if fetched == 0 { + return DSQL_NO_DATA + } + + return DSQL_SUCCESS +} + +// cTypeSize returns the fixed size of a C type, or 0 for variable-length types. +func cTypeSize(cType int16) uintptr { + switch cType { + case DSQL_C_STINYINT, DSQL_C_UTINYINT, DSQL_C_BIT: + return 1 + case DSQL_C_SSHORT, DSQL_C_USHORT: + return 2 + case DSQL_C_SLONG, DSQL_C_ULONG: + return 4 + case DSQL_C_SBIGINT, DSQL_C_UBIGINT: + return 8 + case DSQL_C_FLOAT: + return 4 + case DSQL_C_DOUBLE: + return 8 + case DSQL_C_TIMESTAMP: + return unsafe.Sizeof(C.dpi_timestamp_t{}) + case DSQL_C_DATE: + return unsafe.Sizeof(C.dpi_date_t{}) + case DSQL_C_TIME: + return unsafe.Sizeof(C.dpi_time_t{}) + case DSQL_C_NUMERIC: + return 19 // DPI_MAX_NUMERIC_LEN(16) + precision + scale + sign + default: + return 0 // variable-length (string, binary, etc.) + } +} + +//export dpi_fetch_scroll +func dpi_fetch_scroll(hstmt C.dhstmt, orient C.sdint2, offset C.slength, rowNum *C.ulength) C.DPIRETURN { + // For now, only support FETCH_NEXT + return dpi_fetch(hstmt, rowNum) +} + +//export dpi_get_data +func dpi_get_data(hstmt C.dhstmt, icol C.udint2, ctype C.sdint2, + val C.dpointer, bufLen C.slength, valLen *C.slength) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + idx := int(icol) - 1 + if idx < 0 || idx >= len(stmt.currentRow) { + return DSQL_ERROR + } + + rawVal := stmt.currentRow[idx] + if rawVal == nil { + if valLen != nil { + *valLen = C.slength(DSQL_NULL_DATA) + } + return DSQL_SUCCESS + } + + bind := bindColInfo{ + cType: int16(ctype), + dataPtr: unsafe.Pointer(val), + bufLen: int64(bufLen), + indPtr: valLen, + } + + sqlType := int16(DSQL_VARCHAR) + if idx < len(stmt.columns) { + sqlType = stmt.columns[idx].sqlType + } + + writeValueToBinding(rawVal, bind, sqlType) + return DSQL_SUCCESS +} + +//export dpi_get_data2 +func dpi_get_data2(hstmt C.dhstmt, icol C.udint2, ctype C.sdint2, + val C.dpointer, bufLen C.slength, valLen *C.slength, actLen *C.slength) C.DPIRETURN { + return dpi_get_data(hstmt, icol, ctype, val, bufLen, valLen) +} + +//export dpi_get_dataW +func dpi_get_dataW(hstmt C.dhstmt, icol C.udint2, ctype C.sdint2, + val C.dpointer, bufLen C.slength, valLen *C.slength) C.DPIRETURN { + return dpi_get_data(hstmt, icol, ctype, val, bufLen, valLen) +} + +//export dpi_close_cursor +func dpi_close_cursor(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + stmt.cachedRows = nil + stmt.fetchPos = 0 + stmt.currentRow = nil + stmt.columns = nil + stmt.columnCount = 0 + return DSQL_SUCCESS +} + +//export dpi_more_results +func dpi_more_results(hstmt C.dhstmt) C.DPIRETURN { + // Go's database/sql doesn't easily support multiple result sets + return DSQL_NO_DATA +} + +//export dpi_row_count +func dpi_row_count(hstmt C.dhstmt, rowNum *C.sdint8) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if rowNum != nil { + if stmt.cachedRows != nil { + // Return the actual cached row count for SELECT queries. + *rowNum = C.sdint8(len(stmt.cachedRows)) + } else { + *rowNum = C.sdint8(stmt.rowsAffected) + } + } + return DSQL_SUCCESS +} + +// writeValueToBinding writes a Go value into a C buffer according to the binding info. +func writeValueToBinding(val interface{}, bind bindColInfo, sqlType int16) { + if val == nil { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + + if bind.dataPtr == nil { + // Just report the length + s := fmt.Sprintf("%v", val) + if bind.indPtr != nil { + *bind.indPtr = C.slength(len(s)) + } + return + } + + cType := bind.cType + + switch cType { + case DSQL_C_NCHAR, DSQL_C_CHAR, DSQL_C_WCHAR: + writeStringValue(val, bind) + case DSQL_C_SLONG: + writeInt32Value(val, bind) + case DSQL_C_ULONG: + writeUint32Value(val, bind) + case DSQL_C_SSHORT: + writeInt16Value(val, bind) + case DSQL_C_USHORT: + writeUint16Value(val, bind) + case DSQL_C_SBIGINT: + writeInt64Value(val, bind) + case DSQL_C_UBIGINT: + writeUint64Value(val, bind) + case DSQL_C_FLOAT: + writeFloat32Value(val, bind) + case DSQL_C_DOUBLE: + writeFloat64Value(val, bind) + case DSQL_C_STINYINT: + writeInt8Value(val, bind) + case DSQL_C_UTINYINT: + writeUint8Value(val, bind) + case DSQL_C_BIT: + writeBitValue(val, bind) + case DSQL_C_BINARY: + writeBinaryValue(val, bind) + case DSQL_C_TIMESTAMP: + writeTimestampValue(val, bind) + case DSQL_C_DATE: + writeDateValue(val, bind) + case DSQL_C_TIME: + writeTimeValue(val, bind) + case DSQL_C_NUMERIC: + writeNumericValue(val, bind) + case DSQL_C_LOB_HANDLE: + writeLobHandleValue(val, bind, sqlType) + default: + // Default: treat as string + writeStringValue(val, bind) + } +} + +func writeStringValue(val interface{}, bind bindColInfo) { + var s string + switch v := val.(type) { + case string: + s = v + case []byte: + s = string(v) + case time.Time: + s = v.Format("2006-01-02 15:04:05.000000") + case sql.NullString: + if !v.Valid { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + s = v.String + default: + s = fmt.Sprintf("%v", v) + } + + b := []byte(s) + n := len(b) + bufLen := int(bind.bufLen) + + if bind.cType == DSQL_C_NCHAR || bind.cType == DSQL_C_WCHAR { + // NTS: include null terminator space + if n >= bufLen { + n = bufLen - 1 + } + } else if bind.cType == DSQL_C_CHAR { + // No null terminator + if n > bufLen { + n = bufLen + } + } + + if n > 0 { + C.memcpy(bind.dataPtr, unsafe.Pointer(&b[0]), C.size_t(n)) + } + + // Null terminate for NCHAR/WCHAR + if bind.cType == DSQL_C_NCHAR || bind.cType == DSQL_C_WCHAR { + *(*C.sdbyte)(unsafe.Pointer(uintptr(bind.dataPtr) + uintptr(n))) = 0 + } + + if bind.indPtr != nil { + *bind.indPtr = C.slength(len(b)) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(n) + } +} + +func toInt64(val interface{}) (int64, bool) { + switch v := val.(type) { + case int64: + return v, true + case int32: + return int64(v), true + case int: + return int64(v), true + case int16: + return int64(v), true + case int8: + return int64(v), true + case uint64: + return int64(v), true + case uint32: + return int64(v), true + case uint16: + return int64(v), true + case uint8: + return int64(v), true + case float64: + return int64(v), true + case float32: + return int64(v), true + case string: + if n, err := strconv.ParseInt(v, 10, 64); err == nil { + return n, true + } + if f, err := strconv.ParseFloat(v, 64); err == nil { + return int64(f), true + } + case bool: + if v { + return 1, true + } + return 0, true + case []byte: + return toInt64(string(v)) + } + return 0, false +} + +func toFloat64(val interface{}) (float64, bool) { + switch v := val.(type) { + case float64: + return v, true + case float32: + return float64(v), true + case int64: + return float64(v), true + case int32: + return float64(v), true + case int: + return float64(v), true + case string: + if f, err := strconv.ParseFloat(v, 64); err == nil { + return f, true + } + case []byte: + return toFloat64(string(v)) + } + return 0, false +} + +func writeInt32Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.sdint4)(bind.dataPtr) = C.sdint4(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.sdint4(0))) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(unsafe.Sizeof(C.sdint4(0))) + } +} + +func writeUint32Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.udint4)(bind.dataPtr) = C.udint4(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.udint4(0))) + } +} + +func writeInt16Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.sdint2)(bind.dataPtr) = C.sdint2(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.sdint2(0))) + } +} + +func writeUint16Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.udint2)(bind.dataPtr) = C.udint2(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.udint2(0))) + } +} + +func writeInt64Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.sdint8)(bind.dataPtr) = C.sdint8(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.sdint8(0))) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(unsafe.Sizeof(C.sdint8(0))) + } +} + +func writeUint64Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.udint8)(bind.dataPtr) = C.udint8(n) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.udint8(0))) + } +} + +func writeFloat32Value(val interface{}, bind bindColInfo) { + f, ok := toFloat64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.float)(bind.dataPtr) = C.float(f) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.float(0))) + } +} + +func writeFloat64Value(val interface{}, bind bindColInfo) { + f, ok := toFloat64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.double)(bind.dataPtr) = C.double(f) + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.double(0))) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(unsafe.Sizeof(C.double(0))) + } +} + +func writeInt8Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.sdbyte)(bind.dataPtr) = C.sdbyte(n) + if bind.indPtr != nil { + *bind.indPtr = 1 + } +} + +func writeUint8Value(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + *(*C.udbyte)(bind.dataPtr) = C.udbyte(n) + if bind.indPtr != nil { + *bind.indPtr = 1 + } +} + +func writeBitValue(val interface{}, bind bindColInfo) { + n, ok := toInt64(val) + if !ok { + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + if n != 0 { + *(*C.sdint4)(bind.dataPtr) = 1 + } else { + *(*C.sdint4)(bind.dataPtr) = 0 + } + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.sdint4(0))) + } +} + +func writeBinaryValue(val interface{}, bind bindColInfo) { + var b []byte + switch v := val.(type) { + case []byte: + b = v + case string: + b = []byte(v) + default: + b = []byte(fmt.Sprintf("%v", v)) + } + + n := len(b) + if n > int(bind.bufLen) { + n = int(bind.bufLen) + } + if n > 0 { + C.memcpy(bind.dataPtr, unsafe.Pointer(&b[0]), C.size_t(n)) + } + if bind.indPtr != nil { + *bind.indPtr = C.slength(len(b)) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(n) + } +} + +func writeLobHandleValue(val interface{}, bind bindColInfo, sqlType int16) { + var data []byte + switch v := val.(type) { + case nil: + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + case []byte: + data = make([]byte, len(v)) + copy(data, v) + case string: + data = []byte(v) + default: + s := fmt.Sprintf("%v", v) + data = []byte(s) + } + + lobType := DSQL_BLOB + if sqlType == DSQL_CLOB { + lobType = DSQL_CLOB + } + lob := &lobHandle{ + data: data, + lobType: lobType, + } + id := allocHandle(lob) + *(*C.dhloblctr)(bind.dataPtr) = C.dhloblctr(handleToPtr(id)) + + ptrSize := C.slength(unsafe.Sizeof(uintptr(0))) + if bind.indPtr != nil { + *bind.indPtr = ptrSize + } + if bind.actLenPtr != nil { + *bind.actLenPtr = ptrSize + } +} + +func writeTimestampValue(val interface{}, bind bindColInfo) { + var t time.Time + switch v := val.(type) { + case time.Time: + t = v + case string: + // Try parsing various formats + formats := []string{ + "2006-01-02 15:04:05.999999999", + "2006-01-02 15:04:05", + "2006-01-02", + } + for _, f := range formats { + if parsed, err := time.Parse(f, v); err == nil { + t = parsed + break + } + } + default: + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + + ts := (*C.dpi_timestamp_t)(bind.dataPtr) + ts.year = C.sdint2(t.Year()) + ts.month = C.udint2(t.Month()) + ts.day = C.udint2(t.Day()) + ts.hour = C.udint2(t.Hour()) + ts.minute = C.udint2(t.Minute()) + ts.second = C.udint2(t.Second()) + ts.fraction = C.udint4(t.Nanosecond()) + + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.dpi_timestamp_t{})) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(unsafe.Sizeof(C.dpi_timestamp_t{})) + } +} + +func writeDateValue(val interface{}, bind bindColInfo) { + var t time.Time + switch v := val.(type) { + case time.Time: + t = v + case string: + if parsed, err := time.Parse("2006-01-02", v); err == nil { + t = parsed + } + default: + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + + d := (*C.dpi_date_t)(bind.dataPtr) + d.year = C.sdint2(t.Year()) + d.month = C.udint2(t.Month()) + d.day = C.udint2(t.Day()) + + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.dpi_date_t{})) + } +} + +func writeTimeValue(val interface{}, bind bindColInfo) { + var t time.Time + switch v := val.(type) { + case time.Time: + t = v + case string: + if parsed, err := time.Parse("15:04:05", v); err == nil { + t = parsed + } + default: + if bind.indPtr != nil { + *bind.indPtr = C.slength(DSQL_NULL_DATA) + } + return + } + + tm := (*C.dpi_time_t)(bind.dataPtr) + tm.hour = C.udint2(t.Hour()) + tm.minute = C.udint2(t.Minute()) + tm.second = C.udint2(t.Second()) + + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.dpi_time_t{})) + } +} + +func writeNumericValue(val interface{}, bind bindColInfo) { + // Convert value to string first, then to numeric struct + var s string + switch v := val.(type) { + case string: + s = v + case []byte: + s = string(v) + case int64: + s = strconv.FormatInt(v, 10) + case float64: + s = strconv.FormatFloat(v, 'f', -1, 64) + default: + s = fmt.Sprintf("%v", v) + } + + num := (*C.dpi_numeric_t)(bind.dataPtr) + + // Parse sign + negative := false + if strings.HasPrefix(s, "-") { + negative = true + s = s[1:] + } + if negative { + num.sign = 0 + } else { + num.sign = 1 + } + + // Parse integer and decimal parts + parts := strings.SplitN(s, ".", 2) + intPart := parts[0] + decPart := "" + if len(parts) > 1 { + decPart = parts[1] + } + + // Set precision and scale + num.precision = C.udbyte(len(intPart) + len(decPart)) + num.scale = C.sdbyte(len(decPart)) + + // Convert to big integer representation + fullDigits := intPart + decPart + bigVal := new(big.Int) + bigVal.SetString(fullDigits, 10) + + // Store bytes in little-endian format + bBytes := bigVal.Bytes() + for i := 0; i < 16; i++ { + num.val[i] = 0 + } + // Reverse to little-endian + for i, j := 0, len(bBytes)-1; i <= j; i, j = i+1, j-1 { + bBytes[i], bBytes[j] = bBytes[j], bBytes[i] + } + for i := 0; i < len(bBytes) && i < 16; i++ { + num.val[i] = C.udbyte(bBytes[i]) + } + + if bind.indPtr != nil { + *bind.indPtr = C.slength(unsafe.Sizeof(C.dpi_numeric_t{})) + } + if bind.actLenPtr != nil { + *bind.actLenPtr = C.slength(unsafe.Sizeof(C.dpi_numeric_t{})) + } +} + +// extractBoundValue reads a value from a parameter binding buffer. +func extractBoundValue(bind bindParamInfo) interface{} { + if bind.indPtr != nil { + switch *bind.indPtr { + case C.slength(DSQL_NULL_DATA): + return nil + case C.slength(DSQL_DATA_AT_EXEC): + return extractDataAtExecValue(bind) + } + } + if bind.dataPtr == nil { + return nil + } + + switch bind.cType { + case DSQL_C_NCHAR, DSQL_C_CHAR, DSQL_C_WCHAR: + if bind.indPtr != nil && *bind.indPtr >= 0 { + return C.GoStringN((*C.char)(bind.dataPtr), C.int(*bind.indPtr)) + } + return C.GoString((*C.char)(bind.dataPtr)) + case DSQL_C_SLONG: + return int64(*(*C.sdint4)(bind.dataPtr)) + case DSQL_C_ULONG: + return int64(*(*C.udint4)(bind.dataPtr)) + case DSQL_C_SSHORT: + return int64(*(*C.sdint2)(bind.dataPtr)) + case DSQL_C_USHORT: + return int64(*(*C.udint2)(bind.dataPtr)) + case DSQL_C_SBIGINT: + return int64(*(*C.sdint8)(bind.dataPtr)) + case DSQL_C_UBIGINT: + return int64(*(*C.udint8)(bind.dataPtr)) + case DSQL_C_FLOAT: + return float64(*(*C.float)(bind.dataPtr)) + case DSQL_C_DOUBLE: + return float64(*(*C.double)(bind.dataPtr)) + case DSQL_C_STINYINT: + return int64(*(*C.sdbyte)(bind.dataPtr)) + case DSQL_C_UTINYINT: + return int64(*(*C.udbyte)(bind.dataPtr)) + case DSQL_C_BIT: + return int64(*(*C.sdint4)(bind.dataPtr)) + case DSQL_C_BINARY: + length := int64(bind.bufLen) + if bind.indPtr != nil && *bind.indPtr >= 0 { + length = int64(*bind.indPtr) + } + return C.GoBytes(bind.dataPtr, C.int(length)) + case DSQL_C_TIMESTAMP: + ts := (*C.dpi_timestamp_t)(bind.dataPtr) + return time.Date( + int(ts.year), time.Month(ts.month), int(ts.day), + int(ts.hour), int(ts.minute), int(ts.second), + int(ts.fraction), time.Local, + ) + case DSQL_C_DATE: + d := (*C.dpi_date_t)(bind.dataPtr) + return time.Date(int(d.year), time.Month(d.month), int(d.day), 0, 0, 0, 0, time.Local) + case DSQL_C_TIME: + t := (*C.dpi_time_t)(bind.dataPtr) + return time.Date(0, 1, 1, int(t.hour), int(t.minute), int(t.second), 0, time.Local) + case DSQL_C_NUMERIC: + num := (*C.dpi_numeric_t)(bind.dataPtr) + return numericToString(num) + case DSQL_C_LOB_HANDLE: + hlob := *(*C.dhloblctr)(bind.dataPtr) + if hlob == nil { + return nil + } + lob, err := getLobHandle(hlob) + if err != nil { + return nil + } + lob.mu.Lock() + data := make([]byte, len(lob.data)) + copy(data, lob.data) + lobType := lob.lobType + lob.mu.Unlock() + if bind.sqlType == DSQL_CLOB || lobType == DSQL_CLOB { + return string(data) + } + return data + default: + // Treat as string + if bind.indPtr != nil && *bind.indPtr >= 0 { + return C.GoStringN((*C.char)(bind.dataPtr), C.int(*bind.indPtr)) + } + return C.GoString((*C.char)(bind.dataPtr)) + } +} + +func extractDataAtExecValue(bind bindParamInfo) interface{} { + if bind.dataPtr == nil { + return nil + } + + // LongString/LongBinary stores the real payload pointer in an sdint8 slot. + ptrVal := uintptr(*(*C.sdint8)(bind.dataPtr)) + dataLen := 0 + if bind.actLenPtr != nil && *bind.actLenPtr > 0 { + dataLen = int(*bind.actLenPtr) + } + + switch bind.cType { + case DSQL_C_BINARY: + if dataLen == 0 { + return []byte{} + } + if ptrVal == 0 { + return []byte{} + } + return C.GoBytes(unsafe.Pointer(ptrVal), C.int(dataLen)) + case DSQL_C_NCHAR, DSQL_C_CHAR, DSQL_C_WCHAR: + if dataLen == 0 { + return "" + } + if ptrVal == 0 { + return "" + } + raw := C.GoBytes(unsafe.Pointer(ptrVal), C.int(dataLen)) + return string(raw) + default: + if dataLen == 0 || ptrVal == 0 { + return nil + } + return C.GoBytes(unsafe.Pointer(ptrVal), C.int(dataLen)) + } +} + +func numericToString(num *C.dpi_numeric_t) string { + // Read the val bytes into a big.Int (little-endian) + b := make([]byte, 16) + for i := 0; i < 16; i++ { + b[i] = byte(num.val[i]) + } + // Reverse to big-endian + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + // Trim leading zeros + start := 0 + for start < len(b)-1 && b[start] == 0 { + start++ + } + b = b[start:] + + bigVal := new(big.Int) + bigVal.SetBytes(b) + + s := bigVal.String() + scale := int(num.scale) + if scale > 0 { + if len(s) <= scale { + s = strings.Repeat("0", scale-len(s)+1) + s + } + s = s[:len(s)-scale] + "." + s[len(s)-scale:] + } + + if num.sign == 0 { + s = "-" + s + } + return s +} + +// Unused but keeping for potential future use +var _ = binary.LittleEndian +var _ = math.Float64frombits diff --git a/dpi_bridge/dpi_lob.go b/dpi_bridge/dpi_lob.go new file mode 100644 index 0000000..4af8a3b --- /dev/null +++ b/dpi_bridge/dpi_lob.go @@ -0,0 +1,291 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +typedef dhandle dhbfile; +*/ +import "C" +import ( + "sync" + "unsafe" +) + +// lobHandle represents a LOB locator. +type lobHandle struct { + mu sync.Mutex + conn *connHandle + data []byte // LOB data buffer + lobType int // DSQL_BLOB or DSQL_CLOB + lastErr *diagInfo +} + +//export dpi_alloc_lob_locator +func dpi_alloc_lob_locator(hstmt C.dhstmt, plob *C.dhloblctr) C.DPIRETURN { + if plob == nil { + return DSQL_ERROR + } + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob := &lobHandle{conn: stmt.conn, lobType: DSQL_BLOB} + id := allocHandle(lob) + *plob = C.dhloblctr(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_alloc_lob_locator2 +func dpi_alloc_lob_locator2(hcon C.dhcon, plob *C.dhloblctr) C.DPIRETURN { + if plob == nil { + return DSQL_ERROR + } + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob := &lobHandle{conn: conn, lobType: DSQL_BLOB} + id := allocHandle(lob) + *plob = C.dhloblctr(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_lob_locator +func dpi_free_lob_locator(hlob C.dhloblctr) C.DPIRETURN { + if hlob == nil { + return DSQL_SUCCESS + } + id := ptrToHandle(unsafe.Pointer(hlob)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_lob_get_length +func dpi_lob_get_length(hlob C.dhloblctr, length *C.slength) C.DPIRETURN { + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + if length != nil { + *length = C.slength(len(lob.data)) + } + return DSQL_SUCCESS +} + +//export dpi_lob_get_length2 +func dpi_lob_get_length2(hlob C.dhloblctr, length *C.sdint8) C.DPIRETURN { + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + if length != nil { + *length = C.sdint8(len(lob.data)) + } + return DSQL_SUCCESS +} + +//export dpi_lob_read +func dpi_lob_read(hlob C.dhloblctr, startPos C.ulength, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength) C.DPIRETURN { + + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + start := int(startPos) - 1 // 1-based to 0-based + if start < 0 { + start = 0 + } + if start >= len(lob.data) { + if dataGet != nil { + *dataGet = 0 + } + return DSQL_NO_DATA + } + + toRead := int(dataToRead) + if toRead < 0 { + toRead = 0 + } + available := len(lob.data) - start + if toRead > available { + toRead = available + } + if toRead > int(bufLen) { + toRead = int(bufLen) + } + + if toRead > 0 && valBuf != nil { + C.memcpy(unsafe.Pointer(valBuf), unsafe.Pointer(&lob.data[start]), C.size_t(toRead)) + } + + if dataGet != nil { + *dataGet = C.slength(toRead) + } + + return DSQL_SUCCESS +} + +//export dpi_lob_read2 +func dpi_lob_read2(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength) C.DPIRETURN { + return dpi_lob_read(hlob, C.ulength(startPos), ctype, dataToRead, valBuf, bufLen, dataGet) +} + +//export dpi_lob_read3 +func dpi_lob_read3(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength, dataGetBytes *C.slength) C.DPIRETURN { + rt := dpi_lob_read(hlob, C.ulength(startPos), ctype, dataToRead, valBuf, bufLen, dataGet) + if dataGetBytes != nil && dataGet != nil { + *dataGetBytes = *dataGet + } + return rt +} + +//export dpi_lob_write +func dpi_lob_write(hlob C.dhloblctr, startPos C.ulength, ctype C.sdint2, + val C.dpointer, bytesToWrite C.ulength, dataWrited *C.ulength) C.DPIRETURN { + + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + start := int(startPos) - 1 + if start < 0 { + start = 0 + } + toWrite := int(bytesToWrite) + if toWrite > 0 && val == nil { + if dataWrited != nil { + *dataWrited = 0 + } + lob.lastErr = &diagInfo{errorCode: -1, message: "LOB write with nil buffer"} + return DSQL_ERROR + } + + newData := C.GoBytes(unsafe.Pointer(val), C.int(toWrite)) + + // Ensure buffer is large enough + needed := start + toWrite + if needed > len(lob.data) { + grown := make([]byte, needed) + copy(grown, lob.data) + lob.data = grown + } + copy(lob.data[start:], newData) + + if dataWrited != nil { + *dataWrited = C.ulength(toWrite) + } + + return DSQL_SUCCESS +} + +//export dpi_lob_write2 +func dpi_lob_write2(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + val C.dpointer, bytesToWrite C.ulength, dataWrited *C.ulength) C.DPIRETURN { + return dpi_lob_write(hlob, C.ulength(startPos), ctype, val, bytesToWrite, dataWrited) +} + +//export dpi_lob_truncate +func dpi_lob_truncate(hlob C.dhloblctr, length C.ulength, dataLen *C.ulength) C.DPIRETURN { + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + newLen := int(length) + if newLen < len(lob.data) { + lob.data = lob.data[:newLen] + } + + if dataLen != nil { + *dataLen = C.ulength(len(lob.data)) + } + + return DSQL_SUCCESS +} + +//export dpi_lob_truncate2 +func dpi_lob_truncate2(hlob C.dhloblctr, length C.udint8, dataLen *C.udint8) C.DPIRETURN { + lob, err := getLobHandle(hlob) + if err != nil { + return DSQL_INVALID_HANDLE + } + lob.mu.Lock() + defer lob.mu.Unlock() + + newLen := int(length) + if newLen < len(lob.data) { + lob.data = lob.data[:newLen] + } + + if dataLen != nil { + *dataLen = C.udint8(len(lob.data)) + } + + return DSQL_SUCCESS +} + +// LOB W (wide) variants +//export dpi_lob_readW +func dpi_lob_readW(hlob C.dhloblctr, startPos C.ulength, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength) C.DPIRETURN { + return dpi_lob_read(hlob, startPos, ctype, dataToRead, valBuf, bufLen, dataGet) +} + +//export dpi_lob_readW2 +func dpi_lob_readW2(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength) C.DPIRETURN { + return dpi_lob_read2(hlob, startPos, ctype, dataToRead, valBuf, bufLen, dataGet) +} + +//export dpi_lob_readW3 +func dpi_lob_readW3(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + dataToRead C.slength, valBuf C.dpointer, bufLen C.slength, dataGet *C.slength, dataGetBytes *C.slength) C.DPIRETURN { + return dpi_lob_read3(hlob, startPos, ctype, dataToRead, valBuf, bufLen, dataGet, dataGetBytes) +} + +//export dpi_lob_writeW +func dpi_lob_writeW(hlob C.dhloblctr, startPos C.ulength, ctype C.sdint2, + val C.dpointer, bytesToWrite C.ulength, dataWrited *C.ulength) C.DPIRETURN { + return dpi_lob_write(hlob, startPos, ctype, val, bytesToWrite, dataWrited) +} + +//export dpi_lob_writeW2 +func dpi_lob_writeW2(hlob C.dhloblctr, startPos C.udint8, ctype C.sdint2, + val C.dpointer, bytesToWrite C.ulength, dataWrited *C.ulength) C.DPIRETURN { + return dpi_lob_write2(hlob, startPos, ctype, val, bytesToWrite, dataWrited) +} diff --git a/dpi_bridge/dpi_meta.go b/dpi_bridge/dpi_meta.go new file mode 100644 index 0000000..707e43d --- /dev/null +++ b/dpi_bridge/dpi_meta.go @@ -0,0 +1,355 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +*/ +import "C" +import ( + "fmt" + "unsafe" +) + +// Catalog functions that execute SQL queries and return result sets. + +func goStringFromUdbyte(s *C.udbyte, length C.sdint2) string { + if s == nil || length == 0 { + return "" + } + if length < 0 { + return C.GoString((*C.char)(unsafe.Pointer(s))) + } + return C.GoStringN((*C.char)(unsafe.Pointer(s)), C.int(length)) +} + +//export dpi_tables +func dpi_tables(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + tabletype *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + schema := goStringFromUdbyte(schemaname, namelength2) + table := goStringFromUdbyte(tablename, namelength3) + ttype := goStringFromUdbyte(tabletype, namelength4) + + sql := "SELECT NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, NULL AS REMARKS FROM ALL_TABLES WHERE 1=1" + if schema != "" && schema != "%" { + sql += fmt.Sprintf(" AND OWNER = '%s'", schema) + } + if table != "" && table != "%" { + sql += fmt.Sprintf(" AND TABLE_NAME LIKE '%s'", table) + } + if ttype != "" && ttype != "%" { + sql += fmt.Sprintf(" AND TABLE_TYPE = '%s'", ttype) + } + + return execMetaQuery(stmt, sql) +} + +//export dpi_columns +func dpi_columns(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + columnname *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + schema := goStringFromUdbyte(schemaname, namelength2) + table := goStringFromUdbyte(tablename, namelength3) + column := goStringFromUdbyte(columnname, namelength4) + + sql := `SELECT NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM, TABLE_NAME, COLUMN_NAME, + DATA_TYPE AS DATA_TYPE_CODE, DATA_TYPE AS TYPE_NAME, + DATA_LENGTH AS COLUMN_SIZE, DATA_LENGTH AS BUFFER_LENGTH, + DATA_SCALE AS DECIMAL_DIGITS, 10 AS NUM_PREC_RADIX, + CASE NULLABLE WHEN 'Y' THEN 1 ELSE 0 END AS NULLABLE, + NULL AS REMARKS, DATA_DEFAULT AS COLUMN_DEF, + DATA_TYPE AS SQL_DATA_TYPE, NULL AS SQL_DATETIME_SUB, + DATA_LENGTH AS CHAR_OCTET_LENGTH, COLUMN_ID AS ORDINAL_POSITION, + NULLABLE AS IS_NULLABLE + FROM ALL_TAB_COLUMNS WHERE 1=1` + + if schema != "" && schema != "%" { + sql += fmt.Sprintf(" AND OWNER = '%s'", schema) + } + if table != "" && table != "%" { + sql += fmt.Sprintf(" AND TABLE_NAME LIKE '%s'", table) + } + if column != "" && column != "%" { + sql += fmt.Sprintf(" AND COLUMN_NAME LIKE '%s'", column) + } + sql += " ORDER BY TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION" + + return execMetaQuery(stmt, sql) +} + +//export dpi_columns2 +func dpi_columns2(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + columnname *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + return dpi_columns(hstmt, catalogname, namelength1, schemaname, namelength2, tablename, namelength3, columnname, namelength4) +} + +//export dpi_primarykeys +func dpi_primarykeys(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + schema := goStringFromUdbyte(schemaname, namelength2) + table := goStringFromUdbyte(tablename, namelength3) + + sql := `SELECT NULL AS TABLE_CAT, CON.OWNER AS TABLE_SCHEM, CON.TABLE_NAME, + COL.COLUMN_NAME, COL.POSITION AS KEY_SEQ, CON.CONSTRAINT_NAME AS PK_NAME + FROM ALL_CONSTRAINTS CON + JOIN ALL_CONS_COLUMNS COL ON CON.CONSTRAINT_NAME = COL.CONSTRAINT_NAME AND CON.OWNER = COL.OWNER + WHERE CON.CONSTRAINT_TYPE = 'P'` + + if schema != "" && schema != "%" { + sql += fmt.Sprintf(" AND CON.OWNER = '%s'", schema) + } + if table != "" && table != "%" { + sql += fmt.Sprintf(" AND CON.TABLE_NAME = '%s'", table) + } + sql += " ORDER BY COL.POSITION" + + return execMetaQuery(stmt, sql) +} + +//export dpi_foreignkeys +func dpi_foreignkeys(hstmt C.dhstmt, + pkCatalog *C.udbyte, pkCatalogLen C.sdint2, + pkSchema *C.udbyte, pkSchemaLen C.sdint2, + pkTable *C.udbyte, pkTableLen C.sdint2, + fkCatalog *C.udbyte, fkCatalogLen C.sdint2, + fkSchema *C.udbyte, fkSchemaLen C.sdint2, + fkTable *C.udbyte, fkTableLen C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT NULL AS PKTABLE_CAT, '' AS PKTABLE_SCHEM, '' AS PKTABLE_NAME, + '' AS PKCOLUMN_NAME, NULL AS FKTABLE_CAT, '' AS FKTABLE_SCHEM, + '' AS FKTABLE_NAME, '' AS FKCOLUMN_NAME, 0 AS KEY_SEQ, + 0 AS UPDATE_RULE, 0 AS DELETE_RULE, '' AS FK_NAME, '' AS PK_NAME + WHERE 1=0` // Stub — returns empty result + + return execMetaQuery(stmt, sql) +} + +//export dpi_statistics +func dpi_statistics(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + unique C.udint2, reserved C.udint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + // Return empty result set + sql := `SELECT NULL AS TABLE_CAT, '' AS TABLE_SCHEM, '' AS TABLE_NAME, + 0 AS NON_UNIQUE, '' AS INDEX_QUALIFIER, '' AS INDEX_NAME, + 0 AS TYPE, 0 AS ORDINAL_POSITION, '' AS COLUMN_NAME, + '' AS ASC_OR_DESC, 0 AS CARDINALITY, 0 AS PAGES, '' AS FILTER_CONDITION + WHERE 1=0` + + return execMetaQuery(stmt, sql) +} + +//export dpi_specialcolumns +func dpi_specialcolumns(hstmt C.dhstmt, identifiertype C.udint2, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + scope C.udint2, nullable C.udint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT 0 AS SCOPE, '' AS COLUMN_NAME, 0 AS DATA_TYPE, '' AS TYPE_NAME, + 0 AS COLUMN_SIZE, 0 AS BUFFER_LENGTH, 0 AS DECIMAL_DIGITS, 0 AS PSEUDO_COLUMN + WHERE 1=0` + + return execMetaQuery(stmt, sql) +} + +//export dpi_specialcolumns2 +func dpi_specialcolumns2(hstmt C.dhstmt, identifiertype C.udint2, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + scope C.udint2, nullable C.udint2) C.DPIRETURN { + return dpi_specialcolumns(hstmt, identifiertype, catalogname, namelength1, schemaname, namelength2, tablename, namelength3, scope, nullable) +} + +//export dpi_tableprivileges +func dpi_tableprivileges(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT NULL AS TABLE_CAT, '' AS TABLE_SCHEM, '' AS TABLE_NAME, + '' AS GRANTOR, '' AS GRANTEE, '' AS PRIVILEGE, '' AS IS_GRANTABLE + WHERE 1=0` + return execMetaQuery(stmt, sql) +} + +//export dpi_columnprivileges +func dpi_columnprivileges(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + tablename *C.udbyte, namelength3 C.sdint2, + columnname *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT NULL AS TABLE_CAT, '' AS TABLE_SCHEM, '' AS TABLE_NAME, + '' AS COLUMN_NAME, '' AS GRANTOR, '' AS GRANTEE, '' AS PRIVILEGE, '' AS IS_GRANTABLE + WHERE 1=0` + return execMetaQuery(stmt, sql) +} + +//export dpi_procedures +func dpi_procedures(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + procname *C.udbyte, namelength3 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT NULL AS PROCEDURE_CAT, '' AS PROCEDURE_SCHEM, '' AS PROCEDURE_NAME, + 0 AS NUM_INPUT_PARAMS, 0 AS NUM_OUTPUT_PARAMS, 0 AS NUM_RESULT_SETS, + '' AS REMARKS, 0 AS PROCEDURE_TYPE + WHERE 1=0` + return execMetaQuery(stmt, sql) +} + +//export dpi_procedurecolumns +func dpi_procedurecolumns(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + procname *C.udbyte, namelength3 C.sdint2, + columnname *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sql := `SELECT NULL AS PROCEDURE_CAT, '' AS PROCEDURE_SCHEM, '' AS PROCEDURE_NAME, + '' AS COLUMN_NAME, 0 AS COLUMN_TYPE, 0 AS DATA_TYPE, '' AS TYPE_NAME, + 0 AS COLUMN_SIZE, 0 AS BUFFER_LENGTH, 0 AS DECIMAL_DIGITS, 0 AS NUM_PREC_RADIX, + 0 AS NULLABLE, '' AS REMARKS + WHERE 1=0` + return execMetaQuery(stmt, sql) +} + +//export dpi_procedurecolumns2 +func dpi_procedurecolumns2(hstmt C.dhstmt, + catalogname *C.udbyte, namelength1 C.sdint2, + schemaname *C.udbyte, namelength2 C.sdint2, + procname *C.udbyte, namelength3 C.sdint2, + columnname *C.udbyte, namelength4 C.sdint2) C.DPIRETURN { + return dpi_procedurecolumns(hstmt, catalogname, namelength1, schemaname, namelength2, procname, namelength3, columnname, namelength4) +} + +// execMetaQuery executes a metadata SQL query and sets up the result set. +// Caller must hold stmt.mu.Lock(). +func execMetaQuery(stmt *stmtHandle, sql string) C.DPIRETURN { + if stmt.conn.db == nil { + stmt.lastErr = &diagInfo{errorCode: -1, message: "Not connected"} + return DSQL_ERROR + } + + // Close previous result set + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + + rows, dbErr := stmt.conn.db.Query(sql) + if dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + stmt.rows = rows + stmt.sql = sql + populateColumnInfo(stmt) + if dbErr := cacheAllRows(stmt); dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + return DSQL_SUCCESS +} diff --git a/dpi_bridge/dpi_obj.go b/dpi_bridge/dpi_obj.go new file mode 100644 index 0000000..bb40866 --- /dev/null +++ b/dpi_bridge/dpi_obj.go @@ -0,0 +1,310 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +typedef dhandle dhobjdesc; +typedef dhandle dhobj; +typedef dhandle dhbfile; +*/ +import "C" +import ( + "unsafe" +) + +// Object/BFILE operations — stub implementations for P4 priority. +// These allow dmPython to load and run without crashing for basic operations, +// but complex object/BFILE features will return errors. + +// objDescHandle represents an object type descriptor. +type objDescHandle struct { + name string + schema string + sqlType int16 + fieldCount int32 +} + +// objHandle represents an object instance. +type objHandle struct { + desc *objDescHandle +} + +// bfileHandle represents a BFILE locator. +type bfileHandle struct { + dirName string + fileName string +} + +//export dpi_desc_obj +func dpi_desc_obj(hcon C.dhcon, schema *C.sdbyte, name *C.sdbyte, objDesc *C.dhobjdesc) C.DPIRETURN { + if objDesc == nil { + return DSQL_ERROR + } + desc := &objDescHandle{ + schema: C.GoString((*C.char)(unsafe.Pointer(schema))), + name: C.GoString((*C.char)(unsafe.Pointer(name))), + } + id := allocHandle(desc) + *objDesc = C.dhobjdesc(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_desc_obj2 +func dpi_desc_obj2(hcon C.dhcon, schema *C.sdbyte, pkgName *C.sdbyte, name *C.sdbyte, objDesc *C.dhobjdesc) C.DPIRETURN { + return dpi_desc_obj(hcon, schema, name, objDesc) +} + +//export dpi_free_obj_desc +func dpi_free_obj_desc(objDesc C.dhobjdesc) C.DPIRETURN { + id := ptrToHandle(unsafe.Pointer(objDesc)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_alloc_obj +func dpi_alloc_obj(hcon C.dhcon, pobj *C.dhobj) C.DPIRETURN { + if pobj == nil { + return DSQL_ERROR + } + obj := &objHandle{} + id := allocHandle(obj) + *pobj = C.dhobj(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_obj +func dpi_free_obj(hobj C.dhobj) C.DPIRETURN { + id := ptrToHandle(unsafe.Pointer(hobj)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_bind_obj_desc +func dpi_bind_obj_desc(hobj C.dhobj, hdesc C.dhobjdesc) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_unbind_obj_desc +func dpi_unbind_obj_desc(hobj C.dhobj) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_set_obj_val +func dpi_set_obj_val(hobj C.dhobj, nth C.udint4, ctype C.udint2, val C.dpointer, valLen C.slength) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_get_obj_val +func dpi_get_obj_val(hobj C.dhobj, nth C.udint4, ctype C.udint2, val C.dpointer, bufLen C.udint4, valLen *C.slength) C.DPIRETURN { + if valLen != nil { + *valLen = C.slength(DSQL_NULL_DATA) + } + return DSQL_SUCCESS +} + +//export dpi_get_obj_attr +func dpi_get_obj_attr(hobj C.dhobj, nth C.udint4, attrID C.udint2, buf C.dpointer, bufLen C.udint4, length *C.slength) C.DPIRETURN { + if length != nil { + *length = 0 + } + return DSQL_SUCCESS +} + +//export dpi_get_obj_desc_attr +func dpi_get_obj_desc_attr(objDesc C.dhobjdesc, nth C.udint4, attrID C.udint2, buf C.dpointer, bufLen C.udint4, length *C.slength) C.DPIRETURN { + attr := int(attrID) + const ( + attrObjType = 1 // DSQL_ATTR_OBJ_TYPE + attrObjFieldCount = 5 // DSQL_ATTR_OBJ_FIELD_COUNT + attrObjName = 6 // DSQL_ATTR_OBJ_NAME + ) + switch attr { + case attrObjType: + if buf != nil { + *(*C.sdint2)(unsafe.Pointer(buf)) = C.sdint2(DSQL_VARCHAR) + } + case attrObjFieldCount: + if buf != nil { + *(*C.sdint4)(unsafe.Pointer(buf)) = 0 + } + case attrObjName: + if buf != nil { + *(*C.sdbyte)(unsafe.Pointer(buf)) = 0 + } + if length != nil { + *length = 0 + } + default: + if buf != nil { + *(*C.sdint4)(unsafe.Pointer(buf)) = 0 + } + } + return DSQL_SUCCESS +} + +//export dpi_get_obj_desc_attrW +func dpi_get_obj_desc_attrW(objDesc C.dhobjdesc, nth C.udint4, attrID C.udint2, buf C.dpointer, bufLen C.udint4, length *C.slength) C.DPIRETURN { + return dpi_get_obj_desc_attr(objDesc, nth, attrID, buf, bufLen, length) +} + +//export dpi_set_indtab_node +func dpi_set_indtab_node(hobj C.dhobj, ktype C.udint2, key C.dpointer, keyLen C.slength, + vtype C.udint2, val C.dpointer, valLen C.slength) C.DPIRETURN { + return DSQL_SUCCESS +} + +// BFILE operations +//export dpi_alloc_bfile +func dpi_alloc_bfile(hcon C.dhcon, pbfile *C.dhbfile) C.DPIRETURN { + if pbfile == nil { + return DSQL_ERROR + } + bf := &bfileHandle{} + id := allocHandle(bf) + *pbfile = C.dhbfile(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_bfile +func dpi_free_bfile(hbfile C.dhbfile) C.DPIRETURN { + id := ptrToHandle(unsafe.Pointer(hbfile)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_bfile_construct +func dpi_bfile_construct(hbfile C.dhbfile, dirName *C.udbyte, fileName *C.udbyte) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_bfile_constructW +func dpi_bfile_constructW(hbfile C.dhbfile, dirName *C.udbyte, dirNameLen C.udint4, fileName *C.udbyte, fileNameLen C.udint4) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_bfile_get_name +func dpi_bfile_get_name(hbfile C.dhbfile, + dirBuf *C.udbyte, dirBufLen C.udint4, dirLen *C.udint4, + fileBuf *C.udbyte, fileBufLen C.udint4, fileLen *C.udint4) C.DPIRETURN { + if dirLen != nil { + *dirLen = 0 + } + if fileLen != nil { + *fileLen = 0 + } + return DSQL_SUCCESS +} + +//export dpi_bfile_get_nameW +func dpi_bfile_get_nameW(hbfile C.dhbfile, + dirBuf *C.udbyte, dirBufLen C.udint4, dirLen *C.udint4, + fileBuf *C.udbyte, fileBufLen C.udint4, fileLen *C.udint4) C.DPIRETURN { + return dpi_bfile_get_name(hbfile, dirBuf, dirBufLen, dirLen, fileBuf, fileBufLen, fileLen) +} + +//export dpi_bfile_read +func dpi_bfile_read(hbfile C.dhbfile, startPos C.udint8, ctype C.sdint2, + dataToRead C.udint8, valBuf C.dpointer, bufLen C.udint8, dataGet *C.udint8) C.DPIRETURN { + if dataGet != nil { + *dataGet = 0 + } + return DSQL_NO_DATA +} + +// ROWID operations +//export dpi_build_rowid +func dpi_build_rowid(hcon C.dhcon, epno C.sdint4, partno C.sdint8, realRowid C.udint8, + rowidBuf *C.sdbyte, rowidBufLen C.udint4, rowidLen *C.udint4) C.DPIRETURN { + if rowidLen != nil { + *rowidLen = 0 + } + return DSQL_SUCCESS +} + +//export dpi_rowid_to_char +func dpi_rowid_to_char(hcon C.dhcon, rowid *C.sdbyte, rowidLen C.udint4, + destBuf *C.sdbyte, destBufLen C.udint4, destLen *C.udint4) C.DPIRETURN { + if destBuf != nil && destBufLen > 0 { + *destBuf = 0 + } + if destLen != nil { + *destLen = 0 + } + return DSQL_SUCCESS +} + +//export dpi_char_to_rowid +func dpi_char_to_rowid(hcon C.dhcon, rowidStr *C.sdbyte, rowidLen C.udint4, + destBuf *C.sdbyte, destBufLen C.udint4, destLen *C.udint4) C.DPIRETURN { + if destLen != nil { + *destLen = 0 + } + return DSQL_SUCCESS +} + +// Additional stubs for cursor name operations +//export dpi_set_cursor_name +func dpi_set_cursor_name(hstmt C.dhstmt, name *C.sdbyte, nameLen C.sdint2) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_set_cursor_nameW +func dpi_set_cursor_nameW(hstmt C.dhstmt, name *C.sdbyte, nameLen C.sdint2) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_get_cursor_name +func dpi_get_cursor_name(hstmt C.dhstmt, name *C.sdbyte, bufLen C.sdint2, nameLen *C.sdint2) C.DPIRETURN { + if name != nil && bufLen > 0 { + *name = 0 + } + if nameLen != nil { + *nameLen = 0 + } + return DSQL_SUCCESS +} + +//export dpi_get_cursor_nameW +func dpi_get_cursor_nameW(hstmt C.dhstmt, name *C.sdbyte, bufLen C.sdint2, nameLen *C.sdint2) C.DPIRETURN { + return dpi_get_cursor_name(hstmt, name, bufLen, nameLen) +} + +// set_pos, bulk_operation stubs +//export dpi_set_pos +func dpi_set_pos(hstmt C.dhstmt, rowNum C.ulength, op C.udint2, lockType C.udint2) C.DPIRETURN { + return DSQL_SUCCESS +} + +//export dpi_bulk_operation +func dpi_bulk_operation(hstmt C.dhstmt, op C.udint2) C.DPIRETURN { + return DSQL_SUCCESS +} + +// Connection attribute W variants +//export dpi_set_con_attrW +func dpi_set_con_attrW(hcon C.dhcon, attrID C.sdint4, val C.dpointer, valLen C.sdint4) C.DPIRETURN { + return dpi_set_con_attr(hcon, attrID, val, valLen) +} + +//export dpi_get_con_attrW +func dpi_get_con_attrW(hcon C.dhcon, attrID C.sdint4, val C.dpointer, bufLen C.sdint4, valLen *C.sdint4) C.DPIRETURN { + return dpi_get_con_attr(hcon, attrID, val, bufLen, valLen) +} diff --git a/dpi_bridge/dpi_stmt.go b/dpi_bridge/dpi_stmt.go new file mode 100644 index 0000000..1491f82 --- /dev/null +++ b/dpi_bridge/dpi_stmt.go @@ -0,0 +1,719 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +*/ +import "C" +import ( + "database/sql" + "fmt" + "sync" + "unsafe" +) + +// columnInfo holds metadata about a result set column. +type columnInfo struct { + name string + sqlType int16 + precision uint64 + scale int16 + nullable int16 + displaySize int64 + tableName string +} + +// paramInfo holds metadata about a statement parameter. +type paramInfo struct { + name string + sqlType int16 + precision uint64 + scale int16 + nullable int16 + paramType int16 // DSQL_PARAM_INPUT, etc. +} + +// bindColInfo holds info about a column binding. +type bindColInfo struct { + cType int16 + dataPtr unsafe.Pointer + bufLen int64 + indPtr *C.slength + actLenPtr *C.slength +} + +// bindParamInfo holds info about a parameter binding. +type bindParamInfo struct { + paramType int16 + cType int16 + sqlType int16 + precision uint64 + scale int16 + dataPtr unsafe.Pointer + bufLen int64 + indPtr *C.slength + actLenPtr *C.slength +} + +// stmtHandle represents a DPI statement. +type stmtHandle struct { + mu sync.Mutex + conn *connHandle + + // Prepared statement + prepared *sql.Stmt + sql string + + // Result set + rows *sql.Rows + columns []columnInfo + columnCount int16 + + // Cached result rows (pre-fetched for accurate row count) + cachedRows [][]interface{} // all rows, each row is []interface{} + fetchPos int // current position in cachedRows for dpi_fetch + + // Parameters + params []paramInfo + paramCount uint16 + + // Bindings + colBindings map[int]bindColInfo // 1-based column index + paramBindings map[int]bindParamInfo // 1-based parameter index + + // Current row data (from last fetch) + currentRow []interface{} + rowsFetched int64 + + // Statement attributes + cursorType uint32 + rowArraySize uint64 + paramsetSize uint64 + rowStatusPtr unsafe.Pointer + rowsFetchedPtr unsafe.Pointer + + // Descriptors (implicit) + impRowDesc *descHandle + impParamDesc *descHandle + + // DML result + rowsAffected int64 + + // Diagnostics + lastErr *diagInfo +} + +// descHandle represents a DPI descriptor. +type descHandle struct { + mu sync.Mutex + stmt *stmtHandle + descType int // 0 = row, 1 = param + lastErr *diagInfo +} + +func newStmtHandle(conn *connHandle) *stmtHandle { + st := &stmtHandle{ + conn: conn, + colBindings: make(map[int]bindColInfo), + paramBindings: make(map[int]bindParamInfo), + rowArraySize: 1, + paramsetSize: 1, + cursorType: DSQL_CURSOR_FORWARD_ONLY, + } + // Create implicit descriptors + st.impRowDesc = &descHandle{stmt: st, descType: 0} + st.impParamDesc = &descHandle{stmt: st, descType: 1} + return st +} + +//export dpi_alloc_stmt +func dpi_alloc_stmt(hcon C.dhcon, pstmt *C.dhstmt) C.DPIRETURN { + if pstmt == nil { + return DSQL_ERROR + } + conn, err := getConnHandle(hcon) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt := newStmtHandle(conn) + stmtID := allocHandle(stmt) + // Also allocate handles for the implicit descriptors + allocHandle(stmt.impRowDesc) + allocHandle(stmt.impParamDesc) + *pstmt = C.dhstmt(handleToPtr(stmtID)) + return DSQL_SUCCESS +} + +//export dpi_free_stmt +func dpi_free_stmt(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + if stmt.prepared != nil { + stmt.prepared.Close() + stmt.prepared = nil + } + stmt.mu.Unlock() + + id := ptrToHandle(unsafe.Pointer(hstmt)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_alloc_handle +func dpi_alloc_handle(hndlType C.sdint2, hndlIn C.dhandle, hndlOut *C.dhandle) C.DPIRETURN { + if hndlOut == nil { + return DSQL_ERROR + } + switch int16(hndlType) { + case DSQL_HANDLE_ENV: + return dpi_alloc_env((*C.dhenv)(unsafe.Pointer(hndlOut))) + case DSQL_HANDLE_DBC: + return dpi_alloc_con(C.dhenv(unsafe.Pointer(hndlIn)), (*C.dhcon)(unsafe.Pointer(hndlOut))) + case DSQL_HANDLE_STMT: + return dpi_alloc_stmt(C.dhcon(unsafe.Pointer(hndlIn)), (*C.dhstmt)(unsafe.Pointer(hndlOut))) + case DSQL_HANDLE_DESC: + return dpi_alloc_desc(C.dhcon(unsafe.Pointer(hndlIn)), (*C.dhdesc)(unsafe.Pointer(hndlOut))) + default: + return DSQL_ERROR + } +} + +//export dpi_free_handle +func dpi_free_handle(hndlType C.sdint2, hndl C.dhandle) C.DPIRETURN { + switch int16(hndlType) { + case DSQL_HANDLE_ENV: + return dpi_free_env(C.dhenv(unsafe.Pointer(hndl))) + case DSQL_HANDLE_DBC: + return dpi_free_con(C.dhcon(unsafe.Pointer(hndl))) + case DSQL_HANDLE_STMT: + return dpi_free_stmt(C.dhstmt(unsafe.Pointer(hndl))) + default: + id := ptrToHandle(unsafe.Pointer(hndl)) + freeHandle(id) + return DSQL_SUCCESS + } +} + +//export dpi_set_stmt_attr +func dpi_set_stmt_attr(hstmt C.dhstmt, attrID C.sdint4, val C.dpointer, valLen C.sdint4) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + intVal := uint64(uintptr(val)) + + switch int32(attrID) { + case DSQL_ATTR_CURSOR_TYPE: + stmt.cursorType = uint32(intVal) + case DSQL_ATTR_ROW_ARRAY_SIZE: + if intVal > 0 { + stmt.rowArraySize = intVal + } + case DSQL_ATTR_PARAMSET_SIZE: + if intVal > 0 { + stmt.paramsetSize = intVal + } + case DSQL_ATTR_ROW_STATUS_PTR: + stmt.rowStatusPtr = unsafe.Pointer(val) + case DSQL_ATTR_ROWS_FETCHED_PTR: + stmt.rowsFetchedPtr = unsafe.Pointer(val) + case DSQL_ATTR_QUERY_TIMEOUT, DSQL_ATTR_MAX_ROWS, + DSQL_ATTR_CURSOR_SCROLLABLE, DSQL_ATTR_SQL_CHARSET, + DSQL_ATTR_IGN_BP_ERR: + // Accept but ignore + default: + // Ignore unknown attributes + } + return DSQL_SUCCESS +} + +//export dpi_get_stmt_attr +func dpi_get_stmt_attr(hstmt C.dhstmt, attrID C.sdint4, val C.dpointer, bufLen C.sdint4, valLen *C.sdint4) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + switch int32(attrID) { + case DSQL_ATTR_IMP_ROW_DESC: + // Return the descriptor handle for row description + descID := findDescHandleID(stmt.impRowDesc) + *(*C.dhdesc)(val) = C.dhdesc(handleToPtr(descID)) + if valLen != nil { + *valLen = C.sdint4(unsafe.Sizeof(C.dhdesc(nil))) + } + case DSQL_ATTR_IMP_PARAM_DESC: + descID := findDescHandleID(stmt.impParamDesc) + *(*C.dhdesc)(val) = C.dhdesc(handleToPtr(descID)) + if valLen != nil { + *valLen = C.sdint4(unsafe.Sizeof(C.dhdesc(nil))) + } + case DSQL_ATTR_CURSOR_TYPE: + *(*C.udint4)(val) = C.udint4(stmt.cursorType) + if valLen != nil { + *valLen = 4 + } + case DSQL_ATTR_ROW_ARRAY_SIZE: + *(*C.ulength)(val) = C.ulength(stmt.rowArraySize) + if valLen != nil { + *valLen = C.sdint4(unsafe.Sizeof(C.ulength(0))) + } + default: + *(*C.sdint4)(val) = 0 + if valLen != nil { + *valLen = 4 + } + } + return DSQL_SUCCESS +} + +// findDescHandleID finds the handle ID for a descHandle, allocating one if needed. +func findDescHandleID(desc *descHandle) uintptr { + handleMu.RLock() + for id, obj := range handles { + if obj == desc { + handleMu.RUnlock() + return id + } + } + handleMu.RUnlock() + // Not found — allocate + return allocHandle(desc) +} + +//export dpi_alloc_desc +func dpi_alloc_desc(hcon C.dhcon, pdesc *C.dhdesc) C.DPIRETURN { + if pdesc == nil { + return DSQL_ERROR + } + desc := &descHandle{} + id := allocHandle(desc) + *pdesc = C.dhdesc(handleToPtr(id)) + return DSQL_SUCCESS +} + +//export dpi_free_desc +func dpi_free_desc(hdesc C.dhdesc) C.DPIRETURN { + id := ptrToHandle(unsafe.Pointer(hdesc)) + freeHandle(id) + return DSQL_SUCCESS +} + +//export dpi_prepare +func dpi_prepare(hstmt C.dhstmt, sqlTxt *C.sdbyte) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sqlStr := C.GoString((*C.char)(unsafe.Pointer(sqlTxt))) + stmt.sql = sqlStr + + // Close any previous resources + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + if stmt.prepared != nil { + stmt.prepared.Close() + stmt.prepared = nil + } + + // Reset state + stmt.columns = nil + stmt.columnCount = 0 + stmt.paramCount = 0 + stmt.params = nil + stmt.currentRow = nil + stmt.rowsAffected = 0 + stmt.cachedRows = nil + stmt.fetchPos = 0 + stmt.colBindings = make(map[int]bindColInfo) + + // Prepare the statement + if stmt.conn.db == nil { + stmt.lastErr = &diagInfo{errorCode: -1, message: "Not connected"} + return DSQL_ERROR + } + + prepared, dbErr := stmt.conn.db.Prepare(sqlStr) + if dbErr != nil { + stmt.lastErr = &diagInfo{ + errorCode: -1, + message: fmt.Sprintf("Prepare failed: %v", dbErr), + } + return DSQL_ERROR + } + stmt.prepared = prepared + + // Count parameters (count '?' in SQL) + paramCount := uint16(0) + inStr := false + for _, ch := range sqlStr { + if ch == '\'' { + inStr = !inStr + } else if ch == '?' && !inStr { + paramCount++ + } + } + stmt.paramCount = paramCount + stmt.params = make([]paramInfo, paramCount) + for i := range stmt.params { + stmt.params[i].paramType = DSQL_PARAM_INPUT + stmt.params[i].sqlType = DSQL_VARCHAR + stmt.params[i].nullable = DSQL_NULLABLE_UNKNOWN + } + + return DSQL_SUCCESS +} + +//export dpi_prepareW +func dpi_prepareW(hstmt C.dhstmt, sqlTxt *C.sdbyte, sqlLen C.sdint4) C.DPIRETURN { + return dpi_prepare(hstmt, sqlTxt) +} + +//export dpi_exec +func dpi_exec(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + if stmt.prepared == nil { + stmt.lastErr = &diagInfo{errorCode: -1, message: "Statement not prepared"} + return DSQL_ERROR + } + + // Build args from parameter bindings + args := buildExecArgs(stmt) + + // Determine if this is a query or exec + if isQuery(stmt.sql) { + rows, dbErr := stmt.prepared.Query(args...) + if dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + stmt.rows = rows + stmt.rowsAffected = 0 + populateColumnInfo(stmt) + if dbErr := cacheAllRows(stmt); dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + } else { + result, dbErr := stmt.prepared.Exec(args...) + if dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + affected, _ := result.RowsAffected() + stmt.rowsAffected = affected + stmt.rows = nil + stmt.columnCount = 0 + } + + return DSQL_SUCCESS +} + +//export dpi_exec_direct +func dpi_exec_direct(hstmt C.dhstmt, sqlTxt *C.sdbyte) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + + sqlStr := C.GoString((*C.char)(unsafe.Pointer(sqlTxt))) + stmt.sql = sqlStr + + // Close any previous resources + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + if stmt.prepared != nil { + stmt.prepared.Close() + stmt.prepared = nil + } + stmt.columns = nil + stmt.currentRow = nil + + if stmt.conn.db == nil { + stmt.lastErr = &diagInfo{errorCode: -1, message: "Not connected"} + return DSQL_ERROR + } + + stmt.cachedRows = nil + stmt.fetchPos = 0 + + if isQuery(sqlStr) { + rows, dbErr := stmt.conn.db.Query(sqlStr) + if dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + stmt.rows = rows + populateColumnInfo(stmt) + if dbErr := cacheAllRows(stmt); dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + } else { + result, dbErr := stmt.conn.db.Exec(sqlStr) + if dbErr != nil { + stmt.lastErr = diagFromError(dbErr) + return DSQL_ERROR + } + affected, _ := result.RowsAffected() + stmt.rowsAffected = affected + stmt.rows = nil + stmt.columnCount = 0 + } + + return DSQL_SUCCESS +} + +//export dpi_exec_directW +func dpi_exec_directW(hstmt C.dhstmt, sqlTxt *C.sdbyte, sqlLen C.sdint4) C.DPIRETURN { + return dpi_exec_direct(hstmt, sqlTxt) +} + +//export dpi_cancel +func dpi_cancel(hstmt C.dhstmt) C.DPIRETURN { + stmt, err := getStmtHandle(hstmt) + if err != nil { + return DSQL_INVALID_HANDLE + } + stmt.mu.Lock() + defer stmt.mu.Unlock() + if stmt.rows != nil { + stmt.rows.Close() + stmt.rows = nil + } + return DSQL_SUCCESS +} + +// isQuery checks if a SQL string is a query that returns rows. +func isQuery(sqlStr string) bool { + s := sqlStr + for len(s) > 0 && (s[0] == ' ' || s[0] == '\t' || s[0] == '\n' || s[0] == '\r' || s[0] == '(') { + s = s[1:] + } + if len(s) < 4 { + return false + } + // Case-insensitive prefix check + upper := make([]byte, 0, 7) + for i := 0; i < len(s) && len(upper) < 7; i++ { + c := s[i] + if c >= 'a' && c <= 'z' { + c -= 32 + } + upper = append(upper, c) + } + prefix := string(upper) + return len(prefix) >= 6 && prefix[:6] == "SELECT" || + len(prefix) >= 4 && prefix[:4] == "WITH" || + len(prefix) >= 4 && prefix[:4] == "SHOW" || + len(prefix) >= 6 && prefix[:6] == "EXPLAI" +} + +// populateColumnInfo fills in column metadata from sql.Rows. +func populateColumnInfo(stmt *stmtHandle) { + if stmt.rows == nil { + stmt.columnCount = 0 + stmt.columns = nil + return + } + + colTypes, err := stmt.rows.ColumnTypes() + if err != nil { + colNames, _ := stmt.rows.Columns() + stmt.columnCount = int16(len(colNames)) + stmt.columns = make([]columnInfo, len(colNames)) + for i, name := range colNames { + stmt.columns[i] = columnInfo{ + name: name, + sqlType: DSQL_VARCHAR, + precision: 256, + nullable: DSQL_NULLABLE_UNKNOWN, + displaySize: 256, + } + } + return + } + + stmt.columnCount = int16(len(colTypes)) + stmt.columns = make([]columnInfo, len(colTypes)) + for i, ct := range colTypes { + col := columnInfo{ + name: ct.Name(), + nullable: DSQL_NULLABLE_UNKNOWN, + } + + col.sqlType, col.precision, col.scale, col.displaySize = mapGoTypeToDPI(ct) + + nullable, ok := ct.Nullable() + if ok { + if nullable { + col.nullable = DSQL_NULLABLE + } else { + col.nullable = DSQL_NO_NULLS + } + } + + stmt.columns[i] = col + } +} + +// cacheAllRows pre-fetches all rows from stmt.rows into stmt.cachedRows, +// then closes stmt.rows. This gives us an accurate row count for dpi_row_count. +func cacheAllRows(stmt *stmtHandle) error { + if stmt.rows == nil { + return nil + } + numCols := int(stmt.columnCount) + stmt.cachedRows = nil + stmt.fetchPos = 0 + + for stmt.rows.Next() { + scanDest := make([]interface{}, numCols) + for i := 0; i < numCols; i++ { + scanDest[i] = new(interface{}) + } + if err := stmt.rows.Scan(scanDest...); err != nil { + return err + } + row := make([]interface{}, numCols) + for i := 0; i < numCols; i++ { + row[i] = *(scanDest[i].(*interface{})) + } + stmt.cachedRows = append(stmt.cachedRows, row) + } + + // Close the rows now that we've cached everything + stmt.rows.Close() + stmt.rows = nil + return nil +} + +// mapGoTypeToDPI maps a sql.ColumnType to DPI types. +func mapGoTypeToDPI(ct *sql.ColumnType) (sqlType int16, precision uint64, scale int16, displaySize int64) { + dbTypeName := ct.DatabaseTypeName() + + switch dbTypeName { + case "INT", "INTEGER": + return DSQL_INT, 10, 0, 11 + case "BIGINT": + return DSQL_BIGINT, 19, 0, 20 + case "SMALLINT": + return DSQL_SMALLINT, 5, 0, 6 + case "TINYINT": + return DSQL_TINYINT, 3, 0, 4 + case "FLOAT": + return DSQL_FLOAT, 24, 0, 24 + case "DOUBLE", "DOUBLE PRECISION": + return DSQL_DOUBLE, 53, 0, 53 + case "DECIMAL", "DEC", "NUMBER", "NUMERIC": + p, s, _ := ct.DecimalSize() + return DSQL_DEC, uint64(p), int16(s), int64(p) + 2 + case "CHAR": + l, _ := ct.Length() + return DSQL_CHAR, uint64(l), 0, int64(l) + case "VARCHAR", "VARCHAR2": + l, _ := ct.Length() + if l == 0 { + l = 256 + } + return DSQL_VARCHAR, uint64(l), 0, int64(l) + case "BLOB": + return DSQL_BLOB, 0, 0, 0 + case "CLOB", "TEXT": + return DSQL_CLOB, 0, 0, 0 + case "DATE": + return DSQL_DATE, 10, 0, 10 + case "TIME": + return DSQL_TIME, 8, 0, 8 + case "TIMESTAMP", "DATETIME": + return DSQL_TIMESTAMP, 26, 6, 26 + case "TIMESTAMP WITH TIME ZONE": + return DSQL_TIMESTAMP_TZ, 34, 6, 34 + case "BIT", "BOOL", "BOOLEAN": + return DSQL_BIT, 1, 0, 1 + case "BINARY": + l, _ := ct.Length() + return DSQL_BINARY, uint64(l), 0, int64(l) * 2 + case "VARBINARY": + l, _ := ct.Length() + return DSQL_VARBINARY, uint64(l), 0, int64(l) * 2 + default: + l, _ := ct.Length() + if l == 0 { + l = 256 + } + return DSQL_VARCHAR, uint64(l), 0, int64(l) + } +} + +// buildExecArgs builds []interface{} from parameter bindings. +func buildExecArgs(stmt *stmtHandle) []interface{} { + if len(stmt.paramBindings) == 0 { + return nil + } + args := make([]interface{}, stmt.paramCount) + for i := 0; i < int(stmt.paramCount); i++ { + bind, ok := stmt.paramBindings[i+1] // 1-based + if !ok { + args[i] = nil + continue + } + args[i] = extractBoundValue(bind) + } + return args +} + +// diagFromError creates a diagInfo from a Go error. +func diagFromError(err error) *diagInfo { + if err == nil { + return nil + } + return &diagInfo{ + errorCode: -1, + message: err.Error(), + } +} diff --git a/dpi_bridge/go.mod b/dpi_bridge/go.mod new file mode 100644 index 0000000..6e42122 --- /dev/null +++ b/dpi_bridge/go.mod @@ -0,0 +1,12 @@ +module dpi_bridge + +go 1.21 + +require gitee.com/chunanyong/dm v1.8.22 + +replace gitee.com/chunanyong/dm => ./third_party/chunanyong_dm + +require ( + github.com/golang/snappy v0.0.1 // indirect + golang.org/x/text v0.3.2 // indirect +) diff --git a/dpi_bridge/go.sum b/dpi_bridge/go.sum new file mode 100644 index 0000000..612ce0d --- /dev/null +++ b/dpi_bridge/go.sum @@ -0,0 +1,9 @@ +gitee.com/chunanyong/dm v1.8.15 h1:GIyry2BAlSO7xug95QYbehHdx73md2ZYsSvMZ1Uab0g= +gitee.com/chunanyong/dm v1.8.15/go.mod h1:EPRJnuPFgbyOFgJ0TRYCTGzhq+ZT4wdyaj/GW/LLcNg= +gitee.com/chunanyong/dm v1.8.22 h1:H7fsrnUIvEA0jlDWew7vwELry1ff+tLMIu2Fk2cIBSg= +gitee.com/chunanyong/dm v1.8.22/go.mod h1:EPRJnuPFgbyOFgJ0TRYCTGzhq+ZT4wdyaj/GW/LLcNg= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/dpi_bridge/handle.go b/dpi_bridge/handle.go new file mode 100644 index 0000000..13f1ad2 --- /dev/null +++ b/dpi_bridge/handle.go @@ -0,0 +1,147 @@ +package main + +/* +#include +#include +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef sdint8 slength; +typedef udint8 ulength; +typedef void* dpointer; +typedef sdint2 DPIRETURN; +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +typedef dhandle dhobjdesc; +typedef dhandle dhobj; +typedef dhandle dhbfile; +*/ +import "C" +import ( + "fmt" + "sync" + "unsafe" +) + +// Handle pool: maps uintptr IDs to Go objects. +// C code holds these IDs as void* pointers. +// This avoids passing actual Go pointers to C (which the GC could move). + +var ( + handleMu sync.RWMutex + handles = make(map[uintptr]interface{}) + nextHandle uintptr +) + +// allocHandle stores a Go object and returns a handle ID (as uintptr). +func allocHandle(obj interface{}) uintptr { + handleMu.Lock() + defer handleMu.Unlock() + nextHandle++ + handles[nextHandle] = obj + return nextHandle +} + +// getHandle retrieves a Go object by handle ID. +func getHandle(id uintptr) (interface{}, bool) { + handleMu.RLock() + defer handleMu.RUnlock() + obj, ok := handles[id] + return obj, ok +} + +// freeHandle removes a handle from the pool. +func freeHandle(id uintptr) bool { + handleMu.Lock() + defer handleMu.Unlock() + if _, ok := handles[id]; ok { + delete(handles, id) + return true + } + return false +} + +// handleToPtr converts a uintptr handle ID to a C void* pointer. +func handleToPtr(id uintptr) unsafe.Pointer { + return unsafe.Pointer(id) +} + +// ptrToHandle converts a C void* pointer back to a uintptr handle ID. +func ptrToHandle(p unsafe.Pointer) uintptr { + return uintptr(p) +} + +// getTypedHandle retrieves a handle and checks its type. +func getEnvHandle(h C.dhenv) (*envHandle, error) { + id := ptrToHandle(unsafe.Pointer(h)) + obj, ok := getHandle(id) + if !ok { + return nil, fmt.Errorf("invalid env handle") + } + env, ok := obj.(*envHandle) + if !ok { + return nil, fmt.Errorf("handle is not an env handle") + } + return env, nil +} + +func getConnHandle(h C.dhcon) (*connHandle, error) { + id := ptrToHandle(unsafe.Pointer(h)) + obj, ok := getHandle(id) + if !ok { + return nil, fmt.Errorf("invalid connection handle") + } + conn, ok := obj.(*connHandle) + if !ok { + return nil, fmt.Errorf("handle is not a connection handle") + } + return conn, nil +} + +func getStmtHandle(h C.dhstmt) (*stmtHandle, error) { + id := ptrToHandle(unsafe.Pointer(h)) + obj, ok := getHandle(id) + if !ok { + return nil, fmt.Errorf("invalid statement handle") + } + stmt, ok := obj.(*stmtHandle) + if !ok { + return nil, fmt.Errorf("handle is not a statement handle") + } + return stmt, nil +} + +func getDescHandle(h C.dhdesc) (*descHandle, error) { + id := ptrToHandle(unsafe.Pointer(h)) + obj, ok := getHandle(id) + if !ok { + return nil, fmt.Errorf("invalid descriptor handle") + } + desc, ok := obj.(*descHandle) + if !ok { + return nil, fmt.Errorf("handle is not a descriptor handle") + } + return desc, nil +} + +func getLobHandle(h C.dhloblctr) (*lobHandle, error) { + id := ptrToHandle(unsafe.Pointer(h)) + obj, ok := getHandle(id) + if !ok { + return nil, fmt.Errorf("invalid LOB handle") + } + lob, ok := obj.(*lobHandle) + if !ok { + return nil, fmt.Errorf("handle is not a LOB handle") + } + return lob, nil +} diff --git a/dpi_bridge/main.go b/dpi_bridge/main.go new file mode 100644 index 0000000..f5e6d2d --- /dev/null +++ b/dpi_bridge/main.go @@ -0,0 +1,6 @@ +package main + +// This file is required for c-shared build mode. +// All exported functions are in other files. + +func main() {} diff --git a/dpi_bridge/third_party/chunanyong_dm/CHANGELOG.md b/dpi_bridge/third_party/chunanyong_dm/CHANGELOG.md new file mode 100644 index 0000000..42ab4ef --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/CHANGELOG.md @@ -0,0 +1,43 @@ +# Change Logs + +*你可以在文件p.go中的发版标记里找到当前驱动的svn号 + +## svn 31633 +修复了带ipv6地址的服务名无法连接数据库的问题 +dm.DmError输出不再附加堆栈信息,如需要则调用dm.DmError.Stack()方法单独获取 +服务器开启常量参数化优化时,go驱动出现一些报错问题 + +## svn 16752 +支持在连接串上直接配置动态服务名,使用示例: +dm://user:password@GroupName?GroupName=(host1:port1,host2:port2,...) + +## svn 16505 +新增连接串属性driverReconnect,配合doSwitch=1或2使用,表示连接重连是否使用驱动自身的重连机制,否则在连接失效时返回sql标准错误driver.ErrBadConn,由go来处理重连 + +## svn 16258 +重连逻辑修改,当连接失效时,返回driver.ErrBadConn而不是驱动自己管理重连,连接串参数doSwitch默认值改为1 +驱动接口方法同步锁改到连接网络请求的总入口处,解决一些panic和数组越界问题 +日志优化,去除遍历结果集时因io.EOF错误记录的日志 + +## svn 15619 +驱动接口方法添加同步锁 +驱动日志修改bug,可以记录SQL语句和参数值了 + +## svn 15357 +发布方言包,支持gorm v1和v2框架,方言包位于达梦安装目录的drivers/go目录中,详细使用说明参考《DM8程序员手册》 + +## svn 15157 +修复了字符大字段(Clob)中存在乱码字符时,读取结果会漏读一些字符的问题 +修复了开启SSL后并发创建连接导致panic的问题 + +## svn 15035 +修复了连接串属性doSwitch=1时,语句不会自动切换和重连的问题 +修复了连接重置后,可能出现的空指针问题 + +## svn 14992 +修复了连接串属性doSwitch=1时,连接不会自动切换和重连的问题 +修复了连接串属性loginMode=默认值4时,备库可能会被优先连接的问题 + +## svn 14589 +sql.Result.LastInsertId()函数能优先返回自增列的值,如果没有则返回数据库表内部的rowid +修复了开启事务时指定只读不生效的问题 \ No newline at end of file diff --git a/dpi_bridge/third_party/chunanyong_dm/PATCHES.md b/dpi_bridge/third_party/chunanyong_dm/PATCHES.md new file mode 100644 index 0000000..4c8edcd --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/PATCHES.md @@ -0,0 +1,37 @@ +# Local Patch Notes + +## Base + +- Upstream module: `gitee.com/chunanyong/dm` +- Base version: `v1.8.22` + +## Patch: CLOB Unicode read corruption on large payloads + +- File: `a.go` +- Function: `dm_build_610` +- Problem: + - Large CLOB payloads (for example `>=16000` chars) could return corrupted Unicode + when fetched, with replacement characters (`U+FFFD`) inserted at chunk boundaries. + - Database-side `length(c)` remained correct, while client-side decoded string was incorrect. +- Root cause: + - The original implementation decoded each chunk independently and concatenated strings. + - If a chunk boundary split a multi-byte sequence, per-chunk decode could emit replacement + characters. +- Fix: + - Accumulate raw bytes for all chunks first. + - Decode once at the end using server encoding. + - Keep original offset progression and `readOver` behavior. + - Preserve fallback `charLen == -1` handling for compatibility. + +## Regression coverage + +- `tests/integration/test_p0_clob_unicode_regression.py` + - `test_clob_unicode_problem_patterns_roundtrip` + - `test_clob_unicode_problem_patterns_executemany_roundtrip` + - `test_clob_unicode_problem_patterns_length_contract` + - `test_clob_unicode_problem_patterns_subprocess_no_crash` + +## Rollback + +- Remove `replace gitee.com/chunanyong/dm => ./third_party/chunanyong_dm` in `dpi_bridge/go.mod`. +- Revert `third_party/chunanyong_dm` changes. diff --git a/dpi_bridge/third_party/chunanyong_dm/README.md b/dpi_bridge/third_party/chunanyong_dm/README.md new file mode 100644 index 0000000..a5ade71 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/README.md @@ -0,0 +1,61 @@ +# dm + +### 介绍 +``` +go get gitee.com/chunanyong/dm +``` +达梦数据库官方Go驱动,本项目和官方驱动版本同步,方便go mod 使用. +安装达梦数据库(版本>=8.1.1.126),安装目录下 drivers/go/dm-go-driver.zip +达梦官方文档:https://eco.dameng.com/docs/zh-cn/app-dev/go-go.html +资源下载:https://eco.dameng.com/download/ +达梦官方Go驱动包:https://package.dameng.com/eco/adapter/resource/go/dm-go-driver.zip +达梦官方论坛(提交bug):https://eco.dameng.com/community/question + +### zorm +Go轻量ORM https://gitee.com/chunanyong/zorm 原生支持达梦数据库 + +### DSN +dm://userName:password@127.0.0.1:5236?schema=DBName +用户名(userName)默认就是数据库的名称,达梦用户模式和数据库名称是对应的,也可以通过schema参数指定数据库 +建议达梦使用UTF-8字符编码,不区分大小写,建表语句的字段名不要带""双引号 +密码中包含特殊字符时,密码使用url.PathEscape进行Escape处理,并在DSN中加入&escapeProcess=true 参见:https://eco.dameng.com/community/question/d152258b30bd0fc030d15e6a4afd5fc2 + +### bug +- 达梦开启等保参数 COMM_ENCRYPT_NAME = AES128_ECB,导致连接异常 + +### 版本号 +Go三段位版本号和达梦四段位版本号不兼容,统一使用1.达梦主版本号.发布的小版本号,具体查看标签的备注 + +* v1.8.22 来自 达梦8.1.4.170 +* v1.8.21 来自 达梦8.1.4.116 +* v1.8.20 来自 达梦8.1.4.80 +* v1.8.19 来自 达梦8.1.4.48 +* v1.8.18 来自 达梦8.1.4.6 +* v1.8.17 来自 达梦8.1.4.6 +* v1.8.16 来自 达梦8.1.3.162 +* v1.8.15 来自 达梦8.1.3.140 +* v1.8.14 来自 达梦8.1.3.100 +* v1.8.13 来自 达梦8.1.3.62 +* v1.8.12 来自 达梦8.1.3.12 +* v1.8.11 来自 达梦8.1.2.192 +* v1.8.10 来自 达梦8.1.2.174 +* v1.8.9 来自 达梦8.1.2.162 +* v1.8.8 来自 达梦8.1.2.138 +* v1.8.7 来自 达梦8.1.2.128 +* v1.8.6 来自 达梦8.1.2.114 +* v1.8.5 来自 达梦8.1.2.94 +* v1.8.4 来自 达梦8.1.2.84 +* v1.8.3 来自 达梦8.1.2.38 +* v1.8.2 来自 达梦8.1.2.18 +* v1.8.1 来自 达梦8.1.1.190 +* v1.8.0 来自 达梦8.1.1.126 + + + + + + + + + + diff --git a/dpi_bridge/third_party/chunanyong_dm/VERSION b/dpi_bridge/third_party/chunanyong_dm/VERSION new file mode 100644 index 0000000..7bf7455 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/VERSION @@ -0,0 +1,3 @@ +#8.1.4.170 +#2025.11.21 +#43114 diff --git a/dpi_bridge/third_party/chunanyong_dm/a.go b/dpi_bridge/third_party/chunanyong_dm/a.go new file mode 100644 index 0000000..e22ca80 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/a.go @@ -0,0 +1,890 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "context" + "crypto/tls" + "fmt" + "net" + "strconv" + "time" + "unicode/utf8" + + "gitee.com/chunanyong/dm/security" +) + +const ( + Dm_build_412 = 8192 + Dm_build_413 = 2 * time.Second +) + +type dm_build_414 struct { + dm_build_415 net.Conn + dm_build_416 *tls.Conn + dm_build_417 *Dm_build_78 + dm_build_418 *DmConnection + dm_build_419 security.Cipher + dm_build_420 bool + dm_build_421 bool + dm_build_422 *security.DhKey + + dm_build_423 bool + dm_build_424 string + dm_build_425 bool +} + +func dm_build_426(dm_build_427 context.Context, dm_build_428 *DmConnection) (*dm_build_414, error) { + var dm_build_429 net.Conn + var dm_build_430 error + + dialsLock.RLock() + dm_build_431, dm_build_432 := dials[dm_build_428.dmConnector.dialName] + dialsLock.RUnlock() + if dm_build_432 { + dm_build_429, dm_build_430 = dm_build_431(dm_build_427, dm_build_428.dmConnector.host+":"+strconv.Itoa(int(dm_build_428.dmConnector.port))) + } else { + dm_build_429, dm_build_430 = dm_build_434(dm_build_428.dmConnector.host+":"+strconv.Itoa(int(dm_build_428.dmConnector.port)), time.Duration(dm_build_428.dmConnector.socketTimeout)*time.Second) + } + if dm_build_430 != nil { + return nil, dm_build_430 + } + + dm_build_433 := dm_build_414{} + dm_build_433.dm_build_415 = dm_build_429 + dm_build_433.dm_build_417 = Dm_build_81(Dm_build_707) + dm_build_433.dm_build_418 = dm_build_428 + dm_build_433.dm_build_420 = false + dm_build_433.dm_build_421 = false + dm_build_433.dm_build_423 = false + dm_build_433.dm_build_424 = "" + dm_build_433.dm_build_425 = false + dm_build_428.Access = &dm_build_433 + + return &dm_build_433, nil +} + +func dm_build_434(dm_build_435 string, dm_build_436 time.Duration) (net.Conn, error) { + dm_build_437, dm_build_438 := net.DialTimeout("tcp", dm_build_435, dm_build_436) + if dm_build_438 != nil { + return &net.TCPConn{}, ECGO_COMMUNITION_ERROR.addDetail("\tdial address: " + dm_build_435).throw() + } + + if tcpConn, ok := dm_build_437.(*net.TCPConn); ok { + tcpConn.SetKeepAlive(true) + tcpConn.SetKeepAlivePeriod(Dm_build_413) + tcpConn.SetNoDelay(true) + + } + return dm_build_437, nil +} + +func (dm_build_440 *dm_build_414) dm_build_439(dm_build_441 dm_build_828) bool { + var dm_build_442 = dm_build_440.dm_build_418.dmConnector.compress + if dm_build_441.dm_build_843() == Dm_build_735 || dm_build_442 == Dm_build_784 { + return false + } + + if dm_build_442 == Dm_build_782 { + return true + } else if dm_build_442 == Dm_build_783 { + return !dm_build_440.dm_build_418.Local && dm_build_441.dm_build_841() > Dm_build_781 + } + + return false +} + +func (dm_build_444 *dm_build_414) dm_build_443(dm_build_445 dm_build_828) bool { + var dm_build_446 = dm_build_444.dm_build_418.dmConnector.compress + if dm_build_445.dm_build_843() == Dm_build_735 || dm_build_446 == Dm_build_784 { + return false + } + + if dm_build_446 == Dm_build_782 { + return true + } else if dm_build_446 == Dm_build_783 { + return dm_build_444.dm_build_417.Dm_build_345(Dm_build_743) == 1 + } + + return false +} + +func (dm_build_448 *dm_build_414) dm_build_447(dm_build_449 dm_build_828) (err error) { + defer func() { + if p := recover(); p != nil { + if _, ok := p.(string); ok { + err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw() + } else { + err = fmt.Errorf("internal error: %v", p) + } + } + }() + + dm_build_451 := dm_build_449.dm_build_841() + + if dm_build_451 > 0 { + + if dm_build_448.dm_build_439(dm_build_449) { + var retBytes, err = Compress(dm_build_448.dm_build_417, Dm_build_736, int(dm_build_451), int(dm_build_448.dm_build_418.dmConnector.compressID)) + if err != nil { + return err + } + + dm_build_448.dm_build_417.Dm_build_92(Dm_build_736) + + dm_build_448.dm_build_417.Dm_build_133(dm_build_451) + + dm_build_448.dm_build_417.Dm_build_161(retBytes) + + dm_build_449.dm_build_842(int32(len(retBytes)) + ULINT_SIZE) + + dm_build_448.dm_build_417.Dm_build_265(Dm_build_743, 1) + } + + if dm_build_448.dm_build_421 { + dm_build_451 = dm_build_449.dm_build_841() + var retBytes = dm_build_448.dm_build_419.Encrypt(dm_build_448.dm_build_417.Dm_build_372(Dm_build_736, int(dm_build_451)), true) + + dm_build_448.dm_build_417.Dm_build_92(Dm_build_736) + + dm_build_448.dm_build_417.Dm_build_161(retBytes) + + dm_build_449.dm_build_842(int32(len(retBytes))) + } + } + + if dm_build_448.dm_build_417.Dm_build_90() > Dm_build_708 { + return ECGO_MSG_TOO_LONG.throw() + } + + dm_build_449.dm_build_837() + if dm_build_448.dm_build_690(dm_build_449) { + if dm_build_448.dm_build_416 != nil { + dm_build_448.dm_build_417.Dm_build_95(0) + if _, err := dm_build_448.dm_build_417.Dm_build_114(dm_build_448.dm_build_416); err != nil { + return err + } + } + } else { + dm_build_448.dm_build_417.Dm_build_95(0) + if _, err := dm_build_448.dm_build_417.Dm_build_114(dm_build_448.dm_build_415); err != nil { + return err + } + } + return nil +} + +func (dm_build_453 *dm_build_414) dm_build_452(dm_build_454 dm_build_828) (err error) { + defer func() { + if p := recover(); p != nil { + if _, ok := p.(string); ok { + err = ECGO_COMMUNITION_ERROR.addDetail("\t" + p.(string)).throw() + } else { + err = fmt.Errorf("internal error: %v", p) + } + } + }() + + dm_build_456 := int32(0) + if dm_build_453.dm_build_690(dm_build_454) { + if dm_build_453.dm_build_416 != nil { + dm_build_453.dm_build_417.Dm_build_92(0) + if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_416, Dm_build_736); err != nil { + return err + } + + dm_build_456 = dm_build_454.dm_build_841() + if dm_build_456 > 0 { + if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_416, int(dm_build_456)); err != nil { + return err + } + } + } + } else { + + dm_build_453.dm_build_417.Dm_build_92(0) + if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_415, Dm_build_736); err != nil { + return err + } + dm_build_456 = dm_build_454.dm_build_841() + + if dm_build_456 > 0 { + if _, err := dm_build_453.dm_build_417.Dm_build_108(dm_build_453.dm_build_415, int(dm_build_456)); err != nil { + return err + } + } + } + + dm_build_454.dm_build_838() + + dm_build_456 = dm_build_454.dm_build_841() + if dm_build_456 <= 0 { + return nil + } + + if dm_build_453.dm_build_421 { + ebytes := dm_build_453.dm_build_417.Dm_build_372(Dm_build_736, int(dm_build_456)) + bytes, err := dm_build_453.dm_build_419.Decrypt(ebytes, true) + if err != nil { + return err + } + dm_build_453.dm_build_417.Dm_build_92(Dm_build_736) + dm_build_453.dm_build_417.Dm_build_161(bytes) + dm_build_454.dm_build_842(int32(len(bytes))) + } + + if dm_build_453.dm_build_443(dm_build_454) { + + dm_build_456 = dm_build_454.dm_build_841() + cbytes := dm_build_453.dm_build_417.Dm_build_372(Dm_build_736+ULINT_SIZE, int(dm_build_456-ULINT_SIZE)) + bytes, err := UnCompress(cbytes, int(dm_build_453.dm_build_418.dmConnector.compressID)) + if err != nil { + return err + } + dm_build_453.dm_build_417.Dm_build_92(Dm_build_736) + dm_build_453.dm_build_417.Dm_build_161(bytes) + dm_build_454.dm_build_842(int32(len(bytes))) + } + return nil +} + +func (dm_build_458 *dm_build_414) dm_build_457(dm_build_459 dm_build_828) (dm_build_460 interface{}, dm_build_461 error) { + if dm_build_458.dm_build_425 { + return nil, ECGO_CONNECTION_CLOSED.throw() + } + dm_build_462 := dm_build_458.dm_build_418 + dm_build_462.mu.Lock() + defer dm_build_462.mu.Unlock() + dm_build_461 = dm_build_459.dm_build_832(dm_build_459) + if dm_build_461 != nil { + return nil, dm_build_461 + } + + dm_build_461 = dm_build_458.dm_build_447(dm_build_459) + if dm_build_461 != nil { + return nil, dm_build_461 + } + + dm_build_461 = dm_build_458.dm_build_452(dm_build_459) + if dm_build_461 != nil { + return nil, dm_build_461 + } + + return dm_build_459.dm_build_836(dm_build_459) +} + +func (dm_build_464 *dm_build_414) dm_build_463() (*dm_build_1287, error) { + + Dm_build_465 := dm_build_1293(dm_build_464) + _, dm_build_466 := dm_build_464.dm_build_457(Dm_build_465) + if dm_build_466 != nil { + return nil, dm_build_466 + } + + return Dm_build_465, nil +} + +func (dm_build_468 *dm_build_414) dm_build_467() error { + + dm_build_469 := dm_build_1152(dm_build_468) + _, dm_build_470 := dm_build_468.dm_build_457(dm_build_469) + if dm_build_470 != nil { + return dm_build_470 + } + + return nil +} + +func (dm_build_472 *dm_build_414) dm_build_471() error { + + var dm_build_473 *dm_build_1287 + var err error + if dm_build_473, err = dm_build_472.dm_build_463(); err != nil { + return err + } + + if dm_build_472.dm_build_418.sslEncrypt == 2 { + if err = dm_build_472.dm_build_686(false); err != nil { + return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw() + } + } else if dm_build_472.dm_build_418.sslEncrypt == 1 { + if err = dm_build_472.dm_build_686(true); err != nil { + return ECGO_INIT_SSL_FAILED.addDetail("\n" + err.Error()).throw() + } + } + + if dm_build_472.dm_build_421 || dm_build_472.dm_build_420 { + k, err := dm_build_472.dm_build_676() + if err != nil { + return err + } + sessionKey := security.ComputeSessionKey(k, dm_build_473.Dm_build_1291) + encryptType := dm_build_473.dm_build_1289 + hashType := int(dm_build_473.Dm_build_1290) + if encryptType == -1 { + encryptType = security.DES_CFB + } + if hashType == -1 { + hashType = security.MD5 + } + err = dm_build_472.dm_build_679(encryptType, sessionKey, dm_build_472.dm_build_418.dmConnector.cipherPath, hashType) + if err != nil { + return err + } + } + + if err := dm_build_472.dm_build_467(); err != nil { + return err + } + return nil +} + +func (dm_build_476 *dm_build_414) Dm_build_475(dm_build_477 *DmStatement) error { + dm_build_478 := dm_build_1317(dm_build_476, dm_build_477) + _, dm_build_479 := dm_build_476.dm_build_457(dm_build_478) + if dm_build_479 != nil { + return dm_build_479 + } + + return nil +} + +func (dm_build_481 *dm_build_414) Dm_build_480(dm_build_482 int32) error { + dm_build_483 := dm_build_1327(dm_build_481, dm_build_482) + _, dm_build_484 := dm_build_481.dm_build_457(dm_build_483) + if dm_build_484 != nil { + return dm_build_484 + } + + return nil +} + +func (dm_build_486 *dm_build_414) Dm_build_485(dm_build_487 *DmStatement, dm_build_488 bool, dm_build_489 int16) (*execRetInfo, error) { + dm_build_490 := dm_build_1193(dm_build_486, dm_build_487, dm_build_488, dm_build_489) + dm_build_491, dm_build_492 := dm_build_486.dm_build_457(dm_build_490) + if dm_build_492 != nil { + return nil, dm_build_492 + } + return dm_build_491.(*execRetInfo), nil +} + +func (dm_build_494 *dm_build_414) Dm_build_493(dm_build_495 *DmStatement, dm_build_496 int16) (*execRetInfo, error) { + return dm_build_494.Dm_build_485(dm_build_495, false, Dm_build_788) +} + +func (dm_build_498 *dm_build_414) Dm_build_497(dm_build_499 *DmStatement, dm_build_500 []OptParameter) (*execRetInfo, error) { + dm_build_501, dm_build_502 := dm_build_498.dm_build_457(dm_build_931(dm_build_498, dm_build_499, dm_build_500)) + if dm_build_502 != nil { + return nil, dm_build_502 + } + + return dm_build_501.(*execRetInfo), nil +} + +func (dm_build_504 *dm_build_414) Dm_build_503(dm_build_505 *DmStatement, dm_build_506 int16) (*execRetInfo, error) { + return dm_build_504.Dm_build_485(dm_build_505, true, dm_build_506) +} + +func (dm_build_508 *dm_build_414) Dm_build_507(dm_build_509 *DmStatement, dm_build_510 [][]interface{}) (*execRetInfo, error) { + dm_build_511 := dm_build_963(dm_build_508, dm_build_509, dm_build_510) + dm_build_512, dm_build_513 := dm_build_508.dm_build_457(dm_build_511) + if dm_build_513 != nil { + return nil, dm_build_513 + } + return dm_build_512.(*execRetInfo), nil +} + +func (dm_build_515 *dm_build_414) Dm_build_514(dm_build_516 *DmStatement, dm_build_517 [][]interface{}, dm_build_518 bool) (*execRetInfo, error) { + var dm_build_519, dm_build_520 = 0, 0 + var dm_build_521 = len(dm_build_517) + var dm_build_522 [][]interface{} + var dm_build_523 = NewExceInfo() + dm_build_523.updateCounts = make([]int64, dm_build_521) + var dm_build_524 = false + for dm_build_519 < dm_build_521 { + for dm_build_520 = dm_build_519; dm_build_520 < dm_build_521; dm_build_520++ { + paramData := dm_build_517[dm_build_520] + bindData := make([]interface{}, dm_build_516.paramCount) + dm_build_524 = false + for icol := 0; icol < int(dm_build_516.paramCount); icol++ { + if dm_build_516.bindParams[icol].ioType == IO_TYPE_OUT { + continue + } + if dm_build_515.dm_build_659(bindData, paramData, icol) { + dm_build_524 = true + break + } + } + + if dm_build_524 { + break + } + dm_build_522 = append(dm_build_522, bindData) + } + + if dm_build_520 != dm_build_519 { + tmpExecInfo, err := dm_build_515.Dm_build_507(dm_build_516, dm_build_522) + if err != nil { + return nil, err + } + dm_build_522 = dm_build_522[0:0] + dm_build_523.union(tmpExecInfo, dm_build_519, dm_build_520-dm_build_519) + } + + if dm_build_520 < dm_build_521 { + tmpExecInfo, err := dm_build_515.Dm_build_533(dm_build_516, dm_build_517[dm_build_520], dm_build_518) + if err != nil { + return nil, err + } + + dm_build_518 = true + dm_build_523.union(tmpExecInfo, dm_build_520, 1) + } + + dm_build_519 = dm_build_520 + 1 + } + for _, i := range dm_build_523.updateCounts { + if i > 0 { + dm_build_523.updateCount += i + } + } + return dm_build_523, nil +} + +func (dm_build_526 *dm_build_414) dm_build_525(dm_build_527 *DmStatement, dm_build_528 []parameter) error { + if !dm_build_527.prepared { + retInfo, err := dm_build_526.Dm_build_485(dm_build_527, false, Dm_build_788) + if err != nil { + return nil + } + dm_build_527.serverParams = retInfo.serverParams + dm_build_527.paramCount = int32(len(dm_build_527.serverParams)) + dm_build_527.prepared = true + } + + dm_build_529 := dm_build_1182(dm_build_526, dm_build_527, dm_build_527.bindParams) + dm_build_530, err := dm_build_526.dm_build_457(dm_build_529) + if err != nil { + return nil + } + retInfo := dm_build_530.(*execRetInfo) + if retInfo.serverParams != nil && len(retInfo.serverParams) > 0 { + dm_build_527.serverParams = retInfo.serverParams + dm_build_527.paramCount = int32(len(dm_build_527.serverParams)) + } + dm_build_527.preExec = true + return nil +} + +func (dm_build_534 *dm_build_414) Dm_build_533(dm_build_535 *DmStatement, dm_build_536 []interface{}, dm_build_537 bool) (*execRetInfo, error) { + + var dm_build_538 = make([]interface{}, dm_build_535.paramCount) + for icol := 0; icol < int(dm_build_535.paramCount); icol++ { + if dm_build_535.bindParams[icol].ioType == IO_TYPE_OUT { + continue + } + if dm_build_534.dm_build_659(dm_build_538, dm_build_536, icol) { + + if !dm_build_537 { + dm_build_534.dm_build_525(dm_build_535, dm_build_535.bindParams) + + dm_build_537 = true + } + + dm_build_534.dm_build_665(dm_build_535, dm_build_535.bindParams[icol], icol, dm_build_536[icol].(iOffRowBinder)) + dm_build_538[icol] = ParamDataEnum_OFF_ROW + } + } + + var dm_build_539 = make([][]interface{}, 1, 1) + dm_build_539[0] = dm_build_538 + + dm_build_540 := dm_build_963(dm_build_534, dm_build_535, dm_build_539) + dm_build_541, dm_build_542 := dm_build_534.dm_build_457(dm_build_540) + if dm_build_542 != nil { + return nil, dm_build_542 + } + return dm_build_541.(*execRetInfo), nil +} + +func (dm_build_544 *dm_build_414) Dm_build_543(dm_build_545 *DmStatement, dm_build_546 int16) (*execRetInfo, error) { + dm_build_547 := dm_build_1169(dm_build_544, dm_build_545, dm_build_546) + + dm_build_548, dm_build_549 := dm_build_544.dm_build_457(dm_build_547) + if dm_build_549 != nil { + return nil, dm_build_549 + } + return dm_build_548.(*execRetInfo), nil +} + +func (dm_build_551 *dm_build_414) Dm_build_550(dm_build_552 *innerRows, dm_build_553 int64) (*execRetInfo, error) { + dm_build_554 := dm_build_1070(dm_build_551, dm_build_552, dm_build_553, INT64_MAX) + dm_build_555, dm_build_556 := dm_build_551.dm_build_457(dm_build_554) + if dm_build_556 != nil { + return nil, dm_build_556 + } + return dm_build_555.(*execRetInfo), nil +} + +func (dm_build_558 *dm_build_414) Commit() error { + dm_build_559 := dm_build_916(dm_build_558) + _, dm_build_560 := dm_build_558.dm_build_457(dm_build_559) + if dm_build_560 != nil { + return dm_build_560 + } + + return nil +} + +func (dm_build_562 *dm_build_414) Rollback() error { + dm_build_563 := dm_build_1231(dm_build_562) + _, dm_build_564 := dm_build_562.dm_build_457(dm_build_563) + if dm_build_564 != nil { + return dm_build_564 + } + + return nil +} + +func (dm_build_566 *dm_build_414) Dm_build_565(dm_build_567 *DmConnection) error { + dm_build_568 := dm_build_1236(dm_build_566, dm_build_567.IsoLevel) + _, dm_build_569 := dm_build_566.dm_build_457(dm_build_568) + if dm_build_569 != nil { + return dm_build_569 + } + + return nil +} + +func (dm_build_571 *dm_build_414) Dm_build_570(dm_build_572 *DmStatement, dm_build_573 string) error { + dm_build_574 := dm_build_921(dm_build_571, dm_build_572, dm_build_573) + _, dm_build_575 := dm_build_571.dm_build_457(dm_build_574) + if dm_build_575 != nil { + return dm_build_575 + } + + return nil +} + +func (dm_build_577 *dm_build_414) Dm_build_576(dm_build_578 []uint32) ([]int64, error) { + dm_build_579 := dm_build_1335(dm_build_577, dm_build_578) + dm_build_580, dm_build_581 := dm_build_577.dm_build_457(dm_build_579) + if dm_build_581 != nil { + return nil, dm_build_581 + } + return dm_build_580.([]int64), nil +} + +func (dm_build_583 *dm_build_414) Close() error { + if dm_build_583.dm_build_425 { + return nil + } + + dm_build_584 := dm_build_583.dm_build_415.Close() + if dm_build_584 != nil { + return dm_build_584 + } + + dm_build_583.dm_build_418 = nil + dm_build_583.dm_build_425 = true + return nil +} + +func (dm_build_586 *dm_build_414) dm_build_585(dm_build_587 *lob) (int64, error) { + dm_build_588 := dm_build_1103(dm_build_586, dm_build_587) + dm_build_589, dm_build_590 := dm_build_586.dm_build_457(dm_build_588) + if dm_build_590 != nil { + return 0, dm_build_590 + } + return dm_build_589.(int64), nil +} + +func (dm_build_592 *dm_build_414) dm_build_591(dm_build_593 *lob, dm_build_594 int32, dm_build_595 int32) (*lobRetInfo, error) { + dm_build_596 := dm_build_1088(dm_build_592, dm_build_593, int(dm_build_594), int(dm_build_595)) + dm_build_597, dm_build_598 := dm_build_592.dm_build_457(dm_build_596) + if dm_build_598 != nil { + return nil, dm_build_598 + } + return dm_build_597.(*lobRetInfo), nil +} + +func (dm_build_600 *dm_build_414) dm_build_599(dm_build_601 *DmBlob, dm_build_602 int32, dm_build_603 int32) ([]byte, error) { + var dm_build_604 = make([]byte, dm_build_603) + var dm_build_605 int32 = 0 + var dm_build_606 int32 = 0 + var dm_build_607 *lobRetInfo + var dm_build_608 []byte + var dm_build_609 error + for dm_build_605 < dm_build_603 { + dm_build_606 = dm_build_603 - dm_build_605 + if dm_build_606 > Dm_build_821 { + dm_build_606 = Dm_build_821 + } + dm_build_607, dm_build_609 = dm_build_600.dm_build_591(&dm_build_601.lob, dm_build_602+dm_build_605, dm_build_606) + if dm_build_609 != nil { + return nil, dm_build_609 + } + dm_build_608 = dm_build_607.data + if dm_build_608 == nil || len(dm_build_608) == 0 { + break + } + Dm_build_1346.Dm_build_1402(dm_build_604, int(dm_build_605), dm_build_608, 0, len(dm_build_608)) + dm_build_605 += int32(len(dm_build_608)) + if dm_build_601.readOver { + break + } + } + return dm_build_604, nil +} + +func (dm_build_611 *dm_build_414) dm_build_610(dm_build_612 *DmClob, dm_build_613 int32, dm_build_614 int32) (string, error) { + var dm_build_615 bytes.Buffer + var dm_build_616 int32 = 0 + var dm_build_617 int32 = 0 + var dm_build_618 *lobRetInfo + var dm_build_619 []byte + var dm_build_621 error + for dm_build_616 < dm_build_614 { + dm_build_617 = dm_build_614 - dm_build_616 + if dm_build_617 > Dm_build_821/2 { + dm_build_617 = Dm_build_821 / 2 + } + dm_build_618, dm_build_621 = dm_build_611.dm_build_591(&dm_build_612.lob, dm_build_613+dm_build_616, dm_build_617) + if dm_build_621 != nil { + return "", dm_build_621 + } + dm_build_619 = dm_build_618.data + if dm_build_619 == nil || len(dm_build_619) == 0 { + break + } + dm_build_615.Write(dm_build_619) + var strLen = dm_build_618.charLen + if strLen == -1 { + // Keep offset semantics when server does not provide charLen. + decoded := Dm_build_1346.Dm_build_1503(dm_build_619, 0, len(dm_build_619), dm_build_612.serverEncoding, dm_build_611.dm_build_418) + strLen = int64(utf8.RuneCountInString(decoded)) + } + dm_build_616 += int32(strLen) + if dm_build_612.readOver { + break + } + } + raw := dm_build_615.Bytes() + if len(raw) == 0 { + return "", nil + } + return Dm_build_1346.Dm_build_1503(raw, 0, len(raw), dm_build_612.serverEncoding, dm_build_611.dm_build_418), nil +} + +func (dm_build_623 *dm_build_414) dm_build_622(dm_build_624 *DmClob, dm_build_625 int, dm_build_626 string, dm_build_627 string) (int, error) { + var dm_build_628 = Dm_build_1346.Dm_build_1562(dm_build_626, dm_build_627, dm_build_623.dm_build_418) + var dm_build_629 = 0 + var dm_build_630 = len(dm_build_628) + var dm_build_631 = 0 + var dm_build_632 = 0 + var dm_build_633 = 0 + var dm_build_635 byte = 0 + var dm_build_636 byte = 0x01 + var dm_build_637 byte = 0x02 + for dm_build_632 < dm_build_630 { + dm_build_635 = 0 + if dm_build_632 == 0 { + dm_build_635 |= dm_build_636 + } + dm_build_633 = dm_build_630 - dm_build_632 + if dm_build_633 > Dm_build_820 { + dm_build_633 = Dm_build_820 + // Avoid splitting a UTF-8 sequence at chunk boundaries. + if dm_build_627 == "UTF-8" { + chunkEnd := dm_build_632 + dm_build_633 + if chunkEnd < dm_build_630 { + for chunkEnd > dm_build_632 && (dm_build_628[chunkEnd]&0xC0) == 0x80 { + chunkEnd-- + } + if chunkEnd > dm_build_632 { + dm_build_633 = chunkEnd - dm_build_632 + } + } + } + } + if dm_build_633 <= 0 { + return dm_build_631, nil + } + if dm_build_632+dm_build_633 >= dm_build_630 { + dm_build_635 |= dm_build_637 + } + + setLobData := dm_build_1250(dm_build_623, &dm_build_624.lob, dm_build_635, dm_build_625, dm_build_628, dm_build_629, dm_build_633) + ret, err := dm_build_623.dm_build_457(setLobData) + if err != nil { + return 0, err + } + tmp := ret.(int32) + if err != nil { + return -1, err + } + if tmp <= 0 { + return dm_build_631, nil + } else { + dm_build_625 += int(tmp) + dm_build_631 += int(tmp) + dm_build_632 += dm_build_633 + dm_build_629 += dm_build_633 + } + } + return dm_build_631, nil +} + +func (dm_build_639 *dm_build_414) dm_build_638(dm_build_640 *DmBlob, dm_build_641 int, dm_build_642 []byte) (int, error) { + var dm_build_643 = 0 + var dm_build_644 = len(dm_build_642) + var dm_build_645 = 0 + var dm_build_646 = 0 + var dm_build_647 = 0 + var dm_build_648 = dm_build_644/Dm_build_820 + 1 + var dm_build_649 byte = 0 + var dm_build_650 byte = 0x01 + var dm_build_651 byte = 0x02 + for i := 0; i < dm_build_648; i++ { + dm_build_649 = 0 + if i == 0 { + dm_build_649 |= dm_build_650 + } + if i == dm_build_648-1 { + dm_build_649 |= dm_build_651 + } + dm_build_647 = dm_build_644 - dm_build_646 + if dm_build_647 > Dm_build_820 { + dm_build_647 = Dm_build_820 + } + + setLobData := dm_build_1250(dm_build_639, &dm_build_640.lob, dm_build_649, dm_build_641, dm_build_642, dm_build_643, dm_build_647) + ret, err := dm_build_639.dm_build_457(setLobData) + if err != nil { + return 0, err + } + tmp := ret.(int32) + if tmp <= 0 { + return dm_build_645, nil + } else { + dm_build_641 += int(tmp) + dm_build_645 += int(tmp) + dm_build_646 += dm_build_647 + dm_build_643 += dm_build_647 + } + } + return dm_build_645, nil +} + +func (dm_build_653 *dm_build_414) dm_build_652(dm_build_654 *lob, dm_build_655 int) (int64, error) { + dm_build_656 := dm_build_1114(dm_build_653, dm_build_654, dm_build_655) + dm_build_657, dm_build_658 := dm_build_653.dm_build_457(dm_build_656) + if dm_build_658 != nil { + return dm_build_654.length, dm_build_658 + } + return dm_build_657.(int64), nil +} + +func (dm_build_660 *dm_build_414) dm_build_659(dm_build_661 []interface{}, dm_build_662 []interface{}, dm_build_663 int) bool { + var dm_build_664 = false + dm_build_661[dm_build_663] = dm_build_662[dm_build_663] + + if binder, ok := dm_build_662[dm_build_663].(iOffRowBinder); ok { + dm_build_664 = true + dm_build_661[dm_build_663] = make([]byte, 0) + var lob lob + if l, ok := binder.getObj().(DmBlob); ok { + lob = l.lob + } else if l, ok := binder.getObj().(DmClob); ok { + lob = l.lob + } + if &lob != nil && lob.canOptimized(dm_build_660.dm_build_418) { + dm_build_661[dm_build_663] = &lobCtl{lob.buildCtlData()} + dm_build_664 = false + } + } else { + dm_build_661[dm_build_663] = dm_build_662[dm_build_663] + } + return dm_build_664 +} + +func (dm_build_666 *dm_build_414) dm_build_665(dm_build_667 *DmStatement, dm_build_668 parameter, dm_build_669 int, dm_build_670 iOffRowBinder) error { + var dm_build_671 = Dm_build_4() + dm_build_670.read(dm_build_671) + var dm_build_672 = 0 + var utf8ClobParam = dm_build_668.colType == CLOB && dm_build_666.dm_build_418.getServerEncoding() == "UTF-8" + for !dm_build_670.isReadOver() || dm_build_671.Dm_build_5() > 0 { + if !dm_build_670.isReadOver() && dm_build_671.Dm_build_5() < Dm_build_820 { + dm_build_670.read(dm_build_671) + } + if dm_build_671.Dm_build_5() > Dm_build_820 { + dm_build_672 = Dm_build_820 + } else { + dm_build_672 = dm_build_671.Dm_build_5() + } + if utf8ClobParam && dm_build_672 == Dm_build_820 && dm_build_671.Dm_build_5() > dm_build_672 { + safeLen := dm_build_672 + for safeLen > 0 && (dm_build_671.dm_build_32(safeLen)&0xC0) == 0x80 { + safeLen-- + } + if safeLen > 0 { + dm_build_672 = safeLen + } + } + + putData := dm_build_1221(dm_build_666, dm_build_667, int16(dm_build_669), dm_build_671, int32(dm_build_672)) + _, err := dm_build_666.dm_build_457(putData) + if err != nil { + return err + } + } + return nil +} + +func (dm_build_674 *dm_build_414) dm_build_673() ([]byte, error) { + var dm_build_675 error + if dm_build_674.dm_build_422 == nil { + if dm_build_674.dm_build_422, dm_build_675 = security.NewClientKeyPair(); dm_build_675 != nil { + return nil, dm_build_675 + } + } + return security.Bn2Bytes(dm_build_674.dm_build_422.GetY(), security.DH_KEY_LENGTH), nil +} + +func (dm_build_677 *dm_build_414) dm_build_676() (*security.DhKey, error) { + var dm_build_678 error + if dm_build_677.dm_build_422 == nil { + if dm_build_677.dm_build_422, dm_build_678 = security.NewClientKeyPair(); dm_build_678 != nil { + return nil, dm_build_678 + } + } + return dm_build_677.dm_build_422, nil +} + +func (dm_build_680 *dm_build_414) dm_build_679(dm_build_681 int, dm_build_682 []byte, dm_build_683 string, dm_build_684 int) (dm_build_685 error) { + if dm_build_681 > 0 && dm_build_681 < security.MIN_EXTERNAL_CIPHER_ID && dm_build_682 != nil { + dm_build_680.dm_build_419, dm_build_685 = security.NewSymmCipher(dm_build_681, dm_build_682) + } else if dm_build_681 >= security.MIN_EXTERNAL_CIPHER_ID { + if dm_build_680.dm_build_419, dm_build_685 = security.NewThirdPartCipher(dm_build_681, dm_build_682, dm_build_683, dm_build_684); dm_build_685 != nil { + dm_build_685 = THIRD_PART_CIPHER_INIT_FAILED.addDetailln(dm_build_685.Error()).throw() + } + } + return +} + +func (dm_build_687 *dm_build_414) dm_build_686(dm_build_688 bool) (dm_build_689 error) { + if dm_build_687.dm_build_416, dm_build_689 = security.NewTLSFromTCP(dm_build_687.dm_build_415, dm_build_687.dm_build_418.dmConnector.sslCertPath, dm_build_687.dm_build_418.dmConnector.sslKeyPath, dm_build_687.dm_build_418.dmConnector.user); dm_build_689 != nil { + return + } + if !dm_build_688 { + dm_build_687.dm_build_416 = nil + } + return +} + +func (dm_build_691 *dm_build_414) dm_build_690(dm_build_692 dm_build_828) bool { + return dm_build_692.dm_build_843() != Dm_build_735 && dm_build_691.dm_build_418.sslEncrypt == 1 +} diff --git a/dpi_bridge/third_party/chunanyong_dm/b.go b/dpi_bridge/third_party/chunanyong_dm/b.go new file mode 100644 index 0000000..6939100 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/b.go @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +type ArrayDescriptor struct { + m_typeDesc *TypeDescriptor +} + +func newArrayDescriptor(fulName string, conn *DmConnection) (*ArrayDescriptor, error) { + + ad := new(ArrayDescriptor) + + if fulName == "" { + return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw() + } + + ad.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn) + err := ad.m_typeDesc.parseDescByName() + if err != nil { + return nil, err + } + + return ad, nil +} + +func newArrayDescriptorByTypeDescriptor(desc *TypeDescriptor) *ArrayDescriptor { + ad := new(ArrayDescriptor) + ad.m_typeDesc = desc + return ad +} + +func (ad *ArrayDescriptor) getMDesc() *TypeDescriptor { + return ad.m_typeDesc +} + +func (ad *ArrayDescriptor) getItemDesc() *TypeDescriptor { + return ad.m_typeDesc.m_arrObj +} + +func (ad *ArrayDescriptor) getLength() int { + return ad.m_typeDesc.m_length +} diff --git a/dpi_bridge/third_party/chunanyong_dm/c.go b/dpi_bridge/third_party/chunanyong_dm/c.go new file mode 100644 index 0000000..a03eb88 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/c.go @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "io" + "math" +) + +type Dm_build_78 struct { + dm_build_79 []byte + dm_build_80 int +} + +func Dm_build_81(dm_build_82 int) *Dm_build_78 { + return &Dm_build_78{make([]byte, 0, dm_build_82), 0} +} + +func Dm_build_83(dm_build_84 []byte) *Dm_build_78 { + return &Dm_build_78{dm_build_84, 0} +} + +func (dm_build_86 *Dm_build_78) dm_build_85(dm_build_87 int) *Dm_build_78 { + + dm_build_88 := len(dm_build_86.dm_build_79) + dm_build_89 := cap(dm_build_86.dm_build_79) + + if dm_build_88+dm_build_87 <= dm_build_89 { + dm_build_86.dm_build_79 = dm_build_86.dm_build_79[:dm_build_88+dm_build_87] + } else { + + var calCap = int64(math.Max(float64(2*dm_build_89), float64(dm_build_87+dm_build_88))) + + nbuf := make([]byte, dm_build_87+dm_build_88, calCap) + copy(nbuf, dm_build_86.dm_build_79) + dm_build_86.dm_build_79 = nbuf + } + + return dm_build_86 +} + +func (dm_build_91 *Dm_build_78) Dm_build_90() int { + return len(dm_build_91.dm_build_79) +} + +func (dm_build_93 *Dm_build_78) Dm_build_92(dm_build_94 int) *Dm_build_78 { + for i := dm_build_94; i < len(dm_build_93.dm_build_79); i++ { + dm_build_93.dm_build_79[i] = 0 + } + dm_build_93.dm_build_79 = dm_build_93.dm_build_79[:dm_build_94] + return dm_build_93 +} + +func (dm_build_96 *Dm_build_78) Dm_build_95(dm_build_97 int) *Dm_build_78 { + dm_build_96.dm_build_80 = dm_build_97 + return dm_build_96 +} + +func (dm_build_99 *Dm_build_78) Dm_build_98() int { + return dm_build_99.dm_build_80 +} + +func (dm_build_101 *Dm_build_78) Dm_build_100(dm_build_102 bool) int { + return len(dm_build_101.dm_build_79) - dm_build_101.dm_build_80 +} + +func (dm_build_104 *Dm_build_78) Dm_build_103(dm_build_105 int, dm_build_106 bool, dm_build_107 bool) *Dm_build_78 { + + if dm_build_106 { + if dm_build_107 { + dm_build_104.dm_build_85(dm_build_105) + } else { + dm_build_104.dm_build_79 = dm_build_104.dm_build_79[:len(dm_build_104.dm_build_79)-dm_build_105] + } + } else { + if dm_build_107 { + dm_build_104.dm_build_80 += dm_build_105 + } else { + dm_build_104.dm_build_80 -= dm_build_105 + } + } + + return dm_build_104 +} + +func (dm_build_109 *Dm_build_78) Dm_build_108(dm_build_110 io.Reader, dm_build_111 int) (int, error) { + dm_build_112 := len(dm_build_109.dm_build_79) + dm_build_109.dm_build_85(dm_build_111) + dm_build_113 := 0 + for dm_build_111 > 0 { + n, err := dm_build_110.Read(dm_build_109.dm_build_79[dm_build_112+dm_build_113:]) + if n > 0 && err == io.EOF { + dm_build_113 += n + dm_build_109.dm_build_79 = dm_build_109.dm_build_79[:dm_build_112+dm_build_113] + return dm_build_113, nil + } else if n > 0 && err == nil { + dm_build_111 -= n + dm_build_113 += n + } else if n == 0 && err != nil { + return -1, ECGO_COMMUNITION_ERROR.addDetailln(err.Error()).throw() + } + } + + return dm_build_113, nil +} + +func (dm_build_115 *Dm_build_78) Dm_build_114(dm_build_116 io.Writer) (*Dm_build_78, error) { + if _, err := dm_build_116.Write(dm_build_115.dm_build_79); err != nil { + return nil, ECGO_COMMUNITION_ERROR.addDetailln(err.Error()).throw() + } + return dm_build_115, nil +} + +func (dm_build_118 *Dm_build_78) Dm_build_117(dm_build_119 bool) int { + dm_build_120 := len(dm_build_118.dm_build_79) + dm_build_118.dm_build_85(1) + + if dm_build_119 { + return copy(dm_build_118.dm_build_79[dm_build_120:], []byte{1}) + } else { + return copy(dm_build_118.dm_build_79[dm_build_120:], []byte{0}) + } +} + +func (dm_build_122 *Dm_build_78) Dm_build_121(dm_build_123 byte) int { + dm_build_124 := len(dm_build_122.dm_build_79) + dm_build_122.dm_build_85(1) + + return copy(dm_build_122.dm_build_79[dm_build_124:], Dm_build_1346.Dm_build_1524(dm_build_123)) +} + +func (dm_build_126 *Dm_build_78) Dm_build_125(dm_build_127 int8) int { + dm_build_128 := len(dm_build_126.dm_build_79) + dm_build_126.dm_build_85(1) + + return copy(dm_build_126.dm_build_79[dm_build_128:], Dm_build_1346.Dm_build_1527(dm_build_127)) +} + +func (dm_build_130 *Dm_build_78) Dm_build_129(dm_build_131 int16) int { + dm_build_132 := len(dm_build_130.dm_build_79) + dm_build_130.dm_build_85(2) + + return copy(dm_build_130.dm_build_79[dm_build_132:], Dm_build_1346.Dm_build_1530(dm_build_131)) +} + +func (dm_build_134 *Dm_build_78) Dm_build_133(dm_build_135 int32) int { + dm_build_136 := len(dm_build_134.dm_build_79) + dm_build_134.dm_build_85(4) + + return copy(dm_build_134.dm_build_79[dm_build_136:], Dm_build_1346.Dm_build_1533(dm_build_135)) +} + +func (dm_build_138 *Dm_build_78) Dm_build_137(dm_build_139 uint8) int { + dm_build_140 := len(dm_build_138.dm_build_79) + dm_build_138.dm_build_85(1) + + return copy(dm_build_138.dm_build_79[dm_build_140:], Dm_build_1346.Dm_build_1545(dm_build_139)) +} + +func (dm_build_142 *Dm_build_78) Dm_build_141(dm_build_143 uint16) int { + dm_build_144 := len(dm_build_142.dm_build_79) + dm_build_142.dm_build_85(2) + + return copy(dm_build_142.dm_build_79[dm_build_144:], Dm_build_1346.Dm_build_1548(dm_build_143)) +} + +func (dm_build_146 *Dm_build_78) Dm_build_145(dm_build_147 uint32) int { + dm_build_148 := len(dm_build_146.dm_build_79) + dm_build_146.dm_build_85(4) + + return copy(dm_build_146.dm_build_79[dm_build_148:], Dm_build_1346.Dm_build_1551(dm_build_147)) +} + +func (dm_build_150 *Dm_build_78) Dm_build_149(dm_build_151 uint64) int { + dm_build_152 := len(dm_build_150.dm_build_79) + dm_build_150.dm_build_85(8) + + return copy(dm_build_150.dm_build_79[dm_build_152:], Dm_build_1346.Dm_build_1554(dm_build_151)) +} + +func (dm_build_154 *Dm_build_78) Dm_build_153(dm_build_155 float32) int { + dm_build_156 := len(dm_build_154.dm_build_79) + dm_build_154.dm_build_85(4) + + return copy(dm_build_154.dm_build_79[dm_build_156:], Dm_build_1346.Dm_build_1551(math.Float32bits(dm_build_155))) +} + +func (dm_build_158 *Dm_build_78) Dm_build_157(dm_build_159 float64) int { + dm_build_160 := len(dm_build_158.dm_build_79) + dm_build_158.dm_build_85(8) + + return copy(dm_build_158.dm_build_79[dm_build_160:], Dm_build_1346.Dm_build_1554(math.Float64bits(dm_build_159))) +} + +func (dm_build_162 *Dm_build_78) Dm_build_161(dm_build_163 []byte) int { + dm_build_164 := len(dm_build_162.dm_build_79) + dm_build_162.dm_build_85(len(dm_build_163)) + return copy(dm_build_162.dm_build_79[dm_build_164:], dm_build_163) +} + +func (dm_build_166 *Dm_build_78) Dm_build_165(dm_build_167 []byte) int { + return dm_build_166.Dm_build_133(int32(len(dm_build_167))) + dm_build_166.Dm_build_161(dm_build_167) +} + +func (dm_build_169 *Dm_build_78) Dm_build_168(dm_build_170 []byte) int { + return dm_build_169.Dm_build_137(uint8(len(dm_build_170))) + dm_build_169.Dm_build_161(dm_build_170) +} + +func (dm_build_172 *Dm_build_78) Dm_build_171(dm_build_173 []byte) int { + return dm_build_172.Dm_build_141(uint16(len(dm_build_173))) + dm_build_172.Dm_build_161(dm_build_173) +} + +func (dm_build_175 *Dm_build_78) Dm_build_174(dm_build_176 []byte) int { + return dm_build_175.Dm_build_161(dm_build_176) + dm_build_175.Dm_build_121(0) +} + +func (dm_build_178 *Dm_build_78) Dm_build_177(dm_build_179 string, dm_build_180 string, dm_build_181 *DmConnection) int { + dm_build_182 := Dm_build_1346.Dm_build_1562(dm_build_179, dm_build_180, dm_build_181) + return dm_build_178.Dm_build_165(dm_build_182) +} + +func (dm_build_184 *Dm_build_78) Dm_build_183(dm_build_185 string, dm_build_186 string, dm_build_187 *DmConnection) int { + dm_build_188 := Dm_build_1346.Dm_build_1562(dm_build_185, dm_build_186, dm_build_187) + return dm_build_184.Dm_build_168(dm_build_188) +} + +func (dm_build_190 *Dm_build_78) Dm_build_189(dm_build_191 string, dm_build_192 string, dm_build_193 *DmConnection) int { + dm_build_194 := Dm_build_1346.Dm_build_1562(dm_build_191, dm_build_192, dm_build_193) + return dm_build_190.Dm_build_171(dm_build_194) +} + +func (dm_build_196 *Dm_build_78) Dm_build_195(dm_build_197 string, dm_build_198 string, dm_build_199 *DmConnection) int { + dm_build_200 := Dm_build_1346.Dm_build_1562(dm_build_197, dm_build_198, dm_build_199) + return dm_build_196.Dm_build_174(dm_build_200) +} + +func (dm_build_202 *Dm_build_78) Dm_build_201() byte { + dm_build_203 := Dm_build_1346.Dm_build_1439(dm_build_202.dm_build_79, dm_build_202.dm_build_80) + dm_build_202.dm_build_80++ + return dm_build_203 +} + +func (dm_build_205 *Dm_build_78) Dm_build_204() int16 { + dm_build_206 := Dm_build_1346.Dm_build_1443(dm_build_205.dm_build_79, dm_build_205.dm_build_80) + dm_build_205.dm_build_80 += 2 + return dm_build_206 +} + +func (dm_build_208 *Dm_build_78) Dm_build_207() int32 { + dm_build_209 := Dm_build_1346.Dm_build_1448(dm_build_208.dm_build_79, dm_build_208.dm_build_80) + dm_build_208.dm_build_80 += 4 + return dm_build_209 +} + +func (dm_build_211 *Dm_build_78) Dm_build_210() int64 { + dm_build_212 := Dm_build_1346.Dm_build_1453(dm_build_211.dm_build_79, dm_build_211.dm_build_80) + dm_build_211.dm_build_80 += 8 + return dm_build_212 +} + +func (dm_build_214 *Dm_build_78) Dm_build_213() float32 { + dm_build_215 := Dm_build_1346.Dm_build_1458(dm_build_214.dm_build_79, dm_build_214.dm_build_80) + dm_build_214.dm_build_80 += 4 + return dm_build_215 +} + +func (dm_build_217 *Dm_build_78) Dm_build_216() float64 { + dm_build_218 := Dm_build_1346.Dm_build_1462(dm_build_217.dm_build_79, dm_build_217.dm_build_80) + dm_build_217.dm_build_80 += 8 + return dm_build_218 +} + +func (dm_build_220 *Dm_build_78) Dm_build_219() uint8 { + dm_build_221 := Dm_build_1346.Dm_build_1466(dm_build_220.dm_build_79, dm_build_220.dm_build_80) + dm_build_220.dm_build_80 += 1 + return dm_build_221 +} + +func (dm_build_223 *Dm_build_78) Dm_build_222() uint16 { + dm_build_224 := Dm_build_1346.Dm_build_1470(dm_build_223.dm_build_79, dm_build_223.dm_build_80) + dm_build_223.dm_build_80 += 2 + return dm_build_224 +} + +func (dm_build_226 *Dm_build_78) Dm_build_225() uint32 { + dm_build_227 := Dm_build_1346.Dm_build_1475(dm_build_226.dm_build_79, dm_build_226.dm_build_80) + dm_build_226.dm_build_80 += 4 + return dm_build_227 +} + +func (dm_build_229 *Dm_build_78) Dm_build_228(dm_build_230 int) []byte { + dm_build_231 := Dm_build_1346.Dm_build_1497(dm_build_229.dm_build_79, dm_build_229.dm_build_80, dm_build_230) + dm_build_229.dm_build_80 += dm_build_230 + return dm_build_231 +} + +func (dm_build_233 *Dm_build_78) Dm_build_232() []byte { + return dm_build_233.Dm_build_228(int(dm_build_233.Dm_build_207())) +} + +func (dm_build_235 *Dm_build_78) Dm_build_234() []byte { + return dm_build_235.Dm_build_228(int(dm_build_235.Dm_build_201())) +} + +func (dm_build_237 *Dm_build_78) Dm_build_236() []byte { + return dm_build_237.Dm_build_228(int(dm_build_237.Dm_build_204())) +} + +func (dm_build_239 *Dm_build_78) Dm_build_238(dm_build_240 int) []byte { + return dm_build_239.Dm_build_228(dm_build_240) +} + +func (dm_build_242 *Dm_build_78) Dm_build_241() []byte { + dm_build_243 := 0 + for dm_build_242.Dm_build_201() != 0 { + dm_build_243++ + } + dm_build_242.Dm_build_103(dm_build_243, false, false) + return dm_build_242.Dm_build_228(dm_build_243) +} + +func (dm_build_245 *Dm_build_78) Dm_build_244(dm_build_246 int, dm_build_247 string, dm_build_248 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_245.Dm_build_228(dm_build_246), dm_build_247, dm_build_248) +} + +func (dm_build_250 *Dm_build_78) Dm_build_249(dm_build_251 string, dm_build_252 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_250.Dm_build_232(), dm_build_251, dm_build_252) +} + +func (dm_build_254 *Dm_build_78) Dm_build_253(dm_build_255 string, dm_build_256 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_254.Dm_build_234(), dm_build_255, dm_build_256) +} + +func (dm_build_258 *Dm_build_78) Dm_build_257(dm_build_259 string, dm_build_260 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_258.Dm_build_236(), dm_build_259, dm_build_260) +} + +func (dm_build_262 *Dm_build_78) Dm_build_261(dm_build_263 string, dm_build_264 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_262.Dm_build_241(), dm_build_263, dm_build_264) +} + +func (dm_build_266 *Dm_build_78) Dm_build_265(dm_build_267 int, dm_build_268 byte) int { + return dm_build_266.Dm_build_301(dm_build_267, Dm_build_1346.Dm_build_1524(dm_build_268)) +} + +func (dm_build_270 *Dm_build_78) Dm_build_269(dm_build_271 int, dm_build_272 int16) int { + return dm_build_270.Dm_build_301(dm_build_271, Dm_build_1346.Dm_build_1530(dm_build_272)) +} + +func (dm_build_274 *Dm_build_78) Dm_build_273(dm_build_275 int, dm_build_276 int32) int { + return dm_build_274.Dm_build_301(dm_build_275, Dm_build_1346.Dm_build_1533(dm_build_276)) +} + +func (dm_build_278 *Dm_build_78) Dm_build_277(dm_build_279 int, dm_build_280 int64) int { + return dm_build_278.Dm_build_301(dm_build_279, Dm_build_1346.Dm_build_1536(dm_build_280)) +} + +func (dm_build_282 *Dm_build_78) Dm_build_281(dm_build_283 int, dm_build_284 float32) int { + return dm_build_282.Dm_build_301(dm_build_283, Dm_build_1346.Dm_build_1539(dm_build_284)) +} + +func (dm_build_286 *Dm_build_78) Dm_build_285(dm_build_287 int, dm_build_288 float64) int { + return dm_build_286.Dm_build_301(dm_build_287, Dm_build_1346.Dm_build_1542(dm_build_288)) +} + +func (dm_build_290 *Dm_build_78) Dm_build_289(dm_build_291 int, dm_build_292 uint8) int { + return dm_build_290.Dm_build_301(dm_build_291, Dm_build_1346.Dm_build_1545(dm_build_292)) +} + +func (dm_build_294 *Dm_build_78) Dm_build_293(dm_build_295 int, dm_build_296 uint16) int { + return dm_build_294.Dm_build_301(dm_build_295, Dm_build_1346.Dm_build_1548(dm_build_296)) +} + +func (dm_build_298 *Dm_build_78) Dm_build_297(dm_build_299 int, dm_build_300 uint32) int { + return dm_build_298.Dm_build_301(dm_build_299, Dm_build_1346.Dm_build_1551(dm_build_300)) +} + +func (dm_build_302 *Dm_build_78) Dm_build_301(dm_build_303 int, dm_build_304 []byte) int { + return copy(dm_build_302.dm_build_79[dm_build_303:], dm_build_304) +} + +func (dm_build_306 *Dm_build_78) Dm_build_305(dm_build_307 int, dm_build_308 []byte) int { + return dm_build_306.Dm_build_273(dm_build_307, int32(len(dm_build_308))) + dm_build_306.Dm_build_301(dm_build_307+4, dm_build_308) +} + +func (dm_build_310 *Dm_build_78) Dm_build_309(dm_build_311 int, dm_build_312 []byte) int { + return dm_build_310.Dm_build_265(dm_build_311, byte(len(dm_build_312))) + dm_build_310.Dm_build_301(dm_build_311+1, dm_build_312) +} + +func (dm_build_314 *Dm_build_78) Dm_build_313(dm_build_315 int, dm_build_316 []byte) int { + return dm_build_314.Dm_build_269(dm_build_315, int16(len(dm_build_316))) + dm_build_314.Dm_build_301(dm_build_315+2, dm_build_316) +} + +func (dm_build_318 *Dm_build_78) Dm_build_317(dm_build_319 int, dm_build_320 []byte) int { + return dm_build_318.Dm_build_301(dm_build_319, dm_build_320) + dm_build_318.Dm_build_265(dm_build_319+len(dm_build_320), 0) +} + +func (dm_build_322 *Dm_build_78) Dm_build_321(dm_build_323 int, dm_build_324 string, dm_build_325 string, dm_build_326 *DmConnection) int { + return dm_build_322.Dm_build_305(dm_build_323, Dm_build_1346.Dm_build_1562(dm_build_324, dm_build_325, dm_build_326)) +} + +func (dm_build_328 *Dm_build_78) Dm_build_327(dm_build_329 int, dm_build_330 string, dm_build_331 string, dm_build_332 *DmConnection) int { + return dm_build_328.Dm_build_309(dm_build_329, Dm_build_1346.Dm_build_1562(dm_build_330, dm_build_331, dm_build_332)) +} + +func (dm_build_334 *Dm_build_78) Dm_build_333(dm_build_335 int, dm_build_336 string, dm_build_337 string, dm_build_338 *DmConnection) int { + return dm_build_334.Dm_build_313(dm_build_335, Dm_build_1346.Dm_build_1562(dm_build_336, dm_build_337, dm_build_338)) +} + +func (dm_build_340 *Dm_build_78) Dm_build_339(dm_build_341 int, dm_build_342 string, dm_build_343 string, dm_build_344 *DmConnection) int { + return dm_build_340.Dm_build_317(dm_build_341, Dm_build_1346.Dm_build_1562(dm_build_342, dm_build_343, dm_build_344)) +} + +func (dm_build_346 *Dm_build_78) Dm_build_345(dm_build_347 int) byte { + return Dm_build_1346.Dm_build_1567(dm_build_346.Dm_build_372(dm_build_347, 1)) +} + +func (dm_build_349 *Dm_build_78) Dm_build_348(dm_build_350 int) int16 { + return Dm_build_1346.Dm_build_1570(dm_build_349.Dm_build_372(dm_build_350, 2)) +} + +func (dm_build_352 *Dm_build_78) Dm_build_351(dm_build_353 int) int32 { + return Dm_build_1346.Dm_build_1573(dm_build_352.Dm_build_372(dm_build_353, 4)) +} + +func (dm_build_355 *Dm_build_78) Dm_build_354(dm_build_356 int) int64 { + return Dm_build_1346.Dm_build_1576(dm_build_355.Dm_build_372(dm_build_356, 8)) +} + +func (dm_build_358 *Dm_build_78) Dm_build_357(dm_build_359 int) float32 { + return Dm_build_1346.Dm_build_1579(dm_build_358.Dm_build_372(dm_build_359, 4)) +} + +func (dm_build_361 *Dm_build_78) Dm_build_360(dm_build_362 int) float64 { + return Dm_build_1346.Dm_build_1582(dm_build_361.Dm_build_372(dm_build_362, 8)) +} + +func (dm_build_364 *Dm_build_78) Dm_build_363(dm_build_365 int) uint8 { + return Dm_build_1346.Dm_build_1585(dm_build_364.Dm_build_372(dm_build_365, 1)) +} + +func (dm_build_367 *Dm_build_78) Dm_build_366(dm_build_368 int) uint16 { + return Dm_build_1346.Dm_build_1588(dm_build_367.Dm_build_372(dm_build_368, 2)) +} + +func (dm_build_370 *Dm_build_78) Dm_build_369(dm_build_371 int) uint32 { + return Dm_build_1346.Dm_build_1591(dm_build_370.Dm_build_372(dm_build_371, 4)) +} + +func (dm_build_373 *Dm_build_78) Dm_build_372(dm_build_374 int, dm_build_375 int) []byte { + return dm_build_373.dm_build_79[dm_build_374 : dm_build_374+dm_build_375] +} + +func (dm_build_377 *Dm_build_78) Dm_build_376(dm_build_378 int) []byte { + dm_build_379 := dm_build_377.Dm_build_351(dm_build_378) + return dm_build_377.Dm_build_372(dm_build_378+4, int(dm_build_379)) +} + +func (dm_build_381 *Dm_build_78) Dm_build_380(dm_build_382 int) []byte { + dm_build_383 := dm_build_381.Dm_build_345(dm_build_382) + return dm_build_381.Dm_build_372(dm_build_382+1, int(dm_build_383)) +} + +func (dm_build_385 *Dm_build_78) Dm_build_384(dm_build_386 int) []byte { + dm_build_387 := dm_build_385.Dm_build_348(dm_build_386) + return dm_build_385.Dm_build_372(dm_build_386+2, int(dm_build_387)) +} + +func (dm_build_389 *Dm_build_78) Dm_build_388(dm_build_390 int) []byte { + dm_build_391 := 0 + for dm_build_389.Dm_build_345(dm_build_390) != 0 { + dm_build_390++ + dm_build_391++ + } + + return dm_build_389.Dm_build_372(dm_build_390-dm_build_391, int(dm_build_391)) +} + +func (dm_build_393 *Dm_build_78) Dm_build_392(dm_build_394 int, dm_build_395 string, dm_build_396 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_393.Dm_build_376(dm_build_394), dm_build_395, dm_build_396) +} + +func (dm_build_398 *Dm_build_78) Dm_build_397(dm_build_399 int, dm_build_400 string, dm_build_401 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_398.Dm_build_380(dm_build_399), dm_build_400, dm_build_401) +} + +func (dm_build_403 *Dm_build_78) Dm_build_402(dm_build_404 int, dm_build_405 string, dm_build_406 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_403.Dm_build_384(dm_build_404), dm_build_405, dm_build_406) +} + +func (dm_build_408 *Dm_build_78) Dm_build_407(dm_build_409 int, dm_build_410 string, dm_build_411 *DmConnection) string { + return Dm_build_1346.Dm_build_1598(dm_build_408.Dm_build_388(dm_build_409), dm_build_410, dm_build_411) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/d.go b/dpi_bridge/third_party/chunanyong_dm/d.go new file mode 100644 index 0000000..42fb82d --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/d.go @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "container/list" + "io" +) + +type Dm_build_0 struct { + dm_build_1 *list.List + dm_build_2 *dm_build_54 + dm_build_3 int +} + +func Dm_build_4() *Dm_build_0 { + return &Dm_build_0{ + dm_build_1: list.New(), + dm_build_3: 0, + } +} + +func (dm_build_6 *Dm_build_0) Dm_build_5() int { + return dm_build_6.dm_build_3 +} + +func (dm_build_8 *Dm_build_0) Dm_build_7(dm_build_9 *Dm_build_78, dm_build_10 int) int { + var dm_build_11 = 0 + var dm_build_12 = 0 + for dm_build_11 < dm_build_10 && dm_build_8.dm_build_2 != nil { + dm_build_12 = dm_build_8.dm_build_2.dm_build_62(dm_build_9, dm_build_10-dm_build_11) + if dm_build_8.dm_build_2.dm_build_57 == 0 { + dm_build_8.dm_build_44() + } + dm_build_11 += dm_build_12 + dm_build_8.dm_build_3 -= dm_build_12 + } + return dm_build_11 +} + +func (dm_build_14 *Dm_build_0) Dm_build_13(dm_build_15 []byte, dm_build_16 int, dm_build_17 int) int { + var dm_build_18 = 0 + var dm_build_19 = 0 + for dm_build_18 < dm_build_17 && dm_build_14.dm_build_2 != nil { + dm_build_19 = dm_build_14.dm_build_2.dm_build_66(dm_build_15, dm_build_16, dm_build_17-dm_build_18) + if dm_build_14.dm_build_2.dm_build_57 == 0 { + dm_build_14.dm_build_44() + } + dm_build_18 += dm_build_19 + dm_build_14.dm_build_3 -= dm_build_19 + dm_build_16 += dm_build_19 + } + return dm_build_18 +} + +func (dm_build_21 *Dm_build_0) Dm_build_20(dm_build_22 io.Writer, dm_build_23 int) int { + var dm_build_24 = 0 + var dm_build_25 = 0 + for dm_build_24 < dm_build_23 && dm_build_21.dm_build_2 != nil { + dm_build_25 = dm_build_21.dm_build_2.dm_build_71(dm_build_22, dm_build_23-dm_build_24) + if dm_build_21.dm_build_2.dm_build_57 == 0 { + dm_build_21.dm_build_44() + } + dm_build_24 += dm_build_25 + dm_build_21.dm_build_3 -= dm_build_25 + } + return dm_build_24 +} + +func (dm_build_27 *Dm_build_0) Dm_build_26(dm_build_28 []byte, dm_build_29 int, dm_build_30 int) { + if dm_build_30 == 0 { + return + } + var dm_build_31 = dm_build_58(dm_build_28, dm_build_29, dm_build_30) + if dm_build_27.dm_build_2 == nil { + dm_build_27.dm_build_2 = dm_build_31 + } else { + dm_build_27.dm_build_1.PushBack(dm_build_31) + } + dm_build_27.dm_build_3 += dm_build_30 +} + +func (dm_build_33 *Dm_build_0) dm_build_32(dm_build_34 int) byte { + var dm_build_35 = dm_build_34 + var dm_build_36 = dm_build_33.dm_build_2 + for dm_build_35 > 0 && dm_build_36 != nil { + if dm_build_36.dm_build_57 == 0 { + continue + } + if dm_build_35 > dm_build_36.dm_build_57-1 { + dm_build_35 -= dm_build_36.dm_build_57 + dm_build_36 = dm_build_33.dm_build_1.Front().Value.(*dm_build_54) + } else { + break + } + } + return dm_build_36.dm_build_75(dm_build_35) +} +func (dm_build_38 *Dm_build_0) Dm_build_37(dm_build_39 *Dm_build_0) { + if dm_build_39.dm_build_3 == 0 { + return + } + var dm_build_40 = dm_build_39.dm_build_2 + for dm_build_40 != nil { + dm_build_38.dm_build_41(dm_build_40) + dm_build_39.dm_build_44() + dm_build_40 = dm_build_39.dm_build_2 + } + dm_build_39.dm_build_3 = 0 +} +func (dm_build_42 *Dm_build_0) dm_build_41(dm_build_43 *dm_build_54) { + if dm_build_43.dm_build_57 == 0 { + return + } + if dm_build_42.dm_build_2 == nil { + dm_build_42.dm_build_2 = dm_build_43 + } else { + dm_build_42.dm_build_1.PushBack(dm_build_43) + } + dm_build_42.dm_build_3 += dm_build_43.dm_build_57 +} + +func (dm_build_45 *Dm_build_0) dm_build_44() { + var dm_build_46 = dm_build_45.dm_build_1.Front() + if dm_build_46 == nil { + dm_build_45.dm_build_2 = nil + } else { + dm_build_45.dm_build_2 = dm_build_46.Value.(*dm_build_54) + dm_build_45.dm_build_1.Remove(dm_build_46) + } +} + +func (dm_build_48 *Dm_build_0) Dm_build_47() []byte { + var dm_build_49 = make([]byte, dm_build_48.dm_build_3) + var dm_build_50 = dm_build_48.dm_build_2 + var dm_build_51 = 0 + var dm_build_52 = len(dm_build_49) + var dm_build_53 = 0 + for dm_build_50 != nil { + if dm_build_50.dm_build_57 > 0 { + if dm_build_52 > dm_build_50.dm_build_57 { + dm_build_53 = dm_build_50.dm_build_57 + } else { + dm_build_53 = dm_build_52 + } + copy(dm_build_49[dm_build_51:dm_build_51+dm_build_53], dm_build_50.dm_build_55[dm_build_50.dm_build_56:dm_build_50.dm_build_56+dm_build_53]) + dm_build_51 += dm_build_53 + dm_build_52 -= dm_build_53 + } + if dm_build_48.dm_build_1.Front() == nil { + dm_build_50 = nil + } else { + dm_build_50 = dm_build_48.dm_build_1.Front().Value.(*dm_build_54) + } + } + return dm_build_49 +} + +type dm_build_54 struct { + dm_build_55 []byte + dm_build_56 int + dm_build_57 int +} + +func dm_build_58(dm_build_59 []byte, dm_build_60 int, dm_build_61 int) *dm_build_54 { + return &dm_build_54{ + dm_build_59, + dm_build_60, + dm_build_61, + } +} + +func (dm_build_63 *dm_build_54) dm_build_62(dm_build_64 *Dm_build_78, dm_build_65 int) int { + if dm_build_63.dm_build_57 <= dm_build_65 { + dm_build_65 = dm_build_63.dm_build_57 + } + dm_build_64.Dm_build_161(dm_build_63.dm_build_55[dm_build_63.dm_build_56 : dm_build_63.dm_build_56+dm_build_65]) + dm_build_63.dm_build_56 += dm_build_65 + dm_build_63.dm_build_57 -= dm_build_65 + return dm_build_65 +} + +func (dm_build_67 *dm_build_54) dm_build_66(dm_build_68 []byte, dm_build_69 int, dm_build_70 int) int { + if dm_build_67.dm_build_57 <= dm_build_70 { + dm_build_70 = dm_build_67.dm_build_57 + } + copy(dm_build_68[dm_build_69:dm_build_69+dm_build_70], dm_build_67.dm_build_55[dm_build_67.dm_build_56:dm_build_67.dm_build_56+dm_build_70]) + dm_build_67.dm_build_56 += dm_build_70 + dm_build_67.dm_build_57 -= dm_build_70 + return dm_build_70 +} + +func (dm_build_72 *dm_build_54) dm_build_71(dm_build_73 io.Writer, dm_build_74 int) int { + if dm_build_72.dm_build_57 <= dm_build_74 { + dm_build_74 = dm_build_72.dm_build_57 + } + dm_build_73.Write(dm_build_72.dm_build_55[dm_build_72.dm_build_56 : dm_build_72.dm_build_56+dm_build_74]) + dm_build_72.dm_build_56 += dm_build_74 + dm_build_72.dm_build_57 -= dm_build_74 + return dm_build_74 +} +func (dm_build_76 *dm_build_54) dm_build_75(dm_build_77 int) byte { + return dm_build_76.dm_build_55[dm_build_76.dm_build_56+dm_build_77] +} diff --git a/dpi_bridge/third_party/chunanyong_dm/e.go b/dpi_bridge/third_party/chunanyong_dm/e.go new file mode 100644 index 0000000..45637f8 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/e.go @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/ianaindex" + "golang.org/x/text/transform" + "io" + "io/ioutil" + "math" +) + +type dm_build_1345 struct{} + +var Dm_build_1346 = &dm_build_1345{} + +func (Dm_build_1348 *dm_build_1345) Dm_build_1347(dm_build_1349 []byte, dm_build_1350 int, dm_build_1351 byte) int { + dm_build_1349[dm_build_1350] = dm_build_1351 + return 1 +} + +func (Dm_build_1353 *dm_build_1345) Dm_build_1352(dm_build_1354 []byte, dm_build_1355 int, dm_build_1356 int8) int { + dm_build_1354[dm_build_1355] = byte(dm_build_1356) + return 1 +} + +func (Dm_build_1358 *dm_build_1345) Dm_build_1357(dm_build_1359 []byte, dm_build_1360 int, dm_build_1361 int16) int { + dm_build_1359[dm_build_1360] = byte(dm_build_1361) + dm_build_1360++ + dm_build_1359[dm_build_1360] = byte(dm_build_1361 >> 8) + return 2 +} + +func (Dm_build_1363 *dm_build_1345) Dm_build_1362(dm_build_1364 []byte, dm_build_1365 int, dm_build_1366 int32) int { + dm_build_1364[dm_build_1365] = byte(dm_build_1366) + dm_build_1365++ + dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 8) + dm_build_1365++ + dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 16) + dm_build_1365++ + dm_build_1364[dm_build_1365] = byte(dm_build_1366 >> 24) + dm_build_1365++ + return 4 +} + +func (Dm_build_1368 *dm_build_1345) Dm_build_1367(dm_build_1369 []byte, dm_build_1370 int, dm_build_1371 int64) int { + dm_build_1369[dm_build_1370] = byte(dm_build_1371) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 8) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 16) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 24) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 32) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 40) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 48) + dm_build_1370++ + dm_build_1369[dm_build_1370] = byte(dm_build_1371 >> 56) + return 8 +} + +func (Dm_build_1373 *dm_build_1345) Dm_build_1372(dm_build_1374 []byte, dm_build_1375 int, dm_build_1376 float32) int { + return Dm_build_1373.Dm_build_1392(dm_build_1374, dm_build_1375, math.Float32bits(dm_build_1376)) +} + +func (Dm_build_1378 *dm_build_1345) Dm_build_1377(dm_build_1379 []byte, dm_build_1380 int, dm_build_1381 float64) int { + return Dm_build_1378.Dm_build_1397(dm_build_1379, dm_build_1380, math.Float64bits(dm_build_1381)) +} + +func (Dm_build_1383 *dm_build_1345) Dm_build_1382(dm_build_1384 []byte, dm_build_1385 int, dm_build_1386 uint8) int { + dm_build_1384[dm_build_1385] = byte(dm_build_1386) + return 1 +} + +func (Dm_build_1388 *dm_build_1345) Dm_build_1387(dm_build_1389 []byte, dm_build_1390 int, dm_build_1391 uint16) int { + dm_build_1389[dm_build_1390] = byte(dm_build_1391) + dm_build_1390++ + dm_build_1389[dm_build_1390] = byte(dm_build_1391 >> 8) + return 2 +} + +func (Dm_build_1393 *dm_build_1345) Dm_build_1392(dm_build_1394 []byte, dm_build_1395 int, dm_build_1396 uint32) int { + dm_build_1394[dm_build_1395] = byte(dm_build_1396) + dm_build_1395++ + dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 8) + dm_build_1395++ + dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 16) + dm_build_1395++ + dm_build_1394[dm_build_1395] = byte(dm_build_1396 >> 24) + return 3 +} + +func (Dm_build_1398 *dm_build_1345) Dm_build_1397(dm_build_1399 []byte, dm_build_1400 int, dm_build_1401 uint64) int { + dm_build_1399[dm_build_1400] = byte(dm_build_1401) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 8) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 16) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 24) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 32) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 40) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 48) + dm_build_1400++ + dm_build_1399[dm_build_1400] = byte(dm_build_1401 >> 56) + return 3 +} + +func (Dm_build_1403 *dm_build_1345) Dm_build_1402(dm_build_1404 []byte, dm_build_1405 int, dm_build_1406 []byte, dm_build_1407 int, dm_build_1408 int) int { + copy(dm_build_1404[dm_build_1405:dm_build_1405+dm_build_1408], dm_build_1406[dm_build_1407:dm_build_1407+dm_build_1408]) + return dm_build_1408 +} + +func (Dm_build_1410 *dm_build_1345) Dm_build_1409(dm_build_1411 []byte, dm_build_1412 int, dm_build_1413 []byte, dm_build_1414 int, dm_build_1415 int) int { + dm_build_1412 += Dm_build_1410.Dm_build_1392(dm_build_1411, dm_build_1412, uint32(dm_build_1415)) + return 4 + Dm_build_1410.Dm_build_1402(dm_build_1411, dm_build_1412, dm_build_1413, dm_build_1414, dm_build_1415) +} + +func (Dm_build_1417 *dm_build_1345) Dm_build_1416(dm_build_1418 []byte, dm_build_1419 int, dm_build_1420 []byte, dm_build_1421 int, dm_build_1422 int) int { + dm_build_1419 += Dm_build_1417.Dm_build_1387(dm_build_1418, dm_build_1419, uint16(dm_build_1422)) + return 2 + Dm_build_1417.Dm_build_1402(dm_build_1418, dm_build_1419, dm_build_1420, dm_build_1421, dm_build_1422) +} + +func (Dm_build_1424 *dm_build_1345) Dm_build_1423(dm_build_1425 []byte, dm_build_1426 int, dm_build_1427 string, dm_build_1428 string, dm_build_1429 *DmConnection) int { + dm_build_1430 := Dm_build_1424.Dm_build_1562(dm_build_1427, dm_build_1428, dm_build_1429) + dm_build_1426 += Dm_build_1424.Dm_build_1392(dm_build_1425, dm_build_1426, uint32(len(dm_build_1430))) + return 4 + Dm_build_1424.Dm_build_1402(dm_build_1425, dm_build_1426, dm_build_1430, 0, len(dm_build_1430)) +} + +func (Dm_build_1432 *dm_build_1345) Dm_build_1431(dm_build_1433 []byte, dm_build_1434 int, dm_build_1435 string, dm_build_1436 string, dm_build_1437 *DmConnection) int { + dm_build_1438 := Dm_build_1432.Dm_build_1562(dm_build_1435, dm_build_1436, dm_build_1437) + + dm_build_1434 += Dm_build_1432.Dm_build_1387(dm_build_1433, dm_build_1434, uint16(len(dm_build_1438))) + return 2 + Dm_build_1432.Dm_build_1402(dm_build_1433, dm_build_1434, dm_build_1438, 0, len(dm_build_1438)) +} + +func (Dm_build_1440 *dm_build_1345) Dm_build_1439(dm_build_1441 []byte, dm_build_1442 int) byte { + return dm_build_1441[dm_build_1442] +} + +func (Dm_build_1444 *dm_build_1345) Dm_build_1443(dm_build_1445 []byte, dm_build_1446 int) int16 { + var dm_build_1447 int16 + dm_build_1447 = int16(dm_build_1445[dm_build_1446] & 0xff) + dm_build_1446++ + dm_build_1447 |= int16(dm_build_1445[dm_build_1446]&0xff) << 8 + return dm_build_1447 +} + +func (Dm_build_1449 *dm_build_1345) Dm_build_1448(dm_build_1450 []byte, dm_build_1451 int) int32 { + var dm_build_1452 int32 + dm_build_1452 = int32(dm_build_1450[dm_build_1451] & 0xff) + dm_build_1451++ + dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 8 + dm_build_1451++ + dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 16 + dm_build_1451++ + dm_build_1452 |= int32(dm_build_1450[dm_build_1451]&0xff) << 24 + return dm_build_1452 +} + +func (Dm_build_1454 *dm_build_1345) Dm_build_1453(dm_build_1455 []byte, dm_build_1456 int) int64 { + var dm_build_1457 int64 + dm_build_1457 = int64(dm_build_1455[dm_build_1456] & 0xff) + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 8 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 16 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 24 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 32 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 40 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 48 + dm_build_1456++ + dm_build_1457 |= int64(dm_build_1455[dm_build_1456]&0xff) << 56 + return dm_build_1457 +} + +func (Dm_build_1459 *dm_build_1345) Dm_build_1458(dm_build_1460 []byte, dm_build_1461 int) float32 { + return math.Float32frombits(Dm_build_1459.Dm_build_1475(dm_build_1460, dm_build_1461)) +} + +func (Dm_build_1463 *dm_build_1345) Dm_build_1462(dm_build_1464 []byte, dm_build_1465 int) float64 { + return math.Float64frombits(Dm_build_1463.Dm_build_1480(dm_build_1464, dm_build_1465)) +} + +func (Dm_build_1467 *dm_build_1345) Dm_build_1466(dm_build_1468 []byte, dm_build_1469 int) uint8 { + return uint8(dm_build_1468[dm_build_1469] & 0xff) +} + +func (Dm_build_1471 *dm_build_1345) Dm_build_1470(dm_build_1472 []byte, dm_build_1473 int) uint16 { + var dm_build_1474 uint16 + dm_build_1474 = uint16(dm_build_1472[dm_build_1473] & 0xff) + dm_build_1473++ + dm_build_1474 |= uint16(dm_build_1472[dm_build_1473]&0xff) << 8 + return dm_build_1474 +} + +func (Dm_build_1476 *dm_build_1345) Dm_build_1475(dm_build_1477 []byte, dm_build_1478 int) uint32 { + var dm_build_1479 uint32 + dm_build_1479 = uint32(dm_build_1477[dm_build_1478] & 0xff) + dm_build_1478++ + dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 8 + dm_build_1478++ + dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 16 + dm_build_1478++ + dm_build_1479 |= uint32(dm_build_1477[dm_build_1478]&0xff) << 24 + return dm_build_1479 +} + +func (Dm_build_1481 *dm_build_1345) Dm_build_1480(dm_build_1482 []byte, dm_build_1483 int) uint64 { + var dm_build_1484 uint64 + dm_build_1484 = uint64(dm_build_1482[dm_build_1483] & 0xff) + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 8 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 16 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 24 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 32 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 40 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 48 + dm_build_1483++ + dm_build_1484 |= uint64(dm_build_1482[dm_build_1483]&0xff) << 56 + return dm_build_1484 +} + +func (Dm_build_1486 *dm_build_1345) Dm_build_1485(dm_build_1487 []byte, dm_build_1488 int) []byte { + dm_build_1489 := Dm_build_1486.Dm_build_1475(dm_build_1487, dm_build_1488) + + dm_build_1490 := make([]byte, dm_build_1489) + copy(dm_build_1490[:int(dm_build_1489)], dm_build_1487[dm_build_1488+4:dm_build_1488+4+int(dm_build_1489)]) + return dm_build_1490 +} + +func (Dm_build_1492 *dm_build_1345) Dm_build_1491(dm_build_1493 []byte, dm_build_1494 int) []byte { + dm_build_1495 := Dm_build_1492.Dm_build_1470(dm_build_1493, dm_build_1494) + + dm_build_1496 := make([]byte, dm_build_1495) + copy(dm_build_1496[:int(dm_build_1495)], dm_build_1493[dm_build_1494+2:dm_build_1494+2+int(dm_build_1495)]) + return dm_build_1496 +} + +func (Dm_build_1498 *dm_build_1345) Dm_build_1497(dm_build_1499 []byte, dm_build_1500 int, dm_build_1501 int) []byte { + + dm_build_1502 := make([]byte, dm_build_1501) + copy(dm_build_1502[:dm_build_1501], dm_build_1499[dm_build_1500:dm_build_1500+dm_build_1501]) + return dm_build_1502 +} + +func (Dm_build_1504 *dm_build_1345) Dm_build_1503(dm_build_1505 []byte, dm_build_1506 int, dm_build_1507 int, dm_build_1508 string, dm_build_1509 *DmConnection) string { + return Dm_build_1504.Dm_build_1598(dm_build_1505[dm_build_1506:dm_build_1506+dm_build_1507], dm_build_1508, dm_build_1509) +} + +func (Dm_build_1511 *dm_build_1345) Dm_build_1510(dm_build_1512 []byte, dm_build_1513 int, dm_build_1514 string, dm_build_1515 *DmConnection) string { + dm_build_1516 := Dm_build_1511.Dm_build_1475(dm_build_1512, dm_build_1513) + dm_build_1513 += 4 + return Dm_build_1511.Dm_build_1503(dm_build_1512, dm_build_1513, int(dm_build_1516), dm_build_1514, dm_build_1515) +} + +func (Dm_build_1518 *dm_build_1345) Dm_build_1517(dm_build_1519 []byte, dm_build_1520 int, dm_build_1521 string, dm_build_1522 *DmConnection) string { + dm_build_1523 := Dm_build_1518.Dm_build_1470(dm_build_1519, dm_build_1520) + dm_build_1520 += 2 + return Dm_build_1518.Dm_build_1503(dm_build_1519, dm_build_1520, int(dm_build_1523), dm_build_1521, dm_build_1522) +} + +func (Dm_build_1525 *dm_build_1345) Dm_build_1524(dm_build_1526 byte) []byte { + return []byte{dm_build_1526} +} + +func (Dm_build_1528 *dm_build_1345) Dm_build_1527(dm_build_1529 int8) []byte { + return []byte{byte(dm_build_1529)} +} + +func (Dm_build_1531 *dm_build_1345) Dm_build_1530(dm_build_1532 int16) []byte { + return []byte{byte(dm_build_1532), byte(dm_build_1532 >> 8)} +} + +func (Dm_build_1534 *dm_build_1345) Dm_build_1533(dm_build_1535 int32) []byte { + return []byte{byte(dm_build_1535), byte(dm_build_1535 >> 8), byte(dm_build_1535 >> 16), byte(dm_build_1535 >> 24)} +} + +func (Dm_build_1537 *dm_build_1345) Dm_build_1536(dm_build_1538 int64) []byte { + return []byte{byte(dm_build_1538), byte(dm_build_1538 >> 8), byte(dm_build_1538 >> 16), byte(dm_build_1538 >> 24), byte(dm_build_1538 >> 32), + byte(dm_build_1538 >> 40), byte(dm_build_1538 >> 48), byte(dm_build_1538 >> 56)} +} + +func (Dm_build_1540 *dm_build_1345) Dm_build_1539(dm_build_1541 float32) []byte { + return Dm_build_1540.Dm_build_1551(math.Float32bits(dm_build_1541)) +} + +func (Dm_build_1543 *dm_build_1345) Dm_build_1542(dm_build_1544 float64) []byte { + return Dm_build_1543.Dm_build_1554(math.Float64bits(dm_build_1544)) +} + +func (Dm_build_1546 *dm_build_1345) Dm_build_1545(dm_build_1547 uint8) []byte { + return []byte{byte(dm_build_1547)} +} + +func (Dm_build_1549 *dm_build_1345) Dm_build_1548(dm_build_1550 uint16) []byte { + return []byte{byte(dm_build_1550), byte(dm_build_1550 >> 8)} +} + +func (Dm_build_1552 *dm_build_1345) Dm_build_1551(dm_build_1553 uint32) []byte { + return []byte{byte(dm_build_1553), byte(dm_build_1553 >> 8), byte(dm_build_1553 >> 16), byte(dm_build_1553 >> 24)} +} + +func (Dm_build_1555 *dm_build_1345) Dm_build_1554(dm_build_1556 uint64) []byte { + return []byte{byte(dm_build_1556), byte(dm_build_1556 >> 8), byte(dm_build_1556 >> 16), byte(dm_build_1556 >> 24), byte(dm_build_1556 >> 32), byte(dm_build_1556 >> 40), byte(dm_build_1556 >> 48), byte(dm_build_1556 >> 56)} +} + +func (Dm_build_1558 *dm_build_1345) Dm_build_1557(dm_build_1559 []byte, dm_build_1560 string, dm_build_1561 *DmConnection) []byte { + if dm_build_1560 == "UTF-8" { + return dm_build_1559 + } + + if dm_build_1561 == nil { + if e := dm_build_1603(dm_build_1560); e != nil { + tmp, err := ioutil.ReadAll( + transform.NewReader(bytes.NewReader(dm_build_1559), e.NewEncoder()), + ) + if err != nil { + panic("UTF8 To Charset error!") + } + + return tmp + } + + panic("Unsupported Charset!") + } + + if dm_build_1561.encodeBuffer == nil { + dm_build_1561.encodeBuffer = bytes.NewBuffer(nil) + dm_build_1561.encode = dm_build_1603(dm_build_1561.getServerEncoding()) + dm_build_1561.transformReaderDst = make([]byte, 4096) + dm_build_1561.transformReaderSrc = make([]byte, 4096) + } + + if e := dm_build_1561.encode; e != nil { + + dm_build_1561.encodeBuffer.Reset() + + n, err := dm_build_1561.encodeBuffer.ReadFrom( + Dm_build_1617(bytes.NewReader(dm_build_1559), e.NewEncoder(), dm_build_1561.transformReaderDst, dm_build_1561.transformReaderSrc), + ) + if err != nil { + panic("UTF8 To Charset error!") + } + var tmp = make([]byte, n) + if _, err = dm_build_1561.encodeBuffer.Read(tmp); err != nil { + panic("UTF8 To Charset error!") + } + return tmp + } + + panic("Unsupported Charset!") +} + +func (Dm_build_1563 *dm_build_1345) Dm_build_1562(dm_build_1564 string, dm_build_1565 string, dm_build_1566 *DmConnection) []byte { + return Dm_build_1563.Dm_build_1557([]byte(dm_build_1564), dm_build_1565, dm_build_1566) +} + +func (Dm_build_1568 *dm_build_1345) Dm_build_1567(dm_build_1569 []byte) byte { + return Dm_build_1568.Dm_build_1439(dm_build_1569, 0) +} + +func (Dm_build_1571 *dm_build_1345) Dm_build_1570(dm_build_1572 []byte) int16 { + return Dm_build_1571.Dm_build_1443(dm_build_1572, 0) +} + +func (Dm_build_1574 *dm_build_1345) Dm_build_1573(dm_build_1575 []byte) int32 { + return Dm_build_1574.Dm_build_1448(dm_build_1575, 0) +} + +func (Dm_build_1577 *dm_build_1345) Dm_build_1576(dm_build_1578 []byte) int64 { + return Dm_build_1577.Dm_build_1453(dm_build_1578, 0) +} + +func (Dm_build_1580 *dm_build_1345) Dm_build_1579(dm_build_1581 []byte) float32 { + return Dm_build_1580.Dm_build_1458(dm_build_1581, 0) +} + +func (Dm_build_1583 *dm_build_1345) Dm_build_1582(dm_build_1584 []byte) float64 { + return Dm_build_1583.Dm_build_1462(dm_build_1584, 0) +} + +func (Dm_build_1586 *dm_build_1345) Dm_build_1585(dm_build_1587 []byte) uint8 { + return Dm_build_1586.Dm_build_1466(dm_build_1587, 0) +} + +func (Dm_build_1589 *dm_build_1345) Dm_build_1588(dm_build_1590 []byte) uint16 { + return Dm_build_1589.Dm_build_1470(dm_build_1590, 0) +} + +func (Dm_build_1592 *dm_build_1345) Dm_build_1591(dm_build_1593 []byte) uint32 { + return Dm_build_1592.Dm_build_1475(dm_build_1593, 0) +} + +func (Dm_build_1595 *dm_build_1345) Dm_build_1594(dm_build_1596 []byte, dm_build_1597 string) []byte { + if dm_build_1597 == "UTF-8" { + return dm_build_1596 + } + + if e := dm_build_1603(dm_build_1597); e != nil { + + tmp, err := ioutil.ReadAll( + transform.NewReader(bytes.NewReader(dm_build_1596), e.NewDecoder()), + ) + if err != nil { + + panic("Charset To UTF8 error!") + } + + return tmp + } + + panic("Unsupported Charset!") + +} + +func (Dm_build_1599 *dm_build_1345) Dm_build_1598(dm_build_1600 []byte, dm_build_1601 string, dm_build_1602 *DmConnection) string { + return string(Dm_build_1599.Dm_build_1594(dm_build_1600, dm_build_1601)) +} + +func dm_build_1603(dm_build_1604 string) encoding.Encoding { + if e, err := ianaindex.MIB.Encoding(dm_build_1604); err == nil && e != nil { + return e + } + return nil +} + +type Dm_build_1605 struct { + dm_build_1606 io.Reader + dm_build_1607 transform.Transformer + dm_build_1608 error + + dm_build_1609 []byte + dm_build_1610, dm_build_1611 int + + dm_build_1612 []byte + dm_build_1613, dm_build_1614 int + + dm_build_1615 bool +} + +const dm_build_1616 = 4096 + +func Dm_build_1617(dm_build_1618 io.Reader, dm_build_1619 transform.Transformer, dm_build_1620 []byte, dm_build_1621 []byte) *Dm_build_1605 { + dm_build_1619.Reset() + return &Dm_build_1605{ + dm_build_1606: dm_build_1618, + dm_build_1607: dm_build_1619, + dm_build_1609: dm_build_1620, + dm_build_1612: dm_build_1621, + } +} + +func (dm_build_1623 *Dm_build_1605) Read(dm_build_1624 []byte) (int, error) { + dm_build_1625, dm_build_1626 := 0, error(nil) + for { + + if dm_build_1623.dm_build_1610 != dm_build_1623.dm_build_1611 { + dm_build_1625 = copy(dm_build_1624, dm_build_1623.dm_build_1609[dm_build_1623.dm_build_1610:dm_build_1623.dm_build_1611]) + dm_build_1623.dm_build_1610 += dm_build_1625 + if dm_build_1623.dm_build_1610 == dm_build_1623.dm_build_1611 && dm_build_1623.dm_build_1615 { + return dm_build_1625, dm_build_1623.dm_build_1608 + } + return dm_build_1625, nil + } else if dm_build_1623.dm_build_1615 { + return 0, dm_build_1623.dm_build_1608 + } + + if dm_build_1623.dm_build_1613 != dm_build_1623.dm_build_1614 || dm_build_1623.dm_build_1608 != nil { + dm_build_1623.dm_build_1610 = 0 + dm_build_1623.dm_build_1611, dm_build_1625, dm_build_1626 = dm_build_1623.dm_build_1607.Transform(dm_build_1623.dm_build_1609, dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1613:dm_build_1623.dm_build_1614], dm_build_1623.dm_build_1608 == io.EOF) + dm_build_1623.dm_build_1613 += dm_build_1625 + + switch { + case dm_build_1626 == nil: + if dm_build_1623.dm_build_1613 != dm_build_1623.dm_build_1614 { + dm_build_1623.dm_build_1608 = nil + } + + dm_build_1623.dm_build_1615 = dm_build_1623.dm_build_1608 != nil + continue + case dm_build_1626 == transform.ErrShortDst && (dm_build_1623.dm_build_1611 != 0 || dm_build_1625 != 0): + + continue + case dm_build_1626 == transform.ErrShortSrc && dm_build_1623.dm_build_1614-dm_build_1623.dm_build_1613 != len(dm_build_1623.dm_build_1612) && dm_build_1623.dm_build_1608 == nil: + + default: + dm_build_1623.dm_build_1615 = true + + if dm_build_1623.dm_build_1608 == nil || dm_build_1623.dm_build_1608 == io.EOF { + dm_build_1623.dm_build_1608 = dm_build_1626 + } + continue + } + } + + if dm_build_1623.dm_build_1613 != 0 { + dm_build_1623.dm_build_1613, dm_build_1623.dm_build_1614 = 0, copy(dm_build_1623.dm_build_1612, dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1613:dm_build_1623.dm_build_1614]) + } + dm_build_1625, dm_build_1623.dm_build_1608 = dm_build_1623.dm_build_1606.Read(dm_build_1623.dm_build_1612[dm_build_1623.dm_build_1614:]) + dm_build_1623.dm_build_1614 += dm_build_1625 + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/f.go b/dpi_bridge/third_party/chunanyong_dm/f.go new file mode 100644 index 0000000..8d10799 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/f.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "compress/zlib" + "github.com/golang/snappy" +) + +func Compress(srcBuffer *Dm_build_78, offset int, length int, compressID int) ([]byte, error) { + if compressID == Dm_build_786 { + return snappy.Encode(nil, srcBuffer.Dm_build_372(offset, length)), nil + } + return GzlibCompress(srcBuffer, offset, length) +} + +func UnCompress(srcBytes []byte, compressID int) ([]byte, error) { + if compressID == Dm_build_786 { + return snappy.Decode(nil, srcBytes) + } + return GzlibUncompress(srcBytes) +} + +func GzlibCompress(srcBuffer *Dm_build_78, offset int, length int) ([]byte, error) { + var ret bytes.Buffer + var w = zlib.NewWriter(&ret) + w.Write(srcBuffer.Dm_build_372(offset, length)) + w.Close() + return ret.Bytes(), nil +} + +func GzlibUncompress(srcBytes []byte) ([]byte, error) { + var bytesBuf = new(bytes.Buffer) + r, err := zlib.NewReader(bytes.NewReader(srcBytes)) + if err != nil { + return nil, err + } + defer r.Close() + _, err = bytesBuf.ReadFrom(r) + if err != nil { + return nil, err + } + return bytesBuf.Bytes(), nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/g.go b/dpi_bridge/third_party/chunanyong_dm/g.go new file mode 100644 index 0000000..e87704c --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/g.go @@ -0,0 +1,2158 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "fmt" + "math" + "os" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "gitee.com/chunanyong/dm/util" +) + +type ExecuteTypeEnum int + +const ( + Execute ExecuteTypeEnum = iota + ExecuteQuery + ExecuteUpdate +) + +var idGenerator int64 = 0 + +func generateId() string { + return time.Now().String() + strconv.Itoa(int(atomic.AddInt64(&idGenerator, 1))) +} + +func getInt64(counter *int64, reset bool) int64 { + if reset { + return atomic.SwapInt64(counter, 0) + } + return atomic.LoadInt64(counter) +} + +type SqlStatValue struct { + id string + + sql string + + sqlHash int64 + + dataSource string + + dataSourceId string + + executeLastStartTime int64 + + executeBatchSizeTotal int64 + + executeBatchSizeMax int64 + + executeSuccessCount int64 + + executeSpanNanoTotal int64 + + executeSpanNanoMax int64 + + runningCount int64 + + concurrentMax int64 + + resultSetHoldTimeNano int64 + + executeAndResultSetHoldTime int64 + + executeNanoSpanMaxOccurTime int64 + + executeErrorCount int64 + + executeErrorLast error + + executeErrorLastMessage string + + executeErrorLastStackTrace string + + executeErrorLastTime int64 + + updateCount int64 + + updateCountMax int64 + + fetchRowCount int64 + + fetchRowCountMax int64 + + inTransactionCount int64 + + lastSlowParameters string + + clobOpenCount int64 + + blobOpenCount int64 + + readStringLength int64 + + readBytesLength int64 + + inputStreamOpenCount int64 + + readerOpenCount int64 + + histogram_0_1 int64 + + histogram_1_10 int64 + + histogram_10_100 int64 + + histogram_100_1000 int64 + + histogram_1000_10000 int64 + + histogram_10000_100000 int64 + + histogram_100000_1000000 int64 + + histogram_1000000_more int64 + + executeAndResultHoldTime_0_1 int64 + + executeAndResultHoldTime_1_10 int64 + + executeAndResultHoldTime_10_100 int64 + + executeAndResultHoldTime_100_1000 int64 + + executeAndResultHoldTime_1000_10000 int64 + + executeAndResultHoldTime_10000_100000 int64 + + executeAndResultHoldTime_100000_1000000 int64 + + executeAndResultHoldTime_1000000_more int64 + + fetchRowCount_0_1 int64 + + fetchRowCount_1_10 int64 + + fetchRowCount_10_100 int64 + + fetchRowCount_100_1000 int64 + + fetchRowCount_1000_10000 int64 + + fetchRowCount_10000_more int64 + + updateCount_0_1 int64 + + updateCount_1_10 int64 + + updateCount_10_100 int64 + + updateCount_100_1000 int64 + + updateCount_1000_10000 int64 + + updateCount_10000_more int64 +} + +func newSqlStatValue() *SqlStatValue { + ssv := new(SqlStatValue) + return ssv +} + +func (ssv *SqlStatValue) getExecuteHistogram() []int64 { + return []int64{ + ssv.histogram_0_1, + ssv.histogram_1_10, + ssv.histogram_10_100, + ssv.histogram_100_1000, + ssv.histogram_1000_10000, + ssv.histogram_10000_100000, + ssv.histogram_100000_1000000, + ssv.histogram_1000000_more, + } +} + +func (ssv *SqlStatValue) getExecuteAndResultHoldHistogram() []int64 { + return []int64{ssv.executeAndResultHoldTime_0_1, + ssv.executeAndResultHoldTime_1_10, + ssv.executeAndResultHoldTime_10_100, + ssv.executeAndResultHoldTime_100_1000, + ssv.executeAndResultHoldTime_1000_10000, + ssv.executeAndResultHoldTime_10000_100000, + ssv.executeAndResultHoldTime_100000_1000000, + ssv.executeAndResultHoldTime_1000000_more, + } +} + +func (ssv *SqlStatValue) getFetchRowHistogram() []int64 { + return []int64{ssv.fetchRowCount_0_1, + ssv.fetchRowCount_1_10, + ssv.fetchRowCount_10_100, + ssv.fetchRowCount_100_1000, + ssv.fetchRowCount_1000_10000, + ssv.fetchRowCount_10000_more, + } +} + +func (ssv *SqlStatValue) getUpdateHistogram() []int64 { + return []int64{ssv.updateCount_0_1, + ssv.updateCount_1_10, + ssv.updateCount_10_100, + ssv.updateCount_100_1000, + ssv.updateCount_1000_10000, + ssv.updateCount_10000_more, + } +} + +func (ssv *SqlStatValue) getExecuteCount() int64 { + return ssv.executeErrorCount + ssv.executeSuccessCount +} + +func (ssv *SqlStatValue) getExecuteMillisMax() int64 { + return ssv.executeSpanNanoMax / (1000 * 1000) +} + +func (ssv *SqlStatValue) getExecuteMillisTotal() int64 { + return ssv.executeSpanNanoTotal / (1000 * 1000) +} + +func (ssv *SqlStatValue) getHistogramValues() []int64 { + return []int64{ + + ssv.histogram_0_1, + ssv.histogram_1_10, + ssv.histogram_10_100, + ssv.histogram_100_1000, + ssv.histogram_1000_10000, + ssv.histogram_10000_100000, + ssv.histogram_100000_1000000, + ssv.histogram_1000000_more, + } +} + +func (ssv *SqlStatValue) getFetchRowCountHistogramValues() []int64 { + return []int64{ + + ssv.fetchRowCount_0_1, + ssv.fetchRowCount_1_10, + ssv.fetchRowCount_10_100, + ssv.fetchRowCount_100_1000, + ssv.fetchRowCount_1000_10000, + ssv.fetchRowCount_10000_more, + } +} + +func (ssv *SqlStatValue) getUpdateCountHistogramValues() []int64 { + return []int64{ + + ssv.updateCount_0_1, + ssv.updateCount_1_10, + ssv.updateCount_10_100, + ssv.updateCount_100_1000, + ssv.updateCount_1000_10000, + ssv.updateCount_10000_more, + } +} + +func (ssv *SqlStatValue) getExecuteAndResultHoldTimeHistogramValues() []int64 { + return []int64{ + + ssv.executeAndResultHoldTime_0_1, + ssv.executeAndResultHoldTime_1_10, + ssv.executeAndResultHoldTime_10_100, + ssv.executeAndResultHoldTime_100_1000, + ssv.executeAndResultHoldTime_1000_10000, + ssv.executeAndResultHoldTime_10000_100000, + ssv.executeAndResultHoldTime_100000_1000000, + ssv.executeAndResultHoldTime_1000000_more, + } +} + +func (ssv *SqlStatValue) getResultSetHoldTimeMilis() int64 { + return ssv.resultSetHoldTimeNano / (1000 * 1000) +} + +func (ssv *SqlStatValue) getExecuteAndResultSetHoldTimeMilis() int64 { + return ssv.executeAndResultSetHoldTime / (1000 * 1000) +} + +func (ssv *SqlStatValue) getData() map[string]interface{} { + m := make(map[string]interface{}) + + m[idConstStr] = ssv.id + m[dataSourceConstStr] = ssv.dataSource + m["DataSourceId"] = ssv.dataSourceId + m[sqlConstStr] = ssv.sql + m[executeCountConstStr] = ssv.getExecuteCount() + m[errorCountConstStr] = ssv.executeErrorCount + + m[totalTimeConstStr] = ssv.getExecuteMillisTotal() + m["LastTime"] = ssv.executeLastStartTime + m[maxTimespanConstStr] = ssv.getExecuteMillisMax() + m["LastError"] = ssv.executeErrorLast + m[effectedRowCountConstStr] = ssv.updateCount + + m[fetchRowCountConstStr] = ssv.fetchRowCount + m["MaxTimespanOccurTime"] = ssv.executeNanoSpanMaxOccurTime + m["BatchSizeMax"] = ssv.executeBatchSizeMax + m["BatchSizeTotal"] = ssv.executeBatchSizeTotal + m[concurrentMaxConstStr] = ssv.concurrentMax + + m[runningCountConstStr] = ssv.runningCount + + if ssv.executeErrorLastMessage != "" { + m["LastErrorMessage"] = ssv.executeErrorLastMessage + m["LastErrorStackTrace"] = ssv.executeErrorLastStackTrace + m["LastErrorTime"] = ssv.executeErrorLastTime + } else { + m["LastErrorMessage"] = "" + m["LastErrorClass"] = "" + m["LastErrorStackTrace"] = "" + m["LastErrorTime"] = "" + } + + m[urlConstStr] = "" + m[inTransactionCountConstStr] = ssv.inTransactionCount + + m["Histogram"] = ssv.getHistogramValues() + m["LastSlowParameters"] = ssv.lastSlowParameters + m["ResultSetHoldTime"] = ssv.getResultSetHoldTimeMilis() + m["ExecuteAndResultSetHoldTime"] = ssv.getExecuteAndResultSetHoldTimeMilis() + m[fetchRowCountConstStr] = ssv.getFetchRowCountHistogramValues() + + m[effectedRowCountHistogramConstStr] = ssv.getUpdateCountHistogramValues() + m[executeAndResultHoldTimeHistogramConstStr] = ssv.getExecuteAndResultHoldTimeHistogramValues() + m["EffectedRowCountMax"] = ssv.updateCountMax + m["FetchRowCountMax"] = ssv.fetchRowCountMax + m[clobOpenCountConstStr] = ssv.clobOpenCount + + m[blobOpenCountConstStr] = ssv.blobOpenCount + m["ReadStringLength"] = ssv.readStringLength + m["ReadBytesLength"] = ssv.readBytesLength + m["InputStreamOpenCount"] = ssv.inputStreamOpenCount + m["ReaderOpenCount"] = ssv.readerOpenCount + + m["HASH"] = ssv.sqlHash + + m[executeHoldTimeHistogramConstStr] = ssv.getExecuteHistogram() + + return m +} + +type sqlStat struct { + Sql string + + SqlHash int64 + + Id string + + ExecuteLastStartTime int64 + + ExecuteBatchSizeTotal int64 + + ExecuteBatchSizeMax int64 + + ExecuteSuccessCount int64 + + ExecuteSpanNanoTotal int64 + + ExecuteSpanNanoMax int64 + + RunningCount int64 + + ConcurrentMax int64 + + ResultSetHoldTimeNano int64 + + ExecuteAndResultSetHoldTime int64 + + DataSource string + + File string + + ExecuteNanoSpanMaxOccurTime int64 + + ExecuteErrorCount int64 + + ExecuteErrorLast error + + ExecuteErrorLastTime int64 + + UpdateCount int64 + + UpdateCountMax int64 + + FetchRowCount int64 + + FetchRowCountMax int64 + + InTransactionCount int64 + + LastSlowParameters string + + Removed int64 + + ClobOpenCount int64 + + BlobOpenCount int64 + + ReadStringLength int64 + + ReadBytesLength int64 + + InputStreamOpenCount int64 + + ReaderOpenCount int64 + + Histogram_0_1 int64 + + Histogram_1_10 int64 + + Histogram_10_100 int64 + + Histogram_100_1000 int64 + + Histogram_1000_10000 int64 + + Histogram_10000_100000 int64 + + Histogram_100000_1000000 int64 + + Histogram_1000000_more int64 + + ExecuteAndResultHoldTime_0_1 int64 + + ExecuteAndResultHoldTime_1_10 int64 + + ExecuteAndResultHoldTime_10_100 int64 + + ExecuteAndResultHoldTime_100_1000 int64 + + ExecuteAndResultHoldTime_1000_10000 int64 + + ExecuteAndResultHoldTime_10000_100000 int64 + + ExecuteAndResultHoldTime_100000_1000000 int64 + + ExecuteAndResultHoldTime_1000000_more int64 + + FetchRowCount_0_1 int64 + + FetchRowCount_1_10 int64 + + FetchRowCount_10_100 int64 + + FetchRowCount_100_1000 int64 + + FetchRowCount_1000_10000 int64 + + FetchRowCount_10000_more int64 + + UpdateCount_0_1 int64 + + UpdateCount_1_10 int64 + + UpdateCount_10_100 int64 + + UpdateCount_100_1000 int64 + + UpdateCount_1000_10000 int64 + + UpdateCount_10000_more int64 + + DataSourceId string +} + +func NewSqlStat(sql string) *sqlStat { + s := new(sqlStat) + s.Sql = sql + s.Id = "SQL" + generateId() + return s +} + +func (s *sqlStat) reset() { + s.ExecuteLastStartTime = 0 + + s.ExecuteBatchSizeTotal = 0 + s.ExecuteBatchSizeMax = 0 + + s.ExecuteSuccessCount = 0 + s.ExecuteSpanNanoTotal = 0 + s.ExecuteSpanNanoMax = 0 + s.ExecuteNanoSpanMaxOccurTime = 0 + s.ConcurrentMax = 0 + + s.ExecuteErrorCount = 0 + s.ExecuteErrorLast = nil + s.ExecuteErrorLastTime = 0 + + s.UpdateCount = 0 + s.UpdateCountMax = 0 + s.FetchRowCount = 0 + s.FetchRowCountMax = 0 + + s.Histogram_0_1 = 0 + s.Histogram_1_10 = 0 + s.Histogram_10_100 = 0 + s.Histogram_100_1000 = 0 + s.Histogram_1000_10000 = 0 + s.Histogram_10000_100000 = 0 + s.Histogram_100000_1000000 = 0 + s.Histogram_1000000_more = 0 + + s.LastSlowParameters = "" + s.InTransactionCount = 0 + s.ResultSetHoldTimeNano = 0 + s.ExecuteAndResultSetHoldTime = 0 + + s.FetchRowCount_0_1 = 0 + s.FetchRowCount_1_10 = 0 + s.FetchRowCount_10_100 = 0 + s.FetchRowCount_100_1000 = 0 + s.FetchRowCount_1000_10000 = 0 + s.FetchRowCount_10000_more = 0 + + s.UpdateCount_0_1 = 0 + s.UpdateCount_1_10 = 0 + s.UpdateCount_10_100 = 0 + s.UpdateCount_100_1000 = 0 + s.UpdateCount_1000_10000 = 0 + s.UpdateCount_10000_more = 0 + + s.ExecuteAndResultHoldTime_0_1 = 0 + s.ExecuteAndResultHoldTime_1_10 = 0 + s.ExecuteAndResultHoldTime_10_100 = 0 + s.ExecuteAndResultHoldTime_100_1000 = 0 + s.ExecuteAndResultHoldTime_1000_10000 = 0 + s.ExecuteAndResultHoldTime_10000_100000 = 0 + s.ExecuteAndResultHoldTime_100000_1000000 = 0 + s.ExecuteAndResultHoldTime_1000000_more = 0 + + s.BlobOpenCount = 0 + s.ClobOpenCount = 0 + s.ReadStringLength = 0 + s.ReadBytesLength = 0 + s.InputStreamOpenCount = 0 + s.ReaderOpenCount = 0 +} + +func (s *sqlStat) getValueAndReset() *SqlStatValue { + return s.getValue(true) +} + +func (s *sqlStat) getValue(reset bool) *SqlStatValue { + ssv := newSqlStatValue() + ssv.dataSource = s.DataSource + ssv.dataSourceId = s.DataSourceId + ssv.sql = s.Sql + ssv.sqlHash = s.SqlHash + ssv.id = s.Id + ssv.executeLastStartTime = s.ExecuteLastStartTime + if reset { + s.ExecuteLastStartTime = 0 + } + + ssv.executeBatchSizeTotal = getInt64(&s.ExecuteBatchSizeTotal, reset) + ssv.executeBatchSizeMax = getInt64(&s.ExecuteBatchSizeMax, reset) + ssv.executeSuccessCount = getInt64(&s.ExecuteSuccessCount, reset) + ssv.executeSpanNanoTotal = getInt64(&s.ExecuteSpanNanoTotal, reset) + ssv.executeSpanNanoMax = getInt64(&s.ExecuteSpanNanoMax, reset) + ssv.executeNanoSpanMaxOccurTime = s.ExecuteNanoSpanMaxOccurTime + if reset { + s.ExecuteNanoSpanMaxOccurTime = 0 + } + + ssv.runningCount = s.RunningCount + ssv.concurrentMax = getInt64(&s.ConcurrentMax, reset) + ssv.executeErrorCount = getInt64(&s.ExecuteErrorCount, reset) + ssv.executeErrorLast = s.ExecuteErrorLast + if reset { + s.ExecuteErrorLast = nil + } + + ssv.executeErrorLastTime = s.ExecuteErrorLastTime + if reset { + ssv.executeErrorLastTime = 0 + } + + ssv.updateCount = getInt64(&s.UpdateCount, reset) + ssv.updateCountMax = getInt64(&s.UpdateCountMax, reset) + ssv.fetchRowCount = getInt64(&s.FetchRowCount, reset) + ssv.fetchRowCountMax = getInt64(&s.FetchRowCountMax, reset) + ssv.histogram_0_1 = getInt64(&s.Histogram_0_1, reset) + ssv.histogram_1_10 = getInt64(&s.Histogram_1_10, reset) + ssv.histogram_10_100 = getInt64(&s.Histogram_10_100, reset) + ssv.histogram_100_1000 = getInt64(&s.Histogram_100_1000, reset) + ssv.histogram_1000_10000 = getInt64(&s.Histogram_1000_10000, reset) + ssv.histogram_10000_100000 = getInt64(&s.Histogram_10000_100000, reset) + ssv.histogram_100000_1000000 = getInt64(&s.Histogram_100000_1000000, reset) + ssv.histogram_1000000_more = getInt64(&s.Histogram_1000000_more, reset) + ssv.lastSlowParameters = s.LastSlowParameters + if reset { + s.LastSlowParameters = "" + } + + ssv.inTransactionCount = getInt64(&s.InTransactionCount, reset) + ssv.resultSetHoldTimeNano = getInt64(&s.ResultSetHoldTimeNano, reset) + ssv.executeAndResultSetHoldTime = getInt64(&s.ExecuteAndResultSetHoldTime, reset) + ssv.fetchRowCount_0_1 = getInt64(&s.FetchRowCount_0_1, reset) + ssv.fetchRowCount_1_10 = getInt64(&s.FetchRowCount_1_10, reset) + ssv.fetchRowCount_10_100 = getInt64(&s.FetchRowCount_10_100, reset) + ssv.fetchRowCount_100_1000 = getInt64(&s.FetchRowCount_100_1000, reset) + ssv.fetchRowCount_1000_10000 = getInt64(&s.FetchRowCount_1000_10000, reset) + ssv.fetchRowCount_10000_more = getInt64(&s.FetchRowCount_10000_more, reset) + ssv.updateCount_0_1 = getInt64(&s.UpdateCount_0_1, reset) + ssv.updateCount_1_10 = getInt64(&s.UpdateCount_1_10, reset) + ssv.updateCount_10_100 = getInt64(&s.UpdateCount_10_100, reset) + ssv.updateCount_100_1000 = getInt64(&s.UpdateCount_100_1000, reset) + ssv.updateCount_1000_10000 = getInt64(&s.UpdateCount_1000_10000, reset) + ssv.updateCount_10000_more = getInt64(&s.UpdateCount_10000_more, reset) + ssv.executeAndResultHoldTime_0_1 = getInt64(&s.ExecuteAndResultHoldTime_0_1, reset) + ssv.executeAndResultHoldTime_1_10 = getInt64(&s.ExecuteAndResultHoldTime_1_10, reset) + ssv.executeAndResultHoldTime_10_100 = getInt64(&s.ExecuteAndResultHoldTime_10_100, reset) + ssv.executeAndResultHoldTime_100_1000 = getInt64(&s.ExecuteAndResultHoldTime_100_1000, reset) + ssv.executeAndResultHoldTime_1000_10000 = getInt64(&s.ExecuteAndResultHoldTime_1000_10000, reset) + ssv.executeAndResultHoldTime_10000_100000 = getInt64(&s.ExecuteAndResultHoldTime_10000_100000, reset) + ssv.executeAndResultHoldTime_100000_1000000 = getInt64(&s.ExecuteAndResultHoldTime_100000_1000000, reset) + ssv.executeAndResultHoldTime_1000000_more = getInt64(&s.ExecuteAndResultHoldTime_1000000_more, reset) + ssv.blobOpenCount = getInt64(&s.BlobOpenCount, reset) + ssv.clobOpenCount = getInt64(&s.ClobOpenCount, reset) + ssv.readStringLength = getInt64(&s.ReadStringLength, reset) + ssv.readBytesLength = getInt64(&s.ReadBytesLength, reset) + ssv.inputStreamOpenCount = getInt64(&s.InputStreamOpenCount, reset) + ssv.readerOpenCount = getInt64(&s.ReaderOpenCount, reset) + return ssv +} + +func (s *sqlStat) addUpdateCount(delta int64) { + if delta > 0 { + atomic.AddInt64(&s.UpdateCount, delta) + } + + for { + max := atomic.LoadInt64(&s.UpdateCountMax) + if delta <= max { + break + } + if atomic.CompareAndSwapInt64(&s.UpdateCountMax, max, delta) { + break + } + } + + if delta < 1 { + atomic.AddInt64(&s.UpdateCount_0_1, 1) + } else if delta < 10 { + atomic.AddInt64(&s.UpdateCount_1_10, 1) + } else if delta < 100 { + atomic.AddInt64(&s.UpdateCount_10_100, 1) + } else if delta < 1000 { + atomic.AddInt64(&s.UpdateCount_100_1000, 1) + } else if delta < 10000 { + atomic.AddInt64(&s.UpdateCount_1000_10000, 1) + } else { + atomic.AddInt64(&s.UpdateCount_10000_more, 1) + } +} + +func (s *sqlStat) incrementClobOpenCount() { + atomic.AddInt64(&s.ClobOpenCount, 1) +} + +func (s *sqlStat) incrementBlobOpenCount() { + atomic.AddInt64(&s.BlobOpenCount, 1) +} + +func (s *sqlStat) addStringReadLength(length int64) { + atomic.AddInt64(&s.ReadStringLength, length) +} + +func (s *sqlStat) addReadBytesLength(length int64) { + atomic.AddInt64(&s.ReadBytesLength, length) +} + +func (s *sqlStat) addReaderOpenCount(count int64) { + atomic.AddInt64(&s.ReaderOpenCount, count) +} + +func (s *sqlStat) addInputStreamOpenCount(count int64) { + atomic.AddInt64(&s.InputStreamOpenCount, count) +} + +func (s *sqlStat) addFetchRowCount(delta int64) { + atomic.AddInt64(&s.FetchRowCount, delta) + for { + max := atomic.LoadInt64(&s.FetchRowCountMax) + if delta <= max { + break + } + if atomic.CompareAndSwapInt64(&s.FetchRowCountMax, max, delta) { + break + } + } + + if delta < 1 { + atomic.AddInt64(&s.FetchRowCount_0_1, 1) + } else if delta < 10 { + atomic.AddInt64(&s.FetchRowCount_1_10, 1) + } else if delta < 100 { + atomic.AddInt64(&s.FetchRowCount_10_100, 1) + } else if delta < 1000 { + atomic.AddInt64(&s.FetchRowCount_100_1000, 1) + } else if delta < 10000 { + atomic.AddInt64(&s.FetchRowCount_1000_10000, 1) + } else { + atomic.AddInt64(&s.FetchRowCount_10000_more, 1) + } + +} + +func (s *sqlStat) addExecuteBatchCount(batchSize int64) { + atomic.AddInt64(&s.ExecuteBatchSizeTotal, batchSize) + + for { + current := atomic.LoadInt64(&s.ExecuteBatchSizeMax) + if current < batchSize { + if atomic.CompareAndSwapInt64(&s.ExecuteBatchSizeMax, current, batchSize) { + break + } else { + continue + } + } else { + break + } + } +} + +func (s *sqlStat) incrementExecuteSuccessCount() { + atomic.AddInt64(&s.ExecuteSuccessCount, 1) +} + +func (s *sqlStat) incrementRunningCount() { + val := atomic.AddInt64(&s.RunningCount, 1) + + for { + max := atomic.LoadInt64(&s.ConcurrentMax) + if val > max { + if atomic.CompareAndSwapInt64(&s.ConcurrentMax, max, val) { + break + } else { + continue + } + } else { + break + } + } +} + +func (s *sqlStat) decrementRunningCount() { + atomic.AddInt64(&s.RunningCount, -1) +} + +func (s *sqlStat) addExecuteTimeAndResultHoldTimeHistogramRecord(executeType ExecuteTypeEnum, firstResultSet bool, nanoSpan int64, parameters string) { + s.addExecuteTime(nanoSpan, parameters) + + if ExecuteQuery != executeType && !firstResultSet { + s.executeAndResultHoldTimeHistogramRecord(nanoSpan) + } +} + +func (s *sqlStat) executeAndResultHoldTimeHistogramRecord(nanoSpan int64) { + millis := nanoSpan / 1000 / 1000 + + if millis < 1 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_0_1, 1) + } else if millis < 10 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1_10, 1) + } else if millis < 100 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_10_100, 1) + } else if millis < 1000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_100_1000, 1) + } else if millis < 10000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1000_10000, 1) + } else if millis < 100000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_10000_100000, 1) + } else if millis < 1000000 { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_100000_1000000, 1) + } else { + atomic.AddInt64(&s.ExecuteAndResultHoldTime_1000000_more, 1) + } +} + +func (s *sqlStat) histogramRecord(nanoSpan int64) { + millis := nanoSpan / 1000 / 1000 + + if millis < 1 { + atomic.AddInt64(&s.Histogram_0_1, 1) + } else if millis < 10 { + atomic.AddInt64(&s.Histogram_1_10, 1) + } else if millis < 100 { + atomic.AddInt64(&s.Histogram_10_100, 1) + } else if millis < 1000 { + atomic.AddInt64(&s.Histogram_100_1000, 1) + } else if millis < 10000 { + atomic.AddInt64(&s.Histogram_1000_10000, 1) + } else if millis < 100000 { + atomic.AddInt64(&s.Histogram_10000_100000, 1) + } else if millis < 1000000 { + atomic.AddInt64(&s.Histogram_100000_1000000, 1) + } else { + atomic.AddInt64(&s.Histogram_1000000_more, 1) + } +} + +func (s *sqlStat) addExecuteTime(nanoSpan int64, parameters string) { + atomic.AddInt64(&s.ExecuteSpanNanoTotal, nanoSpan) + + for { + current := atomic.LoadInt64(&s.ExecuteSpanNanoMax) + if current < nanoSpan { + if atomic.CompareAndSwapInt64(&s.ExecuteSpanNanoMax, current, nanoSpan) { + + s.ExecuteNanoSpanMaxOccurTime = time.Now().UnixNano() + s.LastSlowParameters = parameters + + break + } else { + continue + } + } else { + break + } + } + + s.histogramRecord(nanoSpan) +} + +func (s *sqlStat) getExecuteMillisTotal() int64 { + return s.ExecuteSpanNanoTotal / (1000 * 1000) +} + +func (s *sqlStat) getExecuteMillisMax() int64 { + return s.ExecuteSpanNanoMax / (1000 * 1000) +} + +func (s *sqlStat) incrementInTransactionCount() { + atomic.AddInt64(&s.InTransactionCount, 1) +} + +func (s *sqlStat) getExecuteCount() int64 { + return s.ExecuteErrorCount + s.ExecuteSuccessCount +} + +func (s *sqlStat) getData() map[string]interface{} { + return s.getValue(false).getData() +} + +func (s *sqlStat) getHistogramValues() []int64 { + return []int64{ + + s.Histogram_0_1, + s.Histogram_1_10, + s.Histogram_10_100, + s.Histogram_100_1000, + s.Histogram_1000_10000, + s.Histogram_10000_100000, + s.Histogram_100000_1000000, + s.Histogram_1000000_more, + } +} + +func (s *sqlStat) getHistogramSum() int64 { + values := s.getHistogramValues() + var sum int64 = 0 + for i := 0; i < len(values); i++ { + sum += values[i] + } + return sum +} + +func (s *sqlStat) error(err error) { + atomic.AddInt64(&s.ExecuteErrorCount, 1) + s.ExecuteErrorLastTime = time.Now().UnixNano() + s.ExecuteErrorLast = err +} + +func (s *sqlStat) getResultSetHoldTimeMilis() int64 { + return s.ResultSetHoldTimeNano / (1000 * 1000) +} + +func (s *sqlStat) getExecuteAndResultSetHoldTimeMilis() int64 { + return s.ExecuteAndResultSetHoldTime / (1000 * 1000) +} + +func (s *sqlStat) getFetchRowCountHistogramValues() []int64 { + return []int64{ + + s.FetchRowCount_0_1, + s.FetchRowCount_1_10, + s.FetchRowCount_10_100, + s.FetchRowCount_100_1000, + s.FetchRowCount_1000_10000, + s.FetchRowCount_10000_more, + } +} + +func (s *sqlStat) getUpdateCountHistogramValues() []int64 { + return []int64{ + + s.UpdateCount_0_1, + s.UpdateCount_1_10, + s.UpdateCount_10_100, + s.UpdateCount_100_1000, + s.UpdateCount_1000_10000, + s.UpdateCount_10000_more, + } +} + +func (s *sqlStat) getExecuteAndResultHoldTimeHistogramValues() []int64 { + return []int64{ + + s.ExecuteAndResultHoldTime_0_1, + s.ExecuteAndResultHoldTime_1_10, + s.ExecuteAndResultHoldTime_10_100, + s.ExecuteAndResultHoldTime_100_1000, + s.ExecuteAndResultHoldTime_1000_10000, + s.ExecuteAndResultHoldTime_10000_100000, + s.ExecuteAndResultHoldTime_100000_1000000, + s.ExecuteAndResultHoldTime_1000000_more, + } +} + +func (s *sqlStat) getExecuteAndResultHoldTimeHistogramSum() int64 { + values := s.getExecuteAndResultHoldTimeHistogramValues() + var sum int64 = 0 + for i := 0; i < len(values); i++ { + sum += values[i] + } + return sum +} + +func (s *sqlStat) addResultSetHoldTimeNano(nano int64) { + atomic.AddInt64(&s.ResultSetHoldTimeNano, nano) +} + +func (s *sqlStat) addResultSetHoldTimeNano2(statementExecuteNano int64, resultHoldTimeNano int64) { + atomic.AddInt64(&s.ResultSetHoldTimeNano, resultHoldTimeNano) + atomic.AddInt64(&s.ExecuteAndResultSetHoldTime, statementExecuteNano+resultHoldTimeNano) + s.executeAndResultHoldTimeHistogramRecord((statementExecuteNano + resultHoldTimeNano) / 1000 / 1000) + atomic.AddInt64(&s.UpdateCount_0_1, 1) +} + +type connectionStatValue struct { + id string + + url string + + connCount int64 + + activeConnCount int64 + + maxActiveConnCount int64 + + executeCount int64 + + errorCount int64 + + stmtCount int64 + + activeStmtCount int64 + + maxActiveStmtCount int64 + + commitCount int64 + + rollbackCount int64 + + clobOpenCount int64 + + blobOpenCount int64 + + properties string +} + +func newConnectionStatValue() *connectionStatValue { + csv := new(connectionStatValue) + return csv +} + +func (csv *connectionStatValue) getData() map[string]interface{} { + m := make(map[string]interface{}) + m[idConstStr] = csv.id + m[urlConstStr] = csv.url + m[connCountConstStr] = csv.connCount + m[activeConnCountConstStr] = csv.activeConnCount + m[maxActiveConnCountConstStr] = csv.maxActiveConnCount + + m[stmtCountConstStr] = csv.stmtCount + m[activeStmtCountConstStr] = csv.activeStmtCount + m[maxActiveStmtCountConstStr] = csv.maxActiveStmtCount + + m[executeCountConstStr] = csv.executeCount + m[errorCountConstStr] = csv.errorCount + m[commitCountConstStr] = csv.commitCount + m[rollbackCountConstStr] = csv.rollbackCount + + m[clobOpenCountConstStr] = csv.clobOpenCount + m[blobOpenCountConstStr] = csv.blobOpenCount + + m[propertiesConstStr] = csv.properties + return m +} + +type connectionStat struct { + id string + + url string + + connCount int64 + + activeConnCount int64 + + maxActiveConnCount int64 + + executeCount int64 + + errorCount int64 + + stmtCount int64 + + activeStmtCount int64 + + maxActiveStmtCount int64 + + commitCount int64 + + rollbackCount int64 + + clobOpenCount int64 + + blobOpenCount int64 + + sqlStatMap map[string]*sqlStat + + maxSqlSize int + + skipSqlCount int64 + + lock sync.RWMutex + + properties string +} + +func newConnectionStat(url string) *connectionStat { + cs := new(connectionStat) + cs.maxSqlSize = StatSqlMaxCount + cs.id = "DS" + generateId() + cs.url = url + cs.sqlStatMap = make(map[string]*sqlStat, 200) + return cs +} + +func (cs *connectionStat) createSqlStat(sql string) *sqlStat { + cs.lock.Lock() + defer cs.lock.Unlock() + sqlStat, ok := cs.sqlStatMap[sql] + if !ok { + sqlStat := NewSqlStat(sql) + sqlStat.DataSource = cs.url + sqlStat.DataSourceId = cs.id + if cs.putSqlStat(sqlStat) { + return sqlStat + } else { + return nil + } + } + + return sqlStat + +} + +func (cs *connectionStat) putSqlStat(sqlStat *sqlStat) bool { + if cs.maxSqlSize > 0 && len(cs.sqlStatMap) == cs.maxSqlSize { + if StatSqlRemoveMode == STAT_SQL_REMOVE_OLDEST { + removeSqlStat := cs.eliminateSqlStat() + if removeSqlStat.RunningCount > 0 || removeSqlStat.getExecuteCount() > 0 { + atomic.AddInt64(&cs.skipSqlCount, 1) + } + cs.sqlStatMap[sqlStat.Sql] = sqlStat + return true + } else { + if sqlStat.RunningCount > 0 || sqlStat.getExecuteCount() > 0 { + atomic.AddInt64(&cs.skipSqlCount, 1) + } + return false + } + } else { + cs.sqlStatMap[sqlStat.Sql] = sqlStat + return true + } +} + +func (cs *connectionStat) eliminateSqlStat() *sqlStat { + if cs.maxSqlSize > 0 && len(cs.sqlStatMap) == cs.maxSqlSize { + if StatSqlRemoveMode == STAT_SQL_REMOVE_OLDEST { + for s, item := range cs.sqlStatMap { + if item != nil { + delete(cs.sqlStatMap, s) + return item + } + } + } + } + return nil +} + +func (cs *connectionStat) getSqlStatMap() map[string]*sqlStat { + m := make(map[string]*sqlStat, len(cs.sqlStatMap)) + cs.lock.Lock() + defer cs.lock.Unlock() + for s, item := range cs.sqlStatMap { + m[s] = item + } + return m +} + +func (cs *connectionStat) getSqlStatMapAndReset() []*SqlStatValue { + stats := make([]*sqlStat, 0, len(cs.sqlStatMap)) + cs.lock.Lock() + defer cs.lock.Unlock() + + for s, stat := range cs.sqlStatMap { + + if stat.getExecuteCount() == 0 && stat.RunningCount == 0 { + stat.Removed = 1 + delete(cs.sqlStatMap, s) + } else { + stats = append(stats, stat) + } + } + + values := make([]*SqlStatValue, 0, len(stats)) + for _, stat := range stats { + value := stat.getValueAndReset() + if value.getExecuteCount() == 0 && value.runningCount == 0 { + continue + } + values = append(values, value) + } + return values +} + +func (cs *connectionStat) incrementConn() { + atomic.AddInt64(&cs.connCount, 1) + atomic.AddInt64(&cs.activeConnCount, 1) + count := atomic.LoadInt64(&cs.activeConnCount) + if count > atomic.LoadInt64(&cs.maxActiveConnCount) { + atomic.StoreInt64(&cs.maxActiveConnCount, count) + } +} + +func (cs *connectionStat) decrementConn() { + atomic.AddInt64(&cs.activeConnCount, -1) +} + +func (cs *connectionStat) incrementStmt() { + atomic.AddInt64(&cs.stmtCount, 1) + atomic.AddInt64(&cs.activeStmtCount, 1) + count := atomic.LoadInt64(&cs.activeStmtCount) + if count > atomic.LoadInt64(&cs.maxActiveStmtCount) { + atomic.StoreInt64(&cs.maxActiveStmtCount, count) + } +} + +func (cs *connectionStat) decrementStmt() { + atomic.AddInt64(&cs.activeStmtCount, -1) +} + +func (cs *connectionStat) decrementStmtByActiveStmtCount(activeStmtCount int64) { + atomic.AddInt64(&cs.activeStmtCount, -activeStmtCount) +} + +func (cs *connectionStat) incrementExecuteCount() { + atomic.AddInt64(&cs.executeCount, 1) +} + +func (cs *connectionStat) incrementErrorCount() { + atomic.AddInt64(&cs.errorCount, 1) +} + +func (cs *connectionStat) incrementCommitCount() { + atomic.AddInt64(&cs.commitCount, 1) +} + +func (cs *connectionStat) incrementRollbackCount() { + atomic.AddInt64(&cs.rollbackCount, 1) +} + +func (cs *connectionStat) getValue(reset bool) *connectionStatValue { + val := newConnectionStatValue() + val.id = cs.id + val.url = cs.url + + val.connCount = getInt64(&cs.connCount, reset) + val.activeConnCount = getInt64(&cs.activeConnCount, false) + val.maxActiveConnCount = getInt64(&cs.maxActiveConnCount, false) + + val.stmtCount = getInt64(&cs.stmtCount, reset) + val.activeStmtCount = getInt64(&cs.activeStmtCount, false) + val.maxActiveStmtCount = getInt64(&cs.maxActiveStmtCount, false) + + val.commitCount = getInt64(&cs.commitCount, reset) + val.rollbackCount = getInt64(&cs.rollbackCount, reset) + val.executeCount = getInt64(&cs.executeCount, reset) + val.errorCount = getInt64(&cs.errorCount, reset) + + val.blobOpenCount = getInt64(&cs.blobOpenCount, reset) + val.clobOpenCount = getInt64(&cs.clobOpenCount, reset) + + val.properties = cs.properties + return val +} + +func (cs *connectionStat) getData() map[string]interface{} { + return cs.getValue(false).getData() +} + +func (cs *connectionStat) getValueAndReset() *connectionStatValue { + return cs.getValue(true) +} + +type GoStat struct { + connStatMap map[string]*connectionStat + + lock sync.RWMutex + + maxConnSize int + + skipConnCount int64 +} + +func newGoStat(maxConnSize int) *GoStat { + gs := new(GoStat) + if maxConnSize > 0 { + gs.maxConnSize = maxConnSize + } else { + gs.maxConnSize = 1000 + } + + gs.connStatMap = make(map[string]*connectionStat, 16) + return gs +} + +func (gs *GoStat) createConnStat(conn *DmConnection) *connectionStat { + url := conn.dmConnector.host + ":" + strconv.Itoa(int(conn.dmConnector.port)) + gs.lock.Lock() + defer gs.lock.Unlock() + connstat, ok := gs.connStatMap[url] + if !ok { + connstat = newConnectionStat(url) + + remove := len(gs.connStatMap) > gs.maxConnSize + if remove && connstat.activeConnCount > 0 { + atomic.AddInt64(&gs.skipConnCount, 1) + } + + gs.connStatMap[url] = connstat + } + + return connstat +} + +func (gs *GoStat) getConnStatMap() map[string]*connectionStat { + m := make(map[string]*connectionStat, len(gs.connStatMap)) + gs.lock.Lock() + defer gs.lock.Unlock() + + for s, stat := range gs.connStatMap { + m[s] = stat + } + return m +} + +var sqlRowField = []string{rowNumConstStr, dataSourceConstStr, sqlConstStr, executeCountConstStr, + totalTimeConstStr, maxTimespanConstStr, inTransactionCountConstStr, errorCountConstStr, effectedRowCountConstStr, + fetchRowCountConstStr, runningCountConstStr, concurrentMaxConstStr, executeHoldTimeHistogramConstStr, + executeAndResultHoldTimeHistogramConstStr, fetchRowCountHistogramConstStr, effectedRowCountHistogramConstStr} + +var sqlColField = []string{"ID", "DataSource", "SQL", "ExecuteCount", + "ErrorCount", "TotalTime", "LastTime", "MaxTimespan", "LastError", "EffectedRowCount", + "FetchRowCount", "MaxTimespanOccurTime", "BatchSizeMax", "BatchSizeTotal", "ConcurrentMax", + "RunningCount", "Name", "File", "LastErrorMessage", "LastErrorClass", "LastErrorStackTrace", + "LastErrorTime", "DbType", "URL", "InTransactionCount", "Histogram", "LastSlowParameters", + "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram", + "EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram", "EffectedRowCountMax", + "FetchRowCountMax", "ClobOpenCount"} + +const ( + rowNumConstStr = "rowNum" + idConstStr = "ID" + urlConstStr = "Url" + connCountConstStr = "ConnCount" + activeConnCountConstStr = "ActiveConnCount" + maxActiveConnCountConstStr = "MaxActiveConnCount" + stmtCountConstStr = "StmtCount" + activeStmtCountConstStr = "ActiveStmtCount" + maxActiveStmtCountConstStr = "MaxActiveStmtCount" + executeCountConstStr = "ExecuteCount" + errorCountConstStr = "ErrorCount" + commitCountConstStr = "CommitCount" + rollbackCountConstStr = "RollbackCount" + clobOpenCountConstStr = "ClobOpenCount" + blobOpenCountConstStr = "BlobOpenCount" + propertiesConstStr = "Properties" + dataSourceConstStr = "DataSource" + sqlConstStr = "SQL" + totalTimeConstStr = "TotalTime" + maxTimespanConstStr = "MaxTimespan" + inTransactionCountConstStr = "InTransactionCount" + effectedRowCountConstStr = "EffectedRowCount" + fetchRowCountConstStr = "FetchRowCount" + runningCountConstStr = "RunningCount" + concurrentMaxConstStr = "ConcurrentMax" + executeHoldTimeHistogramConstStr = "ExecuteHoldTimeHistogram" + executeAndResultHoldTimeHistogramConstStr = "ExecuteAndResultHoldTimeHistogram" + fetchRowCountHistogramConstStr = "FetchRowCountHistogram" + effectedRowCountHistogramConstStr = "EffectedRowCountHistogram" +) + +var dsRowField = []string{rowNumConstStr, urlConstStr, activeConnCountConstStr, + maxActiveConnCountConstStr, activeStmtCountConstStr, maxActiveStmtCountConstStr, executeCountConstStr, errorCountConstStr, + commitCountConstStr, rollbackCountConstStr} + +var dsColField = []string{"ID", "ConnCount", "ActiveConnCount", + "MaxActiveConnCount", "StmtCount", "ActiveStmtCount", "MaxActiveStmtCount", "ExecuteCount", + "ErrorCount", "CommitCount", "RollbackCount", "ClobOpenCount", "BlobOpenCount"} + +const ( + PROP_NAME_SORT = "sort" + PROP_NAME_SORT_FIELD = "field" + PROP_NAME_SORT_TYPE = "direction" + PROP_NAME_SEARCH = "search" + PROP_NAME_PAGE_NUM = "pageNum" + PROP_NAME_PAGE_SIZE = "pageSize" + PROP_NAME_PAGE_COUNT = "pageCount" + PROP_NAME_TOTAL_ROW_COUNT = "totalRowCount" + PROP_NAME_FLUSH_FREQ = "flushFreq" + PROP_NAME_DATASOURCE_ID = "dataSourceId" + PROP_NAME_SQL_ID = "sqlId" + + URL_SQL = "sql" + URL_SQL_DETAIL = "sqlDetail" + URL_DATASOURCE = "dataSource" + URL_DATASOURCE_DETAIL = "dataSourceDetail" + + RESULT_CODE_SUCCESS = 1 + RESULT_CODE_ERROR = -1 + DEFAULT_PAGE_NUM = 1 + DEFAULT_PAGE_SIZE = int(INT32_MAX) + DEFAULT_ORDER_TYPE = "asc" + DEFAULT_ORDERBY = "DataSourceId" +) + +type StatReader struct { + connStat []map[string]interface{} + + connStatColLens []int + + highFreqSqlStat []map[string]interface{} + + highFreqSqlStatColLens []int + + slowSqlStat []map[string]interface{} + + slowSqlStatColLens []int +} + +func newStatReader() *StatReader { + sr := new(StatReader) + return sr +} + +func (sr *StatReader) readConnStat(retList []string, maxCount int) (bool, []string) { + fields := dsRowField + isAppend := false + if sr.connStat == nil { + sr.connStat = sr.getConnStat("", fields) + sr.connStatColLens = calcColLens(sr.connStat, fields, COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.connStat) > maxCount { + retContent = sr.connStat[0:maxCount] + sr.connStat = sr.connStat[maxCount:len(sr.connStat)] + } else { + retContent = sr.connStat + sr.connStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, fields, sr.connStatColLens, isAppend)) + return sr.connStat != nil, retList +} + +func (sr *StatReader) readHighFreqSqlStat(retList []string, maxCount int) (bool, []string) { + isAppend := false + if sr.highFreqSqlStat == nil { + sr.highFreqSqlStat = sr.getHighFreqSqlStat(StatHighFreqSqlCount, -1, sqlRowField) + sr.highFreqSqlStatColLens = calcColLens(sr.highFreqSqlStat, sqlRowField, COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.highFreqSqlStat) > maxCount { + retContent = sr.highFreqSqlStat[0:maxCount] + sr.highFreqSqlStat = sr.highFreqSqlStat[maxCount:len(sr.highFreqSqlStat)] + } else { + retContent = sr.highFreqSqlStat + sr.highFreqSqlStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, sqlRowField, sr.highFreqSqlStatColLens, isAppend)) + return sr.highFreqSqlStat != nil, retList +} + +func (sr *StatReader) getHighFreqSqlStat(topCount int, sqlId int, + fields []string) []map[string]interface{} { + var content []map[string]interface{} + + if topCount != 0 { + parameters := NewProperties() + parameters.Set(PROP_NAME_SORT_FIELD, "ExecuteCount") + parameters.Set(PROP_NAME_SORT_TYPE, "desc") + parameters.Set(PROP_NAME_PAGE_NUM, "1") + parameters.Set(PROP_NAME_PAGE_SIZE, strconv.Itoa(topCount)) + content = sr.service(URL_SQL, parameters) + if sqlId != -1 { + matchedContent := make([]map[string]interface{}, 0) + for _, sqlStat := range content { + idStr := sqlStat["ID"] + if idStr == sqlId { + matchedContent = append(matchedContent, sqlStat) + break + } + } + content = matchedContent + } + } + + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m[rowNumConstStr] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) readSlowSqlStat(retList []string, maxCount int) (bool, []string) { + isAppend := false + if sr.slowSqlStat == nil { + sr.slowSqlStat = sr.getSlowSqlStat(StatSlowSqlCount, -1, sqlRowField) + sr.slowSqlStatColLens = calcColLens(sr.slowSqlStat, sqlRowField, + COL_MAX_LEN) + isAppend = false + } else { + isAppend = true + } + var retContent []map[string]interface{} + if maxCount > 0 && len(sr.slowSqlStat) > maxCount { + retContent = sr.slowSqlStat[0:maxCount] + sr.slowSqlStat = sr.slowSqlStat[maxCount:len(sr.slowSqlStat)] + } else { + retContent = sr.slowSqlStat + sr.slowSqlStat = nil + } + retList = append(retList, sr.getFormattedOutput(retContent, sqlRowField, sr.slowSqlStatColLens, isAppend)) + return sr.slowSqlStat != nil, retList +} + +func (sr *StatReader) getSlowSqlStat(topCount int, sqlId int, fields []string) []map[string]interface{} { + var content []map[string]interface{} + + if topCount != 0 { + parameters := NewProperties() + parameters.Set(PROP_NAME_SORT_FIELD, "MaxTimespan") + parameters.Set(PROP_NAME_SORT_TYPE, "desc") + parameters.Set(PROP_NAME_PAGE_NUM, "1") + parameters.Set(PROP_NAME_PAGE_SIZE, strconv.Itoa(topCount)) + + content = sr.service(URL_SQL, parameters) + if sqlId != -1 { + matchedContent := make([]map[string]interface{}, 0) + for _, sqlStat := range content { + idStr := sqlStat["ID"] + if idStr == sqlId { + matchedContent = append(matchedContent, sqlStat) + break + } + } + content = matchedContent + } + } + + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m["rowNum"] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) getConnStat(connId string, fields []string) []map[string]interface{} { + content := sr.service(URL_DATASOURCE, nil) + if connId != "" { + matchedContent := make([]map[string]interface{}, 0) + for _, dsStat := range content { + idStr := dsStat["Identity"] + if connId == idStr { + matchedContent = append(matchedContent, dsStat) + break + } + } + content = matchedContent + } + if content == nil { + content = make([]map[string]interface{}, 0) + } else { + i := 1 + for _, m := range content { + m["rowNum"] = i + i++ + } + } + content = addTitles(content, fields) + return content +} + +func (sr *StatReader) getFormattedOutput(content []map[string]interface{}, fields []string, colLens []int, + isAppend bool) string { + return toTable(content, fields, colLens, true, isAppend) +} + +func (sr *StatReader) parseUrl(url string) *Properties { + parameters := NewProperties() + + if url == "" || len(strings.TrimSpace(url)) == 0 { + return parameters + } + + parametersStr := util.StringUtil.SubstringBetween(url, "?", "") + if parametersStr == "" || len(parametersStr) == 0 { + return parameters + } + + parametersArray := strings.Split(parametersStr, "&") + + for _, parameterStr := range parametersArray { + index := strings.Index(parametersStr, "=") + if index <= 0 { + continue + } + + name := parameterStr[0:index] + value := parameterStr[index+1:] + parameters.Set(name, value) + } + return parameters +} + +func (sr *StatReader) service(url string, params *Properties) []map[string]interface{} { + if params != nil { + params.SetProperties(sr.parseUrl(url)) + } else { + params = sr.parseUrl(url) + } + + if strings.Index(url, URL_SQL) == 0 { + array := sr.getSqlStatList(params) + array = sr.comparatorOrderBy(array, params) + params.Set(PROP_NAME_FLUSH_FREQ, strconv.Itoa(StatFlushFreq)) + return array + } else if strings.Index(url, URL_SQL_DETAIL) == 0 { + array := sr.getSqlStatDetailList(params) + return array + } else if strings.Index(url, URL_DATASOURCE) == 0 { + array := sr.getConnStatList(params) + array = sr.comparatorOrderBy(array, params) + params.Set(PROP_NAME_FLUSH_FREQ, strconv.Itoa(StatFlushFreq)) + return array + } else if strings.Index(url, URL_DATASOURCE_DETAIL) == 0 { + array := sr.getConnStatDetailList(params) + return array + } else { + return nil + } +} + +func (sr *StatReader) getSqlStatList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + var sqlStatMap map[string]*sqlStat + for _, connStat := range connStatMap { + sqlStatMap = connStat.getSqlStatMap() + for _, sqlStat := range sqlStatMap { + data := sqlStat.getData() + executeCount := data[executeCountConstStr] + runningCount := data[runningCountConstStr] + if executeCount == 0 && runningCount == 0 { + continue + } + + array = append(array, data) + } + } + + return array +} + +func (sr *StatReader) getSqlStatDetailList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + var data *sqlStat + sqlId := "" + dsId := "" + if v := params.GetString(PROP_NAME_SQL_ID, ""); v != "" { + sqlId = v + } + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + dsId = v + } + if sqlId != "" && dsId != "" { + for _, connStat := range connStatMap { + if dsId != connStat.id { + continue + } else { + sqlStatMap := connStat.getSqlStatMap() + for _, sqlStat := range sqlStatMap { + + if sqlId == sqlStat.Id { + data = sqlStat + break + } + } + } + break + } + } + if data != nil { + + array = append(array, data.getData()) + + } + return array +} + +func (sr *StatReader) getConnStatList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + connStatMap := goStat.getConnStatMap() + id := "" + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + id = v + } + for _, connStat := range connStatMap { + data := connStat.getData() + + connCount := data["ConnCount"] + + if connCount == 0 { + continue + } + + if id != "" { + if id == connStat.id { + array = append(array, data) + break + } else { + continue + } + } else { + + array = append(array, data) + } + + } + return array +} + +func (sr *StatReader) getConnStatDetailList(params *Properties) []map[string]interface{} { + array := make([]map[string]interface{}, 0) + var data *connectionStat + connStatMap := goStat.getConnStatMap() + id := "" + if v := params.GetString(PROP_NAME_DATASOURCE_ID, ""); v != "" { + id = v + } + if id != "" { + for _, connStat := range connStatMap { + if id == connStat.id { + data = connStat + break + } + } + } + if data != nil { + dataValue := data.getValue(false) + m := make(map[string]interface{}, 2) + m["name"] = "数据源" + m["value"] = dataValue.url + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "总会话数" + m["value"] = dataValue.connCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动会话数" + m["value"] = dataValue.activeConnCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动会话数峰值" + m["value"] = dataValue.maxActiveStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "总句柄数" + m["value"] = dataValue.stmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动句柄数" + m["value"] = dataValue.activeStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "活动句柄数峰值" + m["value"] = dataValue.maxActiveStmtCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "执行次数" + m["value"] = dataValue.executeCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "执行出错次数" + m["value"] = dataValue.errorCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "提交次数" + m["value"] = dataValue.commitCount + array = append(array, m) + + m = make(map[string]interface{}, 2) + m["name"] = "回滚次数" + m["value"] = dataValue.rollbackCount + array = append(array, m) + + } + return array +} + +type mapSlice struct { + m []map[string]interface{} + isDesc bool + orderByKey string +} + +func newMapSlice(m []map[string]interface{}, isDesc bool, orderByKey string) *mapSlice { + ms := new(mapSlice) + ms.m = m + ms.isDesc = isDesc + ms.orderByKey = orderByKey + return ms +} + +func (ms mapSlice) Len() int { return len(ms.m) } + +func (ms mapSlice) Less(i, j int) bool { + m1 := ms.m[i] + m2 := ms.m[j] + v1 := m1[ms.orderByKey] + v2 := m2[ms.orderByKey] + if v1 == nil { + return true + } else if v2 == nil { + return false + } + + switch v1.(type) { + case int64: + return v1.(int64) < v2.(int64) + case float64: + return v1.(float64) < v2.(float64) + default: + return true + } +} + +func (ms mapSlice) Swap(i, j int) { + ms.m[i], ms.m[j] = ms.m[j], ms.m[i] +} + +func (sr *StatReader) comparatorOrderBy(array []map[string]interface{}, params *Properties) []map[string]interface{} { + if array == nil { + array = make([]map[string]interface{}, 0) + } + + orderBy := DEFAULT_ORDERBY + orderType := DEFAULT_ORDER_TYPE + pageNum := DEFAULT_PAGE_NUM + pageSize := DEFAULT_PAGE_SIZE + if params != nil { + if v := params.GetTrimString(PROP_NAME_SORT_FIELD, ""); v != "" { + orderBy = v + } + + if v := params.GetTrimString(PROP_NAME_SORT_TYPE, ""); v != "" { + orderType = v + } + + if v := params.GetTrimString(PROP_NAME_PAGE_NUM, ""); v != "" { + var err error + pageNum, err = strconv.Atoi(v) + if err != nil { + pageNum = DEFAULT_PAGE_NUM + } + } + if v := params.GetTrimString(PROP_NAME_PAGE_SIZE, ""); v != "" { + var err error + pageSize, err = strconv.Atoi(v) + if err != nil { + pageSize = DEFAULT_PAGE_SIZE + } + } + } + + rowCount := len(array) + pageCount := int(math.Ceil(float64(rowCount * 1.0 / pageSize))) + if pageCount < 1 { + pageCount = 1 + } + + if pageNum > pageCount { + pageNum = pageCount + } + + if len(array) > 0 { + + if orderBy != "" { + sort.Sort(newMapSlice(array, !(DEFAULT_ORDER_TYPE == orderType), orderBy)) + } + + fromIndex := (pageNum - 1) * pageSize + + toIndex := pageNum * pageSize + if toIndex > rowCount { + toIndex = rowCount + } + array = array[fromIndex:toIndex] + } + sr.resetPageInfo(params, rowCount, pageCount, pageNum) + return array +} + +func (sr *StatReader) resetPageInfo(params *Properties, rowCount int, pageCount int, pageNum int) { + + if params != nil { + v := params.GetString(PROP_NAME_PAGE_SIZE, "") + if v != "" { + + params.Set(PROP_NAME_PAGE_COUNT, strconv.Itoa(pageCount)) + params.Set(PROP_NAME_TOTAL_ROW_COUNT, strconv.Itoa(rowCount)) + params.Set(PROP_NAME_PAGE_NUM, strconv.Itoa(pageNum)) + } + } +} + +const COL_MAX_LEN = 32 + +func calcColLens(objList []map[string]interface{}, fields []string, maxColLen int) []int { + + colLen := 0 + colVal := "" + colLens := make([]int, len(fields)) + for _, obj := range objList { + for i := 0; i < len(fields); i++ { + colVal = getColValue(obj[fields[i]]) + colLen = len(colVal) + if colLen > colLens[i] { + colLens[i] = colLen + } + } + } + if maxColLen > 0 { + for i := 0; i < len(fields); i++ { + if colLens[i] > maxColLen { + colLens[i] = maxColLen + } + } + } + return colLens +} + +func addTitles(objList []map[string]interface{}, fields []string) []map[string]interface{} { + titleMap := make(map[string]interface{}, len(fields)) + for i := 0; i < len(fields); i++ { + titleMap[fields[i]] = fields[i] + } + + dst := append(objList, titleMap) + copy(dst[1:], dst[:len(dst)-1]) + dst[0] = titleMap + return dst +} + +func toTable(objList []map[string]interface{}, fields []string, colLens []int, + showAll bool, append bool) string { + if fields == nil || objList == nil { + return "" + } + + if colLens == nil { + colLens = calcColLens(objList, fields, COL_MAX_LEN) + } + + output := &strings.Builder{} + if !append { + sepLine(output, colLens) + } + + for _, obj := range objList { + objMore := obj + for objMore != nil { + objMore = formateLine(output, objMore, fields, colLens, showAll) + } + sepLine(output, colLens) + } + + return output.String() +} + +func formateLine(output *strings.Builder, obj map[string]interface{}, fields []string, colLens []int, + showAll bool) map[string]interface{} { + hasMore := false + objMore := make(map[string]interface{}) + colLen := 0 + colVal := "" + for i := 0; i < len(fields); i++ { + colVal = getColValue(obj[fields[i]]) + + colLen = len(colVal) + if colLen <= colLens[i] { + output.WriteString("|") + output.WriteString(colVal) + blanks(output, colLens[i]-colLen) + if showAll { + objMore[fields[i]] = "" + } + } else { + output.WriteString("|") + if showAll { + output.WriteString(colVal[0:colLens[i]]) + objMore[fields[i]] = colVal[colLens[i]:] + hasMore = true + } else { + output.WriteString(colVal[0:colLens[i]-3] + "...") + } + } + } + output.WriteString("|") + output.WriteString(util.StringUtil.LineSeparator()) + + if hasMore { + return objMore + } else { + return nil + } +} + +func sepLine(output *strings.Builder, colLens []int) { + output.WriteString("+") + for _, colLen := range colLens { + for i := 0; i < colLen; i++ { + output.WriteString("+") + } + output.WriteString("+") + } + output.WriteString(util.StringUtil.LineSeparator()) +} + +func blanks(output *strings.Builder, count int) { + for count > 0 { + output.WriteString(" ") + count-- + } +} + +func getColValue(colObj interface{}) string { + var colVal string + if colObj == nil { + colVal = "" + } else { + colVal = fmt.Sprint(colObj) + } + + colVal = strings.Replace(colVal, "\t", "", -1) + colVal = strings.Replace(colVal, "\n", "", -1) + colVal = strings.Replace(colVal, "\r", "", -1) + + return colVal +} + +const ( + READ_MAX_SIZE = 100 +) + +type statFlusher struct { + sr *StatReader + logList []string + date string + logFile *os.File + flushFreq int + filePath string + filePrefix string + buffer *Dm_build_0 +} + +func newStatFlusher() *statFlusher { + sf := new(statFlusher) + sf.sr = newStatReader() + sf.logList = make([]string, 0, 32) + sf.date = time.Now().Format("2006-01-02") + sf.flushFreq = StatFlushFreq + sf.filePath = StatDir + sf.filePrefix = "dm_go_stat" + sf.buffer = Dm_build_4() + return sf +} + +func (sf *statFlusher) isConnStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) isSlowSqlStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) isHighFreqSqlStatEnabled() bool { + return StatEnable +} + +func (sf *statFlusher) doRun() { + + for { + if len(goStat.connStatMap) > 0 { + sf.logList = append(sf.logList, time.Now().String()) + if sf.isConnStatEnabled() { + sf.logList = append(sf.logList, "#connection stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readConnStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + if sf.isHighFreqSqlStatEnabled() { + sf.logList = append(sf.logList, "#top "+strconv.Itoa(StatHighFreqSqlCount)+" high freq sql stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readHighFreqSqlStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + if sf.isSlowSqlStatEnabled() { + sf.logList = append(sf.logList, "#top "+strconv.Itoa(StatSlowSqlCount)+" slow sql stat") + hasMore := true + for hasMore { + hasMore, sf.logList = sf.sr.readSlowSqlStat(sf.logList, READ_MAX_SIZE) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + } + } + sf.logList = append(sf.logList, util.StringUtil.LineSeparator()) + sf.logList = append(sf.logList, util.StringUtil.LineSeparator()) + sf.writeAndFlush(sf.logList, 0, len(sf.logList)) + sf.logList = sf.logList[0:0] + time.Sleep(time.Duration(StatFlushFreq) * time.Second) + } + } +} + +func (sf *statFlusher) writeAndFlush(logs []string, startOff int, l int) { + var bytes []byte + for i := startOff; i < startOff+l; i++ { + bytes = []byte(logs[i] + util.StringUtil.LineSeparator()) + + sf.buffer.Dm_build_26(bytes, 0, len(bytes)) + + if sf.buffer.Dm_build_5() >= FLUSH_SIZE { + sf.doFlush(sf.buffer) + } + } + + if sf.buffer.Dm_build_5() > 0 { + sf.doFlush(sf.buffer) + } +} + +func (sf *statFlusher) doFlush(buffer *Dm_build_0) { + if sf.needCreateNewFile() { + sf.closeCurrentFile() + sf.logFile = sf.createNewFile() + } + if sf.logFile != nil { + buffer.Dm_build_20(sf.logFile, buffer.Dm_build_5()) + } +} +func (sf *statFlusher) closeCurrentFile() { + if sf.logFile != nil { + sf.logFile.Close() + sf.logFile = nil + } +} +func (sf *statFlusher) createNewFile() *os.File { + sf.date = time.Now().Format("2006-01-02") + fileName := sf.filePrefix + "_" + sf.date + "_" + strconv.Itoa(time.Now().Nanosecond()) + ".txt" + sf.filePath = StatDir + if len(sf.filePath) > 0 { + if _, err := os.Stat(sf.filePath); err != nil { + os.MkdirAll(sf.filePath, 0755) + } + if _, err := os.Stat(sf.filePath + fileName); err != nil { + logFile, err := os.Create(sf.filePath + fileName) + if err != nil { + fmt.Println(err) + return nil + } + return logFile + } + } + return nil +} +func (sf *statFlusher) needCreateNewFile() bool { + now := time.Now().Format("2006-01-02") + fileInfo, err := sf.logFile.Stat() + return now != sf.date || err != nil || sf.logFile == nil || fileInfo.Size() > int64(MAX_FILE_SIZE) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/go.mod b/dpi_bridge/third_party/chunanyong_dm/go.mod new file mode 100644 index 0000000..f3d5b57 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/go.mod @@ -0,0 +1,8 @@ +module gitee.com/chunanyong/dm + +go 1.13 + +require ( + github.com/golang/snappy v0.0.1 + golang.org/x/text v0.3.2 +) diff --git a/dpi_bridge/third_party/chunanyong_dm/go.sum b/dpi_bridge/third_party/chunanyong_dm/go.sum new file mode 100644 index 0000000..bbde4ab --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/go.sum @@ -0,0 +1,5 @@ +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/dpi_bridge/third_party/chunanyong_dm/h.go b/dpi_bridge/third_party/chunanyong_dm/h.go new file mode 100644 index 0000000..b29a049 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/h.go @@ -0,0 +1,923 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "math" + "strconv" + "strings" + "time" + "unicode" +) + +func encodeByString(x string, column column, conn DmConnection) ([]byte, error) { + dt := make([]int, DT_LEN) + if _, err := toDTFromString(x, dt); err != nil { + return nil, err + } + return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) +} + +func encodeByTime(x time.Time, column column, conn DmConnection) ([]byte, error) { + dt := toDTFromTime(x) + return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) +} + +func toTimeFromString(str string, ltz int) time.Time { + dt := make([]int, DT_LEN) + toDTFromString(str, dt) + return toTimeFromDT(dt, ltz) +} + +func toTimeFromDT(dt []int, ltz int) time.Time { + var year, month, day, hour, minute, second, nsec, tz int + + year = dt[OFFSET_YEAR] + + if dt[OFFSET_MONTH] > 0 { + month = dt[OFFSET_MONTH] + } else { + month = 1 + } + + if dt[OFFSET_DAY] > 0 { + day = dt[OFFSET_DAY] + } else { + day = 1 + } + + hour = dt[OFFSET_HOUR] + minute = dt[OFFSET_MINUTE] + second = dt[OFFSET_SECOND] + nsec = dt[OFFSET_NANOSECOND] + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + tz = ltz * 60 + } else { + tz = dt[OFFSET_TIMEZONE] * 60 + } + return time.Date(year, time.Month(month), day, hour, minute, second, nsec, time.FixedZone("", tz)) +} + +func decode(value []byte, isBdta bool, column column, ltz int, dtz int) []int { + var dt []int + if isBdta { + dt = dmdtDecodeBdta(value) + } else { + dt = dmdtDecodeFast(value) + } + + if column.mask == MASK_LOCAL_DATETIME { + transformTZ(dt, dtz, ltz) + } + + return dt +} + +func dmdtDecodeFast(value []byte) []int { + dt := make([]int, DT_LEN) + dt[OFFSET_TIMEZONE] = INVALID_VALUE + + dtype := 0 + if len(value) == DATE_PREC { + dtype = DATE + } else if len(value) == TIME_PREC { + dtype = TIME + } else if len(value) == TIME_TZ_PREC { + dtype = TIME_TZ + } else if len(value) == DATETIME_PREC { + dtype = DATETIME + } else if len(value) == DATETIME2_PREC { + dtype = DATETIME2 + } else if len(value) == DATETIME_TZ_PREC { + dtype = DATETIME_TZ + } else if len(value) == DATETIME2_TZ_PREC { + dtype = DATETIME2_TZ + } + + if dtype == DATE { + + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + } else if dtype == TIME { + dt[OFFSET_HOUR] = int(value[0]) & 0x1F + dt[OFFSET_MINUTE] = ((int(value[0]) >> 5) & 0x07) + ((int(value[1]) & 0x07) << 3) + dt[OFFSET_SECOND] = ((int(value[1]) >> 3) & 0x1f) + ((int(value[2]) & 0x01) << 5) + dt[OFFSET_NANOSECOND] = ((int(value[2]) >> 1) & 0x7f) + ((int(value[3]) & 0x00ff) << 7) + ((int(value[4]) & 0x1F) << 15) + dt[OFFSET_NANOSECOND] *= 1000 + } else if dtype == TIME_TZ { + dt[OFFSET_HOUR] = int(value[0]) & 0x1F + dt[OFFSET_MINUTE] = ((int(value[0]) >> 5) & 0x07) + ((int(value[1]) & 0x07) << 3) + dt[OFFSET_SECOND] = ((int(value[1]) >> 3) & 0x1f) + ((int(value[2]) & 0x01) << 5) + dt[OFFSET_NANOSECOND] = ((int(value[2]) >> 1) & 0x7f) + ((int(value[3]) & 0x00ff) << 7) + ((int(value[4]) & 0x1F) << 15) + dt[OFFSET_NANOSECOND] *= 1000 + dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, 5)) + } else if dtype == DATETIME { + + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + + dt[OFFSET_HOUR] = (int(value[3]) & 0x1F) + + dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3) + + dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5) + + dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x1F) << 15) + dt[OFFSET_NANOSECOND] *= 1000 + } else if dtype == DATETIME_TZ { + + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + + dt[OFFSET_HOUR] = (int(value[3]) & 0x1F) + + dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3) + + dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5) + + dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x1F) << 15) + dt[OFFSET_NANOSECOND] *= 1000 + + dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, len(value)-2)) + } else if dtype == DATETIME2 { + + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + + dt[OFFSET_HOUR] = (int(value[3]) & 0x1F) + + dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3) + + dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5) + + dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x00ff) << 15) + ((int(value[8]) & 0x7F) << 23) + } else if dtype == DATETIME2_TZ { + + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) & 0x7FFF + if dt[OFFSET_YEAR] > 9999 { + dt[OFFSET_YEAR] = int(int16(dt[OFFSET_YEAR] | 0x8000)) + } + + dt[OFFSET_MONTH] = ((int(value[1]) >> 7) & 0x1) + ((int(value[2]) & 0x07) << 1) + + dt[OFFSET_DAY] = ((int(value[2]) & 0xF8) >> 3) & 0x1f + + dt[OFFSET_HOUR] = (int(value[3]) & 0x1F) + + dt[OFFSET_MINUTE] = ((int(value[3]) >> 5) & 0x07) + ((int(value[4]) & 0x07) << 3) + + dt[OFFSET_SECOND] = ((int(value[4]) >> 3) & 0x1f) + ((int(value[5]) & 0x01) << 5) + + dt[OFFSET_NANOSECOND] = ((int(value[5]) >> 1) & 0x7f) + ((int(value[6]) & 0x00ff) << 7) + ((int(value[7]) & 0x00ff) << 15) + ((int(value[8]) & 0x7F) << 23) + + dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, len(value)-2)) + } + return dt +} + +func dmdtDecodeBdta(value []byte) []int { + dt := make([]int, DT_LEN) + dt[OFFSET_YEAR] = int(Dm_build_1346.Dm_build_1443(value, 0)) + dt[OFFSET_MONTH] = int(value[2] & 0xFF) + dt[OFFSET_DAY] = int(value[3] & 0xFF) + dt[OFFSET_HOUR] = int(value[4] & 0xFF) + dt[OFFSET_MINUTE] = int(value[5] & 0xFF) + dt[OFFSET_SECOND] = int(value[6] & 0xFF) + dt[OFFSET_NANOSECOND] = int((value[7] & 0xFF) + (value[8] << 8) + (value[9] << 16)) + dt[OFFSET_TIMEZONE] = int(Dm_build_1346.Dm_build_1443(value, 10)) + + if len(value) > 12 { + + dt[OFFSET_NANOSECOND] += int(value[12] << 24) + } + return dt +} + +func dtToStringByOracleFormat(dt []int, oracleFormatPattern string, scale int32, language int) string { + return format(dt, oracleFormatPattern, scale, language) +} + +func dtToString(dt []int, dtype int, scale int) string { + switch dtype { + case DATE: + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + + case TIME: + if scale > 0 { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + } else { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + } + + case TIME_TZ: + if scale > 0 { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } else { + return format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } + + case DATETIME, DATETIME2: + if scale > 0 { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + } else { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + } + + case DATETIME_TZ, DATETIME2_TZ: + if scale > 0 { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + "." + formatMilliSecond(dt[OFFSET_NANOSECOND], scale) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } else { + return formatYear(dt[OFFSET_YEAR]) + "-" + format2(dt[OFFSET_MONTH]) + "-" + format2(dt[OFFSET_DAY]) + " " + format2(dt[OFFSET_HOUR]) + ":" + format2(dt[OFFSET_MINUTE]) + ":" + format2(dt[OFFSET_SECOND]) + " " + formatTZ(dt[OFFSET_TIMEZONE]) + } + } + + return "" +} + +func formatYear(value int) string { + if value >= 0 { + if value < 10 { + return "000" + strconv.FormatInt(int64(value), 10) + } else if value < 100 { + return "00" + strconv.FormatInt(int64(value), 10) + } else if value < 1000 { + return "0" + strconv.FormatInt(int64(value), 10) + } else { + return strconv.FormatInt(int64(value), 10) + } + } else { + if value > -10 { + return "-000" + strconv.FormatInt(int64(-value), 10) + } else if value > -100 { + return "-00" + strconv.FormatInt(int64(-value), 10) + } else if value > -1000 { + return "-0" + strconv.FormatInt(int64(-value), 10) + } else { + return strconv.FormatInt(int64(value), 10) + } + } +} + +func format2(value int) string { + if value < 10 { + return "0" + strconv.FormatInt(int64(value), 10) + } else { + return strconv.FormatInt(int64(value), 10) + } +} + +func formatMilliSecond(ms int, prec int) string { + var ret string + if ms < 10 { + ret = "00000000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100 { + ret = "0000000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 1000 { + ret = "000000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 10000 { + ret = "00000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100000 { + ret = "0000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 1000000 { + ret = "000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 10000000 { + ret = "00" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100000000 { + ret = "0" + strconv.FormatInt(int64(ms), 10) + } else { + ret = strconv.FormatInt(int64(ms), 10) + } + + if prec < NANOSECOND_DIGITS { + ret = ret[:prec] + } + return ret +} + +func formatTZ(tz int) string { + tz_hour := int(math.Abs(float64(tz / 60))) + tz_min := int(math.Abs(float64(tz % 60))) + + if tz >= 0 { + return "+" + format2(tz_hour) + ":" + format2(tz_min) + } else { + return "-" + format2(tz_hour) + ":" + format2(tz_min) + } +} + +func toDTFromTime(x time.Time) []int { + hour, min, sec := x.Clock() + ts := make([]int, DT_LEN) + ts[OFFSET_YEAR] = x.Year() + ts[OFFSET_MONTH] = int(x.Month()) + ts[OFFSET_DAY] = x.Day() + ts[OFFSET_HOUR] = hour + ts[OFFSET_MINUTE] = min + ts[OFFSET_SECOND] = sec + ts[OFFSET_NANOSECOND] = (int)(x.Nanosecond()) + _, tz := x.Zone() + ts[OFFSET_TIMEZONE] = tz / 60 + return ts +} + +func toDTFromUnix(sec int64, nsec int64) []int { + return toDTFromTime(time.Unix(sec, nsec)) +} + +func toDTFromString(s string, dt []int) (dtype int, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_DATETIME_FORMAT.throw() + } + }() + date_s := "" + time_s := "" + nanos_s := "" + tz_s := "" + year := 0 + month := 0 + day := 0 + hour := 0 + minute := 0 + second := 0 + a_nanos := 0 + firstDash := -1 + secondDash := -1 + firstColon := -1 + secondColon := -1 + period := -1 + sign := 0 + ownTz := INVALID_VALUE + dtype = -1 + + zeros := "000000000" + + if s != "" && strings.TrimSpace(s) == "" { + return 0, ECGO_INVALID_DATETIME_FORMAT.throw() + } + s = strings.TrimSpace(s) + + if strings.Index(s, "-") == 0 { + s = strings.TrimSpace(s[1:]) + sign = 1 + } + + comps := strings.Split(s, " ") + + switch len(comps) { + case 3: + date_s = comps[0] + time_s = comps[1] + tz_s = comps[2] + dtype = DATETIME_TZ + + case 2: + if strings.Index(comps[0], ":") > 0 { + time_s = comps[0] + tz_s = comps[1] + dtype = TIME_TZ + } else { + date_s = comps[0] + time_s = comps[1] + dtype = DATETIME + } + + case 1: + if strings.Index(comps[0], ":") > 0 { + time_s = comps[0] + dtype = TIME + } else { + date_s = comps[0] + dtype = DATE + } + + default: + return 0, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if date_s != "" { + + firstDash = strings.Index(date_s, "-") + secondDash = strings.Index(date_s[firstDash+1:], "-") + + if firstDash < 0 || secondDash < 0 { + firstDash = strings.Index(s, ".") + secondDash = strings.Index(date_s[firstDash+1:], ".") + } + + if firstDash < 0 || secondDash < 0 { + firstDash = strings.Index(s, "/") + secondDash = strings.Index(date_s[firstDash+1:], "/") + } + if secondDash > 0 { + secondDash += firstDash + 1 + } + + if (firstDash > 0) && (secondDash > 0) && (secondDash < len(date_s)-1) { + + if sign == 1 { + i, err := strconv.ParseInt(date_s[:firstDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + year = 0 - int(i) - 1900 + } else { + i, err := strconv.ParseInt(date_s[:firstDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + year = int(i) - 1900 + } + + i, err := strconv.ParseInt(date_s[firstDash+1:secondDash], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + month = int(i) - 1 + + i, err = strconv.ParseInt(date_s[secondDash+1:], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + day = int(i) + + if !checkDate(year+1900, month+1, day) { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } else { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + if time_s != "" { + firstColon = strings.Index(time_s, ":") + secondColon = strings.Index(time_s[firstColon+1:], ":") + if secondColon > 0 { + secondColon += firstColon + 1 + } + + period = strings.Index(time_s[secondColon+1:], ".") + if period > 0 { + period += secondColon + 1 + } + + if (firstColon > 0) && (secondColon > 0) && (secondColon < len(time_s)-1) { + i, err := strconv.ParseInt(time_s[:firstColon], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + hour = int(i) + + i, err = strconv.ParseInt(time_s[firstColon+1:secondColon], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + minute = int(i) + + if period > 0 && period < len(time_s)-1 { + i, err = strconv.ParseInt(time_s[secondColon+1:period], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + second = int(i) + + nanos_s = time_s[period+1:] + if len(nanos_s) > NANOSECOND_DIGITS { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + if !unicode.IsDigit(rune(nanos_s[0])) { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + nanos_s = nanos_s + zeros[0:NANOSECOND_DIGITS-len(nanos_s)] + + i, err = strconv.ParseInt(nanos_s, 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + a_nanos = int(i) + } else if period > 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } else { + i, err = strconv.ParseInt(time_s[secondColon+1:], 10, 32) + if err != nil { + return 0, ECGO_INVALID_DATETIME_FORMAT.addDetailln(err.Error()).throw() + } + second = int(i) + } + + if hour >= 24 || hour < 0 || minute >= 60 || minute < 0 || second >= 60 || second < 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } else { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + if tz_s != "" { + neg := false + if strings.Index(tz_s, "-") == 0 { + neg = true + } + + if strings.Index(tz_s, "-") == 0 || strings.Index(tz_s, "+") == 0 { + tz_s = strings.TrimSpace(tz_s[1:]) + } + + hm := strings.Split(tz_s, ":") + var tzh, tzm int16 = 0, 0 + switch len(hm) { + case 2: + s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzh = int16(s) + + s, err = strconv.ParseInt(strings.TrimSpace(hm[1]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzm = int16(s) + case 1: + s, err := strconv.ParseInt(strings.TrimSpace(hm[0]), 10, 16) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + tzh = int16(s) + default: + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + ownTz = int(tzh*60 + tzm) + if ownTz < 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if neg { + ownTz *= -1 + } + + if ownTz <= -13*60 || ownTz > 14*60 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + } + + dt[OFFSET_YEAR] = year + 1900 + dt[OFFSET_MONTH] = month + 1 + if day == 0 { + dt[OFFSET_DAY] = 1 + } else { + dt[OFFSET_DAY] = day + } + dt[OFFSET_HOUR] = hour + dt[OFFSET_MINUTE] = minute + dt[OFFSET_SECOND] = second + dt[OFFSET_NANOSECOND] = a_nanos + dt[OFFSET_TIMEZONE] = int(ownTz) + return dtype, nil +} + +func transformTZ(dt []int, defaultSrcTz int, destTz int) { + srcTz := defaultSrcTz + + if srcTz != INVALID_VALUE && destTz != INVALID_VALUE && destTz != srcTz { + dt = addMinute(dt, destTz-srcTz) + + dt[OFFSET_TIMEZONE] = destTz + + } +} + +func encode(dt []int, column column, lTz int, dTz int) ([]byte, error) { + if dt[OFFSET_TIMEZONE] != INVALID_VALUE { + transformTZ(dt, dt[OFFSET_TIMEZONE], lTz) + } + + if column.mask == MASK_LOCAL_DATETIME { + transformTZ(dt, dt[OFFSET_TIMEZONE], dTz) + } + + if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + year := dt[OFFSET_YEAR] + + month := dt[OFFSET_MONTH] + + day := dt[OFFSET_DAY] + + hour := dt[OFFSET_HOUR] + + min := dt[OFFSET_MINUTE] + + sec := dt[OFFSET_SECOND] + + msec := dt[OFFSET_NANOSECOND] + + var tz int + + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + tz = dTz + } else { + tz = dt[OFFSET_TIMEZONE] + } + + var ret []byte + + if column.colType == DATE { + ret = make([]byte, 3) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + } else if column.colType == DATETIME { + msec /= 1000 + ret = make([]byte, 8) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + } else if column.colType == DATETIME2 { + ret = make([]byte, 9) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + + ret[8] = (byte)((msec >> 23) & 0xFF) + } else if column.colType == DATETIME_TZ { + msec /= 1000 + ret = make([]byte, 10) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + + Dm_build_1346.Dm_build_1357(ret, 8, int16(tz)) + } else if column.colType == DATETIME2_TZ { + ret = make([]byte, 11) + + ret[0] = (byte)(year & 0xFF) + + if year >= 0 { + ret[1] = (byte)((year >> 8) | ((month & 0x01) << 7)) + } else { + ret[1] = (byte)((year >> 8) & (((month & 0x01) << 7) | 0x7f)) + } + + ret[2] = (byte)(((month & 0x0E) >> 1) | (day << 3)) + + ret[3] = (byte)(hour | ((min & 0x07) << 5)) + + ret[4] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[5] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[6] = (byte)((msec >> 7) & 0xFF) + + ret[7] = (byte)((msec >> 15) & 0xFF) + + ret[8] = (byte)((msec >> 23) & 0xFF) + + Dm_build_1346.Dm_build_1357(ret, 8, int16(tz)) + } else if column.colType == TIME { + msec /= 1000 + ret = make([]byte, 5) + + ret[0] = (byte)(hour | ((min & 0x07) << 5)) + + ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[3] = (byte)((msec >> 7) & 0xFF) + + ret[4] = (byte)((msec >> 15) & 0xFF) + } else if column.colType == TIME_TZ { + msec /= 1000 + ret = make([]byte, 7) + + ret[0] = (byte)(hour | ((min & 0x07) << 5)) + + ret[1] = (byte)(((min & 0x38) >> 3) | ((sec & 0x1F) << 3)) + + ret[2] = (byte)(((sec & 0x20) >> 5) | ((msec & 0x7F) << 1)) + + ret[3] = (byte)((msec >> 7) & 0xFF) + + ret[4] = (byte)((msec >> 15) & 0xFF) + + Dm_build_1346.Dm_build_1357(ret, 5, int16(tz)) + } + + return ret, nil +} + +func toDate(x int64, column column, conn DmConnection) ([]byte, error) { + switch column.colType { + case DATETIME, DATETIME2: + if x > 2958463*24*60*60 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + dt := toDTFromUnix(x-Seconds_1900_1970, 0) + return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + + case TIME: + dt := toDTFromUnix(x, 0) + return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + + case DATE: + if x > 2958463 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + + dt := toDTFromUnix(x*24*60*60-Seconds_1900_1970, 0) + if dt[OFFSET_YEAR] < -4712 || dt[OFFSET_YEAR] > 9999 { + return nil, ECGO_DATETIME_OVERFLOW.throw() + } + return encode(dt, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} + +func checkDate(year int, month int, day int) bool { + if year > 9999 || year < -4712 || month > 12 || month < 1 { + return false + } + + monthDays := getDaysOfMonth(year, month) + if day > monthDays || day < 1 { + return false + } + return true +} + +func getDaysOfMonth(year int, month int) int { + switch month { + case 1, 3, 5, 7, 8, 10, 12: + return 31 + case 4, 6, 9, 11: + return 30 + case 2: + if isLeapYear(year) { + return 29 + } + return 28 + default: + return 0 + } +} + +func isLeapYear(year int) bool { + return (year%4 == 0 && year%100 != 0) || year%400 == 0 +} + +func addYear(dt []int, n int) []int { + dt[OFFSET_YEAR] += n + return dt +} + +func addMonth(dt []int, n int) []int { + month := dt[OFFSET_MONTH] + n + addYearValue := month / 12 + if month %= 12; month < 1 { + month += 12 + addYearValue-- + } + + daysOfMonth := getDaysOfMonth(dt[OFFSET_YEAR], month) + if dt[OFFSET_DAY] > daysOfMonth { + dt[OFFSET_DAY] = daysOfMonth + } + + dt[OFFSET_MONTH] = month + addYear(dt, addYearValue) + return dt +} + +func addDay(dt []int, n int) []int { + tmp := dt[OFFSET_DAY] + n + monthDays := 0 + monthDays = getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH]) + for tmp > monthDays || tmp <= 0 { + if tmp > monthDays { + addMonth(dt, 1) + tmp -= monthDays + } else { + addMonth(dt, -1) + tmp += monthDays + } + } + dt[OFFSET_DAY] = tmp + return dt +} + +func addHour(dt []int, n int) []int { + hour := dt[OFFSET_HOUR] + n + addDayValue := hour / 24 + if hour %= 24; hour < 0 { + hour += 24 + addDayValue-- + } + + dt[OFFSET_HOUR] = hour + addDay(dt, addDayValue) + return dt +} + +func addMinute(dt []int, n int) []int { + minute := dt[OFFSET_MINUTE] + n + addHourValue := minute / 60 + if minute %= 60; minute < 0 { + minute += 60 + addHourValue-- + } + + dt[OFFSET_MINUTE] = minute + addHour(dt, addHourValue) + return dt +} diff --git a/dpi_bridge/third_party/chunanyong_dm/i.go b/dpi_bridge/third_party/chunanyong_dm/i.go new file mode 100644 index 0000000..3fefb38 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/i.go @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "strconv" + "time" + + "gitee.com/chunanyong/dm/util" +) + +var DB2G db2g + +type db2g struct { +} + +func (DB2G db2g) processVarchar2(bytes []byte, prec int) []byte { + rbytes := make([]byte, prec) + copy(rbytes[:len(bytes)], bytes[:]) + for i := len(bytes); i < len(rbytes); i++ { + rbytes[i] = ' ' + } + return rbytes +} + +func (DB2G db2g) charToString(bytes []byte, column *column, conn *DmConnection) string { + if column.colType == VARCHAR2 { + bytes = DB2G.processVarchar2(bytes, int(column.prec)) + } else if column.colType == CLOB { + clob := newClobFromDB(bytes, conn, column, true) + clobLen, _ := clob.GetLength() + clobStr, _ := clob.getSubString(1, int32(clobLen)) + return clobStr + } + return Dm_build_1346.Dm_build_1598(bytes, conn.serverEncoding, conn) +} + +func (DB2G db2g) charToFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) { + str := DB2G.charToString(bytes, column, conn) + val, err := strconv.ParseFloat(str, 64) + if err != nil { + return 0, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return val, nil +} + +func (DB2G db2g) charToDeciaml(bytes []byte, column *column, conn *DmConnection) (*DmDecimal, error) { + str := DB2G.charToString(bytes, column, conn) + return NewDecimalFromString(str) +} + +func (DB2G db2g) BinaryToInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) { + if column.colType == BLOB { + blob := newBlobFromDB(bytes, conn, column, true) + blobLen, err := blob.GetLength() + if err != nil { + return 0, err + } + bytes, err = blob.getBytes(1, int32(blobLen)) + if err != nil { + return 0, err + } + } + var n, b int64 = 0, 0 + + startIndex := 0 + var length int + if len(bytes) > 8 { + length = 8 + for j := 0; j < len(bytes)-8; j++ { + if bytes[j] != 0 { + return 0, ECGO_DATA_CONVERTION_ERROR.throw() + } + + startIndex = len(bytes) - 8 + length = 8 + } + } else { + length = len(bytes) + } + + for j := startIndex; j < startIndex+length; j++ { + b = int64(0xff & bytes[j]) + n = b | (n << 8) + } + + return n, nil +} + +func (DB2G db2g) decToDecimal(bytes []byte, prec int, scale int, compatibleOracle bool) (*DmDecimal, error) { + + if compatibleOracle { + prec = -1 + scale = -1 + } + return newDecimal(bytes, prec, scale) +} + +func (DB2G db2g) toBytes(bytes []byte, column *column, conn *DmConnection) ([]byte, error) { + retBytes := Dm_build_1346.Dm_build_1497(bytes, 0, len(bytes)) + switch column.colType { + case CLOB: + clob := newClobFromDB(retBytes, conn, column, true) + str, err := clob.getSubString(1, int32(clob.length)) + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1562(str, conn.getServerEncoding(), conn), nil + case BLOB: + blob := newBlobFromDB(retBytes, conn, column, true) + bs, err := blob.getBytes(1, int32(blob.length)) + if err != nil { + return nil, err + } + + return bs, nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toString(bytes []byte, column *column, conn *DmConnection) string { + switch column.colType { + case CHAR, VARCHAR, VARCHAR2: + return DB2G.charToString(bytes, column, conn) + case BIT, BOOLEAN, TINYINT: + return strconv.FormatInt(int64(bytes[0]), 10) + case SMALLINT: + return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1570(bytes)), 10) + case INT: + return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1573(bytes)), 10) + case BIGINT: + return strconv.FormatInt(int64(Dm_build_1346.Dm_build_1576(bytes)), 10) + case REAL: + return strconv.FormatFloat(float64(Dm_build_1346.Dm_build_1579(bytes)), 'f', -1, 32) + case DOUBLE: + return strconv.FormatFloat(float64(Dm_build_1346.Dm_build_1582(bytes)), 'f', -1, 64) + case DECIMAL: + + case BINARY, VARBINARY: + util.StringUtil.BytesToHexString(bytes, false) + case BLOB: + + case CLOB: + + case DATE: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatDate != "" { + return dtToStringByOracleFormat(dt, conn.FormatDate, column.scale, int(conn.OracleDateLanguage)) + } + case TIME: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTime != "" { + return dtToStringByOracleFormat(dt, conn.FormatTime, column.scale, int(conn.OracleDateLanguage)) + } + case DATETIME, DATETIME2: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimestamp != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimestamp, column.scale, int(conn.OracleDateLanguage)) + } + case TIME_TZ: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimeTZ != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimeTZ, column.scale, int(conn.OracleDateLanguage)) + } + case DATETIME_TZ, DATETIME2_TZ: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + if conn.FormatTimestampTZ != "" { + return dtToStringByOracleFormat(dt, conn.FormatTimestampTZ, column.scale, int(conn.OracleDateLanguage)) + } + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes).String() + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes).String() + case ARRAY: + + case SARRAY: + + case CLASS: + + case PLTYPE_RECORD: + + } + return "" +} + +func (DB2G db2g) toBool(bytes []byte, column *column, conn *DmConnection) (bool, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + return bytes[0] != 0, nil + case SMALLINT: + return Dm_build_1346.Dm_build_1443(bytes, 0) != 0, nil + case INT: + return Dm_build_1346.Dm_build_1448(bytes, 0) != 0, nil + case BIGINT: + return Dm_build_1346.Dm_build_1453(bytes, 0) != 0, nil + case REAL: + return Dm_build_1346.Dm_build_1458(bytes, 0) != 0, nil + case DOUBLE: + return Dm_build_1346.Dm_build_1462(bytes, 0) != 0, nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + return G2DB.toBool(DB2G.charToString(bytes, column, conn)) + } + + return false, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toByte(bytes []byte, column *column, conn *DmConnection) (byte, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + + if bytes == nil || len(bytes) == 0 { + return 0, nil + } else { + return bytes[0], nil + } + case SMALLINT: + tval := Dm_build_1346.Dm_build_1443(bytes, 0) + if tval < int16(BYTE_MIN) || tval > int16(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case INT: + tval := Dm_build_1346.Dm_build_1448(bytes, 0) + if tval < int32(BYTE_MIN) || tval > int32(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(BYTE_MIN) || tval > float32(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(BYTE_MIN) || tval > float64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(BYTE_MIN) || tval > int64(BYTE_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return byte(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt8(bytes []byte, column *column, conn *DmConnection) (int8, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int8(bytes[0]), nil + case SMALLINT: + tval := Dm_build_1346.Dm_build_1443(bytes, 0) + if tval < int16(INT8_MIN) || tval < int16(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case INT: + + tval := Dm_build_1346.Dm_build_1448(bytes, 0) + if tval < int32(INT8_MIN) || tval > int32(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(INT8_MIN) || tval > float32(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT8_MIN) || tval > float64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT8_MIN) || tval > int64(INT8_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int8(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt16(bytes []byte, column *column, conn *DmConnection) (int16, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int16(bytes[0]), nil + case SMALLINT: + return Dm_build_1346.Dm_build_1443(bytes, 0), nil + case INT: + + tval := Dm_build_1346.Dm_build_1448(bytes, 0) + if tval < int32(INT16_MIN) || tval > int32(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(INT16_MIN) || tval > float32(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT16_MIN) || tval > float64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT16_MIN) || tval > int64(INT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int16(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt16(bytes []byte, column *column, conn *DmConnection) (uint16, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return uint16(bytes[0]), nil + case SMALLINT: + return uint16(Dm_build_1346.Dm_build_1443(bytes, 0)), nil + case INT: + tval := Dm_build_1346.Dm_build_1448(bytes, 0) + if tval < int32(UINT16_MIN) || tval > int32(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(UINT16_MIN) || tval > float32(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(UINT16_MIN) || tval > float64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(UINT16_MIN) || tval > int64(UINT16_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint16(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt32(bytes []byte, column *column, conn *DmConnection) (int32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return int32(bytes[0]), nil + case SMALLINT: + return int32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil + case INT: + return Dm_build_1346.Dm_build_1448(bytes, 0), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(INT32_MIN) || tval > float32(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(INT32_MIN) || tval > float64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(INT32_MIN) || tval > int64(INT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int32(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt32(bytes []byte, column *column, conn *DmConnection) (uint32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + + return uint32(bytes[0]), nil + case SMALLINT: + return uint32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil + case INT: + return uint32(Dm_build_1346.Dm_build_1448(bytes, 0)), nil + case BIGINT: + tval := Dm_build_1346.Dm_build_1453(bytes, 0) + if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case REAL: + tval := Dm_build_1346.Dm_build_1458(bytes, 0) + if tval < float32(UINT32_MIN) || tval > float32(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case DOUBLE: + tval := Dm_build_1346.Dm_build_1462(bytes, 0) + if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case DECIMAL: + + case CHAR, VARCHAR, VARCHAR2, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < float64(UINT32_MIN) || tval > float64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + case BINARY, VARBINARY, BLOB: + { + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + if tval < int64(UINT32_MIN) || tval > int64(UINT32_MAX) { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint32(tval), nil + } + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt64(bytes []byte, column *column, conn *DmConnection) (int64, error) { + switch column.colType { + case BOOLEAN, BIT, TINYINT: + if bytes == nil || len(bytes) == 0 { + return int64(0), nil + } else { + return int64(bytes[0]), nil + } + case SMALLINT: + return int64(Dm_build_1346.Dm_build_1570(bytes)), nil + case INT: + return int64(Dm_build_1346.Dm_build_1573(bytes)), nil + case BIGINT: + return int64(Dm_build_1346.Dm_build_1576(bytes)), nil + case REAL: + return int64(Dm_build_1346.Dm_build_1579(bytes)), nil + case DOUBLE: + return int64(Dm_build_1346.Dm_build_1582(bytes)), nil + + case CHAR, VARCHAR2, VARCHAR, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if int64(tval) < INT64_MIN || int64(tval) > INT64_MAX { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return int64(tval), nil + case BINARY, VARBINARY, BLOB: + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + return tval, nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toUInt64(bytes []byte, column *column, conn *DmConnection) (uint64, error) { + switch column.colType { + case BOOLEAN, BIT, TINYINT: + if bytes == nil || len(bytes) == 0 { + return uint64(0), nil + } else { + return uint64(bytes[0]), nil + } + case SMALLINT: + return uint64(Dm_build_1346.Dm_build_1570(bytes)), nil + case INT: + return uint64(Dm_build_1346.Dm_build_1573(bytes)), nil + case BIGINT: + return uint64(Dm_build_1346.Dm_build_1576(bytes)), nil + case REAL: + return uint64(Dm_build_1346.Dm_build_1579(bytes)), nil + case DOUBLE: + return uint64(Dm_build_1346.Dm_build_1582(bytes)), nil + + case CHAR, VARCHAR2, VARCHAR, CLOB: + tval, err := DB2G.charToFloat64(bytes, column, conn) + if err != nil { + return 0, err + } + + if uint64(tval) < UINT64_MIN || uint64(tval) > UINT64_MAX { + return 0, ECGO_DATA_OVERFLOW.throw() + } + return uint64(tval), nil + case BINARY, VARBINARY, BLOB: + tval, err := DB2G.BinaryToInt64(bytes, column, conn) + if err != nil { + return 0, err + } + + return uint64(tval), nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toInt(bytes []byte, column *column, conn *DmConnection) (int, error) { + if strconv.IntSize == 32 { + tmp, err := DB2G.toInt32(bytes, column, conn) + return int(tmp), err + } else { + tmp, err := DB2G.toInt64(bytes, column, conn) + return int(tmp), err + } +} + +func (DB2G db2g) toUInt(bytes []byte, column *column, conn *DmConnection) (uint, error) { + if strconv.IntSize == 32 { + tmp, err := DB2G.toUInt32(bytes, column, conn) + return uint(tmp), err + } else { + tmp, err := DB2G.toUInt64(bytes, column, conn) + return uint(tmp), err + } +} + +func (DB2G db2g) toFloat32(bytes []byte, column *column, conn *DmConnection) (float32, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + return float32(bytes[0]), nil + case SMALLINT: + return float32(Dm_build_1346.Dm_build_1443(bytes, 0)), nil + case INT: + return float32(Dm_build_1346.Dm_build_1448(bytes, 0)), nil + case BIGINT: + return float32(Dm_build_1346.Dm_build_1453(bytes, 0)), nil + case REAL: + return Dm_build_1346.Dm_build_1458(bytes, 0), nil + case DOUBLE: + dval := Dm_build_1346.Dm_build_1462(bytes, 0) + return float32(dval), nil + case DECIMAL: + dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle()) + if err != nil { + return 0, err + } + return float32(dval.ToFloat64()), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + dval, err := DB2G.charToDeciaml(bytes, column, conn) + if err != nil { + return 0, err + } + return float32(dval.ToFloat64()), nil + } + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toFloat64(bytes []byte, column *column, conn *DmConnection) (float64, error) { + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if bytes == nil || len(bytes) == 0 { + return 0, nil + } + return float64(bytes[0]), nil + case SMALLINT: + return float64(Dm_build_1346.Dm_build_1443(bytes, 0)), nil + case INT: + return float64(Dm_build_1346.Dm_build_1448(bytes, 0)), nil + case BIGINT: + return float64(Dm_build_1346.Dm_build_1453(bytes, 0)), nil + case REAL: + return float64(Dm_build_1346.Dm_build_1458(bytes, 0)), nil + case DOUBLE: + return Dm_build_1346.Dm_build_1462(bytes, 0), nil + case DECIMAL: + dval, err := DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle()) + if err != nil { + return 0, err + } + return dval.ToFloat64(), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + dval, err := DB2G.charToDeciaml(bytes, column, conn) + if err != nil { + return 0, err + } + return dval.ToFloat64(), nil + } + + return 0, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toDmBlob(value []byte, column *column, conn *DmConnection) *DmBlob { + + switch column.colType { + case BLOB: + return newBlobFromDB(value, conn, column, conn.lobFetchAll()) + default: + return newBlobOfLocal(value, conn) + } +} + +func (DB2G db2g) toDmClob(value []byte, conn *DmConnection, column *column) *DmClob { + + switch column.colType { + case CLOB: + return newClobFromDB(value, conn, column, conn.lobFetchAll()) + default: + return newClobOfLocal(DB2G.toString(value, column, conn), conn) + } +} + +func (DB2G db2g) toDmDecimal(value []byte, column *column, conn *DmConnection) (*DmDecimal, error) { + + switch column.colType { + case BIT, BOOLEAN, TINYINT: + if value == nil || len(value) == 0 { + return NewDecimalFromInt64(0) + } else { + return NewDecimalFromInt64(int64(value[0])) + } + case SMALLINT: + return NewDecimalFromInt64(int64(Dm_build_1346.Dm_build_1443(value, 0))) + case INT: + return NewDecimalFromInt64(int64(Dm_build_1346.Dm_build_1448(value, 0))) + case BIGINT: + return NewDecimalFromInt64(Dm_build_1346.Dm_build_1453(value, 0)) + case REAL: + return NewDecimalFromFloat64(float64(Dm_build_1346.Dm_build_1458(value, 0))) + case DOUBLE: + return NewDecimalFromFloat64(Dm_build_1346.Dm_build_1462(value, 0)) + case DECIMAL: + return decodeDecimal(value, int(column.prec), int(column.scale)) + case CHAR, VARCHAR, VARCHAR2, CLOB: + return DB2G.charToDeciaml(value, column, conn) + } + + return nil, ECGO_DATA_CONVERTION_ERROR +} + +func (DB2G db2g) toTime(bytes []byte, column *column, conn *DmConnection) (time.Time, error) { + switch column.colType { + case DATE, TIME, TIME_TZ, DATETIME_TZ, DATETIME, DATETIME2_TZ, DATETIME2: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil + case CHAR, VARCHAR2, VARCHAR, CLOB: + return toTimeFromString(DB2G.charToString(bytes, column, conn), int(conn.dmConnector.localTimezone)), nil + } + return time.Now(), ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toObject(bytes []byte, column *column, conn *DmConnection) (interface{}, error) { + + switch column.colType { + case BIT, BOOLEAN: + return bytes[0] != 0, nil + + case TINYINT: + + return Dm_build_1346.Dm_build_1439(bytes, 0), nil + case SMALLINT: + return Dm_build_1346.Dm_build_1443(bytes, 0), nil + case INT: + return Dm_build_1346.Dm_build_1448(bytes, 0), nil + case BIGINT: + return Dm_build_1346.Dm_build_1453(bytes, 0), nil + case DECIMAL: + return DB2G.decToDecimal(bytes, int(column.prec), int(column.scale), conn.CompatibleOracle()) + case REAL: + return Dm_build_1346.Dm_build_1458(bytes, 0), nil + case DOUBLE: + return Dm_build_1346.Dm_build_1462(bytes, 0), nil + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + dt := decode(bytes, column.isBdta, *column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + return toTimeFromDT(dt, int(conn.dmConnector.localTimezone)), nil + case BINARY, VARBINARY: + return bytes, nil + case BLOB: + blob := newBlobFromDB(bytes, conn, column, conn.lobFetchAll()) + + if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARBINARY") { + + l, err := blob.GetLength() + if err != nil { + return nil, err + } + return blob.getBytes(1, int32(l)) + } else { + return blob, nil + } + case CHAR, VARCHAR, VARCHAR2: + val := DB2G.charToString(bytes, column, conn) + if column.mask == MASK_BFILE { + + } + + return val, nil + case CLOB: + clob := newClobFromDB(bytes, conn, column, conn.lobFetchAll()) + if util.StringUtil.EqualsIgnoreCase(column.typeName, "LONGVARCHAR") { + + l, err := clob.GetLength() + if err != nil { + return nil, err + } + return clob.getSubString(1, int32(l)) + } else { + return clob, nil + } + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes), nil + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes), nil + case ARRAY: + return TypeDataSV.bytesToArray(bytes, nil, column.typeDescriptor) + case SARRAY: + return TypeDataSV.bytesToSArray(bytes, nil, column.typeDescriptor) + case CLASS: + + case PLTYPE_RECORD: + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (DB2G db2g) toComplexType(bytes []byte, column *column, conn *DmConnection) (interface{}, error) { + switch column.colType { + case BLOB: + if !isComplexType(int(column.colType), int(column.scale)) { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + blob := newBlobFromDB(bytes, conn, column, true) + return TypeDataSV.objBlobToObj(blob, column.typeDescriptor) + case ARRAY: + return TypeDataSV.bytesToArray(bytes, nil, column.typeDescriptor) + case SARRAY: + return TypeDataSV.bytesToSArray(bytes, nil, column.typeDescriptor) + case CLASS: + return TypeDataSV.bytesToObj(bytes, nil, column.typeDescriptor) + case PLTYPE_RECORD: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/i18n/zj.go b/dpi_bridge/third_party/chunanyong_dm/i18n/zj.go new file mode 100644 index 0000000..62b5bfd --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/i18n/zj.go @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +import ( + "encoding/json" + "golang.org/x/text/language" + "golang.org/x/text/message" +) + +type msg struct { + Id string `json:"id"` + Translation string `json:"translation,omitempty"` +} + +type i18n struct { + Language string `json:"language"` + Messages []msg `json:"messages"` +} + +func InitConfig(jsonStr string) { + + var i18n i18n + json.Unmarshal([]byte(jsonStr), &i18n) + msaArry := i18n.Messages + tag := language.MustParse(i18n.Language) + for _, e := range msaArry { + message.SetString(tag, e.Id, e.Translation) + } +} + +func Get(key string, locale int) string { + var p *message.Printer + + switch locale { + case 0: + p = message.NewPrinter(language.SimplifiedChinese) + case 1: + p = message.NewPrinter(language.AmericanEnglish) + case 2: + p = message.NewPrinter(language.TraditionalChinese) + } + + return p.Sprintf(key) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/i18n/zk.go b/dpi_bridge/third_party/chunanyong_dm/i18n/zk.go new file mode 100644 index 0000000..3cddfd1 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/i18n/zk.go @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_en_US = `{ + "language": "en-US", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN must start with dm://" + }, + { + "id": "error.dsn.invalidFormat", + "translation": "DSN is invalid" + }, + { + "id": "error.unsupported.scan", + "translation": "Unsupported scan type" + }, + { + "id": "error.invalidParameterNumber", + "translation": "Invalid parameter number" + }, + { + "id": "error.initThirdPartCipherFailed", + "translation": "Init third part cipher failed" + }, + { + "id": "error.connectionSwitchFailed", + "translation": "Connection switch failed" + }, + { + "id": "error.connectionSwitched", + "translation": "Connection has been switched" + }, + { + "id": "error.invalidServerMode", + "translation": "Invalid server mode" + }, + { + "id": "error.osauthError", + "translation": "At the same time using the specifed user login and OS authentication login, please determine a way." + }, + { + "id": "error.notQuerySQL", + "translation": "The SQL is not a query SQL" + }, + { + "id": "error.notExecSQL", + "translation": "The SQL is not a execute SQL" + }, + { + "id": "error.invalidTranIsolation", + "translation": "invalid Transaltion Isolation" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "Can't commit in Auto commit status" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "Can't rollback in Auto commit status" + }, + { + "id": "errorStatementHandleClosed", + "translation": "Statement handle is closed" + }, + { + "id": "errorResultSetColsed", + "translation": "Resultset is closed" + }, + { + "id": "error.communicationError", + "translation": "Communication error" + }, + { + "id": "error.msgCheckError", + "translation": "Message check error" + }, + { + "id": "error.unkownNetWork", + "translation": "Unkown net work" + }, + { + "id": "error.serverVersion", + "translation": "Server version is too low" + }, + { + "id": "error.usernameTooLong", + "translation": "Username is too long." + }, + { + "id": "error.passwordTooLong", + "translation": "Password to login is too long." + }, + { + "id": "error.dataTooLong", + "translation": "The data is too large to support." + }, + { + "id": "error.invalidColumnType", + "translation": "Invalid column type" + }, + { + "id": "error.dataConvertionError", + "translation": "Data convertion error" + }, + { + "id": "error.invalidConn", + "translation": "Invalid connection" + }, + { + "id": "error.invalidHex", + "translation": "Invalid Hex Number." + }, + { + "id": "error.invalidBFile", + "translation": "Invalid BFile format string." + }, + { + "id": "error.dataOverflow", + "translation": "Digital overflow" + }, + { + "id": "error.invalidDateTimeFormat", + "translation": "Invalid datetime type format" + }, + { + "id": "error.datetimeOverflow", + "translation": "Digital overflow" + }, + { + "id": "error.invalidTimeInterval", + "translation": "Invalid time interval type value" + }, + { + "id": "error.unsupportedInparamType", + "translation": "Unsupported input parameter type" + }, + { + "id": "error.unsupportedOutparamType", + "translation": "Unsupported output parameter type" + }, + { + "id": "error.unsupportedType", + "translation": "Not support this type" + }, + { + "id": "error.invalidObjBlob", + "translation": "invalid Object Blob Data." + }, + { + "id": "error.structMemNotMatch", + "translation": "Members are not matched in Record or Class" + }, + { + "id": "error.invalidComplexTypeName", + "translation": "Invalid descriptor name." + }, + { + "id": "error.invalidParamterValue", + "translation": "Invalid parameter value" + }, + { + "id": "error.invalidArrayLen", + "translation": "the length of static array is bigger than the one when defined." + }, + { + "id": "error.invalidSequenceNumber", + "translation": "Invalid sequence no" + }, + { + "id": "error.resultsetInReadOnlyStatus", + "translation": "Resultset in readonly status" + }, + { + "id": "error.SSLInitFailed", + "translation": "Failed to initialize SSL" + }, + { + "id": "error.LobDataHasFreed", + "translation": "Lob Data has been freed" + }, + { + "id": "error.fatalError", + "translation": "Fatal error" + }, + { + "id": "error.invalidLenOrOffset", + "translation": "Invalid length or offset" + }, + { + "id": "error.intervalValueOverflow", + "translation": "interval type value overflow" + }, + { + "id": "error.invalidCipher", + "translation": "Invalid cipher type" + }, + { + "id": "error.storeInNilPointer", + "translation": "Can't store value into a nil pointer" + }, + { + "id": "error.batchError", + "translation": "Error in executing with batch" + }, + { + "id": "warning.bpWithErr", + "translation": "Warning:Partial failure on execute with batch" + }, + { + "id": "error.invalidSqlType", + "translation": "Invalid sql type" + }, + { + "id": "error.invalidDateTimeValue", + "translation": "Invalid datetime value" + }, + { + "id": "error.msgTooLong", + "translation": "Message too long, limit 512M" + }, + { + "id": "error.isNull", + "translation": "Data is NULL" + }, + { + "id": "error.ParamCountLimit", + "translation": "Parameter count limit is 65536." + }, + { + "id": "error.unbindedParameter", + "translation": "Unbound parameter" + }, + { + "id": "error.stringCut", + "translation": "The string is cut" + }, + { + "id": "error.connectionClosedOrNotBuild", + "translation": "Connection is colsed or not build" + } + ] +}` diff --git a/dpi_bridge/third_party/chunanyong_dm/i18n/zl.go b/dpi_bridge/third_party/chunanyong_dm/i18n/zl.go new file mode 100644 index 0000000..9f898bf --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/i18n/zl.go @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_zh_CN = `{ + "language": "zh-Hans", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN串必须以dm://开头" + }, + { + "id": "error.dsn.invalidFormat", + "translation": "DSN串格式不正确" + }, + { + "id": "error.unsupported.scan", + "translation": "Scan类型转换出错" + }, + { + "id": "error.invalidParameterNumber", + "translation": "参数个数不匹配" + }, + { + "id": "error.initThirdPartCipherFailed", + "translation": "第三方加密初始化失败" + }, + { + "id": "error.connectionSwitchFailed", + "translation": "连接重置失败" + }, + { + "id": "error.connectionSwitched", + "translation": "连接已重置" + }, + { + "id": "error.invalidServerMode", + "translation": "服务器模式不匹配" + }, + { + "id": "error.osauthError", + "translation": "同时使用了指定用户登录和OS认证登录, 请确定一种方式." + }, + { + "id": "error.notQuerySQL", + "translation": "非查询SQL语句" + }, + { + "id": "error.notExecSQL", + "translation": "非执行SQL语句" + }, + { + "id": "error.invalidTranIsolation", + "translation": "非法的事务隔离级" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "自动提交模式下不能手动提交" + }, + { + "id": "errorRollbackInAutoCommitMode", + "translation": "自动提交模式下不能手动回滚" + }, + { + "id": "errorStatementHandleClosed", + "translation": "语句已经关闭" + }, + { + "id": "errorResultSetColsed", + "translation": "结果集已经关闭" + }, + { + "id": "error.communicationError", + "translation": "网络通信异常" + }, + { + "id": "error.msgCheckError", + "translation": "消息校验异常" + }, + { + "id": "error.unkownNetWork", + "translation": "未知的网络" + }, + { + "id": "error.serverVersion", + "translation": "服务器版本太低" + }, + { + "id": "error.usernameTooLong", + "translation": "用户名超长" + }, + { + "id": "error.passwordTooLong", + "translation": "密码超长" + }, + { + "id": "error.dataTooLong", + "translation": "数据大小已超过可支持范围" + }, + { + "id": "error.invalidColumnType", + "translation": "无效的列类型" + }, + { + "id": "error.dataConvertionError", + "translation": "类型转换异常" + }, + { + "id": "error.invalidConn", + "translation": "连接失效" + }, + { + "id": "error.invalidHex", + "translation": "无效的十六进制数字" + }, + { + "id": "error.invalidBFile", + "translation": "无效的BFile格式串" + }, + { + "id": "error.dataOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidDateTimeFormat", + "translation": "错误的日期时间类型格式" + }, + { + "id": "error.datetimeOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidTimeInterval", + "translation": "错误的时间间隔类型数据" + }, + { + "id": "error.unsupportedInparamType", + "translation": "输入参数类型不支持" + }, + { + "id": "error.unsupportedOutparamType", + "translation": "输出参数类型不支持" + }, + { + "id": "error.unsupportedType", + "translation": "不支持该数据类型" + }, + { + "id": "error.invalidObjBlob", + "translation": "无效的对象BLOB数据" + }, + { + "id": "error.structMemNotMatch", + "translation": "记录或类数据成员不匹配" + }, + { + "id": "error.invalidComplexTypeName", + "translation": "无效的类型描述名称" + }, + { + "id": "error.invalidParamterValue", + "translation": "无效的参数值" + }, + { + "id": "error.invalidArrayLen", + "translation": "静态数组长度大于定义时长度" + }, + { + "id": "error.invalidSequenceNumber", + "translation": "无效的列序号" + }, + { + "id": "error.resultsetInReadOnlyStatus", + "translation": "结果集处于只读状态" + }, + { + "id": "error.SSLInitFailed", + "translation": "初始化SSL环境失败" + }, + { + "id": "error.LobDataHasFreed", + "translation": "LOB数据已经被释放" + }, + { + "id": "error.fatalError", + "translation": "致命错误" + }, + { + "id": "error.invalidLenOrOffset", + "translation": "长度或偏移错误" + }, + { + "id": "error.intervalValueOverflow", + "translation": "时间间隔类型数据溢出" + }, + { + "id": "error.invalidCipher", + "translation": "不支持的加密类型" + }, + { + "id": "error.storeInNilPointer", + "translation": "无法将数据存入空指针" + }, + { + "id": "error.batchError", + "translation": "批量执行出错" + }, + { + "id": "warning.bpWithErr", + "translation": "警告:批量执行部分行产生错误" + }, + { + "id": "error.invalidSqlType", + "translation": "非法的SQL语句类型" + }, + { + "id": "error.invalidDateTimeValue", + "translation": "无效的日期时间类型值" + }, + { + "id": "error.msgTooLong", + "translation": "消息长度超出限制512M" + }, + { + "id": "error.isNull", + "translation": "数据为NULL" + }, + { + "id": "error.ParamCountLimit", + "translation": "参数个数超过最大值65536." + }, + { + "id": "error.unbindedParameter", + "translation": "有参数未绑定" + }, + { + "id": "error.stringCut", + "translation": "字符串截断" + }, + { + "id": "error.connectionClosedOrNotBuild", + "translation": "连接尚未建立或已经关闭" + } + ] +}` diff --git a/dpi_bridge/third_party/chunanyong_dm/i18n/zm.go b/dpi_bridge/third_party/chunanyong_dm/i18n/zm.go new file mode 100644 index 0000000..8a97415 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/i18n/zm.go @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package i18n + +const Messages_zh_HK = `{ + "language": "zh-Hant", + "messages": [ + { + "id": "error.dsn.invalidSchema", + "translation": "DSN串必須以dm://開頭" + }, + { + "id": "error.dsn.invalidFormat", + "translation": "DSN串格式不正確" + }, + { + "id": "error.unsupported.scan", + "translation": "Scan類型轉換出錯" + }, + { + "id": "error.invalidParameterNumber", + "translation": "參數個數不匹配" + }, + { + "id": "error.initThirdPartCipherFailed", + "translation": "第三方加密初始化失敗" + }, + { + "id": "error.connectionSwitchFailed", + "translation": "連接重置失敗" + }, + { + "id": "error.connectionSwitched", + "translation": "連接已重置" + }, + { + "id": "error.invalidServerMode", + "translation": "服務器模式不匹配" + }, + { + "id": "error.osauthError", + "translation": "同時使用了指定用戶登錄和OS認證登錄, 請確定一種方式." + }, + { + "id": "error.notQuerySQL", + "translation": "非查詢SQL語句" + }, + { + "id": "error.notExecSQL", + "translation": "非執行SQL語句" + }, + { + "id": "error.invalidTranIsolation", + "translation": "非法的事務隔離級" + }, + { + "id": "errorCommitInAutoCommitMode", + "translation": "自動提交模式下不能手動提交" + }, + { + "id": "errorRollbackInAutoCommitMode", + "translation": "自動提交模式下不能手動回滾" + }, + { + "id": "errorStatementHandleClosed", + "translation": "語句已經關閉" + }, + { + "id": "errorResultSetColsed", + "translation": "結果集已經關閉" + }, + { + "id": "error.communicationError", + "translation": "網絡通信異常" + }, + { + "id": "error.msgCheckError", + "translation": "消息校驗異常" + }, + { + "id": "error.unkownNetWork", + "translation": "未知的網絡" + }, + { + "id": "error.serverVersion", + "translation": "服務器版本太低" + }, + { + "id": "error.usernameTooLong", + "translation": "用戶名超長" + }, + { + "id": "error.passwordTooLong", + "translation": "密碼超長" + }, + { + "id": "error.dataTooLong", + "translation": "數據大小已超過可支持範圍" + }, + { + "id": "error.invalidColumnType", + "translation": "無效的列類型" + }, + { + "id": "error.dataConvertionError", + "translation": "類型轉換異常" + }, + { + "id": "error.invalidConn", + "translation": "連接失效" + }, + { + "id": "error.invalidHex", + "translation": "無效的十六進制数字" + }, + { + "id": "error.invalidBFile", + "translation": "無效的BFile格式串" + }, + { + "id": "error.dataOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidDateTimeFormat", + "translation": "錯誤的日期時間類型格式" + }, + { + "id": "error.datetimeOverflow", + "translation": "数字溢出" + }, + { + "id": "error.invalidTimeInterval", + "translation": "錯誤的時間間隔類型數據" + }, + { + "id": "error.unsupportedInparamType", + "translation": "輸入參數類型不支持" + }, + { + "id": "error.unsupportedOutparamType", + "translation": "輸出參數類型不支持" + }, + { + "id": "error.unsupportedType", + "translation": "不支持該數據類型" + }, + { + "id": "error.invalidObjBlob", + "translation": "無效的對象BLOB數據" + }, + { + "id": "error.structMemNotMatch", + "translation": "記錄或類數據成員不匹配" + }, + { + "id": "error.invalidComplexTypeName", + "translation": "無效的類型描述名稱" + }, + { + "id": "error.invalidParamterValue", + "translation": "無效的參數值" + }, + { + "id": "error.invalidArrayLen", + "translation": "靜態數組長度大於定義時長度" + }, + { + "id": "error.invalidSequenceNumber", + "translation": "無效的列序號" + }, + { + "id": "error.resultsetInReadOnlyStatus", + "translation": "結果集處於只讀狀態" + }, + { + "id": "error.SSLInitFailed", + "translation": "初始化SSL環境失敗" + }, + { + "id": "error.LobDataHasFreed", + "translation": "LOB數據已經被釋放" + }, + { + "id": "error.fatalError", + "translation": "致命錯誤" + }, + { + "id": "error.invalidLenOrOffset", + "translation": "長度或偏移錯誤" + }, + { + "id": "error.intervalValueOverflow", + "translation": "時間間隔類型數據溢出" + }, + { + "id": "error.invalidCipher", + "translation": "不支持的加密類型" + }, + { + "id": "error.storeInNilPointer", + "translation": "無法將數據存入空指針" + }, + { + "id": "error.batchError", + "translation": "批量執行出錯" + }, + { + "id": "warning.bpWithErr", + "translation": "警告:批量執行部分行產生錯誤" + }, + { + "id": "error.invalidSqlType", + "translation": "非法的SQL語句類型" + }, + { + "id": "error.invalidDateTimeValue", + "translation": "無效的日期時間類型值" + }, + { + "id": "error.msgTooLong", + "translation": "消息長度超出限制512M" + }, + { + "id": "error.isNull", + "translation": "數據為NULL" + }, + { + "id": "error.ParamCountLimit", + "translation": "參數個數超過最大值65536." + }, + { + "id": "error.unbindedParameter", + "translation": "有參數未綁定" + }, + { + "id": "error.stringCut", + "translation": "字符串截斷" + }, + { + "id": "error.connectionClosedOrNotBuild", + "translation": "連接尚未建立或已經關閉" + } + ] +}` \ No newline at end of file diff --git a/dpi_bridge/third_party/chunanyong_dm/j.go b/dpi_bridge/third_party/chunanyong_dm/j.go new file mode 100644 index 0000000..2617e12 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/j.go @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import "database/sql/driver" + +type DmArray struct { + TypeData + m_arrDesc *ArrayDescriptor // 数组的描述信息 + + m_arrData []TypeData // 数组中各行数据值 + + m_objArray interface{} // 从服务端获取的 + + m_itemCount int // 本次获取的行数 + + m_itemSize int // 数组中一个数组项的大小,单位bytes + + m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组) + + m_strCount int // 一个数组项中存在字符串类型的个数 + + m_objStrOffs []int // 对象在前,字符串在后 + + typeName string + + elements []interface{} + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +func (da *DmArray) init() *DmArray { + da.initTypeData() + da.m_itemCount = 0 + da.m_itemSize = 0 + da.m_objCount = 0 + da.m_strCount = 0 + da.m_objStrOffs = nil + da.m_dumyData = nil + da.m_offset = 0 + + da.m_objArray = nil + da.Valid = true + return da +} + +// 数据库自定义数组Array构造函数,typeName为库中定义的数组类型名称,elements为该数组类型的每个值 +// +// 例如,自定义数组类型语句为:create or replace type myArray is array int[]; +// +// 则绑入绑出的go对象为: val := dm.NewDmArray("myArray", []interface{} {123, 456}) +func NewDmArray(typeName string, elements []interface{}) *DmArray { + da := new(DmArray) + da.typeName = typeName + da.elements = elements + da.Valid = true + return da +} + +func (da *DmArray) create(dc *DmConnection) (*DmArray, error) { + desc, err := newArrayDescriptor(da.typeName, dc) + if err != nil { + return nil, err + } + return da.createByArrayDescriptor(desc, dc) +} + +func (da *DmArray) createByArrayDescriptor(arrDesc *ArrayDescriptor, conn *DmConnection) (*DmArray, error) { + + if nil == arrDesc { + return nil, ECGO_INVALID_PARAMETER_VALUE.throw() + } + + da.init() + + da.m_arrDesc = arrDesc + if nil == da.elements { + da.m_arrData = make([]TypeData, 0) + } else { + // 若为静态数组,判断给定数组长度是否超过静态数组的上限 + if arrDesc.getMDesc() == nil || (arrDesc.getMDesc().getDType() == SARRAY && len(da.elements) > arrDesc.getMDesc().getStaticArrayLength()) { + return nil, ECGO_INVALID_ARRAY_LEN.throw() + } + + var err error + da.m_arrData, err = TypeDataSV.toArray(da.elements, da.m_arrDesc.getMDesc()) + if err != nil { + return nil, err + } + } + + da.m_itemCount = len(da.m_arrData) + return da, nil +} + +func newDmArrayByTypeData(atData []TypeData, desc *TypeDescriptor) *DmArray { + da := new(DmArray) + da.init() + da.m_arrDesc = newArrayDescriptorByTypeDescriptor(desc) + da.m_arrData = atData + return da +} + +func (da *DmArray) checkIndex(index int64) error { + if index < 0 || index > int64(len(da.m_arrData)-1) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return nil +} + +func (da *DmArray) checkIndexAndCount(index int64, count int) error { + err := da.checkIndex(index) + if err != nil { + return err + } + + if count <= 0 || index+int64(count) > int64(len(da.m_arrData)) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return nil +} + +// 获取Array对象在数据库中的类型名称 +func (da *DmArray) GetBaseTypeName() (string, error) { + if err := da.checkValid(); err != nil { + return "", err + } + return da.m_arrDesc.m_typeDesc.getFulName() +} + +// 获取Array对象的go数组对象 +func (da *DmArray) GetArray() (interface{}, error) { + if da.m_arrData == nil || len(da.m_arrData) <= 0 { + return nil, nil; + } + + return TypeDataSV.toJavaArray(da, 0, len(da.m_arrData), da.m_arrDesc.getItemDesc().getDType()) +} + +// 获取Array对象的指定偏移和执行长度go数据对象 index从0开始 +func (da *DmArray) GetObjArray(index int64, count int) (interface{}, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + return TypeDataSV.toJavaArray(da, index, count, da.m_arrDesc.getItemDesc().getDType()) +} + +func (da *DmArray) GetIntArray(index int64, count int) ([]int, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_INTEGER) + if err != nil { + return nil, err + } + return tmp.([]int), nil +} + +func (da *DmArray) GetInt16Array(index int64, count int) ([]int16, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_SHORT) + if err != nil { + return nil, err + } + return tmp.([]int16), nil +} + +func (da *DmArray) GetInt64Array(index int64, count int) ([]int64, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_LONG) + if err != nil { + return nil, err + } + + return tmp.([]int64), nil +} + +func (da *DmArray) GetFloatArray(index int64, count int) ([]float32, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_FLOAT) + if err != nil { + return nil, err + } + + return tmp.([]float32), nil +} + +func (da *DmArray) GetDoubleArray(index int64, count int) ([]float64, error) { + var err error + if err = da.checkValid(); err != nil { + return nil, err + } + if err = da.checkIndexAndCount(index, count); err != nil { + return nil, err + } + + tmp, err := TypeDataSV.toNumericArray(da, index, count, ARRAY_TYPE_DOUBLE) + if err != nil { + return nil, err + } + + return tmp.([]float64), nil +} + +func (dest *DmArray) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmArray) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmArray: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (array DmArray) Value() (driver.Value, error) { + if !array.Valid { + return nil, nil + } + return array, nil +} + +func (array *DmArray) checkValid() error { + if !array.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/k.go b/dpi_bridge/third_party/chunanyong_dm/k.go new file mode 100644 index 0000000..c2a5992 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/k.go @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "io" +) + +type DmBlob struct { + lob + data []byte + offset int64 +} + +func newDmBlob() *DmBlob { + return &DmBlob{ + lob: lob{ + inRow: true, + groupId: -1, + fileId: -1, + pageNo: -1, + readOver: false, + local: true, + updateable: true, + length: -1, + compatibleOracle: false, + fetchAll: false, + freed: false, + modify: false, + Valid: true, + }, + offset: 1, + } +} + +func newBlobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmBlob { + var blob = newDmBlob() + blob.connection = conn + blob.lobFlag = LOB_FLAG_BYTE + blob.compatibleOracle = conn.CompatibleOracle() + blob.local = false + blob.updateable = !column.readonly + blob.tabId = column.lobTabId + blob.colId = column.lobColId + + blob.inRow = Dm_build_1346.Dm_build_1439(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW + blob.blobId = Dm_build_1346.Dm_build_1453(value, NBLOB_HEAD_BLOBID) + if !blob.inRow { + blob.groupId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_GROUPID) + blob.fileId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_FILEID) + blob.pageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_HEAD_OUTROW_PAGENO) + } + if conn.NewLobFlag { + blob.tabId = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_TABLE_ID) + blob.colId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_COL_ID) + blob.rowId = Dm_build_1346.Dm_build_1453(value, NBLOB_EX_HEAD_ROW_ID) + blob.exGroupId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_GRPID) + blob.exFileId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_FILEID) + blob.exPageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_FPA_PAGENO) + } + blob.resetCurrentInfo() + + blob.length = blob.getLengthFromHead(value) + if blob.inRow { + blob.data = make([]byte, blob.length) + if conn.NewLobFlag { + Dm_build_1346.Dm_build_1402(blob.data, 0, value, NBLOB_EX_HEAD_SIZE, len(blob.data)) + } else { + Dm_build_1346.Dm_build_1402(blob.data, 0, value, NBLOB_INROW_HEAD_SIZE, len(blob.data)) + } + } else if fetchAll { + blob.loadAllData() + } + return blob +} + +func newBlobOfLocal(value []byte, conn *DmConnection) *DmBlob { + var blob = newDmBlob() + blob.connection = conn + blob.lobFlag = LOB_FLAG_BYTE + blob.data = value + blob.length = int64(len(blob.data)) + return blob +} + +func NewBlob(value []byte) *DmBlob { + var blob = newDmBlob() + + blob.lobFlag = LOB_FLAG_BYTE + blob.data = value + blob.length = int64(len(blob.data)) + return blob +} + +func (blob *DmBlob) Read(dest []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + result, err := blob.getBytes(blob.offset, int32(len(dest))) + if err != nil { + return 0, err + } + blob.offset += int64(len(result)) + copy(dest, result) + if len(result) == 0 { + return 0, io.EOF + } + return len(result), nil +} + +func (blob *DmBlob) ReadAt(pos int, dest []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + result, err := blob.getBytes(int64(pos), int32(len(dest))) + if err != nil { + return 0, err + } + if len(result) == 0 { + return 0, io.EOF + } + copy(dest[0:len(result)], result) + return len(result), nil +} + +func (blob *DmBlob) Write(pos int, src []byte) (n int, err error) { + if err = blob.checkValid(); err != nil { + return + } + if err = blob.checkFreed(); err != nil { + return + } + if pos < 1 { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + if !blob.updateable { + err = ECGO_RESULTSET_IS_READ_ONLY.throw() + return + } + pos -= 1 + if blob.local || blob.fetchAll { + if int64(pos) > blob.length { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + blob.setLocalData(pos, src) + n = len(src) + } else { + if err = blob.connection.checkClosed(); err != nil { + return -1, err + } + var writeLen, err = blob.connection.Access.dm_build_638(blob, pos, src) + if err != nil { + return -1, err + } + + if blob.groupId == -1 { + blob.setLocalData(pos, src) + } else { + blob.inRow = false + blob.length = -1 + } + n = writeLen + + } + blob.modify = true + return +} + +func (blob *DmBlob) Truncate(length int64) error { + var err error + if err = blob.checkValid(); err != nil { + return err + } + if err = blob.checkFreed(); err != nil { + return err + } + if length < 0 { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if !blob.updateable { + return ECGO_RESULTSET_IS_READ_ONLY.throw() + } + if blob.local || blob.fetchAll { + if length > int64(len(blob.data)) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if length == int64(len(blob.data)) { + return nil + } + tmp := make([]byte, length) + Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, len(tmp)) + blob.data = tmp + blob.length = int64(len(tmp)) + } else { + if err = blob.connection.checkClosed(); err != nil { + return err + } + blob.length, err = blob.connection.Access.dm_build_652(&blob.lob, int(length)) + if err != nil { + return err + } + if blob.groupId == -1 { + tmp := make([]byte, blob.length) + Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, int(blob.length)) + blob.data = tmp + } + } + blob.modify = true + return nil +} + +func (dest *DmBlob) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmBlob) + + (*dest).Valid = false + return nil + case []byte: + *dest = *NewBlob(src) + return nil + case *DmBlob: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (blob DmBlob) Value() (driver.Value, error) { + if !blob.Valid { + return nil, nil + } + return blob, nil +} + +func (blob *DmBlob) getBytes(pos int64, length int32) ([]byte, error) { + var err error + var leaveLength int64 + if err = blob.checkFreed(); err != nil { + return nil, err + } + if pos < 1 || length < 0 { + return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + pos = pos - 1 + if leaveLength, err = blob.GetLength(); err != nil { + return nil, err + } + leaveLength -= pos + if leaveLength < 0 { + return nil, ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if int64(length) > leaveLength { + length = int32(leaveLength) + } + if blob.local || blob.inRow || blob.fetchAll { + return blob.data[pos : pos+int64(length)], nil + } else { + + return blob.connection.Access.dm_build_599(blob, int32(pos), length) + } +} + +func (blob *DmBlob) loadAllData() { + blob.checkFreed() + if blob.local || blob.inRow || blob.fetchAll { + return + } + len, _ := blob.GetLength() + blob.data, _ = blob.getBytes(1, int32(len)) + blob.fetchAll = true +} + +func (blob *DmBlob) setLocalData(pos int, p []byte) { + if pos+len(p) >= int(blob.length) { + var tmp = make([]byte, pos+len(p)) + Dm_build_1346.Dm_build_1402(tmp, 0, blob.data, 0, pos) + Dm_build_1346.Dm_build_1402(tmp, pos, p, 0, len(p)) + blob.data = tmp + } else { + Dm_build_1346.Dm_build_1402(blob.data, pos, p, 0, len(p)) + } + blob.length = int64(len(blob.data)) +} + +func (d *DmBlob) GormDataType() string { + return "BLOB" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/l.go b/dpi_bridge/third_party/chunanyong_dm/l.go new file mode 100644 index 0000000..30fb511 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/l.go @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "io" +) + +type DmClob struct { + lob + data []rune + serverEncoding string +} + +func newDmClob() *DmClob { + return &DmClob{ + lob: lob{ + inRow: true, + groupId: -1, + fileId: -1, + pageNo: -1, + readOver: false, + local: true, + updateable: true, + length: -1, + compatibleOracle: false, + fetchAll: false, + freed: false, + modify: false, + Valid: true, + }, + } +} + +func newClobFromDB(value []byte, conn *DmConnection, column *column, fetchAll bool) *DmClob { + var clob = newDmClob() + clob.connection = conn + clob.lobFlag = LOB_FLAG_CHAR + clob.compatibleOracle = conn.CompatibleOracle() + clob.local = false + clob.updateable = !column.readonly + clob.tabId = column.lobTabId + clob.colId = column.lobColId + + clob.inRow = Dm_build_1346.Dm_build_1439(value, NBLOB_HEAD_IN_ROW_FLAG) == LOB_IN_ROW + clob.blobId = Dm_build_1346.Dm_build_1453(value, NBLOB_HEAD_BLOBID) + if !clob.inRow { + clob.groupId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_GROUPID) + clob.fileId = Dm_build_1346.Dm_build_1443(value, NBLOB_HEAD_OUTROW_FILEID) + clob.pageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_HEAD_OUTROW_PAGENO) + } + if conn.NewLobFlag { + clob.tabId = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_TABLE_ID) + clob.colId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_COL_ID) + clob.rowId = Dm_build_1346.Dm_build_1453(value, NBLOB_EX_HEAD_ROW_ID) + clob.exGroupId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_GRPID) + clob.exFileId = Dm_build_1346.Dm_build_1443(value, NBLOB_EX_HEAD_FPA_FILEID) + clob.exPageNo = Dm_build_1346.Dm_build_1448(value, NBLOB_EX_HEAD_FPA_PAGENO) + } + clob.resetCurrentInfo() + + clob.serverEncoding = conn.getServerEncoding() + if clob.inRow { + if conn.NewLobFlag { + clob.data = []rune(Dm_build_1346.Dm_build_1503(value, NBLOB_EX_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn)) + } else { + clob.data = []rune(Dm_build_1346.Dm_build_1503(value, NBLOB_INROW_HEAD_SIZE, int(clob.getLengthFromHead(value)), clob.serverEncoding, conn)) + } + clob.length = int64(len(clob.data)) + } else if fetchAll { + clob.loadAllData() + } + return clob +} + +func newClobOfLocal(value string, conn *DmConnection) *DmClob { + var clob = newDmClob() + clob.connection = conn + clob.lobFlag = LOB_FLAG_CHAR + clob.data = []rune(value) + clob.length = int64(len(clob.data)) + return clob +} + +func NewClob(value string) *DmClob { + var clob = newDmClob() + + clob.lobFlag = LOB_FLAG_CHAR + clob.data = []rune(value) + clob.length = int64(len(clob.data)) + return clob +} + +func (clob *DmClob) ReadString(pos int, length int) (result string, err error) { + if err = clob.checkValid(); err != nil { + return + } + result, err = clob.getSubString(int64(pos), int32(length)) + if err != nil { + return + } + if len(result) == 0 { + err = io.EOF + return + } + return +} + +func (clob *DmClob) WriteString(pos int, s string) (n int, err error) { + if err = clob.checkValid(); err != nil { + return + } + if err = clob.checkFreed(); err != nil { + return + } + if pos < 1 { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + if !clob.updateable { + err = ECGO_RESULTSET_IS_READ_ONLY.throw() + return + } + pos -= 1 + if clob.local || clob.fetchAll { + if int64(pos) > clob.length { + err = ECGO_INVALID_LENGTH_OR_OFFSET.throw() + return + } + clob.setLocalData(pos, s) + n = len(s) + } else { + if err = clob.connection.checkClosed(); err != nil { + return -1, err + } + var writeLen, err = clob.connection.Access.dm_build_622(clob, pos, s, clob.serverEncoding) + if err != nil { + return -1, err + } + + if clob.groupId == -1 { + clob.setLocalData(pos, s) + } else { + clob.inRow = false + clob.length = -1 + } + n = writeLen + } + clob.modify = true + return +} + +func (clob *DmClob) Truncate(length int64) error { + var err error + if err = clob.checkValid(); err != nil { + return err + } + if err = clob.checkFreed(); err != nil { + return err + } + if length < 0 { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if !clob.updateable { + return ECGO_RESULTSET_IS_READ_ONLY.throw() + } + if clob.local || clob.fetchAll { + if length > int64(len(clob.data)) { + return ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if length == int64(len(clob.data)) { + return nil + } + clob.data = clob.data[0:length] + clob.length = int64(len(clob.data)) + } else { + if err = clob.connection.checkClosed(); err != nil { + return err + } + clob.length, err = clob.connection.Access.dm_build_652(&clob.lob, int(length)) + if err != nil { + return err + } + if clob.groupId == -1 { + clob.data = clob.data[0:clob.length] + } + } + clob.modify = true + return nil +} + +func (dest *DmClob) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmClob) + + (*dest).Valid = false + return nil + case string: + *dest = *NewClob(src) + return nil + case *DmClob: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (clob DmClob) Value() (driver.Value, error) { + if !clob.Valid { + return nil, nil + } + return clob, nil +} + +func (clob *DmClob) getSubString(pos int64, len int32) (string, error) { + var err error + var leaveLength int64 + if err = clob.checkFreed(); err != nil { + return "", err + } + if pos < 1 || len < 0 { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + pos = pos - 1 + if leaveLength, err = clob.GetLength(); err != nil { + return "", err + } + if pos > leaveLength { + pos = leaveLength + } + leaveLength -= pos + if leaveLength < 0 { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + if int64(len) > leaveLength { + len = int32(leaveLength) + } + if clob.local || clob.inRow || clob.fetchAll { + if pos > clob.length { + return "", ECGO_INVALID_LENGTH_OR_OFFSET.throw() + } + return string(clob.data[pos : pos+int64(len)]), nil + } else { + + return clob.connection.Access.dm_build_610(clob, int32(pos), len) + } +} + +func (clob *DmClob) loadAllData() { + clob.checkFreed() + if clob.local || clob.inRow || clob.fetchAll { + return + } + len, _ := clob.GetLength() + s, _ := clob.getSubString(1, int32(len)) + clob.data = []rune(s) + clob.fetchAll = true +} + +func (clob *DmClob) setLocalData(pos int, str string) { + if pos+len(str) >= int(clob.length) { + clob.data = []rune(string(clob.data[0:pos]) + str) + } else { + clob.data = []rune(string(clob.data[0:pos]) + str + string(clob.data[pos+len(str):len(clob.data)])) + } + clob.length = int64(len(clob.data)) +} + +func (d *DmClob) GormDataType() string { + return "CLOB" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/m.go b/dpi_bridge/third_party/chunanyong_dm/m.go new file mode 100644 index 0000000..9f0be6e --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/m.go @@ -0,0 +1,874 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "context" + "database/sql" + "database/sql/driver" + "fmt" + "sync" + "sync/atomic" + + "gitee.com/chunanyong/dm/parser" + + "gitee.com/chunanyong/dm/util" + "golang.org/x/text/encoding" +) + +type DmConnection struct { + filterable + mu sync.Mutex + + dmConnector *DmConnector + Access *dm_build_414 + stmtMap map[int32]*DmStatement + + lastExecInfo *execRetInfo + lexer *parser.Lexer + encode encoding.Encoding + encodeBuffer *bytes.Buffer + transformReaderDst []byte + transformReaderSrc []byte + + serverEncoding string + GlobalServerSeries int + ServerVersion string + Malini2 bool + Execute2 bool + LobEmptyCompOrcl bool + IsoLevel int32 + ReadOnly bool + NewLobFlag bool + sslEncrypt int + MaxRowSize int32 + DDLAutoCommit bool + BackSlashFlag bool + SvrStat int32 + SvrMode int32 + ConstParaOpt bool + DbTimezone int16 + LifeTimeRemainder int16 + InstanceName string + Schema string + LastLoginIP string + LastLoginTime string + FailedAttempts int32 + LoginWarningID int32 + GraceTimeRemainder int32 + Guid string + DbName string + StandbyHost string + StandbyPort int32 + StandbyCount int32 + SessionID int64 + OracleDateLanguage byte + FormatDate string + FormatTimestamp string + FormatTimestampTZ string + FormatTime string + FormatTimeTZ string + Local bool + MsgVersion int32 + TrxStatus int32 + dscControl bool + trxFinish bool + autoCommit bool + isBatch bool + + watching bool + watcher chan<- context.Context + closech chan struct{} + finished chan<- struct{} + canceled atomicError + closed atomicBool +} + +func (conn *DmConnection) setTrxFinish(status int32) { + switch status & Dm_build_825 { + case Dm_build_822, Dm_build_823, Dm_build_824: + conn.trxFinish = true + default: + conn.trxFinish = false + } +} + +func (dmConn *DmConnection) init() { + + dmConn.stmtMap = make(map[int32]*DmStatement) + dmConn.DbTimezone = 0 + dmConn.GlobalServerSeries = 0 + dmConn.MaxRowSize = 0 + dmConn.LobEmptyCompOrcl = false + dmConn.ReadOnly = false + dmConn.DDLAutoCommit = false + dmConn.ConstParaOpt = false + dmConn.IsoLevel = -1 + dmConn.Malini2 = true + dmConn.NewLobFlag = true + dmConn.Execute2 = true + dmConn.serverEncoding = ENCODING_GB18030 + dmConn.TrxStatus = Dm_build_773 + dmConn.setTrxFinish(dmConn.TrxStatus) + dmConn.OracleDateLanguage = byte(Locale) + dmConn.lastExecInfo = NewExceInfo() + dmConn.MsgVersion = Dm_build_706 + + dmConn.idGenerator = dmConnIDGenerator +} + +func (dmConn *DmConnection) reset() { + dmConn.DbTimezone = 0 + dmConn.GlobalServerSeries = 0 + dmConn.MaxRowSize = 0 + dmConn.LobEmptyCompOrcl = false + dmConn.ReadOnly = false + dmConn.DDLAutoCommit = false + dmConn.ConstParaOpt = false + dmConn.IsoLevel = -1 + dmConn.Malini2 = true + dmConn.NewLobFlag = true + dmConn.Execute2 = true + dmConn.serverEncoding = ENCODING_GB18030 + dmConn.TrxStatus = Dm_build_773 + dmConn.setTrxFinish(dmConn.TrxStatus) +} + +func (dc *DmConnection) checkClosed() error { + if dc.closed.IsSet() { + return driver.ErrBadConn + } + + return nil +} + +func (dc *DmConnection) executeInner(query string, execType int16) (interface{}, error) { + + stmt, err := NewDmStmt(dc, query) + + if err != nil { + return nil, err + } + + if execType == Dm_build_790 { + defer stmt.close() + } + + stmt.innerUsed = true + + var escapeSql = query + if stmt.dmConn.dmConnector.escapeProcess { + escapeSql, err = stmt.dmConn.escape(escapeSql, stmt.dmConn.dmConnector.keyWords) + if err != nil { + stmt.close() + return nil, err + } + } + stmt.nativeSql = escapeSql + + var optParamList []OptParameter + + if stmt.dmConn.ConstParaOpt { + optParamList = make([]OptParameter, 0) + stmt.nativeSql, optParamList, err = stmt.dmConn.execOpt(stmt.nativeSql, optParamList, stmt.dmConn.getServerEncoding(), stmt.dmConn.BackSlashFlag) + } + + if execType == Dm_build_789 && dc.dmConnector.enRsCache { + rpv, err := rp.get(stmt, query) + if err != nil { + return nil, err + } + + if rpv != nil { + stmt.execInfo = rpv.execInfo + dc.lastExecInfo = rpv.execInfo + return newDmRows(rpv.getResultSet(stmt)), nil + } + } + + var info *execRetInfo + + if optParamList != nil && len(optParamList) > 0 { + info, err = dc.Access.Dm_build_497(stmt, optParamList) + if err != nil { + stmt.nativeSql = escapeSql + info, err = dc.Access.Dm_build_503(stmt, execType) + } + } else { + info, err = dc.Access.Dm_build_503(stmt, execType) + } + + if err != nil { + stmt.close() + return nil, err + } + dc.lastExecInfo = info + + if execType == Dm_build_789 && info.hasResultSet { + return newDmRows(newInnerRows(0, stmt, info)), nil + } else { + return newDmResult(stmt, info), nil + } +} + +func g2dbIsoLevel(isoLevel int32) int32 { + switch isoLevel { + case 1: + return Dm_build_777 + case 2: + return Dm_build_778 + case 4: + return Dm_build_779 + case 6: + return Dm_build_780 + default: + return -1 + } +} + +func (dc *DmConnection) Begin() (driver.Tx, error) { + if len(dc.filterChain.filters) == 0 { + return dc.begin() + } else { + return dc.filterChain.reset().DmConnectionBegin(dc) + } +} + +func (dc *DmConnection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if len(dc.filterChain.filters) == 0 { + return dc.beginTx(ctx, opts) + } + return dc.filterChain.reset().DmConnectionBeginTx(dc, ctx, opts) +} + +func (dc *DmConnection) Commit() error { + if len(dc.filterChain.filters) == 0 { + return dc.commit() + } else { + return dc.filterChain.reset().DmConnectionCommit(dc) + } +} + +func (dc *DmConnection) Rollback() error { + if len(dc.filterChain.filters) == 0 { + return dc.rollback() + } else { + return dc.filterChain.reset().DmConnectionRollback(dc) + } +} + +func (dc *DmConnection) Close() error { + if len(dc.filterChain.filters) == 0 { + return dc.close() + } else { + return dc.filterChain.reset().DmConnectionClose(dc) + } +} + +func (dc *DmConnection) Ping(ctx context.Context) error { + if len(dc.filterChain.filters) == 0 { + return dc.ping(ctx) + } else { + return dc.filterChain.reset().DmConnectionPing(dc, ctx) + } +} + +func (dc *DmConnection) Exec(query string, args []driver.Value) (driver.Result, error) { + if len(dc.filterChain.filters) == 0 { + return dc.exec(query, args) + } + return dc.filterChain.reset().DmConnectionExec(dc, query, args) +} + +func (dc *DmConnection) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + if len(dc.filterChain.filters) == 0 { + return dc.execContext(ctx, query, args) + } + return dc.filterChain.reset().DmConnectionExecContext(dc, ctx, query, args) +} + +func (dc *DmConnection) Query(query string, args []driver.Value) (driver.Rows, error) { + if len(dc.filterChain.filters) == 0 { + return dc.query(query, args) + } + return dc.filterChain.reset().DmConnectionQuery(dc, query, args) +} + +func (dc *DmConnection) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + if len(dc.filterChain.filters) == 0 { + return dc.queryContext(ctx, query, args) + } + return dc.filterChain.reset().DmConnectionQueryContext(dc, ctx, query, args) +} + +func (dc *DmConnection) Prepare(query string) (driver.Stmt, error) { + if len(dc.filterChain.filters) == 0 { + return dc.prepare(query) + } + return dc.filterChain.reset().DmConnectionPrepare(dc, query) +} + +func (dc *DmConnection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if len(dc.filterChain.filters) == 0 { + return dc.prepareContext(ctx, query) + } + return dc.filterChain.reset().DmConnectionPrepareContext(dc, ctx, query) +} + +func (dc *DmConnection) ResetSession(ctx context.Context) error { + if len(dc.filterChain.filters) == 0 { + return dc.resetSession(ctx) + } + if err := dc.filterChain.reset().DmConnectionResetSession(dc, ctx); err != nil { + return driver.ErrBadConn + } else { + return nil + } +} + +func (dc *DmConnection) CheckNamedValue(nv *driver.NamedValue) error { + if len(dc.filterChain.filters) == 0 { + return dc.checkNamedValue(nv) + } + return dc.filterChain.reset().DmConnectionCheckNamedValue(dc, nv) +} + +func (dc *DmConnection) begin() (*DmConnection, error) { + return dc.beginTx(context.Background(), driver.TxOptions{driver.IsolationLevel(sql.LevelDefault), false}) +} + +func (dc *DmConnection) beginTx(ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + dc.autoCommit = false + + if dc.ReadOnly != opts.ReadOnly { + dc.ReadOnly = opts.ReadOnly + var readonly = 0 + if opts.ReadOnly { + readonly = 1 + } + dc.exec(fmt.Sprintf("SP_SET_SESSION_READONLY(%d)", readonly), nil) + } + + if dc.IsoLevel != int32(opts.Isolation) { + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + dc.IsoLevel = int32(sql.LevelReadCommitted) + case sql.LevelReadUncommitted, sql.LevelReadCommitted, sql.LevelSerializable: + dc.IsoLevel = int32(opts.Isolation) + case sql.LevelRepeatableRead: + if dc.CompatibleMysql() { + dc.IsoLevel = int32(sql.LevelReadCommitted) + } else { + return nil, ECGO_INVALID_TRAN_ISOLATION.throw() + } + default: + return nil, ECGO_INVALID_TRAN_ISOLATION.throw() + } + + err = dc.Access.Dm_build_565(dc) + if err != nil { + return nil, err + } + } + + return dc, nil +} + +func (dc *DmConnection) commit() error { + err := dc.checkClosed() + if err != nil { + return err + } + + defer func() { + dc.autoCommit = dc.dmConnector.autoCommit + if dc.ReadOnly { + dc.exec("SP_SET_SESSION_READONLY(0)", nil) + } + }() + + if !dc.autoCommit || !dc.trxFinish { + err = dc.Access.Commit() + if err != nil { + return err + } + dc.trxFinish = true + return nil + } else if !dc.dmConnector.alwayseAllowCommit { + return ECGO_COMMIT_IN_AUTOCOMMIT_MODE.throw() + } + + return nil +} + +func (dc *DmConnection) rollback() error { + err := dc.checkClosed() + if err != nil { + return err + } + + defer func() { + dc.autoCommit = dc.dmConnector.autoCommit + if dc.ReadOnly { + dc.exec("SP_SET_SESSION_READONLY(0)", nil) + } + }() + + if !dc.autoCommit { + err = dc.Access.Rollback() + if err != nil { + return err + } + dc.trxFinish = true + return nil + } else if !dc.dmConnector.alwayseAllowCommit { + return ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE.throw() + } + + return nil +} + +func (dc *DmConnection) reconnect() error { + err := dc.Access.Close() + if err != nil { + return err + } + + for _, stmt := range dc.stmtMap { + + for id, rs := range stmt.rsMap { + rs.Close() + delete(stmt.rsMap, id) + } + } + + var newConn *DmConnection + if dc.dmConnector.group != nil { + if newConn, err = dc.dmConnector.group.connect(dc.dmConnector); err != nil { + return err + } + } else { + newConn, err = dc.dmConnector.connect(context.Background()) + } + + oldMap := dc.stmtMap + newConn.mu = dc.mu + newConn.filterable = dc.filterable + *dc = *newConn + + for _, stmt := range oldMap { + if stmt.closed { + continue + } + err = dc.Access.Dm_build_475(stmt) + if err != nil { + stmt.free() + continue + } + + if stmt.prepared || stmt.paramCount > 0 { + if err = stmt.prepare(); err != nil { + continue + } + } + + dc.stmtMap[stmt.id] = stmt + } + + return nil +} + +func (dc *DmConnection) cleanup() { + dc.close() +} + +func (dc *DmConnection) close() error { + if !dc.closed.TrySet(true) { + return nil + } + + util.AbsorbPanic(func() { + close(dc.closech) + }) + if dc.Access == nil { + return nil + } + + dc.rollback() + + for _, stmt := range dc.stmtMap { + stmt.free() + } + + dc.Access.Close() + + return nil +} + +func (dc *DmConnection) ping(ctx context.Context) error { + if err := dc.watchCancel(ctx); err != nil { + return err + } + defer dc.finish() + + rows, err := dc.query("select 1", nil) + if err != nil { + return err + } + return rows.close() +} + +func (dc *DmConnection) exec(query string, args []driver.Value) (*DmResult, error) { + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + return nil, err + } + defer stmt.close() + dc.lastExecInfo = stmt.execInfo + + return stmt.exec(args) + } else { + r1, err := dc.executeInner(query, Dm_build_790) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmResult); ok { + return r2, nil + } else { + return nil, ECGO_NOT_EXEC_SQL.throw() + } + } +} + +func (dc *DmConnection) execContext(ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + return nil, err + } + defer stmt.close() + dc.lastExecInfo = stmt.execInfo + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + return stmt.exec(dargs) + } else { + r1, err := dc.executeInner(query, Dm_build_790) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmResult); ok { + return r2, nil + } else { + return nil, ECGO_NOT_EXEC_SQL.throw() + } + } +} + +func (dc *DmConnection) query(query string, args []driver.Value) (*DmRows, error) { + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + stmt.innerUsed = true + return stmt.query(args) + + } else { + r1, err := dc.executeInner(query, Dm_build_789) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmRows); ok { + return r2, nil + } else { + return nil, ECGO_NOT_QUERY_SQL.throw() + } + } +} + +func (dc *DmConnection) queryContext(ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return nil, err + } + + if args != nil && len(args) > 0 { + stmt, err := dc.prepare(query) + if err != nil { + return nil, err + } + dc.lastExecInfo = stmt.execInfo + + stmt.innerUsed = true + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + return stmt.query(dargs) + + } else { + r1, err := dc.executeInner(query, Dm_build_789) + if err != nil { + return nil, err + } + + if r2, ok := r1.(*DmRows); ok { + return r2, nil + } else { + return nil, ECGO_NOT_QUERY_SQL.throw() + } + } + +} + +func (dc *DmConnection) prepare(query string) (stmt *DmStatement, err error) { + if err = dc.checkClosed(); err != nil { + return + } + if stmt, err = NewDmStmt(dc, query); err != nil { + return + } + if err = stmt.prepare(); err != nil { + stmt.close() + stmt = nil + return + } + return +} + +func (dc *DmConnection) prepareContext(ctx context.Context, query string) (*DmStatement, error) { + if err := dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + return dc.prepare(query) +} + +func (dc *DmConnection) resetSession(ctx context.Context) error { + if err := dc.watchCancel(ctx); err != nil { + return err + } + defer dc.finish() + + err := dc.checkClosed() + if err != nil { + return err + } + + return nil +} + +func (dc *DmConnection) checkNamedValue(nv *driver.NamedValue) error { + var err error + var cvt = converter{dc, false} + nv.Value, err = cvt.ConvertValue(nv.Value) + dc.isBatch = cvt.isBatch + return err +} + +func (dc *DmConnection) driverQuery(query string) (*DmStatement, *DmRows, error) { + stmt, err := NewDmStmt(dc, query) + if err != nil { + return nil, nil, err + } + stmt.innerUsed = true + stmt.innerExec = true + info, err := dc.Access.Dm_build_503(stmt, Dm_build_789) + if err != nil { + return nil, nil, err + } + dc.lastExecInfo = info + stmt.innerExec = false + return stmt, newDmRows(newInnerRows(0, stmt, info)), nil +} + +func (dc *DmConnection) getIndexOnEPGroup() int32 { + if dc.dmConnector.group == nil || dc.dmConnector.group.epList == nil { + return -1 + } + for i := 0; i < len(dc.dmConnector.group.epList); i++ { + ep := dc.dmConnector.group.epList[i] + if dc.dmConnector.host == ep.host && dc.dmConnector.port == ep.port { + return int32(i) + } + } + return -1 +} + +func (dc *DmConnection) getServerEncoding() string { + if dc.dmConnector.charCode != "" { + return dc.dmConnector.charCode + } + return dc.serverEncoding +} + +func (dc *DmConnection) lobFetchAll() bool { + return dc.dmConnector.lobMode == 2 +} + +func (conn *DmConnection) CompatibleOracle() bool { + return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_ORACLE +} + +func (conn *DmConnection) CompatibleMysql() bool { + return conn.dmConnector.compatibleMode == COMPATIBLE_MODE_MYSQL +} + +func (conn *DmConnection) cancel(err error) { + conn.canceled.Set(err) + conn.close() + +} + +func (conn *DmConnection) finish() { + if !conn.watching || conn.finished == nil { + return + } + select { + case conn.finished <- struct{}{}: + conn.watching = false + case <-conn.closech: + } +} + +func (conn *DmConnection) startWatcher() { + watcher := make(chan context.Context, 1) + conn.watcher = watcher + finished := make(chan struct{}) + conn.finished = finished + go func() { + for { + var ctx context.Context + select { + case ctx = <-watcher: + case <-conn.closech: + return + } + + select { + case <-ctx.Done(): + conn.cancel(ctx.Err()) + case <-finished: + case <-conn.closech: + return + } + } + }() +} + +func (conn *DmConnection) watchCancel(ctx context.Context) error { + if conn.watching { + + conn.cleanup() + return nil + } + + if err := ctx.Err(); err != nil { + return err + } + + if ctx.Done() == nil { + return nil + } + + if conn.watcher == nil { + return nil + } + + conn.watching = true + conn.watcher <- ctx + return nil +} + +type noCopy struct{} + +func (*noCopy) Lock() {} + +type atomicBool struct { + _noCopy noCopy + value uint32 +} + +func (ab *atomicBool) IsSet() bool { + return atomic.LoadUint32(&ab.value) > 0 +} + +func (ab *atomicBool) Set(value bool) { + if value { + atomic.StoreUint32(&ab.value, 1) + } else { + atomic.StoreUint32(&ab.value, 0) + } +} + +func (ab *atomicBool) TrySet(value bool) bool { + if value { + return atomic.SwapUint32(&ab.value, 1) == 0 + } + return atomic.SwapUint32(&ab.value, 0) > 0 +} + +type atomicError struct { + _noCopy noCopy + value atomic.Value +} + +func (ae *atomicError) Set(value error) { + ae.value.Store(value) +} + +func (ae *atomicError) Value() error { + if v := ae.value.Load(); v != nil { + + return v.(error) + } + return nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/n.go b/dpi_bridge/third_party/chunanyong_dm/n.go new file mode 100644 index 0000000..a0a77e5 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/n.go @@ -0,0 +1,985 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "context" + "database/sql/driver" + "net" + "net/url" + "os" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "sync" + "time" + + "gitee.com/chunanyong/dm/util" +) + +const ( + TimeZoneKey = "timeZone" + EnRsCacheKey = "enRsCache" + RsCacheSizeKey = "rsCacheSize" + RsRefreshFreqKey = "rsRefreshFreq" + LoginPrimary = "loginPrimary" + LoginModeKey = "loginMode" + LoginStatusKey = "loginStatus" + LoginDscCtrlKey = "loginDscCtrl" + SwitchTimesKey = "switchTimes" + SwitchIntervalKey = "switchInterval" + EpSelectorKey = "epSelector" + PrimaryKey = "primaryKey" + KeywordsKey = "keywords" + CompressKey = "compress" + CompressIdKey = "compressId" + LoginEncryptKey = "loginEncrypt" + CommunicationEncryptKey = "communicationEncrypt" + DirectKey = "direct" + Dec2DoubleKey = "dec2double" + RwSeparateKey = "rwSeparate" + RwPercentKey = "rwPercent" + RwAutoDistributeKey = "rwAutoDistribute" + CompatibleModeKey = "compatibleMode" + CompatibleOraKey = "comOra" + CipherPathKey = "cipherPath" + DoSwitchKey = "doSwitch" + DriverReconnectKey = "driverReconnect" + ClusterKey = "cluster" + LanguageKey = "language" + DbAliveCheckFreqKey = "dbAliveCheckFreq" + RwStandbyRecoverTimeKey = "rwStandbyRecoverTime" + LogLevelKey = "logLevel" + LogDirKey = "logDir" + LogBufferPoolSizeKey = "logBufferPoolSize" + LogBufferSizeKey = "logBufferSize" + LogFlusherQueueSizeKey = "logFlusherQueueSize" + LogFlushFreqKey = "logFlushFreq" + StatEnableKey = "statEnable" + StatDirKey = "statDir" + StatFlushFreqKey = "statFlushFreq" + StatHighFreqSqlCountKey = "statHighFreqSqlCount" + StatSlowSqlCountKey = "statSlowSqlCount" + StatSqlMaxCountKey = "statSqlMaxCount" + StatSqlRemoveModeKey = "statSqlRemoveMode" + AddressRemapKey = "addressRemap" + UserRemapKey = "userRemap" + ConnectTimeoutKey = "connectTimeout" + LoginCertificateKey = "loginCertificate" + UrlKey = "url" + HostKey = "host" + PortKey = "port" + UserKey = "user" + PasswordKey = "password" + DialNameKey = "dialName" + RwStandbyKey = "rwStandby" + IsCompressKey = "isCompress" + RwHAKey = "rwHA" + RwIgnoreSqlKey = "rwIgnoreSql" + AppNameKey = "appName" + OsNameKey = "osName" + MppLocalKey = "mppLocal" + SocketTimeoutKey = "socketTimeout" + SessionTimeoutKey = "sessionTimeout" + ContinueBatchOnErrorKey = "continueBatchOnError" + BatchAllowMaxErrorsKey = "batchAllowMaxErrors" + EscapeProcessKey = "escapeProcess" + AutoCommitKey = "autoCommit" + MaxRowsKey = "maxRows" + RowPrefetchKey = "rowPrefetch" + BufPrefetchKey = "bufPrefetch" + LobModeKey = "LobMode" + StmtPoolSizeKey = "StmtPoolSize" + + AlwayseAllowCommitKey = "AlwayseAllowCommit" + BatchTypeKey = "batchType" + BatchNotOnCallKey = "batchNotOnCall" + IsBdtaRSKey = "isBdtaRS" + ClobAsStringKey = "clobAsString" + SslCertPathKey = "sslCertPath" + SslKeyPathKey = "sslKeyPath" + SslFilesPathKey = "sslFilesPath" + KerberosLoginConfPathKey = "kerberosLoginConfPath" + UKeyNameKey = "uKeyName" + UKeyPinKey = "uKeyPin" + ColumnNameUpperCaseKey = "columnNameUpperCase" + ColumnNameCaseKey = "columnNameCase" + DatabaseProductNameKey = "databaseProductName" + OsAuthTypeKey = "osAuthType" + SchemaKey = "schema" + CatalogKey = "catalog" + ServerOptionKey = "serverOption" + ClobToBytesKey = "clobToBytes" + + DO_SWITCH_OFF int32 = 0 + DO_SWITCH_WHEN_CONN_ERROR int32 = 1 + DO_SWITCH_WHEN_EP_RECOVER int32 = 2 + + CLUSTER_TYPE_NORMAL int32 = 0 + CLUSTER_TYPE_RW int32 = 1 + CLUSTER_TYPE_DW int32 = 2 + CLUSTER_TYPE_DSC int32 = 3 + CLUSTER_TYPE_MPP int32 = 4 + + EP_STATUS_OK int32 = 1 + EP_STATUS_ERROR int32 = 2 + + LOGIN_MODE_PRIMARY_FIRST int32 = 0 + + LOGIN_MODE_PRIMARY_ONLY int32 = 1 + + LOGIN_MODE_STANDBY_ONLY int32 = 2 + + LOGIN_MODE_STANDBY_FIRST int32 = 3 + + LOGIN_MODE_NORMAL_FIRST int32 = 4 + + SERVER_MODE_NORMAL int32 = 0 + + SERVER_MODE_PRIMARY int32 = 1 + + SERVER_MODE_STANDBY int32 = 2 + + SERVER_STATUS_MOUNT int32 = 3 + + SERVER_STATUS_OPEN int32 = 4 + + SERVER_STATUS_SUSPEND int32 = 5 + + COMPATIBLE_MODE_ORACLE int = 1 + + COMPATIBLE_MODE_MYSQL int = 2 + + LANGUAGE_CN int = 0 + + LANGUAGE_EN int = 1 + + LANGUAGE_CNT_HK = 2 + + COLUMN_NAME_NATURAL_CASE = 0 + + COLUMN_NAME_UPPER_CASE = 1 + + COLUMN_NAME_LOWER_CASE = 2 + + RW_SEPARATE_OFF int32 = 0 + + RW_SEPARATE_CLIENT int32 = 1 + + RW_SEPARATE_EP_GROUP int32 = 2 + + RW_SEPARATE_DB int32 = 3 + + RW_SEPARATE_DB_APPLY_WAIT int32 = 4 + + RW_SEPARATE_USER_DEFINED int32 = 5 + + compressDef = Dm_build_784 + compressIDDef = Dm_build_785 + + charCodeDef = "" + + enRsCacheDef = false + + rsCacheSizeDef = 20 + + rsRefreshFreqDef = 10 + + loginModeDef = LOGIN_MODE_NORMAL_FIRST + + loginStatusDef = 0 + + loginEncryptDef = true + + loginCertificateDef = "" + + dec2DoubleDef = false + + rwHADef = false + + rwStandbyDef = false + + rwSeparateDef = RW_SEPARATE_OFF + + rwPercentDef = 25 + + rwAutoDistributeDef = true + + rwStandbyRecoverTimeDef = 1000 + + cipherPathDef = "" + + urlDef = "" + + userDef = "SYSDBA" + + passwordDef = "SYSDBA" + + hostDef = "localhost" + + portDef = DEFAULT_PORT + + appNameDef = "" + + mppLocalDef = false + + socketTimeoutDef = 0 + + connectTimeoutDef = 5000 + + sessionTimeoutDef = 0 + + osAuthTypeDef = Dm_build_767 + + continueBatchOnErrorDef = false + + escapeProcessDef = false + + autoCommitDef = true + + maxRowsDef = 0 + + rowPrefetchDef = Dm_build_768 + + bufPrefetchDef = 0 + + lobModeDef = 1 + + stmtPoolMaxSizeDef = 15 + + alwayseAllowCommitDef = true + + isBdtaRSDef = false + + kerberosLoginConfPathDef = "" + + uKeyNameDef = "" + + uKeyPinDef = "" + + databaseProductNameDef = "" + + caseSensitiveDef = true + + compatibleModeDef = 0 +) + +type DmConnector struct { + filterable + + mu sync.Mutex + + dmDriver *DmDriver + + compress int + + compressID int8 + + newClientType bool + + charCode string + + enRsCache bool + + rsCacheSize int + + rsRefreshFreq int + + loginMode int32 + + loginStatus int + + loginDscCtrl bool + + switchTimes int32 + + switchInterval int + + epSelector int32 + + keyWords []string + + loginEncrypt bool + + loginCertificate string + + dec2Double bool + + rwHA bool + + rwStandby bool + + rwSeparate int32 + + rwPercent int32 + + rwAutoDistribute bool + + rwStandbyRecoverTime int + + rwIgnoreSql bool + + doSwitch int32 + + driverReconnect bool + + cluster int32 + + cipherPath string + + url string + + user string + + password string + + dialName string + + host string + + group *epGroup + + port int32 + + appName string + + osName string + + mppLocal bool + + socketTimeout int + + connectTimeout int + + sessionTimeout int + + osAuthType byte + + continueBatchOnError bool + + batchAllowMaxErrors int32 + + escapeProcess bool + + autoCommit bool + + maxRows int + + rowPrefetch int + + bufPrefetch int + + lobMode int + + stmtPoolMaxSize int + + alwayseAllowCommit bool + + batchType int + + batchNotOnCall bool + + isBdtaRS bool + + sslCertPath string + + sslKeyPath string + + sslFilesPath string + + kerberosLoginConfPath string + + uKeyName string + + uKeyPin string + + svcConfPath string + + columnNameCase int + + caseSensitive bool + + compatibleMode int + + localTimezone int16 + + schema string + + catalog string + + logLevel int + + logDir string + + logFlushFreq int + + logFlushQueueSize int + + logBufferSize int + + statEnable bool + + statDir string + + statFlushFreq int + + statSlowSqlCount int + + statHighFreqSqlCount int + + statSqlMaxCount int + + statSqlRemoveMode int + + serverOption []string + + clobToBytes bool +} + +func (c *DmConnector) init() *DmConnector { + c.compress = compressDef + c.compressID = compressIDDef + c.charCode = charCodeDef + c.enRsCache = enRsCacheDef + c.rsCacheSize = rsCacheSizeDef + c.rsRefreshFreq = rsRefreshFreqDef + c.loginMode = loginModeDef + c.loginStatus = loginStatusDef + c.loginDscCtrl = false + c.switchTimes = 1 + c.switchInterval = 200 + c.epSelector = 0 + c.keyWords = nil + c.loginEncrypt = loginEncryptDef + c.loginCertificate = loginCertificateDef + c.dec2Double = dec2DoubleDef + c.rwHA = rwHADef + c.rwStandby = rwStandbyDef + c.rwSeparate = rwSeparateDef + c.rwPercent = rwPercentDef + c.rwAutoDistribute = rwAutoDistributeDef + c.rwStandbyRecoverTime = rwStandbyRecoverTimeDef + c.rwIgnoreSql = false + c.doSwitch = DO_SWITCH_WHEN_CONN_ERROR + c.driverReconnect = false + c.cluster = CLUSTER_TYPE_NORMAL + c.cipherPath = cipherPathDef + c.url = urlDef + c.user = userDef + c.password = passwordDef + c.host = hostDef + c.port = portDef + c.appName = appNameDef + c.osName = runtime.GOOS + c.mppLocal = mppLocalDef + c.socketTimeout = socketTimeoutDef + c.connectTimeout = connectTimeoutDef + c.sessionTimeout = sessionTimeoutDef + c.osAuthType = osAuthTypeDef + c.continueBatchOnError = continueBatchOnErrorDef + c.batchAllowMaxErrors = 0 + c.escapeProcess = escapeProcessDef + c.autoCommit = autoCommitDef + c.maxRows = maxRowsDef + c.rowPrefetch = rowPrefetchDef + c.bufPrefetch = bufPrefetchDef + c.lobMode = lobModeDef + c.stmtPoolMaxSize = stmtPoolMaxSizeDef + + c.alwayseAllowCommit = alwayseAllowCommitDef + c.batchType = 1 + c.batchNotOnCall = false + c.isBdtaRS = isBdtaRSDef + c.kerberosLoginConfPath = kerberosLoginConfPathDef + c.uKeyName = uKeyNameDef + c.uKeyPin = uKeyPinDef + c.columnNameCase = COLUMN_NAME_NATURAL_CASE + c.caseSensitive = caseSensitiveDef + c.compatibleMode = compatibleModeDef + _, tzs := time.Now().Zone() + c.localTimezone = int16(tzs / 60) + c.idGenerator = dmConntorIDGenerator + + c.logDir = LogDirDef + c.logFlushFreq = LogFlushFreqDef + c.logFlushQueueSize = LogFlushQueueSizeDef + c.logBufferSize = LogBufferSizeDef + c.statEnable = StatEnableDef + c.statDir = StatDirDef + c.statFlushFreq = StatFlushFreqDef + c.statSlowSqlCount = StatSlowSqlCountDef + c.statHighFreqSqlCount = StatHighFreqSqlCountDef + c.statSqlMaxCount = StatSqlMaxCountDef + c.statSqlRemoveMode = StatSqlRemoveModeDef + return c +} + +func (c *DmConnector) setAttributes(props *Properties) error { + if props == nil || props.Len() == 0 { + return nil + } + + c.url = props.GetTrimString(UrlKey, c.url) + c.host = props.GetTrimString(HostKey, c.host) + c.port = int32(props.GetInt(PortKey, int(c.port), 0, 65535)) + c.user = props.GetString(UserKey, c.user) + c.password = props.GetString(PasswordKey, c.password) + c.dialName = props.GetString(DialNameKey, "") + c.rwStandby = props.GetBool(RwStandbyKey, c.rwStandby) + + if b := props.GetBool(IsCompressKey, false); b { + c.compress = Dm_build_783 + } + + c.compress = props.GetInt(CompressKey, c.compress, 0, 2) + c.compressID = int8(props.GetInt(CompressIdKey, int(c.compressID), 0, 1)) + c.enRsCache = props.GetBool(EnRsCacheKey, c.enRsCache) + c.localTimezone = int16(props.GetInt(TimeZoneKey, int(c.localTimezone), -779, 840)) + c.rsCacheSize = props.GetInt(RsCacheSizeKey, c.rsCacheSize, 0, int(INT32_MAX)) + c.rsRefreshFreq = props.GetInt(RsRefreshFreqKey, c.rsRefreshFreq, 0, int(INT32_MAX)) + c.loginMode = int32(props.GetInt(LoginModeKey, int(c.loginMode), 0, 4)) + c.loginStatus = props.GetInt(LoginStatusKey, c.loginStatus, 0, int(INT32_MAX)) + c.loginDscCtrl = props.GetBool(LoginDscCtrlKey, c.loginDscCtrl) + c.switchTimes = int32(props.GetInt(SwitchTimesKey, int(c.switchTimes), 0, int(INT32_MAX))) + c.switchInterval = props.GetInt(SwitchIntervalKey, c.switchInterval, 0, int(INT32_MAX)) + c.epSelector = int32(props.GetInt(EpSelectorKey, int(c.epSelector), 0, 1)) + c.loginEncrypt = props.GetBool(LoginEncryptKey, c.loginEncrypt) + c.loginCertificate = props.GetTrimString(LoginCertificateKey, c.loginCertificate) + c.dec2Double = props.GetBool(Dec2DoubleKey, c.dec2Double) + parseLanguage(props.GetString(LanguageKey, "")) + + c.rwSeparate = int32(props.GetInt(RwSeparateKey, int(c.rwSeparate), 0, 4)) + c.rwAutoDistribute = props.GetBool(RwAutoDistributeKey, c.rwAutoDistribute) + c.rwPercent = int32(props.GetInt(RwPercentKey, int(c.rwPercent), 0, 100)) + c.rwHA = props.GetBool(RwHAKey, c.rwHA) + c.rwStandbyRecoverTime = props.GetInt(RwStandbyRecoverTimeKey, c.rwStandbyRecoverTime, 0, int(INT32_MAX)) + c.rwIgnoreSql = props.GetBool(RwIgnoreSqlKey, c.rwIgnoreSql) + c.doSwitch = int32(props.GetInt(DoSwitchKey, int(c.doSwitch), 0, 2)) + c.driverReconnect = props.GetBool(DriverReconnectKey, c.driverReconnect) + c.parseCluster(props) + c.cipherPath = props.GetTrimString(CipherPathKey, c.cipherPath) + + if props.GetBool(CompatibleOraKey, false) { + c.compatibleMode = int(COMPATIBLE_MODE_ORACLE) + } + c.parseCompatibleMode(props) + c.keyWords = props.GetStringArray(KeywordsKey, c.keyWords) + + c.appName = props.GetTrimString(AppNameKey, c.appName) + c.osName = props.GetTrimString(OsNameKey, c.osName) + c.mppLocal = props.GetBool(MppLocalKey, c.mppLocal) + c.socketTimeout = props.GetInt(SocketTimeoutKey, c.socketTimeout, 0, int(INT32_MAX)) + c.connectTimeout = props.GetInt(ConnectTimeoutKey, c.connectTimeout, 0, int(INT32_MAX)) + c.sessionTimeout = props.GetInt(SessionTimeoutKey, c.sessionTimeout, 0, int(INT32_MAX)) + + err := c.parseOsAuthType(props) + if err != nil { + return err + } + c.continueBatchOnError = props.GetBool(ContinueBatchOnErrorKey, c.continueBatchOnError) + c.batchAllowMaxErrors = int32(props.GetInt(BatchAllowMaxErrorsKey, int(c.batchAllowMaxErrors), 0, int(INT32_MAX))) + c.escapeProcess = props.GetBool(EscapeProcessKey, c.escapeProcess) + c.autoCommit = props.GetBool(AutoCommitKey, c.autoCommit) + c.maxRows = props.GetInt(MaxRowsKey, c.maxRows, 0, int(INT32_MAX)) + c.rowPrefetch = props.GetInt(RowPrefetchKey, c.rowPrefetch, 0, int(INT32_MAX)) + c.bufPrefetch = props.GetInt(BufPrefetchKey, c.bufPrefetch, int(Dm_build_769), int(Dm_build_770)) + c.lobMode = props.GetInt(LobModeKey, c.lobMode, 1, 2) + c.stmtPoolMaxSize = props.GetInt(StmtPoolSizeKey, c.stmtPoolMaxSize, 0, int(INT32_MAX)) + + c.alwayseAllowCommit = props.GetBool(AlwayseAllowCommitKey, c.alwayseAllowCommit) + c.batchType = props.GetInt(BatchTypeKey, c.batchType, 1, 2) + c.batchNotOnCall = props.GetBool(BatchNotOnCallKey, c.batchNotOnCall) + c.isBdtaRS = props.GetBool(IsBdtaRSKey, c.isBdtaRS) + c.sslFilesPath = props.GetTrimString(SslFilesPathKey, c.sslFilesPath) + c.sslCertPath = props.GetTrimString(SslCertPathKey, c.sslCertPath) + if c.sslCertPath == "" && c.sslFilesPath != "" { + c.sslCertPath = filepath.Join(c.sslFilesPath, "client-cert.pem") + } + c.sslKeyPath = props.GetTrimString(SslKeyPathKey, c.sslKeyPath) + if c.sslKeyPath == "" && c.sslFilesPath != "" { + c.sslKeyPath = filepath.Join(c.sslKeyPath, "client-key.pem") + } + + c.kerberosLoginConfPath = props.GetTrimString(KerberosLoginConfPathKey, c.kerberosLoginConfPath) + + c.uKeyName = props.GetTrimString(UKeyNameKey, c.uKeyName) + c.uKeyPin = props.GetTrimString(UKeyPinKey, c.uKeyPin) + + c.svcConfPath = props.GetString("confPath", "") + + if props.GetBool(ColumnNameUpperCaseKey, false) { + c.columnNameCase = COLUMN_NAME_UPPER_CASE + } + + v := props.GetTrimString(ColumnNameCaseKey, "") + if util.StringUtil.EqualsIgnoreCase(v, "upper") { + c.columnNameCase = COLUMN_NAME_UPPER_CASE + } else if util.StringUtil.EqualsIgnoreCase(v, "lower") { + c.columnNameCase = COLUMN_NAME_LOWER_CASE + } + + c.schema = props.GetTrimString(SchemaKey, c.schema) + c.catalog = props.GetTrimString(CatalogKey, c.catalog) + + c.logLevel = ParseLogLevel(props) + LogLevel = c.logLevel + c.logDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef)) + LogDir = c.logDir + c.logBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX)) + LogBufferSize = c.logBufferSize + c.logFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX)) + LogFlushFreq = c.logFlushFreq + c.logFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX)) + LogFlushQueueSize = c.logFlushQueueSize + + c.statEnable = props.GetBool(StatEnableKey, StatEnableDef) + StatEnable = c.statEnable + c.statDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef)) + StatDir = c.statDir + c.statFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX)) + StatFlushFreq = c.statFlushFreq + c.statHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000) + StatHighFreqSqlCount = c.statHighFreqSqlCount + c.statSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000) + StatSlowSqlCount = c.statSlowSqlCount + c.statSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000) + StatSqlMaxCount = c.statSqlMaxCount + c.parseStatSqlRemoveMode(props) + + c.parseServerOption(props) + c.clobToBytes = props.GetBool(ClobToBytesKey, ClobToBytesDef) + return nil +} + +func (c *DmConnector) parseServerOption(props *Properties) { + value := props.GetString(ServerOptionKey, "") + if len(value) == 0 { + return + } + + if strings.HasPrefix(value, "{") && strings.HasSuffix(value, "}") { + + value = strings.TrimPrefix(value, "{") + value = strings.TrimSuffix(value, "}") + } + + c.serverOption = strings.Split(value, ",") +} + +func (c *DmConnector) parseOsAuthType(props *Properties) error { + value := props.GetString(OsAuthTypeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase(value, "ON") { + c.osAuthType = Dm_build_767 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSDBA") { + c.osAuthType = Dm_build_763 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSAUDITOR") { + c.osAuthType = Dm_build_765 + } else if util.StringUtil.EqualsIgnoreCase(value, "SYSSSO") { + c.osAuthType = Dm_build_764 + } else if util.StringUtil.EqualsIgnoreCase(value, "AUTO") { + c.osAuthType = Dm_build_766 + } else if util.StringUtil.EqualsIgnoreCase(value, "OFF") { + c.osAuthType = Dm_build_762 + } + } else { + c.osAuthType = byte(props.GetInt(OsAuthTypeKey, int(c.osAuthType), 0, 4)) + } + if c.user == "" && c.osAuthType == Dm_build_762 { + c.user = "SYSDBA" + } else if c.osAuthType != Dm_build_762 && c.user != "" { + return ECGO_OSAUTH_ERROR.throw() + } else if c.osAuthType != Dm_build_762 { + c.user = os.Getenv("user") + c.password = "" + } + return nil +} + +func (c *DmConnector) parseCompatibleMode(props *Properties) { + value := props.GetString(CompatibleModeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase(value, "oracle") { + c.compatibleMode = COMPATIBLE_MODE_ORACLE + } else if util.StringUtil.EqualsIgnoreCase(value, "mysql") { + c.compatibleMode = COMPATIBLE_MODE_MYSQL + } + } else { + c.compatibleMode = props.GetInt(CompatibleModeKey, c.compatibleMode, 0, 2) + } +} + +func (c *DmConnector) parseStatSqlRemoveMode(props *Properties) { + value := props.GetString(StatSqlRemoveModeKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase("oldest", value) || util.StringUtil.EqualsIgnoreCase("eldest", value) { + c.statSqlRemoveMode = STAT_SQL_REMOVE_OLDEST + } else if util.StringUtil.EqualsIgnoreCase("latest", value) { + c.statSqlRemoveMode = STAT_SQL_REMOVE_LATEST + } + } else { + c.statSqlRemoveMode = props.GetInt(StatSqlRemoveModeKey, StatSqlRemoveModeDef, 1, 2) + } +} + +func (c *DmConnector) parseCluster(props *Properties) { + value := props.GetTrimString(ClusterKey, "") + if util.StringUtil.EqualsIgnoreCase(value, "DSC") { + c.cluster = CLUSTER_TYPE_DSC + } else if util.StringUtil.EqualsIgnoreCase(value, "RW") { + c.cluster = CLUSTER_TYPE_RW + } else if util.StringUtil.EqualsIgnoreCase(value, "DW") { + c.cluster = CLUSTER_TYPE_DW + } else if util.StringUtil.EqualsIgnoreCase(value, "MPP") { + c.cluster = CLUSTER_TYPE_MPP + } else { + c.cluster = CLUSTER_TYPE_NORMAL + } +} + +func (c *DmConnector) parseDSN(dsn string) (*Properties, string, string, error) { + var dsnProps = NewProperties() + + if strings.Index(dsn, "dm://") != 0 { + return nil, "", "", DSN_INVALID_SCHEMA + } + dsn = dsn[5:] + + urlString := dsn + queryIndex := strings.LastIndex(dsn, "?") + if queryIndex > 0 { + urlString = dsn[:queryIndex] + var queryString = dsn[queryIndex+1:] + + for _, kvString := range strings.Split(queryString, "&") { + kv := strings.SplitN(kvString, "=", 2) + if kv != nil && len(kv) > 1 { + dsnProps.Set(kv[0], kv[1]) + } + } + } + + hostString := urlString + atIndex := strings.LastIndex(urlString, "@") + if atIndex == -1 { + return nil, "", "", DSN_INVALID_FORMAT + } else { + var userString = urlString[:atIndex] + hostString = urlString[atIndex+1:] + kv := strings.SplitN(userString, ":", 2) + if kv != nil && len(kv) > 1 { + c.user = kv[0] + c.password = kv[1] + } + } + if catalogIndex := strings.LastIndex(hostString, "/"); catalogIndex > 0 { + return dsnProps, hostString[0:catalogIndex], hostString[catalogIndex+1:], nil + } + return dsnProps, hostString, "", nil + +} + +func (c *DmConnector) BuildDSN() string { + var buf bytes.Buffer + + buf.WriteString("dm://") + + if len(c.user) > 0 { + buf.WriteString(url.QueryEscape(c.user)) + if len(c.password) > 0 { + buf.WriteByte(':') + buf.WriteString(url.QueryEscape(c.password)) + } + buf.WriteByte('@') + } + + if len(c.host) > 0 { + buf.WriteString(c.host) + if c.port > 0 { + buf.WriteByte(':') + buf.WriteString(strconv.Itoa(int(c.port))) + } + } + + hasParam := false + if c.connectTimeout > 0 { + if hasParam { + buf.WriteString("&timeout=") + } else { + buf.WriteString("?timeout=") + hasParam = true + } + buf.WriteString(strconv.Itoa(c.connectTimeout)) + } + return buf.String() +} + +func (c *DmConnector) mergeConfigs(dsn string) error { + props, host, catalog, err := c.parseDSN(dsn) + if err != nil { + return err + } + + driverInit(props.GetString("svcConfPath", "")) + + addressRemapStr := props.GetTrimString(AddressRemapKey, "") + userRemapStr := props.GetTrimString(UserRemapKey, "") + if addressRemapStr == "" { + addressRemapStr = GlobalProperties.GetTrimString(AddressRemapKey, "") + } + if userRemapStr == "" { + userRemapStr = GlobalProperties.GetTrimString(UserRemapKey, "") + } + + host = c.remap(host, addressRemapStr) + + c.user = c.remap(c.user, userRemapStr) + + if a := props.GetTrimString(host, ""); a != "" { + + if strings.HasPrefix(a, "(") && strings.HasSuffix(a, ")") { + a = strings.TrimSpace(a[1 : len(a)-1]) + } + c.group = parseServerName(host, a) + if c.group != nil { + c.group.props = NewProperties() + c.group.props.SetProperties(GlobalProperties) + } + } else if group, ok := ServerGroupMap.Load(strings.ToLower(host)); ok { + + c.group = group.(*epGroup) + } else { + host, port, err := net.SplitHostPort(host) + if err == nil { + ip := net.ParseIP(host) + var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff} + if ip != nil && len(ip) == net.IPv6len && !bytes.Equal(ip[0:12], v4InV6Prefix) { + + host = "[" + host + "]" + } + } + + c.host = host + + tmpPort, err := strconv.Atoi(port) + if err != nil { + c.port = portDef + } else { + c.port = int32(tmpPort) + } + + if len(catalog) > 0 { + c.schema = catalog + } + + c.group = newEPGroup(c.host+":"+strconv.Itoa(int(c.port)), []*ep{newEP(c.host, c.port)}) + } + + props.SetDiffProperties(c.group.props) + + props.SetDiffProperties(GlobalProperties) + + if c.rwSeparate = int32(props.GetInt(RwSeparateKey, 0, 0, 5)); c.rwSeparate > RW_SEPARATE_OFF { + props.SetIfNotExist(LoginModeKey, strconv.Itoa(int(LOGIN_MODE_PRIMARY_ONLY))) + props.SetIfNotExist(LoginStatusKey, strconv.Itoa(int(SERVER_STATUS_OPEN))) + + props.SetIfNotExist(DoSwitchKey, "true") + + } + + if err = c.setAttributes(props); err != nil { + return err + } + return nil +} + +func (c *DmConnector) remap(origin string, cfgStr string) string { + if cfgStr == "" || origin == "" { + return origin + } + + maps := regexp.MustCompile("\\(.*?,.*?\\)").FindAllString(cfgStr, -1) + for _, kvStr := range maps { + kv := strings.Split(strings.TrimSpace(kvStr[1:len(kvStr)-1]), ",") + if util.StringUtil.Equals(strings.TrimSpace(kv[0]), origin) { + return strings.TrimSpace(kv[1]) + } + } + return origin +} + +func (c *DmConnector) Connect(ctx context.Context) (driver.Conn, error) { + c.mu.Lock() + defer c.mu.Unlock() + return c.filterChain.reset().DmConnectorConnect(c, ctx) +} + +func (c *DmConnector) Driver() driver.Driver { + c.mu.Lock() + defer c.mu.Unlock() + return c.filterChain.reset().DmConnectorDriver(c) +} + +func (c *DmConnector) connect(ctx context.Context) (*DmConnection, error) { + if c.group != nil && len(c.group.epList) > 0 { + return c.group.connect(c) + } else { + return c.connectSingle(ctx) + } +} + +func (c *DmConnector) driver() *DmDriver { + return c.dmDriver +} + +func (c *DmConnector) connectSingle(ctx context.Context) (*DmConnection, error) { + var err error + var dc = &DmConnection{ + closech: make(chan struct{}), + dmConnector: c, + autoCommit: c.autoCommit, + } + + dc.createFilterChain(c, nil) + dc.objId = -1 + dc.init() + + dc.Access, err = dm_build_426(ctx, dc) + if err != nil { + return nil, err + } + + dc.startWatcher() + if err = dc.watchCancel(ctx); err != nil { + return nil, err + } + defer dc.finish() + + if err = dc.Access.dm_build_471(); err != nil { + + if !dc.closed.IsSet() { + close(dc.closech) + if dc.Access != nil { + dc.Access.Close() + } + dc.closed.Set(true) + } + return nil, err + } + + if c.schema != "" { + _, err = dc.exec("set schema \""+util.StringUtil.ProcessDoubleQuoteOfName(c.schema)+"\"", nil) + if err != nil { + + dc.cleanup() + return nil, err + } + } + + return dc, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/o.go b/dpi_bridge/third_party/chunanyong_dm/o.go new file mode 100644 index 0000000..44c1adf --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/o.go @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "math/big" + "reflect" + "strconv" + "strings" +) + +const ( + XDEC_MAX_PREC int = 40 + XDEC_SIZE = 21 + + FLAG_ZERO int = 0x80 + FLAG_POSITIVE int = 0xC1 + FLAG_NEGTIVE int = 0x3E + POSITIVE_EXP_MAX = 0xff - FLAG_POSITIVE + EXP_MAX int = 0xFF - 1 - FLAG_POSITIVE + EXP_MIN int = FLAG_NEGTIVE + 1 - 0x7F + + NUM_POSITIVE int = 1 + NUM_NEGTIVE int = 101 +) + +type DmDecimal struct { + sign int + weight int + prec int + scale int + digits string + + Valid bool +} + +func NewDecimalFromInt64(x int64) (*DmDecimal, error) { + return NewDecimalFromBigInt(big.NewInt(x)) +} + +func (d DmDecimal) ToInt64() int64 { + return d.ToBigInt().Int64() +} + +func NewDecimalFromFloat64(x float64) (*DmDecimal, error) { + return NewDecimalFromBigFloat(big.NewFloat(x)) +} + +func (d DmDecimal) ToFloat64() float64 { + f, _ := d.ToBigFloat().Float64() + return f +} + +func NewDecimalFromBigInt(bigInt *big.Int) (*DmDecimal, error) { + return newDecimal(bigInt, len(bigInt.String()), 0) +} + +func (d DmDecimal) ToBigInt() *big.Int { + if d.isZero() { + return big.NewInt(0) + } + var digits = d.digits + if d.sign < 0 { + digits = "-" + digits + } + i1, ok := new(big.Int).SetString(digits, 10) + if !ok { + return nil + } + if d.weight > 0 { + i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", d.weight), 10) + if !ok { + return nil + } + i1.Mul(i1, i2) + } else if d.weight < 0 { + i2, ok := new(big.Int).SetString("1"+strings.Repeat("0", -d.weight), 10) + if !ok { + return nil + } + i1.Quo(i1, i2) + } + return i1 +} + +func NewDecimalFromBigFloat(bigFloat *big.Float) (*DmDecimal, error) { + return newDecimal(bigFloat, int(bigFloat.Prec()), int(bigFloat.Prec())) +} + +func (d DmDecimal) ToBigFloat() *big.Float { + if d.isZero() { + return big.NewFloat(0.0) + } + var digits = d.digits + if d.sign < 0 { + digits = "-" + digits + } + f1, ok := new(big.Float).SetString(digits) + if !ok { + return nil + } + if d.weight > 0 { + f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", d.weight)) + if !ok { + return nil + } + f1.Mul(f1, f2) + } else if d.weight < 0 { + f2, ok := new(big.Float).SetString("1" + strings.Repeat("0", -d.weight)) + if !ok { + return nil + } + f1.Quo(f1, f2) + } + return f1 +} + +func NewDecimalFromString(s string) (*DmDecimal, error) { + num, ok := new(big.Float).SetString(strings.TrimSpace(s)) + if !ok { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return NewDecimalFromBigFloat(num) +} + +func (d DmDecimal) String() string { + + if d.isZero() { + return "0" + } + digitsStr := d.digits + if d.weight > 0 { + digitsStr = digitsStr + strings.Repeat("0", d.weight) + } else if d.weight < 0 { + if len(digitsStr) < -d.weight { + digitsStr = strings.Repeat("0", -d.weight-len(digitsStr)+1) + digitsStr + } + indexOfDot := len(digitsStr) + d.weight + digitsStr = digitsStr[:indexOfDot] + "." + digitsStr[indexOfDot:] + } + + if digitsStr[0] == '0' && digitsStr[1] != '.' { + digitsStr = digitsStr[1:] + } + + if digitsStr[len(digitsStr)-1] == '0' && strings.IndexRune(digitsStr, '.') >= 0 { + digitsStr = digitsStr[0 : len(digitsStr)-1] + } + + if d.sign < 0 { + digitsStr = "-" + digitsStr + } + + return digitsStr +} + +func (d DmDecimal) Sign() int { + return d.sign +} + +func (dest *DmDecimal) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmDecimal) + + (*dest).Valid = false + return nil + case int, int8, int16, int32, int64: + d, err := NewDecimalFromInt64(reflect.ValueOf(src).Int()) + if err != nil { + return err + } + *dest = *d + return nil + case uint, uint8, uint16, uint32, uint64: + d, err := NewDecimalFromBigInt(new(big.Int).SetUint64(reflect.ValueOf(src).Uint())) + if err != nil { + return err + } + *dest = *d + return nil + case float32, float64: + d, err := NewDecimalFromFloat64(reflect.ValueOf(src).Float()) + if err != nil { + return err + } + *dest = *d + return nil + case string: + d, err := NewDecimalFromString(src) + if err != nil { + return err + } + *dest = *d + return nil + case *DmDecimal: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (d DmDecimal) Value() (driver.Value, error) { + if !d.Valid { + return nil, nil + } + return d, nil +} + +func newDecimal(dec interface{}, prec int, scale int) (*DmDecimal, error) { + d := &DmDecimal{ + prec: prec, + scale: scale, + Valid: true, + } + if isFloat(DECIMAL, scale) { + d.prec = getFloatPrec(prec) + d.scale = -1 + } + switch de := dec.(type) { + case *big.Int: + d.sign = de.Sign() + + if d.isZero() { + return d, nil + } + str := de.String() + + if d.sign < 0 { + str = str[1:] + } + + if err := checkPrec(len(str), prec); err != nil { + return d, err + } + i := 0 + istart := len(str) - 1 + + for i = istart; i > 0; i-- { + if str[i] != '0' { + break + } + } + str = str[:i+1] + d.weight += istart - i + + if isOdd(d.weight) { + str += "0" + d.weight -= 1 + } + if isOdd(len(str)) { + str = "0" + str + } + d.digits = str + case *big.Float: + d.sign = de.Sign() + + if d.isZero() { + return d, nil + } + str := de.Text('f', -1) + + if d.sign < 0 { + str = str[1:] + } + + pointIndex := strings.IndexByte(str, '.') + i, istart, length := 0, 0, len(str) + + if pointIndex != -1 { + if str[0] == '0' { + + istart = 2 + for i = istart; i < length; i++ { + if str[i] != '0' { + break + } + } + str = str[i:] + d.weight -= i - istart + len(str) + } else { + str = str[:pointIndex] + str[pointIndex+1:] + d.weight -= length - pointIndex - 1 + } + } + + length = len(str) + istart = length - 1 + for i = istart; i > 0; i-- { + if str[i] != '0' { + break + } + } + str = str[:i+1] + str[length:] + d.weight += istart - i + + if isOdd(d.weight) { + str += "0" + d.weight -= 1 + } + if isOdd(len(str)) { + str = "0" + str + } + d.digits = str + case []byte: + return decodeDecimal(de, prec, scale) + } + return d, nil +} + +func (d DmDecimal) encodeDecimal() ([]byte, error) { + if d.isZero() { + return []byte{byte(FLAG_ZERO)}, nil + } + exp := (d.weight+len(d.digits))/2 - 1 + + var realExpMax int + + if d.sign == NUM_POSITIVE { + realExpMax = POSITIVE_EXP_MAX + } else { + realExpMax = EXP_MAX + } + if exp > realExpMax || exp < EXP_MIN { + return nil, ECGO_DATA_TOO_LONG.throw() + } + validLen := len(d.digits)/2 + 1 + + if d.sign < 0 && validLen >= XDEC_SIZE { + validLen = XDEC_SIZE - 1 + } else if validLen > XDEC_SIZE { + validLen = XDEC_SIZE + } + retLen := validLen + if d.sign < 0 { + retLen = validLen + 1 + } + retBytes := make([]byte, retLen) + if d.sign > 0 { + retBytes[0] = byte(exp + FLAG_POSITIVE) + } else { + retBytes[0] = byte(FLAG_NEGTIVE - exp) + } + + ibytes := 1 + for ichar := 0; ibytes < validLen; { + digit1, err := strconv.Atoi(string(d.digits[ichar])) + if err != nil { + return nil, err + } + ichar++ + digit2, err := strconv.Atoi(string(d.digits[ichar])) + ichar++ + if err != nil { + return nil, err + } + + digit := digit1*10 + digit2 + if d.sign > 0 { + retBytes[ibytes] = byte(digit + NUM_POSITIVE) + } else { + retBytes[ibytes] = byte(NUM_NEGTIVE - digit) + } + ibytes++ + } + if d.sign < 0 && ibytes < retLen { + retBytes[ibytes] = 0x66 + ibytes++ + } + if ibytes < retLen { + retBytes[ibytes] = 0x00 + } + return retBytes, nil +} + +func decodeDecimal(values []byte, prec int, scale int) (*DmDecimal, error) { + var decimal = &DmDecimal{ + prec: prec, + scale: scale, + sign: 0, + weight: 0, + Valid: true, + } + if values == nil || len(values) == 0 || len(values) > XDEC_SIZE { + return nil, ECGO_FATAL_ERROR.throw() + } + if values[0] == byte(FLAG_ZERO) || len(values) == 1 { + return decimal, nil + } + if values[0]&byte(FLAG_ZERO) != 0 { + decimal.sign = 1 + } else { + decimal.sign = -1 + } + + var flag = int(Dm_build_1346.Dm_build_1466(values, 0)) + var exp int + if decimal.sign > 0 { + exp = flag - FLAG_POSITIVE + } else { + exp = FLAG_NEGTIVE - flag + } + var digit = 0 + var sf = "" + for ival := 1; ival < len(values); ival++ { + if decimal.sign > 0 { + digit = int(values[ival]) - NUM_POSITIVE + } else { + digit = NUM_NEGTIVE - int(values[ival]) + } + if digit < 0 || digit > 99 { + break + } + if digit < 10 { + sf += "0" + } + sf += strconv.Itoa(digit) + } + decimal.digits = sf + decimal.weight = exp*2 - (len(decimal.digits) - 2) + + return decimal, nil +} + +func (d DmDecimal) isZero() bool { + return d.sign == 0 +} + +func checkPrec(len int, prec int) error { + if prec > 0 && len > prec || len > XDEC_MAX_PREC { + return ECGO_DATA_TOO_LONG.throw() + } + return nil +} + +func isOdd(val int) bool { + return val%2 != 0 +} + +func (d *DmDecimal) checkValid() error { + if !d.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} + +func (d *DmDecimal) GormDataType() string { + return "DECIMAL" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/p.go b/dpi_bridge/third_party/chunanyong_dm/p.go new file mode 100644 index 0000000..f70aa03 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/p.go @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "context" + "database/sql" + "database/sql/driver" + "net" + "sync" + + "gitee.com/chunanyong/dm/i18n" +) + +// 发版标记 +var version = "8.1.4.170" +var build_date = "2025.11.21" +var svn = "43114" + +var globalDmDriver = newDmDriver() + +func init() { + sql.Register("dm", globalDmDriver) + + i18n.InitConfig(i18n.Messages_zh_CN) + i18n.InitConfig(i18n.Messages_en_US) + i18n.InitConfig(i18n.Messages_zh_HK) +} + +func driverInit(svcConfPath string) { + load(svcConfPath) + if GlobalProperties != nil && GlobalProperties.Len() > 0 { + setDriverAttributes(GlobalProperties) + } + globalDmDriver.createFilterChain(nil, GlobalProperties) +} + +type DmDriver struct { + filterable + mu sync.Mutex + //readPropMutex sync.Mutex +} + +func newDmDriver() *DmDriver { + d := new(DmDriver) + d.idGenerator = dmDriverIDGenerator + return d +} + +// 支持自定义连接网络地址,返回标准net.Conn对象,相关数据库操作的消息包都将发送到该对象 +type DialFunc func(addr string) (net.Conn, error) + +// 支持自定义连接网络地址,返回标准net.Conn对象,相关数据库操作的消息包都将发送到该对象 +type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error) + +var ( + dialsLock sync.RWMutex + dials map[string]DialContextFunc +) + +// 注册自定义连接方法 +func RegisterDial(dialName string, dial DialFunc) { + RegisterDialContext(dialName, func(_ context.Context, addr string) (net.Conn, error) { + return dial(addr) + }) +} + +// 注册自定义连接方法 +func RegisterDialContext(dialName string, dial DialContextFunc) { + dialsLock.Lock() + defer dialsLock.Unlock() + if dials == nil { + dials = make(map[string]DialContextFunc) + } + dials[dialName] = dial +} + +/************************************************************* + ** PUBLIC METHODS AND FUNCTIONS + *************************************************************/ +func (d *DmDriver) Open(dsn string) (driver.Conn, error) { + d.mu.Lock() + defer d.mu.Unlock() + return d.open(dsn) +} + +func (d *DmDriver) OpenConnector(dsn string) (driver.Connector, error) { + d.mu.Lock() + defer d.mu.Unlock() + return d.openConnector(dsn) +} + +func (d *DmDriver) open(dsn string) (*DmConnection, error) { + c, err := d.openConnector(dsn) + if err != nil { + return nil, err + } + return c.connect(context.Background()) +} + +func (d *DmDriver) openConnector(dsn string) (*DmConnector, error) { + connector := new(DmConnector).init() + connector.url = dsn + connector.dmDriver = d + //d.readPropMutex.Lock() + err := connector.mergeConfigs(dsn) + //d.readPropMutex.Unlock() + if err != nil { + return nil, err + } + connector.createFilterChain(connector, nil) + return connector, nil +} + +func GetDriverVersion() string { + return version +} diff --git a/dpi_bridge/third_party/chunanyong_dm/parser/zt.go b/dpi_bridge/third_party/chunanyong_dm/parser/zt.go new file mode 100644 index 0000000..04963dd --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/parser/zt.go @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package parser + +import "strconv" + +const ( + MAX_DEC_LEN = 38 +) + +const ( + NORMAL int = iota + INT + DOUBLE + DECIMAL + STRING + HEX_INT + WHITESPACE_OR_COMMENT + NULL +) + +type LVal struct { + Value string + Tp int + Position int +} + +func newLValNoParams() *LVal { + return new(LVal).reset() +} + +func newLVal(value string, tp int) *LVal { + return &LVal{Value: value, Tp: tp} +} + +func (l *LVal) reset() *LVal { + l.Value = "" + l.Tp = NORMAL + return l +} + +func (l *LVal) String() string { + return strconv.Itoa(l.Tp) + ":" + l.Value +} diff --git a/dpi_bridge/third_party/chunanyong_dm/parser/zu.go b/dpi_bridge/third_party/chunanyong_dm/parser/zu.go new file mode 100644 index 0000000..ed960f3 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/parser/zu.go @@ -0,0 +1,1206 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package parser + +import ( + "io" + "strconv" + "unicode/utf8" +) + +const ( + YYEOF = -1 /** This character denotes the end of file */ + ZZ_BUFFERSIZE = 16384 /** initial size of the lookahead buffer */ + /** lexical states */ + YYINITIAL = 0 + xc = 2 + xq = 4 + xdq = 6 + xsb = 8 + xbin = 10 + xhex = 12 + xhint = 14 + xq2 = 16 + xq2_2 = 18 +) + +/** +* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l +* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l +* at the beginning of a line +* l is of the form l = 2*k, k a non negative integer + */ +var ZZ_LEXSTATE []int = []int{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 4, 4, 7, 7, 8, 8} + +/** +* Translates characters to character classes + */ +var ZZ_CMAP_PACKED []rune = []rune{0011, 0000, 0001, 0026, 0001, 0025, 0001, 0030, 0001, 0026, 0001, 0025, 0022, 0000, 0001, 0026, 0001, 0017, 0001, 0002, + 0002, 0012, 0002, 0017, 0001, 0001, 0002, 0017, 0001, 0004, 0001, 0023, 0001, 0017, 0001, 0027, 0001, 0016, 0001, 0003, + 0001, 0020, 0011, 0013, 0001, 0014, 0001, 0017, 0001, 0017, 0001, 0015, 0003, 0017, 0001, 0021, 0001, 0010, 0001, 0021, + 0001, 0024, 0001, 0022, 0001, 0024, 0002, 0012, 0001, 0034, 0002, 0012, 0001, 0033, 0001, 0012, 0001, 0031, 0001, 0036, + 0001, 0012, 0001, 0007, 0001, 0012, 0001, 0035, 0001, 0037, 0001, 0032, 0002, 0012, 0001, 0011, 0002, 0012, 0001, 0005, + 0001, 0000, 0001, 0006, 0001, 0017, 0001, 0012, 0001, 0000, 0001, 0021, 0001, 0010, 0001, 0021, 0001, 0024, 0001, 0022, + 0001, 0024, 0002, 0012, 0001, 0034, 0002, 0012, 0001, 0033, 0001, 0012, 0001, 0031, 0001, 0036, 0001, 0012, 0001, 0007, + 0001, 0012, 0001, 0035, 0001, 0037, 0001, 0032, 0002, 0012, 0001, 0011, 0002, 0012, 0001, 0017, 0001, 0017, 0002, 0017, + 0001, 0000, 0005, 0012, 0001, 0012, 0172, 0012, 0x1f28, 0000, 0001, 0030, 0001, 0030, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xffff, 0000, 0xdfe6, 0000} + +/** +* Translates characters to character classes + */ +var ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED) + +/** +* Translates DFA states to action switch labels. + */ +var ZZ_ACTION = zzUnpackActionNoParams() + +var ZZ_ACTION_PACKED_0 []rune = []rune{0011, 0000, 0001, 0001, 0001, 0002, 0001, 0003, 0002, 0004, 0004, 0005, 0001, 0006, 0002, 0004, + 0001, 0006, 0001, 0007, 0001, 0004, 0002, 0005, 0001, 0010, 0002, 0011, 0001, 0012, 0001, 0013, + 0001, 0014, 0001, 0015, 0001, 0016, 0001, 0017, 0001, 0020, 0001, 0021, 0001, 0022, 0001, 0023, + 0001, 0024, 0001, 0025, 0001, 0026, 0001, 0007, 0001, 0027, 0001, 0000, 0001, 0030, 0001, 0031, + 0001, 0032, 0001, 0000, 0001, 0033, 0001, 0034, 0001, 0035, 0001, 0032, 0001, 0036, 0001, 0000, + 0003, 0005, 0001, 0037, 0001, 0040, 0001, 0000, 0001, 0041, 0002, 0000, 0001, 0042, 0004, 0000, + 0001, 0043, 0001, 0044, 0001, 0033, 0001, 0000, 0001, 0045, 0002, 0005, 0003, 0000, 0001, 0046, + 0001, 0047, 0001, 0050, 0001, 0051, 0020, 0000, 0001, 0052, 0001, 0000, 0001, 0053, 0001, 0052, + 0001, 0053} + +func zzUnpackActionNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result) + return result +} + +func zzUnpackAction(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //130 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + result[j] = int(value) + j++ + count-- + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +/** +* Translates a state to a row index in the transition table + */ +var ZZ_ROWMAP = zzUnpackRowMapNoParams() + +var ZZ_ROWMAP_PACKED_0 []rune = []rune{0000, 0000, 0000, 0040, 0000, 0100, 0000, 0140, 0000, 0200, 0000, 0240, 0000, 0300, 0000, 0340, + 0000, 0x0100, 0000, 0200, 0000, 0200, 0000, 0200, 0000, 0x0120, 0000, 0200, 0000, 0x0140, 0000, 0x0160, + 0000, 0x0180, 0000, 0x01a0, 0000, 0x01c0, 0000, 0x01e0, 0000, 0x0200, 0000, 0x0220, 0000, 0200, 0000, 0x0240, + 0000, 0x0260, 0000, 0x0280, 0000, 0x02a0, 0000, 0x02c0, 0000, 0x02e0, 0000, 0x0300, 0000, 0x0320, 0000, 0x0340, + 0000, 0x0360, 0000, 0x0380, 0000, 0x03a0, 0000, 0x03c0, 0000, 0x03e0, 0000, 0x0400, 0000, 0200, 0000, 0200, + 0000, 0200, 0000, 0200, 0000, 0x0420, 0000, 0200, 0000, 0x0440, 0000, 0200, 0000, 0200, 0000, 0x0460, + 0000, 0x0480, 0000, 0200, 0000, 0200, 0000, 0200, 0000, 0x04a0, 0000, 0200, 0000, 0x04c0, 0000, 0x04e0, + 0000, 0x0500, 0000, 0x0520, 0000, 0200, 0000, 0200, 0000, 0x02e0, 0000, 0200, 0000, 0x0540, 0000, 0x0560, + 0000, 0200, 0000, 0x0580, 0000, 0x03a0, 0000, 0x05a0, 0000, 0x03e0, 0000, 0200, 0000, 0200, 0000, 0x05c0, + 0000, 0x05c0, 0000, 0x04c0, 0000, 0x05e0, 0000, 0x0600, 0000, 0x0620, 0000, 0x0640, 0000, 0x0660, 0000, 0200, + 0000, 0200, 0000, 0200, 0000, 0x01a0, 0000, 0x0680, 0000, 0x06a0, 0000, 0x06c0, 0000, 0x06e0, 0000, 0x0700, + 0000, 0x0720, 0000, 0x0740, 0000, 0x0760, 0000, 0x0780, 0000, 0x07a0, 0000, 0x07c0, 0000, 0x07e0, 0000, 0x0800, + 0000, 0x0820, 0000, 0x0840, 0000, 0x0860, 0000, 0200, 0000, 0x0880, 0000, 0200, 0000, 0x06e0, 0000, 0x0720} + +func zzUnpackRowMapNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result) + return result +} + +func zzUnpackRowMap(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //208 + for i < l { + high := packed[i] << 16 + i++ + result[j] = int(high | packed[i]) + i++ + j++ + } + return j +} + +/** +* The transition table of the DFA + */ +var ZZ_TRANS []int = zzUnpackTransNoParams() + +var ZZ_TRANS_PACKED_0 []rune = []rune{0001, 0012, 0001, 0013, 0001, 0014, 0001, 0015, 0003, 0016, 0001, 0017, 0001, 0020, 0001, 0021, + 0001, 0022, 0001, 0023, 0001, 0024, 0001, 0016, 0001, 0025, 0001, 0016, 0001, 0026, 0002, 0022, + 0001, 0016, 0001, 0022, 0002, 0027, 0001, 0030, 0001, 0000, 0001, 0031, 0002, 0022, 0001, 0032, + 0003, 0022, 0003, 0033, 0001, 0034, 0001, 0035, 0033, 0033, 0001, 0036, 0001, 0037, 0036, 0036, + 0002, 0040, 0001, 0041, 0035, 0040, 0040, 0000, 0001, 0042, 0001, 0043, 0036, 0042, 0001, 0044, + 0001, 0045, 0036, 0044, 0006, 0046, 0001, 0047, 0031, 0046, 0001, 0050, 0001, 0051, 0004, 0050, + 0001, 0052, 0031, 0050, 0003, 0000, 0001, 0053, 0001, 0054, 0034, 0000, 0001, 0055, 0005, 0000, + 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0007, 0022, 0001, 0000, + 0001, 0056, 0005, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, + 0007, 0022, 0001, 0000, 0001, 0057, 0005, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0007, 0022, 0007, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0007, 0022, 0013, 0000, 0001, 0023, 0002, 0000, 0001, 0060, 0001, 0000, + 0001, 0023, 0001, 0000, 0001, 0061, 0001, 0000, 0001, 0062, 0030, 0000, 0001, 0063, 0026, 0000, + 0001, 0064, 0006, 0000, 0001, 0065, 0002, 0000, 0001, 0066, 0001, 0000, 0001, 0065, 0030, 0000, + 0001, 0067, 0001, 0000, 0001, 0023, 0002, 0000, 0001, 0060, 0001, 0000, 0001, 0023, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0042, 0000, 0001, 0053, 0017, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0001, 0022, 0001, 0070, 0003, 0022, 0001, 0071, + 0001, 0022, 0007, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, + 0004, 0022, 0001, 0072, 0002, 0022, 0003, 0033, 0002, 0000, 0033, 0033, 0004, 0000, 0001, 0073, + 0036, 0000, 0001, 0074, 0001, 0075, 0033, 0000, 0001, 0036, 0001, 0000, 0036, 0036, 0001, 0000, + 0001, 0076, 0023, 0000, 0001, 0077, 0001, 0100, 0011, 0000, 0002, 0040, 0001, 0000, 0035, 0040, + 0002, 0000, 0001, 0101, 0035, 0000, 0001, 0042, 0001, 0000, 0036, 0042, 0025, 0000, 0001, 0102, + 0001, 0103, 0011, 0000, 0001, 0044, 0001, 0000, 0036, 0044, 0025, 0000, 0001, 0104, 0001, 0105, + 0011, 0000, 0006, 0046, 0001, 0000, 0031, 0046, 0025, 0053, 0001, 0000, 0012, 0053, 0005, 0000, + 0001, 0106, 0045, 0000, 0001, 0065, 0002, 0000, 0001, 0107, 0001, 0000, 0001, 0065, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0026, 0000, 0001, 0110, 0004, 0000, 0001, 0110, 0002, 0000, + 0001, 0111, 0003, 0000, 0001, 0111, 0023, 0000, 0001, 0065, 0004, 0000, 0001, 0065, 0001, 0000, + 0001, 0061, 0001, 0000, 0001, 0062, 0023, 0000, 0001, 0112, 0002, 0000, 0001, 0112, 0004, 0000, + 0003, 0112, 0001, 0000, 0001, 0112, 0022, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, + 0001, 0022, 0004, 0000, 0002, 0022, 0001, 0113, 0004, 0022, 0007, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0006, 0022, 0001, 0114, 0003, 0000, 0001, 0115, + 0003, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0002, 0116, 0001, 0117, + 0001, 0000, 0007, 0022, 0001, 0000, 0001, 0120, 0023, 0000, 0002, 0077, 0036, 0000, 0001, 0077, + 0001, 0100, 0012, 0000, 0001, 0121, 0023, 0000, 0002, 0102, 0012, 0000, 0001, 0122, 0023, 0000, + 0002, 0104, 0024, 0000, 0001, 0110, 0004, 0000, 0001, 0110, 0026, 0000, 0005, 0022, 0004, 0000, + 0003, 0022, 0001, 0000, 0001, 0022, 0004, 0000, 0002, 0022, 0001, 0123, 0004, 0022, 0003, 0000, + 0001, 0124, 0003, 0000, 0005, 0022, 0004, 0000, 0003, 0022, 0001, 0000, 0001, 0022, 0002, 0125, + 0001, 0126, 0001, 0000, 0007, 0022, 0003, 0000, 0001, 0127, 0037, 0000, 0001, 0115, 0021, 0000, + 0002, 0116, 0001, 0117, 0001, 0000, 0001, 0130, 0035, 0000, 0001, 0127, 0013, 0000, 0001, 0131, + 0037, 0000, 0001, 0124, 0021, 0000, 0002, 0125, 0001, 0126, 0001, 0000, 0001, 0132, 0035, 0000, + 0001, 0131, 0010, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0006, 0127, 0032, 0000, + 0001, 0134, 0005, 0000, 0025, 0131, 0001, 0125, 0003, 0131, 0001, 0135, 0006, 0131, 0032, 0000, + 0001, 0136, 0005, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0001, 0137, 0005, 0127, + 0033, 0000, 0001, 0140, 0004, 0000, 0025, 0131, 0001, 0125, 0003, 0131, 0001, 0135, 0001, 0141, + 0005, 0131, 0033, 0000, 0001, 0142, 0004, 0000, 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, + 0001, 0127, 0001, 0143, 0004, 0127, 0033, 0000, 0001, 0144, 0004, 0000, 0025, 0131, 0001, 0125, + 0003, 0131, 0001, 0135, 0001, 0131, 0001, 0145, 0004, 0131, 0033, 0000, 0001, 0146, 0004, 0000, + 0025, 0127, 0001, 0116, 0003, 0127, 0001, 0133, 0001, 0127, 0001, 0147, 0004, 0127, 0025, 0131, + 0001, 0125, 0003, 0131, 0001, 0135, 0001, 0131, 0001, 0150, 0004, 0131} + +func zzUnpackTransNoParams() []int { + result := make([]int, 2208) + offset := 0 + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result) + return result +} + +func zzUnpackTrans(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //780 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + value-- + result[j] = int(value) + j++ + count-- + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +/* error codes */ +const ( + ZZ_UNKNOWN_ERROR = 0 + ZZ_NO_MATCH = 1 + ZZ_PUSHBACK_2BIG = 2 +) + +/* error messages for the codes above */ +var ZZ_ERROR_MSG []string = []string{ + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback Value was too large"} + +/** +* ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ +var ZZ_ATTRIBUTE []int = zzUnpackAttributeNoParams() + +var ZZ_ATTRIBUTE_PACKED_0 []rune = []rune{0004, 0000, 0001, 0010, 0004, 0000, 0003, 0011, 0001, 0001, 0001, 0011, 0010, 0001, 0001, 0011, + 0017, 0001, 0004, 0011, 0001, 0001, 0001, 0011, 0001, 0000, 0002, 0011, 0001, 0001, 0001, 0000, + 0003, 0011, 0001, 0001, 0001, 0011, 0001, 0000, 0003, 0001, 0002, 0011, 0001, 0000, 0001, 0011, + 0002, 0000, 0001, 0011, 0004, 0000, 0002, 0011, 0001, 0001, 0001, 0000, 0003, 0001, 0003, 0000, + 0003, 0011, 0001, 0001, 0020, 0000, 0001, 0011, 0001, 0000, 0001, 0011, 0002, 0001} + +func zzUnpackAttributeNoParams() []int { + result := make([]int, 104) + offset := 0 + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result) + return result +} + +func zzUnpackAttribute(packed []rune, offset int, result []int) int { + i := 0 /* index in packed string */ + j := offset /* index in unpacked array */ + l := len(packed) //78 + for i < l { + count := packed[i] + i++ + value := packed[i] + i++ + result[j] = int(value) + j++ + count-- + + for count > 0 { + result[j] = int(value) + j++ + count-- + } + } + return j +} + +type Lexer struct { + /** the input device */ + zzReader io.RuneReader + + /** the current state of the DFA */ + zzState int + + /** the current lexical state */ + zzLexicalState int + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + zzBuffer []rune + + //zzBytesBuffer []byte + + /** the textposition at the last accepting state */ + zzMarkedPos int + + /** the current text Position in the buffer */ + zzCurrentPos int + + /** startRead marks the beginning of the yytext() string in the buffer */ + zzStartRead int + + /** endRead marks the last character in the buffer, that has been read + from input */ + zzEndRead int + + /** number of newlines encountered up to the start of the matched text */ + yyline int + + /** the number of characters up to the start of the matched text */ + yychar int + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + yycolumn int + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + zzAtBOL bool + + /** zzAtEOF == true <=> the scanner is at the EOF */ + zzAtEOF bool + + /** denotes if the user-EOF-code has already been executed */ + zzEOFDone bool + + /** + * The number of occupied positions in zzBuffer beyond zzEndRead. + * When a lead/high surrogate has been read from the input stream + * into the final zzBuffer Position, this will have a Value of 1; + * otherwise, it will have a Value of 0. + */ + zzFinalHighSurrogate int + + /* user code: */ + ltstr string + debugFlag bool +} + +func (lexer *Lexer) init() { + lexer.zzLexicalState = YYINITIAL + lexer.zzBuffer = make([]rune, ZZ_BUFFERSIZE) + lexer.zzAtBOL = true +} + +func (lexer *Lexer) Reset(in io.RuneReader) *Lexer { + lexer.zzLexicalState = YYINITIAL + lexer.zzAtBOL = true + lexer.zzReader = in + lexer.zzState = 0 + lexer.zzMarkedPos = 0 + lexer.zzCurrentPos = 0 + lexer.zzStartRead = 0 + lexer.zzEndRead = 0 + lexer.yyline = 0 + lexer.yychar = 0 + lexer.yycolumn = 0 + lexer.zzAtEOF = false + lexer.zzEOFDone = false + lexer.zzFinalHighSurrogate = 0 + lexer.ltstr = "" + return lexer +} + +func (lexer *Lexer) debug(info string) { + if !lexer.debugFlag { + return + } + +} + +func (lexer *Lexer) yyerror(msg string) { + locInfo := "(line: " + strconv.Itoa(lexer.yyline) + ", column: " + strconv.Itoa(lexer.yycolumn) + ", char: " + strconv.Itoa(lexer.yychar) + ")" + if msg == "" { + panic("syntex error" + locInfo) + } else { + panic("syntex error" + locInfo + ": " + msg) + } +} + +/** +* Creates a new scanner +* +* @param in the java.io.Reader to read input from. + */ +func NewLexer(in io.RuneReader, debug bool) *Lexer { + l := new(Lexer) + l.init() + l.debugFlag = debug + l.zzReader = in + return l +} + +/** +* Unpacks the compressed character translation table. +* +* @param packed the packed character translation table +* @return the unpacked character translation table + */ +func zzUnpackCMap(packed []rune) []rune { + m := make([]rune, 0x110000) + i := 0 /* index in packed string */ + j := 0 /* index in unpacked array */ + for i < 208 { + count := packed[i] + i++ + value := packed[i] + i++ + m[j] = value + j++ + count-- + for count > 0 { + m[j] = value + j++ + count-- + } + } + return m +} + +/** +* Refills the input buffer. +* +* @return false, iff there was new input. +* +* @exception java.io.IOException if any I/O-Error occurs + */ +func (lexer *Lexer) zzRefill() (bool, error) { + + /* first: make room (if you can) */ + if lexer.zzStartRead > 0 { + lexer.zzEndRead += lexer.zzFinalHighSurrogate + lexer.zzFinalHighSurrogate = 0 + l := lexer.zzEndRead - lexer.zzStartRead + if l > 0 { + copy(lexer.zzBuffer[:l], lexer.zzBuffer[lexer.zzStartRead:lexer.zzEndRead]) + } + + /* translate stored positions */ + lexer.zzEndRead -= lexer.zzStartRead + lexer.zzCurrentPos -= lexer.zzStartRead + lexer.zzMarkedPos -= lexer.zzStartRead + lexer.zzStartRead = 0 + } + + /* is the buffer big enough? */ + if lexer.zzCurrentPos >= len(lexer.zzBuffer)-lexer.zzFinalHighSurrogate { + /* if not: blow it up */ + newBuffer := make([]rune, len(lexer.zzBuffer)*2) + + copy(newBuffer[:len(lexer.zzBuffer)], lexer.zzBuffer[:len(lexer.zzBuffer)]) + lexer.zzBuffer = newBuffer + lexer.zzEndRead += lexer.zzFinalHighSurrogate + lexer.zzFinalHighSurrogate = 0 + } + + /* fill the buffer with new input */ + requested := len(lexer.zzBuffer) - lexer.zzEndRead + + var numRead = 0 + for i := lexer.zzEndRead; i < lexer.zzEndRead+requested; i++ { + r, _, err := lexer.zzReader.ReadRune() + if err == io.EOF { + if numRead == 0 { + numRead = -1 + } + break + } else if err != nil { + return false, err + } else { + numRead++ + lexer.zzBuffer[i] = r + } + } + + /* not supposed to occur according to specification of java.io.Reader */ + if numRead == 0 { + panic("Reader returned 0 characters. See JFlex examples for workaround.") + } + + if numRead > 0 { + + lexer.zzEndRead += numRead + /* If numRead == requested, we might have requested to few chars to + encode a full Unicode character. We assume that a Reader would + otherwise never return half characters. */ + if numRead == requested { + if utf8.ValidRune(lexer.zzBuffer[lexer.zzEndRead-1]) { + lexer.zzEndRead-- + lexer.zzFinalHighSurrogate = 1 + } + } + /* potentially more input available */ + return false, nil + } + + /* numRead < 0 ==> end of stream */ + return true, nil +} + +/** +* Closes the input stream. + */ +func (lexer *Lexer) yyclose() error { + lexer.zzAtEOF = true /* indicate end of file */ + lexer.zzEndRead = lexer.zzStartRead /* invalidate buffer */ + + if lexer.zzReader != nil { + if c, ok := lexer.zzReader.(io.Closer); ok { + return c.Close() + } + } + return nil +} + +/** +* Resets the scanner to read from a new input stream. +* Does not close the old reader. +* +* All internal variables are reset, the old input stream +* cannot be reused (internal buffer is discarded and lost). +* Lexical state is set to ZZ_INITIAL. +* +* Internal scan buffer is resized down to its initial length, if it has grown. +* +* @param reader the new input stream + */ +func (lexer *Lexer) yyreset(reader io.RuneReader) { + lexer.zzReader = reader + lexer.zzAtBOL = true + lexer.zzAtEOF = false + lexer.zzEOFDone = false + lexer.zzEndRead = 0 + lexer.zzStartRead = 0 + lexer.zzCurrentPos = 0 + lexer.zzMarkedPos = 0 + lexer.zzFinalHighSurrogate = 0 + lexer.yyline = 0 + lexer.yychar = 0 + lexer.yycolumn = 0 + lexer.zzLexicalState = YYINITIAL + if len(lexer.zzBuffer) > ZZ_BUFFERSIZE { + lexer.zzBuffer = make([]rune, ZZ_BUFFERSIZE) + } +} + +/** +* Returns the current lexical state. + */ +func (lexer *Lexer) yystate() int { + return lexer.zzLexicalState +} + +/** +* Enters a new lexical state +* +* @param newState the new lexical state + */ +func (lexer *Lexer) yybegin(newState int) { + lexer.zzLexicalState = newState +} + +/** +* Returns the text matched by the current regular expression. + */ +func (lexer *Lexer) yytext() string { + return string(lexer.zzBuffer[lexer.zzStartRead:lexer.zzMarkedPos]) +} + +/** +* Returns the character at Position pos from the +* matched text. +* +* It is equivalent to yytext().charAt(pos), but faster +* +* @param pos the Position of the character to fetch. +* A Value from 0 to yylength()-1. +* +* @return the character at Position pos + */ +func (lexer *Lexer) yycharat(pos int) rune { + return lexer.zzBuffer[lexer.zzStartRead+pos] +} + +/** +* Returns the length of the matched text region. + */ +func (lexer *Lexer) yylength() int { + return lexer.zzMarkedPos - lexer.zzStartRead +} + +/** +* Reports an error that occured while scanning. +* +* In a wellformed scanner (no or only correct usage of +* yypushback(int) and a match-all fallback rule) this method +* will only be called with things that "Can't Possibly Happen". +* If this method is called, something is seriously wrong +* (e.g. a JFlex bug producing a faulty scanner etc.). +* +* Usual syntax/scanner level error handling should be done +* in error fallback rules. +* +* @param errorCode the code of the errormessage to display + */ +func (lexer *Lexer) zzScanError(errorCode int) { + var message string + + message = ZZ_ERROR_MSG[errorCode] + if message == "" { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR] + } + + panic(message) +} + +/** +* Pushes the specified amount of characters back into the input stream. +* +* They will be read again by then next call of the scanning method +* +* @param number the number of characters to be read again. +* This number must not be greater than yylength()! + */ +func (lexer *Lexer) yypushback(number int) { + if number > lexer.yylength() { + lexer.zzScanError(ZZ_PUSHBACK_2BIG) + } + + lexer.zzMarkedPos -= number +} + +/** +* Resumes scanning until the next regular expression is matched, +* the end of input is encountered or an I/O-Error occurs. +* +* @return the next token +* @exception java.io.IOException if any I/O-Error occurs + */ +func (lexer *Lexer) Yylex() (*LVal, error) { + var zzInput rune + var zzAction, zzCurrentPosL, zzMarkedPosL int + // cached fields: + zzEndReadL := lexer.zzEndRead + zzBufferL := lexer.zzBuffer + zzCMapL := ZZ_CMAP + + zzTransL := ZZ_TRANS + zzRowMapL := ZZ_ROWMAP + zzAttrL := ZZ_ATTRIBUTE + + for { + zzMarkedPosL = lexer.zzMarkedPos + + lexer.yychar += zzMarkedPosL - lexer.zzStartRead + + zzR := false + var zzCh rune + var zzCharCount int + zzCurrentPosL = lexer.zzStartRead + for zzCurrentPosL < zzMarkedPosL { + zzCh = zzBufferL[zzCurrentPosL] + zzCharCount = utf8.RuneLen(zzCh) + switch zzCh { + case '\u000B', '\u000C', '\u0085', '\u2028', '\u2029': + lexer.yyline++ + lexer.yycolumn = 0 + zzR = false + case '\r': + lexer.yyline++ + lexer.yycolumn = 0 + zzR = true + case '\n': + if zzR { + zzR = false + } else { + lexer.yyline++ + lexer.yycolumn = 0 + } + default: + zzR = false + lexer.yycolumn += zzCharCount + } + zzCurrentPosL += zzCharCount + } + + if zzR { + // peek one character ahead if it is \n (if we have counted one line too much) + var zzPeek bool + if zzMarkedPosL < zzEndReadL { + zzPeek = zzBufferL[zzMarkedPosL] == '\n' + } else if lexer.zzAtEOF { + zzPeek = false + } else { + eof, err := lexer.zzRefill() + if err != nil { + return nil, err + } + zzEndReadL = lexer.zzEndRead + zzMarkedPosL = lexer.zzMarkedPos + zzBufferL = lexer.zzBuffer + if eof { + zzPeek = false + } else { + zzPeek = zzBufferL[zzMarkedPosL] == '\n' + } + + } + if zzPeek { + lexer.yyline-- + } + } + zzAction = -1 + + zzCurrentPosL = zzMarkedPosL + lexer.zzCurrentPos = zzMarkedPosL + lexer.zzStartRead = zzMarkedPosL + lexer.zzState = ZZ_LEXSTATE[lexer.zzLexicalState] + + // set up zzAction for empty match case: + zzAttributes := zzAttrL[lexer.zzState] + if (zzAttributes & 1) == 1 { + zzAction = lexer.zzState + } + + { + for true { + + if zzCurrentPosL < zzEndReadL { + zzInput = zzBufferL[zzCurrentPosL] + zzCurrentPosL += 1 //utf8.RuneLen(zzInput) + } else if lexer.zzAtEOF { + zzInput = YYEOF + goto zzForAction + } else { + // store back cached positions + lexer.zzCurrentPos = zzCurrentPosL + lexer.zzMarkedPos = zzMarkedPosL + eof, err := lexer.zzRefill() + if err != nil { + return nil, err + } + // get translated positions and possibly new buffer + zzCurrentPosL = lexer.zzCurrentPos + zzMarkedPosL = lexer.zzMarkedPos + zzBufferL = lexer.zzBuffer + zzEndReadL = lexer.zzEndRead + if eof { + zzInput = YYEOF + goto zzForAction + } else { + zzInput = zzBufferL[zzCurrentPosL] + zzCurrentPosL += 1 //utf8.RuneLen(zzInput) + } + } + + zzNext := zzTransL[zzRowMapL[lexer.zzState]+int(zzCMapL[zzInput])] + if zzNext == -1 { + goto zzForAction + } + + lexer.zzState = zzNext + + zzAttributes = zzAttrL[lexer.zzState] + if (zzAttributes & 1) == 1 { + zzAction = lexer.zzState + zzMarkedPosL = zzCurrentPosL + if (zzAttributes & 8) == 8 { + goto zzForAction + } + } + + } + } + + zzForAction: + // store back cached Position + lexer.zzMarkedPos = zzMarkedPosL + + if zzInput == YYEOF && lexer.zzStartRead == lexer.zzCurrentPos { + lexer.zzAtEOF = true + switch lexer.zzLexicalState { + case xc: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated /* comment") + } + case 105: + case xq: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated quoted string") + } + fallthrough + case 106: + case xdq: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated quoted identifier") + } + fallthrough + case 107: + case xbin: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated binary string literal") + } + fallthrough + case 108: + case xhex: + { + lexer.debug("<>") + + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated hexadecimal integer") + } + fallthrough + case 109: + case xq2: + { + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated q2 string") + } + fallthrough + case 110: + case xq2_2: + { + lexer.yybegin(YYINITIAL) + lexer.yyerror("unterminated q2 string") + } + fallthrough + case 111: + default: + return nil, nil + } + } else { + var action int + if zzAction < 0 { + action = zzAction + } else { + action = ZZ_ACTION[zzAction] + } + switch action { + case 1: + { + lexer.debug("{other}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 44: + case 2: + { + lexer.debug("{xq_start}") + + lexer.yybegin(xq) + lexer.ltstr = "" + } + fallthrough + case 45: + case 3: + { + lexer.debug("{xdq_start}") + + lexer.yybegin(xdq) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 46: + case 4: + { + lexer.debug("{self} | {op_chars}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 47: + case 5: + { + lexer.debug("{identifier}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 48: + case 6: + { + lexer.debug("{integer}") + + return newLVal(lexer.yytext(), INT), nil + } + fallthrough + case 49: + case 7: + { + lexer.debug("{whitespace} | {comment} | {c_line_comment}") + + return newLVal(lexer.yytext(), WHITESPACE_OR_COMMENT), nil + } + fallthrough + case 50: + case 8: + { + lexer.debug("{xc_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 51: + case 9: + { + lexer.debug("[\\/] | [\\*]") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 52: + case 10: + { + lexer.debug("{xq_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 53: + case 11: + { + lexer.debug("{xq_stop}") + + lexer.yybegin(YYINITIAL) + return newLVal(lexer.ltstr, STRING), nil + } + fallthrough + case 54: + case 12: + { + lexer.debug("{xdq_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 55: + case 13: + { + lexer.debug("{xdq_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 56: + case 14: + { + lexer.debug("{xbin_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 57: + case 15: + { + lexer.debug("{xbin_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 58: + case 16: + { + lexer.debug("{xhex_inside}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 59: + case 17: + { + lexer.debug("{xhex_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, NORMAL), nil + } + fallthrough + case 60: + case 18: + { + lexer.ltstr += lexer.yytext() + } + fallthrough + case 61: + case 19: + { + lexer.yybegin(xq2_2) + } + fallthrough + case 62: + case 20: + { + lexer.ltstr += "]" + lexer.ltstr += lexer.yytext() + lexer.yybegin(xq2) + } + fallthrough + case 63: + case 21: + { + lexer.yybegin(YYINITIAL) + + return newLVal(lexer.ltstr, STRING), nil + } + fallthrough + case 64: + case 22: + { + lexer.ltstr += "]" + lexer.yybegin(xq2_2) + } + fallthrough + case 65: + case 23: + { + lexer.debug("{xc_start}") + + lexer.yybegin(xc) + lexer.ltstr = lexer.yytext() + } + fallthrough + case 66: + case 24: + { + lexer.debug("{xbin_start}") + + lexer.yybegin(xbin) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 67: + case 25: + { + lexer.debug("{xhex_start}") + + lexer.yybegin(xhex) + lexer.ltstr = "" + lexer.ltstr += lexer.yytext() + } + fallthrough + case 68: + case 26: + { + lexer.debug("{decimal}") + + return newLVal(lexer.yytext(), DECIMAL), nil + } + fallthrough + case 69: + case 27: + { + lexer.debug("{real}") + + return newLVal(lexer.yytext(), DOUBLE), nil + } + fallthrough + case 70: + case 28: + { + lexer.debug("{assign}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 71: + case 29: + { + lexer.debug("{selstar}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 72: + case 30: + { + lexer.debug("{boundary}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 73: + case 31: + { + lexer.debug("{xc_start}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 74: + case 32: + { + lexer.debug("{xc_stop}") + + lexer.yybegin(YYINITIAL) + lexer.ltstr += lexer.yytext() + return newLVal(lexer.ltstr, WHITESPACE_OR_COMMENT), nil + } + fallthrough + case 75: + case 33: + { + lexer.debug("{xq_double}") + + lexer.ltstr += "\\'" + } + fallthrough + case 76: + case 34: + { // keep original string + lexer.debug("{xdq_double}") + + lexer.ltstr += lexer.yytext() + } + fallthrough + case 77: + case 35: + { + lexer.yybegin(xq2) + lexer.ltstr = "" + } + fallthrough + case 78: + case 36: + { + lexer.debug("{integer_with_boundary}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 79: + case 37: + { + lexer.debug("{hex_integer}") + + return newLVal(lexer.yytext(), HEX_INT), nil + } + fallthrough + case 80: + case 38: + { + lexer.debug("{xq_cat}") + } + fallthrough + case 81: + case 39: + { /* ignore */ + lexer.debug("{xbin_cat}") + } + fallthrough + case 82: + case 40: + { + lexer.debug("{xhex_cat}") + } + fallthrough + case 83: + case 41: + { + lexer.debug("{null}") + + return newLVal("null", NULL), nil + } + fallthrough + case 84: + case 42: + { + lexer.debug("{is_null}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 85: + case 43: + { + lexer.debug("{not_null}") + + return newLVal(lexer.yytext(), NORMAL), nil + } + fallthrough + case 86: + default: + lexer.zzScanError(ZZ_NO_MATCH) + } + } + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/q.go b/dpi_bridge/third_party/chunanyong_dm/q.go new file mode 100644 index 0000000..83bf6f5 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/q.go @@ -0,0 +1,1455 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "math" + "strconv" + "strings" + + "gitee.com/chunanyong/dm/util" +) + +const ( + LOADPREC_DEFAULT = 2 + + LOADPREC_MAX = 9 + + SECDPREC_DEFAULT = 6 + + SECDPREC_MAX = 6 + + QUA_D byte = 3 + + QUA_DH byte = 4 + + QUA_DHM byte = 5 + + QUA_DHMS byte = 6 + + QUA_H byte = 7 + + QUA_HM byte = 8 + + QUA_HMS byte = 9 + + QUA_M byte = 10 + + QUA_MS byte = 11 + + QUA_S byte = 12 +) + +type DmIntervalDT struct { + _type byte + + leadScale int + + secScale int + + negative bool + + days int + + hours int + + minutes int + + seconds int + + fraction int + + scaleForSvr int + + Valid bool +} + +func (dt *DmIntervalDT) init() { + dt._type = QUA_D + dt.leadScale = 2 + dt.secScale = 6 + dt.negative = false + dt.days = 0 + dt.hours = 0 + dt.minutes = 0 + dt.seconds = 0 + dt.fraction = 0 + dt.scaleForSvr = 0 + dt.Valid = true +} + +func newDmIntervalDTByBytes(bytes []byte) *DmIntervalDT { + dt := new(DmIntervalDT) + dt.init() + + dt._type = bytes[21] + dt.scaleForSvr = int(Dm_build_1346.Dm_build_1448(bytes, 20)) + dt.leadScale = (dt.scaleForSvr >> 4) & 0x0000000F + dt.secScale = dt.scaleForSvr & 0x0000000F + + switch dt._type { + case QUA_D: + dt.days = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + case QUA_DH: + dt.days = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + case QUA_DHM: + dt.days = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + case QUA_DHMS: + dt.days = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + dt.seconds = int(Dm_build_1346.Dm_build_1448(bytes, 12)) + dt.fraction = int(Dm_build_1346.Dm_build_1448(bytes, 16)) + case QUA_H: + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + case QUA_HM: + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + case QUA_HMS: + dt.hours = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + dt.seconds = int(Dm_build_1346.Dm_build_1448(bytes, 12)) + dt.fraction = int(Dm_build_1346.Dm_build_1448(bytes, 16)) + case QUA_M: + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + case QUA_MS: + dt.minutes = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + dt.seconds = int(Dm_build_1346.Dm_build_1448(bytes, 12)) + dt.fraction = int(Dm_build_1346.Dm_build_1448(bytes, 16)) + case QUA_S: + dt.seconds = int(Dm_build_1346.Dm_build_1448(bytes, 12)) + dt.fraction = int(Dm_build_1346.Dm_build_1448(bytes, 16)) + } + if dt.days < 0 { + dt.days = -dt.days + dt.negative = true + } + if dt.hours < 0 { + dt.hours = -dt.hours + dt.negative = true + } + if dt.minutes < 0 { + dt.minutes = -dt.minutes + dt.negative = true + } + if dt.seconds < 0 { + dt.seconds = -dt.seconds + dt.negative = true + } + if dt.fraction < 0 { + dt.fraction = -dt.fraction + dt.negative = true + } + + return dt +} + +func NewDmIntervalDTByString(str string) (dt *DmIntervalDT, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_TIME_INTERVAL.throw() + } + }() + dt = new(DmIntervalDT) + dt.init() + + if str == "" { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr := strings.TrimSpace(strings.ToUpper(str)) + + if !(strings.Index(leadStr, "INTERVAL ") == 0) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr = strings.TrimSpace(leadStr[strings.Index(leadStr, " "):]) + + endIndex := 0 + var valueStr string + + if endIndex = strings.Index(leadStr[1:], "'"); leadStr[0] == '\'' && endIndex != -1 { + endIndex += 1 + valueStr = strings.TrimSpace(leadStr[1:endIndex]) + valueStr = dt.checkSign(valueStr) + leadStr = strings.TrimSpace(leadStr[endIndex+1:]) + } + + if valueStr == "" { + leadStr = dt.checkSign(leadStr) + if endIndex = strings.Index(leadStr[1:], "'"); leadStr[0] != '\'' || endIndex == -1 { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + endIndex += 1 + valueStr = strings.TrimSpace(leadStr[1:endIndex]) + leadStr = strings.TrimSpace(leadStr[endIndex+1:]) + } + + strLeadPrec := "" + strSecPrec := "" + + leadPrecIndex := 0 + secPrecIndex := 0 + toIndex := 0 + + if leadPrecIndex = strings.Index(leadStr, "DAY"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr[leadPrecIndex:], "TO") + + if toIndex == -1 { + strLeadPrec = strings.TrimSpace(leadStr[leadPrecIndex:]) + if err := dt.setDay(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + toIndex += leadPrecIndex + strLeadPrec = strings.TrimSpace(leadStr[leadPrecIndex:toIndex]) + + if strings.Index(leadStr[toIndex:], "HOUR") != -1 { + if err := dt.setDayToHour(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if strings.Index(leadStr[toIndex:], "MINUTE") != -1 { + if err := dt.setDayToMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + secPrecIndex += toIndex + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setDayToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "HOUR"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr[leadPrecIndex:], "TO") + + if toIndex == -1 { + toIndex += leadPrecIndex + strLeadPrec = leadStr[leadPrecIndex:] + if err := dt.setHour(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + strLeadPrec = leadStr[leadPrecIndex:toIndex] + + if strings.Index(leadStr[toIndex:], "MINUTE") != -1 { + if err := dt.setHourToMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + secPrecIndex += toIndex + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setHourToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "MINUTE"); leadPrecIndex != -1 { + toIndex = strings.Index(leadStr, "TO") + + if toIndex == -1 { + toIndex += leadPrecIndex + strLeadPrec = leadStr[leadPrecIndex:] + if err := dt.setMinute(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + strLeadPrec = leadStr[leadPrecIndex:toIndex] + + if secPrecIndex = strings.Index(leadStr[toIndex:], "SECOND"); secPrecIndex != -1 { + strSecPrec = leadStr[secPrecIndex:] + if err := dt.setMinuteToSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + if leadPrecIndex = strings.Index(leadStr, "SECOND"); leadPrecIndex != -1 { + if err := dt.setSecond(valueStr); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + leadStr = strings.TrimSpace(leadStr[leadPrecIndex:]) + + colonIndex := strings.Index(leadStr, ",") + if colonIndex != -1 { + strLeadPrec = strings.TrimSpace(leadStr[:colonIndex]) + ")" + strSecPrec = "(" + strings.TrimSpace(leadStr[:colonIndex+1]) + } + + if err := dt.setPrecForSvr(leadStr, strLeadPrec, strSecPrec); err != nil { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + return dt, nil + } + + return nil, ECGO_INVALID_TIME_INTERVAL.throw() +} + +func (dt *DmIntervalDT) GetDay() int { + return dt.days +} + +func (dt *DmIntervalDT) GetHour() int { + return dt.hours +} + +func (dt *DmIntervalDT) GetMinute() int { + return dt.minutes +} + +func (dt *DmIntervalDT) GetSecond() int { + return dt.seconds +} + +func (dt *DmIntervalDT) GetMsec() int { + return dt.fraction +} + +func (dt *DmIntervalDT) GetDTType() byte { + return dt._type +} + +func (dt *DmIntervalDT) String() string { + if !dt.Valid { + return "" + } + var l, destLen int + var dStr, hStr, mStr, sStr, nStr string + interval := "INTERVAL " + + switch dt._type { + case QUA_D: + dStr := strconv.FormatInt(int64(float64(dt.days)), 10) + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + + interval += "'" + dStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_DH: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + + if len(hStr) < 2 { + hStr = "0" + hStr + } + + interval += "'" + dStr + " " + hStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO HOUR" + case QUA_DHM: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + if len(hStr) < 2 { + hStr = "0" + hStr + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + interval += "'" + dStr + " " + hStr + ":" + mStr + "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO MINUTE" + case QUA_DHMS: + dStr = strconv.FormatInt(int64(float64(dt.days)), 10) + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + nStr = dt.getMsecString() + if dt.negative { + interval += "-" + } + + if len(dStr) < dt.leadScale { + l = len(dStr) + destLen = dt.leadScale + + for destLen > l { + dStr = "0" + dStr + destLen-- + } + } + if len(hStr) < 2 { + hStr = "0" + hStr + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + interval += "'" + dStr + " " + hStr + ":" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' DAY(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + case QUA_H: + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + + interval += "'" + hStr + "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_HM: + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + + interval += "'" + hStr + ":" + mStr + "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO MINUTE" + case QUA_HMS: + nStr = dt.getMsecString() + hStr = strconv.FormatInt(int64(float64(dt.hours)), 10) + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(hStr) < dt.leadScale { + l = len(hStr) + destLen = dt.leadScale + + for destLen > l { + hStr = "0" + hStr + destLen-- + } + } + if len(mStr) < 2 { + mStr = "0" + mStr + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + + interval += "'" + hStr + ":" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' HOUR(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + + case QUA_M: + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + + if dt.negative { + interval += "-" + } + + if len(mStr) < dt.leadScale { + l = len(mStr) + destLen = dt.leadScale + + for destLen > l { + mStr = "0" + mStr + destLen-- + } + } + + interval += "'" + mStr + "' MINUTE(" + strconv.FormatInt(int64(dt.leadScale), 10) + ")" + case QUA_MS: + nStr = dt.getMsecString() + mStr = strconv.FormatInt(int64(float64(dt.minutes)), 10) + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(mStr) < dt.leadScale { + l = len(mStr) + destLen = dt.leadScale + + for destLen > l { + mStr = "0" + mStr + destLen-- + } + } + if len(sStr) < 2 { + sStr = "0" + sStr + } + interval += "'" + mStr + ":" + sStr + if nStr != "" { + interval += "." + nStr + } + + interval += "' MINUTE(" + strconv.FormatInt(int64(dt.leadScale), 10) + ") TO SECOND(" + strconv.FormatInt(int64(dt.secScale), 10) + ")" + case QUA_S: + nStr = dt.getMsecString() + sStr = strconv.FormatInt(int64(float64(dt.seconds)), 10) + + if dt.negative { + interval += "-" + } + + if len(sStr) < dt.leadScale { + l = len(sStr) + destLen = dt.leadScale + + for destLen > l { + sStr = "0" + sStr + destLen-- + } + } + + interval += "'" + sStr + + if nStr != "" { + interval += "." + nStr + } + + interval += "' SECOND(" + strconv.FormatInt(int64(dt.leadScale), 10) + ", " + strconv.FormatInt(int64(dt.secScale), 10) + ")" + + } + + return interval +} + +func (dest *DmIntervalDT) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmIntervalDT) + + (*dest).Valid = false + return nil + case *DmIntervalDT: + *dest = *src + return nil + case string: + ret, err := NewDmIntervalDTByString(src) + if err != nil { + return err + } + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (dt DmIntervalDT) Value() (driver.Value, error) { + if !dt.Valid { + return nil, nil + } + return dt, nil +} + +func (dt *DmIntervalDT) checkScale(leadScale int) (int, error) { + switch dt._type { + case QUA_D: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DH: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + if int64(math.Abs(float64((dt.hours)))) > 23 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DHM: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.hours))) > 23 || int64(math.Abs(float64(dt.minutes))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_DHMS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.days))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.hours))) > 23 || int64(math.Abs(float64(dt.minutes))) > 59 || + int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_H: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_HM: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.minutes))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_HMS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.hours))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.minutes))) > 59 || int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_M: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_MS: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + if int64(math.Abs(float64(dt.seconds))) > 59 { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_S: + if leadScale == -1 { + leadScale = len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) + } else if leadScale < len(strconv.FormatInt(int64(math.Abs(float64(dt.minutes))), 10)) { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + if leadScale > LOADPREC_MAX { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + return leadScale, nil +} + +func (dt *DmIntervalDT) parsePrec(leadStr string) (int, error) { + leftBtId := strings.Index(leadStr, "(") + rightBtId := strings.Index(leadStr, ")") + var prec int64 = -1 + + if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 { + strPrec := strings.TrimSpace(leadStr[leftBtId+1 : rightBtId]) + var err error + prec, err = strconv.ParseInt(strPrec, 10, 32) + if err != nil { + return -1, err + } + } + + return int(prec), nil +} + +func (dt *DmIntervalDT) setPrecForSvr(fullStr string, leadScale string, secScale string) error { + prec, err := dt.parsePrec(leadScale) + if err != nil { + return err + } + + prec, err = dt.checkScale(prec) + if err != nil { + return err + } + + if prec < LOADPREC_DEFAULT { + dt.leadScale = LOADPREC_DEFAULT + } else { + dt.leadScale = prec + } + + prec, err = dt.parsePrec(secScale) + if err != nil { + return err + } + + if prec >= 0 && prec < SECDPREC_MAX { + dt.secScale = prec + } else { + dt.secScale = SECDPREC_DEFAULT + } + + dt.scaleForSvr = (int(dt._type) << 8) + (dt.leadScale << 4) + dt.secScale + return nil +} + +func (dt *DmIntervalDT) checkSign(str string) string { + + if str[0] == '-' { + str = strings.TrimSpace(str[1:]) + dt.negative = true + } else if str[0] == '+' { + str = strings.TrimSpace(str[1:]) + dt.negative = false + } + + return str +} + +func (dt *DmIntervalDT) setDay(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_D + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.days = int(-i) + dt.negative = true + } else { + dt.days = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setHour(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_H + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.hours = int(-i) + dt.negative = true + } else { + dt.hours = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setMinute(value string) error { + list := util.Split(value, " :.") + if len(list) > 1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_M + i, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + + if i < 0 { + dt.minutes = int(-i) + dt.negative = true + } else { + dt.minutes = int(i) + } + return nil +} + +func (dt *DmIntervalDT) setSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_S + i, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 1 { + strNano := "0" + "." + list[1] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if i < 0 { + dt.seconds = int(-i) + } else { + dt.seconds = int(i) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if i < 0 || nano < 0 { + dt.negative = true + } + return nil + +} + +func (dt *DmIntervalDT) setHourToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 4 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_HMS + + h, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + nano := 0 + if len(list) > 3 { + strNano := "0" + "." + list[3] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if h < 0 || m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setHourToMinute(value string) error { + value = strings.TrimSpace(value) + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_HM + + h, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if h < 0 || m < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setMinuteToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 3 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_MS + + m, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 2 { + strNano := "0" + "." + list[2] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToHour(value string) error { + list := util.Split(value, " :.") + if len(list) > 2 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DH + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if d < 0 || h < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToMinute(value string) error { + list := util.Split(value, " :.") + if len(list) > 3 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DHM + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if d < 0 || h < 0 || m < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) setDayToSecond(value string) error { + list := util.Split(value, " :.") + if len(list) > 5 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + dt._type = QUA_DHMS + + d, err := strconv.ParseInt(list[0], 10, 32) + if err != nil { + return err + } + + h, err := strconv.ParseInt(list[1], 10, 32) + if err != nil { + return err + } + + m, err := strconv.ParseInt(list[2], 10, 32) + if err != nil { + return err + } + + s, err := strconv.ParseInt(list[3], 10, 32) + if err != nil { + return err + } + + nano := 0 + if len(list) > 4 { + strNano := "0" + "." + list[4] + d_v, err := strconv.ParseFloat(strNano, 64) + if err != nil { + return err + } + + nx := math.Pow10(dt.secScale) + nano = (int)(d_v * nx) + } + + if d < 0 { + dt.days = int(-d) + } else { + dt.days = int(d) + } + if h < 0 { + dt.hours = int(-h) + } else { + dt.hours = int(h) + } + if m < 0 { + dt.minutes = int(-m) + } else { + dt.minutes = int(m) + } + if s < 0 { + dt.seconds = int(-s) + } else { + dt.seconds = int(s) + } + if nano < 0 { + dt.fraction = -nano + } else { + dt.fraction = nano + } + if d < 0 || h < 0 || m < 0 || s < 0 || nano < 0 { + dt.negative = true + } + return nil +} + +func (dt *DmIntervalDT) getMsecString() string { + nano := strconv.Itoa(dt.fraction) + + for i := 6 - len(nano); i > 0; i-- { + nano = "0" + nano + } + + if len(nano) > dt.secScale { + nano = nano[:dt.secScale] + } + + return nano +} + +func (dt *DmIntervalDT) encode(scale int) ([]byte, error) { + if scale == 0 { + scale = dt.scaleForSvr + } + day, hour, minute, second, f := dt.days, dt.hours, dt.minutes, dt.seconds, dt.fraction + if scale != dt.scaleForSvr { + convertDT, err := dt.convertTo(scale) + if err != nil { + return nil, err + } + day, hour, minute, second, f = convertDT.days, convertDT.hours, convertDT.minutes, convertDT.seconds, convertDT.fraction + } else { + loadPrec := (scale >> 4) & 0x0000000F + if _, err := dt.checkScale(loadPrec); err != nil { + return nil, err + } + } + + bytes := make([]byte, 24) + if dt.negative { + Dm_build_1346.Dm_build_1362(bytes, 0, int32(-day)) + Dm_build_1346.Dm_build_1362(bytes, 4, int32(-hour)) + Dm_build_1346.Dm_build_1362(bytes, 8, int32(-minute)) + Dm_build_1346.Dm_build_1362(bytes, 12, int32(-second)) + Dm_build_1346.Dm_build_1362(bytes, 16, int32(-f)) + Dm_build_1346.Dm_build_1362(bytes, 20, int32(scale)) + } else { + Dm_build_1346.Dm_build_1362(bytes, 0, int32(day)) + Dm_build_1346.Dm_build_1362(bytes, 4, int32(hour)) + Dm_build_1346.Dm_build_1362(bytes, 8, int32(minute)) + Dm_build_1346.Dm_build_1362(bytes, 12, int32(second)) + Dm_build_1346.Dm_build_1362(bytes, 16, int32(f)) + Dm_build_1346.Dm_build_1362(bytes, 20, int32(scale)) + } + return bytes, nil +} + +func (dt *DmIntervalDT) convertTo(scale int) (*DmIntervalDT, error) { + destType := (scale & 0x0000FF00) >> 8 + leadPrec := (scale >> 4) & 0x0000000F + secScale := scale & 0x0000000F + dayIndex := 0 + hourIndex := 1 + minuteIndex := 2 + secondIndex := 3 + fractionIndex := 4 + orgDT := make([]int, 5) + destDT := make([]int, 5) + + switch dt._type { + case QUA_D: + orgDT[dayIndex] = dt.days + case QUA_DH: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + case QUA_DHM: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + orgDT[minuteIndex] = dt.minutes + case QUA_DHMS: + orgDT[dayIndex] = dt.days + orgDT[hourIndex] = dt.hours + orgDT[minuteIndex] = dt.minutes + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_H: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + case QUA_HM: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + orgDT[minuteIndex] = dt.minutes + case QUA_HMS: + orgDT[dayIndex] = dt.hours / 24 + orgDT[hourIndex] = dt.hours % 24 + orgDT[minuteIndex] = dt.minutes + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_M: + orgDT[dayIndex] = dt.minutes / (24 * 60) + orgDT[hourIndex] = (dt.minutes % (24 * 60)) / 60 + orgDT[minuteIndex] = (dt.minutes % (24 * 60)) % 60 + case QUA_MS: + orgDT[dayIndex] = dt.minutes / (24 * 60) + orgDT[hourIndex] = (dt.minutes % (24 * 60)) / 60 + orgDT[minuteIndex] = (dt.minutes % (24 * 60)) % 60 + orgDT[secondIndex] = dt.seconds + orgDT[fractionIndex] = dt.fraction + case QUA_S: + orgDT[dayIndex] = dt.seconds / (24 * 60 * 60) + orgDT[hourIndex] = (dt.seconds % (24 * 60 * 60)) / (60 * 60) + orgDT[minuteIndex] = ((dt.seconds % (24 * 60 * 60)) % (60 * 60)) / 60 + orgDT[secondIndex] = ((dt.seconds % (24 * 60 * 60)) % (60 * 60)) % 60 + orgDT[fractionIndex] = dt.fraction + } + + switch byte(destType) { + case QUA_D: + destDT[dayIndex] = orgDT[dayIndex] + if orgDT[hourIndex] >= 12 { + incrementDay(QUA_D, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DH: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + if orgDT[minuteIndex] >= 30 { + incrementHour(QUA_DH, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DHM: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_DHM, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_DHMS: + destDT[dayIndex] = orgDT[dayIndex] + destDT[hourIndex] = orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_DHMS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[dayIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_H: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + if orgDT[minuteIndex] >= 30 { + incrementHour(QUA_H, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_HM: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_HM, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_HMS: + destDT[hourIndex] = orgDT[dayIndex]*24 + orgDT[hourIndex] + destDT[minuteIndex] = orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_HMS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[hourIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_M: + destDT[minuteIndex] = orgDT[dayIndex]*24*60 + orgDT[hourIndex]*60 + orgDT[minuteIndex] + if orgDT[secondIndex] >= 30 { + incrementMinute(QUA_M, destDT) + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[minuteIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_MS: + destDT[minuteIndex] = orgDT[dayIndex]*24*60 + orgDT[hourIndex]*60 + orgDT[minuteIndex] + destDT[secondIndex] = orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_MS, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[minuteIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + case QUA_S: + destDT[secondIndex] = orgDT[dayIndex]*24*60*60 + orgDT[hourIndex]*60*60 + orgDT[minuteIndex]*60 + orgDT[secondIndex] + destDT[fractionIndex] = orgDT[fractionIndex] + dt.convertMSecond(QUA_S, destDT, secScale) + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(destDT[secondIndex]))))) { + return nil, ECGO_INTERVAL_OVERFLOW.throw() + } + } + + return &DmIntervalDT{ + _type: byte(destType), + negative: dt.negative, + leadScale: (scale >> 4) & 0x0000000F, + secScale: scale & 0x0000000F, + scaleForSvr: scale, + days: destDT[dayIndex], + hours: destDT[hourIndex], + minutes: destDT[minuteIndex], + seconds: destDT[secondIndex], + fraction: destDT[fractionIndex], + Valid: true, + }, nil +} + +func (dt DmIntervalDT) convertMSecond(destType byte, destDT []int, destSecScale int) { + fractionIndex := 4 + orgFraction := destDT[fractionIndex] + if destSecScale == 0 || destSecScale < dt.secScale { + n := int(math.Pow(10, 6-float64(destSecScale)-1)) + f := orgFraction / n / 10 + + if (orgFraction/n)%10 >= 5 { + f++ + f = f * n * 10 + if f == 1000000 { + destDT[fractionIndex] = 0 + incrementSecond(destType, destDT) + return + } + } + destDT[fractionIndex] = f + } +} + +func incrementDay(destType byte, dt []int) { + dayIndex := 0 + dt[dayIndex]++ +} + +func incrementHour(destType byte, dt []int) { + hourIndex := 1 + dt[hourIndex]++ + if dt[hourIndex] == 24 && destType < QUA_H { + incrementDay(destType, dt) + dt[hourIndex] = 0 + } +} + +func incrementMinute(destType byte, dt []int) { + minuteIndex := 2 + dt[minuteIndex]++ + if dt[minuteIndex] == 60 && destType < QUA_M { + incrementHour(destType, dt) + dt[minuteIndex] = 0 + } +} + +func incrementSecond(destType byte, dt []int) { + secondIndex := 3 + dt[secondIndex]++ + if dt[secondIndex] == 60 && destType < QUA_S { + incrementMinute(destType, dt) + dt[secondIndex] = 0 + } +} + +func (dt *DmIntervalDT) checkValid() error { + if !dt.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} + +func (d *DmIntervalDT) GormDataType() string { + return "INTERVAL DAY TO SECOND" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/r.go b/dpi_bridge/third_party/chunanyong_dm/r.go new file mode 100644 index 0000000..d68a9dc --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/r.go @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "math" + "strconv" + "strings" + + "gitee.com/chunanyong/dm/util" +) + +const ( + QUA_Y = 0 + QUA_YM = 1 + QUA_MO = 2 +) + +type DmIntervalYM struct { + leadScale int + isLeadScaleSet bool + _type byte + years int + months int + scaleForSvr int + + Valid bool +} + +func newDmIntervalYM() *DmIntervalYM { + return &DmIntervalYM{ + Valid: true, + } +} + +func NewDmIntervalYMByString(str string) (ym *DmIntervalYM, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_TIME_INTERVAL.throw() + } + }() + ym = newDmIntervalYM() + ym.isLeadScaleSet = false + if err = ym.parseIntervYMString(strings.TrimSpace(str)); err != nil { + return nil, err + } + return ym, nil +} + +func newDmIntervalYMByBytes(bytes []byte) *DmIntervalYM { + ym := newDmIntervalYM() + + ym.scaleForSvr = int(Dm_build_1346.Dm_build_1448(bytes, 8)) + ym.leadScale = (ym.scaleForSvr >> 4) & 0x0000000F + ym._type = bytes[9] + switch ym._type { + case QUA_Y: + ym.years = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + case QUA_YM: + ym.years = int(Dm_build_1346.Dm_build_1448(bytes, 0)) + ym.months = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + case QUA_MO: + ym.months = int(Dm_build_1346.Dm_build_1448(bytes, 4)) + } + return ym +} + +func (ym *DmIntervalYM) GetYear() int { + return ym.years +} + +func (ym *DmIntervalYM) GetMonth() int { + return ym.months +} + +func (ym *DmIntervalYM) GetYMType() byte { + return ym._type +} + +func (ym *DmIntervalYM) String() string { + if !ym.Valid { + return "" + } + str := "INTERVAL " + var year, month string + var l int + var destLen int + + switch ym._type { + case QUA_Y: + year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) + if ym.years < 0 { + str += "-" + } + + if ym.leadScale > len(year) { + l = len(year) + destLen = ym.leadScale + + for destLen > l { + year = "0" + year + destLen-- + } + } + + str += "'" + year + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" + case QUA_YM: + year = strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10) + month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) + + if ym.years < 0 || ym.months < 0 { + str += "-" + } + + if ym.leadScale > len(year) { + l = len(year) + destLen = ym.leadScale + + for destLen > l { + year = "0" + year + destLen-- + } + } + + if len(month) < 2 { + month = "0" + month + } + + str += "'" + year + "-" + month + "' YEAR(" + strconv.FormatInt(int64(ym.leadScale), 10) + ") TO MONTH" + case QUA_MO: + + month = strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10) + if ym.months < 0 { + str += "-" + } + + if ym.leadScale > len(month) { + l = len(month) + destLen = ym.leadScale + for destLen > l { + month = "0" + month + destLen-- + } + } + + str += "'" + month + "' MONTH(" + strconv.FormatInt(int64(ym.leadScale), 10) + ")" + } + return str +} + +func (dest *DmIntervalYM) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmIntervalYM) + + (*dest).Valid = false + return nil + case *DmIntervalYM: + *dest = *src + return nil + case string: + ret, err := NewDmIntervalYMByString(src) + if err != nil { + return err + } + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (ym DmIntervalYM) Value() (driver.Value, error) { + if !ym.Valid { + return nil, nil + } + return ym, nil +} + +func (ym *DmIntervalYM) parseIntervYMString(str string) error { + str = strings.ToUpper(str) + ret := strings.Split(str, " ") + l := len(ret) + if l < 3 || !util.StringUtil.EqualsIgnoreCase(ret[0], "INTERVAL") || !(strings.HasPrefix(ret[2], "YEAR") || strings.HasPrefix(ret[2], "MONTH")) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + ym._type = QUA_YM + yearId := strings.Index(str, "YEAR") + monthId := strings.Index(str, "MONTH") + toId := strings.Index(str, "TO") + var err error + if toId == -1 { + if yearId != -1 && monthId == -1 { + ym._type = QUA_Y + ym.leadScale, err = ym.getLeadPrec(str, yearId) + if err != nil { + return err + } + } else if monthId != -1 && yearId == -1 { + ym._type = QUA_MO + ym.leadScale, err = ym.getLeadPrec(str, monthId) + if err != nil { + return err + } + } else { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + if yearId == -1 || monthId == -1 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + ym._type = QUA_YM + ym.leadScale, err = ym.getLeadPrec(str, yearId) + if err != nil { + return err + } + } + + ym.scaleForSvr = (int(ym._type) << 8) + (ym.leadScale << 4) + timeVals, err := ym.getTimeValue(ret[1], int(ym._type)) + if err != nil { + return err + } + ym.years = timeVals[0] + ym.months = timeVals[1] + return ym.checkScale(ym.leadScale) +} + +func (ym *DmIntervalYM) getLeadPrec(str string, startIndex int) (int, error) { + if ym.isLeadScaleSet { + return ym.leadScale, nil + } + + leftBtId := strings.Index(str[startIndex:], "(") + rightBtId := strings.Index(str[startIndex:], ")") + leadPrec := 0 + + if rightBtId == -1 && leftBtId == -1 { + leftBtId += startIndex + rightBtId += startIndex + l := strings.Index(str, "'") + var r int + var dataStr string + if l != -1 { + r = strings.Index(str[l+1:], "'") + if r != -1 { + r += l + 1 + } + } else { + r = -1 + } + + if r != -1 { + dataStr = strings.TrimSpace(str[l+1 : r]) + } else { + dataStr = "" + } + + if dataStr != "" { + sign := dataStr[0] + if sign == '+' || sign == '-' { + dataStr = strings.TrimSpace(dataStr[1:]) + } + end := strings.Index(dataStr, "-") + + if end != -1 { + dataStr = dataStr[:end] + } + + leadPrec = len(dataStr) + } else { + leadPrec = 2 + } + } else if rightBtId != -1 && leftBtId != -1 && rightBtId > leftBtId+1 { + leftBtId += startIndex + rightBtId += startIndex + strPrec := strings.TrimSpace(str[leftBtId+1 : rightBtId]) + temp, err := strconv.ParseInt(strPrec, 10, 32) + if err != nil { + return 0, err + } + + leadPrec = int(temp) + } else { + return 0, ECGO_INVALID_TIME_INTERVAL.throw() + } + + return leadPrec, nil +} + +func (ym *DmIntervalYM) checkScale(prec int) error { + switch ym._type { + case QUA_Y: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_YM: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.years))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + + if int64(math.Abs(float64(ym.months))) > 11 { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + + case QUA_MO: + if prec < len(strconv.FormatInt(int64(math.Abs(float64(ym.months))), 10)) { + return ECGO_INVALID_TIME_INTERVAL.throw() + } + } + return nil +} + +func (ym *DmIntervalYM) getTimeValue(subStr string, _type int) ([]int, error) { + hasQuate := false + if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { + hasQuate = true + subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) + } + + negative := false + if strings.Index(subStr, "-") == 0 { + negative = true + subStr = subStr[1:] + } else if strings.Index(subStr, "+") == 0 { + negative = false + subStr = subStr[1:] + } + + if subStr[0] == '\'' && subStr[len(subStr)-1] == '\'' { + hasQuate = true + subStr = strings.TrimSpace(subStr[1 : len(subStr)-1]) + } + + if !hasQuate { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + + lastSignIndex := strings.LastIndex(subStr, "-") + + list := make([]string, 2) + if lastSignIndex == -1 || lastSignIndex == 0 { + list[0] = subStr + list[1] = "" + } else { + list[0] = subStr[0:lastSignIndex] + list[1] = subStr[lastSignIndex+1:] + } + + var yearVal, monthVal int64 + var err error + if ym._type == QUA_YM { + yearVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + + if util.StringUtil.EqualsIgnoreCase(list[1], "") { + monthVal = 0 + } else { + monthVal, err = strconv.ParseInt(list[1], 10, 32) + if err != nil { + return nil, err + } + } + + if negative { + yearVal *= -1 + monthVal *= -1 + } + + if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else if ym._type == QUA_Y { + yearVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + monthVal = 0 + + if negative { + yearVal *= -1 + } + + if yearVal > int64(math.Pow10(ym.leadScale))-1 || yearVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } else { + yearVal = 0 + monthVal, err = strconv.ParseInt(list[0], 10, 32) + if err != nil { + return nil, err + } + if negative { + monthVal *= -1 + } + + if monthVal > int64(math.Pow10(ym.leadScale))-1 || monthVal < 1-int64(math.Pow10(ym.leadScale)) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + + ret := make([]int, 2) + ret[0] = int(yearVal) + ret[1] = int(monthVal) + + return ret, nil +} + +func (ym *DmIntervalYM) encode(scale int) ([]byte, error) { + if scale == 0 { + scale = ym.scaleForSvr + } + year, month := ym.years, ym.months + if err := ym.checkScale(ym.leadScale); err != nil { + return nil, err + } + if scale != ym.scaleForSvr { + convertYM, err := ym.convertTo(scale) + if err != nil { + return nil, err + } + year = convertYM.years + month = convertYM.months + } else { + if err := ym.checkScale(ym.leadScale); err != nil { + return nil, err + } + } + + bytes := make([]byte, 12) + Dm_build_1346.Dm_build_1362(bytes, 0, int32(year)) + Dm_build_1346.Dm_build_1362(bytes, 4, int32(month)) + Dm_build_1346.Dm_build_1362(bytes, 8, int32(scale)) + return bytes, nil +} + +func (ym *DmIntervalYM) convertTo(scale int) (*DmIntervalYM, error) { + destType := (scale & 0x0000FF00) >> 8 + leadPrec := (scale >> 4) & 0x0000000F + totalMonths := ym.years*12 + ym.months + year := 0 + month := 0 + switch destType { + case QUA_Y: + year = totalMonths / 12 + + if totalMonths%12 >= 6 { + year++ + } else if totalMonths%12 <= -6 { + year-- + } + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_YM: + year = totalMonths / 12 + month = totalMonths % 12 + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(year))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + case QUA_MO: + month = totalMonths + if leadPrec < len(strconv.Itoa(int(math.Abs(float64(month))))) { + return nil, ECGO_INVALID_TIME_INTERVAL.throw() + } + } + return &DmIntervalYM{ + _type: byte(destType), + years: year, + months: month, + scaleForSvr: scale, + leadScale: (scale >> 4) & 0x0000000F, + Valid: true, + }, nil +} + +func (ym *DmIntervalYM) checkValid() error { + if !ym.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} + +func (d *DmIntervalYM) GormDataType() string { + return "INTERVAL YEAR TO MONTH" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/s.go b/dpi_bridge/third_party/chunanyong_dm/s.go new file mode 100644 index 0000000..5b75034 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/s.go @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import "strings" + +type DmResult struct { + filterable + dmStmt *DmStatement + affectedRows int64 + insertId int64 +} + +func newDmResult(bs *DmStatement, execInfo *execRetInfo) *DmResult { + result := DmResult{} + result.resetFilterable(&bs.filterable) + result.dmStmt = bs + result.affectedRows = execInfo.updateCount + + if execInfo.lastInsertId == 0 && execInfo.hasResultSet && strings.Index(execInfo.nativeSQL, "/*DMGORM-UPSERT*/") == 0 { + if len(execInfo.rsDatas) > 0 && len(execInfo.rsDatas[0]) > 0 { + result.insertId = Dm_build_1346.Dm_build_1576(execInfo.rsDatas[0][1]) + } else { + result.insertId = 0 + } + } else { + result.insertId = execInfo.lastInsertId + } + result.idGenerator = dmResultIDGenerator + + return &result +} + +func (r *DmResult) LastInsertId() (int64, error) { + + if len(r.filterChain.filters) == 0 { + return r.lastInsertId() + } + return r.filterChain.reset().DmResultLastInsertId(r) +} + +func (r *DmResult) RowsAffected() (int64, error) { + + if len(r.filterChain.filters) == 0 { + return r.rowsAffected() + } + return r.filterChain.reset().DmResultRowsAffected(r) +} + +func (result *DmResult) lastInsertId() (int64, error) { + return result.insertId, nil +} + +func (result *DmResult) rowsAffected() (int64, error) { + return result.affectedRows, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zy.go b/dpi_bridge/third_party/chunanyong_dm/security/zy.go new file mode 100644 index 0000000..b3ccc38 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zy.go @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +// This is a mirror of golang.org/x/crypto/internal/subtle. +package security + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zz.go b/dpi_bridge/third_party/chunanyong_dm/security/zz.go new file mode 100644 index 0000000..45b2c1a --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zz.go @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +type Cipher interface { + Encrypt(plaintext []byte, genDigest bool) []byte + Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zza.go b/dpi_bridge/third_party/chunanyong_dm/security/zza.go new file mode 100644 index 0000000..92062ce --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zza.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/rand" + "errors" + "io" + "math/big" +) + +type dhGroup struct { + p *big.Int + g *big.Int +} + +func newDhGroup(prime, generator *big.Int) *dhGroup { + return &dhGroup{ + p: prime, + g: generator, + } +} + +func (dg *dhGroup) P() *big.Int { + p := new(big.Int) + p.Set(dg.p) + return p +} + +func (dg *dhGroup) G() *big.Int { + g := new(big.Int) + g.Set(dg.g) + return g +} + +// 生成本地公私钥 +func (dg *dhGroup) GeneratePrivateKey(randReader io.Reader) (key *DhKey, err error) { + if randReader == nil { + randReader = rand.Reader + } + // 0 < x < p + x, err := rand.Int(randReader, dg.p) + if err != nil { + return + } + zero := big.NewInt(0) + for x.Cmp(zero) == 0 { + x, err = rand.Int(randReader, dg.p) + if err != nil { + return + } + } + key = new(DhKey) + key.x = x + + // y = g ^ x mod p + key.y = new(big.Int).Exp(dg.g, x, dg.p) + key.group = dg + return +} + +func (dg *dhGroup) ComputeKey(pubkey *DhKey, privkey *DhKey) (kye *DhKey, err error) { + if dg.p == nil { + err = errors.New("DH: invalid group") + return + } + if pubkey.y == nil { + err = errors.New("DH: invalid public key") + return + } + if pubkey.y.Sign() <= 0 || pubkey.y.Cmp(dg.p) >= 0 { + err = errors.New("DH parameter out of bounds") + return + } + if privkey.x == nil { + err = errors.New("DH: invalid private key") + return + } + k := new(big.Int).Exp(pubkey.y, privkey.x, dg.p) + key := new(DhKey) + key.y = k + key.group = dg + return +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzb.go b/dpi_bridge/third_party/chunanyong_dm/security/zzb.go new file mode 100644 index 0000000..f9af994 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzb.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "math/big" + +type DhKey struct { + x *big.Int + y *big.Int + group *dhGroup +} + +func newPublicKey(s []byte) *DhKey { + key := new(DhKey) + key.y = new(big.Int).SetBytes(s) + return key +} + +func (dk *DhKey) GetX() *big.Int { + x := new(big.Int) + x.Set(dk.x) + return x +} + +func (dk *DhKey) GetY() *big.Int { + y := new(big.Int) + y.Set(dk.y) + return y +} + +func (dk *DhKey) GetYBytes() []byte { + if dk.y == nil { + return nil + } + if dk.group != nil { + blen := (dk.group.p.BitLen() + 7) / 8 + ret := make([]byte, blen) + copyWithLeftPad(ret, dk.y.Bytes()) + return ret + } + return dk.y.Bytes() +} + +func (dk *DhKey) GetYString() string { + if dk.y == nil { + return "" + } + return dk.y.String() +} + +func (dk *DhKey) IsPrivateKey() bool { + return dk.x != nil +} + +func copyWithLeftPad(dest, src []byte) { + numPaddingBytes := len(dest) - len(src) + for i := 0; i < numPaddingBytes; i++ { + dest[i] = 0 + } + copy(dest[:numPaddingBytes], src) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzc.go b/dpi_bridge/third_party/chunanyong_dm/security/zzc.go new file mode 100644 index 0000000..ee09356 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzc.go @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +// go官方没有实现ecb加密模式 +package security + +import ( + "crypto/cipher" +) + +type ecb struct { + b cipher.Block + blockSize int +} + +func newECB(b cipher.Block) *ecb { + return &ecb{ + b: b, + blockSize: b.BlockSize(), + } +} + +type ecbEncrypter ecb + +func NewECBEncrypter(b cipher.Block) cipher.BlockMode { + return (*ecbEncrypter)(newECB(b)) +} + +func (x *ecbEncrypter) BlockSize() int { return x.blockSize } + +func (x *ecbEncrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("dm/security: input not full blocks") + } + if len(dst) < len(src) { + panic("dm/security: output smaller than input") + } + if InexactOverlap(dst[:len(src)], src) { + panic("dm/security: invalid buffer overlap") + } + for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs+x.blockSize, be+x.blockSize { + x.b.Encrypt(dst[bs:be], src[bs:be]) + } +} + +type ecbDecrypter ecb + +func NewECBDecrypter(b cipher.Block) cipher.BlockMode { + return (*ecbDecrypter)(newECB(b)) +} + +func (x *ecbDecrypter) BlockSize() int { return x.blockSize } + +func (x *ecbDecrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("dm/security: input not full blocks") + } + if len(dst) < len(src) { + panic("dm/security: output smaller than input") + } + if InexactOverlap(dst[:len(src)], src) { + panic("dm/security: invalid buffer overlap") + } + for bs, be := 0, x.blockSize; bs < len(src); bs, be = bs+x.blockSize, be+x.blockSize { + x.b.Decrypt(dst[bs:be], src[bs:be]) + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzd.go b/dpi_bridge/third_party/chunanyong_dm/security/zzd.go new file mode 100644 index 0000000..bedbc54 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzd.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "math/big" +) + +const ( + DH_KEY_LENGTH int = 64 + /* 低7位用于保存分组加密算法中的工作模式 */ + WORK_MODE_MASK int = 0x007f + ECB_MODE int = 0x1 + CBC_MODE int = 0x2 + CFB_MODE int = 0x4 + OFB_MODE int = 0x8 + /* 高位保存加密算法 */ + ALGO_MASK int = 0xff80 + DES int = 0x0080 + DES3 int = 0x0100 + AES128 int = 0x0200 + AES192 int = 0x0400 + AES256 int = 0x0800 + RC4 int = 0x1000 + MD5 int = 0x1100 + + // 用户名密码加密算法 + DES_CFB int = 132 + // 消息加密摘要长度 + MD5_DIGEST_SIZE int = 16 + + MIN_EXTERNAL_CIPHER_ID int = 5000 +) + +var dhParaP = "C009D877BAF5FAF416B7F778E6115DCB90D65217DCC2F08A9DFCB5A192C593EBAB02929266B8DBFC2021039FDBD4B7FDE2B996E00008F57AE6EFB4ED3F17B6D3" +var dhParaG = "5" +var defaultIV = []byte{0x20, 0x21, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x20} +var p *big.Int +var g *big.Int + +func NewClientKeyPair() (key *DhKey, err error) { + p, _ = new(big.Int).SetString(dhParaP, 16) + g, _ = new(big.Int).SetString(dhParaG, 16) + dhGroup := newDhGroup(p, g) + key, err = dhGroup.GeneratePrivateKey(nil) + if err != nil { + return nil, err + } + return key, nil +} + +func ComputeSessionKey(clientPrivKey *DhKey, serverPubKey []byte) []byte { + serverKeyX := bytes2Bn(serverPubKey) + clientPrivKeyX := clientPrivKey.GetX() + sessionKeyBN := serverKeyX.Exp(serverKeyX, clientPrivKeyX, p) + return Bn2Bytes(sessionKeyBN, 0) +} + +func bytes2Bn(bnBytesSrc []byte) *big.Int { + if bnBytesSrc == nil { + return nil + } + if bnBytesSrc[0] == 0 { + return new(big.Int).SetBytes(bnBytesSrc) + } + validBytesCount := len(bnBytesSrc) + 1 + bnBytesTo := make([]byte, validBytesCount) + bnBytesTo[0] = 0 + copy(bnBytesTo[1:validBytesCount], bnBytesSrc) + return new(big.Int).SetBytes(bnBytesTo) +} + +func Bn2Bytes(bn *big.Int, bnLen int) []byte { + var bnBytesSrc, bnBytesTemp, bnBytesTo []byte + var leading_zero_count int + validBytesCount := 0 + if bn == nil { + return nil + } + bnBytesSrc = bn.Bytes() + + // 去除首位0 + if bnBytesSrc[0] != 0 { + bnBytesTemp = bnBytesSrc + validBytesCount = len(bnBytesTemp) + } else { + validBytesCount = len(bnBytesSrc) - 1 + bnBytesTemp = make([]byte, validBytesCount) + copy(bnBytesTemp, bnBytesSrc[1:validBytesCount+1]) + } + + if bnLen == 0 { + leading_zero_count = 0 + } else { + leading_zero_count = bnLen - validBytesCount + } + // 如果位数不足DH_KEY_LENGTH则在前面补0 + if leading_zero_count > 0 { + bnBytesTo = make([]byte, DH_KEY_LENGTH) + i := 0 + for i = 0; i < leading_zero_count; i++ { + bnBytesTo[i] = 0 + } + copy(bnBytesTo[i:i+validBytesCount], bnBytesTemp) + } else { + bnBytesTo = bnBytesTemp + } + return bnBytesTo +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zze.go b/dpi_bridge/third_party/chunanyong_dm/security/zze.go new file mode 100644 index 0000000..ca33e1e --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zze.go @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/des" + "crypto/md5" + "crypto/rc4" + "errors" + "reflect" +) + +type SymmCipher struct { + encryptCipher interface{} //cipher.BlockMode | cipher.Stream + decryptCipher interface{} //cipher.BlockMode | cipher.Stream + key []byte + block cipher.Block // 分组加密算法 + algorithmType int + workMode int + needPadding bool +} + +func NewSymmCipher(algorithmID int, key []byte) (SymmCipher, error) { + var sc SymmCipher + var err error + sc.key = key + sc.algorithmType = algorithmID & ALGO_MASK + sc.workMode = algorithmID & WORK_MODE_MASK + switch sc.algorithmType { + case AES128: + if sc.block, err = aes.NewCipher(key[:16]); err != nil { + return sc, err + } + case AES192: + if sc.block, err = aes.NewCipher(key[:24]); err != nil { + return sc, err + } + case AES256: + if sc.block, err = aes.NewCipher(key[:32]); err != nil { + return sc, err + } + case DES: + if sc.block, err = des.NewCipher(key[:8]); err != nil { + return sc, err + } + case DES3: + var tripleDESKey []byte + tripleDESKey = append(tripleDESKey, key[:16]...) + tripleDESKey = append(tripleDESKey, key[:8]...) + if sc.block, err = des.NewTripleDESCipher(tripleDESKey); err != nil { + return sc, err + } + case RC4: + if sc.encryptCipher, err = rc4.NewCipher(key[:16]); err != nil { + return sc, err + } + if sc.decryptCipher, err = rc4.NewCipher(key[:16]); err != nil { + return sc, err + } + return sc, nil + default: + return sc, errors.New("invalidCipher") + } + blockSize := sc.block.BlockSize() + if sc.encryptCipher, err = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil { + return sc, err + } + if sc.decryptCipher, err = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:blockSize]); err != nil { + return sc, err + } + return sc, nil +} + +func (sc SymmCipher) Encrypt(plaintext []byte, genDigest bool) []byte { + // 执行过加密后,IV值变了,需要重新初始化encryptCipher对象(因为没有类似resetIV的方法) + if sc.algorithmType != RC4 { + sc.encryptCipher, _ = sc.getEncrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()]) + } else { + sc.encryptCipher, _ = rc4.NewCipher(sc.key[:16]) + } + // 填充 + var paddingtext = make([]byte, len(plaintext)) + copy(paddingtext, plaintext) + if sc.needPadding { + paddingtext = pkcs5Padding(paddingtext) + } + + ret := make([]byte, len(paddingtext)) + + if v, ok := sc.encryptCipher.(cipher.Stream); ok { + v.XORKeyStream(ret, paddingtext) + } else if v, ok := sc.encryptCipher.(cipher.BlockMode); ok { + v.CryptBlocks(ret, paddingtext) + } + + // md5摘要 + if genDigest { + digest := md5.Sum(plaintext) + encrypt := ret + ret = make([]byte, len(encrypt)+len(digest)) + copy(ret[:len(encrypt)], encrypt) + copy(ret[len(encrypt):], digest[:]) + } + return ret +} + +func (sc SymmCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) { + // 执行过解密后,IV值变了,需要重新初始化decryptCipher对象(因为没有类似resetIV的方法) + if sc.algorithmType != RC4 { + sc.decryptCipher, _ = sc.getDecrypter(sc.workMode, sc.block, defaultIV[:sc.block.BlockSize()]) + } else { + sc.decryptCipher, _ = rc4.NewCipher(sc.key[:16]) + } + var ret []byte + if checkDigest { + var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:] + ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE] + ret = sc.decrypt(ret) + var msgDigest = md5.Sum(ret) + if !reflect.DeepEqual(msgDigest[:], digest) { + return nil, errors.New("Decrypt failed/Digest not match\n") + } + } else { + ret = sc.decrypt(ciphertext) + } + return ret, nil +} + +func (sc SymmCipher) decrypt(ciphertext []byte) []byte { + ret := make([]byte, len(ciphertext)) + if v, ok := sc.decryptCipher.(cipher.Stream); ok { + v.XORKeyStream(ret, ciphertext) + } else if v, ok := sc.decryptCipher.(cipher.BlockMode); ok { + v.CryptBlocks(ret, ciphertext) + } + // 去除填充 + if sc.needPadding { + ret = pkcs5UnPadding(ret) + } + return ret +} + +func (sc *SymmCipher) getEncrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) { + switch workMode { + case ECB_MODE: + ret = NewECBEncrypter(block) + sc.needPadding = true + case CBC_MODE: + ret = cipher.NewCBCEncrypter(block, iv) + sc.needPadding = true + case CFB_MODE: + ret = cipher.NewCFBEncrypter(block, iv) + sc.needPadding = false + case OFB_MODE: + ret = cipher.NewOFB(block, iv) + sc.needPadding = false + default: + err = errors.New("invalidCipherMode") + } + return +} + +func (sc *SymmCipher) getDecrypter(workMode int, block cipher.Block, iv []byte) (ret interface{}, err error) { + switch workMode { + case ECB_MODE: + ret = NewECBDecrypter(block) + sc.needPadding = true + case CBC_MODE: + ret = cipher.NewCBCDecrypter(block, iv) + sc.needPadding = true + case CFB_MODE: + ret = cipher.NewCFBDecrypter(block, iv) + sc.needPadding = false + case OFB_MODE: + ret = cipher.NewOFB(block, iv) + sc.needPadding = false + default: + err = errors.New("invalidCipherMode") + } + return +} + +// 补码 +func pkcs77Padding(ciphertext []byte, blocksize int) []byte { + padding := blocksize - len(ciphertext)%blocksize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} + +// 去码 +func pkcs7UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:length-unpadding] +} + +// 补码 +func pkcs5Padding(ciphertext []byte) []byte { + return pkcs77Padding(ciphertext, 8) +} + +// 去码 +func pkcs5UnPadding(ciphertext []byte) []byte { + return pkcs7UnPadding(ciphertext) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzf.go b/dpi_bridge/third_party/chunanyong_dm/security/zzf.go new file mode 100644 index 0000000..d002c65 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzf.go @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/md5" + "errors" + "fmt" + "reflect" + "unsafe" +) + +type ThirdPartCipher struct { + encryptType int // 外部加密算法id + encryptName string // 外部加密算法名称 + hashType int + key []byte + cipherCount int // 外部加密算法个数 + //innerId int // 外部加密算法内部id + blockSize int // 分组块大小 + khSize int // key/hash大小 +} + +func NewThirdPartCipher(encryptType int, key []byte, cipherPath string, hashType int) (ThirdPartCipher, error) { + var tpc = ThirdPartCipher{ + encryptType: encryptType, + key: key, + hashType: hashType, + cipherCount: -1, + } + var err error + err = initThirdPartCipher(cipherPath) + if err != nil { + return tpc, err + } + tpc.getCount() + if err = tpc.getInfo(); err != nil { + return tpc, err + } + return tpc, nil +} + +func (tpc *ThirdPartCipher) getCount() int { + if tpc.cipherCount == -1 { + tpc.cipherCount = cipherGetCount() + } + return tpc.cipherCount +} + +func (tpc *ThirdPartCipher) getInfo() error { + var cipher_id, ty, blk_size, kh_size int + //var strptr, _ = syscall.UTF16PtrFromString(tpc.encryptName) + var strptr *uint16 = new(uint16) + for i := 1; i <= tpc.getCount(); i++ { + cipherGetInfo(uintptr(i), uintptr(unsafe.Pointer(&cipher_id)), uintptr(unsafe.Pointer(&strptr)), + uintptr(unsafe.Pointer(&ty)), uintptr(unsafe.Pointer(&blk_size)), uintptr(unsafe.Pointer(&kh_size))) + if tpc.encryptType == cipher_id { + tpc.blockSize = blk_size + tpc.khSize = kh_size + tpc.encryptName = string(uintptr2bytes(uintptr(unsafe.Pointer(strptr)))) + return nil + } + } + return fmt.Errorf("ThirdPartyCipher: cipher id:%d not found", tpc.encryptType) +} + +func (tpc ThirdPartCipher) Encrypt(plaintext []byte, genDigest bool) []byte { + var tmp_para uintptr + cipherEncryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para) + + ciphertextLen := cipherGetCipherTextSize(uintptr(tpc.encryptType), tmp_para, uintptr(len(plaintext))) + + ciphertext := make([]byte, ciphertextLen) + ret := cipherEncrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext)), + uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext))) + ciphertext = ciphertext[:ret] + + cipherClean(uintptr(tpc.encryptType), tmp_para) + // md5摘要 + if genDigest { + digest := md5.Sum(plaintext) + encrypt := ciphertext + ciphertext = make([]byte, len(encrypt)+len(digest)) + copy(ciphertext[:len(encrypt)], encrypt) + copy(ciphertext[len(encrypt):], digest[:]) + } + return ciphertext +} + +func (tpc ThirdPartCipher) Decrypt(ciphertext []byte, checkDigest bool) ([]byte, error) { + var ret []byte + if checkDigest { + var digest = ciphertext[len(ciphertext)-MD5_DIGEST_SIZE:] + ret = ciphertext[:len(ciphertext)-MD5_DIGEST_SIZE] + ret = tpc.decrypt(ret) + var msgDigest = md5.Sum(ret) + if !reflect.DeepEqual(msgDigest[:], digest) { + return nil, errors.New("Decrypt failed/Digest not match\n") + } + } else { + ret = tpc.decrypt(ciphertext) + } + return ret, nil +} + +func (tpc ThirdPartCipher) decrypt(ciphertext []byte) []byte { + var tmp_para uintptr + + cipherDecryptInit(uintptr(tpc.encryptType), uintptr(unsafe.Pointer(&tpc.key[0])), uintptr(len(tpc.key)), tmp_para) + + plaintext := make([]byte, len(ciphertext)) + ret := cipherDecrypt(uintptr(tpc.encryptType), tmp_para, uintptr(unsafe.Pointer(&ciphertext[0])), uintptr(len(ciphertext)), + uintptr(unsafe.Pointer(&plaintext[0])), uintptr(len(plaintext))) + plaintext = plaintext[:ret] + + cipherClean(uintptr(tpc.encryptType), tmp_para) + return plaintext +} + +func addBufSize(buf []byte, newCap int) []byte { + newBuf := make([]byte, newCap) + copy(newBuf, buf) + return newBuf +} + +func uintptr2bytes(p uintptr) []byte { + buf := make([]byte, 64) + i := 0 + for b := (*byte)(unsafe.Pointer(p)); *b != 0; i++ { + if i > cap(buf) { + buf = addBufSize(buf, i*2) + } + buf[i] = *b + // byte占1字节 + p++ + b = (*byte)(unsafe.Pointer(p)) + } + return buf[:i] +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzg_darwin.go b/dpi_bridge/third_party/chunanyong_dm/security/zzg_darwin.go new file mode 100644 index 0000000..835002e --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzg_darwin.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "plugin" + +var ( + dmCipherEncryptSo *plugin.Plugin + cipherGetCountProc plugin.Symbol + cipherGetInfoProc plugin.Symbol + cipherEncryptInitProc plugin.Symbol + cipherGetCipherTextSizeProc plugin.Symbol + cipherEncryptProc plugin.Symbol + cipherCleanupProc plugin.Symbol + cipherDecryptInitProc plugin.Symbol + cipherDecryptProc plugin.Symbol +) + +func initThirdPartCipher(cipherPath string) (err error) { + if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil { + return err + } + if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil { + return err + } + if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil { + return err + } + if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil { + return err + } + if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil { + return err + } + if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil { + return err + } + if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil { + return err + } + if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil { + return err + } + if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil { + return err + } + return nil +} + +func cipherGetCount() int { + ret := cipherGetCountProc.(func() interface{})() + return ret.(int) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize) + return ciphertextLen.(uintptr) +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret.(uintptr) +} + +func cipherClean(cipherId, cipherPara uintptr) { + cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret.(uintptr) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzg_linux.go b/dpi_bridge/third_party/chunanyong_dm/security/zzg_linux.go new file mode 100644 index 0000000..835002e --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzg_linux.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import "plugin" + +var ( + dmCipherEncryptSo *plugin.Plugin + cipherGetCountProc plugin.Symbol + cipherGetInfoProc plugin.Symbol + cipherEncryptInitProc plugin.Symbol + cipherGetCipherTextSizeProc plugin.Symbol + cipherEncryptProc plugin.Symbol + cipherCleanupProc plugin.Symbol + cipherDecryptInitProc plugin.Symbol + cipherDecryptProc plugin.Symbol +) + +func initThirdPartCipher(cipherPath string) (err error) { + if dmCipherEncryptSo, err = plugin.Open(cipherPath); err != nil { + return err + } + if cipherGetCountProc, err = dmCipherEncryptSo.Lookup("cipher_get_count"); err != nil { + return err + } + if cipherGetInfoProc, err = dmCipherEncryptSo.Lookup("cipher_get_info"); err != nil { + return err + } + if cipherEncryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt_init"); err != nil { + return err + } + if cipherGetCipherTextSizeProc, err = dmCipherEncryptSo.Lookup("cipher_get_cipher_text_size"); err != nil { + return err + } + if cipherEncryptProc, err = dmCipherEncryptSo.Lookup("cipher_encrypt"); err != nil { + return err + } + if cipherCleanupProc, err = dmCipherEncryptSo.Lookup("cipher_cleanup"); err != nil { + return err + } + if cipherDecryptInitProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt_init"); err != nil { + return err + } + if cipherDecryptProc, err = dmCipherEncryptSo.Lookup("cipher_decrypt"); err != nil { + return err + } + return nil +} + +func cipherGetCount() int { + ret := cipherGetCountProc.(func() interface{})() + return ret.(int) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret := cipherGetInfoProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherEncryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen := cipherGetCipherTextSizeProc.(func(uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainTextSize) + return ciphertextLen.(uintptr) +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret := cipherEncryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret.(uintptr) +} + +func cipherClean(cipherId, cipherPara uintptr) { + cipherEncryptProc.(func(uintptr, uintptr))(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret := cipherDecryptInitProc.(func(uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, key, keySize, cipherPara) + if ret.(int) == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret := cipherDecryptProc.(func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) interface{})(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret.(uintptr) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzh_windows.go b/dpi_bridge/third_party/chunanyong_dm/security/zzh_windows.go new file mode 100644 index 0000000..2fa6861 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzh_windows.go @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "syscall" +) + +var ( + dmCipherEncryptDLL *syscall.LazyDLL + cipherGetCountProc *syscall.LazyProc + cipherGetInfoProc *syscall.LazyProc + cipherEncryptInitProc *syscall.LazyProc + cipherGetCipherTextSizeProc *syscall.LazyProc + cipherEncryptProc *syscall.LazyProc + cipherCleanupProc *syscall.LazyProc + cipherDecryptInitProc *syscall.LazyProc + cipherDecryptProc *syscall.LazyProc +) + +func initThirdPartCipher(cipherPath string) error { + dmCipherEncryptDLL = syscall.NewLazyDLL(cipherPath) + if err := dmCipherEncryptDLL.Load(); err != nil { + return err + } + cipherGetCountProc = dmCipherEncryptDLL.NewProc("cipher_get_count") + cipherGetInfoProc = dmCipherEncryptDLL.NewProc("cipher_get_info") + cipherEncryptInitProc = dmCipherEncryptDLL.NewProc("cipher_encrypt_init") + cipherGetCipherTextSizeProc = dmCipherEncryptDLL.NewProc("cipher_get_cipher_text_size") + cipherEncryptProc = dmCipherEncryptDLL.NewProc("cipher_encrypt") + cipherCleanupProc = dmCipherEncryptDLL.NewProc("cipher_cleanup") + cipherDecryptInitProc = dmCipherEncryptDLL.NewProc("cipher_decrypt_init") + cipherDecryptProc = dmCipherEncryptDLL.NewProc("cipher_decrypt") + return nil +} + +func cipherGetCount() int { + ret, _, _ := cipherGetCountProc.Call() + return int(ret) +} + +func cipherGetInfo(seqno, cipherId, cipherName, _type, blkSize, khSIze uintptr) { + ret, _, _ := cipherGetInfoProc.Call(seqno, cipherId, cipherName, _type, blkSize, khSIze) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_get_info failed") + } +} + +func cipherEncryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret, _, _ := cipherEncryptInitProc.Call(cipherId, key, keySize, cipherPara) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_encrypt_init failed") + } +} + +func cipherGetCipherTextSize(cipherId, cipherPara, plainTextSize uintptr) uintptr { + ciphertextLen, _, _ := cipherGetCipherTextSizeProc.Call(cipherId, cipherPara, plainTextSize) + return ciphertextLen +} + +func cipherEncrypt(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize uintptr) uintptr { + ret, _, _ := cipherEncryptProc.Call(cipherId, cipherPara, plainText, plainTextSize, cipherText, cipherTextBufSize) + return ret +} + +func cipherClean(cipherId, cipherPara uintptr) { + _, _, _ = cipherCleanupProc.Call(cipherId, cipherPara) +} + +func cipherDecryptInit(cipherId, key, keySize, cipherPara uintptr) { + ret, _, _ := cipherDecryptInitProc.Call(cipherId, key, keySize, cipherPara) + if ret == 0 { + panic("ThirdPartyCipher: call cipher_decrypt_init failed") + } +} + +func cipherDecrypt(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize uintptr) uintptr { + ret, _, _ := cipherDecryptProc.Call(cipherId, cipherPara, cipherText, cipherTextSize, plainText, plainTextBufSize) + return ret +} diff --git a/dpi_bridge/third_party/chunanyong_dm/security/zzi.go b/dpi_bridge/third_party/chunanyong_dm/security/zzi.go new file mode 100644 index 0000000..bfc3f1c --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/security/zzi.go @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package security + +import ( + "crypto/tls" + "errors" + "net" + "sync" +) + +//var dmHome = flag.String("DM_HOME", "", "Where DMDB installed") +var flagLock = sync.Mutex{} + +func NewTLSFromTCP(conn net.Conn, sslCertPath string, sslKeyPath string, user string) (*tls.Conn, error) { + if sslCertPath == "" && sslKeyPath == "" { + // 用户必须手动指定ssl文件和签名(.cert文件) + return nil, errors.New("sslCertPath and sslKeyPath can not be empty!") + + } + cer, err := tls.LoadX509KeyPair(sslCertPath, sslKeyPath) + if err != nil { + return nil, err + } + conf := &tls.Config{ + InsecureSkipVerify: true, + Certificates: []tls.Certificate{cer}, + } + tlsConn := tls.Client(conn, conf) + if err := tlsConn.Handshake(); err != nil { + return nil, err + } + return tlsConn, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/t.go b/dpi_bridge/third_party/chunanyong_dm/t.go new file mode 100644 index 0000000..ffca83f --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/t.go @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" + "io" + "reflect" + "strings" +) + +type DmRows struct { + filterable + CurrentRows *innerRows + finish func() +} + +func (r *DmRows) Columns() []string { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return nil + } + if len(r.filterChain.filters) == 0 { + return r.columns() + } + return r.filterChain.reset().DmRowsColumns(r) +} + +func (r *DmRows) Close() error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.close() + } + return r.filterChain.reset().DmRowsClose(r) +} + +func (r *DmRows) Next(dest []driver.Value) error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.next(dest) + } + return r.filterChain.reset().DmRowsNext(r, dest) +} + +func (r *DmRows) HasNextResultSet() bool { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return false + } + if len(r.filterChain.filters) == 0 { + return r.hasNextResultSet() + } + return r.filterChain.reset().DmRowsHasNextResultSet(r) +} + +func (r *DmRows) NextResultSet() error { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return err + } + if len(r.filterChain.filters) == 0 { + return r.nextResultSet() + } + return r.filterChain.reset().DmRowsNextResultSet(r) +} + +func (r *DmRows) ColumnTypeScanType(index int) reflect.Type { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return nil + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeScanType(index) + } + return r.filterChain.reset().DmRowsColumnTypeScanType(r, index) +} + +func (r *DmRows) ColumnTypeDatabaseTypeName(index int) string { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return "" + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeDatabaseTypeName(index) + } + return r.filterChain.reset().DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (r *DmRows) ColumnTypeLength(index int) (length int64, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return -1, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeLength(index) + } + return r.filterChain.reset().DmRowsColumnTypeLength(r, index) +} + +func (r *DmRows) ColumnTypeNullable(index int) (nullable, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return false, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypeNullable(index) + } + return r.filterChain.reset().DmRowsColumnTypeNullable(r, index) +} + +func (r *DmRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + if err := r.CurrentRows.dmStmt.checkClosed(); err != nil { + return -1, -1, false + } + if len(r.filterChain.filters) == 0 { + return r.columnTypePrecisionScale(index) + } + return r.filterChain.reset().DmRowsColumnTypePrecisionScale(r, index) +} + +func (dest *DmRows) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + *dest = *new(DmRows) + return nil + case *DmRows: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN + } +} + +func (rows *DmRows) columns() []string { + return rows.CurrentRows.Columns() +} + +func (rows *DmRows) close() error { + if f := rows.finish; f != nil { + f() + rows.finish = nil + } + return rows.CurrentRows.Close() +} + +func (rows *DmRows) next(dest []driver.Value) error { + return rows.CurrentRows.Next(dest) +} + +func (rows *DmRows) hasNextResultSet() bool { + return rows.CurrentRows.HasNextResultSet() +} + +func (rows *DmRows) nextResultSet() error { + return rows.CurrentRows.NextResultSet() +} + +func (rows *DmRows) columnTypeScanType(index int) reflect.Type { + return rows.CurrentRows.ColumnTypeScanType(index) +} + +func (rows *DmRows) columnTypeDatabaseTypeName(index int) string { + return rows.CurrentRows.ColumnTypeDatabaseTypeName(index) +} + +func (rows *DmRows) columnTypeLength(index int) (length int64, ok bool) { + return rows.CurrentRows.ColumnTypeLength(index) +} + +func (rows *DmRows) columnTypeNullable(index int) (nullable, ok bool) { + return rows.CurrentRows.ColumnTypeNullable(index) +} + +func (rows *DmRows) columnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + return rows.CurrentRows.ColumnTypePrecisionScale(index) +} + +type innerRows struct { + dmStmt *DmStatement + + id int16 + + columns []column + + datas [][][]byte + + datasOffset int + + datasStartPos int64 + + currentPos int64 + + totalRowCount int64 + + fetchSize int + + sizeOfRow int + + isBdta bool + + nextExecInfo *execRetInfo + + next *innerRows + + dmRows *DmRows + + closed bool +} + +func (innerRows *innerRows) checkClosed() error { + if innerRows.closed { + return ECGO_RESULTSET_CLOSED.throw() + } + return nil +} + +func (innerRows *innerRows) Columns() []string { + if err := innerRows.checkClosed(); err != nil { + return nil + } + + columnNames := make([]string, len(innerRows.columns)) + nameCase := innerRows.dmStmt.dmConn.dmConnector.columnNameCase + + for i, column := range innerRows.columns { + if nameCase == COLUMN_NAME_NATURAL_CASE { + columnNames[i] = column.name + } else if nameCase == COLUMN_NAME_UPPER_CASE { + columnNames[i] = strings.ToUpper(column.name) + } else if nameCase == COLUMN_NAME_LOWER_CASE { + columnNames[i] = strings.ToLower(column.name) + } else { + columnNames[i] = column.name + } + } + + return columnNames +} + +func (innerRows *innerRows) Close() error { + if innerRows.closed { + return nil + } + + innerRows.closed = true + + if innerRows.dmStmt.innerUsed { + innerRows.dmStmt.close() + } else { + delete(innerRows.dmStmt.rsMap, innerRows.id) + } + + innerRows.dmStmt = nil + + return nil +} + +func (innerRows *innerRows) Next(dest []driver.Value) error { + err := innerRows.checkClosed() + if err != nil { + return err + } + + if innerRows.totalRowCount == 0 || innerRows.currentPos >= innerRows.totalRowCount { + return io.EOF + } + + if innerRows.currentPos+1 == innerRows.totalRowCount { + innerRows.currentPos++ + innerRows.datasOffset++ + return io.EOF + } + + if innerRows.currentPos+1 < innerRows.datasStartPos || innerRows.currentPos+1 >= innerRows.datasStartPos+int64(len(innerRows.datas)) { + if innerRows.fetchData(innerRows.currentPos + 1) { + innerRows.currentPos++ + err := innerRows.getRowData(dest) + if err != nil { + return err + } + } else { + innerRows.currentPos++ + innerRows.datasOffset++ + return io.EOF + } + } else { + innerRows.currentPos++ + innerRows.datasOffset++ + err := innerRows.getRowData(dest) + if err != nil { + return err + } + } + + return nil +} + +func (innerRows *innerRows) HasNextResultSet() bool { + err := innerRows.checkClosed() + if err != nil { + return false + } + + if innerRows.nextExecInfo != nil { + return innerRows.nextExecInfo.hasResultSet + } + + innerRows.nextExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_543(innerRows.dmStmt, 0) + if err != nil { + return false + } + + if innerRows.nextExecInfo.hasResultSet { + innerRows.next = newInnerRows(innerRows.id+1, innerRows.dmStmt, innerRows.nextExecInfo) + return true + } + + return false +} + +func (innerRows *innerRows) NextResultSet() error { + err := innerRows.checkClosed() + if err != nil { + return err + } + + if innerRows.nextExecInfo == nil { + innerRows.HasNextResultSet() + } + + if innerRows.next == nil { + return io.EOF + } + + innerRows.next.dmRows = innerRows.dmRows + innerRows.dmRows.CurrentRows = innerRows.next + return nil +} + +func (innerRows *innerRows) ColumnTypeScanType(index int) reflect.Type { + if err := innerRows.checkClosed(); err != nil { + return nil + } + if column := innerRows.checkIndex(index); column != nil { + return column.ScanType() + } + return nil +} + +func (innerRows *innerRows) ColumnTypeDatabaseTypeName(index int) string { + if err := innerRows.checkClosed(); err != nil { + return "" + } + if column := innerRows.checkIndex(index); column != nil { + return column.typeName + } + return "" +} + +func (innerRows *innerRows) ColumnTypeLength(index int) (length int64, ok bool) { + if err := innerRows.checkClosed(); err != nil { + return 0, false + } + if column := innerRows.checkIndex(index); column != nil { + return column.Length() + } + return 0, false +} + +func (innerRows *innerRows) ColumnTypeNullable(index int) (nullable, ok bool) { + if err := innerRows.checkClosed(); err != nil { + return false, false + } + if column := innerRows.checkIndex(index); column != nil { + return column.nullable, true + } + return false, false +} + +func (innerRows *innerRows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { + if err := innerRows.checkClosed(); err != nil { + return 0, 0, false + } + if column := innerRows.checkIndex(index); column != nil { + return column.PrecisionScale() + } + return 0, 0, false +} + +func newDmRows(currentRows *innerRows) *DmRows { + dr := new(DmRows) + dr.resetFilterable(¤tRows.dmStmt.filterable) + dr.CurrentRows = currentRows + dr.idGenerator = dmRowsIDGenerator + currentRows.dmRows = dr + return dr +} + +func newInnerRows(id int16, stmt *DmStatement, execInfo *execRetInfo) *innerRows { + rows := new(innerRows) + rows.id = id + rows.dmStmt = stmt + rows.columns = stmt.columns + rows.datas = execInfo.rsDatas + rows.totalRowCount = execInfo.updateCount + rows.isBdta = execInfo.rsBdta + rows.fetchSize = stmt.fetchSize + + if len(execInfo.rsDatas) == 0 { + rows.sizeOfRow = 0 + } else { + rows.sizeOfRow = execInfo.rsSizeof / len(execInfo.rsDatas) + } + + rows.currentPos = -1 + rows.datasOffset = -1 + rows.datasStartPos = 0 + + rows.nextExecInfo = nil + rows.next = nil + + if rows.dmStmt.rsMap != nil { + rows.dmStmt.rsMap[rows.id] = rows + } + + if stmt.dmConn.dmConnector.enRsCache && execInfo.rsCacheOffset > 0 && + int64(len(execInfo.rsDatas)) == execInfo.updateCount { + rp.put(stmt, stmt.nativeSql, execInfo) + } + + return rows +} + +func newLocalInnerRows(stmt *DmStatement, columns []column, rsDatas [][][]byte) *innerRows { + rows := new(innerRows) + rows.id = 0 + rows.dmStmt = stmt + rows.fetchSize = stmt.fetchSize + + if columns == nil { + rows.columns = make([]column, 0) + } else { + rows.columns = columns + } + + if rsDatas == nil { + rows.datas = make([][][]byte, 0) + rows.totalRowCount = 0 + } else { + rows.datas = rsDatas + rows.totalRowCount = int64(len(rsDatas)) + } + + rows.isBdta = false + return rows +} + +func (innerRows *innerRows) checkIndex(index int) *column { + if index < 0 || index > len(innerRows.columns)-1 { + return nil + } + + return &innerRows.columns[index] +} + +func (innerRows *innerRows) fetchData(startPos int64) bool { + execInfo, err := innerRows.dmStmt.dmConn.Access.Dm_build_550(innerRows, startPos) + if err != nil { + return false + } + + innerRows.totalRowCount = execInfo.updateCount + if execInfo.rsDatas != nil { + innerRows.datas = execInfo.rsDatas + innerRows.datasStartPos = startPos + innerRows.datasOffset = 0 + return true + } + + return false +} + +func (innerRows *innerRows) getRowData(dest []driver.Value) (err error) { + for i, column := range innerRows.columns { + + if i <= len(dest)-1 { + if column.colType == CURSOR { + var tmpExecInfo *execRetInfo + tmpExecInfo, err = innerRows.dmStmt.dmConn.Access.Dm_build_543(innerRows.dmStmt, 1) + if err != nil { + return err + } + + if tmpExecInfo.hasResultSet { + dest[i] = newDmRows(newInnerRows(innerRows.id+1, innerRows.dmStmt, tmpExecInfo)) + } else { + dest[i] = nil + } + continue + } + + dest[i], err = column.getColumnData(innerRows.datas[innerRows.datasOffset][i+1], innerRows.dmStmt.dmConn) + innerRows.columns[i].isBdta = innerRows.isBdta + if err != nil { + return err + } + } else { + return nil + } + } + + return nil +} + +func (innerRows *innerRows) getRowCount() int64 { + innerRows.checkClosed() + + if innerRows.totalRowCount == INT64_MAX { + return -1 + } + + return innerRows.totalRowCount +} diff --git a/dpi_bridge/third_party/chunanyong_dm/u.go b/dpi_bridge/third_party/chunanyong_dm/u.go new file mode 100644 index 0000000..f622932 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/u.go @@ -0,0 +1,1590 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "container/list" + "context" + "database/sql" + "database/sql/driver" + "fmt" + "io" + "math/big" + "reflect" + "strconv" + "strings" + "time" + + "gitee.com/chunanyong/dm/util" +) + +var rp = newRsPool() + +type DmStatement struct { + filterable + + dmConn *DmConnection + rsMap map[int16]*innerRows + inUse bool + + prepared bool + innerUsed bool + + innerExec bool + + id int32 + + cursorName string + + readBaseColName bool + + execInfo *execRetInfo + + resultSetType int + + resultSetConcurrency int + + resultSetHoldability int + + nativeSql string + + maxFieldSize int + + maxRows int64 + + escapeProcessing bool + + queryTimeout int32 + + fetchDirection int + + fetchSize int + + cursorUpdateRow int64 + + closeOnCompletion bool + + isBatch bool + + closed bool + + columns []column + + serverParams []parameter + + bindParams []parameter + + paramCount int32 + + preExec bool +} + +type stmtPoolInfo struct { + id int32 + + cursorName string + + readBaseColName bool +} + +type rsPoolKey struct { + dbGuid string + currentSchema string + sql string + paramCount int +} + +func newRsPoolKey(stmt *DmStatement, sql string) rsPoolKey { + rpk := new(rsPoolKey) + rpk.dbGuid = stmt.dmConn.Guid + rpk.currentSchema = stmt.dmConn.Schema + rpk.paramCount = int(stmt.paramCount) + + rpk.sql = sql + return *rpk +} + +func (key rsPoolKey) equals(destKey rsPoolKey) bool { + return key.dbGuid == destKey.dbGuid && + key.currentSchema == destKey.currentSchema && + key.sql == destKey.sql && + key.paramCount == destKey.paramCount + +} + +type rsPoolValue struct { + m_lastChkTime int + m_TbIds []int32 + m_TbTss []int64 + execInfo *execRetInfo +} + +func newRsPoolValue(execInfo *execRetInfo) rsPoolValue { + rpv := new(rsPoolValue) + rpv.execInfo = execInfo + rpv.m_lastChkTime = time.Now().Nanosecond() + copy(rpv.m_TbIds, execInfo.tbIds) + copy(rpv.m_TbTss, execInfo.tbTss) + return *rpv +} + +func (rpv rsPoolValue) refreshed(conn *DmConnection) (bool, error) { + + if conn.dmConnector.rsRefreshFreq == 0 { + return false, nil + } + + if rpv.m_lastChkTime+conn.dmConnector.rsRefreshFreq*int(time.Second) > time.Now().Nanosecond() { + return false, nil + } + + tss, err := conn.Access.Dm_build_576(interface{}(rpv.m_TbIds).([]uint32)) + if err != nil { + return false, err + } + rpv.m_lastChkTime = time.Now().Nanosecond() + + var tbCount int + if tss != nil { + tbCount = len(tss) + } + + if tbCount != len(rpv.m_TbTss) { + return true, nil + } + + for i := 0; i < tbCount; i++ { + if rpv.m_TbTss[i] != tss[i] { + return true, nil + } + + } + return false, nil +} + +func (rpv rsPoolValue) getResultSet(stmt *DmStatement) *innerRows { + destDatas := rpv.execInfo.rsDatas + var totalRows int + if rpv.execInfo.rsDatas != nil { + totalRows = len(rpv.execInfo.rsDatas) + } + + if stmt.maxRows > 0 && stmt.maxRows < int64(totalRows) { + destDatas = make([][][]byte, stmt.maxRows) + copy(destDatas[:len(destDatas)], rpv.execInfo.rsDatas[:len(destDatas)]) + } + + rs := newLocalInnerRows(stmt, stmt.columns, destDatas) + rs.id = 1 + return rs +} + +func (rpv rsPoolValue) getDataLen() int { + return rpv.execInfo.rsSizeof +} + +type rsPool struct { + rsMap map[rsPoolKey]rsPoolValue + rsList *list.List + totalDataLen int +} + +func newRsPool() *rsPool { + rp := new(rsPool) + rp.rsMap = make(map[rsPoolKey]rsPoolValue, 100) + rp.rsList = list.New() + return rp +} + +func (rp *rsPool) removeInList(key rsPoolKey) { + for e := rp.rsList.Front(); e != nil && e.Value.(rsPoolKey).equals(key); e = e.Next() { + rp.rsList.Remove(e) + } +} + +func (rp *rsPool) put(stmt *DmStatement, sql string, execInfo *execRetInfo) { + var dataLen int + if execInfo != nil { + dataLen = execInfo.rsSizeof + } + + cacheSize := stmt.dmConn.dmConnector.rsCacheSize * 1024 * 1024 + + for rp.totalDataLen+dataLen > cacheSize { + if rp.totalDataLen == 0 { + return + } + + lk := rp.rsList.Back().Value.(rsPoolKey) + rp.totalDataLen -= rp.rsMap[lk].getDataLen() + rp.rsList.Remove(rp.rsList.Back()) + delete(rp.rsMap, rp.rsList.Back().Value.(rsPoolKey)) + } + + key := newRsPoolKey(stmt, sql) + value := newRsPoolValue(execInfo) + + if _, ok := rp.rsMap[key]; !ok { + rp.rsList.PushFront(key) + } else { + rp.removeInList(key) + rp.rsList.PushFront(key) + } + + rp.rsMap[key] = value + rp.totalDataLen += dataLen +} + +func (rp *rsPool) get(stmt *DmStatement, sql string) (*rsPoolValue, error) { + key := newRsPoolKey(stmt, sql) + + v, ok := rp.rsMap[key] + if ok { + b, err := v.refreshed(stmt.dmConn) + if err != nil { + return nil, err + } + + if b { + rp.removeInList(key) + delete(rp.rsMap, key) + return nil, nil + } + + rp.removeInList(key) + rp.rsList.PushFront(key) + return &v, nil + } else { + return nil, nil + } +} + +func (s *DmStatement) Close() error { + if s.closed { + return nil + } + if len(s.filterChain.filters) == 0 { + return s.close() + } + return s.filterChain.reset().DmStatementClose(s) +} + +func (s *DmStatement) NumInput() int { + if err := s.checkClosed(); err != nil { + return -1 + } + if len(s.filterChain.filters) == 0 { + return s.numInput() + } + return s.filterChain.reset().DmStatementNumInput(s) +} + +func (s *DmStatement) Exec(args []driver.Value) (driver.Result, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.exec(args) + } + return s.filterChain.reset().DmStatementExec(s, args) +} + +func (s *DmStatement) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.execContext(ctx, args) + } + return s.filterChain.reset().DmStatementExecContext(s, ctx, args) +} + +func (s *DmStatement) Query(args []driver.Value) (driver.Rows, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.query(args) + } + return s.filterChain.reset().DmStatementQuery(s, args) +} + +func (s *DmStatement) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if err := s.checkClosed(); err != nil { + return nil, err + } + if len(s.filterChain.filters) == 0 { + return s.queryContext(ctx, args) + } + return s.filterChain.reset().DmStatementQueryContext(s, ctx, args) +} + +func (s *DmStatement) CheckNamedValue(nv *driver.NamedValue) error { + if len(s.filterChain.filters) == 0 { + return s.checkNamedValue(nv) + } + return s.filterChain.reset().DmStatementCheckNamedValue(s, nv) +} + +func (st *DmStatement) prepare() error { + var err error + if st.dmConn.dmConnector.escapeProcess { + st.nativeSql, err = st.dmConn.escape(st.nativeSql, st.dmConn.dmConnector.keyWords) + if err != nil { + return err + } + } + + st.execInfo, err = st.dmConn.Access.Dm_build_493(st, Dm_build_788) + if err != nil { + return err + } + st.serverParams = st.execInfo.serverParams + st.paramCount = int32(len(st.serverParams)) + st.bindParams = make([]parameter, len(st.serverParams)) + for i := 0; i < len(st.serverParams); i++ { + st.bindParams[i].InitParameter() + st.bindParams[i].colType = st.serverParams[i].colType + st.bindParams[i].prec = st.serverParams[i].prec + st.bindParams[i].scale = st.serverParams[i].scale + st.bindParams[i].nullable = st.serverParams[i].nullable + st.bindParams[i].hasDefault = st.serverParams[i].hasDefault + st.bindParams[i].typeFlag = st.serverParams[i].typeFlag + st.bindParams[i].lob = st.serverParams[i].lob + st.bindParams[i].ioType = st.serverParams[i].ioType + st.bindParams[i].name = st.serverParams[i].name + st.bindParams[i].typeName = st.serverParams[i].typeName + st.bindParams[i].tableName = st.serverParams[i].tableName + st.bindParams[i].schemaName = st.serverParams[i].schemaName + st.bindParams[i].lobTabId = st.serverParams[i].lobTabId + st.bindParams[i].lobColId = st.serverParams[i].lobColId + st.bindParams[i].mask = st.serverParams[i].mask + st.bindParams[i].typeDescriptor = st.serverParams[i].typeDescriptor + } + + st.prepared = true + return nil +} + +func (stmt *DmStatement) close() error { + delete(stmt.dmConn.stmtMap, stmt.id) + if stmt.closed { + return nil + } + stmt.inUse = true + + return stmt.free() + +} + +func (stmt *DmStatement) numInput() int { + return int(stmt.paramCount) +} + +func (stmt *DmStatement) checkNamedValue(nv *driver.NamedValue) error { + var err error + var cvt = converter{stmt.dmConn, false} + nv.Value, err = cvt.ConvertValue(nv.Value) + stmt.isBatch = cvt.isBatch + return err +} + +func (stmt *DmStatement) exec(args []driver.Value) (*DmResult, error) { + var err error + + stmt.inUse = true + if stmt.isBatch && len(args) > 0 { + var tmpArg []driver.Value + var arg driver.Value + for i := len(args) - 1; i >= 0; i-- { + if args[i] != nil { + arg = args[i] + break + } + } + for _, row := range arg.([][]interface{}) { + tmpArg = append(tmpArg, row) + } + err = stmt.executeBatch(tmpArg) + } else { + err = stmt.executeInner(args, Dm_build_788) + } + if err != nil { + return nil, err + } + return newDmResult(stmt, stmt.execInfo), nil +} + +func (stmt *DmStatement) execContext(ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + stmt.inUse = true + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + + if err := stmt.dmConn.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.dmConn.finish() + + return stmt.exec(dargs) +} + +func (stmt *DmStatement) query(args []driver.Value) (*DmRows, error) { + var err error + stmt.inUse = true + err = stmt.executeInner(args, Dm_build_789) + if err != nil { + return nil, err + } + + if stmt.execInfo.hasResultSet { + return newDmRows(newInnerRows(0, stmt, stmt.execInfo)), nil + } else { + return newDmRows(newLocalInnerRows(stmt, nil, nil)), nil + } +} + +func (stmt *DmStatement) queryContext(ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + stmt.inUse = true + dargs, err := namedValueToValue(stmt, args) + if err != nil { + return nil, err + } + + if err := stmt.dmConn.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.dmConn.finish() + + rows, err := stmt.query(dargs) + if err != nil { + stmt.dmConn.finish() + return nil, err + } + rows.finish = stmt.dmConn.finish + return rows, err +} + +func NewDmStmt(conn *DmConnection, sql string) (*DmStatement, error) { + var s *DmStatement + + if s == nil { + s = new(DmStatement) + s.resetFilterable(&conn.filterable) + s.objId = -1 + s.idGenerator = dmStmtIDGenerator + s.dmConn = conn + s.maxRows = int64(conn.dmConnector.maxRows) + s.nativeSql = sql + s.rsMap = make(map[int16]*innerRows) + s.inUse = true + s.isBatch = conn.isBatch + + err := conn.Access.Dm_build_475(s) + if err != nil { + return nil, err + } + + conn.stmtMap[s.id] = s + } + + return s, nil + +} + +func (stmt *DmStatement) checkClosed() error { + if stmt.dmConn.closed.IsSet() { + return driver.ErrBadConn + } else if stmt.closed { + return ECGO_STATEMENT_HANDLE_CLOSED.throw() + } + + return nil +} + +func (stmt *DmStatement) free() error { + delete(stmt.dmConn.stmtMap, stmt.id) + for _, rs := range stmt.rsMap { + rs.Close() + } + + err := stmt.dmConn.Access.Dm_build_480(int32(stmt.id)) + if err != nil { + return err + } + stmt.inUse = false + stmt.closed = true + return nil +} + +func bindInParam(stmt *DmStatement, i int, dtype int32, isNil bool, firstRow bool) { + if !firstRow { + return + } + serverParam := &stmt.serverParams[i] + bindParam := &stmt.bindParams[i] + if serverParam == nil { + bindParam.resetType(dtype) + } else { + bindParam.name = serverParam.name + bindParam.typeDescriptor = serverParam.typeDescriptor + bindParam.mask = serverParam.mask + bindParam.typeFlag = serverParam.typeFlag + + if (serverParam.colType != UNKNOWN && (isNil || serverParam.typeFlag == TYPE_FLAG_EXACT)) || serverParam.mask != 0 { + + bindParam.colType = serverParam.colType + bindParam.prec = serverParam.prec + bindParam.scale = serverParam.scale + bindParam.mask = serverParam.mask + } else { + + bindParam.resetType(dtype) + } + } + + if bindParam.ioType == IO_TYPE_OUT || bindParam.ioType == IO_TYPE_INOUT { + bindParam.ioType = IO_TYPE_INOUT + } else { + bindParam.ioType = IO_TYPE_IN + } +} + +func checkBindParameters(stmt *DmStatement, bytes []interface{}) error { + + for i := 0; int32(i) < stmt.paramCount; i++ { + if stmt.bindParams[i].ioType == IO_TYPE_UNKNOWN { + + if stmt.serverParams[i].ioType == IO_TYPE_OUT { + + bytes[i] = nil + } else { + return ECGO_UNBINDED_PARAMETER.throw() + } + } + + if stmt.bindParams[i].colType == CURSOR { + stmt.bindParams[i].ioType = IO_TYPE_INOUT + continue + } + + if stmt.serverParams[i].ioType != stmt.bindParams[i].ioType { + + stmt.bindParams[i].ioType = stmt.serverParams[i].ioType + } + } + + for i := 0; int32(i) < stmt.paramCount; i++ { + if stmt.bindParams[i].ioType == IO_TYPE_INOUT || stmt.bindParams[i].ioType == IO_TYPE_OUT { + continue + } + switch stmt.bindParams[i].colType { + case CHAR, VARCHAR, VARCHAR2: + length := -1 + if b, ok := bytes[i].([]byte); ok { + length = len(b) + } + if length > VARCHAR_PREC { + return ECGO_STRING_CUT.throw() + } + if length > int(stmt.bindParams[i].prec) { + if length < VARCHAR_PREC/4 { + stmt.bindParams[i].prec = VARCHAR_PREC / 4 + } else if length < VARCHAR_PREC/2 { + stmt.bindParams[i].prec = VARCHAR_PREC / 2 + } else if length < VARCHAR_PREC*3/4 { + stmt.bindParams[i].prec = VARCHAR_PREC * 3 / 4 + } else { + stmt.bindParams[i].prec = VARCHAR_PREC + } + } + } + } + return nil +} + +func bindOutParam(stmt *DmStatement, i int, dtype int32) error { + var err error + serverParam := &stmt.serverParams[i] + bindParam := &stmt.bindParams[i] + + if bindParam.ioType == IO_TYPE_OUT || bindParam.ioType == IO_TYPE_UNKNOWN { + + if serverParam == nil { + + bindParam.resetType(dtype) + } else { + + bindParam.name = serverParam.name + bindParam.typeDescriptor = serverParam.typeDescriptor + bindParam.mask = serverParam.mask + bindParam.typeFlag = serverParam.typeFlag + + if (serverParam.colType != UNKNOWN && serverParam.typeFlag == TYPE_FLAG_EXACT) || serverParam.mask != 0 { + + bindParam.colType = serverParam.colType + bindParam.prec = serverParam.prec + bindParam.scale = serverParam.scale + bindParam.mask = serverParam.mask + } else { + + bindParam.resetType(dtype) + } + } + + if bindParam.colType == CURSOR { + bindParam.ioType = IO_TYPE_INOUT + if bindParam.cursorStmt == nil { + bindParam.cursorStmt = &DmStatement{dmConn: stmt.dmConn} + bindParam.cursorStmt.resetFilterable(&stmt.dmConn.filterable) + err = bindParam.cursorStmt.dmConn.Access.Dm_build_475(bindParam.cursorStmt) + } + } + } + + if bindParam.ioType == IO_TYPE_IN || bindParam.ioType == IO_TYPE_INOUT { + bindParam.ioType = IO_TYPE_INOUT + } else { + bindParam.ioType = IO_TYPE_OUT + } + + return err +} + +func encodeArgs(stmt *DmStatement, args []driver.Value, firstRow bool) ([]interface{}, error) { + bytes := make([]interface{}, len(args), len(args)) + + var err error + + for i, arg := range args { + nextSwitch: + if stmt.serverParams[i].colType == CURSOR { + bindInParam(stmt, i, CURSOR, false, firstRow) + if stmt.bindParams[i].cursorStmt == nil { + stmt.bindParams[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn} + stmt.bindParams[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable) + err = stmt.bindParams[i].cursorStmt.dmConn.Access.Dm_build_475(stmt.bindParams[i].cursorStmt) + } + stmt.bindParams[i].ioType = IO_TYPE_INOUT + continue + } + if checkNull(arg) { + bindInParam(stmt, i, NULL, true, firstRow) + bytes[i] = nil + + continue + } + + switch v := arg.(type) { + case bool: + bindInParam(stmt, i, TINYINT, false, firstRow) + bytes[i], err = G2DB.fromBool(v, stmt.bindParams[i], stmt.dmConn) + case int8: + bindInParam(stmt, i, TINYINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case int16: + bindInParam(stmt, i, SMALLINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case int32: + bindInParam(stmt, i, INT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case int64: + bindInParam(stmt, i, BIGINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case int: + bindInParam(stmt, i, BIGINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case uint8: + bindInParam(stmt, i, SMALLINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case uint16: + bindInParam(stmt, i, INT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case uint32: + bindInParam(stmt, i, BIGINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case uint64: + bindInParam(stmt, i, BIGINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case uint: + bindInParam(stmt, i, BIGINT, false, firstRow) + bytes[i], err = G2DB.fromInt64(int64(v), stmt.bindParams[i], stmt.dmConn) + case float32: + bindInParam(stmt, i, REAL, false, firstRow) + bytes[i], err = G2DB.fromFloat32(v, stmt.bindParams[i], stmt.dmConn) + case float64: + bindInParam(stmt, i, DOUBLE, false, firstRow) + bytes[i], err = G2DB.fromFloat64(float64(v), stmt.bindParams[i], stmt.dmConn) + case []byte: + if v == nil { + bindInParam(stmt, i, VARBINARY, true, firstRow) + bytes[i] = nil + + } else { + dtype := VARBINARY + if len(v) >= VARBINARY_PREC { + dtype = BLOB + } + bindInParam(stmt, i, int32(dtype), false, firstRow) + bytes[i], err = G2DB.fromBytes(v, stmt.bindParams[i], stmt.dmConn) + } + case string: + + if v == "" && emptyStringToNil(stmt.serverParams[i].colType) { + arg = nil + goto nextSwitch + } + dtype := VARCHAR + if len(v) >= VARCHAR_PREC { + dtype = CLOB + } + bindInParam(stmt, i, int32(dtype), false, firstRow) + bytes[i], err = G2DB.fromString(v, stmt.bindParams[i], stmt.dmConn) + case time.Time: + bindInParam(stmt, i, DATETIME, false, firstRow) + bytes[i], err = G2DB.fromTime(v, stmt.bindParams[i], stmt.dmConn) + case *time.Time: + bindInParam(stmt, i, DATETIME, false, firstRow) + bytes[i], err = G2DB.fromTime(*v, stmt.bindParams[i], stmt.dmConn) + case DmTimestamp: + bindInParam(stmt, i, DATETIME, false, firstRow) + bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.bindParams[i], stmt.dmConn) + case DmIntervalDT: + bindInParam(stmt, i, INTERVAL_DT, false, firstRow) + if stmt.bindParams[i].typeFlag != TYPE_FLAG_EXACT { + stmt.bindParams[i].scale = int32(v.scaleForSvr) + } + bytes[i], err = G2DB.fromDmIntervalDT(v, stmt.bindParams[i], stmt.dmConn) + case DmIntervalYM: + bindInParam(stmt, i, INTERVAL_YM, false, firstRow) + if stmt.bindParams[i].typeFlag != TYPE_FLAG_EXACT { + stmt.bindParams[i].scale = int32(v.scaleForSvr) + } + bytes[i], err = G2DB.fromDmdbIntervalYM(v, stmt.bindParams[i], stmt.dmConn) + case DmDecimal: + bindInParam(stmt, i, DECIMAL, false, firstRow) + bytes[i], err = G2DB.fromDecimal(v, stmt.bindParams[i], stmt.dmConn) + + case DmBlob: + bindInParam(stmt, i, BLOB, false, firstRow) + bytes[i], err = G2DB.fromBlob(DmBlob(v), stmt.bindParams[i], stmt.dmConn) + if err != nil { + return nil, err + } + case DmClob: + bindInParam(stmt, i, CLOB, false, firstRow) + bytes[i], err = G2DB.fromClob(DmClob(v), stmt.bindParams[i], stmt.dmConn) + if err != nil { + return nil, err + } + case DmArray: + bindInParam(stmt, i, ARRAY, false, firstRow) + da := &v + da, err = da.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromArray(da, stmt.bindParams[i], stmt.dmConn) + case DmStruct: + bindInParam(stmt, i, CLASS, false, firstRow) + ds := &v + ds, err = ds.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromStruct(ds, stmt.bindParams[i], stmt.dmConn) + case sql.Out: + var cvt = converter{stmt.dmConn, false} + if arg, err = cvt.ConvertValue(v.Dest); err != nil { + return nil, err + } + if v.In { + goto nextSwitch + } + + case *DmTimestamp: + bindInParam(stmt, i, DATETIME, false, firstRow) + bytes[i], err = G2DB.fromTime(v.ToTime(), stmt.bindParams[i], stmt.dmConn) + case *DmIntervalDT: + bindInParam(stmt, i, INTERVAL_DT, false, firstRow) + if stmt.bindParams[i].typeFlag != TYPE_FLAG_EXACT { + stmt.bindParams[i].scale = int32(v.scaleForSvr) + } + bytes[i], err = G2DB.fromDmIntervalDT(*v, stmt.bindParams[i], stmt.dmConn) + case *DmIntervalYM: + bindInParam(stmt, i, INTERVAL_YM, false, firstRow) + if stmt.bindParams[i].typeFlag != TYPE_FLAG_EXACT { + stmt.bindParams[i].scale = int32(v.scaleForSvr) + } + bytes[i], err = G2DB.fromDmdbIntervalYM(*v, stmt.bindParams[i], stmt.dmConn) + case *DmDecimal: + bindInParam(stmt, i, DECIMAL, false, firstRow) + bytes[i], err = G2DB.fromDecimal(*v, stmt.bindParams[i], stmt.dmConn) + case *DmBlob: + bindInParam(stmt, i, BLOB, false, firstRow) + bytes[i], err = G2DB.fromBlob(DmBlob(*v), stmt.bindParams[i], stmt.dmConn) + case *DmClob: + bindInParam(stmt, i, CLOB, false, firstRow) + bytes[i], err = G2DB.fromClob(DmClob(*v), stmt.bindParams[i], stmt.dmConn) + case *DmArray: + bindInParam(stmt, i, ARRAY, false, firstRow) + v, err = v.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromArray(v, stmt.bindParams[i], stmt.dmConn) + case *DmStruct: + bindInParam(stmt, i, CLASS, false, firstRow) + v, err = v.create(stmt.dmConn) + if err != nil { + return nil, err + } + + bytes[i], err = G2DB.fromStruct(v, stmt.bindParams[i], stmt.dmConn) + case *driver.Rows: + if stmt.serverParams[i].colType == CURSOR { + bindInParam(stmt, i, CURSOR, false, firstRow) + if stmt.bindParams[i].cursorStmt == nil { + stmt.bindParams[i].cursorStmt = &DmStatement{dmConn: stmt.dmConn} + stmt.bindParams[i].cursorStmt.resetFilterable(&stmt.dmConn.filterable) + err = stmt.bindParams[i].cursorStmt.dmConn.Access.Dm_build_475(stmt.bindParams[i].cursorStmt) + } + } + case io.Reader: + bindInParam(stmt, i, stmt.serverParams[i].colType, stmt.serverParams[i].colType == NULL, firstRow) + bytes[i], err = G2DB.fromReader(io.Reader(v), stmt.serverParams[i], stmt.dmConn) + if err != nil { + return nil, err + } + default: + err = ECGO_UNSUPPORTED_INPARAM_TYPE.throw() + } + + if err != nil { + return nil, err + } + + } + checkBindParameters(stmt, bytes) + + return bytes, nil +} + +func checkNull(arg interface{}) bool { + if arg == nil { + return true + } + + innerValuer, ok := arg.(driver.Valuer) + if ok { + innerValue, err := innerValuer.Value() + if err == nil && innerValue == nil { + return true + } + } + return false +} + +type converter struct { + conn *DmConnection + isBatch bool +} +type decimalDecompose interface { + Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32) +} + +func (c *converter) ConvertValue(v interface{}) (driver.Value, error) { + if driver.IsValue(v) { + return v, nil + } + + switch vr := v.(type) { + case driver.Valuer: + sv, err := callValuerValue(vr) + if err != nil { + return nil, err + } + + rv := reflect.ValueOf(sv) + switch rv.Kind() { + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } else if ek == reflect.Slice { + c.isBatch = true + return sv, nil + } + } + return sv, nil + + case decimalDecompose, DmDecimal, *DmDecimal, DmTimestamp, *DmTimestamp, DmIntervalDT, *DmIntervalDT, + DmIntervalYM, *DmIntervalYM, driver.Rows, *driver.Rows, DmArray, *DmArray, DmStruct, *DmStruct, sql.Out: + return vr, nil + case big.Int: + return NewDecimalFromBigInt(&vr) + case big.Float: + return NewDecimalFromBigFloat(&vr) + case DmClob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case *DmClob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case DmBlob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case *DmBlob: + + if vr.connection == nil { + vr.connection = c.conn + } + return vr, nil + case io.Reader: + return vr, nil + } + + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + return nil, nil + } else { + return c.ConvertValue(rv.Elem().Interface()) + } + case reflect.Int: + return rv.Int(), nil + case reflect.Int8: + return int8(rv.Int()), nil + case reflect.Int16: + return int16(rv.Int()), nil + case reflect.Int32: + return int32(rv.Int()), nil + case reflect.Int64: + return int64(rv.Int()), nil + case reflect.Uint8: + return uint8(rv.Uint()), nil + case reflect.Uint16: + return uint16(rv.Uint()), nil + case reflect.Uint32: + return uint32(rv.Uint()), nil + case reflect.Uint64, reflect.Uint: + u64 := rv.Uint() + if u64 >= 1<<63 { + bigInt := &big.Int{} + bigInt.SetString(strconv.FormatUint(u64, 10), 10) + return NewDecimalFromBigInt(bigInt) + } + return int64(u64), nil + case reflect.Float32: + return float32(rv.Float()), nil + case reflect.Float64: + return float64(rv.Float()), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } else if ek == reflect.Slice { + c.isBatch = true + return v, nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil + } + return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) +} + +var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() + +func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { + if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && + rv.IsNil() && + rv.Type().Elem().Implements(valuerReflectType) { + return nil, nil + } + return vr.Value() +} + +func namedValueToValue(stmt *DmStatement, named []driver.NamedValue) ([]driver.Value, error) { + + dargs := make([]driver.Value, stmt.paramCount) + for i, _ := range dargs { + found := false + for _, nv := range named { + if nv.Name != "" && strings.ToUpper(nv.Name) == strings.ToUpper(stmt.serverParams[i].name) { + dargs[i] = nv.Value + found = true + break + } + } + + if !found && i < len(named) { + dargs[i] = named[i].Value + } + + } + return dargs, nil +} + +func (stmt *DmStatement) executeInner(args []driver.Value, executeType int16) (err error) { + + var bytes []interface{} + + if stmt.paramCount > 0 { + bytes, err = encodeArgs(stmt, args, true) + if err != nil { + return err + } + } + stmt.execInfo, err = stmt.dmConn.Access.Dm_build_533(stmt, bytes, false) + if err != nil { + return err + } + if stmt.execInfo.outParamDatas != nil { + for i, outParamData := range stmt.execInfo.outParamDatas { + if stmt.bindParams[i].ioType == IO_TYPE_IN || stmt.bindParams[i].ioType == IO_TYPE_UNKNOWN { + continue + } + + var v sql.Out + ok := true + for ok { + if v, ok = args[i].(sql.Out); ok { + args[i] = v.Dest + } + } + + if sc, ok := args[i].(sql.Scanner); ok { + var v interface{} + if outParamData == nil && stmt.bindParams[i].colType != CURSOR { + v = nil + if err = sc.Scan(v); err != nil { + return err + } + continue + } + + switch stmt.bindParams[i].colType { + case BOOLEAN: + v, err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BIT: + if strings.ToLower(stmt.bindParams[i].typeName) == "boolean" { + v, err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + } + + v, err = DB2G.toInt8(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case TINYINT: + v, err = DB2G.toInt8(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case SMALLINT: + v, err = DB2G.toInt16(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case INT: + v, err = DB2G.toInt32(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BIGINT: + v, err = DB2G.toInt64(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case REAL: + v, err = DB2G.toFloat32(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case DOUBLE: + v, err = DB2G.toFloat64(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + v, err = DB2G.toTime(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case INTERVAL_DT: + v = newDmIntervalDTByBytes(outParamData) + case INTERVAL_YM: + v = newDmIntervalYMByBytes(outParamData) + case DECIMAL: + v, err = DB2G.toDmDecimal(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BINARY, VARBINARY: + v = util.StringUtil.BytesToHexString(outParamData, false) + case BLOB: + v = DB2G.toDmBlob(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case CHAR, VARCHAR2, VARCHAR: + v = DB2G.toString(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case CLOB: + v = DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.bindParams[i].column) + case ARRAY: + v, err = TypeDataSV.bytesToArray(outParamData, nil, stmt.bindParams[i].typeDescriptor) + case CLASS: + v, err = TypeDataSV.bytesToObj(outParamData, nil, stmt.bindParams[i].typeDescriptor) + case CURSOR: + var tmpExecInfo *execRetInfo + if tmpExecInfo, err = stmt.dmConn.Access.Dm_build_543(stmt.bindParams[i].cursorStmt, 1); err != nil { + return err + } + if tmpExecInfo.hasResultSet { + v = newDmRows(newInnerRows(0, stmt.bindParams[i].cursorStmt, tmpExecInfo)) + } + default: + err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + if err == nil { + err = sc.Scan(v) + } + } else if args[i] == nil { + if outParamData == nil && stmt.bindParams[i].colType != CURSOR { + continue + } + + switch stmt.bindParams[i].colType { + case BOOLEAN: + args[i], err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BIT: + if strings.ToLower(stmt.bindParams[i].typeName) == "boolean" { + args[i], err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + } + + args[i], err = DB2G.toInt8(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case TINYINT: + args[i], err = DB2G.toInt8(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case SMALLINT: + args[i], err = DB2G.toInt16(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case INT: + args[i], err = DB2G.toInt32(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BIGINT: + args[i], err = DB2G.toInt64(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case REAL: + args[i], err = DB2G.toFloat32(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case DOUBLE: + args[i], err = DB2G.toFloat64(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + args[i], err = DB2G.toTime(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case INTERVAL_DT: + args[i] = newDmIntervalDTByBytes(outParamData) + case INTERVAL_YM: + args[i] = newDmIntervalYMByBytes(outParamData) + case DECIMAL: + args[i], err = DB2G.toDmDecimal(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case BINARY, VARBINARY: + args[i] = util.StringUtil.BytesToHexString(outParamData, false) + case BLOB: + args[i] = DB2G.toDmBlob(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case CHAR, VARCHAR2, VARCHAR: + args[i] = DB2G.toString(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + case CLOB: + args[i] = DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.bindParams[i].column) + default: + err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } else { + switch v := args[i].(type) { + case *string: + if outParamData == nil { + *v = "" + } else { + *v = DB2G.toString(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + } + case *sql.NullString: + if outParamData == nil { + v.String = "" + v.Valid = false + } else { + v.String = DB2G.toString(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + v.Valid = true + } + case *[]byte: + if outParamData == nil { + *v = nil + } else { + var val []byte + if val, err = DB2G.toBytes(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *[][]byte: + if outParamData == nil { + *v = nil + } else { + var ret [][]byte + var dmobj interface{} + var arr interface{} + if dmobj, err = TypeDataSV.bytesToObj(outParamData, nil, stmt.bindParams[i].typeDescriptor); err != nil { + return err + } + if dmobj != nil { + if dmobj, ok := dmobj.(*DmArray); ok { + if arr, err = dmobj.GetArray(); err != nil { + return err + } + if arr != nil { + var iarr = arr.([]interface{}) + ret = make([][]byte, len(iarr)) + + for i = 0; i < len(iarr); i++ { + if iarr[i] == nil { + ret[i] = nil + } else if tmp, ok := iarr[i].(string); ok { + ret[i] = []byte(tmp) + } else if tmp, ok := iarr[i].([]byte); ok { + ret[i] = tmp + } else { + return ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } + } + } else { + return ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } + *v = ret + } + case *bool: + if outParamData == nil { + *v = false + } else { + var val bool + if val, err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *sql.NullBool: + if outParamData == nil { + v.Bool = false + v.Valid = false + } else { + var val bool + if val, err = DB2G.toBool(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + v.Bool = val + v.Valid = true + } + case *int8: + if outParamData == nil { + *v = 0 + } else { + var val int8 + if val, err = DB2G.toInt8(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *int16: + if outParamData == nil { + *v = 0 + } else { + var val int16 + if val, err = DB2G.toInt16(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *int32: + if outParamData == nil { + *v = 0 + } else { + var val int32 + if val, err = DB2G.toInt32(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *sql.NullInt32: + if outParamData == nil { + v.Int32 = 0 + v.Valid = false + } else { + var val int32 + if val, err = DB2G.toInt32(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + v.Int32 = val + v.Valid = true + } + case *int64: + if outParamData == nil { + *v = 0 + } else { + var val int64 + if val, err = DB2G.toInt64(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *sql.NullInt64: + if outParamData == nil { + v.Int64 = 0 + v.Valid = false + } else { + var val int64 + if val, err = DB2G.toInt64(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + v.Int64 = val + v.Valid = true + } + case *uint8: + if outParamData == nil { + *v = 0 + } else { + var val uint8 + if val, err = DB2G.toByte(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *uint16: + if outParamData == nil { + *v = 0 + } else { + var val uint16 + if val, err = DB2G.toUInt16(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *uint32: + if outParamData == nil { + *v = 0 + } else { + var val uint32 + if val, err = DB2G.toUInt32(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *uint64: + if outParamData == nil { + *v = 0 + } else { + var val uint64 + if val, err = DB2G.toUInt64(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *int: + if outParamData == nil { + *v = 0 + } else { + var val int + if val, err = DB2G.toInt(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *uint: + if outParamData == nil { + *v = 0 + } else { + var val uint + if val, err = DB2G.toUInt(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *float32: + if outParamData == nil { + *v = 0.0 + } else { + var val float32 + if val, err = DB2G.toFloat32(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *float64: + if outParamData == nil { + *v = 0.0 + } else { + var val float64 + if val, err = DB2G.toFloat64(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *sql.NullFloat64: + if outParamData == nil { + v.Float64 = 0.0 + v.Valid = false + } else { + var val float64 + if val, err = DB2G.toFloat64(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + v.Float64 = val + v.Valid = true + } + case *time.Time: + if outParamData == nil { + *v = time.Time{} + } else { + var val time.Time + if val, err = DB2G.toTime(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = val + } + case *sql.NullTime: + if outParamData == nil { + v.Time = time.Time{} + v.Valid = false + } else { + var val time.Time + if val, err = DB2G.toTime(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + v.Time = val + v.Valid = true + } + case *DmTimestamp: + if outParamData == nil { + *v = DmTimestamp{} + } else { + *v = *newDmTimestampFromBytes(outParamData, stmt.bindParams[i].column, stmt.dmConn) + } + case *DmIntervalDT: + if outParamData == nil { + *v = DmIntervalDT{} + } else { + *v = *newDmIntervalDTByBytes(outParamData) + } + case *DmIntervalYM: + if outParamData == nil { + *v = DmIntervalYM{} + } else { + *v = *newDmIntervalYMByBytes(outParamData) + } + case *DmDecimal: + if outParamData == nil { + *v = DmDecimal{} + } else { + var val *DmDecimal + if val, err = DB2G.toDmDecimal(outParamData, &stmt.bindParams[i].column, stmt.dmConn); err != nil { + return err + } + *v = *val + } + case *DmBlob: + if outParamData == nil { + *v = DmBlob{} + } else { + *v = *DB2G.toDmBlob(outParamData, &stmt.bindParams[i].column, stmt.dmConn) + } + case *DmClob: + if outParamData == nil { + *v = DmClob{} + } else { + *v = *DB2G.toDmClob(outParamData, stmt.dmConn, &stmt.bindParams[i].column) + } + case *driver.Rows: + if stmt.bindParams[i].colType == CURSOR { + var tmpExecInfo *execRetInfo + tmpExecInfo, err = stmt.dmConn.Access.Dm_build_543(stmt.bindParams[i].cursorStmt, 1) + if err != nil { + return err + } + + if tmpExecInfo.hasResultSet { + *v = newDmRows(newInnerRows(0, stmt.bindParams[i].cursorStmt, tmpExecInfo)) + } else { + *v = nil + } + } + case *DmArray: + if outParamData == nil { + *v = DmArray{} + } else { + var val *DmArray + if val, err = TypeDataSV.bytesToArray(outParamData, nil, stmt.bindParams[i].typeDescriptor); err != nil { + return err + } + *v = *val + } + case *DmStruct: + if outParamData == nil { + *v = DmStruct{} + } else { + var tmp interface{} + if tmp, err = TypeDataSV.bytesToObj(outParamData, nil, stmt.bindParams[i].typeDescriptor); err != nil { + return err + } + if val, ok := tmp.(*DmStruct); ok { + *v = *val + } + } + default: + err = ECGO_UNSUPPORTED_OUTPARAM_TYPE.throw() + } + } + if err != nil { + return err + } + } + + } + return err +} + +func (stmt *DmStatement) executeBatch(args []driver.Value) (err error) { + + var bytes [][]interface{} + + if stmt.execInfo.retSqlType == Dm_build_803 || stmt.execInfo.retSqlType == Dm_build_808 { + return ECGO_INVALID_SQL_TYPE.throw() + } + + if stmt.paramCount > 0 && args != nil && len(args) > 0 { + + if len(args) == 1 || stmt.dmConn.dmConnector.batchType == 2 || + (stmt.dmConn.dmConnector.batchNotOnCall && stmt.execInfo.retSqlType == Dm_build_804) { + return stmt.executeBatchByRow(args) + } else { + for i, arg := range args { + var newArg []driver.Value + for _, a := range arg.([]interface{}) { + newArg = append(newArg, a) + } + tmpBytes, err := encodeArgs(stmt, newArg, i == 0) + if err != nil { + return err + } + bytes = append(bytes, tmpBytes) + } + stmt.execInfo, err = stmt.dmConn.Access.Dm_build_514(stmt, bytes, stmt.preExec) + } + } + return err +} + +func (stmt *DmStatement) executeBatchByRow(args []driver.Value) (err error) { + count := len(args) + stmt.execInfo = NewExceInfo() + stmt.execInfo.updateCounts = make([]int64, count) + var sqlErrBuilder strings.Builder + for i := 0; i < count; i++ { + tmpExecInfo, err := stmt.dmConn.Access.Dm_build_533(stmt, args[i].([]interface{}), stmt.preExec || i != 0) + if err == nil { + stmt.execInfo.union(tmpExecInfo, i, 1) + } else { + stmt.execInfo.updateCounts[i] = -1 + if stmt.dmConn.dmConnector.continueBatchOnError { + sqlErrBuilder.WriteString("row[" + strconv.Itoa(i) + "]:" + err.Error() + util.LINE_SEPARATOR) + } else { + return ECGO_BATCH_ERROR.addDetailln(err.Error()).throw() + } + } + } + if sqlErrBuilder.Len() > 0 { + return EC_BP_WITH_ERROR.addDetail(sqlErrBuilder.String()).throw() + } + return nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/util/zzq.go b/dpi_bridge/third_party/chunanyong_dm/util/zzq.go new file mode 100644 index 0000000..00660f2 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/util/zzq.go @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +func Split(s string, sep string) []string { + var foot = make([]int, len(s)) // 足够的元素个数 + var count, sLen, sepLen = 0, len(s), len(sep) + for i := 0; i < sLen; i++ { + // 处理 s == “-9999-1" && seperators == "-"情况 + if i == 0 && sLen >= sepLen { + if s[0:sepLen] == sep { + i += sepLen - 1 + continue + } + } + for j := 0; j < sepLen; j++ { + if s[i] == sep[j] { + foot[count] = i + count++ + break + } + } + } + var ret = make([]string, count+1) + if count == 0 { + ret[0] = s + return ret + } + ret[0] = s[0:foot[0]] + for i := 1; i < count; i++ { + ret[i] = s[foot[i-1]+1 : foot[i]] + } + ret[count] = s[foot[count-1]+1:] + return ret +} diff --git a/dpi_bridge/third_party/chunanyong_dm/util/zzr.go b/dpi_bridge/third_party/chunanyong_dm/util/zzr.go new file mode 100644 index 0000000..3e6dbb3 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/util/zzr.go @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +import ( + "go/build" + "os" + "runtime" + "strings" +) + +const ( + PathSeparator = string(os.PathSeparator) + PathListSeparator = string(os.PathListSeparator) +) + +var ( + goRoot = build.Default.GOROOT + goPath = build.Default.GOPATH //获取实际编译时的GOPATH值 +) + +type fileUtil struct { +} + +var FileUtil = &fileUtil{} + +func (fileUtil *fileUtil) Exists(path string) bool { + if _, err := os.Stat(path); !os.IsNotExist(err) { + return true + } + return false +} + +func (fileUtil *fileUtil) Search(relativePath string) (path string) { + if strings.Contains(runtime.GOOS, "windows") { + relativePath = strings.ReplaceAll(relativePath, "/", "\\") + } + + if fileUtil.Exists(goPath) { + for _, s := range strings.Split(goPath, PathListSeparator) { + path = s + PathSeparator + "src" + PathSeparator + relativePath + if fileUtil.Exists(path) { + return path + } + } + } + + if fileUtil.Exists(goPath) { + for _, s := range strings.Split(goPath, PathListSeparator) { + path = s + PathSeparator + "pkg" + PathSeparator + relativePath + if fileUtil.Exists(path) { + return path + } + } + } + + //if workDir, _ := os.Getwd(); fileUtil.Exists(workDir) { + // path = workDir + PathSeparator + "src" + PathSeparator + relativePath + // if fileUtil.Exists(path) { + // return path + // } + //} + + //if fileUtil.Exists(goRoot) { + // path = goRoot + PathSeparator + "src" + PathSeparator + relativePath + // if fileUtil.Exists(path) { + // return path + // } + //} + + return "" +} diff --git a/dpi_bridge/third_party/chunanyong_dm/util/zzs.go b/dpi_bridge/third_party/chunanyong_dm/util/zzs.go new file mode 100644 index 0000000..a575e38 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/util/zzs.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package util + +const ( + LINE_SEPARATOR = "\n" +) + +// 执行f并忽略panic +func AbsorbPanic(f func()){ + defer func() { + if p := recover(); p != nil { + // TODO do something + } + }() + f() +} + +func SliceEquals(src []byte, dest []byte) bool { + if len(src) != len(dest) { + return false + } + + for i, _ := range src { + if src[i] != dest[i] { + return false + } + } + + return true +} + +// 获取两个数的最大公约数,由调用者确保m、n>=0;如果m或n为0,返回1 +func GCD(m int32, n int32) int32 { + if m == 0 || n == 0 { + return 1 + } + r := m % n + m = n + n = r + if r == 0 { + return m + } else { + return GCD(m, n) + } +} + +// 返回切片中所有数的累加值 +func Sum(arr []int32) int32 { + var sum int32 = 0 + for _, i := range arr { + sum += i + } + return sum +} diff --git a/dpi_bridge/third_party/chunanyong_dm/util/zzt.go b/dpi_bridge/third_party/chunanyong_dm/util/zzt.go new file mode 100644 index 0000000..877fdb2 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/util/zzt.go @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package util + +import ( + "bytes" + "runtime" + "strings" + "time" + "unicode" +) + +type stringutil struct{} + +var StringUtil = &stringutil{} + +/*----------------------------------------------------*/ +func (StringUtil *stringutil) LineSeparator() string { + var lineSeparator string + if strings.Contains(runtime.GOOS, "windows") { + lineSeparator = "\r\n" + } else if strings.Contains(runtime.GOOS, "mac") { + lineSeparator = "\r" + } else { + lineSeparator = "\n" + } + + return lineSeparator +} + +func (StringUtil *stringutil) Equals(str1 string, str2 string) bool { + return str1 == str2 +} + +func (StringUtil *stringutil) EqualsIgnoreCase(str1 string, str2 string) bool { + return strings.ToUpper(str1) == strings.ToUpper(str2) +} + +func (StringUtil *stringutil) StartsWith(s string, subStr string) bool { + return strings.Index(s, subStr) == 0 +} + +func (StringUtil *stringutil) StartWithIgnoreCase(s string, subStr string) bool { + return strings.HasPrefix(strings.ToLower(s), strings.ToLower(subStr)) +} + +func (StringUtil *stringutil) EndsWith(s string, subStr string) bool { + return strings.LastIndex(s, subStr) == len(s)-1 +} + +func (StringUtil *stringutil) IsDigit(str string) bool { + if str == "" { + return false + } + sz := len(str) + for i := 0; i < sz; i++ { + if unicode.IsDigit(rune(str[i])) { + continue + } else { + return false + } + } + return true +} + +func (StringUtil *stringutil) FormatDir(dir string) string { + dir = strings.TrimSpace(dir) + if dir != "" { + if !StringUtil.EndsWith(dir, PathSeparator) { + dir += PathSeparator + } + } + return dir +} + +func (StringUtil *stringutil) HexStringToBytes(s string) []byte { + str := s + + bs := make([]byte, 0) + flag := false + + if strings.Index(str, "0x") == 0 || strings.Index(str, "0X") == 0 { + str = str[2:] + } + + if len(str) == 0 { + return bs + } + + var bsChr []byte + l := len(str) + + if l%2 == 0 { + bsChr = []byte(str) + } else { + l += 1 + bsChr = make([]byte, l) + bsChr[0] = '0' + for i := 0; i < l-1; i++ { + bsChr[i+1] = str[i] + } + } + + bs = make([]byte, l/2) + + pos := 0 + for i := 0; i < len(bsChr); i += 2 { + bt := convertHex(bsChr[i]) + bt2 := convertHex(bsChr[i+1]) + if int(bt) == 0xff || int(bt2) == 0xff { + flag = true + break + } + + bs[pos] = byte(bt*16 + bt2) + pos++ + } + + if flag { + bs = ([]byte)(str) + } + + return bs +} + +func convertHex(chr byte) byte { + if chr >= '0' && chr <= '9' { + return chr - '0' + } else if chr >= 'a' && chr <= 'f' { + return chr - 'a' + 10 + } else if chr >= 'A' && chr <= 'F' { + return chr - 'A' + 10 + } else { + return 0xff + } +} + +func (StringUtil *stringutil) BytesToHexString(bs []byte, pre bool) string { + if bs == nil { + return "" + } + if len(bs) == 0 { + return "" + } + + hexDigits := "0123456789ABCDEF" + ret := new(strings.Builder) + for _, b := range bs { + ret.WriteByte(hexDigits[0x0F&(b>>4)]) + ret.WriteByte(hexDigits[0x0F&b]) + } + if pre { + return "0x" + ret.String() + } + return ret.String() +} + +func (StringUtil *stringutil) ProcessSingleQuoteOfName(name string) string { + return StringUtil.processQuoteOfName(name, "'") +} + +func (StringUtil *stringutil) ProcessDoubleQuoteOfName(name string) string { + return StringUtil.processQuoteOfName(name, "\"") +} + +func (StringUtil *stringutil) processQuoteOfName(name string, quote string) string { + if quote == "" || name == "" { + return name + } + + temp := name + result := bytes.NewBufferString("") + index := -1 + quetoLength := len(quote) + index = strings.Index(temp, quote) + for index != -1 { + result.WriteString(temp[:index+quetoLength]) + result.WriteString(quote) + temp = temp[index+quetoLength:] + index = strings.Index(temp, quote) + } + result.WriteString(temp) + return result.String() +} + +func (StringUtil *stringutil) FormatTime() string { + return time.Now().Format("2006-01-02 15:04:05") +} + +func (StringUtil *stringutil) SubstringBetween(str string, open string, close string) string { + if str == "" { + return "" + } + + iopen := -1 + if open != "" { + iopen = strings.Index(str, open) + } + + iclose := -1 + if close != "" { + iclose = strings.LastIndex(str, close) + } + + if iopen == -1 && iclose == -1 { + return "" + } else if iopen == -1 { + return str[0:iclose] + } else if iclose == -1 { + return str[iopen:] + } else { + return str[iopen:iclose] + } +} + +//bug656976 在常量参数化时,将\+任意字符的两个字符解析成一个转义后字符,如: +// 字符串参数'a\nb'解析成字符串参数'a换行b' +func (StringUtil *stringutil) Translate(s string) string { + if !strings.ContainsRune(s, '\\') { + return s + } + reader := strings.NewReader(s) + trans := bytes.NewBufferString("") + + for { + curRune, _, err := reader.ReadRune() + if err != nil { + break + } + if curRune != '\\' { + trans.WriteRune(curRune) + } else { + //转义规则参考mysql,'\'作为转义符必须消除,不管是否作为有真正含义的特殊字符,如\x也需要变化为x + nextRune, _, err := reader.ReadRune() + if err != nil { + break + } + switch nextRune { + case 'b': + trans.WriteRune('\b') + break + case 'f': + trans.WriteRune('\f') + break + case 'n': + trans.WriteRune('\n') + break + case 'r': + trans.WriteRune('\r') + break + case 't': + trans.WriteRune('\t') + break + default: + trans.WriteRune(nextRune) + break + } + } + } + return trans.String() +} diff --git a/dpi_bridge/third_party/chunanyong_dm/v.go b/dpi_bridge/third_party/chunanyong_dm/v.go new file mode 100644 index 0000000..3e586e1 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/v.go @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import "database/sql/driver" + +type DmStruct struct { + TypeData + m_strctDesc *StructDescriptor // 结构体的描述信息 + + m_attribs []TypeData // 各属性值 + + m_objCount int // 一个数组项中存在对象类型的个数(class、动态数组) + + m_strCount int // 一个数组项中存在字符串类型的个数 + + typeName string + + elements []interface{} + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +// 数据库自定义类型Struct构造函数,typeName为库中定义的类型名称,elements为该类型每个字段的值 +// +// 例如,自定义类型语句为:create or replace type myType as object (a1 int, a2 varchar); +// +// 则绑入绑出的go对象为: val := dm.NewDmStruct("myType", []interface{} {123, "abc"}) +func NewDmStruct(typeName string, elements []interface{}) *DmStruct { + ds := new(DmStruct) + ds.typeName = typeName + ds.elements = elements + ds.Valid = true + return ds +} + +func (ds *DmStruct) create(dc *DmConnection) (*DmStruct, error) { + desc, err := newStructDescriptor(ds.typeName, dc) + if err != nil { + return nil, err + } + return ds.createByStructDescriptor(desc, dc) +} + +func newDmStructByTypeData(atData []TypeData, desc *TypeDescriptor) *DmStruct { + ds := new(DmStruct) + ds.Valid = true + ds.initTypeData() + ds.m_strctDesc = newStructDescriptorByTypeDescriptor(desc) + ds.m_attribs = atData + return ds +} + +func (dest *DmStruct) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmStruct) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmStruct: + *dest = *src + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (dt DmStruct) Value() (driver.Value, error) { + if !dt.Valid { + return nil, nil + } + return dt, nil +} + +func (ds *DmStruct) getAttribsTypeData() []TypeData { + return ds.m_attribs +} + +func (ds *DmStruct) createByStructDescriptor(desc *StructDescriptor, conn *DmConnection) (*DmStruct, error) { + ds.initTypeData() + + if nil == desc { + return nil, ECGO_INVALID_PARAMETER_VALUE.throw() + } + + ds.m_strctDesc = desc + if nil == ds.elements { + ds.m_attribs = make([]TypeData, desc.getSize()) + } else { + if desc.getSize() != len(ds.elements) && desc.getObjId() != 4 { + return nil, ECGO_STRUCT_MEM_NOT_MATCH.throw() + } + var err error + ds.m_attribs, err = TypeDataSV.toStruct(ds.elements, ds.m_strctDesc.m_typeDesc) + if err != nil { + return nil, err + } + } + + return ds, nil +} + +// 获取Struct对象在数据库中的类型名称 +func (ds *DmStruct) GetSQLTypeName() (string, error) { + return ds.m_strctDesc.m_typeDesc.getFulName() +} + +// 获取Struct对象中的各个字段的值 +func (ds *DmStruct) GetAttributes() ([]interface{}, error) { + return TypeDataSV.toJavaArrayByDmStruct(ds) +} + +func (ds *DmStruct) checkCol(col int) error { + if col < 1 || col > len(ds.m_attribs) { + return ECGO_INVALID_SEQUENCE_NUMBER.throw() + } + return nil +} + +// 获取指定索引的成员变量值,以TypeData的形式给出,col 1 based +func (ds *DmStruct) getAttrValue(col int) (*TypeData, error) { + err := ds.checkCol(col) + if err != nil { + return nil, err + } + return &ds.m_attribs[col-1], nil +} + +func (ds *DmStruct) checkValid() error { + if !ds.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/w.go b/dpi_bridge/third_party/chunanyong_dm/w.go new file mode 100644 index 0000000..a7fa35c --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/w.go @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "database/sql/driver" + "strings" + "time" +) + +const ( + Seconds_1900_1970 = 2209017600 + + OFFSET_YEAR = 0 + + OFFSET_MONTH = 1 + + OFFSET_DAY = 2 + + OFFSET_HOUR = 3 + + OFFSET_MINUTE = 4 + + OFFSET_SECOND = 5 + + OFFSET_NANOSECOND = 6 + + OFFSET_TIMEZONE = 7 + + DT_LEN = 8 + + INVALID_VALUE = int(INT32_MIN) + + NANOSECOND_DIGITS = 9 + + NANOSECOND_POW = 1000000000 +) + +type DmTimestamp struct { + dt []int + dtype int + scale int + oracleFormatPattern string + oracleDateLanguage int + + // Valid为false代表DmArray数据在数据库中为NULL + Valid bool +} + +func newDmTimestampFromDt(dt []int, dtype int, scale int) *DmTimestamp { + dmts := new(DmTimestamp) + dmts.Valid = true + dmts.dt = dt + dmts.dtype = dtype + dmts.scale = scale + return dmts +} + +func newDmTimestampFromBytes(bytes []byte, column column, conn *DmConnection) *DmTimestamp { + dmts := new(DmTimestamp) + dmts.Valid = true + dmts.dt = decode(bytes, column.isBdta, column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + + if isLocalTimeZone(int(column.colType), int(column.scale)) { + dmts.scale = getLocalTimeZoneScale(int(column.colType), int(column.scale)) + } else { + dmts.scale = int(column.scale) + } + + dmts.dtype = int(column.colType) + dmts.scale = int(column.scale) + dmts.oracleDateLanguage = int(conn.OracleDateLanguage) + switch column.colType { + case DATE: + dmts.oracleFormatPattern = conn.FormatDate + case TIME: + dmts.oracleFormatPattern = conn.FormatTime + case TIME_TZ: + dmts.oracleFormatPattern = conn.FormatTimeTZ + case DATETIME, DATETIME2: + dmts.oracleFormatPattern = conn.FormatTimestamp + case DATETIME_TZ, DATETIME2_TZ: + dmts.oracleFormatPattern = conn.FormatTimestampTZ + } + return dmts +} + +func NewDmTimestampFromString(str string) (*DmTimestamp, error) { + dt := make([]int, DT_LEN) + dtype, err := toDTFromString(strings.TrimSpace(str), dt) + if err != nil { + return nil, err + } + + if dtype == DATE { + return newDmTimestampFromDt(dt, dtype, 0), nil + } + return newDmTimestampFromDt(dt, dtype, 6), nil +} + +func NewDmTimestampFromTime(time time.Time) *DmTimestamp { + dt := toDTFromTime(time) + return newDmTimestampFromDt(dt, DATETIME, 6) +} + +func (dmTimestamp *DmTimestamp) ToTime() time.Time { + _, tzs := time.Now().Zone() + return toTimeFromDT(dmTimestamp.dt, tzs / 60) +} + +// 获取年月日时分秒毫秒时区 +func (dmTimestamp *DmTimestamp) GetDt() []int { + return dmTimestamp.dt +} + +func (dmTimestamp *DmTimestamp) CompareTo(ts DmTimestamp) int { + if dmTimestamp.ToTime().Equal(ts.ToTime()) { + return 0 + } else if dmTimestamp.ToTime().Before(ts.ToTime()) { + return -1 + } else { + return 1 + } +} + +func (dmTimestamp *DmTimestamp) String() string { + if dmTimestamp.oracleFormatPattern != "" { + return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, int32(dmTimestamp.scale), dmTimestamp.oracleDateLanguage) + } + return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale) +} + +func (dest *DmTimestamp) Scan(src interface{}) error { + if dest == nil { + return ECGO_STORE_IN_NIL_POINTER.throw() + } + switch src := src.(type) { + case nil: + *dest = *new(DmTimestamp) + // 将Valid标志置false表示数据库中该列为NULL + (*dest).Valid = false + return nil + case *DmTimestamp: + *dest = *src + return nil + case time.Time: + ret := NewDmTimestampFromTime(src) + *dest = *ret + return nil + case string: + ret, err := NewDmTimestampFromString(src) + if err != nil { + return err + } + *dest = *ret + return nil + default: + return UNSUPPORTED_SCAN.throw() + } +} + +func (dmTimestamp DmTimestamp) Value() (driver.Value, error) { + if !dmTimestamp.Valid { + return nil, nil + } + return dmTimestamp, nil +} + +//func (dmTimestamp *DmTimestamp) toBytes() ([]byte, error) { +// return encode(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale, dmTimestamp.dt[OFFSET_TIMEZONE]) +//} + +/** + * 获取当前对象的年月日时分秒,如果原来没有decode会先decode; + */ +func (dmTimestamp *DmTimestamp) getDt() []int { + return dmTimestamp.dt +} + +func (dmTimestamp *DmTimestamp) getTime() int64 { + _, tzs := time.Now().Zone() + sec := toTimeFromDT(dmTimestamp.dt, tzs / 60).Unix() + return sec + int64(dmTimestamp.dt[OFFSET_NANOSECOND]) +} + +func (dmTimestamp *DmTimestamp) setTime(time int64) { + timeInMillis := (time / 1000) * 1000 + nanos := (int64)((time % 1000) * 1000000) + if nanos < 0 { + nanos = 1000000000 + nanos + timeInMillis = (((time / 1000) - 1) * 1000) + } + dmTimestamp.dt = toDTFromUnix(timeInMillis, nanos) +} + +func (dmTimestamp *DmTimestamp) setTimezone(tz int) error { + // DM中合法的时区取值范围为-12:59至+14:00 + if tz <= -13*60 || tz > 14*60 { + return ECGO_INVALID_DATETIME_FORMAT.throw() + } + dmTimestamp.dt[OFFSET_TIMEZONE] = tz + return nil +} + +func (dmTimestamp *DmTimestamp) getNano() int64 { + return int64(dmTimestamp.dt[OFFSET_NANOSECOND] * 1000) +} + +func (dmTimestamp *DmTimestamp) setNano(nano int64) { + dmTimestamp.dt[OFFSET_NANOSECOND] = (int)(nano / 1000) +} + +func (dmTimestamp *DmTimestamp) string() string { + if dmTimestamp.oracleFormatPattern != "" { + return dtToStringByOracleFormat(dmTimestamp.dt, dmTimestamp.oracleFormatPattern, int32(dmTimestamp.scale), dmTimestamp.oracleDateLanguage) + } + return dtToString(dmTimestamp.dt, dmTimestamp.dtype, dmTimestamp.scale) +} + +func (dmTimestamp *DmTimestamp) checkValid() error { + if !dmTimestamp.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} + +/* for gorm v2 */ +func (d *DmTimestamp) GormDataType() string { + return "TIMESTAMP" +} \ No newline at end of file diff --git a/dpi_bridge/third_party/chunanyong_dm/x.go b/dpi_bridge/third_party/chunanyong_dm/x.go new file mode 100644 index 0000000..b2f6ebf --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/x.go @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "context" + "strconv" + "strings" + "sync" + "time" +) + +const ( + STATUS_VALID_TIME = 20 * time.Second // ms + + // sort 值 + SORT_SERVER_MODE_INVALID = -1 // 不允许连接的模式 + + SORT_SERVER_NOT_ALIVE = -2 // 站点无法连接 + + SORT_UNKNOWN = INT32_MAX // 站点还未连接过,模式未知 + + SORT_NORMAL = 30 + + SORT_PRIMARY = 20 + + SORT_STANDBY = 10 + + // OPEN>MOUNT>SUSPEND + SORT_OPEN = 3 + + SORT_MOUNT = 2 + + SORT_SUSPEND = 1 +) + +type ep struct { + host string + port int32 + alive bool + statusRefreshTs int64 // 状态更新的时间点 + serverMode int32 + serverStatus int32 + dscControl bool + sort int32 + epSeqno int32 + epStatus int32 + lock sync.Mutex +} + +func newEP(host string, port int32) *ep { + ep := new(ep) + ep.host = host + ep.port = port + ep.serverMode = -1 + ep.serverStatus = -1 + ep.sort = SORT_UNKNOWN + return ep +} + +func (ep *ep) getSort(checkTime bool) int32 { + if checkTime { + if time.Now().UnixNano()-ep.statusRefreshTs < int64(STATUS_VALID_TIME) { + return ep.sort + } else { + return SORT_UNKNOWN + } + } + return ep.sort +} + +func (ep *ep) calcSort(loginMode int32) int32 { + var sort int32 = 0 + switch loginMode { + case LOGIN_MODE_PRIMARY_FIRST: + { + // 主机优先:PRIMARY>NORMAL>STANDBY + switch ep.serverMode { + case SERVER_MODE_NORMAL: + sort += SORT_NORMAL * 10 + case SERVER_MODE_PRIMARY: + sort += SORT_PRIMARY * 100 + case SERVER_MODE_STANDBY: + sort += SORT_STANDBY + } + } + case LOGIN_MODE_STANDBY_FIRST: + { + // STANDBY优先: STANDBY>PRIMARY>NORMAL + switch ep.serverMode { + case SERVER_MODE_NORMAL: + sort += SORT_NORMAL + case SERVER_MODE_PRIMARY: + sort += SORT_PRIMARY * 10 + case SERVER_MODE_STANDBY: + sort += SORT_STANDBY * 100 + } + } + case LOGIN_MODE_NORMAL_FIRST: + { + // NORMAL优先: NORMAL>PRIMARY>STANDBY + switch ep.serverMode { + case SERVER_MODE_STANDBY: + sort += SORT_STANDBY + case SERVER_MODE_PRIMARY: + sort += SORT_PRIMARY * 10 + case SERVER_MODE_NORMAL: + sort += SORT_NORMAL * 100 + } + } + case LOGIN_MODE_PRIMARY_ONLY: + if ep.serverMode != SERVER_MODE_PRIMARY { + return SORT_SERVER_MODE_INVALID + } + sort += SORT_PRIMARY + case LOGIN_MODE_STANDBY_ONLY: + if ep.serverMode != SERVER_MODE_STANDBY { + return SORT_SERVER_MODE_INVALID + } + sort += SORT_STANDBY + } + + switch ep.serverStatus { + case SERVER_STATUS_MOUNT: + sort += SORT_MOUNT + case SERVER_STATUS_OPEN: + sort += SORT_OPEN + case SERVER_STATUS_SUSPEND: + sort += SORT_SUSPEND + } + return sort +} + +func (ep *ep) refreshStatus(alive bool, conn *DmConnection) { + ep.lock.Lock() + defer ep.lock.Unlock() + ep.alive = alive + ep.statusRefreshTs = time.Now().UnixNano() + if alive { + ep.serverMode = conn.SvrMode + ep.serverStatus = conn.SvrStat + ep.dscControl = conn.dscControl + ep.sort = ep.calcSort(int32(conn.dmConnector.loginMode)) + } else { + ep.serverMode = -1 + ep.serverStatus = -1 + ep.dscControl = false + ep.sort = SORT_SERVER_NOT_ALIVE + } +} + +func (ep *ep) connect(connector *DmConnector) (*DmConnection, error) { + connector.host = ep.host + connector.port = ep.port + conn, err := connector.connectSingle(context.Background()) + if err != nil { + ep.refreshStatus(false, conn) + return nil, err + } + ep.refreshStatus(true, conn) + return conn, nil +} + +func (ep *ep) getServerStatusDesc(serverStatus int32) string { + ret := "" + switch ep.serverStatus { + case SERVER_STATUS_OPEN: + ret = "OPEN" + case SERVER_STATUS_MOUNT: + ret = "MOUNT" + case SERVER_STATUS_SUSPEND: + ret = "SUSPEND" + default: + ret = "UNKNOWN" + } + return ret +} + +func (ep *ep) getServerModeDesc(serverMode int32) string { + ret := "" + switch ep.serverMode { + case SERVER_MODE_NORMAL: + ret = "NORMAL" + case SERVER_MODE_PRIMARY: + ret = "PRIMARY" + case SERVER_MODE_STANDBY: + ret = "STANDBY" + default: + ret = "UNKNOWN" + } + return ret +} + +func (ep *ep) String() string { + dscControl := ")" + if ep.dscControl { + dscControl = ", DSC CONTROL)" + } + return strings.TrimSpace(ep.host) + ":" + strconv.Itoa(int(ep.port)) + + " (" + ep.getServerModeDesc(ep.serverMode) + ", " + ep.getServerStatusDesc(ep.serverStatus) + dscControl +} diff --git a/dpi_bridge/third_party/chunanyong_dm/y.go b/dpi_bridge/third_party/chunanyong_dm/y.go new file mode 100644 index 0000000..dea32fc --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/y.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "bytes" + "math/rand" + "sync" + "time" + + "gitee.com/chunanyong/dm/util" +) + +/** + * dm_svc.conf中配置的服务名对应的一组实例, 以及相关属性和状态信息 + * + * 需求: + * 1. 连接均匀分布在各个节点上 + * 2. loginMode,loginStatus匹配 + * 3. 连接异常节点比较耗时,在DB列表中包含异常节点时异常连接尽量靠后,减少对建连接速度的影响 + * + * + * DB 连接顺序: + * 1. well distribution,每次连接都从列表的下一个节点开始 + * 2. 用DB sort值按从大到小排序,sort为一个四位数XXXX,个位--serverStatus,十位--serverMode,共 有三种模式,最优先的 *100, 次优先的*10 + */ +type epGroup struct { + name string + epList []*ep + props *Properties + epStartPos int32 // wellDistribute 起始位置 + lock sync.Mutex +} + +func newEPGroup(name string, serverList []*ep) *epGroup { + g := new(epGroup) + g.name = name + g.epList = serverList + if serverList == nil || len(serverList) == 0 { + g.epStartPos = -1 + } else { + // 保证进程间均衡,起始位置采用随机值 + g.epStartPos = rand.Int31n(int32(len(serverList))) - 1 + } + return g +} + +func (g *epGroup) connect(connector *DmConnector) (*DmConnection, error) { + var dbSelector = g.getEPSelector(connector) + var ex error = nil + // 如果配置了loginMode的主、备等优先策略,而未找到最高优先级的节点时持续循环switchtimes次,如果最终还是没有找到最高优先级则选择次优先级的 + // 如果只有一个节点,无需switchTimes+1;多个节点时保证switchTimes轮尝试,最后一轮决定用哪个节点(由于节点已经按照模式优先级排序,最后一轮理论上就是连第一个节点) + var cycleCount int32 + if len(g.epList) == 1 { + cycleCount = connector.switchTimes + } else { + cycleCount = connector.switchTimes + 1 + } + for i := int32(0); i < cycleCount; i++ { + // 循环了一遍,如果没有符合要求的, 重新排序, 再尝试连接 + conn, err := g.traverseServerList(connector, dbSelector, i == 0, i == cycleCount-1) + if err != nil { + ex = err + time.Sleep(time.Duration(connector.switchInterval) * time.Millisecond) + continue + } + return conn, nil + } + return nil, ex +} + +func (g *epGroup) getEPSelector(connector *DmConnector) *epSelector { + if connector.epSelector == TYPE_HEAD_FIRST { + return newEPSelector(g.epList) + } else { + serverCount := int32(len(g.epList)) + sortEPs := make([]*ep, serverCount) + g.lock.Lock() + defer g.lock.Unlock() + g.epStartPos = (g.epStartPos + 1) % serverCount + for i := int32(0); i < serverCount; i++ { + sortEPs[i] = g.epList[(i+g.epStartPos)%serverCount] + } + return newEPSelector(sortEPs) + } +} + +/** +* 从指定编号开始,遍历一遍服务名中的ip列表,只连接指定类型(主机或备机)的ip +* @param servers +* @param checkTime +* +* @exception +* DBError.ECJDBC_INVALID_SERVER_MODE 有站点的模式不匹配 +* DBError.ECJDBC_COMMUNITION_ERROR 所有站点都连不上 + */ +func (g *epGroup) traverseServerList(connector *DmConnector, epSelector *epSelector, first bool, last bool) (*DmConnection, error) { + epList := epSelector.sortDBList(first) + errorMsg := bytes.NewBufferString("") + var ex error = nil // 第一个错误 + for _, server := range epList { + conn, err := server.connect(connector) + if err != nil { + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + valid, err := epSelector.checkServerMode(conn, last) + if err != nil { + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + if !valid { + conn.close() + err = ECGO_INVALID_SERVER_MODE.throw() + if ex == nil { + ex = err + } + errorMsg.WriteString("[") + errorMsg.WriteString(server.String()) + errorMsg.WriteString("]") + errorMsg.WriteString(err.Error()) + errorMsg.WriteString(util.StringUtil.LineSeparator()) + continue + } + return conn, nil + } + if ex != nil { + return nil, ex + } + return nil, ECGO_COMMUNITION_ERROR.addDetail(errorMsg.String()).throw() +} diff --git a/dpi_bridge/third_party/chunanyong_dm/z.go b/dpi_bridge/third_party/chunanyong_dm/z.go new file mode 100644 index 0000000..7bb3315 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/z.go @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import "sort" + +const ( + TYPE_WELL_DISTRIBUTE = 0 + TYPE_HEAD_FIRST = 1 +) + +type epSelector struct { + dbs []*ep +} + +func newEPSelector(dbs []*ep) *epSelector { + return &epSelector{dbs} +} + +func (s *epSelector) sortDBList(first bool) []*ep { + if !first { + // 按sort从大到小排序,相同sort值顺序不变 + sort.Slice(s.dbs, func(i, j int) bool { + return s.dbs[i].getSort(first) > s.dbs[j].getSort(first) + }) + } + return s.dbs +} + +func (s *epSelector) checkServerMode(conn *DmConnection, last bool) (bool, error) { + // 只连dsc control节点 + if conn.dmConnector.loginDscCtrl && !conn.dscControl { + conn.close() + return false, ECGO_INVALID_SERVER_MODE.throw() + } + // 模式不匹配, 这里使用的是连接之前的sort,连接之后server的状态可能发生改变sort也可能改变 + if conn.dmConnector.loginStatus > 0 && int(conn.SvrStat) != conn.dmConnector.loginStatus { + conn.close() + return false, ECGO_INVALID_SERVER_MODE.throw() + } + if last { + switch conn.dmConnector.loginMode { + case LOGIN_MODE_PRIMARY_ONLY: + return conn.SvrMode == SERVER_MODE_PRIMARY, nil + case LOGIN_MODE_STANDBY_ONLY: + return conn.SvrMode == SERVER_MODE_STANDBY, nil + default: + return true, nil + } + } + switch conn.dmConnector.loginMode { + case LOGIN_MODE_NORMAL_FIRST: + return conn.SvrMode == SERVER_MODE_NORMAL, nil + case LOGIN_MODE_PRIMARY_FIRST, LOGIN_MODE_PRIMARY_ONLY: + return conn.SvrMode == SERVER_MODE_PRIMARY, nil + case LOGIN_MODE_STANDBY_FIRST, LOGIN_MODE_STANDBY_ONLY: + return conn.SvrMode == SERVER_MODE_STANDBY, nil + default: + break + } + return false, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/za.go b/dpi_bridge/third_party/chunanyong_dm/za.go new file mode 100644 index 0000000..72c4ad3 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/za.go @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "bytes" + "fmt" + "runtime" + + "gitee.com/chunanyong/dm/i18n" +) + +// 驱动级错误 +var ( + DSN_INVALID_SCHEMA = newDmError(9001, "error.dsn.invalidSchema") + UNSUPPORTED_SCAN = newDmError(9002, "error.unsupported.scan") + INVALID_PARAMETER_NUMBER = newDmError(9003, "error.invalidParameterNumber") + THIRD_PART_CIPHER_INIT_FAILED = newDmError(9004, "error.initThirdPartCipherFailed") + ECGO_NOT_QUERY_SQL = newDmError(9005, "error.notQuerySQL") + ECGO_NOT_EXEC_SQL = newDmError(9006, "error.notExecSQL") + ECGO_UNKOWN_NETWORK = newDmError(9007, "error.unkownNetWork") + ECGO_INVALID_CONN = newDmError(9008, "error.invalidConn") + ECGO_UNSUPPORTED_INPARAM_TYPE = newDmError(9009, "error.unsupportedInparamType") + ECGO_UNSUPPORTED_OUTPARAM_TYPE = newDmError(9010, "error.unsupportedOutparamType") + ECGO_STORE_IN_NIL_POINTER = newDmError(9011, "error.storeInNilPointer") + ECGO_IS_NULL = newDmError(9012, "error.isNull") + DSN_INVALID_FORMAT = newDmError(9001, "error.dsn.invalidFormat") +) + +var ( + ECGO_CONNECTION_SWITCH_FAILED = newDmError(20001, "error.connectionSwitchFailed") + ECGO_CONNECTION_SWITCHED = newDmError(20000, "error.connectionSwitched") + ECGO_COMMUNITION_ERROR = newDmError(6001, "error.communicationError") + ECGO_MSG_CHECK_ERROR = newDmError(6002, "error.msgCheckError") + ECGO_INVALID_TIME_INTERVAL = newDmError(6005, "error.invalidTimeInterval") + ECGO_UNSUPPORTED_TYPE = newDmError(6006, "error.unsupportedType") + ECGO_DATA_CONVERTION_ERROR = newDmError(6007, "error.dataConvertionError") + ECGO_INVALID_SQL_TYPE = newDmError(6009, "error.invalidSqlType") + ECGO_INVALID_DATETIME_FORMAT = newDmError(6015, "error.invalidDateTimeFormat") + ECGO_INVALID_COLUMN_TYPE = newDmError(6016, "error.invalidColumnType") + ECGO_RESULTSET_IS_READ_ONLY = newDmError(6029, "error.resultsetInReadOnlyStatus") + ECGO_INVALID_SEQUENCE_NUMBER = newDmError(6032, "error.invalidSequenceNumber") + ECGO_RESULTSET_CLOSED = newDmError(6034, "errorResultSetColsed") + ECGO_STATEMENT_HANDLE_CLOSED = newDmError(6035, "errorStatementHandleClosed") + ECGO_INVALID_PARAMETER_VALUE = newDmError(6036, "error.invalidParamterValue") + ECGO_INVALID_TRAN_ISOLATION = newDmError(6038, "error.invalidTranIsolation") + ECGO_COMMIT_IN_AUTOCOMMIT_MODE = newDmError(6039, "errorCommitInAutoCommitMode") + ECGO_ROLLBACK_IN_AUTOCOMMIT_MODE = newDmError(6040, "errorRollbackInAutoCommitMode") + ECGO_UNBINDED_PARAMETER = newDmError(6054, "error.unbindedParameter") + ECGO_PARAM_COUNT_LIMIT = newDmError(6056, "error.ParamCountLimit") + ECGO_INVALID_LENGTH_OR_OFFSET = newDmError(6057, "error.invalidLenOrOffset") + ECGO_CONNECTION_CLOSED = newDmError(6060, "error.error.connectionClosedOrNotBuild") + ECGO_INTERVAL_OVERFLOW = newDmError(6066, "error.intervalValueOverflow") + ECGO_STRING_CUT = newDmError(6067, "error.stringCut") + ECGO_INVALID_HEX = newDmError(6068, "error.invalidHex") + ECGO_INVALID_CIPHER = newDmError(6069, "error.invalidCipher") + ECGO_INVALID_BFILE_STR = newDmError(6070, "error.invalidBFile") + ECGO_OSAUTH_ERROR = newDmError(6073, "error.osauthError") + ECGO_ERROR_SERVER_VERSION = newDmError(6074, "error.serverVersion") + ECGO_USERNAME_TOO_LONG = newDmError(6075, "error.usernameTooLong") + ECGO_PASSWORD_TOO_LONG = newDmError(6076, "error.passwordTooLong") + ECGO_INVALID_COMPLEX_TYPE_NAME = newDmError(6079, "error.invalidComplexTypeName") + ECGO_STRUCT_MEM_NOT_MATCH = newDmError(6080, "error.structMemNotMatch") + ECGO_INVALID_OBJ_BLOB = newDmError(6081, "error.invalidObjBlob") + ECGO_INVALID_ARRAY_LEN = newDmError(6082, "error.invalidArrayLen") + ECGO_INVALID_SERVER_MODE = newDmError(6091, "error.invalidServerMode") + ECGO_DATA_TOO_LONG = newDmError(6092, "error.dataTooLong") + ECGO_BATCH_ERROR = newDmError(6093, "error.batchError") + ECGO_MSG_TOO_LONG = newDmError(6101, "error.msgTooLong") + ECGO_INVALID_DATETIME_VALUE = newDmError(6103, "error.invalidDateTimeValue") + + ECGO_INIT_SSL_FAILED = newDmError(20002, "error.SSLInitFailed") + ECGO_LOB_FREED = newDmError(20003, "error.LobDataHasFreed") + ECGO_FATAL_ERROR = newDmError(20004, "error.fatalError") +) + +// Svr Msg Err +var ( + ECGO_DATA_OVERFLOW = newDmError(-6102, "error.dataOverflow") + ECGO_DATETIME_OVERFLOW = newDmError(-6112, "error.datetimeOverflow") + EC_RN_EXCEED_ROWSET_SIZE = newDmError(-7036, "") + EC_BP_WITH_ERROR = newDmError(121, "warning.bpWithErr") +) + +type DmError struct { + ErrCode int32 + ErrText string + stack []uintptr + detail string +} + +func newDmError(errCode int32, errText string) *DmError { + de := new(DmError) + de.ErrCode = errCode + de.ErrText = errText + de.stack = nil + de.detail = "" + return de +} + +func (dmError *DmError) throw() *DmError { + var pcs [32]uintptr + n := runtime.Callers(2, pcs[:]) + dmError.stack = pcs[0:n] + return dmError +} + +func (dmError *DmError) Stack() string { + if dmError == nil || dmError.stack == nil { + return "" + } + buffer := bytes.NewBuffer(nil) + index := 1 + space := " " + for _, p := range dmError.stack { + if fn := runtime.FuncForPC(p - 1); fn != nil { + file, line := fn.FileLine(p - 1) + buffer.WriteString(fmt.Sprintf(" %d).%s%s\n \t%s:%d\n", index, space, fn.Name(), file, line)) + index++ + } + } + return buffer.String() +} + +func (dmError *DmError) getErrText() string { + return i18n.Get(dmError.ErrText, Locale) +} + +func (dmError *DmError) Error() string { + return fmt.Sprintf("Error %d: %s", dmError.ErrCode, dmError.getErrText()) + dmError.detail // + "\n" + "stack info:\n" + dmError.Stack() +} + +// 扩充ErrText +func (dmError *DmError) addDetail(detail string) *DmError { + dmError.detail = detail + return dmError +} +func (dmError *DmError) addDetailln(detail string) *DmError { + return dmError.addDetail("\n" + detail) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zb.go b/dpi_bridge/third_party/chunanyong_dm/zb.go new file mode 100644 index 0000000..c6af3c6 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zb.go @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +const ( + PARAM_COUNT_LIMIT int32 = 65536 + + IGNORE_TARGET_LENGTH int32 = -1 + + IGNORE_TARGET_SCALE int32 = -1 + + IGNORE_TARGET_TYPE = INT32_MIN + + TYPE_FLAG_UNKNOWN byte = 0 // 未知类型 + + TYPE_FLAG_EXACT byte = 1 // 精确类型 + + TYPE_FLAG_RECOMMEND byte = 2 // 推荐类型 + + IO_TYPE_UNKNOWN int8 = -1 + + IO_TYPE_IN int8 = 0 + + IO_TYPE_OUT int8 = 1 + + IO_TYPE_INOUT int8 = 2 + + MASK_ORACLE_DATE int32 = 1 + + MASK_ORACLE_FLOAT int32 = 2 + + MASK_BFILE int32 = 3 + + MASK_LOCAL_DATETIME int32 = 4 +) + +type execRetInfo struct { + // param + outParamDatas [][]byte + + // rs + hasResultSet bool + + rsDatas [][][]byte + + rsSizeof int // 结果集数据占用多少空间,(消息中结果集起始位置到 rsCacheOffset + // 的空间大小,这和实际的rsDatas占用空间大小有一定出入,这里粗略估算,用于结果集缓存时的空间管理) + + rsCacheOffset int32 // 缓存信息,在响应消息体中的偏移,0表示不存在,仅结果集缓存中可以用 + + rsBdta bool + + rsUpdatable bool + + rsRowIds []int64 + + // rs cache + tbIds []int32 + + tbTss []int64 + + // print + printLen int32 + + printMsg string + + // explain + explain string + + // 影响行数 + updateCount int64 // Insert/Update/Delet影响行数, select结果集的总行数 + + updateCounts []int64 // 批量影响行数 + + // 键 + rowid int64 + + lastInsertId int64 + + // other + retSqlType int16 // 执行返回的语句类型 + + execId int32 + + serverParams []parameter + + nativeSQL string +} + +type column struct { + typeName string + + colType int32 + + prec int32 + + scale int32 + + name string + + tableName string + + schemaName string + + nullable bool + + identity bool + + readonly bool // 是否只读 + + baseName string + + // lob info + lob bool + + lobTabId int32 + + lobColId int16 + + // 用于描述ARRAY、STRUCT类型的特有描述信息 + typeDescriptor *TypeDescriptor + + isBdta bool + + mask int32 +} + +type parameter struct { + column + + typeFlag byte + + ioType int8 + + outJType int32 + + outScale int32 + + outObjectName string + + cursorStmt *DmStatement + + hasDefault bool +} + +func (column *column) InitColumn() *column { + column.typeName = "" + + column.colType = 0 + + column.prec = 0 + + column.scale = 0 + + column.name = "" + + column.tableName = "" + + column.schemaName = "" + + column.nullable = false + + column.identity = false + + column.readonly = false + + column.baseName = "" + + // lob info + column.lob = false + + column.lobTabId = 0 + + column.lobColId = 0 + + // 用于描述ARRAY、STRUCT类型的特有描述信息 + column.typeDescriptor = nil + + column.isBdta = false + + return column +} + +func (parameter *parameter) InitParameter() *parameter { + parameter.InitColumn() + + parameter.typeFlag = TYPE_FLAG_UNKNOWN + + parameter.ioType = IO_TYPE_UNKNOWN + + parameter.outJType = IGNORE_TARGET_TYPE + + parameter.outScale = IGNORE_TARGET_SCALE + + parameter.outObjectName = "" + + parameter.cursorStmt = nil + + return parameter +} + +func (parameter *parameter) resetType(colType int32) { + parameter.colType = colType + parameter.scale = 0 + switch colType { + case BIT, BOOLEAN: + parameter.prec = BIT_PREC + case TINYINT: + parameter.prec = TINYINT_PREC + case SMALLINT: + parameter.prec = SMALLINT_PREC + case INT: + parameter.prec = INT_PREC + case BIGINT: + parameter.prec = BIGINT_PREC + case CHAR, VARCHAR, VARCHAR2: + parameter.prec = VARCHAR_PREC + case CLOB: + parameter.prec = CLOB_PREC + case BINARY, VARBINARY: + parameter.prec = VARBINARY_PREC + case BLOB: + parameter.prec = BLOB_PREC + case DATE: + parameter.prec = DATE_PREC + case TIME: + parameter.prec = TIME_PREC + parameter.scale = 6 + case TIME_TZ: + parameter.prec = TIME_TZ_PREC + parameter.scale = 6 + case DATETIME: + parameter.prec = DATETIME_PREC + parameter.scale = 6 + case DATETIME_TZ: + parameter.prec = DATETIME_TZ_PREC + parameter.scale = 6 + case DATETIME2: + parameter.prec = DATETIME2_PREC + parameter.scale = 9 + case DATETIME2_TZ: + parameter.prec = DATETIME2_TZ_PREC + parameter.scale = 9 + case REAL,DOUBLE,DECIMAL,INTERVAL_YM,INTERVAL_DT,ARRAY,CLASS,PLTYPE_RECORD,SARRAY: + parameter.prec = 0 + case UNKNOWN, NULL: + // UNKNOWN 导致服务器断言 // setNull导致服务器报错“字符转换失败” + parameter.colType = VARCHAR + parameter.prec = VARCHAR_PREC + default: + } +} + +func (execInfo *execRetInfo) union(other *execRetInfo, startRow int, count int) { + if count == 1 { + execInfo.updateCounts[startRow] = other.updateCount + } else if execInfo.updateCounts != nil && other.updateCounts != nil{ + copy(execInfo.updateCounts[startRow:startRow+count], other.updateCounts[0:count]) + } + if execInfo.outParamDatas != nil { + execInfo.outParamDatas = append(execInfo.outParamDatas, other.outParamDatas...) + } +} + +func NewExceInfo() *execRetInfo { + + execInfo := execRetInfo{} + + execInfo.outParamDatas = nil + + execInfo.hasResultSet = false + + execInfo.rsDatas = nil + + execInfo.rsSizeof = 0 + + execInfo.rsCacheOffset = 0 + + execInfo.rsBdta = false + + execInfo.rsUpdatable = false + + execInfo.rsRowIds = nil + + execInfo.tbIds = nil + + execInfo.tbTss = nil + + execInfo.printLen = 0 + + execInfo.printMsg = "" + + execInfo.explain = "" + + execInfo.updateCount = 0 + + execInfo.updateCounts = nil + + execInfo.rowid = -1 + + execInfo.lastInsertId = 0 + // other + execInfo.retSqlType = -1 // 执行返回的语句类型 + + execInfo.execId = 0 + + return &execInfo +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zc.go b/dpi_bridge/third_party/chunanyong_dm/zc.go new file mode 100644 index 0000000..0672767 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zc.go @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "context" + "database/sql/driver" + "reflect" + "sync" + "sync/atomic" + "time" +) + +type filter interface { + DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) + DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) + + DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) + DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver + + DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) + DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) + DmConnectionCommit(filterChain *filterChain, c *DmConnection) error + DmConnectionRollback(filterChain *filterChain, c *DmConnection) error + DmConnectionClose(filterChain *filterChain, c *DmConnection) error + DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error + DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) + DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) + DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) + DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) + DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) + DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) + DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error + DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error + + DmStatementClose(filterChain *filterChain, s *DmStatement) error + DmStatementNumInput(filterChain *filterChain, s *DmStatement) int + DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) + DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) + DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) + DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) + DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error + + DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) + DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) + + DmRowsColumns(filterChain *filterChain, r *DmRows) []string + DmRowsClose(filterChain *filterChain, r *DmRows) error + DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error + DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool + DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error + DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type + DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string + DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) + DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) + DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) +} + +type IDGenerator int64 + +var dmDriverIDGenerator = new(IDGenerator) +var dmConntorIDGenerator = new(IDGenerator) +var dmConnIDGenerator = new(IDGenerator) +var dmStmtIDGenerator = new(IDGenerator) +var dmResultIDGenerator = new(IDGenerator) +var dmRowsIDGenerator = new(IDGenerator) + +func (g *IDGenerator) incrementAndGet() int64 { + return atomic.AddInt64((*int64)(g), 1) +} + +type RWSiteEnum int + +const ( + PRIMARY RWSiteEnum = iota + STANDBY + ANYSITE +) + +var ( + goMapMu sync.RWMutex + goMap = make(map[string]goRun, 2) +) + +type filterable struct { + filterChain *filterChain + rwInfo *rwInfo + logInfo *logInfo + recoverInfo *recoverInfo + statInfo *statInfo + objId int64 + idGenerator *IDGenerator +} + +func runLog() { + goMapMu.Lock() + _, ok := goMap["log"] + if !ok { + goMap["log"] = &logWriter{ + flushQueue: make(chan []byte, LogFlushQueueSize), + date: time.Now().Format("2006-01-02"), + logFile: nil, + flushFreq: LogFlushFreq, + filePath: LogDir, + filePrefix: "dm_go", + buffer: Dm_build_4(), + } + go goMap["log"].doRun() + } + goMapMu.Unlock() +} + +func runStat() { + goMapMu.Lock() + _, ok := goMap["stat"] + if !ok { + goMap["stat"] = newStatFlusher() + go goMap["stat"].doRun() + } + goMapMu.Unlock() +} + +func (f *filterable) createFilterChain(bc *DmConnector, props *Properties) { + var filters = make([]filter, 0, 5) + + if bc != nil { + if LogLevel != LOG_OFF { + filters = append(filters, &logFilter{}) + f.logInfo = &logInfo{logRecord: new(LogRecord)} + runLog() + } + + if StatEnable { + filters = append(filters, &statFilter{}) + f.statInfo = newStatInfo() + goStatMu.Lock() + if goStat == nil { + goStat = newGoStat(1000) + } + goStatMu.Unlock() + runStat() + } + + if bc.doSwitch != DO_SWITCH_OFF { + filters = append(filters, &reconnectFilter{}) + f.recoverInfo = newRecoverInfo() + } + + if bc.rwSeparate > RW_SEPARATE_OFF { + filters = append(filters, &rwFilter{}) + f.rwInfo = newRwInfo() + } + } else if props != nil { + if ParseLogLevel(props) != LOG_OFF { + filters = append(filters, &logFilter{}) + f.logInfo = &logInfo{logRecord: new(LogRecord)} + runLog() + } + + if props.GetBool("statEnable", StatEnable) { + filters = append(filters, &statFilter{}) + f.statInfo = newStatInfo() + goStatMu.Lock() + if goStat == nil { + goStat = newGoStat(1000) + } + goStatMu.Unlock() + runStat() + } + + if props.GetInt(DoSwitchKey, int(DO_SWITCH_OFF), 0, 2) != int(DO_SWITCH_OFF) { + filters = append(filters, &reconnectFilter{}) + f.recoverInfo = newRecoverInfo() + } + + if props.GetBool("rwSeparate", false) { + filters = append(filters, &rwFilter{}) + f.rwInfo = newRwInfo() + } + } + + f.filterChain = newFilterChain(filters) +} + +func (f *filterable) resetFilterable(src *filterable) { + f.filterChain = src.filterChain + f.logInfo = src.logInfo + f.rwInfo = src.rwInfo + f.statInfo = src.statInfo +} + +func (f *filterable) getID() int64 { + if f.objId < 0 { + f.objId = f.idGenerator.incrementAndGet() + } + return f.objId +} + +type logInfo struct { + logRecord *LogRecord + lastExecuteStartNano time.Time +} + +type rwInfo struct { + distribute RWSiteEnum + + rwCounter *rwCounter + + connStandby *DmConnection + + connCurrent *DmConnection + + tryRecoverTs int64 + + stmtStandby *DmStatement + + stmtCurrent *DmStatement + + readOnly bool +} + +func newRwInfo() *rwInfo { + rwInfo := new(rwInfo) + rwInfo.distribute = PRIMARY + rwInfo.readOnly = true + return rwInfo +} + +func (rwi *rwInfo) cleanup() { + rwi.distribute = PRIMARY + rwi.rwCounter = nil + rwi.connStandby = nil + rwi.connCurrent = nil + rwi.stmtStandby = nil + rwi.stmtCurrent = nil +} + +func (rwi *rwInfo) toPrimary() RWSiteEnum { + if rwi.distribute != PRIMARY { + + rwi.rwCounter.countPrimary() + } + rwi.distribute = PRIMARY + return rwi.distribute +} + +func (rwi *rwInfo) toAny() RWSiteEnum { + + rwi.distribute = rwi.rwCounter.count(ANYSITE, rwi.connStandby) + return rwi.distribute +} + +type recoverInfo struct { + checkEpRecoverTs int64 +} + +func newRecoverInfo() *recoverInfo { + recoverInfo := new(recoverInfo) + recoverInfo.checkEpRecoverTs = 0 + return recoverInfo +} + +type statInfo struct { + constructNano int64 + + connStat *connectionStat + + lastExecuteStartNano int64 + + lastExecuteTimeNano int64 + + lastExecuteType ExecuteTypeEnum + + firstResultSet bool + + lastExecuteSql string + + sqlStat *sqlStat + + sql string + + cursorIndex int + + closeCount int + + readStringLength int64 + + readBytesLength int64 + + openInputStreamCount int + + openReaderCount int +} + +var ( + goStatMu sync.RWMutex + goStat *GoStat +) + +func newStatInfo() *statInfo { + si := new(statInfo) + return si +} +func (si *statInfo) init(conn *DmConnection) { + si.connStat = goStat.createConnStat(conn) +} + +func (si *statInfo) setConstructNano() { + si.constructNano = time.Now().UnixNano() +} + +func (si *statInfo) getConstructNano() int64 { + return si.constructNano +} + +func (si *statInfo) getConnStat() *connectionStat { + return si.connStat +} + +func (si *statInfo) getLastExecuteStartNano() int64 { + return si.lastExecuteStartNano +} + +func (si *statInfo) setLastExecuteStartNano(lastExecuteStartNano int64) { + si.lastExecuteStartNano = lastExecuteStartNano +} + +func (si *statInfo) getLastExecuteTimeNano() int64 { + return si.lastExecuteTimeNano +} + +func (si *statInfo) setLastExecuteTimeNano(lastExecuteTimeNano int64) { + si.lastExecuteTimeNano = lastExecuteTimeNano +} + +func (si *statInfo) getLastExecuteType() ExecuteTypeEnum { + return si.lastExecuteType +} + +func (si *statInfo) setLastExecuteType(lastExecuteType ExecuteTypeEnum) { + si.lastExecuteType = lastExecuteType +} + +func (si *statInfo) isFirstResultSet() bool { + return si.firstResultSet +} + +func (si *statInfo) setFirstResultSet(firstResultSet bool) { + si.firstResultSet = firstResultSet +} + +func (si *statInfo) getLastExecuteSql() string { + return si.lastExecuteSql +} + +func (si *statInfo) setLastExecuteSql(lastExecuteSql string) { + si.lastExecuteSql = lastExecuteSql +} + +func (si *statInfo) getSqlStat() *sqlStat { + return si.sqlStat +} + +func (si *statInfo) setSqlStat(sqlStat *sqlStat) { + si.sqlStat = sqlStat +} + +func (si *statInfo) setConnStat(connStat *connectionStat) { + si.connStat = connStat +} + +func (si *statInfo) setConstructNanoWithConstructNano(constructNano int64) { + si.constructNano = constructNano +} + +func (si *statInfo) afterExecute(nanoSpan int64) { + si.lastExecuteTimeNano = nanoSpan +} + +func (si *statInfo) beforeExecute() { + si.lastExecuteStartNano = time.Now().UnixNano() +} + +func (si *statInfo) getSql() string { + return si.sql +} + +func (si *statInfo) setSql(sql string) { + si.sql = sql +} + +func (si *statInfo) getCursorIndex() int { + return si.cursorIndex +} + +func (si *statInfo) setCursorIndex(cursorIndex int) { + si.cursorIndex = cursorIndex +} + +func (si *statInfo) getCloseCount() int { + return si.closeCount +} + +func (si *statInfo) setCloseCount(closeCount int) { + si.closeCount = closeCount +} + +func (si *statInfo) getReadStringLength() int64 { + return si.readStringLength +} + +func (si *statInfo) setReadStringLength(readStringLength int64) { + si.readStringLength = readStringLength +} + +func (si *statInfo) getReadBytesLength() int64 { + return si.readBytesLength +} + +func (si *statInfo) setReadBytesLength(readBytesLength int64) { + si.readBytesLength = readBytesLength +} + +func (si *statInfo) getOpenInputStreamCount() int { + return si.openInputStreamCount +} + +func (si *statInfo) setOpenInputStreamCount(openInputStreamCount int) { + si.openInputStreamCount = openInputStreamCount +} + +func (si *statInfo) getOpenReaderCount() int { + return si.openReaderCount +} + +func (si *statInfo) setOpenReaderCount(openReaderCount int) { + si.openReaderCount = openReaderCount +} + +func (si *statInfo) incrementCloseCount() { + si.closeCount++ +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zd.go b/dpi_bridge/third_party/chunanyong_dm/zd.go new file mode 100644 index 0000000..2cf414c --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zd.go @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "context" + "database/sql/driver" + "reflect" +) + +type filterChain struct { + filters []filter + fpos int +} + +func newFilterChain(filters []filter) *filterChain { + fc := new(filterChain) + fc.filters = filters + fc.fpos = 0 + return fc +} + +func (filterChain *filterChain) reset() *filterChain { + filterChain.fpos = 0 + return filterChain +} + +func (filterChain *filterChain) DmDriverOpen(d *DmDriver, dsn string) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmDriverOpen(filterChain, d, dsn) + } + + return d.open(dsn) +} + +func (filterChain *filterChain) DmDriverOpenConnector(d *DmDriver, dsn string) (*DmConnector, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmDriverOpenConnector(filterChain, d, dsn) + } + + return d.openConnector(dsn) +} + +//DmConnector +func (filterChain *filterChain) DmConnectorConnect(c *DmConnector, ctx context.Context) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectorConnect(filterChain, c, ctx) + } + + return c.connect(ctx) +} + +func (filterChain *filterChain) DmConnectorDriver(c *DmConnector) *DmDriver { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectorDriver(filterChain, c) + } + + return c.driver() +} + +//DmConnection +func (filterChain *filterChain) DmConnectionBegin(c *DmConnection) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionBegin(filterChain, c) + } + + return c.begin() +} +func (filterChain *filterChain) DmConnectionBeginTx(c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionBeginTx(filterChain, c, ctx, opts) + } + + return c.beginTx(ctx, opts) +} + +func (filterChain *filterChain) DmConnectionCommit(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionCommit(filterChain, c) + } + + return c.commit() +} + +func (filterChain *filterChain) DmConnectionRollback(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionRollback(filterChain, c) + } + + return c.rollback() +} + +func (filterChain *filterChain) DmConnectionClose(c *DmConnection) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionClose(filterChain, c) + } + + return c.close() +} + +func (filterChain *filterChain) DmConnectionPing(c *DmConnection, ctx context.Context) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPing(filterChain, c, ctx) + } + + return c.ping(ctx) +} + +func (filterChain *filterChain) DmConnectionExec(c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionExec(filterChain, c, query, args) + } + + return c.exec(query, args) +} + +func (filterChain *filterChain) DmConnectionExecContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionExecContext(filterChain, c, ctx, query, args) + } + + return c.execContext(ctx, query, args) +} + +func (filterChain *filterChain) DmConnectionQuery(c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionQuery(filterChain, c, query, args) + } + + return c.query(query, args) +} + +func (filterChain *filterChain) DmConnectionQueryContext(c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionQueryContext(filterChain, c, ctx, query, args) + } + + return c.queryContext(ctx, query, args) +} + +func (filterChain *filterChain) DmConnectionPrepare(c *DmConnection, query string) (*DmStatement, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPrepare(filterChain, c, query) + } + + return c.prepare(query) +} + +func (filterChain *filterChain) DmConnectionPrepareContext(c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionPrepareContext(filterChain, c, ctx, query) + } + + return c.prepareContext(ctx, query) +} + +func (filterChain *filterChain) DmConnectionResetSession(c *DmConnection, ctx context.Context) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionResetSession(filterChain, c, ctx) + } + + return c.resetSession(ctx) +} + +func (filterChain *filterChain) DmConnectionCheckNamedValue(c *DmConnection, nv *driver.NamedValue) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmConnectionCheckNamedValue(filterChain, c, nv) + } + + return c.checkNamedValue(nv) +} + +//DmStatement +func (filterChain *filterChain) DmStatementClose(s *DmStatement) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementClose(filterChain, s) + } + + return s.close() +} + +func (filterChain *filterChain) DmStatementNumInput(s *DmStatement) int { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementNumInput(filterChain, s) + } + + return s.numInput() +} + +func (filterChain *filterChain) DmStatementExec(s *DmStatement, args []driver.Value) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementExec(filterChain, s, args) + } + + return s.exec(args) +} + +func (filterChain *filterChain) DmStatementExecContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementExecContext(filterChain, s, ctx, args) + } + + return s.execContext(ctx, args) +} + +func (filterChain *filterChain) DmStatementQuery(s *DmStatement, args []driver.Value) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementQuery(filterChain, s, args) + } + + return s.query(args) +} + +func (filterChain *filterChain) DmStatementQueryContext(s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementQueryContext(filterChain, s, ctx, args) + } + + return s.queryContext(ctx, args) +} + +func (filterChain *filterChain) DmStatementCheckNamedValue(s *DmStatement, nv *driver.NamedValue) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmStatementCheckNamedValue(filterChain, s, nv) + } + + return s.checkNamedValue(nv) +} + +//DmResult +func (filterChain *filterChain) DmResultLastInsertId(r *DmResult) (int64, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmResultLastInsertId(filterChain, r) + } + + return r.lastInsertId() +} + +func (filterChain *filterChain) DmResultRowsAffected(r *DmResult) (int64, error) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmResultRowsAffected(filterChain, r) + } + + return r.rowsAffected() +} + +//DmRows +func (filterChain *filterChain) DmRowsColumns(r *DmRows) []string { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumns(filterChain, r) + } + + return r.columns() +} + +func (filterChain *filterChain) DmRowsClose(r *DmRows) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsClose(filterChain, r) + } + + return r.close() +} + +func (filterChain *filterChain) DmRowsNext(r *DmRows, dest []driver.Value) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsNext(filterChain, r, dest) + } + + return r.next(dest) +} + +func (filterChain *filterChain) DmRowsHasNextResultSet(r *DmRows) bool { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsHasNextResultSet(filterChain, r) + } + + return r.hasNextResultSet() +} + +func (filterChain *filterChain) DmRowsNextResultSet(r *DmRows) error { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsNextResultSet(filterChain, r) + } + + return r.nextResultSet() +} + +func (filterChain *filterChain) DmRowsColumnTypeScanType(r *DmRows, index int) reflect.Type { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeScanType(filterChain, r, index) + } + + return r.columnTypeScanType(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeDatabaseTypeName(r *DmRows, index int) string { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeDatabaseTypeName(filterChain, r, index) + } + + return r.columnTypeDatabaseTypeName(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeLength(r *DmRows, index int) (length int64, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeLength(filterChain, r, index) + } + + return r.columnTypeLength(index) +} + +func (filterChain *filterChain) DmRowsColumnTypeNullable(r *DmRows, index int) (nullable, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypeNullable(filterChain, r, index) + } + + return r.columnTypeNullable(index) +} + +func (filterChain *filterChain) DmRowsColumnTypePrecisionScale(r *DmRows, index int) (precision, scale int64, ok bool) { + if filterChain.fpos < len(filterChain.filters) { + f := filterChain.filters[filterChain.fpos] + filterChain.fpos++ + return f.DmRowsColumnTypePrecisionScale(filterChain, r, index) + } + + return r.columnTypePrecisionScale(index) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/ze.go b/dpi_bridge/third_party/chunanyong_dm/ze.go new file mode 100644 index 0000000..bc5a528 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/ze.go @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "context" + "database/sql/driver" + "fmt" + "io" + "reflect" + "strconv" + "time" + + "gitee.com/chunanyong/dm/util" +) + +type logFilter struct{} + +func (filter *logFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnection, err error) { + var logRecord = d.logInfo.logRecord.Reset() + logRecord.Set(d, "open", dsn) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmDriverOpen(d, dsn) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (ret *DmConnector, err error) { + var logRecord = d.logInfo.logRecord.Reset() + logRecord.Set(d, "openConnector", dsn) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmDriverOpenConnector(d, dsn) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "connect") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectorConnect(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) (ret *DmDriver) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "driver") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmConnectorDriver(c) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "begin") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectionBegin(c) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (ret *DmConnection, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "beginTx", opts) + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmConnectionBeginTx(c, ctx, opts) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "commit") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionCommit(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "rollback") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionRollback(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionClose(c) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "ping") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionPing(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmResult, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "exec", convertParams2(args)...) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query, true) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionExec(c, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmResult, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "execCtx", convertParams1(args)...) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query, true) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (ret *DmRows, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "query", convertParams2(args)...) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query, true) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionQuery(c, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (ret *DmRows, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "queryCtx", convertParams1(args)...) + defer func() { + filter.executeAfter(c.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(query, true) + filter.executeBefore(c.logInfo) + ret, err = filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (ret *DmStatement, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "prepare", query) + defer func() { + filter.doLog(logRecord) + }() + logRecord.SetSql(query, false) + ret, err = filterChain.DmConnectionPrepare(c, query) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (ret *DmStatement, err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "prepareCtx", query) + defer func() { + filter.doLog(logRecord) + }() + logRecord.SetSql(query, false) + ret, err = filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "resetSession") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionResetSession(c, ctx) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) (err error) { + var logRecord = c.logInfo.logRecord.Reset() + logRecord.Set(c, "checkNamedValue", nv.Value) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmConnectionCheckNamedValue(c, nv) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) (err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmStatementClose(s) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) (ret int) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "numInput") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmStatementNumInput(s) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmResult, err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "exec", convertParams2(args)...) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql, true) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementExec(s, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmResult, err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "execCtx", convertParams1(args)...) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql, true) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (ret *DmRows, err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "query", convertParams2(args)...) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql, true) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementQuery(s, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (ret *DmRows, err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "queryCtx", convertParams1(args)...) + defer func() { + filter.executeAfter(s.logInfo, logRecord) + filter.doLog(logRecord) + }() + logRecord.SetSql(s.nativeSql, true) + filter.executeBefore(s.logInfo) + ret, err = filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) (err error) { + var logRecord = s.logInfo.logRecord.Reset() + logRecord.Set(s, "checkNamedValue", nv.Value) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmStatementCheckNamedValue(s, nv) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (ret int64, err error) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "lastInsertId") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmResultLastInsertId(r) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (ret int64, err error) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "rowsAffected") + defer func() { + filter.doLog(logRecord) + }() + ret, err = filterChain.DmResultRowsAffected(r) + if err != nil { + logRecord.SetError(err) + return + } + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) (ret []string) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columns") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumns(r) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsClose(filterChain *filterChain, r *DmRows) (err error) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "close") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsClose(r) + if err != nil { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) (err error) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "next", convertParams2(dest)...) + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsNext(r, dest) + if err != nil && err != io.EOF { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) (ret bool) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "hasNextResultSet") + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsHasNextResultSet(r) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) (err error) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "nextResultSet") + defer func() { + filter.doLog(logRecord) + }() + err = filterChain.DmRowsNextResultSet(r) + if err != nil && err != io.EOF { + logRecord.SetError(err) + return + } + return +} + +func (filter *logFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) (ret reflect.Type) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columnTypeScanType", index) + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumnTypeScanType(r, index) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) (ret string) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columnTypeDatabaseTypeName", index) + defer func() { + filter.doLog(logRecord) + }() + ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) + logRecord.SetReturnValue(ret) + return +} + +func (filter *logFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columnTypeLength", index) + defer func() { + filter.doLog(logRecord) + }() + length, ok = filterChain.DmRowsColumnTypeLength(r, index) + if ok { + logRecord.SetReturnValue(length) + } else { + logRecord.SetReturnValue(-1) + } + return +} + +func (filter *logFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columnTypeNullable", index) + defer func() { + filter.doLog(logRecord) + }() + nullable, ok = filterChain.DmRowsColumnTypeNullable(r, index) + if ok { + logRecord.SetReturnValue(nullable) + } else { + logRecord.SetReturnValue(false) + } + return +} + +func (filter *logFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + var logRecord = r.logInfo.logRecord.Reset() + logRecord.Set(r, "columnTypePrecisionScale", index) + defer func() { + filter.doLog(logRecord) + }() + precision, scale, ok = filterChain.DmRowsColumnTypePrecisionScale(r, index) + if ok { + logRecord.SetReturnValue(strconv.FormatInt(precision, 10) + "&" + strconv.FormatInt(scale, 10)) + } else { + logRecord.SetReturnValue("-1&-1") + } + return +} + +func (filter *logFilter) executeBefore(logInfo *logInfo) { + if LogFilterLogger.IsSqlEnabled() { + logInfo.lastExecuteStartNano = time.Now() + } +} + +func (filter *logFilter) executeAfter(logInfo *logInfo, record *LogRecord) { + if LogFilterLogger.IsSqlEnabled() { + record.SetUsedTime(time.Since(logInfo.lastExecuteStartNano)) + } +} + +func (filter *logFilter) doLog(record *LogRecord) { + + if record == nil { + return + } + if record.GetError() != nil { + LogFilterLogger.ErrorWithErr(record.ToString(), record.GetError()) + } else if record.GetSql() != "" && LogFilterLogger.IsSqlEnabled() { + LogFilterLogger.Sql(record.ToString()) + } else { + LogFilterLogger.Info(record.ToString()) + } +} + +/************************************************************************************************************/ +type Logger struct { +} + +var LogFilterLogger = &Logger{} +var ConnLogger = &Logger{} +var AccessLogger = &Logger{} + +func (logger Logger) IsDebugEnabled() bool { + return LogLevel >= LOG_DEBUG +} +func (logger Logger) IsErrorEnabled() bool { + return LogLevel >= LOG_ERROR +} +func (logger Logger) IsInfoEnabled() bool { + return LogLevel >= LOG_INFO +} +func (logger Logger) IsWarnEnabled() bool { + return LogLevel >= LOG_WARN +} +func (logger Logger) IsSqlEnabled() bool { + return LogLevel >= LOG_SQL +} +func (logger Logger) Debug(msg string) { + if logger.IsDebugEnabled() { + logger.println(logger.formatHead("DEBUG") + msg) + } +} +func (logger Logger) DebugWithErr(msg string, err error) { + if logger.IsDebugEnabled() { + if e, ok := err.(*DmError); ok { + logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + e.Stack()) + } else { + logger.println(logger.formatHead("DEBUG") + msg + util.LINE_SEPARATOR + err.Error()) + } + } +} +func (logger Logger) Info(msg string) { + if logger.IsInfoEnabled() { + logger.println(logger.formatHead("INFO ") + msg) + } +} +func (logger Logger) Sql(msg string) { + if logger.IsSqlEnabled() { + logger.println(logger.formatHead("SQL ") + msg) + } +} +func (logger Logger) Warn(msg string) { + if logger.IsWarnEnabled() { + logger.println(logger.formatHead("WARN ") + msg) + } +} +func (logger Logger) ErrorWithErr(msg string, err error) { + //if e, ok := err.(*DmError); ok { + // logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + e.Stack()) + //} else { + logger.println(logger.formatHead("ERROR") + msg + util.LINE_SEPARATOR + err.Error()) + //} +} + +// TODO: 获取goroutine objId +func (logger Logger) formatHead(head string) string { + // return "[" + head + " - " + StringUtil.formatTime() + "] tid:" + Thread.currentThread().getId(); + return "[" + head + " - " + util.StringUtil.FormatTime() + "]" +} +func (logger Logger) println(msg string) { + goMap["log"].(*logWriter).WriteLine(msg) +} + +/*************************************************************************************************/ +func formatSource(source interface{}) string { + if source == nil { + return "" + } + var str string + switch src := source.(type) { + case string: + str += src + case *DmDriver: + str += formatDriver(src) + case *DmConnector: + str += formatContor(src) + case *DmConnection: + str += formatConn(src) + case *DmStatement: + str += formatConn(src.dmConn) + ", " + str += formatStmt(src) + case *DmResult: + str += formatConn(src.dmStmt.dmConn) + ", " + str += formatStmt(src.dmStmt) + ", " + str += formatRs(src) + case *DmRows: + str += formatConn(src.CurrentRows.dmStmt.dmConn) + ", " + str += formatStmt(src.CurrentRows.dmStmt) + ", " + str += formatRows(src) + default: + str += reflect.TypeOf(src).String() + "@" + reflect.ValueOf(src).Addr().String() + } + return str +} + +func formatDriver(driver *DmDriver) string { + if driver != nil && driver.logInfo != nil { + return "driver-" + strconv.FormatInt(driver.getID(), 10) + } + return "driver-nil" +} + +func formatContor(contor *DmConnector) string { + if contor != nil && contor.logInfo != nil { + return "contor-" + strconv.FormatInt(contor.getID(), 10) + } + return "contor-nil" +} + +func formatConn(conn *DmConnection) string { + if conn != nil && conn.logInfo != nil { + return "conn-0x" + strconv.FormatInt(conn.SessionID, 16) + } + return "conn-nil" +} + +func formatStmt(stmt *DmStatement) string { + if stmt != nil && stmt.logInfo != nil { + return "stmt-" + strconv.Itoa(int(stmt.id)) + } + return "stmt-nil" +} + +func formatRs(result *DmResult) string { + if result != nil && result.logInfo != nil { + return "rs-" + strconv.FormatInt(result.getID(), 10) + } + return "rs-nil" +} + +func formatRows(rows *DmRows) string { + if rows != nil && rows.logInfo != nil { + return "rows-" + strconv.FormatInt(rows.getID(), 10) + } + return "rows-nil" +} + +func formatTrace(source string, sql string, method string, returnValue interface{}, params ...interface{}) string { + var str string + if source != "" { + str += "{ " + source + " } " + } + str += method + "(" + var paramStartIndex = 0 + if params != nil && len(params) > paramStartIndex { + for i := paramStartIndex; i < len(params); i++ { + if i != paramStartIndex { + str += ", " + } + if params[i] != nil { + str += reflect.TypeOf(params[i]).String() + } else { + str += "nil" + } + } + } + str += ")" + if returnValue != nil { + str += ": " + formatReturn(returnValue) + } + str += "; " + if params != nil && len(params) > paramStartIndex { + str += "[PARAMS]: " + for i := paramStartIndex; i < len(params); i++ { + if i != 0 { + str += ", " + } + //if s, ok := params[i].(driver.NamedValue); ok { + // str += fmt.Sprintf("%v", s.Value) + //} else { + str += fmt.Sprintf("%v", params[i]) + //} + } + str += "; " + } + + if sql != "" { + str += "[SQL]: " + sql + "; " + } + + return str +} + +func formatReturn(returnObj interface{}) string { + var str string + switch o := returnObj.(type) { + case *DmConnection: + str = formatConn(o) + case *DmStatement: + str = formatStmt(o) + case *DmResult: + str = formatRs(o) + case *DmRows: + str = formatRows(o) + case string: + str = `"` + o + `"` + case nullData: + str = "nil" + default: + str = "unknown" + } + return str +} + +func formatUsedTime(duration time.Duration) string { + return "[USED TIME]: " + duration.String() +} + +/************************************************************************************************************/ + +type nullData struct{} + +var null = nullData{} + +type LogRecord struct { + source string + method string + params []interface{} + returnValue interface{} + e error + usedTime time.Duration + sql string + logSql bool // 是否需要记录sql(exec,query等需要在日志中记录sql语句) +} + +func (record *LogRecord) Reset() *LogRecord { + record.source = "" + record.method = "" + record.params = nil + record.returnValue = nil + record.e = nil + record.usedTime = 0 + record.sql = "" + record.logSql = false + return record +} + +func (record *LogRecord) Set(source interface{}, method string, params ...interface{}) { + record.source = formatSource(source) + record.method = method + record.params = params +} + +func (record *LogRecord) SetReturnValue(retValue interface{}) { + if retValue == nil { + record.returnValue = null + } else { + record.returnValue = retValue + } +} + +func (record *LogRecord) GetReturnValue() interface{} { + return record.returnValue +} + +func (record *LogRecord) SetSql(sql string, logSql bool) { + record.sql = sql + record.logSql = logSql +} + +func (record *LogRecord) GetSql() string { + return record.sql +} + +func (record *LogRecord) SetUsedTime(usedTime time.Duration) { + record.usedTime = usedTime +} + +func (record *LogRecord) GetUsedTime() time.Duration { + return record.usedTime +} + +func (record *LogRecord) SetError(err error) { + record.e = err +} + +func (record *LogRecord) GetError() error { + return record.e +} + +func (record *LogRecord) ToString() string { + var sql string + if record.logSql && record.sql != "" { + sql = record.sql + } + var str string + str += formatTrace(record.source, sql, record.method, record.returnValue, record.params...) + if record.usedTime > 0 { + str += formatUsedTime(record.usedTime) + } + return str +} + +func convertParams1(args []driver.NamedValue) []interface{} { + tmp := make([]interface{}, len(args)) + for i := 0; i < len(tmp); i++ { + tmp[i] = args[i].Value + } + return tmp +} + +func convertParams2(args []driver.Value) []interface{} { + tmp := make([]interface{}, len(args)) + for i := 0; i < len(tmp); i++ { + tmp[i] = args[i] + } + return tmp +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zf.go b/dpi_bridge/third_party/chunanyong_dm/zf.go new file mode 100644 index 0000000..638ca2f --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zf.go @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "context" + "database/sql/driver" + "io" + "reflect" + "time" + + "gitee.com/chunanyong/dm/util" +) + +const SQL_GET_DSC_EP_SITE = "SELECT " + + "dsc.ep_seqno, " + + "(CASE mal.MAL_INST_HOST WHEN '' THEN mal.MAL_HOST ELSE mal.MAL_INST_HOST END) as ep_host, " + + "dcr.EP_PORT, " + + "dsc.EP_STATUS " + + "FROM V$DSC_EP_INFO dsc " + + "LEFT join V$DM_MAL_INI mal " + + "on dsc.EP_NAME = mal.MAL_INST_NAME " + + "LEFT join (SELECT grp.GROUP_TYPE GROUP_TYPE, ep.* FROM SYS.\"V$DCR_GROUP\" grp, SYS.\"V$DCR_EP\" ep where grp.GROUP_NAME = ep.GROUP_NAME) dcr " + + "on dsc.EP_NAME = dcr.EP_NAME and GROUP_TYPE = 'DB' order by dsc.ep_seqno asc;" + +type reconnectFilter struct { +} + +// 一定抛错 +func (rf *reconnectFilter) autoReconnect(connection *DmConnection, err error) error { + if dmErr, ok := err.(*DmError); ok { + if dmErr.ErrCode == ECGO_COMMUNITION_ERROR.ErrCode || dmErr.ErrCode == ECGO_CONNECTION_CLOSED.ErrCode { + + if connection.dmConnector.driverReconnect { + return rf.reconnect(connection, dmErr.getErrText()) + } else { + connection.Access.Close() + connection.closed.Set(true) + return driver.ErrBadConn + } + } + } + return err +} + +// 一定抛错 +func (rf *reconnectFilter) reconnect(connection *DmConnection, reason string) error { + // 读写分离,重连需要处理备机 + var err error + if connection.dmConnector.rwSeparate > RW_SEPARATE_OFF { + err = RWUtil.reconnect(connection) + } else { + err = connection.reconnect() + } + + if err != nil { + connection.closed.Set(true) + return ECGO_CONNECTION_SWITCH_FAILED.addDetailln(reason).throw() + } + + // 重连成功 + connection.closed.Set(false) + return ECGO_CONNECTION_SWITCHED.addDetailln(reason).throw() +} + +func (rf *reconnectFilter) loadDscEpSites(conn *DmConnection) []*ep { + stmt, rs, err := conn.driverQuery(SQL_GET_DSC_EP_SITE) + if err != nil { + return nil + } + defer func() { + rs.close() + stmt.close() + }() + epList := make([]*ep, 0) + dest := make([]driver.Value, 4) + for err = rs.next(dest); err != io.EOF; err = rs.next(dest) { + ep := newEP(dest[1].(string), dest[2].(int32)) + ep.epSeqno = dest[0].(int32) + if util.StringUtil.EqualsIgnoreCase(dest[3].(string), "OK") { + ep.epStatus = EP_STATUS_OK + } else { + ep.epStatus = EP_STATUS_ERROR + } + epList = append(epList, ep) + } + return epList +} + +func (rf *reconnectFilter) checkAndRecover(conn *DmConnection) error { + if conn.dmConnector.doSwitch != DO_SWITCH_WHEN_EP_RECOVER { + return nil + } + // check trx finish + if !conn.trxFinish { + return nil + } + var curIndex = conn.getIndexOnEPGroup() + if curIndex == 0 || (time.Now().UnixNano()/1000000-conn.recoverInfo.checkEpRecoverTs) < int64(conn.dmConnector.switchInterval) { + return nil + } + // check db recover + var dscEps []*ep + if conn.dmConnector.cluster == CLUSTER_TYPE_DSC { + dscEps = rf.loadDscEpSites(conn) + } + if dscEps == nil || len(dscEps) == 0 { + return nil + } + var recover = false + for _, okEp := range dscEps { + if okEp.epStatus != EP_STATUS_OK { + continue + } + for i := int32(0); i < curIndex; i++ { + ep := conn.dmConnector.group.epList[i] + if okEp.host == ep.host && okEp.port == ep.port { + recover = true + break + } + } + if recover { + break + } + } + + conn.recoverInfo.checkEpRecoverTs = time.Now().UnixNano() / 1000000 + if !recover { + return nil + } + + if conn.dmConnector.driverReconnect { + return conn.reconnect() + } else { + conn.Access.Close() + conn.closed.Set(false) + return ECGO_CONNECTION_CLOSED.throw() + } + + //return driver.ErrBadConn + // do reconnect + //return conn.reconnect() +} + +// DmDriver +func (rf *reconnectFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + return filterChain.DmDriverOpen(d, dsn) +} + +func (rf *reconnectFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +// DmConnector +func (rf *reconnectFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + return filterChain.DmConnectorConnect(c, ctx) +} + +func (rf *reconnectFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +// DmConnection +func (rf *reconnectFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + dc, err := filterChain.DmConnectionBegin(c) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + return dc, err +} + +func (rf *reconnectFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + dc, err := filterChain.DmConnectionBeginTx(c, ctx, opts) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + return dc, err +} + +func (rf *reconnectFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + if err := filterChain.DmConnectionCommit(c); err != nil { + return rf.autoReconnect(c, err) + } + if err := rf.checkAndRecover(c); err != nil { + return rf.autoReconnect(c, err) + } + return nil +} + +func (rf *reconnectFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionRollback(c) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionClose(c) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + err := filterChain.DmConnectionPing(c, ctx) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionExec(c, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionQuery(c, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + if err := rf.checkAndRecover(c); err != nil { + return nil, rf.autoReconnect(c, err) + } + dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + ds, err := filterChain.DmConnectionPrepare(c, query) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return ds, err +} + +func (rf *reconnectFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + ds, err := filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + return nil, rf.autoReconnect(c, err) + } + + return ds, err +} + +func (rf *reconnectFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + err := filterChain.DmConnectionResetSession(c, ctx) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +func (rf *reconnectFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + err := filterChain.DmConnectionCheckNamedValue(c, nv) + if err != nil { + err = rf.autoReconnect(c, err) + } + + return err +} + +// DmStatement +func (rf *reconnectFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + err := filterChain.DmStatementClose(s) + if err != nil { + err = rf.autoReconnect(s.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + var ret int + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(s.dmConn, err.(error)) + ret = 0 + } + }() + ret = filterChain.DmStatementNumInput(s) + return ret +} + +func (rf *reconnectFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementExec(s, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementQuery(s, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + if err := rf.checkAndRecover(s.dmConn); err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + dr, err := filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + return nil, rf.autoReconnect(s.dmConn, err) + } + + return dr, err +} + +func (rf *reconnectFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + err := filterChain.DmStatementCheckNamedValue(s, nv) + if err != nil { + err = rf.autoReconnect(s.dmConn, err) + } + + return err +} + +// DmResult +func (rf *reconnectFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + i, err := filterChain.DmResultLastInsertId(r) + if err != nil { + err = rf.autoReconnect(r.dmStmt.dmConn, err) + return 0, err + } + + return i, err +} + +func (rf *reconnectFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + i, err := filterChain.DmResultRowsAffected(r) + if err != nil { + err = rf.autoReconnect(r.dmStmt.dmConn, err) + return 0, err + } + + return i, err +} + +// DmRows +func (rf *reconnectFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + var ret []string + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = nil + } + }() + ret = filterChain.DmRowsColumns(r) + return ret +} + +func (rf *reconnectFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + err := filterChain.DmRowsClose(r) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + err := filterChain.DmRowsNext(r, dest) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + var ret bool + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = false + } + }() + ret = filterChain.DmRowsHasNextResultSet(r) + return ret +} + +func (rf *reconnectFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + err := filterChain.DmRowsNextResultSet(r) + if err != nil { + err = rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err) + } + + return err +} + +func (rf *reconnectFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + var ret reflect.Type + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = scanTypeUnknown + } + }() + ret = filterChain.DmRowsColumnTypeScanType(r, index) + return ret +} + +func (rf *reconnectFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + var ret string + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + ret = "" + } + }() + ret = filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) + return ret +} + +func (rf *reconnectFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + length, ok = 0, false + } + }() + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (rf *reconnectFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + nullable, ok = false, false + } + }() + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (rf *reconnectFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + defer func() { + err := recover() + if err != nil { + rf.autoReconnect(r.CurrentRows.dmStmt.dmConn, err.(error)) + precision, scale, ok = 0, 0, false + } + }() + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zg.go b/dpi_bridge/third_party/chunanyong_dm/zg.go new file mode 100644 index 0000000..79efa21 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zg.go @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "context" + "database/sql/driver" + "reflect" +) + +type rwFilter struct { +} + +//DmDriver +func (rwf *rwFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + return filterChain.DmDriverOpen(d, dsn) +} + +func (rwf *rwFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +//DmConnector +func (rwf *rwFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + return RWUtil.connect(c, ctx) +} + +func (rwf *rwFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +//DmConnection +func (rwf *rwFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + if RWUtil.isStandbyAlive(c) { + _, err := c.rwInfo.connStandby.begin() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionBegin(c) +} + +func (rwf *rwFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + if RWUtil.isStandbyAlive(c) { + _, err := c.rwInfo.connStandby.beginTx(ctx, opts) + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionBeginTx(c, ctx, opts) +} + +func (rwf *rwFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.commit() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionCommit(c) +} + +func (rwf *rwFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.rollback() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionRollback(c) +} + +func (rwf *rwFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.close() + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionClose(c) +} + +func (rwf *rwFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return filterChain.DmConnectionPing(c, ctx) +} + +func (rwf *rwFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.exec(query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.exec(query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.execContext(ctx, query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.execContext(ctx, query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.query(query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.query(query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + ret, err := RWUtil.executeByConn(c, query, func() (interface{}, error) { + return c.rwInfo.connCurrent.queryContext(ctx, query, args) + }, func(otherConn *DmConnection) (interface{}, error) { + return otherConn.queryContext(ctx, query, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + stmt, err := c.prepare(query) + if err != nil { + return nil, err + } + stmt.rwInfo.stmtCurrent = stmt + stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt) + if RWUtil.isCreateStandbyStmt(stmt) { + stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepare(query) + if err == nil { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } else { + RWUtil.afterExceptionOnStandby(c, err) + } + } + return stmt, nil +} + +func (rwf *rwFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + stmt, err := c.prepareContext(ctx, query) + if err != nil { + return nil, err + } + stmt.rwInfo.stmtCurrent = stmt + stmt.rwInfo.readOnly = RWUtil.checkReadonlyByStmt(stmt) + if RWUtil.isCreateStandbyStmt(stmt) { + stmt.rwInfo.stmtStandby, err = c.rwInfo.connStandby.prepareContext(ctx, query) + if err == nil { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } else { + RWUtil.afterExceptionOnStandby(c, err) + } + } + return stmt, nil +} + +func (rwf *rwFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + if RWUtil.isStandbyAlive(c) { + err := c.rwInfo.connStandby.resetSession(ctx) + if err != nil { + RWUtil.afterExceptionOnStandby(c, err) + } + } + + return filterChain.DmConnectionResetSession(c, ctx) +} + +func (rwf *rwFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + return filterChain.DmConnectionCheckNamedValue(c, nv) +} + +//DmStatement +func (rwf *rwFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + if RWUtil.isStandbyStatementValid(s) { + err := s.rwInfo.stmtStandby.close() + if err != nil { + RWUtil.afterExceptionOnStandby(s.dmConn, err) + } + } + + return filterChain.DmStatementClose(s) +} + +func (rwf *rwFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + return filterChain.DmStatementNumInput(s) +} + +func (rwf *rwFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.exec(args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.exec(args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.execContext(ctx, args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.execContext(ctx, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmResult), nil +} + +func (rwf *rwFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.query(args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.query(args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + ret, err := RWUtil.executeByStmt(s, func() (interface{}, error) { + return s.rwInfo.stmtCurrent.queryContext(ctx, args) + }, func(otherStmt *DmStatement) (interface{}, error) { + return otherStmt.queryContext(ctx, args) + }) + if err != nil { + return nil, err + } + return ret.(*DmRows), nil +} + +func (rwf *rwFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + return filterChain.DmStatementCheckNamedValue(s, nv) +} + +//DmResult +func (rwf *rwFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultLastInsertId(r) +} + +func (rwf *rwFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultRowsAffected(r) +} + +//DmRows +func (rwf *rwFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + return filterChain.DmRowsColumns(r) +} + +func (rwf *rwFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsClose(r) +} + +func (rwf *rwFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + return filterChain.DmRowsNext(r, dest) +} + +func (rwf *rwFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + return filterChain.DmRowsHasNextResultSet(r) +} + +func (rwf *rwFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsNextResultSet(r) +} + +func (rwf *rwFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + return filterChain.DmRowsColumnTypeScanType(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (rwf *rwFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zh.go b/dpi_bridge/third_party/chunanyong_dm/zh.go new file mode 100644 index 0000000..cd74d70 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zh.go @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "bytes" + "context" + "database/sql/driver" + "fmt" + "reflect" + "time" +) + +type statFilter struct { +} + +//DmDriver +func (sf *statFilter) DmDriverOpen(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnection, error) { + conn, err := filterChain.DmDriverOpen(d, dsn) + if err != nil { + return nil, err + } + conn.statInfo.init(conn) + conn.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementConn() + return conn, nil +} + +func (sf *statFilter) DmDriverOpenConnector(filterChain *filterChain, d *DmDriver, dsn string) (*DmConnector, error) { + return filterChain.DmDriverOpenConnector(d, dsn) +} + +//DmConnector +func (sf *statFilter) DmConnectorConnect(filterChain *filterChain, c *DmConnector, ctx context.Context) (*DmConnection, error) { + conn, err := filterChain.DmConnectorConnect(c, ctx) + if err != nil { + return nil, err + } + conn.statInfo.init(conn) + conn.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementConn() + return conn, nil +} + +func (sf *statFilter) DmConnectorDriver(filterChain *filterChain, c *DmConnector) *DmDriver { + return filterChain.DmConnectorDriver(c) +} + +//DmConnection +func (sf *statFilter) DmConnectionBegin(filterChain *filterChain, c *DmConnection) (*DmConnection, error) { + return filterChain.DmConnectionBegin(c) +} + +func (sf *statFilter) DmConnectionBeginTx(filterChain *filterChain, c *DmConnection, ctx context.Context, opts driver.TxOptions) (*DmConnection, error) { + return filterChain.DmConnectionBeginTx(c, ctx, opts) +} + +func (sf *statFilter) DmConnectionCommit(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionCommit(c) + if err != nil { + return err + } + c.statInfo.getConnStat().incrementCommitCount() + return nil +} + +func (sf *statFilter) DmConnectionRollback(filterChain *filterChain, c *DmConnection) error { + err := filterChain.DmConnectionRollback(c) + if err != nil { + return err + } + c.statInfo.getConnStat().incrementRollbackCount() + return nil +} + +func (sf *statFilter) DmConnectionClose(filterChain *filterChain, c *DmConnection) error { + if !c.closed.IsSet() { + c.statInfo.getConnStat().decrementStmtByActiveStmtCount(int64(getActiveStmtCount(c))) + c.statInfo.getConnStat().decrementConn() + } + + return filterChain.DmConnectionClose(c) +} + +func (sf *statFilter) DmConnectionPing(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return c.ping(ctx) +} + +func (sf *statFilter) DmConnectionExec(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmResult, error) { + connExecBefore(c, query) + dr, err := filterChain.DmConnectionExec(c, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connExecAfter(c, query, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmConnectionExecContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmResult, error) { + connExecBefore(c, query) + dr, err := filterChain.DmConnectionExecContext(c, ctx, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connExecAfter(c, query, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmConnectionQuery(filterChain *filterChain, c *DmConnection, query string, args []driver.Value) (*DmRows, error) { + connQueryBefore(c, query) + dr, err := filterChain.DmConnectionQuery(c, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connQueryAfter(c, query, args, dr) + return dr, nil +} + +func (sf *statFilter) DmConnectionQueryContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string, args []driver.NamedValue) (*DmRows, error) { + connQueryBefore(c, query) + dr, err := filterChain.DmConnectionQueryContext(c, ctx, query, args) + if err != nil { + connExecuteErrorAfter(c, args, err) + return nil, err + } + connQueryAfter(c, query, args, dr) + return dr, nil +} + +func (sf *statFilter) DmConnectionPrepare(filterChain *filterChain, c *DmConnection, query string) (*DmStatement, error) { + stmt, err := filterChain.DmConnectionPrepare(c, query) + if err != nil { + return nil, err + } + statementCreateAfter(c, stmt) + return stmt, nil +} + +func (sf *statFilter) DmConnectionPrepareContext(filterChain *filterChain, c *DmConnection, ctx context.Context, query string) (*DmStatement, error) { + stmt, err := filterChain.DmConnectionPrepareContext(c, ctx, query) + if err != nil { + return nil, err + } + statementCreateAfter(c, stmt) + return stmt, nil +} + +func (sf *statFilter) DmConnectionResetSession(filterChain *filterChain, c *DmConnection, ctx context.Context) error { + return filterChain.DmConnectionResetSession(c, ctx) +} + +func (sf *statFilter) DmConnectionCheckNamedValue(filterChain *filterChain, c *DmConnection, nv *driver.NamedValue) error { + return filterChain.DmConnectionCheckNamedValue(c, nv) +} + +//DmStatement +func (sf *statFilter) DmStatementClose(filterChain *filterChain, s *DmStatement) error { + if !s.closed { + statementCloseBefore(s) + } + return filterChain.DmStatementClose(s) +} + +func (sf *statFilter) DmStatementNumInput(filterChain *filterChain, s *DmStatement) int { + return filterChain.DmStatementNumInput(s) +} + +func (sf *statFilter) DmStatementExec(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmResult, error) { + stmtExecBefore(s) + dr, err := filterChain.DmStatementExec(s, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtExecAfter(s, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmStatementExecContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmResult, error) { + stmtExecBefore(s) + dr, err := filterChain.DmStatementExecContext(s, ctx, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtExecAfter(s, args, int(dr.affectedRows)) + return dr, nil +} + +func (sf *statFilter) DmStatementQuery(filterChain *filterChain, s *DmStatement, args []driver.Value) (*DmRows, error) { + stmtQueryBefore(s) + dr, err := filterChain.DmStatementQuery(s, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtQueryAfter(s, args, dr) + return dr, nil +} + +func (sf *statFilter) DmStatementQueryContext(filterChain *filterChain, s *DmStatement, ctx context.Context, args []driver.NamedValue) (*DmRows, error) { + stmtQueryBefore(s) + dr, err := filterChain.DmStatementQueryContext(s, ctx, args) + if err != nil { + statementExecuteErrorAfter(s, args, err) + return nil, err + } + stmtQueryAfter(s, args, dr) + return dr, nil +} + +func (sf *statFilter) DmStatementCheckNamedValue(filterChain *filterChain, s *DmStatement, nv *driver.NamedValue) error { + return filterChain.DmStatementCheckNamedValue(s, nv) +} + +//DmResult +func (sf *statFilter) DmResultLastInsertId(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultLastInsertId(r) +} + +func (sf *statFilter) DmResultRowsAffected(filterChain *filterChain, r *DmResult) (int64, error) { + return filterChain.DmResultRowsAffected(r) +} + +//DmRows +func (sf *statFilter) DmRowsColumns(filterChain *filterChain, r *DmRows) []string { + return filterChain.DmRowsColumns(r) +} + +func (sf *statFilter) DmRowsClose(filterChain *filterChain, r *DmRows) error { + if !r.CurrentRows.closed { + resultSetCloseBefore(r) + } + return filterChain.DmRowsClose(r) +} + +func (sf *statFilter) DmRowsNext(filterChain *filterChain, r *DmRows, dest []driver.Value) error { + return filterChain.DmRowsNext(r, dest) +} + +func (sf *statFilter) DmRowsHasNextResultSet(filterChain *filterChain, r *DmRows) bool { + return filterChain.DmRowsHasNextResultSet(r) +} + +func (sf *statFilter) DmRowsNextResultSet(filterChain *filterChain, r *DmRows) error { + return filterChain.DmRowsNextResultSet(r) +} + +func (sf *statFilter) DmRowsColumnTypeScanType(filterChain *filterChain, r *DmRows, index int) reflect.Type { + return filterChain.DmRowsColumnTypeScanType(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeDatabaseTypeName(filterChain *filterChain, r *DmRows, index int) string { + return filterChain.DmRowsColumnTypeDatabaseTypeName(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeLength(filterChain *filterChain, r *DmRows, index int) (length int64, ok bool) { + return filterChain.DmRowsColumnTypeLength(r, index) +} + +func (sf *statFilter) DmRowsColumnTypeNullable(filterChain *filterChain, r *DmRows, index int) (nullable, ok bool) { + return filterChain.DmRowsColumnTypeNullable(r, index) +} + +func (sf *statFilter) DmRowsColumnTypePrecisionScale(filterChain *filterChain, r *DmRows, index int) (precision, scale int64, ok bool) { + return filterChain.DmRowsColumnTypePrecisionScale(r, index) +} + +func getActiveStmtCount(conn *DmConnection) int { + if conn.stmtMap == nil { + return 0 + } else { + return len(conn.stmtMap) + } +} + +func statementCreateAfter(conn *DmConnection, stmt *DmStatement) { + stmt.statInfo.setConstructNano() + conn.statInfo.getConnStat().incrementStmt() +} + +func connExecBefore(conn *DmConnection, sql string) { + conn.statInfo.setLastExecuteSql(sql) + conn.statInfo.setFirstResultSet(false) + conn.statInfo.setLastExecuteType(ExecuteUpdate) + internalBeforeConnExecute(conn, sql) +} + +func connExecAfter(conn *DmConnection, sql string, args interface{}, updateCount int) { + internalAfterConnExecute(conn, args, updateCount) +} + +func connQueryBefore(conn *DmConnection, sql string) { + conn.statInfo.setLastExecuteSql(sql) + conn.statInfo.setFirstResultSet(true) + conn.statInfo.setLastExecuteType(ExecuteQuery) + internalBeforeConnExecute(conn, sql) +} + +func connQueryAfter(conn *DmConnection, sql string, args interface{}, resultSet *DmRows) { + if resultSet != nil { + connResultSetCreateAfter(resultSet, conn) + } + internalAfterConnExecute(conn, args, 0) +} + +func stmtExecBefore(stmt *DmStatement) { + stmt.statInfo.setLastExecuteSql(stmt.nativeSql) + stmt.statInfo.setFirstResultSet(false) + stmt.statInfo.setLastExecuteType(ExecuteUpdate) + internalBeforeStatementExecute(stmt, stmt.nativeSql) +} + +func stmtExecAfter(stmt *DmStatement, args interface{}, updateCount int) { + internalAfterStatementExecute(stmt, args, updateCount) +} + +func stmtQueryBefore(stmt *DmStatement) { + stmt.statInfo.setLastExecuteSql(stmt.nativeSql) + stmt.statInfo.setFirstResultSet(true) + stmt.statInfo.setLastExecuteType(ExecuteQuery) + internalBeforeStatementExecute(stmt, stmt.nativeSql) +} + +func stmtQueryAfter(stmt *DmStatement, args interface{}, resultSet *DmRows) { + if resultSet != nil { + stmtResultSetCreateAfter(resultSet, stmt) + } + internalAfterStatementExecute(stmt, args, 0) +} + +func internalBeforeConnExecute(conn *DmConnection, sql string) { + connStat := conn.statInfo.getConnStat() + connStat.incrementExecuteCount() + conn.statInfo.beforeExecute() + + sqlStat := conn.statInfo.getSqlStat() + if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) { + sqlStat = connStat.createSqlStat(sql) + conn.statInfo.setSqlStat(sqlStat) + } + + inTransaction := false + inTransaction = !conn.autoCommit + + if sqlStat != nil { + sqlStat.ExecuteLastStartTime = time.Now().UnixNano() + sqlStat.incrementRunningCount() + + if inTransaction { + sqlStat.incrementInTransactionCount() + } + } +} + +func internalAfterConnExecute(conn *DmConnection, args interface{}, updateCount int) { + nowNano := time.Now().UnixNano() + nanos := nowNano - conn.statInfo.getLastExecuteStartNano() + + conn.statInfo.afterExecute(nanos) + + sqlStat := conn.statInfo.getSqlStat() + + if sqlStat != nil { + sqlStat.incrementExecuteSuccessCount() + + sqlStat.decrementRunningCount() + + parameters := buildSlowParameters(args) + + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(), + nanos, parameters) + + if !conn.statInfo.isFirstResultSet() && + conn.statInfo.getLastExecuteType() == ExecuteUpdate { + if updateCount < 0 { + updateCount = 0 + } + sqlStat.addUpdateCount(int64(updateCount)) + } + } + +} + +func internalBeforeStatementExecute(stmt *DmStatement, sql string) { + connStat := stmt.dmConn.statInfo.getConnStat() + connStat.incrementExecuteCount() + stmt.statInfo.beforeExecute() + + sqlStat := stmt.statInfo.getSqlStat() + if sqlStat == nil || sqlStat.Removed == 1 || !(sqlStat.Sql == sql) { + sqlStat = connStat.createSqlStat(sql) + stmt.statInfo.setSqlStat(sqlStat) + } + + inTransaction := false + inTransaction = !stmt.dmConn.autoCommit + + if sqlStat != nil { + sqlStat.ExecuteLastStartTime = time.Now().UnixNano() + sqlStat.incrementRunningCount() + + if inTransaction { + sqlStat.incrementInTransactionCount() + } + } +} + +func internalAfterStatementExecute(stmt *DmStatement, args interface{}, updateCount int) { + nowNano := time.Now().UnixNano() + nanos := nowNano - stmt.statInfo.getLastExecuteStartNano() + + stmt.statInfo.afterExecute(nanos) + + sqlStat := stmt.statInfo.getSqlStat() + + if sqlStat != nil { + sqlStat.incrementExecuteSuccessCount() + + sqlStat.decrementRunningCount() + + parameters := "" + if stmt.paramCount > 0 { + parameters = buildStmtSlowParameters(stmt, args) + } + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(), + nanos, parameters) + + if (!stmt.statInfo.isFirstResultSet()) && + stmt.statInfo.getLastExecuteType() == ExecuteUpdate { + updateCount := stmt.execInfo.updateCount + if updateCount < 0 { + updateCount = 0 + } + sqlStat.addUpdateCount(updateCount) + } + + } + +} + +func buildSlowParameters(args interface{}) string { + switch v := args.(type) { + case []driver.Value: + sb := bytes.NewBufferString("") + for i := 0; i < len(v); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + case []driver.NamedValue: + sb := bytes.NewBufferString("") + for i := 0; i < len(v); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + default: + return "" + } +} + +func buildStmtSlowParameters(stmt *DmStatement, args interface{}) string { + switch v := args.(type) { + case []driver.Value: + sb := bytes.NewBufferString("") + for i := 0; i < int(stmt.paramCount); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + case []driver.NamedValue: + sb := bytes.NewBufferString("") + for i := 0; i < int(stmt.paramCount); i++ { + if i != 0 { + sb.WriteString(",") + } else { + sb.WriteString("[") + } + + sb.WriteString(fmt.Sprint(v[i])) + } + if len(v) > 0 { + sb.WriteString("]") + } + return sb.String() + default: + return "" + } +} + +func connExecuteErrorAfter(conn *DmConnection, args interface{}, err error) { + nanos := time.Now().UnixNano() - conn.statInfo.getLastExecuteStartNano() + conn.statInfo.getConnStat().incrementErrorCount() + conn.statInfo.afterExecute(nanos) + + // SQL + sqlStat := conn.statInfo.getSqlStat() + if sqlStat != nil { + sqlStat.decrementRunningCount() + sqlStat.error(err) + parameters := buildSlowParameters(args) + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(conn.statInfo.getLastExecuteType(), conn.statInfo.isFirstResultSet(), + nanos, parameters) + } + +} + +func statementExecuteErrorAfter(stmt *DmStatement, args interface{}, err error) { + nanos := time.Now().UnixNano() - stmt.statInfo.getLastExecuteStartNano() + stmt.dmConn.statInfo.getConnStat().incrementErrorCount() + stmt.statInfo.afterExecute(nanos) + + // SQL + sqlStat := stmt.statInfo.getSqlStat() + if sqlStat != nil { + sqlStat.decrementRunningCount() + sqlStat.error(err) + parameters := "" + if stmt.paramCount > 0 { + parameters = buildStmtSlowParameters(stmt, args) + } + sqlStat.addExecuteTimeAndResultHoldTimeHistogramRecord(stmt.statInfo.getLastExecuteType(), stmt.statInfo.isFirstResultSet(), + nanos, parameters) + } + +} + +func statementCloseBefore(stmt *DmStatement) { + stmt.dmConn.statInfo.getConnStat().decrementStmt() +} + +func connResultSetCreateAfter(dmdbResultSet *DmRows, conn *DmConnection) { + dmdbResultSet.statInfo.setSql(conn.statInfo.getLastExecuteSql()) + dmdbResultSet.statInfo.setSqlStat(conn.statInfo.getSqlStat()) + dmdbResultSet.statInfo.setConstructNano() +} + +func stmtResultSetCreateAfter(dmdbResultSet *DmRows, stmt *DmStatement) { + dmdbResultSet.statInfo.setSql(stmt.statInfo.getLastExecuteSql()) + dmdbResultSet.statInfo.setSqlStat(stmt.statInfo.getSqlStat()) + dmdbResultSet.statInfo.setConstructNano() +} + +func resultSetCloseBefore(resultSet *DmRows) { + nanos := time.Now().UnixNano() - resultSet.statInfo.getConstructNano() + fetchRowCount := getFetchedRows(resultSet) + sqlStat := resultSet.statInfo.getSqlStat() + if sqlStat != nil && resultSet.statInfo.getCloseCount() == 0 { + sqlStat.addFetchRowCount(fetchRowCount) + stmtExecuteNano := resultSet.statInfo.getLastExecuteTimeNano() + sqlStat.addResultSetHoldTimeNano2(stmtExecuteNano, nanos) + if resultSet.statInfo.getReadStringLength() > 0 { + sqlStat.addStringReadLength(resultSet.statInfo.getReadStringLength()) + } + if resultSet.statInfo.getReadBytesLength() > 0 { + sqlStat.addReadBytesLength(resultSet.statInfo.getReadBytesLength()) + } + if resultSet.statInfo.getOpenInputStreamCount() > 0 { + sqlStat.addInputStreamOpenCount(int64(resultSet.statInfo.getOpenInputStreamCount())) + } + if resultSet.statInfo.getOpenReaderCount() > 0 { + sqlStat.addReaderOpenCount(int64(resultSet.statInfo.getOpenReaderCount())) + } + } + + resultSet.statInfo.incrementCloseCount() +} + +func getFetchedRows(rs *DmRows) int64 { + if rs.CurrentRows.currentPos >= rs.CurrentRows.totalRowCount { + return rs.CurrentRows.totalRowCount + } else { + return rs.CurrentRows.currentPos + 1 + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zi.go b/dpi_bridge/third_party/chunanyong_dm/zi.go new file mode 100644 index 0000000..46562ea --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zi.go @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "io" + "math/big" + "strconv" + "strings" + "time" + + "gitee.com/chunanyong/dm/util" +) + +var G2DB g2db + +type g2db struct { +} + +func (G2DB g2db) checkTinyint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT8_MIN) || v > float64(INT8_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT8_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT8_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkSmallint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT16_MIN) || v > float64(INT16_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT16_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT16_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkInt(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT32_MIN) || v > float64(INT32_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(int64(INT32_MIN))) < 0 || + v.ToBigInt().Cmp(big.NewInt(int64(INT32_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkBigint(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(INT64_MIN) || v > float64(INT64_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigInt().Cmp(big.NewInt(INT64_MIN)) < 0 || + v.ToBigInt().Cmp(big.NewInt(INT64_MAX)) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) checkReal(val interface{}) error { + switch v := val.(type) { + case float64: + if v < float64(FLOAT32_MIN) || v > float64(FLOAT32_MAX) { + return ECGO_DATA_OVERFLOW.throw() + } + case DmDecimal: + if v.ToBigFloat().Cmp(big.NewFloat(float64(FLOAT32_MIN))) < 0 || + v.ToBigFloat().Cmp(big.NewFloat(float64(FLOAT32_MAX))) > 0 { + return ECGO_DATA_OVERFLOW.throw() + } + } + return nil +} + +func (G2DB g2db) fromBool(val bool, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL, CHAR, + VARCHAR2, VARCHAR, CLOB: + if val { + return G2DB.fromInt64(1, param, conn) + } else { + return G2DB.fromInt64(0, param, conn) + } + case BINARY, VARBINARY, BLOB: + if val { + return Dm_build_1346.Dm_build_1524(byte(1)), nil + } else { + return Dm_build_1346.Dm_build_1524(byte(0)), nil + } + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromInt64(val int64, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case BOOLEAN, BIT: + if val == 0 { + return Dm_build_1346.Dm_build_1524(byte(0)), nil + } + + return Dm_build_1346.Dm_build_1524(byte(1)), nil + + case TINYINT: + err := G2DB.checkTinyint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1524(byte(val)), nil + case SMALLINT: + err := G2DB.checkSmallint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1530(int16(val)), nil + case INT: + err := G2DB.checkInt(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1533(int32(val)), nil + case BIGINT: + err := G2DB.checkBigint(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1536(int64(val)), nil + case REAL: + err := G2DB.checkReal(float64(val)) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1539(float32(val)), nil + case DOUBLE: + return Dm_build_1346.Dm_build_1542(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewInt(val), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1346.Dm_build_1562(strconv.FormatInt(val, 10), conn.getServerEncoding(), conn), nil + case BINARY, VARBINARY, BLOB: + return G2DB.ToBinary(val, int(param.prec)), nil + case DATE, TIME, DATETIME, DATETIME2: + if err := G2DB.checkInt(float64(val)); err != nil { + return nil, err + } + return toDate(val, param.column, *conn) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) ToBinary(x int64, prec int) []byte { + b := make([]byte, 8) + b[7] = byte(x) + b[6] = byte(x >> 8) + b[5] = byte(x >> 16) + b[4] = byte(x >> 24) + b[3] = byte(x >> 32) + b[2] = byte(x >> 40) + b[1] = byte(x >> 48) + b[0] = byte(x >> 56) + + if prec > 0 && prec < len(b) { + dest := make([]byte, prec) + copy(dest, b[len(b)-prec:]) + return dest + } + return b +} + +func (G2DB g2db) fromFloat32(val float32, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case BOOLEAN, BIT: + if val == 0.0 { + return Dm_build_1346.Dm_build_1524(0), nil + } + return Dm_build_1346.Dm_build_1524(1), nil + case TINYINT: + if err := G2DB.checkTinyint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1524(byte(val)), nil + case SMALLINT: + if err := G2DB.checkSmallint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1530(int16(val)), nil + case INT: + if err := G2DB.checkInt(float64(val)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1533(int32(val)), nil + case BIGINT: + if err := G2DB.checkBigint(float64(val)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1536(int64(val)), nil + case REAL: + if err := G2DB.checkReal(float64(val)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1539(val), nil + case DOUBLE: + return Dm_build_1346.Dm_build_1542(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewFloat(float64(val)), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1346.Dm_build_1562(strconv.FormatFloat(float64(val), 'f', -1, 32), conn.getServerEncoding(), conn), nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromFloat64(val float64, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case BOOLEAN, BIT: + if val == 0.0 { + return Dm_build_1346.Dm_build_1524(0), nil + } + return Dm_build_1346.Dm_build_1524(1), nil + + case TINYINT: + err := G2DB.checkTinyint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1524(byte(val)), nil + case SMALLINT: + err := G2DB.checkSmallint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1530(int16(val)), nil + case INT: + err := G2DB.checkInt(val) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1533(int32(val)), nil + case BIGINT: + err := G2DB.checkBigint(val) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1536(int64(val)), nil + case REAL: + err := G2DB.checkReal(val) + + if err != nil { + return nil, err + } + + return Dm_build_1346.Dm_build_1539(float32(val)), nil + case DOUBLE: + return Dm_build_1346.Dm_build_1542(float64(val)), nil + case DECIMAL: + d, err := newDecimal(big.NewFloat(val), int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + return d.encodeDecimal() + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1346.Dm_build_1562(strconv.FormatFloat(val, 'f', -1, 64), conn.getServerEncoding(), conn), nil + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromBytes(val []byte, param parameter, conn *DmConnection) (interface{}, error) { + switch param.colType { + case CHAR, VARCHAR2, VARCHAR: + return G2DB.toVarchar(val) + case CLOB: + b, err := G2DB.toVarchar(val) + if err != nil { + return nil, err + } + return G2DB.changeOffRowData(param, b, conn.getServerEncoding()) + case BINARY, VARBINARY: + return val, nil + case BLOB: + return G2DB.bytes2Blob(val, param, conn) + case ARRAY, CLASS, PLTYPE_RECORD, SARRAY: + if param.typeDescriptor == nil { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return TypeDataSV.objBlobToBytes(val, param.typeDescriptor) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) toVarchar(bsArr []byte) ([]byte, error) { + if bsArr == nil || len(bsArr) == 0 { + return make([]byte, 0), nil + } + + realLen := len(bsArr) * 2 + bsRet := make([]byte, realLen) + for i := 0; i < len(bsArr); i++ { + bsTemp, err := G2DB.toChar(bsArr[i]) + if err != nil { + return nil, err + } + + bsRet[i*2] = bsTemp[0] + bsRet[i*2+1] = bsTemp[1] + } + + return bsRet, nil +} + +func (G2DB g2db) toChar(bt byte) ([]byte, error) { + bytes := make([]byte, 2) + var err error + + bytes[0], err = G2DB.getCharByNumVal((bt >> 4) & 0x0F) + if err != nil { + return nil, err + } + + bytes[1], err = G2DB.getCharByNumVal(bt & 0x0F) + if err != nil { + return nil, err + } + + return bytes, nil +} + +func (G2DB g2db) getCharByNumVal(val byte) (byte, error) { + if val >= 0 && val <= 9 { + return (byte)(val + '0'), nil + } + + if val >= 0x0a && val <= 0x0F { + return (byte)(val + 'A' - 0x0a), nil + } + return 0, ECGO_INVALID_HEX.throw() +} + +func (G2DB g2db) fromString(val string, param parameter, conn *DmConnection) (interface{}, error) { + switch param.colType { + case BOOLEAN, BIT: + ret, err := G2DB.toBool(val) + if err != nil { + return nil, err + } + + if ret { + return Dm_build_1346.Dm_build_1524(byte(1)), nil + } else { + return Dm_build_1346.Dm_build_1524(byte(0)), nil + } + + case TINYINT, SMALLINT, INT, BIGINT: + f, ok := new(big.Float).SetString(val) + if !ok { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + if f.Sign() < 0 { + f.Sub(f, big.NewFloat(0.5)) + } else { + f.Add(f, big.NewFloat(0.5)) + } + z, _ := f.Int(nil) + return G2DB.fromBigInt(z, param, conn) + case REAL, DOUBLE, DECIMAL: + f, ok := new(big.Float).SetString(val) + if ok { + return G2DB.fromBigFloat(f, param, conn) + } else { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + case CHAR, VARCHAR2, VARCHAR: + if param.mask == MASK_BFILE && !isValidBFileStr(val) { + return nil, ECGO_INVALID_BFILE_STR.throw() + } + return Dm_build_1346.Dm_build_1562(val, conn.getServerEncoding(), conn), nil + case CLOB: + return G2DB.string2Clob(val, param, conn) + case BINARY, VARBINARY: + return util.StringUtil.HexStringToBytes(val), nil + case BLOB: + return G2DB.bytes2Blob(util.StringUtil.HexStringToBytes(val), param, conn) + case DATE: + if conn.FormatDate != "" { + dt, err := parse(val, conn.FormatDate, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, param.column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + } + + return encodeByString(val, param.column, *conn) + case TIME: + if conn.FormatTime != "" { + dt, err := parse(val, conn.FormatTime, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, param.column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + } + + return encodeByString(val, param.column, *conn) + case DATETIME, DATETIME2: + if conn.FormatTimestamp != "" { + dt, err := parse(val, conn.FormatTimestamp, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, param.column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + } + + return encodeByString(val, param.column, *conn) + case TIME_TZ: + dt, err := parse(val, conn.FormatTimeTZ, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + if conn.FormatTimeTZ != "" { + return encode(dt, param.column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + } + + return encodeByString(val, param.column, *conn) + case DATETIME_TZ, DATETIME2_TZ: + if conn.FormatTimestampTZ != "" { + dt, err := parse(val, conn.FormatTimestampTZ, int(conn.OracleDateLanguage)) + if err != nil { + return nil, err + } + + return encode(dt, param.column, int(conn.dmConnector.localTimezone), int(conn.DbTimezone)) + } + + return encodeByString(val, param.column, *conn) + case INTERVAL_DT: + dt, err := NewDmIntervalDTByString(val) + if err != nil { + return nil, err + } + return dt.encode(int(param.scale)) + + case INTERVAL_YM: + ym, err := NewDmIntervalYMByString(val) + if err != nil { + return nil, err + } + return ym.encode(int(param.scale)) + } + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) toBool(str string) (bool, error) { + str = strings.TrimSpace(str) + if util.StringUtil.Equals(str, "0") { + return false, nil + } else if util.StringUtil.Equals(str, "1") { + return true, nil + } + + return strings.ToLower(str) == "true", nil +} + +func (G2DB g2db) fromBigInt(val *big.Int, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1346.Dm_build_1524(0) + } else { + ret = Dm_build_1346.Dm_build_1524(1) + } + case TINYINT: + err := G2DB.checkTinyint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1524(byte(val.Int64())) + case SMALLINT: + err := G2DB.checkSmallint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1530(int16(val.Int64())) + case INT: + err := G2DB.checkInt(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1533(int32(val.Int64())) + case BIGINT: + err := G2DB.checkBigint(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1536(val.Int64()) + case REAL: + err := G2DB.checkReal(float64(val.Int64())) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1539(float32(val.Int64())) + case DOUBLE: + ret = Dm_build_1346.Dm_build_1542(float64(val.Int64())) + case DECIMAL, BINARY, VARBINARY, BLOB: + d, err := newDecimal(val, int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + ret, err = d.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1346.Dm_build_1562(val.String(), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromBigFloat(val *big.Float, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1346.Dm_build_1524(0) + } else { + ret = Dm_build_1346.Dm_build_1524(1) + } + case TINYINT: + f, _ := val.Float64() + + err := G2DB.checkTinyint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1524(byte(f)) + case SMALLINT: + f, _ := val.Float64() + + err := G2DB.checkSmallint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1530(int16(f)) + case INT: + f, _ := val.Float64() + + err := G2DB.checkInt(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1533(int32(f)) + case BIGINT: + f, _ := val.Float64() + + err := G2DB.checkBigint(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1536(int64(f)) + case REAL: + f, _ := val.Float64() + + err := G2DB.checkReal(f) + + if err != nil { + return nil, err + } + + ret = Dm_build_1346.Dm_build_1539(float32(f)) + case DOUBLE: + f, _ := val.Float64() + ret = Dm_build_1346.Dm_build_1542(f) + case DECIMAL: + d, err := newDecimal(val, int(param.prec), int(param.scale)) + if err != nil { + return nil, err + } + ret, err = d.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1346.Dm_build_1562(val.Text('f', int(param.scale)), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromDecimal(val DmDecimal, param parameter, conn *DmConnection) ([]byte, error) { + var ret []byte + switch param.colType { + case BOOLEAN, BIT: + if val.Sign() == 0 { + ret = Dm_build_1346.Dm_build_1524(0) + } else { + ret = Dm_build_1346.Dm_build_1524(1) + } + case TINYINT: + if err := G2DB.checkTinyint(val); err != nil { + return nil, err + } + ret = Dm_build_1346.Dm_build_1524(byte(val.ToBigInt().Int64())) + case SMALLINT: + if err := G2DB.checkSmallint(val); err != nil { + return nil, err + } + ret = Dm_build_1346.Dm_build_1530(int16(val.ToBigInt().Int64())) + case INT: + if err := G2DB.checkInt(val); err != nil { + return nil, err + } + ret = Dm_build_1346.Dm_build_1533(int32(val.ToBigInt().Int64())) + case BIGINT: + if err := G2DB.checkBigint(val); err != nil { + return nil, err + } + ret = Dm_build_1346.Dm_build_1536(int64(val.ToBigInt().Int64())) + case REAL: + if err := G2DB.checkReal(val); err != nil { + return nil, err + } + f, _ := val.ToBigFloat().Float32() + ret = Dm_build_1346.Dm_build_1539(f) + case DOUBLE: + f, _ := val.ToBigFloat().Float64() + ret = Dm_build_1346.Dm_build_1542(f) + case DECIMAL: + var err error + ret, err = val.encodeDecimal() + if err != nil { + return nil, err + } + case CHAR, VARCHAR2, VARCHAR, CLOB: + ret = Dm_build_1346.Dm_build_1562(val.ToBigFloat().Text('f', -1), conn.getServerEncoding(), conn) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromTime(val time.Time, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case DATE, DATETIME, DATETIME_TZ, TIME, TIME_TZ, DATETIME2, DATETIME2_TZ: + return encodeByTime(val, param.column, *conn) + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1346.Dm_build_1562(val.Format("2006-01-02 15:04:05.999999999 -07:00"), conn.getServerEncoding(), conn), nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (G2DB g2db) fromDmIntervalDT(val DmIntervalDT, param parameter, conn *DmConnection) ([]byte, error) { + switch param.colType { + case CHAR, VARCHAR2, VARCHAR, CLOB: + return Dm_build_1346.Dm_build_1562(val.String(), conn.getServerEncoding(), conn), nil + case INTERVAL_DT: + return val.encode(int(param.scale)) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} + +func (G2DB g2db) fromDmdbIntervalYM(val DmIntervalYM, param parameter, conn *DmConnection) ([]byte, error) { + + switch param.colType { + case CHAR, VARCHAR, VARCHAR2, CLOB: + return Dm_build_1346.Dm_build_1562(val.String(), conn.getServerEncoding(), conn), nil + case INTERVAL_YM: + return val.encode(int(param.scale)) + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } +} + +func (G2DB g2db) fromBlob(val DmBlob, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case BINARY, VARBINARY: + len, err := val.GetLength() + if err != nil { + return nil, err + } + ret, err = val.getBytes(1, int32(len)) + if err != nil { + return nil, err + } + case BLOB: + var err error + ret, err = G2DB.blob2Blob(val, param, conn) + if err != nil { + return nil, err + } + case ARRAY, CLASS, PLTYPE_RECORD, SARRAY: + + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromClob(val DmClob, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case CHAR, VARCHAR, VARCHAR2: + var len int64 + var s string + var err error + len, err = val.GetLength() + if err != nil { + return nil, err + } + s, err = val.getSubString(1, int32(len)) + if err != nil { + return nil, err + } + ret = []byte(s) + case CLOB: + var err error + ret, err = G2DB.clob2Clob(val, param, conn) + if err != nil { + return nil, err + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) fromReader(val io.Reader, param parameter, conn *DmConnection) (interface{}, error) { + var ret interface{} + switch param.colType { + case CHAR, VARCHAR2, VARCHAR: + var bytesBuf = new(bytes.Buffer) + if _, err := bytesBuf.ReadFrom(val); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1562(string(bytesBuf.Bytes()), conn.getServerEncoding(), conn), nil + case BINARY, VARBINARY: + var bytesBuf = new(bytes.Buffer) + if _, err := bytesBuf.ReadFrom(val); err != nil { + return nil, err + } + return util.StringUtil.HexStringToBytes(string(bytesBuf.Bytes())), nil + case BLOB, CLOB: + var binder = newOffRowReaderBinder(val, conn.getServerEncoding()) + if binder.offRow { + ret = binder + } else { + ret = binder.readAll() + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, nil +} + +func (G2DB g2db) string2Clob(val string, param parameter, conn *DmConnection) (interface{}, error) { + return G2DB.changeOffRowData(param, Dm_build_1346.Dm_build_1562(val, conn.getServerEncoding(), conn), conn.getServerEncoding()) +} + +func (G2DB g2db) bytes2Blob(val []byte, param parameter, conn *DmConnection) (interface{}, error) { + return G2DB.changeOffRowData(param, val, conn.getServerEncoding()) +} + +func (G2DB g2db) clob2Clob(val DmClob, param parameter, conn *DmConnection) (interface{}, error) { + var clobLen int64 + var err error + if clobLen, err = val.GetLength(); err != nil { + return nil, err + } + if G2DB.isOffRow(param.colType, clobLen) { + return newOffRowClobBinder(val, conn.getServerEncoding()), nil + } else { + var length int64 + var str string + if length, err = val.GetLength(); err != nil { + return nil, err + } + if str, err = val.getSubString(1, int32(length)); err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1562(str, conn.getServerEncoding(), conn), nil + } +} + +func (G2DB g2db) blob2Blob(val DmBlob, param parameter, conn *DmConnection) (interface{}, error) { + var clobLen int64 + var err error + if clobLen, err = val.GetLength(); err != nil { + return nil, err + } + if G2DB.isOffRow(param.colType, clobLen) { + return newOffRowBlobBinder(val, conn.getServerEncoding()), nil + } else { + var length int64 + if length, err = val.GetLength(); err != nil { + return nil, err + } + return val.getBytes(1, int32(length)) + } +} + +func (G2DB g2db) changeOffRowData(paramDesc parameter, paramData []byte, encoding string) (interface{}, error) { + if G2DB.isOffRow(paramDesc.colType, int64(len(paramData))) { + return newOffRowBytesBinder(paramData, encoding), nil + } else { + return paramData, nil + } +} + +func (G2DB g2db) isOffRow(dtype int32, length int64) bool { + return (dtype == BLOB || dtype == CLOB) && length > Dm_build_817 +} + +func (G2DB g2db) fromObject(mem interface{}, param parameter, conn *DmConnection) ([]byte, error) { + switch v := mem.(type) { + case bool: + return G2DB.fromBool(v, param, conn) + case string: + val, err := G2DB.fromString(v, param, conn) + if err != nil { + return nil, err + } + return val.([]byte), err + case byte: + return G2DB.fromInt64(int64(v), param, conn) + case int: + return G2DB.fromInt64(int64(v), param, conn) + case int16: + return G2DB.fromInt64(int64(v), param, conn) + case int32: + return G2DB.fromInt64(int64(v), param, conn) + case int64: + return G2DB.fromInt64(v, param, conn) + case float32: + return G2DB.fromFloat64(float64(v), param, conn) + case float64: + return G2DB.fromFloat64(v, param, conn) + case time.Time: + return G2DB.fromTime(v, param, conn) + case DmDecimal: + return G2DB.fromDecimal(v, param, conn) + case DmIntervalDT: + return G2DB.fromDmIntervalDT(v, param, conn) + case DmIntervalYM: + return G2DB.fromDmdbIntervalYM(v, param, conn) + case DmBlob: + length, _ := v.GetLength() + return v.getBytes(1, int32(length)) + case DmClob: + length, _ := v.GetLength() + str, err := v.getSubString(1, int32(length)) + if err != nil { + return nil, err + } + return Dm_build_1346.Dm_build_1562(str, conn.getServerEncoding(), conn), nil + default: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + } + +} + +func (G2DB g2db) toInt32(val int32) []byte { + bytes := make([]byte, 4) + Dm_build_1346.Dm_build_1362(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toInt64(val int64) []byte { + bytes := make([]byte, 8) + Dm_build_1346.Dm_build_1367(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toFloat32(val float32) []byte { + bytes := make([]byte, 4) + Dm_build_1346.Dm_build_1372(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toFloat64(val float64) []byte { + bytes := make([]byte, 8) + Dm_build_1346.Dm_build_1377(bytes, 0, val) + return bytes +} + +func (G2DB g2db) toDecimal(val string) ([]byte, error) { + d, err := NewDecimalFromString(val) + if err != nil { + return nil, err + } + return d.encodeDecimal() +} + +func (G2DB g2db) fromArray(x *DmArray, param parameter, connection *DmConnection) (interface{}, error) { + var ret interface{} + var err error + switch param.colType { + case SARRAY: + ret, err = TypeDataSV.sarrayToBytes(x, param.typeDescriptor) + case CLASS, ARRAY: + ret, err = TypeDataSV.arrayToBytes(x, param.typeDescriptor) + case BLOB: + ret, err = TypeDataSV.toBytesFromDmArray(x, param.typeDescriptor) + if err == nil { + ret, err = G2DB.bytes2Blob(ret.([]byte), param, connection) + } + default: + err = ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, err +} + +func (G2DB g2db) fromStruct(x *DmStruct, param parameter, connection *DmConnection) (interface{}, error) { + var ret interface{} + var err error + switch param.colType { + case CLASS: + ret, err = TypeDataSV.structToBytes(x, param.typeDescriptor) + case PLTYPE_RECORD: + ret, err = TypeDataSV.recordToBytes(x, param.typeDescriptor) + case BLOB: + ret, err = TypeDataSV.toBytesFromDmStruct(x, param.typeDescriptor) + if err == nil { + ret, err = G2DB.bytes2Blob(ret.([]byte), param, connection) + } + + default: + err = ECGO_DATA_CONVERTION_ERROR.throw() + } + return ret, err +} + +func isValidBFileStr(s string) bool { + strs := strings.Split(strings.TrimSpace(s), ":") + if len(strs) != 2 { + return false + } + if len(strs[0]) > Dm_build_745 || len(strs[1]) > Dm_build_746 { + return false + } + return true +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zn.go b/dpi_bridge/third_party/chunanyong_dm/zn.go new file mode 100644 index 0000000..9596fb6 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zn.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +const ( + LOB_FLAG_BYTE = 0 + LOB_FLAG_CHAR = 1 + + LOB_IN_ROW = 0x1 + LOB_OFF_ROW = 0x2 + + NBLOB_HEAD_IN_ROW_FLAG = 0 + NBLOB_HEAD_BLOBID = NBLOB_HEAD_IN_ROW_FLAG + BYTE_SIZE + NBLOB_HEAD_BLOB_LEN = NBLOB_HEAD_BLOBID + DDWORD_SIZE + + NBLOB_HEAD_OUTROW_GROUPID = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE + NBLOB_HEAD_OUTROW_FILEID = NBLOB_HEAD_OUTROW_GROUPID + USINT_SIZE + NBLOB_HEAD_OUTROW_PAGENO = NBLOB_HEAD_OUTROW_FILEID + USINT_SIZE + + NBLOB_EX_HEAD_TABLE_ID = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE + NBLOB_EX_HEAD_COL_ID = NBLOB_EX_HEAD_TABLE_ID + ULINT_SIZE + NBLOB_EX_HEAD_ROW_ID = NBLOB_EX_HEAD_COL_ID + USINT_SIZE + NBLOB_EX_HEAD_FPA_GRPID = NBLOB_EX_HEAD_ROW_ID + LINT64_SIZE + NBLOB_EX_HEAD_FPA_FILEID = NBLOB_EX_HEAD_FPA_GRPID + USINT_SIZE + NBLOB_EX_HEAD_FPA_PAGENO = NBLOB_EX_HEAD_FPA_FILEID + USINT_SIZE + NBLOB_EX_HEAD_SIZE = NBLOB_EX_HEAD_FPA_PAGENO + ULINT_SIZE + + NBLOB_OUTROW_HEAD_SIZE = NBLOB_HEAD_OUTROW_PAGENO + ULINT_SIZE + + NBLOB_INROW_HEAD_SIZE = NBLOB_HEAD_BLOB_LEN + ULINT_SIZE +) + +type lob struct { + blobId int64 + inRow bool + + groupId int16 + fileId int16 + pageNo int32 + tabId int32 + colId int16 + rowId int64 + exGroupId int16 + exFileId int16 + exPageNo int32 + + curFileId int16 + curPageNo int32 + curPageOffset int16 + totalOffset int32 + readOver bool + + connection *DmConnection + local bool + updateable bool + lobFlag int8 + length int64 + compatibleOracle bool + fetchAll bool + freed bool + modify bool + + Valid bool +} + +func (lob *lob) GetLength() (int64, error) { + var err error + if err = lob.checkValid(); err != nil { + return -1, err + } + if err = lob.checkFreed(); err != nil { + return -1, err + } + if lob.length == -1 { + + if lob.length, err = lob.connection.Access.dm_build_585(lob); err != nil { + return -1, err + } + } + return lob.length, nil +} + +func (lob *lob) resetCurrentInfo() { + lob.curFileId = lob.fileId + lob.curPageNo = lob.pageNo + lob.totalOffset = 0 + lob.curPageOffset = 0 +} + +func (lob *lob) getLengthFromHead(head []byte) int64 { + return int64(Dm_build_1346.Dm_build_1448(head, NBLOB_HEAD_BLOB_LEN)) +} + +func (lob *lob) canOptimized(connection *DmConnection) bool { + return !(lob.inRow || lob.fetchAll || lob.local || connection != lob.connection) +} + +func (lob *lob) buildCtlData() (bytes []byte) { + if lob.connection.NewLobFlag { + bytes = make([]byte, NBLOB_EX_HEAD_SIZE, NBLOB_EX_HEAD_SIZE) + } else { + bytes = make([]byte, NBLOB_OUTROW_HEAD_SIZE, NBLOB_OUTROW_HEAD_SIZE) + } + Dm_build_1346.Dm_build_1347(bytes, NBLOB_HEAD_IN_ROW_FLAG, LOB_OFF_ROW) + Dm_build_1346.Dm_build_1367(bytes, NBLOB_HEAD_BLOBID, lob.blobId) + Dm_build_1346.Dm_build_1362(bytes, NBLOB_HEAD_BLOB_LEN, -1) + + Dm_build_1346.Dm_build_1357(bytes, NBLOB_HEAD_OUTROW_GROUPID, lob.groupId) + Dm_build_1346.Dm_build_1357(bytes, NBLOB_HEAD_OUTROW_FILEID, lob.fileId) + Dm_build_1346.Dm_build_1362(bytes, NBLOB_HEAD_OUTROW_PAGENO, lob.pageNo) + + if lob.connection.NewLobFlag { + Dm_build_1346.Dm_build_1362(bytes, NBLOB_EX_HEAD_TABLE_ID, lob.tabId) + Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_COL_ID, lob.colId) + Dm_build_1346.Dm_build_1367(bytes, NBLOB_EX_HEAD_ROW_ID, lob.rowId) + Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_FPA_GRPID, lob.exGroupId) + Dm_build_1346.Dm_build_1357(bytes, NBLOB_EX_HEAD_FPA_FILEID, lob.exFileId) + Dm_build_1346.Dm_build_1362(bytes, NBLOB_EX_HEAD_FPA_PAGENO, lob.exPageNo) + } + return +} + +func (lob *lob) checkFreed() (err error) { + if lob.freed { + err = ECGO_LOB_FREED.throw() + } + return +} + +func (lob *lob) checkValid() error { + if !lob.Valid { + return ECGO_IS_NULL.throw() + } + return nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zo.go b/dpi_bridge/third_party/chunanyong_dm/zo.go new file mode 100644 index 0000000..14e6c07 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zo.go @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +const ( + ParamDataEnum_Null = 0 + /** + * 只有大字段才有行内数据、行外数据的概念 + */ + ParamDataEnum_OFF_ROW = 1 +) + +// JDBC中的Data +type lobCtl struct { + value []byte +} + +// lob数据返回信息,自bug610335后,服务器不光返回字节数组,还返回字符数 +type lobRetInfo struct { + charLen int64 // 字符长度 + data []byte //lob数据 +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zp.go b/dpi_bridge/third_party/chunanyong_dm/zp.go new file mode 100644 index 0000000..c5afccb --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zp.go @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" + + "gitee.com/chunanyong/dm/util" +) + +const ( + MAX_FILE_SIZE = 100 * 1024 * 1024 + FLUSH_SIZE = 32 * 1024 +) + +type goRun interface { + doRun() +} + +type logWriter struct { + flushQueue chan []byte + date string + logFile *os.File + flushFreq int + filePath string + filePrefix string + buffer *Dm_build_0 +} + +func (lw *logWriter) doRun() { + defer func() { + lw.beforeExit() + lw.closeCurrentFile() + }() + + i := 0 + for { + var ibytes []byte + + select { + case ibytes = <-lw.flushQueue: + if LogLevel != LOG_OFF { + if i == LogFlushQueueSize { + lw.doFlush(lw.buffer) + i = 0 + } else { + lw.buffer.Dm_build_26(ibytes, 0, len(ibytes)) + i++ + } + } + case <-time.After(time.Duration(LogFlushFreq) * time.Millisecond): + if LogLevel != LOG_OFF && lw.buffer.Dm_build_5() > 0 { + lw.doFlush(lw.buffer) + i = 0 + } + + } + + } +} + +func (lw *logWriter) doFlush(buffer *Dm_build_0) { + if lw.needCreateNewFile() { + lw.closeCurrentFile() + lw.logFile = lw.createNewFile() + } + if lw.logFile != nil { + buffer.Dm_build_20(lw.logFile, buffer.Dm_build_5()) + } +} +func (lw *logWriter) closeCurrentFile() { + if lw.logFile != nil { + lw.logFile.Close() + lw.logFile = nil + } +} +func (lw *logWriter) createNewFile() *os.File { + lw.date = time.Now().Format("2006-01-02") + fileName := lw.filePrefix + "_" + lw.date + "_" + strconv.Itoa(time.Now().Nanosecond()) + ".log" + lw.filePath = LogDir + if len(lw.filePath) > 0 { + if _, err := os.Stat(lw.filePath); err != nil { + os.MkdirAll(lw.filePath, 0755) + } + if _, err := os.Stat(lw.filePath + fileName); err != nil { + logFile, err := os.Create(lw.filePath + fileName) + if err != nil { + fmt.Println(err) + return nil + } + return logFile + } + } + return nil +} +func (lw *logWriter) needCreateNewFile() bool { + now := time.Now().Format("2006-01-02") + fileInfo, err := lw.logFile.Stat() + return now != lw.date || err != nil || lw.logFile == nil || fileInfo.Size() > int64(MAX_FILE_SIZE) +} +func (lw *logWriter) beforeExit() { + close(lw.flushQueue) + var ibytes []byte + for ibytes = <-lw.flushQueue; ibytes != nil; ibytes = <-lw.flushQueue { + lw.buffer.Dm_build_26(ibytes, 0, len(ibytes)) + if lw.buffer.Dm_build_5() >= LogBufferSize { + lw.doFlush(lw.buffer) + } + } + if lw.buffer.Dm_build_5() > 0 { + lw.doFlush(lw.buffer) + } +} + +func (lw *logWriter) WriteLine(msg string) { + var b = []byte(strings.TrimSpace(msg) + util.LINE_SEPARATOR) + lw.flushQueue <- b +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zq.go b/dpi_bridge/third_party/chunanyong_dm/zq.go new file mode 100644 index 0000000..d9f466a --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zq.go @@ -0,0 +1,2944 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "fmt" + "math" + "os" + "strconv" + "strings" + + "gitee.com/chunanyong/dm/util" +) + +const ( + Dm_build_693 = "7.6.0.0" + + Dm_build_694 = "7.0.0.9" + + Dm_build_695 = "8.0.0.73" + + Dm_build_696 = "7.1.2.128" + + Dm_build_697 = "7.1.5.144" + + Dm_build_698 = "7.1.6.123" + + Dm_build_699 = 1 + + Dm_build_700 = 2 + + Dm_build_701 = 3 + + Dm_build_702 = 4 + + Dm_build_703 = 5 + + Dm_build_704 = 6 + + Dm_build_705 = 8 + + Dm_build_706 = Dm_build_705 + + Dm_build_707 = 32768 - 128 + + Dm_build_708 = 0x20000000 + + Dm_build_709 int16 = 1 + + Dm_build_710 int16 = 2 + + Dm_build_711 int16 = 3 + + Dm_build_712 int16 = 4 + + Dm_build_713 int16 = 5 + + Dm_build_714 int16 = 6 + + Dm_build_715 int16 = 7 + + Dm_build_716 int16 = 8 + + Dm_build_717 int16 = 9 + + Dm_build_718 int16 = 13 + + Dm_build_719 int16 = 14 + + Dm_build_720 int16 = 15 + + Dm_build_721 int16 = 17 + + Dm_build_722 int16 = 21 + + Dm_build_723 int16 = 24 + + Dm_build_724 int16 = 27 + + Dm_build_725 int16 = 29 + + Dm_build_726 int16 = 30 + + Dm_build_727 int16 = 31 + + Dm_build_728 int16 = 32 + + Dm_build_729 int16 = 44 + + Dm_build_730 int16 = 52 + + Dm_build_731 int16 = 60 + + Dm_build_732 int16 = 71 + + Dm_build_733 int16 = 90 + + Dm_build_734 int16 = 91 + + Dm_build_735 int16 = 200 + + Dm_build_736 = 64 + + Dm_build_737 = 20 + + Dm_build_738 = 0 + + Dm_build_739 = 4 + + Dm_build_740 = 6 + + Dm_build_741 = 10 + + Dm_build_742 = 14 + + Dm_build_743 = 18 + + Dm_build_744 = 19 + + Dm_build_745 = 128 + + Dm_build_746 = 256 + + Dm_build_747 int32 = 2 + + Dm_build_748 int32 = 5 + + Dm_build_749 = -1 + + Dm_build_750 int32 = 0xFF00 + + Dm_build_751 int32 = 0xFFFE - 3 + + Dm_build_752 int32 = 0xFFFE - 4 + + Dm_build_753 int32 = 0xFFFE + + Dm_build_754 int32 = 0xFFFF + + Dm_build_755 int32 = 0x80 + + Dm_build_756 byte = 0x60 + + Dm_build_757 uint16 = uint16(Dm_build_753) + + Dm_build_758 uint16 = uint16(Dm_build_754) + + Dm_build_759 int16 = 0x00 + + Dm_build_760 int16 = 0x03 + + Dm_build_761 int32 = 0x80 + + Dm_build_762 byte = 0 + + Dm_build_763 byte = 1 + + Dm_build_764 byte = 2 + + Dm_build_765 byte = 3 + + Dm_build_766 byte = 4 + + Dm_build_767 byte = Dm_build_762 + + Dm_build_768 int = 10 + + Dm_build_769 int32 = 32 + + Dm_build_770 int32 = 65536 + + Dm_build_771 byte = 0 + + Dm_build_772 byte = 1 + + Dm_build_773 int32 = 0x00000000 + + Dm_build_774 int32 = 0x00000020 + + Dm_build_775 int32 = 0x00000040 + + Dm_build_776 int32 = 0x00000FFF + + Dm_build_777 int32 = 0 + + Dm_build_778 int32 = 1 + + Dm_build_779 int32 = 2 + + Dm_build_780 int32 = 3 + + Dm_build_781 = 8192 + + Dm_build_782 = 1 + + Dm_build_783 = 2 + + Dm_build_784 = 0 + + Dm_build_785 = 0 + + Dm_build_786 = 1 + + Dm_build_787 = -1 + + Dm_build_788 int16 = 0 + + Dm_build_789 int16 = 1 + + Dm_build_790 int16 = 2 + + Dm_build_791 int16 = 3 + + Dm_build_792 int16 = 4 + + Dm_build_793 int16 = 127 + + Dm_build_794 int16 = Dm_build_793 + 20 + + Dm_build_795 int16 = Dm_build_793 + 21 + + Dm_build_796 int16 = Dm_build_793 + 22 + + Dm_build_797 int16 = Dm_build_793 + 24 + + Dm_build_798 int16 = Dm_build_793 + 25 + + Dm_build_799 int16 = Dm_build_793 + 26 + + Dm_build_800 int16 = Dm_build_793 + 30 + + Dm_build_801 int16 = Dm_build_793 + 31 + + Dm_build_802 int16 = Dm_build_793 + 32 + + Dm_build_803 int16 = Dm_build_793 + 33 + + Dm_build_804 int16 = Dm_build_793 + 35 + + Dm_build_805 int16 = Dm_build_793 + 38 + + Dm_build_806 int16 = Dm_build_793 + 39 + + Dm_build_807 int16 = Dm_build_793 + 51 + + Dm_build_808 int16 = Dm_build_793 + 71 + + Dm_build_809 int16 = Dm_build_793 + 124 + + Dm_build_810 int16 = Dm_build_793 + 125 + + Dm_build_811 int16 = Dm_build_793 + 126 + + Dm_build_812 int16 = Dm_build_793 + 127 + + Dm_build_813 int16 = Dm_build_793 + 128 + + Dm_build_814 int16 = Dm_build_793 + 129 + + Dm_build_815 byte = 0 + + Dm_build_816 byte = 2 + + Dm_build_817 = 2048 + + Dm_build_818 = -1 + + Dm_build_819 = 0 + + Dm_build_820 = 16000 + + Dm_build_821 = 32000 + + Dm_build_822 = 0x00000000 + + Dm_build_823 = 0x00000020 + + Dm_build_824 = 0x00000040 + + Dm_build_825 = 0x00000FFF + + Dm_build_826 = 4 +) + +var Dm_build_827 = [8][256]uint32{ + + {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, + 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, + 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, + 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, + 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, + 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, + 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, + 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, + 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, + 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, + 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, + 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, + 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, + 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, + 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, + 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, + 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, + 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, + 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, + 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, + 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, + 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, + 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, + 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, + 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, + 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, + 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, + 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, + 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, + 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, + 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, + 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, + 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, + 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, + 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}, + + {0x00000000, 0x191b3141, 0x32366282, 0x2b2d53c3, 0x646cc504, 0x7d77f445, 0x565aa786, + 0x4f4196c7, 0xc8d98a08, 0xd1c2bb49, 0xfaefe88a, 0xe3f4d9cb, 0xacb54f0c, + 0xb5ae7e4d, 0x9e832d8e, 0x87981ccf, 0x4ac21251, 0x53d92310, 0x78f470d3, + 0x61ef4192, 0x2eaed755, 0x37b5e614, 0x1c98b5d7, 0x05838496, 0x821b9859, + 0x9b00a918, 0xb02dfadb, 0xa936cb9a, 0xe6775d5d, 0xff6c6c1c, 0xd4413fdf, + 0xcd5a0e9e, 0x958424a2, 0x8c9f15e3, 0xa7b24620, 0xbea97761, 0xf1e8e1a6, + 0xe8f3d0e7, 0xc3de8324, 0xdac5b265, 0x5d5daeaa, 0x44469feb, 0x6f6bcc28, + 0x7670fd69, 0x39316bae, 0x202a5aef, 0x0b07092c, 0x121c386d, 0xdf4636f3, + 0xc65d07b2, 0xed705471, 0xf46b6530, 0xbb2af3f7, 0xa231c2b6, 0x891c9175, + 0x9007a034, 0x179fbcfb, 0x0e848dba, 0x25a9de79, 0x3cb2ef38, 0x73f379ff, + 0x6ae848be, 0x41c51b7d, 0x58de2a3c, 0xf0794f05, 0xe9627e44, 0xc24f2d87, + 0xdb541cc6, 0x94158a01, 0x8d0ebb40, 0xa623e883, 0xbf38d9c2, 0x38a0c50d, + 0x21bbf44c, 0x0a96a78f, 0x138d96ce, 0x5ccc0009, 0x45d73148, 0x6efa628b, + 0x77e153ca, 0xbabb5d54, 0xa3a06c15, 0x888d3fd6, 0x91960e97, 0xded79850, + 0xc7cca911, 0xece1fad2, 0xf5facb93, 0x7262d75c, 0x6b79e61d, 0x4054b5de, + 0x594f849f, 0x160e1258, 0x0f152319, 0x243870da, 0x3d23419b, 0x65fd6ba7, + 0x7ce65ae6, 0x57cb0925, 0x4ed03864, 0x0191aea3, 0x188a9fe2, 0x33a7cc21, + 0x2abcfd60, 0xad24e1af, 0xb43fd0ee, 0x9f12832d, 0x8609b26c, 0xc94824ab, + 0xd05315ea, 0xfb7e4629, 0xe2657768, 0x2f3f79f6, 0x362448b7, 0x1d091b74, + 0x04122a35, 0x4b53bcf2, 0x52488db3, 0x7965de70, 0x607eef31, 0xe7e6f3fe, + 0xfefdc2bf, 0xd5d0917c, 0xcccba03d, 0x838a36fa, 0x9a9107bb, 0xb1bc5478, + 0xa8a76539, 0x3b83984b, 0x2298a90a, 0x09b5fac9, 0x10aecb88, 0x5fef5d4f, + 0x46f46c0e, 0x6dd93fcd, 0x74c20e8c, 0xf35a1243, 0xea412302, 0xc16c70c1, + 0xd8774180, 0x9736d747, 0x8e2de606, 0xa500b5c5, 0xbc1b8484, 0x71418a1a, + 0x685abb5b, 0x4377e898, 0x5a6cd9d9, 0x152d4f1e, 0x0c367e5f, 0x271b2d9c, + 0x3e001cdd, 0xb9980012, 0xa0833153, 0x8bae6290, 0x92b553d1, 0xddf4c516, + 0xc4eff457, 0xefc2a794, 0xf6d996d5, 0xae07bce9, 0xb71c8da8, 0x9c31de6b, + 0x852aef2a, 0xca6b79ed, 0xd37048ac, 0xf85d1b6f, 0xe1462a2e, 0x66de36e1, + 0x7fc507a0, 0x54e85463, 0x4df36522, 0x02b2f3e5, 0x1ba9c2a4, 0x30849167, + 0x299fa026, 0xe4c5aeb8, 0xfdde9ff9, 0xd6f3cc3a, 0xcfe8fd7b, 0x80a96bbc, + 0x99b25afd, 0xb29f093e, 0xab84387f, 0x2c1c24b0, 0x350715f1, 0x1e2a4632, + 0x07317773, 0x4870e1b4, 0x516bd0f5, 0x7a468336, 0x635db277, 0xcbfad74e, + 0xd2e1e60f, 0xf9ccb5cc, 0xe0d7848d, 0xaf96124a, 0xb68d230b, 0x9da070c8, + 0x84bb4189, 0x03235d46, 0x1a386c07, 0x31153fc4, 0x280e0e85, 0x674f9842, + 0x7e54a903, 0x5579fac0, 0x4c62cb81, 0x8138c51f, 0x9823f45e, 0xb30ea79d, + 0xaa1596dc, 0xe554001b, 0xfc4f315a, 0xd7626299, 0xce7953d8, 0x49e14f17, + 0x50fa7e56, 0x7bd72d95, 0x62cc1cd4, 0x2d8d8a13, 0x3496bb52, 0x1fbbe891, + 0x06a0d9d0, 0x5e7ef3ec, 0x4765c2ad, 0x6c48916e, 0x7553a02f, 0x3a1236e8, + 0x230907a9, 0x0824546a, 0x113f652b, 0x96a779e4, 0x8fbc48a5, 0xa4911b66, + 0xbd8a2a27, 0xf2cbbce0, 0xebd08da1, 0xc0fdde62, 0xd9e6ef23, 0x14bce1bd, + 0x0da7d0fc, 0x268a833f, 0x3f91b27e, 0x70d024b9, 0x69cb15f8, 0x42e6463b, + 0x5bfd777a, 0xdc656bb5, 0xc57e5af4, 0xee530937, 0xf7483876, 0xb809aeb1, + 0xa1129ff0, 0x8a3fcc33, 0x9324fd72}, + + {0x00000000, 0x01c26a37, 0x0384d46e, 0x0246be59, 0x0709a8dc, 0x06cbc2eb, 0x048d7cb2, + 0x054f1685, 0x0e1351b8, 0x0fd13b8f, 0x0d9785d6, 0x0c55efe1, 0x091af964, + 0x08d89353, 0x0a9e2d0a, 0x0b5c473d, 0x1c26a370, 0x1de4c947, 0x1fa2771e, + 0x1e601d29, 0x1b2f0bac, 0x1aed619b, 0x18abdfc2, 0x1969b5f5, 0x1235f2c8, + 0x13f798ff, 0x11b126a6, 0x10734c91, 0x153c5a14, 0x14fe3023, 0x16b88e7a, + 0x177ae44d, 0x384d46e0, 0x398f2cd7, 0x3bc9928e, 0x3a0bf8b9, 0x3f44ee3c, + 0x3e86840b, 0x3cc03a52, 0x3d025065, 0x365e1758, 0x379c7d6f, 0x35dac336, + 0x3418a901, 0x3157bf84, 0x3095d5b3, 0x32d36bea, 0x331101dd, 0x246be590, + 0x25a98fa7, 0x27ef31fe, 0x262d5bc9, 0x23624d4c, 0x22a0277b, 0x20e69922, + 0x2124f315, 0x2a78b428, 0x2bbade1f, 0x29fc6046, 0x283e0a71, 0x2d711cf4, + 0x2cb376c3, 0x2ef5c89a, 0x2f37a2ad, 0x709a8dc0, 0x7158e7f7, 0x731e59ae, + 0x72dc3399, 0x7793251c, 0x76514f2b, 0x7417f172, 0x75d59b45, 0x7e89dc78, + 0x7f4bb64f, 0x7d0d0816, 0x7ccf6221, 0x798074a4, 0x78421e93, 0x7a04a0ca, + 0x7bc6cafd, 0x6cbc2eb0, 0x6d7e4487, 0x6f38fade, 0x6efa90e9, 0x6bb5866c, + 0x6a77ec5b, 0x68315202, 0x69f33835, 0x62af7f08, 0x636d153f, 0x612bab66, + 0x60e9c151, 0x65a6d7d4, 0x6464bde3, 0x662203ba, 0x67e0698d, 0x48d7cb20, + 0x4915a117, 0x4b531f4e, 0x4a917579, 0x4fde63fc, 0x4e1c09cb, 0x4c5ab792, + 0x4d98dda5, 0x46c49a98, 0x4706f0af, 0x45404ef6, 0x448224c1, 0x41cd3244, + 0x400f5873, 0x4249e62a, 0x438b8c1d, 0x54f16850, 0x55330267, 0x5775bc3e, + 0x56b7d609, 0x53f8c08c, 0x523aaabb, 0x507c14e2, 0x51be7ed5, 0x5ae239e8, + 0x5b2053df, 0x5966ed86, 0x58a487b1, 0x5deb9134, 0x5c29fb03, 0x5e6f455a, + 0x5fad2f6d, 0xe1351b80, 0xe0f771b7, 0xe2b1cfee, 0xe373a5d9, 0xe63cb35c, + 0xe7fed96b, 0xe5b86732, 0xe47a0d05, 0xef264a38, 0xeee4200f, 0xeca29e56, + 0xed60f461, 0xe82fe2e4, 0xe9ed88d3, 0xebab368a, 0xea695cbd, 0xfd13b8f0, + 0xfcd1d2c7, 0xfe976c9e, 0xff5506a9, 0xfa1a102c, 0xfbd87a1b, 0xf99ec442, + 0xf85cae75, 0xf300e948, 0xf2c2837f, 0xf0843d26, 0xf1465711, 0xf4094194, + 0xf5cb2ba3, 0xf78d95fa, 0xf64fffcd, 0xd9785d60, 0xd8ba3757, 0xdafc890e, + 0xdb3ee339, 0xde71f5bc, 0xdfb39f8b, 0xddf521d2, 0xdc374be5, 0xd76b0cd8, + 0xd6a966ef, 0xd4efd8b6, 0xd52db281, 0xd062a404, 0xd1a0ce33, 0xd3e6706a, + 0xd2241a5d, 0xc55efe10, 0xc49c9427, 0xc6da2a7e, 0xc7184049, 0xc25756cc, + 0xc3953cfb, 0xc1d382a2, 0xc011e895, 0xcb4dafa8, 0xca8fc59f, 0xc8c97bc6, + 0xc90b11f1, 0xcc440774, 0xcd866d43, 0xcfc0d31a, 0xce02b92d, 0x91af9640, + 0x906dfc77, 0x922b422e, 0x93e92819, 0x96a63e9c, 0x976454ab, 0x9522eaf2, + 0x94e080c5, 0x9fbcc7f8, 0x9e7eadcf, 0x9c381396, 0x9dfa79a1, 0x98b56f24, + 0x99770513, 0x9b31bb4a, 0x9af3d17d, 0x8d893530, 0x8c4b5f07, 0x8e0de15e, + 0x8fcf8b69, 0x8a809dec, 0x8b42f7db, 0x89044982, 0x88c623b5, 0x839a6488, + 0x82580ebf, 0x801eb0e6, 0x81dcdad1, 0x8493cc54, 0x8551a663, 0x8717183a, + 0x86d5720d, 0xa9e2d0a0, 0xa820ba97, 0xaa6604ce, 0xaba46ef9, 0xaeeb787c, + 0xaf29124b, 0xad6fac12, 0xacadc625, 0xa7f18118, 0xa633eb2f, 0xa4755576, + 0xa5b73f41, 0xa0f829c4, 0xa13a43f3, 0xa37cfdaa, 0xa2be979d, 0xb5c473d0, + 0xb40619e7, 0xb640a7be, 0xb782cd89, 0xb2cddb0c, 0xb30fb13b, 0xb1490f62, + 0xb08b6555, 0xbbd72268, 0xba15485f, 0xb853f606, 0xb9919c31, 0xbcde8ab4, + 0xbd1ce083, 0xbf5a5eda, 0xbe9834ed}, + + {0x00000000, 0xb8bc6765, 0xaa09c88b, 0x12b5afee, 0x8f629757, 0x37def032, 0x256b5fdc, + 0x9dd738b9, 0xc5b428ef, 0x7d084f8a, 0x6fbde064, 0xd7018701, 0x4ad6bfb8, + 0xf26ad8dd, 0xe0df7733, 0x58631056, 0x5019579f, 0xe8a530fa, 0xfa109f14, + 0x42acf871, 0xdf7bc0c8, 0x67c7a7ad, 0x75720843, 0xcdce6f26, 0x95ad7f70, + 0x2d111815, 0x3fa4b7fb, 0x8718d09e, 0x1acfe827, 0xa2738f42, 0xb0c620ac, + 0x087a47c9, 0xa032af3e, 0x188ec85b, 0x0a3b67b5, 0xb28700d0, 0x2f503869, + 0x97ec5f0c, 0x8559f0e2, 0x3de59787, 0x658687d1, 0xdd3ae0b4, 0xcf8f4f5a, + 0x7733283f, 0xeae41086, 0x525877e3, 0x40edd80d, 0xf851bf68, 0xf02bf8a1, + 0x48979fc4, 0x5a22302a, 0xe29e574f, 0x7f496ff6, 0xc7f50893, 0xd540a77d, + 0x6dfcc018, 0x359fd04e, 0x8d23b72b, 0x9f9618c5, 0x272a7fa0, 0xbafd4719, + 0x0241207c, 0x10f48f92, 0xa848e8f7, 0x9b14583d, 0x23a83f58, 0x311d90b6, + 0x89a1f7d3, 0x1476cf6a, 0xaccaa80f, 0xbe7f07e1, 0x06c36084, 0x5ea070d2, + 0xe61c17b7, 0xf4a9b859, 0x4c15df3c, 0xd1c2e785, 0x697e80e0, 0x7bcb2f0e, + 0xc377486b, 0xcb0d0fa2, 0x73b168c7, 0x6104c729, 0xd9b8a04c, 0x446f98f5, + 0xfcd3ff90, 0xee66507e, 0x56da371b, 0x0eb9274d, 0xb6054028, 0xa4b0efc6, + 0x1c0c88a3, 0x81dbb01a, 0x3967d77f, 0x2bd27891, 0x936e1ff4, 0x3b26f703, + 0x839a9066, 0x912f3f88, 0x299358ed, 0xb4446054, 0x0cf80731, 0x1e4da8df, + 0xa6f1cfba, 0xfe92dfec, 0x462eb889, 0x549b1767, 0xec277002, 0x71f048bb, + 0xc94c2fde, 0xdbf98030, 0x6345e755, 0x6b3fa09c, 0xd383c7f9, 0xc1366817, + 0x798a0f72, 0xe45d37cb, 0x5ce150ae, 0x4e54ff40, 0xf6e89825, 0xae8b8873, + 0x1637ef16, 0x048240f8, 0xbc3e279d, 0x21e91f24, 0x99557841, 0x8be0d7af, + 0x335cb0ca, 0xed59b63b, 0x55e5d15e, 0x47507eb0, 0xffec19d5, 0x623b216c, + 0xda874609, 0xc832e9e7, 0x708e8e82, 0x28ed9ed4, 0x9051f9b1, 0x82e4565f, + 0x3a58313a, 0xa78f0983, 0x1f336ee6, 0x0d86c108, 0xb53aa66d, 0xbd40e1a4, + 0x05fc86c1, 0x1749292f, 0xaff54e4a, 0x322276f3, 0x8a9e1196, 0x982bbe78, + 0x2097d91d, 0x78f4c94b, 0xc048ae2e, 0xd2fd01c0, 0x6a4166a5, 0xf7965e1c, + 0x4f2a3979, 0x5d9f9697, 0xe523f1f2, 0x4d6b1905, 0xf5d77e60, 0xe762d18e, + 0x5fdeb6eb, 0xc2098e52, 0x7ab5e937, 0x680046d9, 0xd0bc21bc, 0x88df31ea, + 0x3063568f, 0x22d6f961, 0x9a6a9e04, 0x07bda6bd, 0xbf01c1d8, 0xadb46e36, + 0x15080953, 0x1d724e9a, 0xa5ce29ff, 0xb77b8611, 0x0fc7e174, 0x9210d9cd, + 0x2aacbea8, 0x38191146, 0x80a57623, 0xd8c66675, 0x607a0110, 0x72cfaefe, + 0xca73c99b, 0x57a4f122, 0xef189647, 0xfdad39a9, 0x45115ecc, 0x764dee06, + 0xcef18963, 0xdc44268d, 0x64f841e8, 0xf92f7951, 0x41931e34, 0x5326b1da, + 0xeb9ad6bf, 0xb3f9c6e9, 0x0b45a18c, 0x19f00e62, 0xa14c6907, 0x3c9b51be, + 0x842736db, 0x96929935, 0x2e2efe50, 0x2654b999, 0x9ee8defc, 0x8c5d7112, + 0x34e11677, 0xa9362ece, 0x118a49ab, 0x033fe645, 0xbb838120, 0xe3e09176, + 0x5b5cf613, 0x49e959fd, 0xf1553e98, 0x6c820621, 0xd43e6144, 0xc68bceaa, + 0x7e37a9cf, 0xd67f4138, 0x6ec3265d, 0x7c7689b3, 0xc4caeed6, 0x591dd66f, + 0xe1a1b10a, 0xf3141ee4, 0x4ba87981, 0x13cb69d7, 0xab770eb2, 0xb9c2a15c, + 0x017ec639, 0x9ca9fe80, 0x241599e5, 0x36a0360b, 0x8e1c516e, 0x866616a7, + 0x3eda71c2, 0x2c6fde2c, 0x94d3b949, 0x090481f0, 0xb1b8e695, 0xa30d497b, + 0x1bb12e1e, 0x43d23e48, 0xfb6e592d, 0xe9dbf6c3, 0x516791a6, 0xccb0a91f, + 0x740cce7a, 0x66b96194, 0xde0506f1}, + + {0x00000000, 0x3d6029b0, 0x7ac05360, 0x47a07ad0, 0xf580a6c0, 0xc8e08f70, 0x8f40f5a0, + 0xb220dc10, 0x30704bc1, 0x0d106271, 0x4ab018a1, 0x77d03111, 0xc5f0ed01, + 0xf890c4b1, 0xbf30be61, 0x825097d1, 0x60e09782, 0x5d80be32, 0x1a20c4e2, + 0x2740ed52, 0x95603142, 0xa80018f2, 0xefa06222, 0xd2c04b92, 0x5090dc43, + 0x6df0f5f3, 0x2a508f23, 0x1730a693, 0xa5107a83, 0x98705333, 0xdfd029e3, + 0xe2b00053, 0xc1c12f04, 0xfca106b4, 0xbb017c64, 0x866155d4, 0x344189c4, + 0x0921a074, 0x4e81daa4, 0x73e1f314, 0xf1b164c5, 0xccd14d75, 0x8b7137a5, + 0xb6111e15, 0x0431c205, 0x3951ebb5, 0x7ef19165, 0x4391b8d5, 0xa121b886, + 0x9c419136, 0xdbe1ebe6, 0xe681c256, 0x54a11e46, 0x69c137f6, 0x2e614d26, + 0x13016496, 0x9151f347, 0xac31daf7, 0xeb91a027, 0xd6f18997, 0x64d15587, + 0x59b17c37, 0x1e1106e7, 0x23712f57, 0x58f35849, 0x659371f9, 0x22330b29, + 0x1f532299, 0xad73fe89, 0x9013d739, 0xd7b3ade9, 0xead38459, 0x68831388, + 0x55e33a38, 0x124340e8, 0x2f236958, 0x9d03b548, 0xa0639cf8, 0xe7c3e628, + 0xdaa3cf98, 0x3813cfcb, 0x0573e67b, 0x42d39cab, 0x7fb3b51b, 0xcd93690b, + 0xf0f340bb, 0xb7533a6b, 0x8a3313db, 0x0863840a, 0x3503adba, 0x72a3d76a, + 0x4fc3feda, 0xfde322ca, 0xc0830b7a, 0x872371aa, 0xba43581a, 0x9932774d, + 0xa4525efd, 0xe3f2242d, 0xde920d9d, 0x6cb2d18d, 0x51d2f83d, 0x167282ed, + 0x2b12ab5d, 0xa9423c8c, 0x9422153c, 0xd3826fec, 0xeee2465c, 0x5cc29a4c, + 0x61a2b3fc, 0x2602c92c, 0x1b62e09c, 0xf9d2e0cf, 0xc4b2c97f, 0x8312b3af, + 0xbe729a1f, 0x0c52460f, 0x31326fbf, 0x7692156f, 0x4bf23cdf, 0xc9a2ab0e, + 0xf4c282be, 0xb362f86e, 0x8e02d1de, 0x3c220dce, 0x0142247e, 0x46e25eae, + 0x7b82771e, 0xb1e6b092, 0x8c869922, 0xcb26e3f2, 0xf646ca42, 0x44661652, + 0x79063fe2, 0x3ea64532, 0x03c66c82, 0x8196fb53, 0xbcf6d2e3, 0xfb56a833, + 0xc6368183, 0x74165d93, 0x49767423, 0x0ed60ef3, 0x33b62743, 0xd1062710, + 0xec660ea0, 0xabc67470, 0x96a65dc0, 0x248681d0, 0x19e6a860, 0x5e46d2b0, + 0x6326fb00, 0xe1766cd1, 0xdc164561, 0x9bb63fb1, 0xa6d61601, 0x14f6ca11, + 0x2996e3a1, 0x6e369971, 0x5356b0c1, 0x70279f96, 0x4d47b626, 0x0ae7ccf6, + 0x3787e546, 0x85a73956, 0xb8c710e6, 0xff676a36, 0xc2074386, 0x4057d457, + 0x7d37fde7, 0x3a978737, 0x07f7ae87, 0xb5d77297, 0x88b75b27, 0xcf1721f7, + 0xf2770847, 0x10c70814, 0x2da721a4, 0x6a075b74, 0x576772c4, 0xe547aed4, + 0xd8278764, 0x9f87fdb4, 0xa2e7d404, 0x20b743d5, 0x1dd76a65, 0x5a7710b5, + 0x67173905, 0xd537e515, 0xe857cca5, 0xaff7b675, 0x92979fc5, 0xe915e8db, + 0xd475c16b, 0x93d5bbbb, 0xaeb5920b, 0x1c954e1b, 0x21f567ab, 0x66551d7b, + 0x5b3534cb, 0xd965a31a, 0xe4058aaa, 0xa3a5f07a, 0x9ec5d9ca, 0x2ce505da, + 0x11852c6a, 0x562556ba, 0x6b457f0a, 0x89f57f59, 0xb49556e9, 0xf3352c39, + 0xce550589, 0x7c75d999, 0x4115f029, 0x06b58af9, 0x3bd5a349, 0xb9853498, + 0x84e51d28, 0xc34567f8, 0xfe254e48, 0x4c059258, 0x7165bbe8, 0x36c5c138, + 0x0ba5e888, 0x28d4c7df, 0x15b4ee6f, 0x521494bf, 0x6f74bd0f, 0xdd54611f, + 0xe03448af, 0xa794327f, 0x9af41bcf, 0x18a48c1e, 0x25c4a5ae, 0x6264df7e, + 0x5f04f6ce, 0xed242ade, 0xd044036e, 0x97e479be, 0xaa84500e, 0x4834505d, + 0x755479ed, 0x32f4033d, 0x0f942a8d, 0xbdb4f69d, 0x80d4df2d, 0xc774a5fd, + 0xfa148c4d, 0x78441b9c, 0x4524322c, 0x028448fc, 0x3fe4614c, 0x8dc4bd5c, + 0xb0a494ec, 0xf704ee3c, 0xca64c78c}, + + {0x00000000, 0xcb5cd3a5, 0x4dc8a10b, 0x869472ae, 0x9b914216, 0x50cd91b3, 0xd659e31d, + 0x1d0530b8, 0xec53826d, 0x270f51c8, 0xa19b2366, 0x6ac7f0c3, 0x77c2c07b, + 0xbc9e13de, 0x3a0a6170, 0xf156b2d5, 0x03d6029b, 0xc88ad13e, 0x4e1ea390, + 0x85427035, 0x9847408d, 0x531b9328, 0xd58fe186, 0x1ed33223, 0xef8580f6, + 0x24d95353, 0xa24d21fd, 0x6911f258, 0x7414c2e0, 0xbf481145, 0x39dc63eb, + 0xf280b04e, 0x07ac0536, 0xccf0d693, 0x4a64a43d, 0x81387798, 0x9c3d4720, + 0x57619485, 0xd1f5e62b, 0x1aa9358e, 0xebff875b, 0x20a354fe, 0xa6372650, + 0x6d6bf5f5, 0x706ec54d, 0xbb3216e8, 0x3da66446, 0xf6fab7e3, 0x047a07ad, + 0xcf26d408, 0x49b2a6a6, 0x82ee7503, 0x9feb45bb, 0x54b7961e, 0xd223e4b0, + 0x197f3715, 0xe82985c0, 0x23755665, 0xa5e124cb, 0x6ebdf76e, 0x73b8c7d6, + 0xb8e41473, 0x3e7066dd, 0xf52cb578, 0x0f580a6c, 0xc404d9c9, 0x4290ab67, + 0x89cc78c2, 0x94c9487a, 0x5f959bdf, 0xd901e971, 0x125d3ad4, 0xe30b8801, + 0x28575ba4, 0xaec3290a, 0x659ffaaf, 0x789aca17, 0xb3c619b2, 0x35526b1c, + 0xfe0eb8b9, 0x0c8e08f7, 0xc7d2db52, 0x4146a9fc, 0x8a1a7a59, 0x971f4ae1, + 0x5c439944, 0xdad7ebea, 0x118b384f, 0xe0dd8a9a, 0x2b81593f, 0xad152b91, + 0x6649f834, 0x7b4cc88c, 0xb0101b29, 0x36846987, 0xfdd8ba22, 0x08f40f5a, + 0xc3a8dcff, 0x453cae51, 0x8e607df4, 0x93654d4c, 0x58399ee9, 0xdeadec47, + 0x15f13fe2, 0xe4a78d37, 0x2ffb5e92, 0xa96f2c3c, 0x6233ff99, 0x7f36cf21, + 0xb46a1c84, 0x32fe6e2a, 0xf9a2bd8f, 0x0b220dc1, 0xc07ede64, 0x46eaacca, + 0x8db67f6f, 0x90b34fd7, 0x5bef9c72, 0xdd7beedc, 0x16273d79, 0xe7718fac, + 0x2c2d5c09, 0xaab92ea7, 0x61e5fd02, 0x7ce0cdba, 0xb7bc1e1f, 0x31286cb1, + 0xfa74bf14, 0x1eb014d8, 0xd5ecc77d, 0x5378b5d3, 0x98246676, 0x852156ce, + 0x4e7d856b, 0xc8e9f7c5, 0x03b52460, 0xf2e396b5, 0x39bf4510, 0xbf2b37be, + 0x7477e41b, 0x6972d4a3, 0xa22e0706, 0x24ba75a8, 0xefe6a60d, 0x1d661643, + 0xd63ac5e6, 0x50aeb748, 0x9bf264ed, 0x86f75455, 0x4dab87f0, 0xcb3ff55e, + 0x006326fb, 0xf135942e, 0x3a69478b, 0xbcfd3525, 0x77a1e680, 0x6aa4d638, + 0xa1f8059d, 0x276c7733, 0xec30a496, 0x191c11ee, 0xd240c24b, 0x54d4b0e5, + 0x9f886340, 0x828d53f8, 0x49d1805d, 0xcf45f2f3, 0x04192156, 0xf54f9383, + 0x3e134026, 0xb8873288, 0x73dbe12d, 0x6eded195, 0xa5820230, 0x2316709e, + 0xe84aa33b, 0x1aca1375, 0xd196c0d0, 0x5702b27e, 0x9c5e61db, 0x815b5163, + 0x4a0782c6, 0xcc93f068, 0x07cf23cd, 0xf6999118, 0x3dc542bd, 0xbb513013, + 0x700de3b6, 0x6d08d30e, 0xa65400ab, 0x20c07205, 0xeb9ca1a0, 0x11e81eb4, + 0xdab4cd11, 0x5c20bfbf, 0x977c6c1a, 0x8a795ca2, 0x41258f07, 0xc7b1fda9, + 0x0ced2e0c, 0xfdbb9cd9, 0x36e74f7c, 0xb0733dd2, 0x7b2fee77, 0x662adecf, + 0xad760d6a, 0x2be27fc4, 0xe0beac61, 0x123e1c2f, 0xd962cf8a, 0x5ff6bd24, + 0x94aa6e81, 0x89af5e39, 0x42f38d9c, 0xc467ff32, 0x0f3b2c97, 0xfe6d9e42, + 0x35314de7, 0xb3a53f49, 0x78f9ecec, 0x65fcdc54, 0xaea00ff1, 0x28347d5f, + 0xe368aefa, 0x16441b82, 0xdd18c827, 0x5b8cba89, 0x90d0692c, 0x8dd55994, + 0x46898a31, 0xc01df89f, 0x0b412b3a, 0xfa1799ef, 0x314b4a4a, 0xb7df38e4, + 0x7c83eb41, 0x6186dbf9, 0xaada085c, 0x2c4e7af2, 0xe712a957, 0x15921919, + 0xdececabc, 0x585ab812, 0x93066bb7, 0x8e035b0f, 0x455f88aa, 0xc3cbfa04, + 0x089729a1, 0xf9c19b74, 0x329d48d1, 0xb4093a7f, 0x7f55e9da, 0x6250d962, + 0xa90c0ac7, 0x2f987869, 0xe4c4abcc}, + + {0x00000000, 0xa6770bb4, 0x979f1129, 0x31e81a9d, 0xf44f2413, 0x52382fa7, 0x63d0353a, + 0xc5a73e8e, 0x33ef4e67, 0x959845d3, 0xa4705f4e, 0x020754fa, 0xc7a06a74, + 0x61d761c0, 0x503f7b5d, 0xf64870e9, 0x67de9cce, 0xc1a9977a, 0xf0418de7, + 0x56368653, 0x9391b8dd, 0x35e6b369, 0x040ea9f4, 0xa279a240, 0x5431d2a9, + 0xf246d91d, 0xc3aec380, 0x65d9c834, 0xa07ef6ba, 0x0609fd0e, 0x37e1e793, + 0x9196ec27, 0xcfbd399c, 0x69ca3228, 0x582228b5, 0xfe552301, 0x3bf21d8f, + 0x9d85163b, 0xac6d0ca6, 0x0a1a0712, 0xfc5277fb, 0x5a257c4f, 0x6bcd66d2, + 0xcdba6d66, 0x081d53e8, 0xae6a585c, 0x9f8242c1, 0x39f54975, 0xa863a552, + 0x0e14aee6, 0x3ffcb47b, 0x998bbfcf, 0x5c2c8141, 0xfa5b8af5, 0xcbb39068, + 0x6dc49bdc, 0x9b8ceb35, 0x3dfbe081, 0x0c13fa1c, 0xaa64f1a8, 0x6fc3cf26, + 0xc9b4c492, 0xf85cde0f, 0x5e2bd5bb, 0x440b7579, 0xe27c7ecd, 0xd3946450, + 0x75e36fe4, 0xb044516a, 0x16335ade, 0x27db4043, 0x81ac4bf7, 0x77e43b1e, + 0xd19330aa, 0xe07b2a37, 0x460c2183, 0x83ab1f0d, 0x25dc14b9, 0x14340e24, + 0xb2430590, 0x23d5e9b7, 0x85a2e203, 0xb44af89e, 0x123df32a, 0xd79acda4, + 0x71edc610, 0x4005dc8d, 0xe672d739, 0x103aa7d0, 0xb64dac64, 0x87a5b6f9, + 0x21d2bd4d, 0xe47583c3, 0x42028877, 0x73ea92ea, 0xd59d995e, 0x8bb64ce5, + 0x2dc14751, 0x1c295dcc, 0xba5e5678, 0x7ff968f6, 0xd98e6342, 0xe86679df, + 0x4e11726b, 0xb8590282, 0x1e2e0936, 0x2fc613ab, 0x89b1181f, 0x4c162691, + 0xea612d25, 0xdb8937b8, 0x7dfe3c0c, 0xec68d02b, 0x4a1fdb9f, 0x7bf7c102, + 0xdd80cab6, 0x1827f438, 0xbe50ff8c, 0x8fb8e511, 0x29cfeea5, 0xdf879e4c, + 0x79f095f8, 0x48188f65, 0xee6f84d1, 0x2bc8ba5f, 0x8dbfb1eb, 0xbc57ab76, + 0x1a20a0c2, 0x8816eaf2, 0x2e61e146, 0x1f89fbdb, 0xb9fef06f, 0x7c59cee1, + 0xda2ec555, 0xebc6dfc8, 0x4db1d47c, 0xbbf9a495, 0x1d8eaf21, 0x2c66b5bc, + 0x8a11be08, 0x4fb68086, 0xe9c18b32, 0xd82991af, 0x7e5e9a1b, 0xefc8763c, + 0x49bf7d88, 0x78576715, 0xde206ca1, 0x1b87522f, 0xbdf0599b, 0x8c184306, + 0x2a6f48b2, 0xdc27385b, 0x7a5033ef, 0x4bb82972, 0xedcf22c6, 0x28681c48, + 0x8e1f17fc, 0xbff70d61, 0x198006d5, 0x47abd36e, 0xe1dcd8da, 0xd034c247, + 0x7643c9f3, 0xb3e4f77d, 0x1593fcc9, 0x247be654, 0x820cede0, 0x74449d09, + 0xd23396bd, 0xe3db8c20, 0x45ac8794, 0x800bb91a, 0x267cb2ae, 0x1794a833, + 0xb1e3a387, 0x20754fa0, 0x86024414, 0xb7ea5e89, 0x119d553d, 0xd43a6bb3, + 0x724d6007, 0x43a57a9a, 0xe5d2712e, 0x139a01c7, 0xb5ed0a73, 0x840510ee, + 0x22721b5a, 0xe7d525d4, 0x41a22e60, 0x704a34fd, 0xd63d3f49, 0xcc1d9f8b, + 0x6a6a943f, 0x5b828ea2, 0xfdf58516, 0x3852bb98, 0x9e25b02c, 0xafcdaab1, + 0x09baa105, 0xfff2d1ec, 0x5985da58, 0x686dc0c5, 0xce1acb71, 0x0bbdf5ff, + 0xadcafe4b, 0x9c22e4d6, 0x3a55ef62, 0xabc30345, 0x0db408f1, 0x3c5c126c, + 0x9a2b19d8, 0x5f8c2756, 0xf9fb2ce2, 0xc813367f, 0x6e643dcb, 0x982c4d22, + 0x3e5b4696, 0x0fb35c0b, 0xa9c457bf, 0x6c636931, 0xca146285, 0xfbfc7818, + 0x5d8b73ac, 0x03a0a617, 0xa5d7ada3, 0x943fb73e, 0x3248bc8a, 0xf7ef8204, + 0x519889b0, 0x6070932d, 0xc6079899, 0x304fe870, 0x9638e3c4, 0xa7d0f959, + 0x01a7f2ed, 0xc400cc63, 0x6277c7d7, 0x539fdd4a, 0xf5e8d6fe, 0x647e3ad9, + 0xc209316d, 0xf3e12bf0, 0x55962044, 0x90311eca, 0x3646157e, 0x07ae0fe3, + 0xa1d90457, 0x579174be, 0xf1e67f0a, 0xc00e6597, 0x66796e23, 0xa3de50ad, + 0x05a95b19, 0x34414184, 0x92364a30}, + + {0x00000000, 0xccaa009e, 0x4225077d, 0x8e8f07e3, 0x844a0efa, 0x48e00e64, 0xc66f0987, + 0x0ac50919, 0xd3e51bb5, 0x1f4f1b2b, 0x91c01cc8, 0x5d6a1c56, 0x57af154f, + 0x9b0515d1, 0x158a1232, 0xd92012ac, 0x7cbb312b, 0xb01131b5, 0x3e9e3656, + 0xf23436c8, 0xf8f13fd1, 0x345b3f4f, 0xbad438ac, 0x767e3832, 0xaf5e2a9e, + 0x63f42a00, 0xed7b2de3, 0x21d12d7d, 0x2b142464, 0xe7be24fa, 0x69312319, + 0xa59b2387, 0xf9766256, 0x35dc62c8, 0xbb53652b, 0x77f965b5, 0x7d3c6cac, + 0xb1966c32, 0x3f196bd1, 0xf3b36b4f, 0x2a9379e3, 0xe639797d, 0x68b67e9e, + 0xa41c7e00, 0xaed97719, 0x62737787, 0xecfc7064, 0x205670fa, 0x85cd537d, + 0x496753e3, 0xc7e85400, 0x0b42549e, 0x01875d87, 0xcd2d5d19, 0x43a25afa, + 0x8f085a64, 0x562848c8, 0x9a824856, 0x140d4fb5, 0xd8a74f2b, 0xd2624632, + 0x1ec846ac, 0x9047414f, 0x5ced41d1, 0x299dc2ed, 0xe537c273, 0x6bb8c590, + 0xa712c50e, 0xadd7cc17, 0x617dcc89, 0xeff2cb6a, 0x2358cbf4, 0xfa78d958, + 0x36d2d9c6, 0xb85dde25, 0x74f7debb, 0x7e32d7a2, 0xb298d73c, 0x3c17d0df, + 0xf0bdd041, 0x5526f3c6, 0x998cf358, 0x1703f4bb, 0xdba9f425, 0xd16cfd3c, + 0x1dc6fda2, 0x9349fa41, 0x5fe3fadf, 0x86c3e873, 0x4a69e8ed, 0xc4e6ef0e, + 0x084cef90, 0x0289e689, 0xce23e617, 0x40ace1f4, 0x8c06e16a, 0xd0eba0bb, + 0x1c41a025, 0x92cea7c6, 0x5e64a758, 0x54a1ae41, 0x980baedf, 0x1684a93c, + 0xda2ea9a2, 0x030ebb0e, 0xcfa4bb90, 0x412bbc73, 0x8d81bced, 0x8744b5f4, + 0x4beeb56a, 0xc561b289, 0x09cbb217, 0xac509190, 0x60fa910e, 0xee7596ed, + 0x22df9673, 0x281a9f6a, 0xe4b09ff4, 0x6a3f9817, 0xa6959889, 0x7fb58a25, + 0xb31f8abb, 0x3d908d58, 0xf13a8dc6, 0xfbff84df, 0x37558441, 0xb9da83a2, + 0x7570833c, 0x533b85da, 0x9f918544, 0x111e82a7, 0xddb48239, 0xd7718b20, + 0x1bdb8bbe, 0x95548c5d, 0x59fe8cc3, 0x80de9e6f, 0x4c749ef1, 0xc2fb9912, + 0x0e51998c, 0x04949095, 0xc83e900b, 0x46b197e8, 0x8a1b9776, 0x2f80b4f1, + 0xe32ab46f, 0x6da5b38c, 0xa10fb312, 0xabcaba0b, 0x6760ba95, 0xe9efbd76, + 0x2545bde8, 0xfc65af44, 0x30cfafda, 0xbe40a839, 0x72eaa8a7, 0x782fa1be, + 0xb485a120, 0x3a0aa6c3, 0xf6a0a65d, 0xaa4de78c, 0x66e7e712, 0xe868e0f1, + 0x24c2e06f, 0x2e07e976, 0xe2ade9e8, 0x6c22ee0b, 0xa088ee95, 0x79a8fc39, + 0xb502fca7, 0x3b8dfb44, 0xf727fbda, 0xfde2f2c3, 0x3148f25d, 0xbfc7f5be, + 0x736df520, 0xd6f6d6a7, 0x1a5cd639, 0x94d3d1da, 0x5879d144, 0x52bcd85d, + 0x9e16d8c3, 0x1099df20, 0xdc33dfbe, 0x0513cd12, 0xc9b9cd8c, 0x4736ca6f, + 0x8b9ccaf1, 0x8159c3e8, 0x4df3c376, 0xc37cc495, 0x0fd6c40b, 0x7aa64737, + 0xb60c47a9, 0x3883404a, 0xf42940d4, 0xfeec49cd, 0x32464953, 0xbcc94eb0, + 0x70634e2e, 0xa9435c82, 0x65e95c1c, 0xeb665bff, 0x27cc5b61, 0x2d095278, + 0xe1a352e6, 0x6f2c5505, 0xa386559b, 0x061d761c, 0xcab77682, 0x44387161, + 0x889271ff, 0x825778e6, 0x4efd7878, 0xc0727f9b, 0x0cd87f05, 0xd5f86da9, + 0x19526d37, 0x97dd6ad4, 0x5b776a4a, 0x51b26353, 0x9d1863cd, 0x1397642e, + 0xdf3d64b0, 0x83d02561, 0x4f7a25ff, 0xc1f5221c, 0x0d5f2282, 0x079a2b9b, + 0xcb302b05, 0x45bf2ce6, 0x89152c78, 0x50353ed4, 0x9c9f3e4a, 0x121039a9, + 0xdeba3937, 0xd47f302e, 0x18d530b0, 0x965a3753, 0x5af037cd, 0xff6b144a, + 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, + 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, + 0x646e019b, 0xeae10678, 0x264b06e6}} + +type dm_build_828 interface { + dm_build_829() + dm_build_830() error + dm_build_831() + dm_build_832(imsg dm_build_828) error + dm_build_833() error + dm_build_834() (interface{}, error) + dm_build_835() + dm_build_836(imsg dm_build_828) (interface{}, error) + dm_build_837() + dm_build_838() error + dm_build_839() byte + dm_build_840(buffer *Dm_build_78, startOff int32, endOff int32) uint32 + dm_build_841() int32 + dm_build_842(length int32) + dm_build_843() int16 +} + +type dm_build_844 struct { + dm_build_845 *dm_build_414 + + dm_build_846 int16 + + dm_build_847 int32 + + dm_build_848 *DmStatement +} + +func (dm_build_850 *dm_build_844) dm_build_849(dm_build_851 *dm_build_414, dm_build_852 int16) *dm_build_844 { + dm_build_850.dm_build_845 = dm_build_851 + dm_build_850.dm_build_846 = dm_build_852 + return dm_build_850 +} + +func (dm_build_854 *dm_build_844) dm_build_853(dm_build_855 *dm_build_414, dm_build_856 int16, dm_build_857 *DmStatement) *dm_build_844 { + dm_build_854.dm_build_849(dm_build_855, dm_build_856).dm_build_848 = dm_build_857 + return dm_build_854 +} + +func dm_build_858(dm_build_859 *dm_build_414, dm_build_860 int16) *dm_build_844 { + return new(dm_build_844).dm_build_849(dm_build_859, dm_build_860) +} + +func dm_build_861(dm_build_862 *dm_build_414, dm_build_863 int16, dm_build_864 *DmStatement) *dm_build_844 { + return new(dm_build_844).dm_build_853(dm_build_862, dm_build_863, dm_build_864) +} + +func (dm_build_866 *dm_build_844) dm_build_829() { + dm_build_866.dm_build_845.dm_build_417.Dm_build_92(0) + dm_build_866.dm_build_845.dm_build_417.Dm_build_103(Dm_build_736, true, true) +} + +func (dm_build_868 *dm_build_844) dm_build_830() error { + return nil +} + +func (dm_build_870 *dm_build_844) dm_build_831() { + if dm_build_870.dm_build_848 == nil { + dm_build_870.dm_build_845.dm_build_417.Dm_build_273(Dm_build_738, 0) + } else { + dm_build_870.dm_build_845.dm_build_417.Dm_build_273(Dm_build_738, dm_build_870.dm_build_848.id) + } + + dm_build_870.dm_build_845.dm_build_417.Dm_build_269(Dm_build_739, dm_build_870.dm_build_846) + dm_build_870.dm_build_845.dm_build_417.Dm_build_273(Dm_build_740, int32(dm_build_870.dm_build_845.dm_build_417.Dm_build_90()-Dm_build_736)) +} + +func (dm_build_872 *dm_build_844) dm_build_833() error { + dm_build_872.dm_build_845.dm_build_417.Dm_build_95(0) + dm_build_872.dm_build_845.dm_build_417.Dm_build_103(Dm_build_736, false, true) + return dm_build_872.dm_build_877() +} + +func (dm_build_874 *dm_build_844) dm_build_834() (interface{}, error) { + return nil, nil +} + +func (dm_build_876 *dm_build_844) dm_build_835() { +} + +func (dm_build_878 *dm_build_844) dm_build_877() error { + dm_build_878.dm_build_847 = dm_build_878.dm_build_845.dm_build_417.Dm_build_351(Dm_build_741) + if dm_build_878.dm_build_847 < 0 && dm_build_878.dm_build_847 != EC_RN_EXCEED_ROWSET_SIZE.ErrCode { + return (&DmError{dm_build_878.dm_build_847, dm_build_878.dm_build_879(), nil, ""}).throw() + } else if dm_build_878.dm_build_847 > 0 { + + } else if dm_build_878.dm_build_846 == Dm_build_735 || dm_build_878.dm_build_846 == Dm_build_709 { + dm_build_878.dm_build_879() + } + + return nil +} + +func (dm_build_880 *dm_build_844) dm_build_879() string { + + dm_build_881 := dm_build_880.dm_build_845.dm_build_418.getServerEncoding() + + if Locale != LANGUAGE_EN && dm_build_881 == ENCODING_EUCKR { + dm_build_881 = ENCODING_GB18030 + } + + if Locale == LANGUAGE_CNT_HK && dm_build_881 != ENCODING_UTF8 { + dm_build_881 = ENCODING_BIG5 + } + + dm_build_880.dm_build_845.dm_build_417.Dm_build_103(int(dm_build_880.dm_build_845.dm_build_417.Dm_build_207()), false, true) + + dm_build_880.dm_build_845.dm_build_417.Dm_build_103(int(dm_build_880.dm_build_845.dm_build_417.Dm_build_207()), false, true) + + dm_build_880.dm_build_845.dm_build_417.Dm_build_103(int(dm_build_880.dm_build_845.dm_build_417.Dm_build_207()), false, true) + + return dm_build_880.dm_build_845.dm_build_417.Dm_build_249(dm_build_881, dm_build_880.dm_build_845.dm_build_418) +} + +func (dm_build_883 *dm_build_844) dm_build_832(dm_build_884 dm_build_828) (dm_build_885 error) { + dm_build_884.dm_build_829() + if dm_build_885 = dm_build_884.dm_build_830(); dm_build_885 != nil { + return dm_build_885 + } + dm_build_884.dm_build_831() + return nil +} + +func (dm_build_887 *dm_build_844) dm_build_836(dm_build_888 dm_build_828) (dm_build_889 interface{}, dm_build_890 error) { + dm_build_890 = dm_build_888.dm_build_833() + if dm_build_890 != nil { + return nil, dm_build_890 + } + dm_build_889, dm_build_890 = dm_build_888.dm_build_834() + if dm_build_890 != nil { + return nil, dm_build_890 + } + dm_build_888.dm_build_835() + return dm_build_889, nil +} + +func (dm_build_892 *dm_build_844) dm_build_837() { + if dm_build_892.dm_build_845.dm_build_423 { + + var orgLen = dm_build_892.dm_build_841() + + dm_build_892.dm_build_842(orgLen + Dm_build_826) + var crc = dm_build_892.dm_build_840(dm_build_892.dm_build_845.dm_build_417, 0, Dm_build_736+orgLen) + dm_build_892.dm_build_845.dm_build_417.Dm_build_145(crc) + } else { + dm_build_892.dm_build_845.dm_build_417.Dm_build_265(Dm_build_744, dm_build_892.dm_build_839()) + } +} + +func (dm_build_894 *dm_build_844) dm_build_838() error { + if dm_build_894.dm_build_845.dm_build_423 { + + var bodyLen = dm_build_894.dm_build_841() - Dm_build_826 + var msgLen = Dm_build_736 + bodyLen + var recv = dm_build_894.dm_build_845.dm_build_417.Dm_build_369(int(msgLen)) + var calc = dm_build_894.dm_build_840(dm_build_894.dm_build_845.dm_build_417, 0, msgLen) + if recv != calc { + return ECGO_MSG_CHECK_ERROR.throw() + } + + dm_build_894.dm_build_842(bodyLen) + dm_build_894.dm_build_845.dm_build_417.Dm_build_92(int(msgLen)) + return nil + } else { + var recv = dm_build_894.dm_build_845.dm_build_417.Dm_build_345(Dm_build_744) + var calc = dm_build_894.dm_build_839() + if recv != calc { + return ECGO_MSG_CHECK_ERROR.throw() + } + return nil + } +} + +func (dm_build_896 *dm_build_844) dm_build_839() byte { + dm_build_897 := dm_build_896.dm_build_845.dm_build_417.Dm_build_345(0) + + for i := 1; i < Dm_build_744; i++ { + dm_build_897 ^= dm_build_896.dm_build_845.dm_build_417.Dm_build_345(i) + } + + return dm_build_897 +} + +func (dm_build_899 *dm_build_844) dm_build_840(dm_build_900 *Dm_build_78, dm_build_901 int32, dm_build_902 int32) uint32 { + + var dm_build_903 uint32 = 0xFFFFFFFF + var dm_build_904 = dm_build_901 + var dm_build_905 = dm_build_902 - dm_build_901 + var dm_build_906, dm_build_907 uint32 + + for dm_build_905 >= 8 { + dm_build_906 = dm_build_900.Dm_build_369(int(dm_build_904)) ^ dm_build_903 + dm_build_904 += ULINT_SIZE + + dm_build_907 = dm_build_900.Dm_build_369(int(dm_build_904)) + dm_build_904 += ULINT_SIZE + + dm_build_903 = Dm_build_827[7][dm_build_906&0xFF] ^ Dm_build_827[6][(dm_build_906>>8)&0xFF] ^ + Dm_build_827[5][(dm_build_906>>16)&0xFF] ^ Dm_build_827[4][(dm_build_906>>24)&0xFF] ^ + Dm_build_827[3][dm_build_907&0xFF] ^ Dm_build_827[2][(dm_build_907>>8)&0xFF] ^ + Dm_build_827[1][(dm_build_907>>16)&0xFF] ^ Dm_build_827[0][(dm_build_907>>24)&0xFF] + dm_build_905 -= 8 + } + + for dm_build_905 > 0 { + dm_build_903 = ((dm_build_903 >> 8) & 0x00FFFFFF) ^ Dm_build_827[0][(dm_build_903&0xFF)^uint32(dm_build_900.Dm_build_363(int(dm_build_904)))] + dm_build_904++ + dm_build_905-- + } + return ^dm_build_903 +} + +func (dm_build_909 *dm_build_844) dm_build_841() int32 { + return dm_build_909.dm_build_845.dm_build_417.Dm_build_351(Dm_build_740) +} + +func (dm_build_911 *dm_build_844) dm_build_842(dm_build_912 int32) { + dm_build_911.dm_build_845.dm_build_417.Dm_build_273(Dm_build_740, dm_build_912) +} + +func (dm_build_914 *dm_build_844) dm_build_843() int16 { + return dm_build_914.dm_build_846 +} + +type dm_build_915 struct { + dm_build_844 +} + +func dm_build_916(dm_build_917 *dm_build_414) *dm_build_915 { + dm_build_918 := new(dm_build_915) + dm_build_918.dm_build_849(dm_build_917, Dm_build_716) + return dm_build_918 +} + +type dm_build_919 struct { + dm_build_844 + dm_build_920 string +} + +func dm_build_921(dm_build_922 *dm_build_414, dm_build_923 *DmStatement, dm_build_924 string) *dm_build_919 { + dm_build_925 := new(dm_build_919) + dm_build_925.dm_build_853(dm_build_922, Dm_build_724, dm_build_923) + dm_build_925.dm_build_920 = dm_build_924 + dm_build_925.dm_build_848.cursorName = dm_build_924 + return dm_build_925 +} + +func (dm_build_927 *dm_build_919) dm_build_830() error { + dm_build_927.dm_build_845.dm_build_417.Dm_build_195(dm_build_927.dm_build_920, dm_build_927.dm_build_845.dm_build_418.getServerEncoding(), dm_build_927.dm_build_845.dm_build_418) + dm_build_927.dm_build_845.dm_build_417.Dm_build_133(1) + return nil +} + +const Dm_build_928 = 62 + +type Dm_build_929 struct { + dm_build_952 + dm_build_930 []OptParameter +} + +func dm_build_931(dm_build_932 *dm_build_414, dm_build_933 *DmStatement, dm_build_934 []OptParameter) *Dm_build_929 { + dm_build_935 := new(Dm_build_929) + dm_build_935.dm_build_853(dm_build_932, Dm_build_734, dm_build_933) + dm_build_935.dm_build_930 = dm_build_934 + return dm_build_935 +} + +func (dm_build_937 *Dm_build_929) dm_build_830() error { + dm_build_938 := len(dm_build_937.dm_build_930) + + if err := dm_build_937.dm_build_968(int32(dm_build_938), 1); err != nil { + return err + } + dm_build_937.dm_build_845.dm_build_417.Dm_build_265(Dm_build_928, 0) + + if dm_build_937.dm_build_845.dm_build_418.MsgVersion >= Dm_build_701 { + dm_build_937.dm_build_983() + dm_build_937.dm_build_845.dm_build_417.Dm_build_265(Dm_build_950, byte(dm_build_937.dm_build_955)) + } + + dm_build_937.dm_build_845.dm_build_417.Dm_build_195(dm_build_937.dm_build_848.nativeSql, dm_build_937.dm_build_848.dmConn.getServerEncoding(), dm_build_937.dm_build_848.dmConn) + + for _, param := range dm_build_937.dm_build_930 { + dm_build_937.dm_build_845.dm_build_417.Dm_build_121(param.ioType) + dm_build_937.dm_build_845.dm_build_417.Dm_build_133(int32(param.tp)) + dm_build_937.dm_build_845.dm_build_417.Dm_build_133(int32(param.prec)) + dm_build_937.dm_build_845.dm_build_417.Dm_build_133(int32(param.scale)) + } + + for _, param := range dm_build_937.dm_build_930 { + if param.bytes == nil { + dm_build_937.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_753)) + } else { + var dataBytes = param.bytes[:len(param.bytes)] + if len(dataBytes) > int(Dm_build_750) { + if dm_build_937.dm_build_845.dm_build_418.MsgVersion >= Dm_build_704 && len(dataBytes) < 0xffffffff && + isComplexType(param.tp, param.scale) { + dm_build_937.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_754)) + dm_build_937.dm_build_845.dm_build_417.Dm_build_165(dataBytes) + continue + } + return ECGO_DATA_TOO_LONG.throw() + } + dm_build_937.dm_build_845.dm_build_417.Dm_build_171(dataBytes) + } + } + return nil +} + +func (dm_build_940 *Dm_build_929) dm_build_834() (interface{}, error) { + return dm_build_940.dm_build_952.dm_build_834() +} + +const ( + Dm_build_941 int = 0x01 + + Dm_build_942 int = 0x02 + + Dm_build_943 int = 0x04 + + Dm_build_944 int = 0x08 + + Dm_build_945 int = 0x0100 + + Dm_build_946 int32 = 0x00 + + Dm_build_947 int32 = 0x01 + + Dm_build_948 int32 = 0x02 + + Dm_build_949 int32 = 0x03 + + Dm_build_950 = 48 + + Dm_build_951 = 59 +) + +type dm_build_952 struct { + dm_build_844 + dm_build_953 [][]interface{} + dm_build_954 []parameter + + dm_build_955 int32 + dm_build_956 int32 + dm_build_957 int32 +} + +func dm_build_958(dm_build_959 *dm_build_414, dm_build_960 int16, dm_build_961 *DmStatement) *dm_build_952 { + dm_build_962 := new(dm_build_952) + dm_build_962.dm_build_853(dm_build_959, dm_build_960, dm_build_961) + + return dm_build_962 +} + +func dm_build_963(dm_build_964 *dm_build_414, dm_build_965 *DmStatement, dm_build_966 [][]interface{}) *dm_build_952 { + dm_build_967 := new(dm_build_952) + + if dm_build_964.dm_build_418.Execute2 { + dm_build_967.dm_build_853(dm_build_964, Dm_build_718, dm_build_965) + } else { + dm_build_967.dm_build_853(dm_build_964, Dm_build_714, dm_build_965) + } + + dm_build_967.dm_build_954 = dm_build_965.bindParams + dm_build_967.dm_build_953 = dm_build_966 + + return dm_build_967 +} + +func (dm_build_969 *dm_build_952) dm_build_968(dm_build_970 int32, dm_build_971 int64) error { + + dm_build_972 := Dm_build_737 + + if dm_build_969.dm_build_845.dm_build_418.autoCommit { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 1) + } else { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 0) + } + + if dm_build_970 > PARAM_COUNT_LIMIT { + return ECGO_PARAM_COUNT_LIMIT.throw() + } + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_293(dm_build_972, uint16(dm_build_970)) + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 1) + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_277(dm_build_972, dm_build_971) + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_277(dm_build_972, dm_build_969.dm_build_848.cursorUpdateRow) + + if dm_build_969.dm_build_848.maxRows <= 0 || dm_build_969.dm_build_848.dmConn.dmConnector.enRsCache { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_277(dm_build_972, INT64_MAX) + } else { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_277(dm_build_972, dm_build_969.dm_build_848.maxRows) + } + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 1) + + if dm_build_969.dm_build_845.dm_build_418.dmConnector.continueBatchOnError { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 1) + } else { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 0) + } + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 0) + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 0) + + if dm_build_969.dm_build_848.queryTimeout == 0 { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_273(dm_build_972, -1) + } else { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_273(dm_build_972, dm_build_969.dm_build_848.queryTimeout) + } + + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_273(dm_build_972, dm_build_969.dm_build_845.dm_build_418.dmConnector.batchAllowMaxErrors) + + if dm_build_969.dm_build_848.innerExec { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 1) + } else { + dm_build_972 += dm_build_969.dm_build_845.dm_build_417.Dm_build_265(dm_build_972, 0) + } + return nil +} + +func (dm_build_974 *dm_build_952) dm_build_830() error { + var dm_build_975 int32 + var dm_build_976 int64 + + if dm_build_974.dm_build_954 != nil { + dm_build_975 = int32(len(dm_build_974.dm_build_954)) + } else { + dm_build_975 = 0 + } + + if dm_build_974.dm_build_953 != nil { + dm_build_976 = int64(len(dm_build_974.dm_build_953)) + } else { + dm_build_976 = 0 + } + + if err := dm_build_974.dm_build_968(dm_build_975, dm_build_976); err != nil { + return err + } + + if dm_build_974.dm_build_845.dm_build_418.MsgVersion >= Dm_build_701 { + dm_build_974.dm_build_983() + dm_build_974.dm_build_845.dm_build_417.Dm_build_265(Dm_build_950, byte(dm_build_974.dm_build_955)) + } + + if dm_build_975 > 0 { + err := dm_build_974.dm_build_977(dm_build_974.dm_build_954) + if err != nil { + return err + } + if dm_build_974.dm_build_953 != nil && len(dm_build_974.dm_build_953) > 0 { + for _, paramObject := range dm_build_974.dm_build_953 { + if err := dm_build_974.dm_build_980(paramObject); err != nil { + return err + } + } + } + } + + return nil +} + +func (dm_build_978 *dm_build_952) dm_build_977(dm_build_979 []parameter) error { + for _, param := range dm_build_979 { + if param.mask == MASK_ORACLE_DATE { + + param.scale = param.scale | ORACLE_DATE_SCALE_MASK + } else if param.mask == MASK_LOCAL_DATETIME { + + param.scale = param.scale | LOCAL_DATETIME_SCALE_MASK + } else if param.mask == MASK_ORACLE_FLOAT { + + param.prec = int32(math.Round(float64(param.prec) * 3.32193)) + param.scale = ORACLE_FLOAT_SCALE_MASK + } + + if param.colType == CURSOR && param.ioType == IO_TYPE_OUT { + dm_build_978.dm_build_845.dm_build_417.Dm_build_125(IO_TYPE_INOUT) + } else { + dm_build_978.dm_build_845.dm_build_417.Dm_build_125(param.ioType) + } + + dm_build_978.dm_build_845.dm_build_417.Dm_build_133(param.colType) + + lprec := param.prec + lscale := param.scale + typeDesc := param.typeDescriptor + switch param.colType { + case ARRAY, SARRAY: + tmp, err := getPackArraySize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case PLTYPE_RECORD: + tmp, err := getPackRecordSize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case CLASS: + tmp, err := getPackClassSize(typeDesc) + if err != nil { + return err + } + lprec = int32(tmp) + case BLOB: + if isComplexType(int(param.colType), int(param.scale)) { + lprec = int32(typeDesc.getObjId()) + if lprec == 4 { + lprec = int32(typeDesc.getOuterId()) + } + } + } + + dm_build_978.dm_build_845.dm_build_417.Dm_build_133(lprec) + + dm_build_978.dm_build_845.dm_build_417.Dm_build_133(lscale) + + switch param.colType { + case ARRAY, SARRAY: + err := packArray(typeDesc, dm_build_978.dm_build_845.dm_build_417) + if err != nil { + return err + } + + case PLTYPE_RECORD: + err := packRecord(typeDesc, dm_build_978.dm_build_845.dm_build_417) + if err != nil { + return err + } + + case CLASS: + err := packClass(typeDesc, dm_build_978.dm_build_845.dm_build_417) + if err != nil { + return err + } + + } + } + + return nil +} + +func (dm_build_981 *dm_build_952) dm_build_980(dm_build_982 []interface{}) error { + for i := 0; i < len(dm_build_981.dm_build_954); i++ { + + if dm_build_981.dm_build_954[i].colType == CURSOR { + dm_build_981.dm_build_845.dm_build_417.Dm_build_129(ULINT_SIZE) + dm_build_981.dm_build_845.dm_build_417.Dm_build_133(dm_build_981.dm_build_954[i].cursorStmt.id) + continue + } + + if dm_build_981.dm_build_954[i].ioType == IO_TYPE_OUT { + continue + } + + if dm_build_982[i] == nil { + dm_build_981.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_753)) + } else { + switch dm_build_982[i].(type) { + case []byte: + if dataBytes, ok := dm_build_982[i].([]byte); ok { + if len(dataBytes) > int(Dm_build_750) { + if dm_build_981.dm_build_845.dm_build_418.MsgVersion >= Dm_build_704 && len(dataBytes) < 0xffffffff && + isComplexType(int(dm_build_981.dm_build_954[i].colType), int(dm_build_981.dm_build_954[i].scale)) { + dm_build_981.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_754)) + dm_build_981.dm_build_845.dm_build_417.Dm_build_165(dataBytes) + continue + } + return ECGO_DATA_TOO_LONG.throw() + } + dm_build_981.dm_build_845.dm_build_417.Dm_build_171(dataBytes) + } + case int: + if dm_build_982[i] == ParamDataEnum_Null { + dm_build_981.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_753)) + } else if dm_build_982[i] == ParamDataEnum_OFF_ROW { + dm_build_981.dm_build_845.dm_build_417.Dm_build_129(0) + } + case lobCtl: + dm_build_981.dm_build_845.dm_build_417.Dm_build_141(uint16(Dm_build_751)) + dm_build_981.dm_build_845.dm_build_417.Dm_build_161(dm_build_982[i].(lobCtl).value) + default: + return fmt.Errorf("Bind param data failed by invalid param data type: ") + } + } + } + + return nil +} + +func (dm_build_984 *dm_build_952) dm_build_983() int32 { + dm_build_984.dm_build_955 = Dm_build_947 + dm_build_984.dm_build_956 = 1 + return dm_build_984.dm_build_955 +} + +func (dm_build_986 *dm_build_952) dm_build_834() (interface{}, error) { + dm_build_987 := execRetInfo{} + + dm_build_987.nativeSQL = dm_build_986.dm_build_848.nativeSql + + dm_build_988 := dm_build_986.dm_build_848.dmConn + + dm_build_989 := Dm_build_737 + + dm_build_987.retSqlType = dm_build_986.dm_build_845.dm_build_417.Dm_build_348(dm_build_989) + dm_build_989 += USINT_SIZE + + dm_build_990 := dm_build_986.dm_build_845.dm_build_417.Dm_build_348(dm_build_989) + dm_build_989 += USINT_SIZE + + dm_build_987.updateCount = dm_build_986.dm_build_845.dm_build_417.Dm_build_354(dm_build_989) + dm_build_989 += DDWORD_SIZE + + dm_build_991 := dm_build_986.dm_build_845.dm_build_417.Dm_build_366(dm_build_989) + dm_build_989 += USINT_SIZE + + dm_build_987.rsUpdatable = dm_build_986.dm_build_845.dm_build_417.Dm_build_345(dm_build_989) != 0 + dm_build_989 += BYTE_SIZE + + dm_build_992 := dm_build_986.dm_build_845.dm_build_417.Dm_build_348(dm_build_989) + dm_build_989 += ULINT_SIZE + + dm_build_987.printLen = dm_build_986.dm_build_845.dm_build_417.Dm_build_351(dm_build_989) + dm_build_989 += ULINT_SIZE + + var dm_build_993 int16 = -1 + if dm_build_987.retSqlType == Dm_build_803 || dm_build_987.retSqlType == Dm_build_804 { + dm_build_987.rowid = 0 + + dm_build_987.rsBdta = dm_build_986.dm_build_845.dm_build_417.Dm_build_345(dm_build_989) == Dm_build_816 + dm_build_989 += BYTE_SIZE + + dm_build_993 = dm_build_986.dm_build_845.dm_build_417.Dm_build_348(dm_build_989) + dm_build_989 += USINT_SIZE + dm_build_989 += 5 + } else { + dm_build_987.rowid = dm_build_986.dm_build_845.dm_build_417.Dm_build_354(dm_build_989) + dm_build_989 += DDWORD_SIZE + } + + dm_build_987.execId = dm_build_986.dm_build_845.dm_build_417.Dm_build_351(dm_build_989) + dm_build_989 += ULINT_SIZE + + dm_build_987.rsCacheOffset = dm_build_986.dm_build_845.dm_build_417.Dm_build_351(dm_build_989) + dm_build_989 += ULINT_SIZE + + dm_build_994 := dm_build_986.dm_build_845.dm_build_417.Dm_build_345(dm_build_989) + dm_build_989 += BYTE_SIZE + dm_build_995 := (dm_build_994 & 0x01) == 0x01 + + dm_build_988.TrxStatus = dm_build_986.dm_build_845.dm_build_417.Dm_build_351(dm_build_989) + dm_build_988.setTrxFinish(dm_build_988.TrxStatus) + dm_build_989 += ULINT_SIZE + + if dm_build_987.printLen > 0 { + bytes := dm_build_986.dm_build_845.dm_build_417.Dm_build_228(int(dm_build_987.printLen)) + dm_build_987.printMsg = Dm_build_1346.Dm_build_1503(bytes, 0, len(bytes), dm_build_988.getServerEncoding(), dm_build_988) + } + + if dm_build_991 > 0 { + dm_build_987.outParamDatas = dm_build_986.dm_build_996(int(dm_build_991)) + } + + switch dm_build_987.retSqlType { + case Dm_build_805: + dm_build_988.dmConnector.localTimezone = dm_build_986.dm_build_845.dm_build_417.Dm_build_204() + case Dm_build_803: + dm_build_987.hasResultSet = true + if dm_build_990 > 0 { + dm_build_986.dm_build_848.columns = dm_build_986.dm_build_1005(int(dm_build_990), dm_build_987.rsBdta) + } + dm_build_986.dm_build_1015(&dm_build_987, len(dm_build_986.dm_build_848.columns), int(dm_build_992), int(dm_build_993)) + case Dm_build_804: + if dm_build_990 > 0 || dm_build_992 > 0 { + dm_build_987.hasResultSet = true + } + if dm_build_990 > 0 { + dm_build_986.dm_build_848.columns = dm_build_986.dm_build_1005(int(dm_build_990), dm_build_987.rsBdta) + } + dm_build_986.dm_build_1015(&dm_build_987, len(dm_build_986.dm_build_848.columns), int(dm_build_992), int(dm_build_993)) + case Dm_build_806: + dm_build_988.IsoLevel = int32(dm_build_986.dm_build_845.dm_build_417.Dm_build_204()) + dm_build_988.ReadOnly = dm_build_986.dm_build_845.dm_build_417.Dm_build_201() == 1 + case Dm_build_799: + dm_build_988.Schema = dm_build_986.dm_build_845.dm_build_417.Dm_build_249(dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_796: + dm_build_987.explain = dm_build_986.dm_build_845.dm_build_417.Dm_build_249(dm_build_988.getServerEncoding(), dm_build_988) + + case Dm_build_800, Dm_build_802, Dm_build_801: + if dm_build_995 { + + counts := dm_build_986.dm_build_845.dm_build_417.Dm_build_207() + rowCounts := make([]int64, counts) + for i := 0; i < int(counts); i++ { + rowCounts[i] = dm_build_986.dm_build_845.dm_build_417.Dm_build_210() + } + dm_build_987.updateCounts = rowCounts + } + + dm_build_986.dm_build_1027(&dm_build_987) + + if dm_build_986.dm_build_847 == EC_BP_WITH_ERROR.ErrCode { + dm_build_986.dm_build_1021(dm_build_987.updateCounts) + } + case Dm_build_809: + len := dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + dm_build_988.FormatDate = dm_build_986.dm_build_845.dm_build_417.Dm_build_244(int(len), dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_811: + + len := dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + dm_build_988.FormatTimestamp = dm_build_986.dm_build_845.dm_build_417.Dm_build_244(int(len), dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_812: + + len := dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + dm_build_988.FormatTimestampTZ = dm_build_986.dm_build_845.dm_build_417.Dm_build_244(int(len), dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_810: + len := dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + dm_build_988.FormatTime = dm_build_986.dm_build_845.dm_build_417.Dm_build_244(int(len), dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_813: + len := dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + dm_build_988.FormatTimeTZ = dm_build_986.dm_build_845.dm_build_417.Dm_build_244(int(len), dm_build_988.getServerEncoding(), dm_build_988) + case Dm_build_814: + dm_build_988.OracleDateLanguage = dm_build_986.dm_build_845.dm_build_417.Dm_build_219() + } + + return &dm_build_987, nil +} + +func (dm_build_997 *dm_build_952) dm_build_996(dm_build_998 int) [][]byte { + dm_build_999 := make([]int, dm_build_998) + + dm_build_1000 := 0 + for i := 0; i < len(dm_build_997.dm_build_954); i++ { + if dm_build_997.dm_build_954[i].ioType == IO_TYPE_INOUT || dm_build_997.dm_build_954[i].ioType == IO_TYPE_OUT { + dm_build_999[dm_build_1000] = i + dm_build_1000++ + } + } + + dm_build_1001 := make([][]byte, len(dm_build_997.dm_build_954)) + var dm_build_1002 int32 + var dm_build_1003 bool + var dm_build_1004 []byte = nil + for i := 0; i < dm_build_998; i++ { + dm_build_1003 = false + dm_build_1002 = int32(dm_build_997.dm_build_845.dm_build_417.Dm_build_222()) + + if dm_build_1002 == int32(Dm_build_753) { + dm_build_1002 = 0 + dm_build_1003 = true + } else if dm_build_1002 == int32(Dm_build_754) { + dm_build_1002 = dm_build_997.dm_build_845.dm_build_417.Dm_build_207() + } + + if dm_build_1003 { + dm_build_1001[dm_build_999[i]] = nil + } else { + dm_build_1004 = dm_build_997.dm_build_845.dm_build_417.Dm_build_228(int(dm_build_1002)) + dm_build_1001[dm_build_999[i]] = dm_build_1004 + } + } + + return dm_build_1001 +} + +func (dm_build_1006 *dm_build_952) dm_build_1005(dm_build_1007 int, dm_build_1008 bool) []column { + dm_build_1009 := dm_build_1006.dm_build_845.dm_build_418.getServerEncoding() + var dm_build_1010, dm_build_1011, dm_build_1012, dm_build_1013 int16 + dm_build_1014 := make([]column, dm_build_1007) + for i := 0; i < dm_build_1007; i++ { + dm_build_1014[i].InitColumn() + + dm_build_1014[i].colType = dm_build_1006.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1014[i].prec = dm_build_1006.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1014[i].scale = dm_build_1006.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1014[i].nullable = dm_build_1006.dm_build_845.dm_build_417.Dm_build_207() != 0 + + itemFlag := dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1014[i].lob = int(itemFlag)&Dm_build_942 != 0 + dm_build_1014[i].identity = int(itemFlag)&Dm_build_941 != 0 + dm_build_1014[i].readonly = int(itemFlag)&Dm_build_943 != 0 + + dm_build_1006.dm_build_845.dm_build_417.Dm_build_103(4, false, true) + + dm_build_1006.dm_build_845.dm_build_417.Dm_build_103(2, false, true) + + dm_build_1010 = dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1011 = dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1012 = dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1013 = dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1014[i].name = dm_build_1006.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1010), dm_build_1009, dm_build_1006.dm_build_845.dm_build_418) + dm_build_1014[i].typeName = dm_build_1006.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1011), dm_build_1009, dm_build_1006.dm_build_845.dm_build_418) + dm_build_1014[i].tableName = dm_build_1006.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1012), dm_build_1009, dm_build_1006.dm_build_845.dm_build_418) + dm_build_1014[i].schemaName = dm_build_1006.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1013), dm_build_1009, dm_build_1006.dm_build_845.dm_build_418) + + if dm_build_1006.dm_build_848.readBaseColName { + dm_build_1014[i].baseName = dm_build_1006.dm_build_845.dm_build_417.Dm_build_257(dm_build_1009, dm_build_1006.dm_build_845.dm_build_418) + } + + if dm_build_1014[i].lob { + dm_build_1014[i].lobTabId = dm_build_1006.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1014[i].lobColId = dm_build_1006.dm_build_845.dm_build_417.Dm_build_204() + } + + if dm_build_1014[i].colType == DATETIME || dm_build_1014[i].colType == DATETIME2 { + if (dm_build_1014[i].scale & LOCAL_DATETIME_SCALE_MASK) != 0 { + + dm_build_1014[i].scale = dm_build_1014[i].scale & ^LOCAL_DATETIME_SCALE_MASK + dm_build_1014[i].mask = MASK_LOCAL_DATETIME + } else if (dm_build_1014[i].scale & ORACLE_DATE_SCALE_MASK) != 0 { + + dm_build_1014[i].scale = dm_build_1014[i].scale & ^ORACLE_DATE_SCALE_MASK + dm_build_1014[i].mask = MASK_ORACLE_DATE + } + } + + if dm_build_1014[i].colType == DECIMAL && dm_build_1014[i].scale == ORACLE_FLOAT_SCALE_MASK { + dm_build_1014[i].prec = int32(math.Round(float64(dm_build_1014[i].prec)*0.30103) + 1) + dm_build_1014[i].scale = -1 + dm_build_1014[i].mask = MASK_ORACLE_FLOAT + } + + if dm_build_1014[i].colType == VARCHAR && dm_build_1014[i].prec == BFILE_PREC && dm_build_1014[i].scale == BFILE_SCALE { + dm_build_1014[i].mask = MASK_BFILE + } + } + + for i := 0; i < dm_build_1007; i++ { + + if isComplexType(int(dm_build_1014[i].colType), int(dm_build_1014[i].scale)) { + strDesc := newTypeDescriptor(dm_build_1006.dm_build_845.dm_build_418) + strDesc.unpack(dm_build_1006.dm_build_845.dm_build_417) + dm_build_1014[i].typeDescriptor = strDesc + } + } + + return dm_build_1014 +} + +func (dm_build_1016 *dm_build_952) dm_build_1015(dm_build_1017 *execRetInfo, dm_build_1018 int, dm_build_1019 int, dm_build_1020 int) { + if dm_build_1019 > 0 { + startOffset := dm_build_1016.dm_build_845.dm_build_417.Dm_build_98() + if dm_build_1017.rsBdta { + dm_build_1017.rsDatas = dm_build_1016.dm_build_1040(dm_build_1016.dm_build_848.columns, dm_build_1020) + } else { + datas := make([][][]byte, dm_build_1019) + + for i := 0; i < dm_build_1019; i++ { + + datas[i] = make([][]byte, dm_build_1018+1) + + dm_build_1016.dm_build_845.dm_build_417.Dm_build_103(2, false, true) + + datas[i][0] = dm_build_1016.dm_build_845.dm_build_417.Dm_build_228(LINT64_SIZE) + + dm_build_1016.dm_build_845.dm_build_417.Dm_build_103(2*dm_build_1018, false, true) + + for j := 1; j < dm_build_1018+1; j++ { + + colLen := dm_build_1016.dm_build_845.dm_build_417.Dm_build_222() + if colLen == Dm_build_757 { + datas[i][j] = nil + } else if colLen != Dm_build_758 { + datas[i][j] = dm_build_1016.dm_build_845.dm_build_417.Dm_build_228(int(colLen)) + } else { + datas[i][j] = dm_build_1016.dm_build_845.dm_build_417.Dm_build_232() + } + } + } + + dm_build_1017.rsDatas = datas + } + dm_build_1017.rsSizeof = dm_build_1016.dm_build_845.dm_build_417.Dm_build_98() - startOffset + } + + if dm_build_1017.rsCacheOffset > 0 { + tbCount := dm_build_1016.dm_build_845.dm_build_417.Dm_build_204() + + ids := make([]int32, tbCount) + tss := make([]int64, tbCount) + + for i := 0; i < int(tbCount); i++ { + ids[i] = dm_build_1016.dm_build_845.dm_build_417.Dm_build_207() + tss[i] = dm_build_1016.dm_build_845.dm_build_417.Dm_build_210() + } + + dm_build_1017.tbIds = ids[:] + dm_build_1017.tbTss = tss[:] + } +} + +func (dm_build_1022 *dm_build_952) dm_build_1021(dm_build_1023 []int64) error { + + dm_build_1022.dm_build_845.dm_build_417.Dm_build_103(4, false, true) + + dm_build_1024 := dm_build_1022.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1025 := dm_build_1022.dm_build_845.dm_build_418.getServerEncoding() + + if Locale != LANGUAGE_EN && dm_build_1025 == ENCODING_EUCKR { + dm_build_1025 = ENCODING_GB18030 + } + + if Locale == LANGUAGE_CNT_HK && dm_build_1025 != ENCODING_UTF8 { + dm_build_1025 = ENCODING_BIG5 + } + + dm_build_1026 := make([]string, 0, 8) + for i := 0; i < int(dm_build_1024); i++ { + irow := dm_build_1022.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1023[irow] = -3 + + code := dm_build_1022.dm_build_845.dm_build_417.Dm_build_207() + + errStr := dm_build_1022.dm_build_845.dm_build_417.Dm_build_257(dm_build_1025, dm_build_1022.dm_build_845.dm_build_418) + + dm_build_1026 = append(dm_build_1026, "row["+strconv.Itoa(int(irow))+"]:"+strconv.Itoa(int(code))+", "+errStr) + } + + if len(dm_build_1026) > 0 { + builder := &strings.Builder{} + for _, str := range dm_build_1026 { + builder.WriteString(util.LINE_SEPARATOR) + builder.WriteString(str) + } + EC_BP_WITH_ERROR.ErrText += builder.String() + return EC_BP_WITH_ERROR.throw() + } + return nil +} + +func (dm_build_1028 *dm_build_952) dm_build_1027(dm_build_1029 *execRetInfo) error { + dm_build_1030 := dm_build_1028.dm_build_845.dm_build_417.Dm_build_345(Dm_build_951) + dm_build_1031 := (dm_build_1030 & 0x02) == 0x02 + if !dm_build_1031 { + + if dm_build_1029.updateCount == 1 { + + dm_build_1029.lastInsertId = dm_build_1029.rowid + } + return nil + } + + if dm_build_1028.dm_build_845.dm_build_418.MsgVersion < Dm_build_701 || dm_build_1028.dm_build_955 == Dm_build_947 { + + rows := dm_build_1028.dm_build_845.dm_build_417.Dm_build_207() + var lastInsertId int64 + for i := 0; i < int(rows); i++ { + lastInsertId = dm_build_1028.dm_build_845.dm_build_417.Dm_build_210() + } + dm_build_1029.lastInsertId = lastInsertId + } else { + + } + + return nil +} + +const ( + Dm_build_1032 = 0 + + Dm_build_1033 = Dm_build_1032 + ULINT_SIZE + + Dm_build_1034 = Dm_build_1033 + USINT_SIZE + + Dm_build_1035 = Dm_build_1034 + ULINT_SIZE + + Dm_build_1036 = Dm_build_1035 + ULINT_SIZE + + Dm_build_1037 = Dm_build_1036 + BYTE_SIZE + + Dm_build_1038 = -2 + + Dm_build_1039 = -3 +) + +func (dm_build_1041 *dm_build_952) dm_build_1040(dm_build_1042 []column, dm_build_1043 int) [][][]byte { + + dm_build_1044 := dm_build_1041.dm_build_845.dm_build_417.Dm_build_225() + + dm_build_1045 := dm_build_1041.dm_build_845.dm_build_417.Dm_build_222() + + var dm_build_1046 bool + + if dm_build_1043 >= 0 && int(dm_build_1045) == len(dm_build_1042)+1 { + dm_build_1046 = true + } else { + dm_build_1046 = false + } + + dm_build_1041.dm_build_845.dm_build_417.Dm_build_103(ULINT_SIZE, false, true) + + dm_build_1041.dm_build_845.dm_build_417.Dm_build_103(ULINT_SIZE, false, true) + + dm_build_1041.dm_build_845.dm_build_417.Dm_build_103(BYTE_SIZE, false, true) + + dm_build_1047 := make([]uint16, dm_build_1045) + for icol := 0; icol < int(dm_build_1045); icol++ { + dm_build_1047[icol] = dm_build_1041.dm_build_845.dm_build_417.Dm_build_222() + } + + dm_build_1048 := make([]uint32, dm_build_1045) + dm_build_1049 := make([][][]byte, dm_build_1044) + + for i := uint32(0); i < dm_build_1044; i++ { + dm_build_1049[i] = make([][]byte, len(dm_build_1042)+1) + } + + for icol := 0; icol < int(dm_build_1045); icol++ { + dm_build_1048[icol] = dm_build_1041.dm_build_845.dm_build_417.Dm_build_225() + } + + for icol := 0; icol < int(dm_build_1045); icol++ { + + dataCol := icol + 1 + if dm_build_1046 && icol == dm_build_1043 { + dataCol = 0 + } else if dm_build_1046 && icol > dm_build_1043 { + dataCol = icol + } + + allNotNull := dm_build_1041.dm_build_845.dm_build_417.Dm_build_207() == 1 + var isNull []bool = nil + if !allNotNull { + isNull = make([]bool, dm_build_1044) + for irow := uint32(0); irow < dm_build_1044; irow++ { + isNull[irow] = dm_build_1041.dm_build_845.dm_build_417.Dm_build_201() == 0 + } + } + + for irow := uint32(0); irow < dm_build_1044; irow++ { + if allNotNull || !isNull[irow] { + dm_build_1049[irow][dataCol] = dm_build_1041.dm_build_1050(int(dm_build_1047[icol])) + } + } + } + + if !dm_build_1046 && dm_build_1043 >= 0 { + for irow := uint32(0); irow < dm_build_1044; irow++ { + dm_build_1049[irow][0] = dm_build_1049[irow][dm_build_1043+1] + } + } + + return dm_build_1049 +} + +func (dm_build_1051 *dm_build_952) dm_build_1050(dm_build_1052 int) []byte { + + dm_build_1053 := dm_build_1051.dm_build_1056(dm_build_1052) + + dm_build_1054 := int32(0) + if dm_build_1053 == Dm_build_1038 { + dm_build_1054 = dm_build_1051.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1053 = int(dm_build_1051.dm_build_845.dm_build_417.Dm_build_207()) + } else if dm_build_1053 == Dm_build_1039 { + dm_build_1053 = int(dm_build_1051.dm_build_845.dm_build_417.Dm_build_207()) + } + + dm_build_1055 := dm_build_1051.dm_build_845.dm_build_417.Dm_build_228(dm_build_1053 + int(dm_build_1054)) + if dm_build_1054 == 0 { + return dm_build_1055 + } + + for i := dm_build_1053; i < len(dm_build_1055); i++ { + dm_build_1055[i] = ' ' + } + return dm_build_1055 +} + +func (dm_build_1057 *dm_build_952) dm_build_1056(dm_build_1058 int) int { + + dm_build_1059 := 0 + switch dm_build_1058 { + case INT, BIT, TINYINT, SMALLINT, BOOLEAN, NULL: + dm_build_1059 = 4 + + case BIGINT: + + dm_build_1059 = 8 + + case CHAR, VARCHAR2, VARCHAR, BINARY, VARBINARY, BLOB, CLOB: + dm_build_1059 = Dm_build_1038 + + case DECIMAL: + dm_build_1059 = Dm_build_1039 + + case REAL: + dm_build_1059 = 4 + + case DOUBLE: + dm_build_1059 = 8 + + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ: + dm_build_1059 = 12 + + case DATETIME2, DATETIME2_TZ: + dm_build_1059 = 13 + + case INTERVAL_YM: + dm_build_1059 = 12 + + case INTERVAL_DT: + dm_build_1059 = 24 + + default: + dm_build_1059 = 0 + } + return dm_build_1059 +} + +const ( + Dm_build_1060 = Dm_build_737 + + Dm_build_1061 = Dm_build_1060 + DDWORD_SIZE + + Dm_build_1062 = Dm_build_1061 + LINT64_SIZE + + Dm_build_1063 = Dm_build_1062 + USINT_SIZE + + Dm_build_1064 = Dm_build_737 + + Dm_build_1065 = Dm_build_1064 + DDWORD_SIZE +) + +type dm_build_1066 struct { + dm_build_952 + dm_build_1067 *innerRows + dm_build_1068 int64 + dm_build_1069 int64 +} + +func dm_build_1070(dm_build_1071 *dm_build_414, dm_build_1072 *innerRows, dm_build_1073 int64, dm_build_1074 int64) *dm_build_1066 { + dm_build_1075 := new(dm_build_1066) + dm_build_1075.dm_build_853(dm_build_1071, Dm_build_715, dm_build_1072.dmStmt) + dm_build_1075.dm_build_1067 = dm_build_1072 + dm_build_1075.dm_build_1068 = dm_build_1073 + dm_build_1075.dm_build_1069 = dm_build_1074 + return dm_build_1075 +} + +func (dm_build_1077 *dm_build_1066) dm_build_830() error { + + dm_build_1077.dm_build_845.dm_build_417.Dm_build_277(Dm_build_1060, dm_build_1077.dm_build_1068) + + dm_build_1077.dm_build_845.dm_build_417.Dm_build_277(Dm_build_1061, dm_build_1077.dm_build_1069) + + dm_build_1077.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1062, dm_build_1077.dm_build_1067.id) + + dm_build_1078 := dm_build_1077.dm_build_1067.dmStmt.dmConn.dmConnector.bufPrefetch + var dm_build_1079 int32 + if dm_build_1077.dm_build_1067.sizeOfRow != 0 && dm_build_1077.dm_build_1067.fetchSize != 0 { + if dm_build_1077.dm_build_1067.sizeOfRow*dm_build_1077.dm_build_1067.fetchSize > int(INT32_MAX) { + dm_build_1079 = INT32_MAX + } else { + dm_build_1079 = int32(dm_build_1077.dm_build_1067.sizeOfRow * dm_build_1077.dm_build_1067.fetchSize) + } + + if dm_build_1079 < Dm_build_769 { + dm_build_1078 = int(Dm_build_769) + } else if dm_build_1079 > Dm_build_770 { + dm_build_1078 = int(Dm_build_770) + } else { + dm_build_1078 = int(dm_build_1079) + } + + dm_build_1077.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1063, int32(dm_build_1078)) + } + + return nil +} + +func (dm_build_1081 *dm_build_1066) dm_build_834() (interface{}, error) { + dm_build_1082 := execRetInfo{} + dm_build_1082.rsBdta = dm_build_1081.dm_build_1067.isBdta + + dm_build_1082.updateCount = dm_build_1081.dm_build_845.dm_build_417.Dm_build_354(Dm_build_1064) + dm_build_1083 := dm_build_1081.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1065) + + dm_build_1081.dm_build_1015(&dm_build_1082, len(dm_build_1081.dm_build_1067.columns), int(dm_build_1083), -1) + + return &dm_build_1082, nil +} + +type dm_build_1084 struct { + dm_build_844 + dm_build_1085 *lob + dm_build_1086 int + dm_build_1087 int +} + +func dm_build_1088(dm_build_1089 *dm_build_414, dm_build_1090 *lob, dm_build_1091 int, dm_build_1092 int) *dm_build_1084 { + dm_build_1093 := new(dm_build_1084) + dm_build_1093.dm_build_849(dm_build_1089, Dm_build_728) + dm_build_1093.dm_build_1085 = dm_build_1090 + dm_build_1093.dm_build_1086 = dm_build_1091 + dm_build_1093.dm_build_1087 = dm_build_1092 + return dm_build_1093 +} + +func (dm_build_1095 *dm_build_1084) dm_build_830() error { + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_121(byte(dm_build_1095.dm_build_1085.lobFlag)) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(dm_build_1095.dm_build_1085.tabId) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.colId) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1095.dm_build_1085.blobId)) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.groupId) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.fileId) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(dm_build_1095.dm_build_1085.pageNo) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.curFileId) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(dm_build_1095.dm_build_1085.curPageNo) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(dm_build_1095.dm_build_1085.totalOffset) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(int32(dm_build_1095.dm_build_1086)) + + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(int32(dm_build_1095.dm_build_1087)) + + if dm_build_1095.dm_build_845.dm_build_418.NewLobFlag { + dm_build_1095.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1095.dm_build_1085.rowId)) + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.exGroupId) + dm_build_1095.dm_build_845.dm_build_417.Dm_build_129(dm_build_1095.dm_build_1085.exFileId) + dm_build_1095.dm_build_845.dm_build_417.Dm_build_133(dm_build_1095.dm_build_1085.exPageNo) + } + + return nil +} + +func (dm_build_1097 *dm_build_1084) dm_build_834() (interface{}, error) { + + dm_build_1097.dm_build_1085.readOver = dm_build_1097.dm_build_845.dm_build_417.Dm_build_201() == 1 + var dm_build_1098 = dm_build_1097.dm_build_845.dm_build_417.Dm_build_225() + if dm_build_1098 <= 0 { + return &lobRetInfo{0, []byte{}}, nil + } + dm_build_1097.dm_build_1085.curFileId = dm_build_1097.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1097.dm_build_1085.curPageNo = dm_build_1097.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1097.dm_build_1085.totalOffset = dm_build_1097.dm_build_845.dm_build_417.Dm_build_207() + + var dm_build_1099 = dm_build_1097.dm_build_845.dm_build_417.Dm_build_238(int(dm_build_1098)) + var dm_build_1100 int64 = -1 + if dm_build_1097.dm_build_845.dm_build_417.Dm_build_100(false) > 0 { + dm_build_1100 = int64(dm_build_1097.dm_build_845.dm_build_417.Dm_build_225()) + } + return &lobRetInfo{dm_build_1100, dm_build_1099}, nil +} + +type dm_build_1101 struct { + dm_build_844 + dm_build_1102 *lob +} + +func dm_build_1103(dm_build_1104 *dm_build_414, dm_build_1105 *lob) *dm_build_1101 { + dm_build_1106 := new(dm_build_1101) + dm_build_1106.dm_build_849(dm_build_1104, Dm_build_725) + dm_build_1106.dm_build_1102 = dm_build_1105 + return dm_build_1106 +} + +func (dm_build_1108 *dm_build_1101) dm_build_830() error { + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_121(byte(dm_build_1108.dm_build_1102.lobFlag)) + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1108.dm_build_1102.blobId)) + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_129(dm_build_1108.dm_build_1102.groupId) + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_129(dm_build_1108.dm_build_1102.fileId) + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_133(dm_build_1108.dm_build_1102.pageNo) + + if dm_build_1108.dm_build_845.dm_build_418.NewLobFlag { + dm_build_1108.dm_build_845.dm_build_417.Dm_build_133(dm_build_1108.dm_build_1102.tabId) + dm_build_1108.dm_build_845.dm_build_417.Dm_build_129(dm_build_1108.dm_build_1102.colId) + dm_build_1108.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1108.dm_build_1102.rowId)) + + dm_build_1108.dm_build_845.dm_build_417.Dm_build_129(dm_build_1108.dm_build_1102.exGroupId) + dm_build_1108.dm_build_845.dm_build_417.Dm_build_129(dm_build_1108.dm_build_1102.exFileId) + dm_build_1108.dm_build_845.dm_build_417.Dm_build_133(dm_build_1108.dm_build_1102.exPageNo) + } + + return nil +} + +func (dm_build_1110 *dm_build_1101) dm_build_834() (interface{}, error) { + + if dm_build_1110.dm_build_845.dm_build_417.Dm_build_100(false) == 8 { + return dm_build_1110.dm_build_845.dm_build_417.Dm_build_210(), nil + } else { + return int64(dm_build_1110.dm_build_845.dm_build_417.Dm_build_225()), nil + } +} + +type dm_build_1111 struct { + dm_build_844 + dm_build_1112 *lob + dm_build_1113 int +} + +func dm_build_1114(dm_build_1115 *dm_build_414, dm_build_1116 *lob, dm_build_1117 int) *dm_build_1111 { + dm_build_1118 := new(dm_build_1111) + dm_build_1118.dm_build_849(dm_build_1115, Dm_build_727) + dm_build_1118.dm_build_1112 = dm_build_1116 + dm_build_1118.dm_build_1113 = dm_build_1117 + return dm_build_1118 +} + +func (dm_build_1120 *dm_build_1111) dm_build_830() error { + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_121(byte(dm_build_1120.dm_build_1112.lobFlag)) + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1120.dm_build_1112.blobId)) + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_129(dm_build_1120.dm_build_1112.groupId) + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_129(dm_build_1120.dm_build_1112.fileId) + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_133(dm_build_1120.dm_build_1112.pageNo) + + dm_build_1120.dm_build_845.dm_build_417.Dm_build_133(dm_build_1120.dm_build_1112.tabId) + dm_build_1120.dm_build_845.dm_build_417.Dm_build_129(dm_build_1120.dm_build_1112.colId) + dm_build_1120.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1120.dm_build_1112.rowId)) + dm_build_1120.dm_build_845.dm_build_417.Dm_build_161(Dm_build_1346.Dm_build_1551(uint32(dm_build_1120.dm_build_1113))) + + if dm_build_1120.dm_build_845.dm_build_418.NewLobFlag { + dm_build_1120.dm_build_845.dm_build_417.Dm_build_129(dm_build_1120.dm_build_1112.exGroupId) + dm_build_1120.dm_build_845.dm_build_417.Dm_build_129(dm_build_1120.dm_build_1112.exFileId) + dm_build_1120.dm_build_845.dm_build_417.Dm_build_133(dm_build_1120.dm_build_1112.exPageNo) + } + return nil +} + +func (dm_build_1122 *dm_build_1111) dm_build_834() (interface{}, error) { + + dm_build_1123 := dm_build_1122.dm_build_845.dm_build_417.Dm_build_225() + dm_build_1122.dm_build_1112.blobId = dm_build_1122.dm_build_845.dm_build_417.Dm_build_210() + dm_build_1122.dm_build_1112.resetCurrentInfo() + return int64(dm_build_1123), nil +} + +const ( + Dm_build_1124 = Dm_build_737 + + Dm_build_1125 = Dm_build_1124 + ULINT_SIZE + + Dm_build_1126 = Dm_build_1125 + ULINT_SIZE + + Dm_build_1127 = Dm_build_1126 + ULINT_SIZE + + Dm_build_1128 = Dm_build_1127 + BYTE_SIZE + + Dm_build_1129 = Dm_build_1128 + USINT_SIZE + + Dm_build_1130 = Dm_build_1129 + ULINT_SIZE + + Dm_build_1131 = Dm_build_1130 + BYTE_SIZE + + Dm_build_1132 = Dm_build_1131 + BYTE_SIZE + + Dm_build_1133 = Dm_build_1132 + BYTE_SIZE + + Dm_build_1134 = Dm_build_737 + + Dm_build_1135 = Dm_build_1134 + ULINT_SIZE + + Dm_build_1136 = Dm_build_1135 + ULINT_SIZE + + Dm_build_1137 = Dm_build_1136 + BYTE_SIZE + + Dm_build_1138 = Dm_build_1137 + ULINT_SIZE + + Dm_build_1139 = Dm_build_1138 + BYTE_SIZE + + Dm_build_1140 = Dm_build_1139 + BYTE_SIZE + + Dm_build_1141 = Dm_build_1140 + USINT_SIZE + + Dm_build_1142 = Dm_build_1141 + USINT_SIZE + + Dm_build_1143 = Dm_build_1142 + BYTE_SIZE + + Dm_build_1144 = Dm_build_1143 + USINT_SIZE + + Dm_build_1145 = Dm_build_1144 + BYTE_SIZE + + Dm_build_1146 = Dm_build_1145 + BYTE_SIZE + + Dm_build_1147 = Dm_build_1146 + ULINT_SIZE + + Dm_build_1148 = Dm_build_1147 + USINT_SIZE +) + +type dm_build_1149 struct { + dm_build_844 + + dm_build_1150 *DmConnection + + dm_build_1151 bool +} + +func dm_build_1152(dm_build_1153 *dm_build_414) *dm_build_1149 { + dm_build_1154 := new(dm_build_1149) + dm_build_1154.dm_build_849(dm_build_1153, Dm_build_709) + dm_build_1154.dm_build_1150 = dm_build_1153.dm_build_418 + return dm_build_1154 +} + +func (dm_build_1156 *dm_build_1149) dm_build_830() error { + + if dm_build_1156.dm_build_1150.dmConnector.newClientType { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1124, Dm_build_748) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1124, Dm_build_747) + } + + dm_build_1156.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1125, g2dbIsoLevel(dm_build_1156.dm_build_1150.IsoLevel)) + dm_build_1156.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1126, int32(Locale)) + dm_build_1156.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1128, dm_build_1156.dm_build_1150.dmConnector.localTimezone) + + if dm_build_1156.dm_build_1150.ReadOnly { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1127, Dm_build_772) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1127, Dm_build_771) + } + + dm_build_1156.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1129, int32(dm_build_1156.dm_build_1150.dmConnector.sessionTimeout)) + + if dm_build_1156.dm_build_1150.dmConnector.mppLocal { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1130, 1) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1130, 0) + } + + var dm_build_1157 byte = 0 + if dm_build_1156.dm_build_1150.dmConnector.rwSeparate == RW_SEPARATE_DB_APPLY_WAIT { + dm_build_1157 = 4 + } else if dm_build_1156.dm_build_1150.dmConnector.rwSeparate > 0 { + dm_build_1157 = 1 + } + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1131, dm_build_1157) + + if dm_build_1156.dm_build_1150.NewLobFlag { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1132, 1) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1132, 0) + } + + dm_build_1156.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1133, dm_build_1156.dm_build_1150.dmConnector.osAuthType) + + dm_build_1158 := dm_build_1156.dm_build_1150.getServerEncoding() + + if dm_build_1156.dm_build_845.dm_build_424 != "" { + + } + + dm_build_1159 := Dm_build_1346.Dm_build_1562(dm_build_1156.dm_build_1150.dmConnector.user, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + dm_build_1160 := Dm_build_1346.Dm_build_1562(dm_build_1156.dm_build_1150.dmConnector.password, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + if len(dm_build_1159) > Dm_build_745 { + return ECGO_USERNAME_TOO_LONG.throw() + } + if len(dm_build_1160) > Dm_build_745 { + return ECGO_PASSWORD_TOO_LONG.throw() + } + + if dm_build_1156.dm_build_845.dm_build_420 && dm_build_1156.dm_build_1150.dmConnector.loginCertificate != "" { + + } else if dm_build_1156.dm_build_845.dm_build_420 { + dm_build_1159 = dm_build_1156.dm_build_845.dm_build_419.Encrypt(dm_build_1159, false) + dm_build_1160 = dm_build_1156.dm_build_845.dm_build_419.Encrypt(dm_build_1160, false) + } + + dm_build_1156.dm_build_845.dm_build_417.Dm_build_165(dm_build_1159) + dm_build_1156.dm_build_845.dm_build_417.Dm_build_165(dm_build_1160) + + dm_build_1156.dm_build_845.dm_build_417.Dm_build_177(dm_build_1156.dm_build_1150.dmConnector.appName, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + dm_build_1156.dm_build_845.dm_build_417.Dm_build_177(dm_build_1156.dm_build_1150.dmConnector.osName, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + + if hostName, err := os.Hostname(); err != nil { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_177(hostName, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_177("", dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + } + + if dm_build_1156.dm_build_1150.dmConnector.rwStandby { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_121(1) + } else { + dm_build_1156.dm_build_845.dm_build_417.Dm_build_121(0) + } + + var dm_build_1161 string = "" + if len(dm_build_1156.dm_build_1150.dmConnector.serverOption) > 0 { + dm_build_1161 = strings.Join(dm_build_1156.dm_build_1150.dmConnector.serverOption, ",") + if strings.HasPrefix(dm_build_1161, "{") && strings.HasSuffix(dm_build_1161, "}") { + dm_build_1161 = dm_build_1161[1 : len(dm_build_1161)-1] + } + } + dm_build_1156.dm_build_845.dm_build_417.Dm_build_189(dm_build_1161, dm_build_1158, dm_build_1156.dm_build_845.dm_build_418) + + return nil +} + +func (dm_build_1163 *dm_build_1149) dm_build_834() (interface{}, error) { + + dm_build_1163.dm_build_1150.MaxRowSize = dm_build_1163.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1134) + dm_build_1163.dm_build_1150.DDLAutoCommit = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1136) == 1 + dm_build_1163.dm_build_1150.IsoLevel = dm_build_1163.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1137) + dm_build_1163.dm_build_1150.dmConnector.caseSensitive = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1138) == 1 + dm_build_1163.dm_build_1150.BackSlashFlag = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1139) == 1 + dm_build_1163.dm_build_1150.SvrStat = int32(dm_build_1163.dm_build_845.dm_build_417.Dm_build_348(Dm_build_1141)) + dm_build_1163.dm_build_1150.SvrMode = int32(dm_build_1163.dm_build_845.dm_build_417.Dm_build_348(Dm_build_1140)) + dm_build_1163.dm_build_1150.ConstParaOpt = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1142) == 1 + dm_build_1163.dm_build_1150.DbTimezone = dm_build_1163.dm_build_845.dm_build_417.Dm_build_348(Dm_build_1143) + dm_build_1163.dm_build_1150.NewLobFlag = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1145) == 1 + + if dm_build_1163.dm_build_1150.dmConnector.bufPrefetch == 0 { + dm_build_1163.dm_build_1150.dmConnector.bufPrefetch = int(dm_build_1163.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1146)) + } + + dm_build_1163.dm_build_1150.LifeTimeRemainder = dm_build_1163.dm_build_845.dm_build_417.Dm_build_348(Dm_build_1147) + dm_build_1163.dm_build_1150.dscControl = dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1148) == 1 + + dm_build_1164 := dm_build_1163.dm_build_1150.getServerEncoding() + + dm_build_1163.dm_build_1150.InstanceName = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + + var dm_build_1165 = dm_build_1163.dm_build_845.dm_build_417.Dm_build_207() + if dm_build_1165 == 0 && dm_build_1163.dm_build_1150.MsgVersion > 0 { + dm_build_1163.dm_build_1150.Schema = strings.ToUpper(dm_build_1163.dm_build_1150.dmConnector.user) + } else { + dm_build_1163.dm_build_1150.Schema = dm_build_1163.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1165), dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + } + + dm_build_1163.dm_build_1150.LastLoginIP = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + dm_build_1163.dm_build_1150.LastLoginTime = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + dm_build_1163.dm_build_1150.FailedAttempts = dm_build_1163.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1163.dm_build_1150.LoginWarningID = dm_build_1163.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1163.dm_build_1150.GraceTimeRemainder = dm_build_1163.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1163.dm_build_1150.Guid = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + dm_build_1163.dm_build_1150.DbName = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + + if dm_build_1163.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1144) == 1 { + dm_build_1163.dm_build_1150.StandbyHost = dm_build_1163.dm_build_845.dm_build_417.Dm_build_249(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + dm_build_1163.dm_build_1150.StandbyPort = dm_build_1163.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1163.dm_build_1150.StandbyCount = int32(dm_build_1163.dm_build_845.dm_build_417.Dm_build_222()) + } + + if dm_build_1163.dm_build_845.dm_build_417.Dm_build_100(false) > 0 { + dm_build_1163.dm_build_1150.SessionID = dm_build_1163.dm_build_845.dm_build_417.Dm_build_210() + } + + if dm_build_1163.dm_build_845.dm_build_417.Dm_build_100(false) > 0 { + if dm_build_1163.dm_build_845.dm_build_417.Dm_build_201() == 1 { + + dm_build_1163.dm_build_1150.FormatDate = "DD-MON-YY" + + dm_build_1163.dm_build_1150.FormatTime = "HH12.MI.SS.FF6 AM" + + dm_build_1163.dm_build_1150.FormatTimestamp = "DD-MON-YY HH12.MI.SS.FF6 AM" + + dm_build_1163.dm_build_1150.FormatTimestampTZ = "DD-MON-YY HH12.MI.SS.FF6 AM +TZH:TZM" + + dm_build_1163.dm_build_1150.FormatTimeTZ = "HH12.MI.SS.FF6 AM +TZH:TZM" + } + } + + if dm_build_1163.dm_build_845.dm_build_417.Dm_build_100(false) > 0 { + + format := dm_build_1163.dm_build_845.dm_build_417.Dm_build_253(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + if format != "" { + dm_build_1163.dm_build_1150.FormatDate = format + } + format = dm_build_1163.dm_build_845.dm_build_417.Dm_build_253(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + if format != "" { + dm_build_1163.dm_build_1150.FormatTime = format + } + format = dm_build_1163.dm_build_845.dm_build_417.Dm_build_253(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + if format != "" { + dm_build_1163.dm_build_1150.FormatTimestamp = format + } + format = dm_build_1163.dm_build_845.dm_build_417.Dm_build_253(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + if format != "" { + dm_build_1163.dm_build_1150.FormatTimestampTZ = format + } + format = dm_build_1163.dm_build_845.dm_build_417.Dm_build_253(dm_build_1164, dm_build_1163.dm_build_845.dm_build_418) + if format != "" { + dm_build_1163.dm_build_1150.FormatTimeTZ = format + } + } + + return nil, nil +} + +const ( + Dm_build_1166 = Dm_build_737 +) + +type dm_build_1167 struct { + dm_build_952 + dm_build_1168 int16 +} + +func dm_build_1169(dm_build_1170 *dm_build_414, dm_build_1171 *DmStatement, dm_build_1172 int16) *dm_build_1167 { + dm_build_1173 := new(dm_build_1167) + dm_build_1173.dm_build_853(dm_build_1170, Dm_build_729, dm_build_1171) + dm_build_1173.dm_build_1168 = dm_build_1172 + return dm_build_1173 +} + +func (dm_build_1175 *dm_build_1167) dm_build_830() error { + dm_build_1175.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1166, dm_build_1175.dm_build_1168) + return nil +} + +func (dm_build_1177 *dm_build_1167) dm_build_834() (interface{}, error) { + return dm_build_1177.dm_build_952.dm_build_834() +} + +const ( + Dm_build_1178 = Dm_build_737 + Dm_build_1179 = Dm_build_1178 + USINT_SIZE +) + +type dm_build_1180 struct { + dm_build_1190 + dm_build_1181 []parameter +} + +func dm_build_1182(dm_build_1183 *dm_build_414, dm_build_1184 *DmStatement, dm_build_1185 []parameter) *dm_build_1180 { + dm_build_1186 := new(dm_build_1180) + dm_build_1186.dm_build_853(dm_build_1183, Dm_build_733, dm_build_1184) + dm_build_1186.dm_build_1181 = dm_build_1185 + return dm_build_1186 +} + +func (dm_build_1188 *dm_build_1180) dm_build_830() error { + + if dm_build_1188.dm_build_1181 == nil { + dm_build_1188.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1178, 0) + } else { + dm_build_1188.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1178, int16(len(dm_build_1188.dm_build_1181))) + } + + dm_build_1188.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1179, 0) + + return dm_build_1188.dm_build_977(dm_build_1188.dm_build_1181) +} + +const Dm_build_1189 = 38 + +type dm_build_1190 struct { + dm_build_952 + dm_build_1191 bool + dm_build_1192 int16 +} + +func dm_build_1193(dm_build_1194 *dm_build_414, dm_build_1195 *DmStatement, dm_build_1196 bool, dm_build_1197 int16) *dm_build_1190 { + dm_build_1198 := new(dm_build_1190) + dm_build_1198.dm_build_853(dm_build_1194, Dm_build_713, dm_build_1195) + dm_build_1198.dm_build_1191 = dm_build_1196 + dm_build_1198.dm_build_1192 = dm_build_1197 + return dm_build_1198 +} + +func (dm_build_1200 *dm_build_1190) dm_build_830() error { + + dm_build_1201 := Dm_build_737 + + if dm_build_1200.dm_build_845.dm_build_418.autoCommit { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 1) + } else { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + } + + if dm_build_1200.dm_build_1191 { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 1) + } else { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + } + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 1) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_269(dm_build_1201, Dm_build_788) + + if dm_build_1200.dm_build_848.maxRows <= 0 || dm_build_1200.dm_build_845.dm_build_418.dmConnector.enRsCache { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_277(dm_build_1201, INT64_MAX) + } else { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_277(dm_build_1201, dm_build_1200.dm_build_848.maxRows) + } + + if dm_build_1200.dm_build_845.dm_build_418.dmConnector.isBdtaRS { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, Dm_build_816) + } else { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, Dm_build_815) + } + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_269(dm_build_1201, 0) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 1) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_273(dm_build_1201, dm_build_1200.dm_build_848.queryTimeout) + + if dm_build_1200.dm_build_848.innerExec { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 1) + } else { + dm_build_1201 += dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(dm_build_1201, 0) + } + + if dm_build_1200.dm_build_845.dm_build_418.MsgVersion >= Dm_build_701 { + if dm_build_1200.dm_build_1191 { + dm_build_1200.dm_build_955 = dm_build_1200.dm_build_983() + } else { + dm_build_1200.dm_build_955 = Dm_build_946 + } + dm_build_1200.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1189, byte(dm_build_1200.dm_build_955)) + } + + dm_build_1200.dm_build_845.dm_build_417.Dm_build_195(dm_build_1200.dm_build_848.nativeSql, dm_build_1200.dm_build_845.dm_build_418.getServerEncoding(), dm_build_1200.dm_build_845.dm_build_418) + + return nil +} + +func (dm_build_1203 *dm_build_1190) dm_build_834() (interface{}, error) { + + if dm_build_1203.dm_build_1191 { + return dm_build_1203.dm_build_952.dm_build_834() + } + + dm_build_1204 := NewExceInfo() + dm_build_1205 := Dm_build_737 + + dm_build_1204.retSqlType = dm_build_1203.dm_build_845.dm_build_417.Dm_build_348(dm_build_1205) + dm_build_1205 += USINT_SIZE + + dm_build_1206 := dm_build_1203.dm_build_845.dm_build_417.Dm_build_366(dm_build_1205) + dm_build_1205 += USINT_SIZE + + dm_build_1207 := dm_build_1203.dm_build_845.dm_build_417.Dm_build_348(dm_build_1205) + dm_build_1205 += USINT_SIZE + + dm_build_1203.dm_build_845.dm_build_417.Dm_build_354(dm_build_1205) + dm_build_1205 += DDWORD_SIZE + + dm_build_1203.dm_build_845.dm_build_418.TrxStatus = dm_build_1203.dm_build_845.dm_build_417.Dm_build_351(dm_build_1205) + dm_build_1205 += ULINT_SIZE + + dm_build_1204.serverParams = dm_build_1203.dm_build_1208(int(dm_build_1206)) + + if dm_build_1207 > 0 { + dm_build_1203.dm_build_848.columns = dm_build_1203.dm_build_1005(int(dm_build_1207), dm_build_1204.rsBdta) + } else { + dm_build_1203.dm_build_848.columns = make([]column, 0) + } + + return dm_build_1204, nil +} + +func (dm_build_1209 *dm_build_1190) dm_build_1208(dm_build_1210 int) []parameter { + + var dm_build_1211, dm_build_1212, dm_build_1213, dm_build_1214 int16 + + dm_build_1215 := make([]parameter, dm_build_1210) + for i := 0; i < dm_build_1210; i++ { + + dm_build_1215[i].InitParameter() + + dm_build_1215[i].colType = dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1215[i].prec = dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1215[i].scale = dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1215[i].nullable = dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() != 0 + + itemFlag := dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1215[i].hasDefault = int(itemFlag)&Dm_build_945 != 0 + + if int(itemFlag)&Dm_build_944 != 0 { + dm_build_1215[i].typeFlag = TYPE_FLAG_RECOMMEND + } else { + dm_build_1215[i].typeFlag = TYPE_FLAG_EXACT + } + + dm_build_1215[i].lob = int(itemFlag)&Dm_build_942 != 0 + + dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() + + dm_build_1215[i].ioType = int8(dm_build_1209.dm_build_845.dm_build_417.Dm_build_204()) + + dm_build_1211 = dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1212 = dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1213 = dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + + dm_build_1214 = dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1215[i].name = dm_build_1209.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1211), dm_build_1209.dm_build_845.dm_build_418.getServerEncoding(), dm_build_1209.dm_build_845.dm_build_418) + dm_build_1215[i].typeName = dm_build_1209.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1212), dm_build_1209.dm_build_845.dm_build_418.getServerEncoding(), dm_build_1209.dm_build_845.dm_build_418) + dm_build_1215[i].tableName = dm_build_1209.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1213), dm_build_1209.dm_build_845.dm_build_418.getServerEncoding(), dm_build_1209.dm_build_845.dm_build_418) + dm_build_1215[i].schemaName = dm_build_1209.dm_build_845.dm_build_417.Dm_build_244(int(dm_build_1214), dm_build_1209.dm_build_845.dm_build_418.getServerEncoding(), dm_build_1209.dm_build_845.dm_build_418) + + if dm_build_1215[i].lob { + dm_build_1215[i].lobTabId = dm_build_1209.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1215[i].lobColId = dm_build_1209.dm_build_845.dm_build_417.Dm_build_204() + } + + if dm_build_1215[i].colType == DATETIME || dm_build_1215[i].colType == DATETIME2 { + if (dm_build_1215[i].scale & LOCAL_DATETIME_SCALE_MASK) != 0 { + + dm_build_1215[i].scale = dm_build_1215[i].scale & ^LOCAL_DATETIME_SCALE_MASK + dm_build_1215[i].mask = MASK_LOCAL_DATETIME + } else if (dm_build_1215[i].scale & ORACLE_DATE_SCALE_MASK) != 0 { + + dm_build_1215[i].scale = dm_build_1215[i].scale & ^ORACLE_DATE_SCALE_MASK + dm_build_1215[i].mask = MASK_ORACLE_DATE + } + } + + if dm_build_1215[i].colType == DECIMAL && dm_build_1215[i].scale == ORACLE_FLOAT_SCALE_MASK { + dm_build_1215[i].prec = int32(math.Round(float64(dm_build_1215[i].prec)*0.30103) + 1) + dm_build_1215[i].scale = -1 + dm_build_1215[i].mask = MASK_ORACLE_FLOAT + } + + if dm_build_1215[i].colType == VARCHAR && dm_build_1215[i].prec == BFILE_PREC && dm_build_1215[i].scale == BFILE_SCALE { + dm_build_1215[i].mask = MASK_BFILE + } + } + + for i := 0; i < dm_build_1210; i++ { + + if isComplexType(int(dm_build_1215[i].colType), int(dm_build_1215[i].scale)) { + + strDesc := newTypeDescriptor(dm_build_1209.dm_build_845.dm_build_418) + strDesc.unpack(dm_build_1209.dm_build_845.dm_build_417) + dm_build_1215[i].typeDescriptor = strDesc + } + } + + return dm_build_1215 +} + +const ( + Dm_build_1216 = Dm_build_737 +) + +type dm_build_1217 struct { + dm_build_844 + dm_build_1218 int16 + dm_build_1219 *Dm_build_0 + dm_build_1220 int32 +} + +func dm_build_1221(dm_build_1222 *dm_build_414, dm_build_1223 *DmStatement, dm_build_1224 int16, dm_build_1225 *Dm_build_0, dm_build_1226 int32) *dm_build_1217 { + dm_build_1227 := new(dm_build_1217) + dm_build_1227.dm_build_853(dm_build_1222, Dm_build_719, dm_build_1223) + dm_build_1227.dm_build_1218 = dm_build_1224 + dm_build_1227.dm_build_1219 = dm_build_1225 + dm_build_1227.dm_build_1220 = dm_build_1226 + return dm_build_1227 +} + +func (dm_build_1229 *dm_build_1217) dm_build_830() error { + dm_build_1229.dm_build_845.dm_build_417.Dm_build_269(Dm_build_1216, dm_build_1229.dm_build_1218) + + dm_build_1229.dm_build_845.dm_build_417.Dm_build_133(dm_build_1229.dm_build_1220) + + if dm_build_1229.dm_build_845.dm_build_418.NewLobFlag { + dm_build_1229.dm_build_845.dm_build_417.Dm_build_133(-1) + } + dm_build_1229.dm_build_1219.Dm_build_7(dm_build_1229.dm_build_845.dm_build_417, int(dm_build_1229.dm_build_1220)) + return nil +} + +type dm_build_1230 struct { + dm_build_844 +} + +func dm_build_1231(dm_build_1232 *dm_build_414) *dm_build_1230 { + dm_build_1233 := new(dm_build_1230) + dm_build_1233.dm_build_849(dm_build_1232, Dm_build_717) + return dm_build_1233 +} + +type dm_build_1234 struct { + dm_build_844 + dm_build_1235 int32 +} + +func dm_build_1236(dm_build_1237 *dm_build_414, dm_build_1238 int32) *dm_build_1234 { + dm_build_1239 := new(dm_build_1234) + dm_build_1239.dm_build_849(dm_build_1237, Dm_build_730) + dm_build_1239.dm_build_1235 = dm_build_1238 + return dm_build_1239 +} + +func (dm_build_1241 *dm_build_1234) dm_build_830() error { + + dm_build_1242 := Dm_build_737 + dm_build_1242 += dm_build_1241.dm_build_845.dm_build_417.Dm_build_273(dm_build_1242, g2dbIsoLevel(dm_build_1241.dm_build_1235)) + return nil +} + +type dm_build_1243 struct { + dm_build_844 + dm_build_1244 *lob + dm_build_1245 byte + dm_build_1246 int + dm_build_1247 []byte + dm_build_1248 int + dm_build_1249 int +} + +func dm_build_1250(dm_build_1251 *dm_build_414, dm_build_1252 *lob, dm_build_1253 byte, dm_build_1254 int, dm_build_1255 []byte, + dm_build_1256 int, dm_build_1257 int) *dm_build_1243 { + dm_build_1258 := new(dm_build_1243) + dm_build_1258.dm_build_849(dm_build_1251, Dm_build_726) + dm_build_1258.dm_build_1244 = dm_build_1252 + dm_build_1258.dm_build_1245 = dm_build_1253 + dm_build_1258.dm_build_1246 = dm_build_1254 + dm_build_1258.dm_build_1247 = dm_build_1255 + dm_build_1258.dm_build_1248 = dm_build_1256 + dm_build_1258.dm_build_1249 = dm_build_1257 + return dm_build_1258 +} + +func (dm_build_1260 *dm_build_1243) dm_build_830() error { + + dm_build_1260.dm_build_845.dm_build_417.Dm_build_121(byte(dm_build_1260.dm_build_1244.lobFlag)) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_121(dm_build_1260.dm_build_1245) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1260.dm_build_1244.blobId)) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.groupId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.fileId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(dm_build_1260.dm_build_1244.pageNo) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.curFileId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(dm_build_1260.dm_build_1244.curPageNo) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(dm_build_1260.dm_build_1244.totalOffset) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(dm_build_1260.dm_build_1244.tabId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.colId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_149(uint64(dm_build_1260.dm_build_1244.rowId)) + + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(int32(dm_build_1260.dm_build_1246)) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(int32(dm_build_1260.dm_build_1249)) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_161(dm_build_1260.dm_build_1247) + + if dm_build_1260.dm_build_845.dm_build_418.NewLobFlag { + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.exGroupId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_129(dm_build_1260.dm_build_1244.exFileId) + dm_build_1260.dm_build_845.dm_build_417.Dm_build_133(dm_build_1260.dm_build_1244.exPageNo) + } + return nil +} + +func (dm_build_1262 *dm_build_1243) dm_build_834() (interface{}, error) { + + var dm_build_1263 = dm_build_1262.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1262.dm_build_1244.blobId = dm_build_1262.dm_build_845.dm_build_417.Dm_build_210() + dm_build_1262.dm_build_1244.fileId = dm_build_1262.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1262.dm_build_1244.pageNo = dm_build_1262.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1262.dm_build_1244.curFileId = dm_build_1262.dm_build_845.dm_build_417.Dm_build_204() + dm_build_1262.dm_build_1244.curPageNo = dm_build_1262.dm_build_845.dm_build_417.Dm_build_207() + dm_build_1262.dm_build_1244.totalOffset = dm_build_1262.dm_build_845.dm_build_417.Dm_build_207() + return dm_build_1263, nil +} + +const ( + Dm_build_1264 = Dm_build_737 + + Dm_build_1265 = Dm_build_1264 + ULINT_SIZE + + Dm_build_1266 = Dm_build_1265 + ULINT_SIZE + + Dm_build_1267 = Dm_build_1266 + BYTE_SIZE + + Dm_build_1268 = Dm_build_1267 + BYTE_SIZE + + Dm_build_1269 = Dm_build_1268 + BYTE_SIZE + + Dm_build_1270 = Dm_build_1269 + BYTE_SIZE + + Dm_build_1271 = Dm_build_1270 + BYTE_SIZE + + Dm_build_1272 = Dm_build_1271 + BYTE_SIZE + + Dm_build_1273 = Dm_build_1272 + BYTE_SIZE + + Dm_build_1274 = Dm_build_737 + + Dm_build_1275 = Dm_build_1274 + ULINT_SIZE + + Dm_build_1276 = Dm_build_1275 + ULINT_SIZE + + Dm_build_1277 = Dm_build_1276 + ULINT_SIZE + + Dm_build_1278 = Dm_build_1277 + ULINT_SIZE + + Dm_build_1279 = Dm_build_1278 + ULINT_SIZE + + Dm_build_1280 = Dm_build_1279 + BYTE_SIZE + + Dm_build_1281 = Dm_build_1280 + BYTE_SIZE + + Dm_build_1282 = Dm_build_1281 + BYTE_SIZE + + Dm_build_1283 = Dm_build_1282 + BYTE_SIZE + + Dm_build_1284 = Dm_build_1283 + BYTE_SIZE + + Dm_build_1285 = Dm_build_1284 + USINT_SIZE + + Dm_build_1286 = Dm_build_1285 + BYTE_SIZE +) + +type dm_build_1287 struct { + dm_build_844 + dm_build_1288 *DmConnection + dm_build_1289 int + Dm_build_1290 int32 + Dm_build_1291 []byte + dm_build_1292 byte +} + +func dm_build_1293(dm_build_1294 *dm_build_414) *dm_build_1287 { + dm_build_1295 := new(dm_build_1287) + dm_build_1295.dm_build_849(dm_build_1294, Dm_build_735) + dm_build_1295.dm_build_1288 = dm_build_1294.dm_build_418 + return dm_build_1295 +} + +func dm_build_1296(dm_build_1297 string, dm_build_1298 string) int { + dm_build_1299 := strings.Split(dm_build_1297, ".") + dm_build_1300 := strings.Split(dm_build_1298, ".") + + for i, serStr := range dm_build_1299 { + ser, _ := strconv.ParseInt(serStr, 10, 32) + global, _ := strconv.ParseInt(dm_build_1300[i], 10, 32) + if ser < global { + return -1 + } else if ser == global { + continue + } else { + return 1 + } + } + + return 0 +} + +func (dm_build_1302 *dm_build_1287) dm_build_830() error { + + dm_build_1302.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1264, int32(0)) + dm_build_1302.dm_build_845.dm_build_417.Dm_build_273(Dm_build_1265, int32(dm_build_1302.dm_build_1288.dmConnector.compress)) + + if dm_build_1302.dm_build_1288.dmConnector.loginEncrypt { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1267, 2) + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1266, 1) + } else { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1267, 0) + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1266, 0) + } + + if dm_build_1302.dm_build_1288.dmConnector.isBdtaRS { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1268, Dm_build_816) + } else { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1268, Dm_build_815) + } + + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1269, byte(dm_build_1302.dm_build_1288.dmConnector.compressID)) + + if dm_build_1302.dm_build_1288.dmConnector.loginCertificate != "" { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1270, 1) + } else { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1270, 0) + } + + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1271, 0) + dm_build_1302.dm_build_845.dm_build_417.Dm_build_265(Dm_build_1272, 1) + dm_build_1302.dm_build_845.dm_build_417.Dm_build_293(Dm_build_1273, uint16(dm_build_1302.dm_build_1288.MsgVersion)) + + dm_build_1303 := dm_build_1302.dm_build_1288.getServerEncoding() + dm_build_1304 := GetDriverVersion() + if len(dm_build_1304) > 0 { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_177(dm_build_1304, dm_build_1303, dm_build_1302.dm_build_845.dm_build_418) + } else { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_177(Dm_build_693, dm_build_1303, dm_build_1302.dm_build_845.dm_build_418) + } + + var dm_build_1305 byte + if dm_build_1302.dm_build_1288.dmConnector.uKeyName != "" { + dm_build_1305 = 1 + } else { + dm_build_1305 = 0 + } + + dm_build_1302.dm_build_845.dm_build_417.Dm_build_121(0) + + if dm_build_1305 == 1 { + + } + + if dm_build_1302.dm_build_1288.dmConnector.loginEncrypt { + clientPubKey, err := dm_build_1302.dm_build_845.dm_build_673() + if err != nil { + return err + } + dm_build_1302.dm_build_845.dm_build_417.Dm_build_165(clientPubKey) + } + + if dm_build_1302.dm_build_1288.dmConnector.catalog != "" { + dm_build_1302.dm_build_845.dm_build_417.Dm_build_177(dm_build_1302.dm_build_1288.dmConnector.catalog, dm_build_1303, dm_build_1302.dm_build_845.dm_build_418) + } + + return nil +} + +func (dm_build_1307 *dm_build_1287) dm_build_833() error { + dm_build_1307.dm_build_845.dm_build_417.Dm_build_95(0) + dm_build_1307.dm_build_845.dm_build_417.Dm_build_103(Dm_build_736, false, true) + return nil +} + +func (dm_build_1309 *dm_build_1287) dm_build_834() (interface{}, error) { + + dm_build_1309.dm_build_1288.sslEncrypt = int(dm_build_1309.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1274)) + dm_build_1309.dm_build_1288.GlobalServerSeries = int(dm_build_1309.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1275)) + + switch dm_build_1309.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1276) { + case 1: + dm_build_1309.dm_build_1288.serverEncoding = ENCODING_UTF8 + case 2: + dm_build_1309.dm_build_1288.serverEncoding = ENCODING_EUCKR + default: + dm_build_1309.dm_build_1288.serverEncoding = ENCODING_GB18030 + } + + dm_build_1309.dm_build_1288.dmConnector.compress = int(dm_build_1309.dm_build_845.dm_build_417.Dm_build_351(Dm_build_1277)) + dm_build_1310 := dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1279) + dm_build_1311 := dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1280) + dm_build_1309.dm_build_1288.dmConnector.isBdtaRS = dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1281) > 0 + dm_build_1309.dm_build_1288.dmConnector.compressID = int8(dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1282)) + + dm_build_1309.dm_build_845.dm_build_423 = dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1284) == 1 + dm_build_1309.dm_build_1288.dmConnector.newClientType = dm_build_1309.dm_build_845.dm_build_417.Dm_build_345(Dm_build_1285) == 1 + dm_build_1309.dm_build_1288.MsgVersion = int32(dm_build_1309.dm_build_845.dm_build_417.Dm_build_366(Dm_build_1286)) + + dm_build_1312 := dm_build_1309.dm_build_877() + if dm_build_1312 != nil { + return nil, dm_build_1312 + } + + dm_build_1313 := dm_build_1309.dm_build_845.dm_build_417.Dm_build_249(dm_build_1309.dm_build_1288.getServerEncoding(), dm_build_1309.dm_build_845.dm_build_418) + if dm_build_1296(dm_build_1313, Dm_build_694) < 0 { + return nil, ECGO_ERROR_SERVER_VERSION.throw() + } + + dm_build_1309.dm_build_1288.ServerVersion = dm_build_1313 + dm_build_1309.dm_build_1288.Malini2 = dm_build_1296(dm_build_1313, Dm_build_695) > 0 + dm_build_1309.dm_build_1288.Execute2 = dm_build_1296(dm_build_1313, Dm_build_696) > 0 + dm_build_1309.dm_build_1288.LobEmptyCompOrcl = dm_build_1296(dm_build_1313, Dm_build_697) > 0 + + if dm_build_1309.dm_build_845.dm_build_418.dmConnector.uKeyName != "" { + dm_build_1309.dm_build_1292 = 1 + } else { + dm_build_1309.dm_build_1292 = 0 + } + + if dm_build_1309.dm_build_1292 == 1 { + dm_build_1309.dm_build_845.dm_build_424 = dm_build_1309.dm_build_845.dm_build_417.Dm_build_244(16, dm_build_1309.dm_build_1288.getServerEncoding(), dm_build_1309.dm_build_845.dm_build_418) + } + + dm_build_1309.dm_build_1289 = -1 + dm_build_1314 := false + dm_build_1315 := false + dm_build_1309.Dm_build_1290 = -1 + if dm_build_1311 > 0 { + dm_build_1309.dm_build_1289 = int(dm_build_1309.dm_build_845.dm_build_417.Dm_build_207()) + } + + if dm_build_1310 > 0 { + + if dm_build_1309.dm_build_1289 == -1 { + dm_build_1314 = true + } else { + dm_build_1315 = true + } + + dm_build_1309.Dm_build_1291 = dm_build_1309.dm_build_845.dm_build_417.Dm_build_232() + } + + if dm_build_1311 == 2 { + dm_build_1309.Dm_build_1290 = dm_build_1309.dm_build_845.dm_build_417.Dm_build_207() + } + dm_build_1309.dm_build_845.dm_build_420 = dm_build_1314 + dm_build_1309.dm_build_845.dm_build_421 = dm_build_1315 + + return nil, nil +} + +type dm_build_1316 struct { + dm_build_844 +} + +func dm_build_1317(dm_build_1318 *dm_build_414, dm_build_1319 *DmStatement) *dm_build_1316 { + dm_build_1320 := new(dm_build_1316) + dm_build_1320.dm_build_853(dm_build_1318, Dm_build_711, dm_build_1319) + return dm_build_1320 +} + +func (dm_build_1322 *dm_build_1316) dm_build_830() error { + + dm_build_1322.dm_build_845.dm_build_417.Dm_build_265(Dm_build_737, 1) + return nil +} + +func (dm_build_1324 *dm_build_1316) dm_build_834() (interface{}, error) { + + dm_build_1324.dm_build_848.id = dm_build_1324.dm_build_845.dm_build_417.Dm_build_351(Dm_build_738) + + dm_build_1324.dm_build_848.readBaseColName = dm_build_1324.dm_build_845.dm_build_417.Dm_build_345(Dm_build_737) == 1 + return nil, nil +} + +type dm_build_1325 struct { + dm_build_844 + dm_build_1326 int32 +} + +func dm_build_1327(dm_build_1328 *dm_build_414, dm_build_1329 int32) *dm_build_1325 { + dm_build_1330 := new(dm_build_1325) + dm_build_1330.dm_build_849(dm_build_1328, Dm_build_712) + dm_build_1330.dm_build_1326 = dm_build_1329 + return dm_build_1330 +} + +func (dm_build_1332 *dm_build_1325) dm_build_831() { + dm_build_1332.dm_build_844.dm_build_831() + dm_build_1332.dm_build_845.dm_build_417.Dm_build_273(Dm_build_738, dm_build_1332.dm_build_1326) +} + +type dm_build_1333 struct { + dm_build_844 + dm_build_1334 []uint32 +} + +func dm_build_1335(dm_build_1336 *dm_build_414, dm_build_1337 []uint32) *dm_build_1333 { + dm_build_1338 := new(dm_build_1333) + dm_build_1338.dm_build_849(dm_build_1336, Dm_build_732) + dm_build_1338.dm_build_1334 = dm_build_1337 + return dm_build_1338 +} + +func (dm_build_1340 *dm_build_1333) dm_build_830() error { + + dm_build_1340.dm_build_845.dm_build_417.Dm_build_293(Dm_build_737, uint16(len(dm_build_1340.dm_build_1334))) + + for _, tableID := range dm_build_1340.dm_build_1334 { + dm_build_1340.dm_build_845.dm_build_417.Dm_build_145(uint32(tableID)) + } + + return nil +} + +func (dm_build_1342 *dm_build_1333) dm_build_834() (interface{}, error) { + dm_build_1343 := dm_build_1342.dm_build_845.dm_build_417.Dm_build_366(Dm_build_737) + if dm_build_1343 <= 0 { + return nil, nil + } + + dm_build_1344 := make([]int64, dm_build_1343) + for i := 0; i < int(dm_build_1343); i++ { + dm_build_1344[i] = dm_build_1342.dm_build_845.dm_build_417.Dm_build_210() + } + + return dm_build_1344, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zr.go b/dpi_bridge/third_party/chunanyong_dm/zr.go new file mode 100644 index 0000000..7e32e17 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zr.go @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "io" +) + +const ( + READ_LEN = Dm_build_820 +) + +type iOffRowBinder interface { + read(buf *Dm_build_0) + isReadOver() bool + getObj() interface{} +} + +type offRowBinder struct { + obj interface{} + encoding string + readOver bool + buffer *Dm_build_0 + position int32 + offRow bool + targetLength int64 +} + +func newOffRowBinder(obj interface{}, encoding string, targetLength int64) *offRowBinder { + return &offRowBinder{ + obj: obj, + encoding: encoding, + targetLength: targetLength, + readOver: false, + buffer: Dm_build_4(), + position: 0, + } +} + +type offRowBytesBinder struct { + *offRowBinder +} + +func newOffRowBytesBinder(obj []byte, encoding string) *offRowBytesBinder { + var binder = &offRowBytesBinder{ + newOffRowBinder(obj, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817 + return binder +} + +func (b *offRowBytesBinder) read(buf *Dm_build_0) { + if b.buffer.Dm_build_5() > 0 { + buf.Dm_build_37(b.buffer) + } else if !b.readOver { + var obj = b.obj.([]byte) + buf.Dm_build_26(obj, 0, len(obj)) + b.readOver = true + } +} + +func (b *offRowBytesBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowBytesBinder) getObj() interface{} { + return b.obj +} + +type offRowBlobBinder struct { + *offRowBinder +} + +func newOffRowBlobBinder(blob DmBlob, encoding string) *offRowBlobBinder { + var binder = &offRowBlobBinder{ + newOffRowBinder(blob, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817 + return binder +} + +func (b *offRowBlobBinder) read(buf *Dm_build_0) { + if b.buffer.Dm_build_5() > 0 { + buf.Dm_build_37(b.buffer) + } else if !b.readOver { + var obj = b.obj.(DmBlob) + var totalLen, _ = obj.GetLength() + var leaveLen = totalLen - int64(b.position) + var readLen = int32(leaveLen) + if leaveLen > READ_LEN { + readLen = READ_LEN + } + var bytes, _ = obj.getBytes(int64(b.position)+1, readLen) + b.position += readLen + if b.position == int32(totalLen) { + b.readOver = true + } + buf.Dm_build_26(bytes, 0, len(bytes)) + } +} + +func (b *offRowBlobBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowBlobBinder) getObj() interface{} { + return b.obj +} + +type offRowClobBinder struct { + *offRowBinder +} + +func newOffRowClobBinder(clob DmClob, encoding string) *offRowClobBinder { + var binder = &offRowClobBinder{ + newOffRowBinder(clob, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817 + return binder +} + +func (b *offRowClobBinder) read(buf *Dm_build_0) { + if b.buffer.Dm_build_5() > 0 { + buf.Dm_build_37(b.buffer) + } else if !b.readOver { + var obj = b.obj.(DmClob) + var totalLen, _ = obj.GetLength() + var leaveLen = totalLen - int64(b.position) + var readLen = int32(leaveLen) + if leaveLen > READ_LEN { + readLen = READ_LEN + } + var str, _ = obj.getSubString(int64(b.position)+1, readLen) + var bytes = Dm_build_1346.Dm_build_1562(str, b.encoding, nil) + b.position += readLen + if b.position == int32(totalLen) { + b.readOver = true + } + buf.Dm_build_26(bytes, 0, len(bytes)) + } +} + +func (b *offRowClobBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowClobBinder) getObj() interface{} { + return b.obj +} + +type offRowReaderBinder struct { + *offRowBinder +} + +func newOffRowReaderBinder(reader io.Reader, encoding string) *offRowReaderBinder { + var binder = &offRowReaderBinder{ + newOffRowBinder(reader, encoding, int64(IGNORE_TARGET_LENGTH)), + } + binder.read(binder.buffer) + binder.offRow = binder.buffer.Dm_build_5() > Dm_build_817 + return binder +} + +func (b *offRowReaderBinder) read(buf *Dm_build_0) { + if b.buffer.Dm_build_5() > 0 { + buf.Dm_build_37(b.buffer) + } else if !b.readOver { + var err error + var readLen = READ_LEN + var reader = b.obj.(io.Reader) + var bytes = make([]byte, readLen) + readLen, err = reader.Read(bytes) + if err == io.EOF { + b.readOver = true + return + } + b.position += int32(readLen) + if readLen < len(bytes) || b.targetLength != int64(IGNORE_TARGET_LENGTH) && int64(b.position) == b.targetLength { + b.readOver = true + } + buf.Dm_build_26(bytes[0:readLen], 0, readLen) + } +} + +func (b *offRowReaderBinder) readAll() []byte { + var byteArray = Dm_build_4() + b.read(byteArray) + for !b.readOver { + b.read(byteArray) + } + return byteArray.Dm_build_47() +} + +func (b *offRowReaderBinder) isReadOver() bool { + return b.readOver +} + +func (b *offRowReaderBinder) getObj() interface{} { + return b.obj +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zs.go b/dpi_bridge/third_party/chunanyong_dm/zs.go new file mode 100644 index 0000000..316b431 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zs.go @@ -0,0 +1,882 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "fmt" + "math" + "strconv" + "strings" + "time" + "unicode" + "unicode/utf8" + + "gitee.com/chunanyong/dm/util" +) + +type oracleDateFormat struct { + PM bool + TZNegative bool + pattern string + language int + scale int32 + FormatElementList []interface{} + YearElement yearElement + MonthElement monthElement + MonElement monElement + MMElement mmElement + DDElement ddElement + HH24Element hh24Element + HH12Element hh12Element + MIElement miElement + SSElement ssElement + FElement fElement + TZHElement tzhElement + TZMElement tzmElement + AMElement amElement +} + +type element interface { + /** + * 从字符串中解析出对应的值, + * @param str 完整的字符串 + * @param offset 当前偏移 + * @return 解析后的offset + */ + parse(str string, offset int, dt []int) (int, error) + + /** + * 将时间值value格式化成字符串 + */ + format(dt []int) string +} + +type yearElement struct { + OracleDateFormat *oracleDateFormat + len int +} + +func (YearElement yearElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+YearElement.len && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + if YearElement.len < 4 { + today := strconv.FormatInt(int64(dt[OFFSET_YEAR]), 10) + i, err := strconv.ParseInt(today[:4-YearElement.len]+str, 10, 32) + if err != nil { + return 0, err + } + dt[OFFSET_YEAR] = int(i) + } else { + i, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return 0, err + } + dt[OFFSET_YEAR] = int(i) + } + + return offset + strLen, nil +} + +func (YearElement yearElement) format(dt []int) string { + return YearElement.OracleDateFormat.formatInt(dt[OFFSET_YEAR], YearElement.len) +} + +type monthElement struct { + OracleDateFormat *oracleDateFormat + upperCase bool + lowerCase bool +} + +var monthNameList = []string{"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + +func (MonthElement monthElement) parse(str string, offset int, dt []int) (int, error) { + + if MonthElement.OracleDateFormat.language == LANGUAGE_CN { + index := strings.IndexRune(str[offset:], '月') + if index == -1 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + index += offset + + mon, err := strconv.ParseInt(str[offset:index], 10, 32) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if mon > 12 || mon < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(mon) + return index + utf8.RuneLen('月'), nil + } else { + str = str[offset:] + mon := 0 + for i := 1; i < len(monthNameList); i++ { + if util.StringUtil.StartWithIgnoreCase(str, monthNameList[i]) { + mon = i + break + } + } + if mon == 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + dt[OFFSET_MONTH] = mon + return offset + len(monthNameList[mon]), nil + } +} + +func (MonthElement monthElement) format(dt []int) string { + value := dt[OFFSET_MONTH] + + if MonthElement.OracleDateFormat.language == LANGUAGE_CN { + return strconv.FormatInt(int64(value), 10) + "月" + } + + if MonthElement.upperCase { + return strings.ToUpper(monthNameList[value]) + } else if MonthElement.lowerCase { + return strings.ToLower(monthNameList[value]) + } else { + return monthNameList[value] + } + +} + +type monElement struct { + OracleDateFormat *oracleDateFormat + upperCase bool + lowerCase bool +} + +var monNameList []string = []string{"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} + +func (MonElement monElement) parse(str string, offset int, dt []int) (int, error) { + + if MonElement.OracleDateFormat.language == LANGUAGE_CN { + index := strings.IndexRune(str[offset:], '月') + offset + if index == -1+offset { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + mon, err := strconv.ParseInt(str[offset:index], 10, 32) + if err != nil { + return -1, err + } + + if mon > 12 || mon < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(mon) + return index + utf8.RuneLen('月'), nil + } else { + str = str[offset : offset+3] + mon := 0 + for i := 1; i < len(monNameList); i++ { + if util.StringUtil.EqualsIgnoreCase(str, monNameList[i]) { + mon = i + break + } + } + if mon == 0 { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + dt[OFFSET_MONTH] = mon + return offset + 3, nil + } + +} + +func (MonElement monElement) format(dt []int) string { + value := dt[OFFSET_MONTH] + language := int(0) + if language == LANGUAGE_CN { + return strconv.FormatInt(int64(value), 10) + "月" + } + + if MonElement.upperCase { + return strings.ToUpper(monNameList[value]) + } else if MonElement.lowerCase { + return strings.ToLower(monNameList[value]) + } else { + return monNameList[value] + } +} + +type mmElement struct { + OracleDateFormat *oracleDateFormat +} + +func (MMElement mmElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + month, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, ECGO_INVALID_DATETIME_FORMAT.throw() + } + + if month > 12 || month < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MONTH] = int(month) + return offset + strLen, nil +} + +func (MMElement mmElement) format(dt []int) string { + return MMElement.OracleDateFormat.formatInt(dt[OFFSET_MONTH], 2) +} + +type ddElement struct { + OracleDateFormat *oracleDateFormat +} + +func (DDElement ddElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + day, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if day > 31 || day < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_DAY] = int(day) + return offset + strLen, nil +} + +func (DDElement ddElement) format(dt []int) string { + return DDElement.OracleDateFormat.formatInt(dt[OFFSET_DAY], 2) +} + +type hh24Element struct { + OracleDateFormat *oracleDateFormat +} + +func (HH24Element hh24Element) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + hour, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if hour > 23 || hour < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_HOUR] = int(hour) // 0-23 + return offset + strLen, nil +} + +func (HH24Element hh24Element) format(dt []int) string { + return HH24Element.OracleDateFormat.formatInt(dt[OFFSET_HOUR], 2) // 0-23 +} + +type hh12Element struct { + OracleDateFormat *oracleDateFormat +} + +func (HH12Element hh12Element) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + hour, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if hour > 12 || hour < 1 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_HOUR] = int(hour) + return offset + strLen, nil +} + +func (HH12Element hh12Element) format(dt []int) string { + var ret string + value := dt[OFFSET_HOUR] + if value > 12 || value == 0 { + ret = HH12Element.OracleDateFormat.formatInt(int(math.Abs(float64(value-12))), 2) // 1-12 + } else { + ret = HH12Element.OracleDateFormat.formatInt(value, 2) + } + return ret +} + +type miElement struct { + OracleDateFormat *oracleDateFormat +} + +func (MIElement miElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + minute, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if minute > 59 || minute < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_MINUTE] = int(minute) // 0-59 + return offset + strLen, nil +} + +func (MIElement miElement) format(dt []int) string { + return MIElement.OracleDateFormat.formatInt(dt[OFFSET_MINUTE], 2) // 0-59 +} + +type ssElement struct { + OracleDateFormat *oracleDateFormat +} + +func (SSElement ssElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + second, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if second > 59 || second < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + dt[OFFSET_SECOND] = int(second) // 0-59 + return offset + strLen, nil +} + +func (SSElement ssElement) format(dt []int) string { + return SSElement.OracleDateFormat.formatInt(dt[OFFSET_SECOND], 2) // 0-59 +} + +type fElement struct { + OracleDateFormat *oracleDateFormat + len int +} + +func (FElement fElement) parse(str string, offset int, dt []int) (int, error) { + strLen := 0 + maxLen := 0 + if FElement.len > 0 { + maxLen = FElement.len + } else { + maxLen = NANOSECOND_DIGITS + } + for i := offset; i < offset+maxLen && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + ms, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if strLen < NANOSECOND_DIGITS { + ms *= int64(math.Pow10(NANOSECOND_DIGITS - strLen)) + } else { + ms /= int64(math.Pow10(strLen - NANOSECOND_DIGITS)) + } + + dt[OFFSET_NANOSECOND] = int(ms) + return offset + strLen, nil +} + +func (FElement fElement) format(dt []int) string { + msgLen := 0 + if FElement.len > 0 { + msgLen = FElement.len + } else { + msgLen = int(FElement.OracleDateFormat.scale) + } + return FElement.OracleDateFormat.formatMilliSecond(dt[OFFSET_NANOSECOND], msgLen) +} + +type tzhElement struct { + OracleDateFormat *oracleDateFormat +} + +func (TZHElement tzhElement) parse(str string, offset int, dt []int) (int, error) { + if str[offset] == '+' { + offset += 1 + } else if str[offset] == '-' { + offset += 1 + TZHElement.OracleDateFormat.TZNegative = true + } + + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + + tzh, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + + if tzh > 23 || tzh < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + + tzh *= 60 + if dt[OFFSET_TIMEZONE] == int(INVALID_VALUE) { + dt[OFFSET_TIMEZONE] = int(tzh) + } else { + dt[OFFSET_TIMEZONE] += int(tzh) + } + + return offset + strLen, nil +} + +func (TZHElement tzhElement) format(dt []int) string { + var value int + if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) { + value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) / 60 + } else { + value = 0 + } + + return TZHElement.OracleDateFormat.formatInt(value, 2) +} + +type tzmElement struct { + OracleDateFormat *oracleDateFormat +} + +func (TZMElement tzmElement) parse(str string, offset int, dt []int) (int, error) { + if str[offset] == '+' { + offset += 1 + } else if str[offset] == '-' { + offset += 1 + TZMElement.OracleDateFormat.TZNegative = true + } + + strLen := 0 + for i := offset; i < offset+2 && i < len(str); i++ { + if !unicode.IsLetter(rune(str[i])) && !unicode.IsDigit(rune(str[i])) { + break + } + strLen++ + } + str = str[offset : offset+strLen] + + tzm, err := strconv.ParseInt(str, 10, 32) + if err != nil { + return -1, err + } + if tzm > 59 || tzm < 0 { + return -1, ECGO_INVALID_DATETIME_VALUE.throw() + } + + if dt[OFFSET_TIMEZONE] == INVALID_VALUE { + dt[OFFSET_TIMEZONE] = int(tzm) + } else { + dt[OFFSET_TIMEZONE] += int(tzm) + } + return offset + strLen, nil +} + +func (TZMElement tzmElement) format(dt []int) string { + var value int + if dt[OFFSET_TIMEZONE] != int(INVALID_VALUE) { + value = int(math.Abs(float64(dt[OFFSET_TIMEZONE]))) % 60 + } else { + value = 0 + } + + return TZMElement.OracleDateFormat.formatInt(value, 2) +} + +type amElement struct { + OracleDateFormat *oracleDateFormat +} + +func (AMElement amElement) parse(str string, offset int, dt []int) (int, error) { + runeStr := ([]rune(str))[offset : offset+2] + + if AMElement.OracleDateFormat.language == LANGUAGE_CN { + if util.StringUtil.EqualsIgnoreCase("下午", string(runeStr)) { + AMElement.OracleDateFormat.PM = true + return offset + utf8.RuneLen('下') + utf8.RuneLen('午'), nil + } else { + AMElement.OracleDateFormat.PM = false + return offset + utf8.RuneLen('上') + utf8.RuneLen('午'), nil + } + + } else if util.StringUtil.EqualsIgnoreCase("PM", string(runeStr)) { + AMElement.OracleDateFormat.PM = true + } else { + AMElement.OracleDateFormat.PM = false + } + + return offset + 2, nil +} + +func (AMElement amElement) format(dt []int) string { + hour := dt[OFFSET_HOUR] + language := int(0) + if language == LANGUAGE_CN { + if hour > 12 { + return "下午" + } else { + return "上午" + } + } + + if hour > 12 { + return "PM" + } else { + return "AM" + } +} + +/** + * 将int值格式化成指定长度,长度不足前面补0,长度超过的取末尾指定长度 + */ +func (OracleDateFormat *oracleDateFormat) formatInt(value int, len int) string { + pow := int(math.Pow10(len)) + if value >= pow { + value %= pow + } + value += pow + return strconv.FormatInt(int64(value), 10)[1:] +} + +/** + * 格式化毫秒值 + * @param ms + * @param len <= 6 + */ +func (OracleDateFormat *oracleDateFormat) formatMilliSecond(ms int, len int) string { + var ret string + if ms < 10 { + ret = "00000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100 { + ret = "0000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 1000 { + ret = "000" + strconv.FormatInt(int64(ms), 10) + } else if ms < 10000 { + ret = "00" + strconv.FormatInt(int64(ms), 10) + } else if ms < 100000 { + ret = "0" + strconv.FormatInt(int64(ms), 10) + } else { + ret = strconv.FormatInt(int64(ms), 10) + } + + if len < 6 { + ret = ret[:len] + } + return ret +} + +func getFormat() *oracleDateFormat { + format := new(oracleDateFormat) + format.PM = false + format.TZNegative = false + format.YearElement = yearElement{format, 4} + format.MonthElement = monthElement{format, false, false} + format.MonElement = monElement{format, false, false} + format.MMElement = mmElement{format} + format.DDElement = ddElement{format} + format.HH24Element = hh24Element{format} + format.HH12Element = hh12Element{format} + format.MIElement = miElement{format} + format.SSElement = ssElement{format} + format.FElement = fElement{format, -1} + format.TZHElement = tzhElement{format} + format.TZMElement = tzmElement{format} + format.AMElement = amElement{format} + + return format +} + +func (OracleDateFormat *oracleDateFormat) parse(str string) (ret []int, err error) { + defer func() { + if p := recover(); p != nil { + err = ECGO_INVALID_DATETIME_FORMAT.throw() + } + }() + OracleDateFormat.TZNegative = false + OracleDateFormat.PM = false + dt := make([]int, DT_LEN) + // oracle默认年月日为 当前时间 + today := time.Now() + dt[OFFSET_YEAR] = today.Year() + dt[OFFSET_MONTH] = int(today.Month()) + dt[OFFSET_DAY] = today.Day() + dt[OFFSET_TIMEZONE] = INVALID_VALUE + offset := 0 + str = strings.TrimSpace(str) + for _, obj := range OracleDateFormat.FormatElementList { + // 跳过空格 + for str[offset] == ' ' && fmt.Sprintf("%+v", obj) != " " { + offset++ + } + if e, ok := obj.(element); ok { + offset, err = e.parse(str, offset, dt) + if err != nil { + return nil, err + } + } else { + offset += len(obj.(string)) + } + } + if offset < len(str) { + //[6103]:文字与格式字符串不匹配. + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + + // 12小时制时间转换 + if OracleDateFormat.PM { + dt[OFFSET_HOUR] = (dt[OFFSET_HOUR] + 12) % 24 + } + + // 时区符号保留 + if OracleDateFormat.TZNegative { + dt[OFFSET_TIMEZONE] = -dt[OFFSET_TIMEZONE] + } + + // check day + if dt[OFFSET_DAY] > getDaysOfMonth(dt[OFFSET_YEAR], dt[OFFSET_MONTH]) || dt[OFFSET_DAY] < 1 { + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + // check timezone 兼容oracle + if dt[OFFSET_TIMEZONE] != INVALID_VALUE && (dt[OFFSET_TIMEZONE] > 14*60 || dt[OFFSET_TIMEZONE] <= -13*60) { + return nil, ECGO_INVALID_DATETIME_VALUE.throw() + } + return dt, nil +} + +func parse(str string, pattern string, language int) ([]int, error) { + f := getFormat() + f.setPattern(pattern) + f.language = language + return f.parse(str) +} + +func (OracleDateFormat *oracleDateFormat) setPattern(pattern string) { + if pattern != OracleDateFormat.pattern { + OracleDateFormat.pattern = pattern + OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:0] + OracleDateFormat.analysePattern(pattern) + } +} + +func format(dt []int, pattern string, scale int32, language int) string { + f := getFormat() + f.setPattern(pattern) + f.language = language + f.scale = scale + ret := f.format(dt) + return ret +} + +func (OracleDateFormat *oracleDateFormat) format(dt []int) string { + sf := strings.Builder{} + tzStart := false + for _, obj := range OracleDateFormat.FormatElementList { + _, ok1 := obj.(tzhElement) + _, ok2 := obj.(tzmElement) + if !tzStart && (ok1 || ok2) { + tzStart = true + if dt[OFFSET_TIMEZONE] < 0 { + sf.WriteString("-") + } else { + sf.WriteString("+") + } + } + + if e, ok := obj.(element); ok { + sf.WriteString(e.format(dt)) + } else { + sf.WriteString(obj.(string)) + } + } + return sf.String() +} + +/** + * 解析格式串 + */ +func (OracleDateFormat *oracleDateFormat) analysePattern(pattern string) ([]interface{}, error) { + + // 按分隔符split + pattern = strings.TrimSpace(pattern) + l := len(pattern) + var splitPatterns []string + starti := 0 + var curChar rune + for i := 0; i < l; i++ { + curChar = rune(pattern[i]) + if !unicode.IsDigit(curChar) && !unicode.IsLetter(curChar) { + if i > starti { + splitPatterns = append(splitPatterns, pattern[starti:i]) + } + + splitPatterns = append(splitPatterns, string(curChar)) + starti = i + 1 + } else if i == l-1 { + splitPatterns = append(splitPatterns, pattern[starti:i+1]) + } + } + + // 每个串按照从完整串,然后依次去掉一个末尾字符 来进行尝试规约 + for _, subPattern := range splitPatterns { + if len(subPattern) != 1 || unicode.IsDigit(rune(subPattern[0])) || unicode.IsLetter(rune(subPattern[0])) { + fmtWord := subPattern + for subPattern != "" { + i := len(subPattern) + for ; i > 0; i-- { + fmtWord = subPattern[0:i] + element, err := OracleDateFormat.getFormatElement(fmtWord) + if err != nil { + return nil, err + } + if element != nil { + // 忽略时区前面的+-号 + if element == OracleDateFormat.TZHElement || element == OracleDateFormat.TZMElement { + var lastFormatElement string = OracleDateFormat.FormatElementList[len(OracleDateFormat.FormatElementList)-1].(string) + if util.StringUtil.Equals("+", lastFormatElement) || util.StringUtil.Equals("-", lastFormatElement) { + OracleDateFormat.FormatElementList = OracleDateFormat.FormatElementList[:len(OracleDateFormat.FormatElementList)-2] + } + } + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, element) + if i == len(subPattern) { + subPattern = "" + } else { + subPattern = subPattern[i:len(subPattern)] + } + break + } + } + + if i == 0 { + // 非标识符串 + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern) + break + } + } + + } else { + OracleDateFormat.FormatElementList = append(OracleDateFormat.FormatElementList, subPattern) + } + } + return OracleDateFormat.FormatElementList, nil +} + +func (OracleDateFormat *oracleDateFormat) getFormatElement(word string) (element, error) { + if util.StringUtil.EqualsIgnoreCase("HH", word) || util.StringUtil.EqualsIgnoreCase("HH12", word) { + return OracleDateFormat.HH12Element, nil + } else if util.StringUtil.EqualsIgnoreCase("HH24", word) { + return OracleDateFormat.HH24Element, nil + } else if util.StringUtil.EqualsIgnoreCase("MI", word) { + return OracleDateFormat.MIElement, nil + } else if util.StringUtil.EqualsIgnoreCase("SS", word) { + return OracleDateFormat.SSElement, nil + } else if util.StringUtil.EqualsIgnoreCase("AM", word) || util.StringUtil.EqualsIgnoreCase("A.M.", word) || util.StringUtil.EqualsIgnoreCase("PM", word) || util.StringUtil.EqualsIgnoreCase("P.M.", word) { + return OracleDateFormat.AMElement, nil + } else if util.StringUtil.Equals("MONTH", word) { + OracleDateFormat.MonthElement.upperCase = true + OracleDateFormat.MonthElement.lowerCase = false + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.Equals("month", word) { + OracleDateFormat.MonthElement.upperCase = false + OracleDateFormat.MonthElement.lowerCase = true + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.EqualsIgnoreCase("Month", word) { + OracleDateFormat.MonthElement.upperCase = false + OracleDateFormat.MonthElement.lowerCase = false + return OracleDateFormat.MonthElement, nil + } else if util.StringUtil.Equals("MON", word) { + OracleDateFormat.MonElement.upperCase = true + OracleDateFormat.MonElement.lowerCase = false + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.Equals("mon", word) { + OracleDateFormat.MonElement.upperCase = false + OracleDateFormat.MonElement.lowerCase = true + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.EqualsIgnoreCase("Mon", word) { + OracleDateFormat.MonElement.upperCase = false + OracleDateFormat.MonElement.lowerCase = false + return OracleDateFormat.MonElement, nil + } else if util.StringUtil.EqualsIgnoreCase("MM", word) { + return OracleDateFormat.MMElement, nil + } else if util.StringUtil.EqualsIgnoreCase("DD", word) { + return OracleDateFormat.DDElement, nil + } else if util.StringUtil.EqualsIgnoreCase("TZH", word) { + return OracleDateFormat.TZHElement, nil + } else if util.StringUtil.EqualsIgnoreCase("TZM", word) { + return OracleDateFormat.TZMElement, nil + } else if strings.Index(word, "Y") == 0 || strings.Index(word, "y") == 0 { + OracleDateFormat.YearElement.len = len(word) + return OracleDateFormat.YearElement, nil + } else if strings.Index(word, "F") == 0 || strings.Index(word, "f") == 0 { + + word = strings.ToUpper(word) + numIndex := strings.LastIndex(word, "F") + 1 + var count int64 + var err error + if numIndex < len(word) { + count, err = strconv.ParseInt(word[numIndex:len(word)], 10, 32) + if err != nil { + return nil, err + } + } else { + count = -1 + } + + OracleDateFormat.FElement.len = int(count) + return OracleDateFormat.FElement, nil + } + + return nil, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zv.go b/dpi_bridge/third_party/chunanyong_dm/zv.go new file mode 100644 index 0000000..3029be0 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zv.go @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "strconv" + "strings" +) + +type Properties struct { + innerProps map[string]string +} + +func NewProperties() *Properties { + p := Properties{ + innerProps: make(map[string]string, 50), + } + return &p +} + +func (g *Properties) SetProperties(p *Properties) { + if p == nil { + return + } + for k, v := range p.innerProps { + g.Set(strings.ToLower(k), v) + } +} + +func (g *Properties) Len() int { + return len(g.innerProps) +} + +func (g *Properties) IsNil() bool { + return g == nil || g.innerProps == nil +} + +func (g *Properties) GetString(key, def string) string { + v, ok := g.innerProps[strings.ToLower(key)] + + if !ok || v == "" { + return def + } + return v +} + +func (g *Properties) GetInt(key string, def int, min int, max int) int { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } + + i, err := strconv.Atoi(value) + if err != nil { + return def + } + + if i > max || i < min { + return def + } + return i +} + +func (g *Properties) GetBool(key string, def bool) bool { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } + b, err := strconv.ParseBool(value) + if err != nil { + return def + } + return b +} + +func (g *Properties) GetTrimString(key string, def string) string { + value, ok := g.innerProps[strings.ToLower(key)] + if !ok || value == "" { + return def + } else { + return strings.TrimSpace(value) + } +} + +func (g *Properties) GetStringArray(key string, def []string) []string { + value, ok := g.innerProps[strings.ToLower(key)] + if ok || value != "" { + array := strings.Split(value, ",") + if len(array) > 0 { + return array + } + } + return def +} + +//func (g *Properties) GetBool(key string) bool { +// i, _ := strconv.ParseBool(g.innerProps[key]) +// return i +//} + +func (g *Properties) Set(key, value string) { + g.innerProps[strings.ToLower(key)] = value +} + +func (g *Properties) SetIfNotExist(key, value string) { + if _, ok := g.innerProps[strings.ToLower(key)]; !ok { + g.Set(key, value) + } +} + +// 如果p有g没有的键值对,添加进g中 +func (g *Properties) SetDiffProperties(p *Properties) { + if p == nil { + return + } + for k, v := range p.innerProps { + if _, ok := g.innerProps[strings.ToLower(k)]; !ok { + g.innerProps[strings.ToLower(k)] = v + } + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zw.go b/dpi_bridge/third_party/chunanyong_dm/zw.go new file mode 100644 index 0000000..7c4c4ce --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zw.go @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "math/rand" + "strconv" + "sync" + "time" + + "gitee.com/chunanyong/dm/util" +) + +var rwMap sync.Map + +type rwCounter struct { + ntrx_primary int64 + + ntrx_total int64 + + primaryPercent float64 + + standbyPercent float64 + + standbyNTrxMapMu sync.RWMutex + + standbyNTrxMap map[string]int64 + + standbyIdMapMu sync.RWMutex + + standbyIdMap map[string]int32 + + standbyCount int32 + + flag []int32 + + increments []int32 + + //用来计数,选择存活的standby节点 + indexCount int64 +} + +func newRWCounter(primaryPercent int32, standbyCount int32) *rwCounter { + rwc := new(rwCounter) + rwc.standbyNTrxMap = make(map[string]int64) + rwc.standbyIdMap = make(map[string]int32) + rwc.reset(primaryPercent, standbyCount) + return rwc +} + +func (rwc *rwCounter) reset(primaryPercent int32, standbyCount int32) { + rwc.ntrx_primary = 0 + rwc.ntrx_total = 0 + rwc.standbyCount = standbyCount + rwc.increments = make([]int32, standbyCount+1) + rwc.flag = make([]int32, standbyCount+1) + var gcd = util.GCD(primaryPercent*standbyCount, 100-primaryPercent) + rwc.increments[0] = primaryPercent * standbyCount / gcd + for i, tmp := 1, (100-primaryPercent)/gcd; i < len(rwc.increments); i++ { + rwc.increments[i] = tmp + } + copy(rwc.flag, rwc.increments) + + if standbyCount > 0 { + rwc.primaryPercent = float64(primaryPercent) / 100.0 + rwc.standbyPercent = float64(100-primaryPercent) / 100.0 / float64(standbyCount) + } else { + rwc.primaryPercent = 1 + rwc.standbyPercent = 0 + } +} + +// 连接创建成功后调用,需要服务器返回standbyCount +func getRwCounterInstance(conn *DmConnection, standbyCount int32) *rwCounter { + key := conn.dmConnector.host + "_" + strconv.Itoa(int(conn.dmConnector.port)) + "_" + strconv.Itoa(int(conn.dmConnector.rwPercent)) + + val, ok := rwMap.Load(key) + if !ok { + rwc := newRWCounter(conn.dmConnector.rwPercent, standbyCount) + rwMap.Store(key, rwc) + return rwc + } else { + rwc := val.(*rwCounter) + if rwc.standbyCount != standbyCount { + rwc.reset(conn.dmConnector.rwPercent, standbyCount) + } + return rwc + } +} + +/** +* @return 主机; + */ +func (rwc *rwCounter) countPrimary() RWSiteEnum { + rwc.adjustNtrx() + rwc.increasePrimaryNtrx() + return PRIMARY +} + +/** +* @param dest 主机; 备机; any; +* @return 主机; 备机 + */ +func (rwc *rwCounter) count(dest RWSiteEnum, standby *DmConnection) RWSiteEnum { + rwc.adjustNtrx() + switch dest { + case ANYSITE: + { + if rwc.primaryPercent == 1 || (rwc.flag[0] > rwc.getStandbyFlag(standby) && rwc.flag[0] > util.Sum(rwc.flag[1:])) { + rwc.increasePrimaryNtrx() + dest = PRIMARY + } else { + rwc.increaseStandbyNtrx(standby) + dest = STANDBY + } + } + case STANDBY: + { + rwc.increaseStandbyNtrx(standby) + } + case PRIMARY: + { + rwc.increasePrimaryNtrx() + } + } + return dest +} + +/** +* 防止ntrx超出有效范围,等比调整 + */ +func (rwc *rwCounter) adjustNtrx() { + if rwc.ntrx_total >= INT64_MAX { + var min int64 + var i = 0 + func() { + rwc.standbyNTrxMapMu.Lock() + defer rwc.standbyNTrxMapMu.Unlock() + for _, num := range rwc.standbyNTrxMap { + if i == 0 || num < min { + min = num + } + i++ + } + if rwc.ntrx_primary < min { + min = rwc.ntrx_primary + } + rwc.ntrx_primary /= min + rwc.ntrx_total /= min + for k, v := range rwc.standbyNTrxMap { + rwc.standbyNTrxMap[k] = v / min + } + }() + } + + if rwc.flag[0] <= 0 && util.Sum(rwc.flag[1:]) <= 0 { + // 如果主库事务数以及所有备库事务数的总和 都 <= 0, 重置事务计数,给每个库的事务计数加上初始计数值 + for i := 0; i < len(rwc.flag); i++ { + rwc.flag[i] += rwc.increments[i] + } + } +} + +func (rwc *rwCounter) increasePrimaryNtrx() { + rwc.ntrx_primary++ + rwc.flag[0]-- + rwc.ntrx_total++ +} + +//func (rwc *rwCounter) getStandbyNtrx(standby *DmConnection) int64 { +// key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) +// ret, ok := rwc.standbyNTrxMap[key] +// if !ok { +// ret = 0 +// } +// +// return ret +//} + +func (rwc *rwCounter) getStandbyId(standby *DmConnection) int32 { + key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) + rwc.standbyIdMapMu.Lock() + defer rwc.standbyIdMapMu.Unlock() + sid, ok := rwc.standbyIdMap[key] + if !ok { + sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary + if sid > rwc.standbyCount { + // 不在有效备库中 + return -1 + } + rwc.standbyIdMap[key] = sid + } + return sid +} + +func (rwc *rwCounter) getStandbyFlag(standby *DmConnection) int32 { + sid := rwc.getStandbyId(standby) + if sid > 0 && sid < int32(len(rwc.flag)) { + // 保证备库有效 + return rwc.flag[sid] + } + return 0 +} + +func (rwc *rwCounter) increaseStandbyNtrx(standby *DmConnection) { + key := standby.dmConnector.host + ":" + strconv.Itoa(int(standby.dmConnector.port)) + func() { + rwc.standbyNTrxMapMu.Lock() + defer rwc.standbyNTrxMapMu.Unlock() + ret, ok := rwc.standbyNTrxMap[key] + if ok { + ret += 1 + } else { + ret = 1 + } + rwc.standbyNTrxMap[key] = ret + }() + func() { + rwc.standbyIdMapMu.Lock() + defer rwc.standbyIdMapMu.Unlock() + sid, ok := rwc.standbyIdMap[key] + if !ok { + sid = int32(len(rwc.standbyIdMap) + 1) // 下标0是primary + rwc.standbyIdMap[key] = sid + } + rwc.flag[sid]-- + }() + rwc.ntrx_total++ +} + +func (rwc *rwCounter) random(rowCount int32) int32 { + rand.Seed(time.Now().UnixNano()) + if rowCount > rwc.standbyCount { + return rand.Int31n(rwc.standbyCount) + } else { + return rand.Int31n(rowCount) + } +} + +func (rwc *rwCounter) String() string { + return "PERCENT(P/S) : " + strconv.FormatFloat(rwc.primaryPercent, 'f', -1, 64) + "/" + strconv.FormatFloat(rwc.standbyPercent, 'f', -1, 64) + "\nNTRX_PRIMARY : " + + strconv.FormatInt(rwc.ntrx_primary, 10) + "\nNTRX_TOTAL : " + strconv.FormatInt(rwc.ntrx_total, 10) + "\nNTRX_STANDBY : " +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zx.go b/dpi_bridge/third_party/chunanyong_dm/zx.go new file mode 100644 index 0000000..03823a1 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zx.go @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "context" + "database/sql" + "database/sql/driver" + "errors" + "io" + "regexp" + "strings" + "time" + + "gitee.com/chunanyong/dm/util" +) + +const ( + SQL_SELECT_STANDBY = "select distinct mailIni.inst_name, mailIni.INST_IP, mailIni.INST_PORT, archIni.arch_status " + + "from v$arch_status archIni " + + "left join (select * from V$DM_MAL_INI) mailIni on archIni.arch_dest = mailIni.inst_name " + + "left join V$MAL_LINK_STATUS on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " + + "where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'" + + SQL_SELECT_STANDBY2 = "select distinct " + + "mailIni.mal_inst_name, mailIni.mal_INST_HOST, mailIni.mal_INST_PORT, archIni.arch_status " + + "from v$arch_status archIni " + "left join (select * from V$DM_MAL_INI) mailIni " + + "on archIni.arch_dest = mailIni.mal_inst_name " + "left join V$MAL_LINK_STATUS " + + "on CTL_LINK_STATUS = 'CONNECTED' AND DATA_LINK_STATUS = 'CONNECTED' " + + "where archIni.arch_type in ('TIMELY', 'REALTIME') AND archIni.arch_status = 'VALID'" +) + +type rwUtil struct { +} + +var RWUtil = rwUtil{} + +func (RWUtil rwUtil) connect(c *DmConnector, ctx context.Context) (*DmConnection, error) { + c.loginMode = LOGIN_MODE_PRIMARY_ONLY + connection, err := c.connect(ctx) + if err != nil { + return nil, err + } + + connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount) + err = RWUtil.connectStandby(connection) + + return connection, err +} + +func (RWUtil rwUtil) reconnect(connection *DmConnection) error { + if connection.rwInfo == nil { + return nil + } + + RWUtil.removeStandby(connection) + + err := connection.reconnect() + if err != nil { + return err + } + connection.rwInfo.cleanup() + connection.rwInfo.rwCounter = getRwCounterInstance(connection, connection.StandbyCount) + + err = RWUtil.connectStandby(connection) + + return err +} + +func (RWUtil rwUtil) recoverStandby(connection *DmConnection) error { + if connection.closed.IsSet() || RWUtil.isStandbyAlive(connection) { + return nil + } + + ts := time.Now().UnixNano() / 1000000 + + freq := int64(connection.dmConnector.rwStandbyRecoverTime) + if freq <= 0 || ts-connection.rwInfo.tryRecoverTs < freq { + return nil + } + + err := RWUtil.connectStandby(connection) + + if err == nil && !RWUtil.checkStatusValid(connection) { + RWUtil.removeStandby(connection) + } + + connection.rwInfo.tryRecoverTs = ts + + return err +} + +func (RWUtil rwUtil) checkStatusValid(connection *DmConnection) bool { + standbyConn := connection.rwInfo.connStandby + if standbyConn == nil { + return false + } + + var id int32 = -1 + stmt, rs, err := connection.driverQuery("select oguid from v$instance") + defer stmt.close() + defer rs.close() + if err == nil { + dest := make([]driver.Value, 1) + err := rs.next(dest) + if err == nil { + id = dest[0].(int32) + } else { + return false + } + } else { + return false + } + + stmt2, rs2, err2 := standbyConn.driverQuery("select oguid from v$instance") + defer stmt2.close() + defer rs2.close() + if err2 == nil { + dest2 := make([]driver.Value, 1) + err2 := rs.next(dest2) + if err2 == nil { + if dest2[0].(int32) == id { + return true + } + } + } + + return false +} + +func (RWUtil rwUtil) connectStandby(connection *DmConnection) error { + var err error + db, err := RWUtil.chooseValidStandby(connection) + if err != nil { + return err + } + if db == nil { + return nil + } + + standbyConnectorValue := *connection.dmConnector + standbyConnector := &standbyConnectorValue + standbyConnector.host = db.host + standbyConnector.port = db.port + standbyConnector.rwStandby = true + standbyConnector.group = nil + standbyConnector.loginMode = LOGIN_MODE_STANDBY_ONLY + standbyConnector.switchTimes = 0 + connection.rwInfo.connStandby, err = standbyConnector.connectSingle(context.Background()) + if err != nil { + return err + } + + if connection.rwInfo.connStandby.SvrMode != SERVER_MODE_STANDBY || connection.rwInfo.connStandby.SvrStat != SERVER_STATUS_OPEN { + RWUtil.removeStandby(connection) + } + return nil +} + +func (RWUtil rwUtil) chooseValidStandby(connection *DmConnection) (*ep, error) { + var filter, filter2 string + var stmt *DmStatement + var rs *DmRows + var err error + if connection.dmConnector.rwSeparate == RW_SEPARATE_USER_DEFINED { + return RWUtil.chooseStandbyUserDefined(connection), nil + } else if connection.dmConnector.rwSeparate == RW_SEPARATE_DB_APPLY_WAIT { + return newEP(connection.StandbyHost, connection.StandbyPort), nil + } else if connection.dmConnector.rwSeparate == RW_SEPARATE_EP_GROUP { + epStr := "" + if connection.dmConnector.group != nil { + for i := 0; i < len(connection.dmConnector.group.epList); i++ { + if i != 0 { + epStr += "," + } + epStr += "'" + connection.dmConnector.group.epList[i].host + ":" + string(connection.dmConnector.group.epList[i].port) + "'" + } + } + if len(epStr) > 0 { + filter = " and (mailIni.INST_IP || ':'|| mailIni.INST_PORT) in (" + epStr + ")" + filter2 = " and (mailIni.mal_INST_HOST || ':'|| mailIni.mal_INST_PORT) in (" + epStr + ")" + } + } + + if connection.Malini2 { + stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY2 + filter2) + } else { + stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY + filter) + } + + defer func() { + if rs != nil { + rs.close() + } + if stmt != nil { + stmt.close() + } + }() + + if err != nil { + rs.close() + stmt.close() + + if connection.Malini2 { + stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY2 + filter) + } else { + stmt, rs, err = connection.driverQuery(SQL_SELECT_STANDBY + filter2) + } + } + + if err == nil { + count := int32(rs.CurrentRows.getRowCount()) + if count > 0 { + connection.rwInfo.rwCounter = getRwCounterInstance(connection, count) + i := int32(0) + rowIndex := connection.rwInfo.rwCounter.random(count) + dest := make([]driver.Value, 3) + for err := rs.next(dest); err != io.EOF; err = rs.next(dest) { + if i == rowIndex { + ep := newEP(dest[1].(string), dest[2].(int32)) + return ep, nil + } + i++ + } + } + } + if err != nil { + return nil, errors.New("choose valid standby error!" + err.Error()) + } + return nil, nil +} + +func (RWUtil rwUtil) chooseStandbyUserDefined(connection *DmConnection) *ep { + epGroup := connection.dmConnector.group.epList + if epGroup == nil { + return nil + } + aliveEp := make([]*ep, len(epGroup)) + + aliveCount := 0 + for i := 0; i < len(epGroup); i++ { + ep := epGroup[i] + if isAliveStandby(ep, connection) { + aliveEp = append(aliveEp, epGroup[i]) + aliveCount++ + } + } + + if aliveCount > 0 { + if connection.rwInfo.rwCounter.indexCount == INT64_MAX { + connection.rwInfo.rwCounter.indexCount = 0 + } + ret := aliveEp[int(connection.rwInfo.rwCounter.indexCount)%aliveCount] + + connection.rwInfo.rwCounter.indexCount++ + return ret + } + + return nil +} + +func isAliveStandby(ep *ep, connection *DmConnection) bool { + standbyConnectorValue := *connection.dmConnector + standbyConnector := &standbyConnectorValue + standbyConnector.host = ep.host + standbyConnector.port = ep.port + standbyConnector.rwStandby = true + standbyConnector.group = nil + standbyConnector.loginMode = LOGIN_MODE_STANDBY_ONLY + standbyConnector.switchTimes = 0 + standbyConnect, err := standbyConnector.connectSingle(context.Background()) + + if err != nil { + return false + } + + defer standbyConnect.close() + + if standbyConnect.SvrMode != SERVER_MODE_STANDBY || standbyConnect.SvrStat != SERVER_STATUS_OPEN { + return false + } + return true +} + +func (RWUtil rwUtil) afterExceptionOnStandby(connection *DmConnection, e error) { + if e.(*DmError).ErrCode == ECGO_COMMUNITION_ERROR.ErrCode { + RWUtil.removeStandby(connection) + } +} + +func (RWUtil rwUtil) removeStandby(connection *DmConnection) { + if connection.rwInfo.connStandby != nil { + connection.rwInfo.connStandby.close() + connection.rwInfo.connStandby = nil + } +} + +func (RWUtil rwUtil) isCreateStandbyStmt(stmt *DmStatement) bool { + return stmt != nil && stmt.rwInfo.readOnly && RWUtil.isStandbyAlive(stmt.dmConn) +} + +func (RWUtil rwUtil) executeByConn(conn *DmConnection, query string, execute1 func() (interface{}, error), execute2 func(otherConn *DmConnection) (interface{}, error)) (interface{}, error) { + + if err := RWUtil.recoverStandby(conn); err != nil { + return nil, err + } + RWUtil.distributeSqlByConn(conn, query) + + turnToPrimary := false + + ret, err := execute1() + if err != nil { + if conn.rwInfo.connCurrent == conn.rwInfo.connStandby { + + RWUtil.afterExceptionOnStandby(conn, err) + turnToPrimary = true + } else { + + return nil, err + } + } + + curConn := conn.rwInfo.connCurrent + var otherConn *DmConnection + if curConn != conn { + otherConn = conn + } else { + otherConn = conn.rwInfo.connStandby + } + + switch curConn.lastExecInfo.retSqlType { + case Dm_build_794, Dm_build_795, Dm_build_799, Dm_build_806, Dm_build_805, Dm_build_797: + { + + if otherConn != nil { + execute2(otherConn) + } + } + case Dm_build_804: + { + + sqlhead := regexp.MustCompile("[ (]").Split(strings.TrimSpace(query), 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") { + if otherConn != nil { + execute2(otherConn) + } + } + } + case Dm_build_803: + { + + if conn.dmConnector.rwHA && curConn == conn.rwInfo.connStandby && + (curConn.lastExecInfo.rsDatas == nil || len(curConn.lastExecInfo.rsDatas) == 0) { + turnToPrimary = true + } + } + } + + if turnToPrimary { + conn.rwInfo.toPrimary() + conn.rwInfo.connCurrent = conn + + return execute2(conn) + } + return ret, nil +} + +func (RWUtil rwUtil) executeByStmt(stmt *DmStatement, execute1 func() (interface{}, error), execute2 func(otherStmt *DmStatement) (interface{}, error)) (interface{}, error) { + orgStmt := stmt.rwInfo.stmtCurrent + query := stmt.nativeSql + + if err := RWUtil.recoverStandby(stmt.dmConn); err != nil { + return nil, err + } + RWUtil.distributeSqlByStmt(stmt) + if orgStmt != stmt.rwInfo.stmtCurrent { + RWUtil.copyStatement(orgStmt, stmt.rwInfo.stmtCurrent) + stmt.rwInfo.stmtCurrent.nativeSql = orgStmt.nativeSql + } + + turnToPrimary := false + + ret, err := execute1() + if err != nil { + + if stmt.rwInfo.stmtCurrent == stmt.rwInfo.stmtStandby { + RWUtil.afterExceptionOnStandby(stmt.dmConn, err) + turnToPrimary = true + } else { + return nil, err + } + } + + curStmt := stmt.rwInfo.stmtCurrent + var otherStmt *DmStatement + if curStmt != stmt { + otherStmt = stmt + } else { + otherStmt = stmt.rwInfo.stmtStandby + } + + switch curStmt.execInfo.retSqlType { + case Dm_build_794, Dm_build_795, Dm_build_799, Dm_build_806, Dm_build_805, Dm_build_797: + { + + if otherStmt != nil { + RWUtil.copyStatement(curStmt, otherStmt) + execute2(otherStmt) + } + } + case Dm_build_804: + { + + var tmpsql string + if query != "" { + tmpsql = strings.TrimSpace(query) + } else if stmt.nativeSql != "" { + tmpsql = strings.TrimSpace(stmt.nativeSql) + } else { + tmpsql = "" + } + sqlhead := regexp.MustCompile("[ (]").Split(tmpsql, 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_PARA_VALUE") || util.StringUtil.EqualsIgnoreCase(sqlhead, "SP_SET_SESSION_READONLY") { + if otherStmt != nil { + RWUtil.copyStatement(curStmt, otherStmt) + execute2(otherStmt) + } + } + } + case Dm_build_803: + { + + if stmt.dmConn.dmConnector.rwHA && curStmt == stmt.rwInfo.stmtStandby && + (curStmt.execInfo.rsDatas == nil || len(curStmt.execInfo.rsDatas) == 0) { + turnToPrimary = true + } + } + } + + if turnToPrimary { + stmt.dmConn.rwInfo.toPrimary() + stmt.rwInfo.stmtCurrent = stmt + + RWUtil.copyStatement(stmt.rwInfo.stmtStandby, stmt) + + return execute2(stmt) + } + return ret, nil +} + +func (RWUtil rwUtil) checkReadonlyByConn(conn *DmConnection, sql string) bool { + readonly := true + + if sql != "" && !conn.dmConnector.rwIgnoreSql { + tmpsql := strings.TrimSpace(sql) + sqlhead := strings.SplitN(tmpsql, " ", 2)[0] + if util.StringUtil.EqualsIgnoreCase(sqlhead, "INSERT") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "UPDATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "DELETE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "CREATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "TRUNCATE") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "DROP") || + util.StringUtil.EqualsIgnoreCase(sqlhead, "ALTER") { + readonly = false + } else { + readonly = true + } + } + return readonly +} + +func (RWUtil rwUtil) checkReadonlyByStmt(stmt *DmStatement) bool { + return RWUtil.checkReadonlyByConn(stmt.dmConn, stmt.nativeSql) +} + +func (RWUtil rwUtil) distributeSqlByConn(conn *DmConnection, query string) RWSiteEnum { + var dest RWSiteEnum + if !RWUtil.isStandbyAlive(conn) { + + dest = conn.rwInfo.toPrimary() + } else if !RWUtil.checkReadonlyByConn(conn, query) { + + dest = conn.rwInfo.toPrimary() + } else if (conn.rwInfo.distribute == PRIMARY && !conn.trxFinish) || + (conn.rwInfo.distribute == STANDBY && !conn.rwInfo.connStandby.trxFinish) { + + dest = conn.rwInfo.distribute + } else if conn.IsoLevel != int32(sql.LevelSerializable) { + + dest = conn.rwInfo.toAny() + } else { + dest = conn.rwInfo.toPrimary() + } + + if dest == PRIMARY { + conn.rwInfo.connCurrent = conn + } else { + conn.rwInfo.connCurrent = conn.rwInfo.connStandby + } + return dest +} + +func (RWUtil rwUtil) distributeSqlByStmt(stmt *DmStatement) RWSiteEnum { + var dest RWSiteEnum + if !RWUtil.isStandbyAlive(stmt.dmConn) { + + dest = stmt.dmConn.rwInfo.toPrimary() + } else if !RWUtil.checkReadonlyByStmt(stmt) { + + dest = stmt.dmConn.rwInfo.toPrimary() + } else if (stmt.dmConn.rwInfo.distribute == PRIMARY && !stmt.dmConn.trxFinish) || + (stmt.dmConn.rwInfo.distribute == STANDBY && !stmt.dmConn.rwInfo.connStandby.trxFinish) { + + dest = stmt.dmConn.rwInfo.distribute + } else if stmt.dmConn.IsoLevel != int32(sql.LevelSerializable) { + + dest = stmt.dmConn.rwInfo.toAny() + } else { + dest = stmt.dmConn.rwInfo.toPrimary() + } + + if dest == STANDBY && !RWUtil.isStandbyStatementValid(stmt) { + + var err error + stmt.rwInfo.stmtStandby, err = stmt.dmConn.rwInfo.connStandby.prepare(stmt.nativeSql) + if err != nil { + dest = stmt.dmConn.rwInfo.toPrimary() + } + } + + if dest == PRIMARY { + stmt.rwInfo.stmtCurrent = stmt + } else { + stmt.rwInfo.stmtCurrent = stmt.rwInfo.stmtStandby + } + return dest +} + +func (RWUtil rwUtil) isStandbyAlive(connection *DmConnection) bool { + return connection.rwInfo.connStandby != nil && !connection.rwInfo.connStandby.closed.IsSet() +} + +func (RWUtil rwUtil) isStandbyStatementValid(statement *DmStatement) bool { + return statement.rwInfo.stmtStandby != nil && !statement.rwInfo.stmtStandby.closed +} + +func (RWUtil rwUtil) copyStatement(srcStmt *DmStatement, destStmt *DmStatement) { + destStmt.nativeSql = srcStmt.nativeSql + destStmt.serverParams = srcStmt.serverParams + destStmt.bindParams = srcStmt.bindParams + destStmt.paramCount = srcStmt.paramCount +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzj.go b/dpi_bridge/third_party/chunanyong_dm/zzj.go new file mode 100644 index 0000000..6a5d859 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzj.go @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "database/sql" + "database/sql/driver" +) + +var SQLName sqlName + +type sqlName struct { + m_name string // 描述对象自身名称, + + // 若为内置类型,则表示数据库端定义的名称,与dType相对应 + m_pkgName string // 所在包的名称,适用于包中类型的定义 + + m_schName string // 描述对象所在模式名 + + m_fulName string // 描述对象完全限定名, 记录用户发送的名称信息; + + // 以及接受服务器响应后,拼成的名称信息 + + m_schId int // 保存模式id,模式名无法传出,利用模式id查找 + + m_packId int // 保存包的id,包名无法传出,用于查找包名 + + m_conn *DmConnection +} + +func (SqlName *sqlName) init() { + SqlName.m_name = "" + SqlName.m_pkgName = "" + SqlName.m_schName = "" + SqlName.m_fulName = "" + SqlName.m_schId = -1 + SqlName.m_packId = -1 + SqlName.m_conn = nil +} + +func newSqlNameByFulName(fulName string) *sqlName { + o := new(sqlName) + o.init() + o.m_fulName = fulName + return o +} + +func newSqlNameByConn(conn *DmConnection) *sqlName { + o := new(sqlName) + o.init() + o.m_conn = conn + return o +} + +func (SqlName *sqlName) getFulName() (string, error) { + // 说明非内嵌式数据类型名称描述信息传入或已经获取过描述信息 + if len(SqlName.m_fulName) > 0 { + return SqlName.m_fulName, nil + } + + // 内嵌式数据类型无名称描述信息返回,直接返回null + if SqlName.m_name == "" { + // DBError.throwUnsupportedSQLException(); + return "", nil + } + + // 其他数据名描述信息 + if SqlName.m_packId != 0 || SqlName.m_schId != 0 { + query := "SELECT NAME INTO ? FROM SYS.SYSOBJECTS WHERE ID=?" + + params := make([]driver.Value, 2) + var v string + params[0] = sql.Out{Dest: &v} + if SqlName.m_packId != 0 { + params[1] = SqlName.m_packId + } else { + params[1] = SqlName.m_schId + } + + rs, err := SqlName.m_conn.query(query, params) + if err != nil { + return "", err + } + rs.close() + + // 说明是包中定义的对象 + if SqlName.m_packId != 0 { + // pkg全名 + SqlName.m_pkgName = v + SqlName.m_fulName = SqlName.m_pkgName + "." + SqlName.m_name + } else { + // 非包中定义的对象 + // schema 名称 + SqlName.m_schName = v + SqlName.m_fulName = SqlName.m_schName + "." + SqlName.m_name + } + } + // 将有效值返回 + if len(SqlName.m_fulName) > 0 { + return SqlName.m_fulName, nil + } else { + return SqlName.m_name, nil + } + +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzk.go b/dpi_bridge/third_party/chunanyong_dm/zzk.go new file mode 100644 index 0000000..d9e4129 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzk.go @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "bytes" + "strconv" + "strings" + + "gitee.com/chunanyong/dm/parser" + + "gitee.com/chunanyong/dm/util" +) + +func (dc *DmConnection) lex(sql string) ([]*parser.LVal, error) { + if dc.lexer == nil { + dc.lexer = parser.NewLexer(strings.NewReader(sql), false) + } else { + dc.lexer.Reset(strings.NewReader(sql)) + } + + lexer := dc.lexer + var lval *parser.LVal + var err error + lvalList := make([]*parser.LVal, 0, 64) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + for lval != nil { + lvalList = append(lvalList, lval) + lval.Position = len(lvalList) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + } + + return lvalList, nil +} + +func lexSkipWhitespace(sql string, n int) ([]*parser.LVal, error) { + lexer := parser.NewLexer(strings.NewReader(sql), false) + + var lval *parser.LVal + var err error + lvalList := make([]*parser.LVal, 0, 64) + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + for lval != nil && n > 0 { + lval.Position = len(lvalList) + if lval.Tp == parser.WHITESPACE_OR_COMMENT { + continue + } + + lvalList = append(lvalList, lval) + n-- + lval, err = lexer.Yylex() + if err != nil { + return nil, err + } + + } + + return lvalList, nil +} + +func (dc *DmConnection) escape(sql string, keywords []string) (string, error) { + + if (keywords == nil || len(keywords) == 0) && strings.Index(sql, "{") == -1 { + return sql, nil + } + var keywordMap map[string]interface{} + if keywords != nil && len(keywords) > 0 { + keywordMap = make(map[string]interface{}, len(keywords)) + for _, keyword := range keywords { + keywordMap[strings.ToUpper(keyword)] = nil + } + } + nsql := bytes.NewBufferString("") + stack := make([]bool, 0, 64) + lvalList, err := dc.lex(sql) + if err != nil { + return "", err + } + + for i := 0; i < len(lvalList); i++ { + lval0 := lvalList[i] + if lval0.Tp == parser.NORMAL { + if lval0.Value == "{" { + lval1 := next(lvalList, i+1) + if lval1 == nil || lval1.Tp != parser.NORMAL { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "escape") || util.StringUtil.EqualsIgnoreCase(lval1.Value, "call") { + stack = append(stack, true) + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "oj") { + stack = append(stack, true) + lval1.Value = "" + lval1.Tp = parser.WHITESPACE_OR_COMMENT + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "d") { + stack = append(stack, true) + lval1.Value = "date" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "t") { + stack = append(stack, true) + lval1.Value = "time" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "ts") { + stack = append(stack, true) + lval1.Value = "datetime" + } else if util.StringUtil.EqualsIgnoreCase(lval1.Value, "fn") { + stack = append(stack, true) + lval1.Value = "" + lval1.Tp = parser.WHITESPACE_OR_COMMENT + lval2 := next(lvalList, lval1.Position+1) + if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "database") { + lval2.Value = "cur_database" + } + } else if util.StringUtil.Equals(lval1.Value, "?") { + lval2 := next(lvalList, lval1.Position+1) + if lval2 != nil && lval2.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval2.Value, "=") { + lval3 := next(lvalList, lval2.Position+1) + if lval3 != nil && lval3.Tp == parser.NORMAL && util.StringUtil.EqualsIgnoreCase(lval3.Value, "call") { + stack = append(stack, true) + lval3.Value = "" + lval3.Tp = parser.WHITESPACE_OR_COMMENT + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else { + stack = append(stack, false) + nsql.WriteString(lval0.Value) + } + } else if util.StringUtil.Equals(lval0.Value, "}") { + if len(stack) != 0 && stack[len(stack)-1] { + + } else { + nsql.WriteString(lval0.Value) + } + stack = stack[:len(stack)-1] + } else { + if keywordMap != nil { + _, ok := keywordMap[strings.ToUpper(lval0.Value)] + if ok { + nsql.WriteString("\"" + util.StringUtil.ProcessDoubleQuoteOfName(strings.ToUpper(lval0.Value)) + "\"") + } else { + nsql.WriteString(lval0.Value) + } + } else { + nsql.WriteString(lval0.Value) + } + } + } else if lval0.Tp == parser.STRING { + nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval0.Value) + "'") + } else { + nsql.WriteString(lval0.Value) + } + } + + return nsql.String(), nil +} + +func next(lvalList []*parser.LVal, start int) *parser.LVal { + var lval *parser.LVal + + size := len(lvalList) + for i := start; i < size; i++ { + lval = lvalList[i] + if lval.Tp != parser.WHITESPACE_OR_COMMENT { + break + } + } + return lval +} + +func (dc *DmConnection) execOpt(sql string, optParamList []OptParameter, serverEncoding string, backSlashFlag bool) (string, []OptParameter, error) { + nsql := bytes.NewBufferString("") + + lvalList, err := dc.lex(sql) + if err != nil { + return sql, nil, err + } + + if nil == lvalList || len(lvalList) == 0 { + return sql, nil, nil + } + + firstWord := lvalList[0].Value + if !(util.StringUtil.EqualsIgnoreCase(firstWord, "INSERT") || util.StringUtil.EqualsIgnoreCase(firstWord, "SELECT") || + util.StringUtil.EqualsIgnoreCase(firstWord, "UPDATE") || util.StringUtil.EqualsIgnoreCase(firstWord, "DELETE")) { + return sql, nil, nil + } + + breakIndex := 0 + for i := 0; i < len(lvalList); i++ { + lval := lvalList[i] + switch lval.Tp { + case parser.NULL: + { + nsql.WriteString("?") + optParamList = append(optParamList, newOptParameter(nil, NULL, NULL_PREC)) + } + case parser.INT: + { + nsql.WriteString("?") + value, err := strconv.Atoi(lval.Value) + if err != nil { + return sql, nil, err + } + + if value <= int(INT32_MAX) && value >= int(INT32_MIN) { + optParamList = append(optParamList, newOptParameter(G2DB.toInt32(int32(value)), INT, INT_PREC)) + + } else { + optParamList = append(optParamList, newOptParameter(G2DB.toInt64(int64(value)), BIGINT, BIGINT_PREC)) + } + } + case parser.DOUBLE: + { + nsql.WriteString("?") + f, err := strconv.ParseFloat(lval.Value, 64) + if err != nil { + return sql, nil, err + } + + optParamList = append(optParamList, newOptParameter(G2DB.toFloat64(f), DOUBLE, DOUBLE_PREC)) + } + case parser.DECIMAL: + { + nsql.WriteString("?") + bytes, err := G2DB.toDecimal(lval.Value) + if err != nil { + return sql, nil, err + } + optParamList = append(optParamList, newOptParameter(bytes, DECIMAL, 0)) + } + case parser.STRING: + { + + if len(lval.Value) > int(INT16_MAX) { + + nsql.WriteString("'" + util.StringUtil.ProcessSingleQuoteOfName(lval.Value) + "'") + } else { + nsql.WriteString("?") + + if backSlashFlag { + lval.Value = util.StringUtil.Translate(lval.Value) + } + optParamList = append(optParamList, newOptParameter(Dm_build_1346.Dm_build_1562(lval.Value, serverEncoding, dc), VARCHAR, VARCHAR_PREC)) + } + } + case parser.HEX_INT: + + nsql.WriteString(lval.Value) + default: + + nsql.WriteString(lval.Value) + } + + if breakIndex > 0 { + break + } + } + + if breakIndex > 0 { + for i := breakIndex + 1; i < len(lvalList); i++ { + nsql.WriteString(lvalList[i].Value) + } + } + + return nsql.String(), optParamList, nil +} + +func (dc *DmConnection) hasConst(sql string) (bool, error) { + lvalList, err := dc.lex(sql) + if err != nil { + return false, err + } + + if nil == lvalList || len(lvalList) == 0 { + return false, nil + } + + for i := 0; i < len(lvalList); i++ { + switch lvalList[i].Tp { + case parser.NULL, parser.INT, parser.DOUBLE, parser.DECIMAL, parser.STRING, parser.HEX_INT: + return true, nil + } + } + return false, nil +} + +type OptParameter struct { + bytes []byte + ioType byte + tp int + prec int + scale int +} + +func newOptParameter(bytes []byte, tp int, prec int) OptParameter { + o := new(OptParameter) + o.bytes = bytes + o.tp = tp + o.prec = prec + return *o +} + +func (parameter *OptParameter) String() string { + if parameter.bytes == nil { + return "" + } + return string(parameter.bytes) +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzl.go b/dpi_bridge/third_party/chunanyong_dm/zzl.go new file mode 100644 index 0000000..e28795b --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzl.go @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +type StructDescriptor struct { + m_typeDesc *TypeDescriptor +} + +func newStructDescriptor(fulName string, conn *DmConnection) (*StructDescriptor, error) { + sd := new(StructDescriptor) + if fulName == "" { + return nil, ECGO_INVALID_COMPLEX_TYPE_NAME.throw() + } + + sd.m_typeDesc = newTypeDescriptorWithFulName(fulName, conn) + + err := sd.m_typeDesc.parseDescByName() + if err != nil { + return nil, err + } + + return sd, nil +} + +func newStructDescriptorByTypeDescriptor(desc *TypeDescriptor) *StructDescriptor { + sd := new(StructDescriptor) + sd.m_typeDesc = desc + return sd +} + +func (sd *StructDescriptor) getSize() int { + return sd.m_typeDesc.m_size +} + +func (sd *StructDescriptor) getObjId() int { + return sd.m_typeDesc.m_objId +} + +func (sd *StructDescriptor) getItemsDesc() []TypeDescriptor { + return sd.m_typeDesc.m_fieldsObj +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzm.go b/dpi_bridge/third_party/chunanyong_dm/zzm.go new file mode 100644 index 0000000..cf1c5fe --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzm.go @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ + +package dm + +import ( + "bufio" + "io" + "os" + "runtime" + "strconv" + "strings" + "sync" + + "gitee.com/chunanyong/dm/util" +) + +var LogDirDef, _ = os.Getwd() + +var StatDirDef, _ = os.Getwd() + +const ( + DEFAULT_PORT int32 = 5236 + + //log level + LOG_OFF int = 0 + + LOG_ERROR int = 1 + + LOG_WARN int = 2 + + LOG_SQL int = 3 + + LOG_INFO int = 4 + + LOG_DEBUG int = 5 + + LOG_ALL int = 9 + + //stat + STAT_SQL_REMOVE_LATEST int = 0 + + STAT_SQL_REMOVE_OLDEST int = 1 + + // 编码字符集 + ENCODING_UTF8 string = "UTF-8" + + ENCODING_EUCKR string = "EUC-KR" + + ENCODING_GB18030 string = "GB18030" + + ENCODING_BIG5 string = "BIG5" + + DbAliveCheckFreqDef = 0 + + LocaleDef = LANGUAGE_CN + + // log + LogLevelDef = LOG_OFF // 日志级别:off, error, warn, sql, info, all + + LogFlushFreqDef = 10 // 日志刷盘时间s (>=0) + + LogFlushQueueSizeDef = 100 //日志队列大小 + + LogBufferSizeDef = 32 * 1024 // 日志缓冲区大小 (>0) + + // stat + StatEnableDef = false // + + StatFlushFreqDef = 3 // 日志刷盘时间s (>=0) + + StatSlowSqlCountDef = 100 // 慢sql top行数,(0-1000) + + StatHighFreqSqlCountDef = 100 // 高频sql top行数, (0-1000) + + StatSqlMaxCountDef = 100000 // sql 统计最大值(0-100000) + + StatSqlRemoveModeDef = STAT_SQL_REMOVE_LATEST // 记录sql数超过最大值时,sql淘汰方式 + + ClobToBytesDef = false //Clob是否转换为bytes +) + +var ( + DbAliveCheckFreq = DbAliveCheckFreqDef + + Locale = LocaleDef // 0:简体中文 1:英文 2:繁体中文 + + // log + LogLevel = LogLevelDef // 日志级别:off, error, warn, sql, info, all + + LogDir = LogDirDef + + LogFlushFreq = LogFlushFreqDef // 日志刷盘时间s (>=0) + + LogFlushQueueSize = LogFlushQueueSizeDef + + LogBufferSize = LogBufferSizeDef // 日志缓冲区大小 (>0) + + // stat + StatEnable = StatEnableDef // + + StatDir = StatDirDef // jdbc工作目录,所有生成的文件都在该目录下 + + StatFlushFreq = StatFlushFreqDef // 日志刷盘时间s (>=0) + + StatSlowSqlCount = StatSlowSqlCountDef // 慢sql top行数,(0-1000) + + StatHighFreqSqlCount = StatHighFreqSqlCountDef // 高频sql top行数, (0-1000) + + StatSqlMaxCount = StatSqlMaxCountDef // sql 统计最大值(0-100000) + + StatSqlRemoveMode = StatSqlRemoveModeDef // 记录sql数超过最大值时,sql淘汰方式 + + /*---------------------------------------------------------------*/ + ServerGroupMap sync.Map + + GlobalProperties = NewProperties() +) + +// filePath: dm_svc.conf 文件路径 +func load(filePath string) { + if filePath == "" { + // 如果设置了环境变量则环境变量优先 + filePath = os.Getenv("DM_SVC_PATH") + if filePath == "" { + // 否则使用默认 + switch runtime.GOOS { + case "windows": + filePath = os.Getenv("SystemRoot") + "\\system32\\dm_svc.conf" + case "linux": + filePath = "/etc/dm_svc.conf" + default: + return + } + } + } + + // 如果设置了连接串上svcConfPath,则串上优先 + file, err := os.Open(filePath) + defer file.Close() + if err != nil { + return + } + fileReader := bufio.NewReader(file) + + // GlobalProperties = NewProperties() + var groupProps *Properties + var line string //dm_svc.conf读取到的一行 + + for line, err = fileReader.ReadString('\n'); line != "" && (err == nil || err == io.EOF); line, err = fileReader.ReadString('\n') { + // 去除#标记的注释 + if notesIndex := strings.IndexByte(line, '#'); notesIndex != -1 { + line = line[:notesIndex] + } + // 去除前后多余的空格 + line = strings.TrimSpace(line) + if line == "" { + continue + } + + if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { + groupName := strings.ToLower(line[1 : len(line)-1]) + dbGroup, ok := ServerGroupMap.Load(groupName) + if groupName == "" || !ok { + continue + } + groupProps = dbGroup.(*epGroup).props + if groupProps.IsNil() { + groupProps = NewProperties() + groupProps.SetProperties(GlobalProperties) + dbGroup.(*epGroup).props = groupProps + } + + } else { + cfgInfo := [2]string{} + if index := strings.Index(line, "="); index > 0 { + cfgInfo[0] = line[0:index] + cfgInfo[1] = line[index+1:] + } else { + continue + } + key := strings.TrimSpace(cfgInfo[0]) + value := strings.TrimSpace(cfgInfo[1]) + if strings.HasPrefix(value, "(") && strings.HasSuffix(value, ")") { + value = strings.TrimSpace(value[1 : len(value)-1]) + } + if key == "" || value == "" { + continue + } + // 区分属性是全局的还是组的 + var success bool + if groupProps.IsNil() { + success = SetServerGroupProperties(GlobalProperties, key, value) + } else { + success = SetServerGroupProperties(groupProps, key, value) + } + if !success { + var serverGroup = parseServerName(key, value) + if serverGroup != nil { + serverGroup.props = NewProperties() + serverGroup.props.SetProperties(GlobalProperties) + ServerGroupMap.Store(strings.ToLower(key), serverGroup) + } + } + } + } +} + +func SetServerGroupProperties(props *Properties, key string, value string) bool { + key = strings.ToUpper(key) + if key == "ADDRESS_REMAP" { + tmp := props.GetString(AddressRemapKey, "") + props.Set(AddressRemapKey, tmp+"("+value+")") + } else if key == "ALWAYS_ALLOW_COMMIT" { + props.Set(AlwayseAllowCommitKey, value) + } else if key == "APP_NAME" { + props.Set(AppNameKey, value) + } else if key == "AUTO_COMMIT" { + props.Set(AutoCommitKey, value) + } else if key == "BATCH_ALLOW_MAX_ERRORS" { + props.Set(BatchAllowMaxErrorsKey, value) + } else if key == "BATCH_CONTINUE_ON_ERROR" || + key == "CONTINUE_BATCH_ON_ERROR" { + props.Set(ContinueBatchOnErrorKey, value) + } else if key == "BATCH_NOT_ON_CALL" { + props.Set(BatchNotOnCallKey, value) + } else if key == "BATCH_TYPE" { + props.Set(BatchTypeKey, value) + } else if key == "BUF_PREFETCH" { + props.Set(BufPrefetchKey, value) + } else if key == "CIPHER_PATH" { + props.Set(CipherPathKey, value) + } else if key == "CLUSTER" { + props.Set(ClusterKey, value) + } else if key == "COLUMN_NAME_UPPER_CASE" { + props.Set(ColumnNameUpperCaseKey, value) + } else if key == "COLUMN_NAME_CASE" { + props.Set(ColumnNameCaseKey, value) + } else if key == "COMPATIBLE_MODE" { + props.Set(CompatibleModeKey, value) + } else if key == "COMPRESS" || + key == "COMPRESS_MSG" { + props.Set(CompressKey, value) + } else if key == "COMPRESS_ID" { + props.Set(CompressIdKey, value) + } else if key == "CONNECT_TIMEOUT" { + props.Set(ConnectTimeoutKey, value) + } else if key == "DO_SWITCH" || + key == "AUTO_RECONNECT" { + props.Set(DoSwitchKey, value) + } else if key == "ENABLE_RS_CACHE" { + props.Set(EnRsCacheKey, value) + } else if key == "EP_SELECTION" { + props.Set(EpSelectorKey, value) + } else if key == "ESCAPE_PROCESS" { + props.Set(EscapeProcessKey, value) + } else if key == "IS_BDTA_RS" { + props.Set(IsBdtaRSKey, value) + } else if key == "KEY_WORDS" || + key == "KEYWORDS" { + props.Set(KeywordsKey, value) + } else if key == "LANGUAGE" { + props.Set(LanguageKey, value) + } else if key == "LOB_MODE" { + props.Set(LobModeKey, value) + } else if key == "LOG_BUFFER_SIZE" { + props.Set(LogBufferSizeKey, value) + } else if key == "LOG_DIR" { + props.Set(LogDirKey, value) + } else if key == "LOG_FLUSH_FREQ" { + props.Set(LogFlushFreqKey, value) + } else if key == "LOG_FLUSHER_QUEUESIZE" { + props.Set(LogFlusherQueueSizeKey, value) + } else if key == "LOG_LEVEL" { + props.Set(LogLevelKey, value) + } else if key == "LOGIN_DSC_CTRL" { + props.Set(LoginDscCtrlKey, value) + } else if key == "LOGIN_ENCRYPT" { + props.Set(LoginEncryptKey, value) + } else if key == "LOGIN_MODE" { + props.Set(LoginModeKey, value) + } else if key == "LOGIN_STATUS" { + props.Set(LoginStatusKey, value) + } else if key == "MAX_ROWS" { + props.Set(MaxRowsKey, value) + } else if key == "MPP_LOCAL" { + props.Set(MppLocalKey, value) + } else if key == "OS_NAME" { + props.Set(OsNameKey, value) + } else if key == "RS_CACHE_SIZE" { + props.Set(RsCacheSizeKey, value) + } else if key == "RS_REFRESH_FREQ" { + props.Set(RsRefreshFreqKey, value) + } else if key == "RW_HA" { + props.Set(RwHAKey, value) + } else if key == "RW_IGNORE_SQL" { + props.Set(RwIgnoreSqlKey, value) + } else if key == "RW_PERCENT" { + props.Set(RwPercentKey, value) + } else if key == "RW_SEPARATE" { + props.Set(RwSeparateKey, value) + } else if key == "RW_STANDBY_RECOVER_TIME" { + props.Set(RwStandbyRecoverTimeKey, value) + } else if key == "SCHEMA" { + props.Set(SchemaKey, value) + } else if key == "CATALOG" { + props.Set(CatalogKey, value) + } else if key == "SESS_ENCODE" { + if IsSupportedCharset(value) { + props.Set("sessEncode", value) + } + } else if key == "SESSION_TIMEOUT" { + props.Set(SessionTimeoutKey, value) + } else if key == "SOCKET_TIMEOUT" { + props.Set(SocketTimeoutKey, value) + } else if key == "SSL_CERT_PATH" { + props.Set(SslCertPathKey, value) + } else if key == "SSL_FILES_PATH" { + props.Set(SslFilesPathKey, value) + } else if key == "SSL_KEY_PATH" { + props.Set(SslKeyPathKey, value) + } else if key == "STAT_DIR" { + props.Set(StatDirKey, value) + } else if key == "STAT_ENABLE" { + props.Set(StatEnableKey, value) + } else if key == "STAT_FLUSH_FREQ" { + props.Set(StatFlushFreqKey, value) + } else if key == "STAT_HIGH_FREQ_SQL_COUNT" { + props.Set(StatHighFreqSqlCountKey, value) + } else if key == "STAT_SLOW_SQL_COUNT" { + props.Set(StatSlowSqlCountKey, value) + } else if key == "STAT_SQL_MAX_COUNT" { + props.Set(StatSqlMaxCountKey, value) + } else if key == "STAT_SQL_REMOVE_MODE" { + props.Set(StatSqlRemoveModeKey, value) + } else if key == "SWITCH_INTERVAL" { + props.Set(SwitchIntervalKey, value) + } else if key == "SWITCH_TIME" || + key == "SWITCH_TIMES" { + props.Set(SwitchTimesKey, value) + } else if key == "TIME_ZONE" { + props.Set(TimeZoneKey, value) + props.Set("localTimezone", value) + } else if key == "USER_REMAP" { + tmp := props.GetString(UserRemapKey, "") + props.Set(UserRemapKey, tmp+"("+value+")") + } else if key == "SERVER_OPTION" { + props.Set(ServerOptionKey, value) + } else if key == "CLOB_TO_BYTES" { + props.Set(ClobToBytesKey, value) + } else { + return false + } + return true +} + +func parseServerName(name string, value string) *epGroup { + values := strings.Split(value, ",") + + var tmpVals []string + var tmpName string + var tmpPort int + var svrList = make([]*ep, 0, len(values)) + + for _, v := range values { + + var tmp *ep + // 先查找IPV6,以[]包括 + begin := strings.IndexByte(v, '[') + end := -1 + if begin != -1 { + end = strings.IndexByte(v[begin:], ']') + } + if end != -1 { + //tmpName = v[begin+1 : end] + tmpName = v[begin : end+1] + + // port + if portIndex := strings.IndexByte(v[end:], ':'); portIndex != -1 { + tmpPort, _ = strconv.Atoi(strings.TrimSpace(v[end+portIndex+1:])) + } else { + tmpPort = int(DEFAULT_PORT) + } + tmp = newEP(tmpName, int32(tmpPort)) + svrList = append(svrList, tmp) + continue + } + // IPV4 + tmpVals = strings.Split(v, ":") + tmpName = strings.TrimSpace(tmpVals[0]) + if len(tmpVals) >= 2 { + tmpPort, _ = strconv.Atoi(tmpVals[1]) + } else { + tmpPort = int(DEFAULT_PORT) + } + tmp = newEP(tmpName, int32(tmpPort)) + svrList = append(svrList, tmp) + } + + if len(svrList) == 0 { + return nil + } + return newEPGroup(name, svrList) +} + +func setDriverAttributes(props *Properties) { + if props == nil || props.Len() == 0 { + return + } + + parseLanguage(props.GetString(LanguageKey, "cn")) + DbAliveCheckFreq = props.GetInt(DbAliveCheckFreqKey, DbAliveCheckFreqDef, 1, int(INT32_MAX)) + //// log + //LogLevel = ParseLogLevel(props) + //LogDir = util.StringUtil.FormatDir(props.GetTrimString(LogDirKey, LogDirDef)) + //LogBufferSize = props.GetInt(LogBufferSizeKey, LogBufferSizeDef, 1, int(INT32_MAX)) + //LogFlushFreq = props.GetInt(LogFlushFreqKey, LogFlushFreqDef, 1, int(INT32_MAX)) + //LogFlushQueueSize = props.GetInt(LogFlusherQueueSizeKey, LogFlushQueueSizeDef, 1, int(INT32_MAX)) + // + //// stat + //StatEnable = props.GetBool(StatEnableKey, StatEnableDef) + //StatDir = util.StringUtil.FormatDir(props.GetTrimString(StatDirKey, StatDirDef)) + //StatFlushFreq = props.GetInt(StatFlushFreqKey, StatFlushFreqDef, 1, int(INT32_MAX)) + //StatHighFreqSqlCount = props.GetInt(StatHighFreqSqlCountKey, StatHighFreqSqlCountDef, 0, 1000) + //StatSlowSqlCount = props.GetInt(StatSlowSqlCountKey, StatSlowSqlCountDef, 0, 1000) + //StatSqlMaxCount = props.GetInt(StatSqlMaxCountKey, StatSqlMaxCountDef, 0, 100000) + //parseStatSqlRemoveMode(props) +} + +func parseLanguage(value string) { + if util.StringUtil.EqualsIgnoreCase("cn", value) { + Locale = 0 + } else if util.StringUtil.EqualsIgnoreCase("en", value) { + Locale = 1 + } else if util.StringUtil.EqualsIgnoreCase("cnt_hk", value) || + util.StringUtil.EqualsIgnoreCase("hk", value) || + util.StringUtil.EqualsIgnoreCase("tw", value) { + Locale = 2 + } +} + +func IsSupportedCharset(charset string) bool { + if util.StringUtil.EqualsIgnoreCase(ENCODING_UTF8, charset) || + util.StringUtil.EqualsIgnoreCase(ENCODING_GB18030, charset) || + util.StringUtil.EqualsIgnoreCase(ENCODING_EUCKR, charset) || + util.StringUtil.EqualsIgnoreCase(ENCODING_BIG5, charset) { + return true + } + return false +} + +func ParseLogLevel(props *Properties) int { + logLevel := LOG_OFF + value := props.GetString(LogLevelKey, "") + if value != "" && !util.StringUtil.IsDigit(value) { + if util.StringUtil.EqualsIgnoreCase("debug", value) { + logLevel = LOG_DEBUG + } else if util.StringUtil.EqualsIgnoreCase("info", value) { + logLevel = LOG_INFO + } else if util.StringUtil.EqualsIgnoreCase("sql", value) { + logLevel = LOG_SQL + } else if util.StringUtil.EqualsIgnoreCase("warn", value) { + logLevel = LOG_WARN + } else if util.StringUtil.EqualsIgnoreCase("error", value) { + logLevel = LOG_ERROR + } else if util.StringUtil.EqualsIgnoreCase("off", value) { + logLevel = LOG_OFF + } else if util.StringUtil.EqualsIgnoreCase("all", value) { + logLevel = LOG_ALL + } + } else { + logLevel = props.GetInt(LogLevelKey, logLevel, LOG_OFF, LOG_INFO) + } + + return logLevel +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzn.go b/dpi_bridge/third_party/chunanyong_dm/zzn.go new file mode 100644 index 0000000..6ddf7ff --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzn.go @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql" + "database/sql/driver" + "math" + "reflect" + "strings" + "time" +) + +const ( + INT8_MAX int8 = math.MaxInt8 + + INT8_MIN int8 = math.MinInt8 + + BYTE_MAX byte = math.MaxUint8 + + BYTE_MIN byte = 0 + + INT16_MAX int16 = math.MaxInt16 + + INT16_MIN int16 = math.MinInt16 + + UINT16_MAX uint16 = math.MaxUint16 + + UINT16_MIN uint16 = 0 + + INT32_MAX int32 = math.MaxInt32 + + INT32_MIN int32 = math.MinInt32 + + UINT32_MAX uint32 = math.MaxUint32 + + UINT32_MIN uint32 = 0 + + INT64_MAX int64 = math.MaxInt64 + + INT64_MIN int64 = math.MinInt64 + + UINT64_MAX uint64 = math.MaxUint64 + + UINT64_MIN uint64 = 0 + + FLOAT32_MAX float32 = 3.4e+38 + + FLOAT32_MIN float32 = -3.4e+38 + + BYTE_SIZE = 1 + + USINT_SIZE = 2 + + ULINT_SIZE = 4 + + DDWORD_SIZE = 8 + + LINT64_SIZE = 8 + + CHAR = 0 + + VARCHAR2 = 1 + + VARCHAR = 2 + + BIT = 3 + + TINYINT = 5 + + SMALLINT = 6 + + INT = 7 + + BIGINT = 8 + + DECIMAL = 9 + + REAL = 10 + + DOUBLE = 11 + + BLOB = 12 + + BOOLEAN = 13 + + DATE = 14 + + TIME = 15 + + DATETIME = 16 + + BINARY = 17 + + VARBINARY = 18 + + CLOB = 19 + + INTERVAL_YM = 20 + + INTERVAL_DT = 21 + + TIME_TZ = 22 + + DATETIME_TZ = 23 + + XDEC_INT32 = 24 + + XDEC_INT64 = 25 + + DATETIME2 = 26 + + DATETIME2_TZ = 27 + + NULL = 28 + + ANY = 31 + + STAR_ALL = 32 + + STAR = 33 + + RECORD = 40 + + TYPE = 41 + + TYPE_REF = 42 + + UNKNOWN = 54 + + ARRAY = 117 + + CLASS = 119 + + CURSOR = 120 + + PLTYPE_RECORD = 121 + + SARRAY = 122 + + CURSOR_ORACLE = -10 + + BIT_PREC = BYTE_SIZE + + TINYINT_PREC = BYTE_SIZE + + SMALLINT_PREC = USINT_SIZE + + INT_PREC = ULINT_SIZE + + BIGINT_PREC = LINT64_SIZE + + REAL_PREC = 4 + + DOUBLE_PREC = 8 + + DATE_PREC = 3 + + TIME_PREC = 5 + + DATETIME_PREC = 8 + + DATETIME2_PREC = 9 + + TIME_TZ_PREC = TIME_PREC + 2 + + DATETIME_TZ_PREC = DATETIME_PREC + 2 + + DATETIME2_TZ_PREC = DATETIME2_PREC + 2 + + INTERVAL_YM_PREC = 3 * ULINT_SIZE + + INTERVAL_DT_PREC = 6 * ULINT_SIZE + + VARCHAR_PREC = 8188 + + VARBINARY_PREC = 8188 + + BLOB_PREC int32 = INT32_MAX + + CLOB_PREC int32 = INT32_MAX + + NULL_PREC = 0 + + LOCAL_TIME_ZONE_SCALE_MASK = 0x00001000 + + BFILE_PREC = 512 + + BFILE_SCALE = 6 + + COMPLEX_SCALE = 5 + + CURRENCY_PREC = 19 + + CURRENCY_SCALE = 4 + + LOCAL_DATETIME_SCALE_MASK int32 = 0x00001000 + + ORACLE_FLOAT_SCALE_MASK int32 = 0x81 + + ORACLE_DATE_SCALE_MASK int32 = 0x00002000 +) + +func isComplexType(colType int, scale int) bool { + return (colType == BLOB && scale == COMPLEX_SCALE) || colType == ARRAY || colType == SARRAY || colType == CLASS || colType == PLTYPE_RECORD +} + +func isLocalTimeZone(colType int, scale int) bool { + return (colType == DATETIME || colType == DATETIME2) && (scale&LOCAL_TIME_ZONE_SCALE_MASK) != 0 +} + +func getLocalTimeZoneScale(colType int, scale int) int { + return scale & (^LOCAL_TIME_ZONE_SCALE_MASK) +} + +func isFloat(colType int, scale int) bool { + return colType == DECIMAL && scale == int(ORACLE_FLOAT_SCALE_MASK) +} + +func getFloatPrec(prec int) int { + return int(math.Round(float64(prec)*0.30103)) + 1 +} + +func getFloatScale(scale int) int { + return scale & (^int(ORACLE_FLOAT_SCALE_MASK)) +} + +var ( + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeBool = reflect.TypeOf(false) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullBool = reflect.TypeOf(sql.NullBool{}) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullString = reflect.TypeOf(sql.NullString{}) + scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeString = reflect.TypeOf("") + scanTypeTime = reflect.TypeOf(time.Now()) + scanTypeUnknown = reflect.TypeOf(new(interface{})) +) + +func (column *column) ScanType() reflect.Type { + + switch column.colType { + case BOOLEAN: + if column.nullable { + return scanTypeNullBool + } + + return scanTypeBool + + case BIT: + if strings.ToLower(column.typeName) == "boolean" { + + if column.nullable { + return scanTypeNullBool + } + + return scanTypeBool + } else { + + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt8 + } + + case TINYINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt8 + + case SMALLINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt16 + + case INT: + if column.nullable { + return scanTypeNullInt + } + + return scanTypeInt32 + + case BIGINT: + if column.nullable { + return scanTypeNullInt + } + return scanTypeInt64 + + case REAL: + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat32 + + case DOUBLE: + + if strings.ToLower(column.typeName) == "float" { + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat32 + } + + if column.nullable { + return scanTypeNullFloat + } + + return scanTypeFloat64 + case DATE, TIME, TIME_TZ, DATETIME, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + if column.nullable { + return scanTypeNullTime + } + + return scanTypeTime + + case DECIMAL, BINARY, VARBINARY, BLOB: + return scanTypeRawBytes + + case CHAR, VARCHAR2, VARCHAR, CLOB: + if column.nullable { + return scanTypeNullString + } + return scanTypeString + } + + return scanTypeUnknown +} + +func (column *column) Length() (length int64, ok bool) { + switch column.colType { + case BINARY, VARBINARY, BLOB, CHAR, VARCHAR2, VARCHAR, CLOB: + return int64(column.prec), true + } + + return int64(0), false +} + +func (column *column) PrecisionScale() (precision, scale int64, ok bool) { + switch column.colType { + case DECIMAL: + if column.prec == 0 { + return 38, int64(column.scale), true + } else { + return int64(column.prec), int64(column.scale), true + } + } + + return int64(0), int64(0), false +} + +func (column *column) getColumnData(bytes []byte, conn *DmConnection) (driver.Value, error) { + if bytes == nil { + return nil, nil + } + + switch column.colType { + case BOOLEAN: + return bytes[0] != 0, nil + case BIT: + if strings.ToLower(column.typeName) == "boolean" { + return bytes[0] != 0, nil + } + + return int8(bytes[0]), nil + case TINYINT: + return int8(bytes[0]), nil + case SMALLINT: + return Dm_build_1346.Dm_build_1443(bytes, 0), nil + case INT: + return Dm_build_1346.Dm_build_1448(bytes, 0), nil + case BIGINT: + return Dm_build_1346.Dm_build_1453(bytes, 0), nil + case REAL: + return Dm_build_1346.Dm_build_1458(bytes, 0), nil + case DOUBLE: + + return Dm_build_1346.Dm_build_1462(bytes, 0), nil + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + return DB2G.toTime(bytes, column, conn) + case INTERVAL_DT: + return newDmIntervalDTByBytes(bytes).String(), nil + case INTERVAL_YM: + return newDmIntervalYMByBytes(bytes).String(), nil + case DECIMAL: + tmp, err := DB2G.toDmDecimal(bytes, column, conn) + if err != nil { + return nil, err + } + return tmp.String(), nil + + case BINARY, VARBINARY: + return bytes, nil + case BLOB: + if isComplexType(int(column.colType), int(column.scale)) { + return DB2G.toComplexType(bytes, column, conn) + } + blob := DB2G.toDmBlob(bytes, column, conn) + + l, err := blob.GetLength() + if err != nil { + return nil, err + } + return blob.getBytes(1, int32(l)) + + case CHAR, VARCHAR2, VARCHAR: + return Dm_build_1346.Dm_build_1503(bytes, 0, len(bytes), conn.getServerEncoding(), conn), nil + case CLOB: + clob := DB2G.toDmClob(bytes, conn, column) + + l, err := clob.GetLength() + if err != nil { + return nil, err + } + str, err := clob.getSubString(1, int32(l)) + if err != nil { + return str, err + } + if conn.dmConnector.clobToBytes { + return []byte(str), err + } else { + return str, err + } + + } + + return string(bytes), nil +} + +func emptyStringToNil(t int32) bool { + switch t { + case BOOLEAN, BIT, TINYINT, SMALLINT, INT, BIGINT, REAL, DOUBLE, DECIMAL, DATE, TIME, + DATETIME, INTERVAL_DT, INTERVAL_YM, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + return true + default: + return false + } +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzo.go b/dpi_bridge/third_party/chunanyong_dm/zzo.go new file mode 100644 index 0000000..59272f4 --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzo.go @@ -0,0 +1,1389 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "strconv" + + "gitee.com/chunanyong/dm/util" +) + +const ( + ARRAY_TYPE_SHORT = 1 + + ARRAY_TYPE_INTEGER = 2 + + ARRAY_TYPE_LONG = 3 + + ARRAY_TYPE_FLOAT = 4 + + ARRAY_TYPE_DOUBLE = 5 +) + +var TypeDataSV TypeData + +type InterfaceTypeData interface { + toBytes(x *TypeData, typeDesc *TypeDescriptor) ([]byte, error) +} + +type TypeData struct { + m_dumyData interface{} + + m_offset int + + m_bufLen int + + m_dataBuf []byte + + m_objBlobDescBuf []byte + + m_isFromBlob bool + + m_packid int + + m_objRefArr []interface{} +} + +func newTypeData(val interface{}, dataBuf []byte) *TypeData { + td := new(TypeData).initTypeData() + td.m_dumyData = val + td.m_offset = 0 + td.m_bufLen = 0 + td.m_dataBuf = dataBuf + return td +} + +func (td *TypeData) initTypeData() *TypeData { + td.m_dumyData = nil + + td.m_offset = 0 + + td.m_bufLen = 0 + + td.m_dataBuf = nil + + td.m_objBlobDescBuf = nil + + td.m_isFromBlob = false + + td.m_packid = -1 + + td.m_objRefArr = make([]interface{}, 0) + + return td +} + +func (sv TypeData) toStruct(objArr []interface{}, desc *TypeDescriptor) ([]TypeData, error) { + size := desc.getStrctMemSize() + retData := make([]TypeData, size) + + for i := 0; i < size; i++ { + + if objArr[i] == nil { + retData[i] = *newTypeData(objArr[i], nil) + continue + } + + switch objArr[i].(type) { + case DmStruct, DmArray: + retData[i] = *newTypeData(objArr[i], nil) + default: + switch desc.m_fieldsObj[i].getDType() { + case CLASS, PLTYPE_RECORD: + tdArr, err := sv.toStruct(objArr[i].([]interface{}), &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmStructByTypeData(tdArr, &desc.m_fieldsObj[i]), nil) + case ARRAY, SARRAY: + tdArr, err := sv.toArray(objArr[i].([]interface{}), &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmArrayByTypeData(tdArr, &desc.m_fieldsObj[i]), nil) + default: + tdArr, err := sv.toMemberObj(objArr[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + retData[i] = *tdArr + } + + } + } + return retData, nil +} + +func (sv TypeData) toArray(objArr []interface{}, desc *TypeDescriptor) ([]TypeData, error) { + size := len(objArr) + retData := make([]TypeData, size) + for i := 0; i < size; i++ { + if objArr[i] == nil { + retData[i] = *newTypeData(objArr[i], nil) + continue + } + + switch objArr[i].(type) { + case DmStruct, DmArray: + retData[i] = *newTypeData(objArr[i], nil) + default: + switch desc.m_arrObj.getDType() { + case CLASS, PLTYPE_RECORD: + tdArr, err := sv.toStruct(objArr[i].([]interface{}), desc.m_arrObj) + if err != nil { + return nil, err + } + retData[i] = *newTypeData(newDmStructByTypeData(tdArr, desc.m_arrObj), nil) + case ARRAY, SARRAY: + + tmp, ok := objArr[i].([]interface{}) + + if !ok && desc.m_arrObj.m_arrObj != nil { + obj, err := sv.makeupObjToArr(tmp[i], desc.m_arrObj) + if err != nil { + return nil, err + } + objArr[i] = obj + } + + tdArr, err := sv.toArray(objArr[i].([]interface{}), desc.m_arrObj) + if err != nil { + return nil, err + } + + retData[i] = *newTypeData(newDmArrayByTypeData(tdArr, desc.m_arrObj), nil) + default: + tdArr, err := sv.toMemberObj(objArr[i], desc.m_arrObj) + if err != nil { + return nil, err + } + retData[i] = *tdArr + } + } + } + + return retData, nil +} + +func (sv TypeData) makeupObjToArr(obj interface{}, objDesc *TypeDescriptor) ([]interface{}, error) { + arrType := objDesc.getDType() + dynamic := true + arrLen := 0 + if arrType == SARRAY { + dynamic = false + arrLen = objDesc.m_length + } + + subType := objDesc.m_arrObj.getDType() + if subType == BINARY || subType == VARBINARY || subType == BIT { + + strRet := "" + switch v := obj.(type) { + case int: + strRet = strconv.FormatInt(int64(v), 2) + case int32: + strRet = strconv.FormatInt(int64(v), 2) + case int64: + strRet = strconv.FormatInt(v, 2) + case string: + strRet = v + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + var prec int + if dynamic { + prec = len(strRet) + } else { + prec = arrLen + } + + ret := make([]interface{}, prec) + rs := Dm_build_1346.Dm_build_1562(strRet, objDesc.getServerEncoding(), objDesc.m_conn) + for i := 0; i < prec; i++ { + ret[i] = rs[i] + } + + return ret, nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (sv TypeData) toMemberObj(mem interface{}, desc *TypeDescriptor) (*TypeData, error) { + var bs []byte + scale := desc.getScale() + prec := desc.getPrec() + dtype := desc.getDType() + if mem == nil { + return newTypeData(nil, nil), nil + } + + param := new(parameter).InitParameter() + param.colType = int32(dtype) + param.prec = int32(prec) + param.scale = int32(scale) + + var err error + bs, err = G2DB.fromObject(mem, *param, desc.m_conn) + if err != nil { + return nil, err + } + + return newTypeData(mem, bs), nil +} + +func (sv TypeData) typeDataToBytes(data *TypeData, desc *TypeDescriptor) ([]byte, error) { + dType := desc.getDType() + var innerData []byte + var err error + if nil == data.m_dumyData { + innerData = sv.realocBuffer(nil, 0, 2) + Dm_build_1346.Dm_build_1347(innerData, 0, byte(0)) + Dm_build_1346.Dm_build_1347(innerData, 1, byte(0)) + return innerData, nil + } + + var result []byte + var offset int + switch dType { + case ARRAY: + + innerData, err = sv.arrayToBytes(data.m_dumyData.(*DmArray), desc) + if err != nil { + return nil, err + } + + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case SARRAY: + + innerData, err = sv.sarrayToBytes(data.m_dumyData.(*DmArray), desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case CLASS: + + innerData, err = sv.objToBytes(data.m_dumyData, desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case PLTYPE_RECORD: + + innerData, err = sv.recordToBytes(data.m_dumyData.(*DmStruct), desc) + if err != nil { + return nil, err + } + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case BLOB, CLOB: + innerData, err = sv.convertLobToBytes(data.m_dumyData, int(desc.column.colType), desc.getServerEncoding()) + + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + return result, nil + + case BOOLEAN: + innerData = sv.realocBuffer(nil, 0, 2) + Dm_build_1346.Dm_build_1347(innerData, 0, byte(0)) + if data.m_dataBuf != nil && len(data.m_dataBuf) > 0 { + Dm_build_1346.Dm_build_1347(innerData, 1, data.m_dataBuf[0]) + } else { + Dm_build_1346.Dm_build_1347(innerData, 1, byte(0)) + } + return innerData, nil + + default: + + innerData = data.m_dataBuf + result = sv.realocBuffer(nil, 0, len(innerData)+BYTE_SIZE+BYTE_SIZE+USINT_SIZE) + + Dm_build_1346.Dm_build_1347(result, 0, byte(0)) + offset = 1 + + Dm_build_1346.Dm_build_1347(result, offset, byte(1)) + offset += 1 + + Dm_build_1346.Dm_build_1357(result, offset, int16(len(innerData))) + offset += 2 + + copy(result[offset:offset+len(innerData)], innerData[:len(innerData)]) + + return result, nil + } +} + +func (sv TypeData) convertLobToBytes(value interface{}, dtype int, serverEncoding string) ([]byte, error) { + var tmp []byte + var ret []byte + if dtype == BLOB { + lob, ok := value.(DmBlob) + if ok { + l, err := lob.GetLength() + if err != nil { + return nil, err + } + tmp, err = lob.getBytes(1, int32(l)) + if err != nil { + return nil, err + } + + ret = make([]byte, l+ULINT_SIZE) + Dm_build_1346.Dm_build_1362(ret, 0, int32(l)) + copy(ret[:ULINT_SIZE:ULINT_SIZE+l], tmp[:l]) + return ret, nil + } + + } + + if dtype == CLOB { + lob, ok := value.(DmClob) + if ok { + l, err := lob.GetLength() + if err != nil { + return nil, err + } + + subString, err := lob.getSubString(1, int32(l)) + if err != nil { + return nil, err + } + + tmp = Dm_build_1346.Dm_build_1562(subString, serverEncoding, nil) + ret = make([]byte, len(tmp)+ULINT_SIZE) + Dm_build_1346.Dm_build_1362(ret, 0, int32(l)) + copy(ret[:ULINT_SIZE:ULINT_SIZE+l], tmp[:l]) + } + return ret, nil + } + + return nil, ECGO_DATA_CONVERTION_ERROR.throw() +} + +func (sv TypeData) sarrayToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + realLen := len(data.m_arrData) + results := make([][]byte, realLen) + var rdata []byte + var err error + + if desc.getObjId() == 4 { + return sv.ctlnToBytes(data, desc) + } + + totalLen := 0 + for i := 0; i < realLen; i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (ULINT_SIZE + ULINT_SIZE) + rdata = sv.realocBuffer(nil, 0, totalLen) + off := 0 + + Dm_build_1346.Dm_build_1362(rdata, off, int32(totalLen)) + off += ULINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, off, int32(data.m_arrDesc.getLength())) + off += ULINT_SIZE + + for i := 0; i < realLen; i++ { + copy(rdata[off:off+len(results[i])], results[i][:len(results[i])]) + off += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) ctlnToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + results := make([][]byte, len(data.m_arrData)) + var rdata []byte + var err error + + var totalLen int + totalLen = BYTE_SIZE + ULINT_SIZE + + totalLen += USINT_SIZE + USINT_SIZE + ULINT_SIZE + + for i := 0; i < len(data.m_arrData); i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + rdata = sv.realocBuffer(nil, 0, totalLen) + + offset := 0 + + Dm_build_1346.Dm_build_1347(rdata, offset, byte(0)) + offset += BYTE_SIZE + + offset += ULINT_SIZE + + Dm_build_1346.Dm_build_1357(rdata, offset, int16(desc.getCltnType())) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1357(rdata, offset, int16(desc.m_arrObj.getDType())) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, int32(len(data.m_arrData))) + offset += ULINT_SIZE + + for i := 0; i < len(data.m_arrData); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + Dm_build_1346.Dm_build_1362(rdata, BYTE_SIZE, int32(offset)) + + return rdata, nil +} + +func (sv TypeData) arrayToBytes(data *DmArray, desc *TypeDescriptor) ([]byte, error) { + results := make([][]byte, len(data.m_arrData)) + var rdata []byte + var err error + if desc.getObjId() == 4 { + return sv.ctlnToBytes(data, desc) + } + + totalLen := 0 + for i := 0; i < len(data.m_arrData); i++ { + results[i], err = sv.typeDataToBytes(&data.m_arrData[i], desc.m_arrObj) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (ULINT_SIZE + ULINT_SIZE + ULINT_SIZE + ULINT_SIZE + ULINT_SIZE) + + total := data.m_objCount + data.m_strCount + if total > 0 { + totalLen += USINT_SIZE * total + } + + rdata = sv.realocBuffer(nil, 0, totalLen) + + Dm_build_1346.Dm_build_1362(rdata, 0, int32(totalLen)) + offset := ULINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, int32(len(data.m_arrData))) + offset += ULINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, 0) + offset += ULINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, int32(data.m_objCount)) + offset += ULINT_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, int32(data.m_strCount)) + offset += ULINT_SIZE + + for i := 0; i < total; i++ { + Dm_build_1346.Dm_build_1362(rdata, offset, int32(data.m_objStrOffs[i])) + offset += ULINT_SIZE + } + + for i := 0; i < len(data.m_arrData); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) objToBytes(data interface{}, desc *TypeDescriptor) ([]byte, error) { + + switch data.(type) { + case *DmArray: + return sv.arrayToBytes(data.(*DmArray), desc) + default: + return sv.structToBytes(data.(*DmStruct), desc) + } +} + +func (sv TypeData) structToBytes(data *DmStruct, desc *TypeDescriptor) ([]byte, error) { + size := desc.getStrctMemSize() + results := make([][]byte, size) + var rdata []byte + var err error + + totalLen := 0 + for i := 0; i < size; i++ { + results[i], err = sv.typeDataToBytes(&data.m_attribs[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += (BYTE_SIZE + ULINT_SIZE) + + rdata = sv.realocBuffer(nil, 0, totalLen) + offset := 0 + + Dm_build_1346.Dm_build_1347(rdata, offset, byte(0)) + offset += BYTE_SIZE + + Dm_build_1346.Dm_build_1362(rdata, offset, int32(totalLen)) + offset += ULINT_SIZE + + for i := 0; i < size; i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) recordToBytes(data *DmStruct, desc *TypeDescriptor) ([]byte, error) { + size := desc.getStrctMemSize() + results := make([][]byte, size) + var rdata []byte + var err error + + totalLen := 0 + for i := 0; i < size; i++ { + results[i], err = sv.typeDataToBytes(&data.m_attribs[i], &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + totalLen += len(results[i]) + } + + totalLen += ULINT_SIZE + rdata = sv.realocBuffer(nil, 0, totalLen) + Dm_build_1346.Dm_build_1362(rdata, 0, int32(totalLen)) + + offset := ULINT_SIZE + for i := 0; i < desc.getStrctMemSize(); i++ { + copy(rdata[offset:offset+len(results[i])], results[i][:len(results[i])]) + offset += len(results[i]) + } + + return rdata, nil +} + +func (sv TypeData) bytesToBlob(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + l := Dm_build_1346.Dm_build_1448(val, offset) + offset += ULINT_SIZE + + tmp := Dm_build_1346.Dm_build_1497(val, offset, int(l)) + offset += int(l) + out.m_offset = offset + + return newTypeData(newBlobOfLocal(tmp, desc.m_conn), tmp), nil +} + +func (sv TypeData) bytesToClob(val []byte, out *TypeData, desc *TypeDescriptor, serverEncoding string) (*TypeData, error) { + offset := out.m_offset + l := Dm_build_1346.Dm_build_1448(val, offset) + offset += ULINT_SIZE + + tmp := Dm_build_1346.Dm_build_1497(val, offset, int(l)) + offset += int(l) + out.m_offset = offset + + return newTypeData(newClobOfLocal(Dm_build_1346.Dm_build_1503(tmp, 0, len(tmp), serverEncoding, desc.m_conn), desc.m_conn), tmp), nil +} + +func (sv TypeData) bytesToTypeData(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + + offset += 1 + + null_flag := Dm_build_1346.Dm_build_1439(val, offset) + offset += 1 + + out.m_offset = offset + + if desc.getDType() == BOOLEAN { + b := false + if null_flag != byte(0) { + b = true + } + + tmp := Dm_build_1346.Dm_build_1497(val, offset-1, 1) + return newTypeData(b, tmp), nil + } + + var retObj interface{} + var err error + var retDataBuf []byte + switch desc.getDType() { + case CLASS: + if null_flag&byte(1) != byte(0) { + retObj, err = sv.bytesToObj(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case ARRAY: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToArray(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case PLTYPE_RECORD: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToRecord(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case SARRAY: + if (null_flag & byte(1)) != byte(0) { + retObj, err = sv.bytesToSArray(val, out, desc) + if err != nil { + return nil, err + } + + if out.m_offset > offset { + retDataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + } + + return newTypeData(retObj, retDataBuf), nil + } else { + return newTypeData(nil, nil), nil + } + + case BLOB: + if null_flag&byte(1) != byte(0) { + return sv.bytesToBlob(val, out, desc) + } else { + return newTypeData(nil, nil), nil + } + + case CLOB: + if null_flag&byte(1) != byte(0) { + return sv.bytesToClob(val, out, desc, desc.getServerEncoding()) + } else { + return newTypeData(nil, nil), nil + } + + default: + if null_flag&byte(1) != byte(0) { + return sv.convertBytes2BaseData(val, out, desc) + } else { + return newTypeData(nil, nil), nil + } + + } +} + +func (sv TypeData) checkObjExist(val []byte, out *TypeData) bool { + offset := out.m_offset + exist_flag := Dm_build_1346.Dm_build_1439(val, offset) + offset += 1 + + out.m_offset = offset + + if exist_flag == byte(1) { + return true + } + + out.m_offset += ULINT_SIZE + return false +} + +func (sv TypeData) findObjByPackId(val []byte, out *TypeData) (*DmStruct, error) { + offset := out.m_offset + + pack_id := int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + if pack_id < 0 || pack_id > out.m_packid { + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return out.m_objRefArr[pack_id].(*DmStruct), nil +} + +func (sv TypeData) addObjToRefArr(out *TypeData, objToAdd interface{}) { + out.m_objRefArr = append(out.m_objRefArr, objToAdd) + out.m_packid++ +} + +func (sv TypeData) checkObjClnt(desc *TypeDescriptor) bool { + return desc.m_objId == 4 +} + +func (sv TypeData) bytesToObj_EXACT(val []byte, out *TypeData, desc *TypeDescriptor) (*DmStruct, error) { + strOut := newDmStructByTypeData(nil, desc) + var sub_desc *TypeDescriptor + offset := out.m_offset + + size := desc.getStrctMemSize() + + out.m_offset = offset + + strOut.m_attribs = make([]TypeData, size) + for i := 0; i < size; i++ { + sub_desc = &desc.m_fieldsObj[i] + tmp, err := sv.bytesToTypeData(val, out, sub_desc) + if err != nil { + return nil, err + } + strOut.m_attribs[i] = *tmp + } + + strOut.m_dataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + + return strOut, nil +} + +func (sv TypeData) bytesToNestTab(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + offset := out.m_offset + + offset += USINT_SIZE + + count := Dm_build_1346.Dm_build_1448(val, offset) + offset += ULINT_SIZE + + out.m_offset = offset + + arrOut := newDmArrayByTypeData(nil, desc) + arrOut.m_itemCount = int(count) + arrOut.m_arrData = make([]TypeData, count) + for i := 0; i < int(count); i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToClnt(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + var array *DmArray + + offset := out.m_offset + + cltn_type := Dm_build_1346.Dm_build_1443(val, offset) + offset += USINT_SIZE + + out.m_offset = offset + switch cltn_type { + case CLTN_TYPE_IND_TABLE: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + return sv.bytesToNestTab(val, out, desc) + } + + return array, nil +} + +func (sv TypeData) bytesToObj(val []byte, out *TypeData, desc *TypeDescriptor) (interface{}, error) { + var retObj interface{} + var err error + if out == nil { + out = newTypeData(nil, nil) + } + + if sv.checkObjExist(val, out) { + retObj, err = sv.findObjByPackId(val, out) + if err != nil { + return nil, err + } + } else { + sv.addObjToRefArr(out, retObj) + } + + if sv.checkObjClnt(desc) { + retObj, err = sv.bytesToClnt(val, out, desc) + if err != nil { + return nil, err + } + } else { + retObj, err = sv.bytesToObj_EXACT(val, out, desc) + if err != nil { + return nil, err + } + } + + return retObj, nil +} + +func (sv TypeData) bytesToArray(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + arrOut := newDmArrayByTypeData(nil, desc) + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + arrOut.m_bufLen = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += 4 + + arrOut.m_itemCount = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + arrOut.m_itemSize = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + arrOut.m_objCount = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + arrOut.m_strCount = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + total := arrOut.m_objCount + arrOut.m_strCount + arrOut.m_objStrOffs = make([]int, total) + for i := 0; i < total; i++ { + arrOut.m_objStrOffs[i] = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += 4 + } + + out.m_offset = offset + + arrOut.m_arrData = make([]TypeData, arrOut.m_itemCount) + for i := 0; i < arrOut.m_itemCount; i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToSArray(val []byte, out *TypeData, desc *TypeDescriptor) (*DmArray, error) { + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + arrOut := newDmArrayByTypeData(nil, desc) + arrOut.m_bufLen = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + arrOut.m_itemCount = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + arrOut.m_arrData = make([]TypeData, arrOut.m_itemCount) + for i := 0; i < arrOut.m_itemCount; i++ { + tmp, err := sv.bytesToTypeData(val, out, desc.m_arrObj) + if err != nil { + return nil, err + } + arrOut.m_arrData[i] = *tmp + } + + arrOut.m_dataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + + return arrOut, nil +} + +func (sv TypeData) bytesToRecord(val []byte, out *TypeData, desc *TypeDescriptor) (*DmStruct, error) { + if out == nil { + out = newTypeData(nil, nil) + } + + offset := out.m_offset + + strOut := newDmStructByTypeData(nil, desc) + strOut.m_bufLen = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + + out.m_offset = offset + + strOut.m_attribs = make([]TypeData, desc.getStrctMemSize()) + for i := 0; i < desc.getStrctMemSize(); i++ { + tmp, err := sv.bytesToTypeData(val, out, &desc.m_fieldsObj[i]) + if err != nil { + return nil, err + } + strOut.m_attribs[i] = *tmp + } + + strOut.m_dataBuf = Dm_build_1346.Dm_build_1497(val, offset, out.m_offset-offset) + + return strOut, nil +} + +func (sv TypeData) objBlob_GetChkBuf(buf []byte, typeData *TypeData) { + + offset := 4 + + l := int(Dm_build_1346.Dm_build_1448(buf, offset)) + offset += ULINT_SIZE + + typeData.m_objBlobDescBuf = Dm_build_1346.Dm_build_1497(buf, offset, l) + offset += l + + typeData.m_isFromBlob = true + + typeData.m_offset = offset +} + +func (sv TypeData) objBlobToObj(lob *DmBlob, desc *TypeDescriptor) (interface{}, error) { + typeData := newTypeData(nil, nil) + loblen, err := lob.GetLength() + if err != nil { + return nil, err + } + + buf, err := lob.getBytes(1, int32(loblen)) + if err != nil { + return nil, err + } + + sv.objBlob_GetChkBuf(buf, typeData) + + return sv.bytesToObj(buf, typeData, desc) +} + +func (sv TypeData) objBlobToBytes(lobBuf []byte, desc *TypeDescriptor) ([]byte, error) { + l := len(lobBuf) + offset := 0 + + magic := Dm_build_1346.Dm_build_1448(lobBuf, offset) + offset += ULINT_SIZE + + if OBJ_BLOB_MAGIC != magic { + return nil, ECGO_INVALID_OBJ_BLOB.throw() + } + + descLen := int(Dm_build_1346.Dm_build_1448(lobBuf, offset)) + offset += ULINT_SIZE + descBuf := Dm_build_1346.Dm_build_1497(lobBuf, offset, descLen) + tmp, err := desc.getClassDescChkInfo() + if err != nil { + return nil, err + } + if !util.SliceEquals(descBuf, tmp) { + return nil, ECGO_INVALID_OBJ_BLOB.throw() + } + offset += descLen + + ret := make([]byte, l-offset) + copy(ret[:len(ret)], lobBuf[offset:offset+len(ret)]) + return ret, nil +} + +func (sv TypeData) realocBuffer(oldBuf []byte, offset int, needLen int) []byte { + var retBuf []byte + + if oldBuf == nil { + return make([]byte, needLen) + } else if needLen+offset > len(oldBuf) { + retBuf = make([]byte, len(oldBuf)+needLen) + copy(retBuf[:offset], oldBuf[:offset]) + } else { + retBuf = oldBuf + } + + return retBuf +} + +func (sv TypeData) convertBytes2BaseData(val []byte, out *TypeData, desc *TypeDescriptor) (*TypeData, error) { + offset := out.m_offset + isNull := false + valueLen := int(Dm_build_1346.Dm_build_1470(val, offset)) + offset += USINT_SIZE + + if valueLen == int(Dm_build_753) { + valueLen = 0 + isNull = true + } + + if -1 == valueLen { + valueLen = int(Dm_build_1346.Dm_build_1448(val, offset)) + offset += ULINT_SIZE + } + + if isNull { + out.m_offset = offset + return newTypeData(nil, nil), nil + } + + var tmpObj interface{} + var err error + temp := Dm_build_1346.Dm_build_1497(val, offset, valueLen) + offset += valueLen + out.m_offset = offset + + tmpObj, err = DB2G.toObject(temp, desc.column, desc.m_conn) + if err != nil { + return nil, err + } + return newTypeData(tmpObj, temp), nil +} + +func (td *TypeData) toJavaArray(arr *DmArray, index int64, l int, dType int) (interface{}, error) { + if arr.m_objArray != nil { + return arr.m_objArray, nil + } + + var nr = make([]interface{}, l) + var tempData *TypeData + switch dType { + case CHAR, VARCHAR, VARCHAR2: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + case BIT, TINYINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case BINARY, VARBINARY: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case BOOLEAN: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case SMALLINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case INT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case BIGINT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DECIMAL: + + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + case REAL: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DOUBLE: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } else { + nr[i] = nil + } + } + + case DATE, TIME, DATETIME, TIME_TZ, DATETIME_TZ, DATETIME2, DATETIME2_TZ: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case INTERVAL_YM: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case INTERVAL_DT: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case PLTYPE_RECORD, CLASS, ARRAY, SARRAY: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil { + nr[i] = tempData.m_dumyData + } + } + + case BLOB: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + case CLOB: + for i := 0; i < l; i++ { + tempData = &arr.m_arrData[index+int64(i)] + if tempData != nil && tempData.m_dumyData != nil { + nr[i] = tempData.m_dumyData + } + } + + default: + return nil, ECGO_UNSUPPORTED_TYPE.throw() + } + + return nr, nil +} + +func (td *TypeData) toNumericArray(arr *DmArray, index int64, l int, flag int) (interface{}, error) { + if nil == arr.m_objArray { + return nil, nil + } + + var retObj interface{} + switch arr.m_objArray.(type) { + case []int16: + if flag == ARRAY_TYPE_SHORT { + ret := make([]int16, l) + copy(ret[:l], arr.m_objArray.([]int16)[index:index+int64(l)]) + retObj = ret + } + case []int: + if flag == ARRAY_TYPE_INTEGER { + ret := make([]int, l) + copy(ret[:l], arr.m_objArray.([]int)[index:index+int64(l)]) + retObj = ret + } + case []int64: + if flag == ARRAY_TYPE_LONG { + ret := make([]int64, l) + copy(ret[:l], arr.m_objArray.([]int64)[index:index+int64(l)]) + retObj = ret + } + case []float32: + if flag == ARRAY_TYPE_FLOAT { + ret := make([]float32, l) + copy(ret[:l], arr.m_objArray.([]float32)[index:index+int64(l)]) + retObj = ret + } + case []float64: + if flag == ARRAY_TYPE_DOUBLE { + ret := make([]float64, l) + copy(ret[:l], arr.m_objArray.([]float64)[index:index+int64(l)]) + retObj = ret + } + default: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + } + + return retObj, nil +} + +func (td *TypeData) toJavaArrayByDmStruct(st *DmStruct) ([]interface{}, error) { + attrsData := st.getAttribsTypeData() + if nil == st.getAttribsTypeData() || len(st.getAttribsTypeData()) <= 0 { + return nil, nil + } + + fields := st.m_strctDesc.getItemsDesc() + if len(attrsData) != len(fields) { + return nil, ECGO_STRUCT_MEM_NOT_MATCH.throw() + } + + out := make([]interface{}, len(fields)) + for i := 0; i < len(fields); i++ { + out[i] = attrsData[i].m_dumyData + } + + return out, nil +} + +func (td *TypeData) toBytesFromDmArray(x *DmArray, typeDesc *TypeDescriptor) ([]byte, error) { + var err error + desc, err := typeDesc.getClassDescChkInfo() + if err != nil { + return nil, err + } + var data []byte + switch typeDesc.getDType() { + case ARRAY: + data, err = TypeDataSV.arrayToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case SARRAY: + data, err = TypeDataSV.sarrayToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case PLTYPE_RECORD: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case CLASS: + data, err = TypeDataSV.objToBytes(x, typeDesc) + if err != nil { + return nil, err + } + } + ret := make([]byte, ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)) + Dm_build_1346.Dm_build_1362(ret, 0, OBJ_BLOB_MAGIC) + Dm_build_1346.Dm_build_1362(ret, ULINT_SIZE, int32(len(desc))) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)], desc[:len(desc)]) + copy(ret[ULINT_SIZE+ULINT_SIZE+len(desc):ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)], data[:len(data)]) + return ret, nil +} + +func (td *TypeData) toBytesFromDmStruct(x *DmStruct, typeDesc *TypeDescriptor) ([]byte, error) { + var err error + desc, err := typeDesc.getClassDescChkInfo() + if err != nil { + return nil, err + } + var data []byte + switch typeDesc.getDType() { + case ARRAY: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case SARRAY: + return nil, ECGO_DATA_CONVERTION_ERROR.throw() + case PLTYPE_RECORD: + data, err = TypeDataSV.recordToBytes(x, typeDesc) + if err != nil { + return nil, err + } + case CLASS: + data, err = TypeDataSV.objToBytes(x, typeDesc) + if err != nil { + return nil, err + } + } + ret := make([]byte, ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)) + Dm_build_1346.Dm_build_1362(ret, 0, OBJ_BLOB_MAGIC) + Dm_build_1346.Dm_build_1362(ret, ULINT_SIZE, int32(len(desc))) + copy(ret[ULINT_SIZE+ULINT_SIZE:ULINT_SIZE+ULINT_SIZE+len(desc)], desc[:len(desc)]) + copy(ret[ULINT_SIZE+ULINT_SIZE+len(desc):ULINT_SIZE+ULINT_SIZE+len(desc)+len(data)], data[:len(data)]) + return ret, nil +} diff --git a/dpi_bridge/third_party/chunanyong_dm/zzp.go b/dpi_bridge/third_party/chunanyong_dm/zzp.go new file mode 100644 index 0000000..09b226d --- /dev/null +++ b/dpi_bridge/third_party/chunanyong_dm/zzp.go @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2000-2018, 达梦数据库有限公司. + * All rights reserved. + */ +package dm + +import ( + "database/sql/driver" +) + +const ( + OBJ_BLOB_MAGIC = 78111999 + + CLTN_TYPE_IND_TABLE = 3 + + CLTN_TYPE_NST_TABLE = 2 + + CLTN_TYPE_VARRAY = 1 +) + +type TypeDescriptor struct { + column *column + + m_sqlName *sqlName + + m_objId int + + m_objVersion int + + m_outerId int + + m_outerVer int + + m_subId int + + m_cltnType int + + m_maxCnt int + + m_length int + + m_size int + + m_conn *DmConnection + + m_serverEncoding string + + m_arrObj *TypeDescriptor + + m_fieldsObj []TypeDescriptor + + m_descBuf []byte +} + +func newTypeDescriptorWithFulName(fulName string, conn *DmConnection) *TypeDescriptor { + td := new(TypeDescriptor) + td.init() + td.m_sqlName = newSqlNameByFulName(fulName) + td.m_conn = conn + return td +} + +func newTypeDescriptor(conn *DmConnection) *TypeDescriptor { + td := new(TypeDescriptor) + td.init() + td.m_sqlName = newSqlNameByConn(conn) + td.m_conn = conn + return td +} + +func (typeDescriptor *TypeDescriptor) init() { + typeDescriptor.column = new(column).InitColumn() + + typeDescriptor.m_sqlName = nil + + typeDescriptor.m_objId = -1 + + typeDescriptor.m_objVersion = -1 + + typeDescriptor.m_outerId = 0 + + typeDescriptor.m_outerVer = 0 + + typeDescriptor.m_subId = 0 + + typeDescriptor.m_cltnType = 0 + + typeDescriptor.m_maxCnt = 0 + + typeDescriptor.m_length = 0 + + typeDescriptor.m_size = 0 + + typeDescriptor.m_conn = nil + + typeDescriptor.m_serverEncoding = "" + + typeDescriptor.m_arrObj = nil + + typeDescriptor.m_fieldsObj = nil + + typeDescriptor.m_descBuf = nil +} + +func (typeDescriptor *TypeDescriptor) parseDescByName() error { + sql := "BEGIN ? = SF_DESCRIBE_TYPE(?); END;" + + params := make([]driver.Value, 2) + params[1] = typeDescriptor.m_sqlName.m_fulName + + rs, err := typeDescriptor.m_conn.query(sql, params) + if err != nil { + return err + } + rs.close() + l, err := params[0].(*DmBlob).GetLength() + if err != nil { + return err + } + + buf, err := params[0].(*DmBlob).getBytes(1, int32(l)) + if err != nil { + return err + } + typeDescriptor.m_serverEncoding = typeDescriptor.m_conn.getServerEncoding() + err = typeDescriptor.unpack(Dm_build_83(buf)) + if err != nil { + return err + } + return nil +} + +func (typeDescriptor *TypeDescriptor) getFulName() (string, error) { + return typeDescriptor.m_sqlName.getFulName() +} + +func (typeDescriptor *TypeDescriptor) getDType() int { + return int(typeDescriptor.column.colType) +} + +func (typeDescriptor *TypeDescriptor) getPrec() int { + return int(typeDescriptor.column.prec) +} + +func (typeDescriptor *TypeDescriptor) getScale() int { + return int(typeDescriptor.column.scale) +} + +func (typeDescriptor *TypeDescriptor) getServerEncoding() string { + if typeDescriptor.m_serverEncoding == "" { + return typeDescriptor.m_conn.getServerEncoding() + } else { + return typeDescriptor.m_serverEncoding + } +} + +func (typeDescriptor *TypeDescriptor) getObjId() int { + return typeDescriptor.m_objId +} + +func (typeDescriptor *TypeDescriptor) getStaticArrayLength() int { + return typeDescriptor.m_length +} + +func (typeDescriptor *TypeDescriptor) getStrctMemSize() int { + return typeDescriptor.m_size +} + +func (typeDescriptor *TypeDescriptor) getOuterId() int { + return typeDescriptor.m_outerId +} + +func (typeDescriptor *TypeDescriptor) getCltnType() int { + return typeDescriptor.m_cltnType +} + +func (typeDescriptor *TypeDescriptor) getMaxCnt() int { + return typeDescriptor.m_maxCnt +} + +func getPackSize(typeDesc *TypeDescriptor) (int, error) { + len := 0 + + switch typeDesc.column.colType { + case ARRAY, SARRAY: + return getPackArraySize(typeDesc) + + case CLASS: + return getPackClassSize(typeDesc) + + case PLTYPE_RECORD: + return getPackRecordSize(typeDesc) + } + + len += ULINT_SIZE + + len += ULINT_SIZE + + len += ULINT_SIZE + + return len, nil +} + +func pack(typeDesc *TypeDescriptor, msg *Dm_build_78) error { + switch typeDesc.column.colType { + case ARRAY, SARRAY: + return packArray(typeDesc, msg) + case CLASS: + return packClass(typeDesc, msg) + case PLTYPE_RECORD: + return packRecord(typeDesc, msg) + } + + msg.Dm_build_133(typeDesc.column.colType) + + msg.Dm_build_133(typeDesc.column.prec) + + msg.Dm_build_133(typeDesc.column.scale) + return nil +} + +func getPackArraySize(arrDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := arrDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := arrDesc.getServerEncoding() + ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, arrDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += ULINT_SIZE + + i, err := getPackSize(arrDesc.m_arrObj) + if err != nil { + return 0, err + } + + l += i + + return l, nil +} + +func packArray(arrDesc *TypeDescriptor, msg *Dm_build_78) error { + + msg.Dm_build_133(arrDesc.column.colType) + + msg.Dm_build_189(arrDesc.m_sqlName.m_name, arrDesc.getServerEncoding(), arrDesc.m_conn) + + msg.Dm_build_133(int32(arrDesc.m_objId)) + + msg.Dm_build_133(int32(arrDesc.m_objVersion)) + + msg.Dm_build_133(int32(arrDesc.m_length)) + + return pack(arrDesc.m_arrObj, msg) +} + +func packRecord(strctDesc *TypeDescriptor, msg *Dm_build_78) error { + + msg.Dm_build_133(strctDesc.column.colType) + + msg.Dm_build_189(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn) + + msg.Dm_build_133(int32(strctDesc.m_objId)) + + msg.Dm_build_133(int32(strctDesc.m_objVersion)) + + msg.Dm_build_129(int16(strctDesc.m_size)) + + for i := 0; i < strctDesc.m_size; i++ { + err := pack(&strctDesc.m_fieldsObj[i], msg) + if err != nil { + return err + } + } + return nil +} + +func getPackRecordSize(strctDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := strctDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := strctDesc.getServerEncoding() + ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, strctDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += USINT_SIZE + + for i := 0; i < strctDesc.m_size; i++ { + i, err := getPackSize(&strctDesc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + l += i + } + + return l, nil +} + +func getPackClassSize(strctDesc *TypeDescriptor) (int, error) { + l := 0 + + l += ULINT_SIZE + + name := strctDesc.m_sqlName.m_name + l += USINT_SIZE + + serverEncoding := strctDesc.getServerEncoding() + ret := Dm_build_1346.Dm_build_1562(name, serverEncoding, strctDesc.m_conn) + l += len(ret) + + l += ULINT_SIZE + + l += ULINT_SIZE + + if strctDesc.m_objId == 4 { + + l += ULINT_SIZE + + l += ULINT_SIZE + + l += USINT_SIZE + } + + return l, nil +} + +func packClass(strctDesc *TypeDescriptor, msg *Dm_build_78) error { + + msg.Dm_build_133(strctDesc.column.colType) + + msg.Dm_build_189(strctDesc.m_sqlName.m_name, strctDesc.getServerEncoding(), strctDesc.m_conn) + + msg.Dm_build_133(int32(strctDesc.m_objId)) + + msg.Dm_build_133(int32(strctDesc.m_objVersion)) + + if strctDesc.m_objId == 4 { + + msg.Dm_build_133(int32(strctDesc.m_outerId)) + + msg.Dm_build_133(int32(strctDesc.m_outerVer)) + + msg.Dm_build_141(uint16(strctDesc.m_subId)) + + } + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpack(buffer *Dm_build_78) error { + + typeDescriptor.column.colType = buffer.Dm_build_207() + + switch typeDescriptor.column.colType { + case ARRAY, SARRAY: + return typeDescriptor.unpackArray(buffer) + case CLASS: + return typeDescriptor.unpackClass(buffer) + case PLTYPE_RECORD: + return typeDescriptor.unpackRecord(buffer) + } + + typeDescriptor.column.prec = buffer.Dm_build_207() + + typeDescriptor.column.scale = buffer.Dm_build_207() + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackArray(buffer *Dm_build_78) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_207()) + + typeDescriptor.m_length = int(buffer.Dm_build_207()) + if typeDescriptor.column.colType == ARRAY { + typeDescriptor.m_length = 0 + } + + typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn) + return typeDescriptor.m_arrObj.unpack(buffer) +} + +func (typeDescriptor *TypeDescriptor) unpackRecord(buffer *Dm_build_78) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_207()) + + typeDescriptor.m_size = int(buffer.Dm_build_222()) + + typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size) + for i := 0; i < typeDescriptor.m_size; i++ { + typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn) + typeDescriptor.m_fieldsObj[i].unpack(buffer) + } + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClnt_nestTab(buffer *Dm_build_78) error { + + typeDescriptor.m_maxCnt = int(buffer.Dm_build_207()) + + typeDescriptor.m_arrObj = newTypeDescriptor(typeDescriptor.m_conn) + + typeDescriptor.m_arrObj.unpack(buffer) + + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClnt(buffer *Dm_build_78) error { + + typeDescriptor.m_outerId = int(buffer.Dm_build_207()) + + typeDescriptor.m_outerVer = int(buffer.Dm_build_207()) + + typeDescriptor.m_subId = int(buffer.Dm_build_222()) + + typeDescriptor.m_cltnType = int(buffer.Dm_build_222()) + + switch typeDescriptor.m_cltnType { + case CLTN_TYPE_IND_TABLE: + return ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + return typeDescriptor.unpackClnt_nestTab(buffer) + + } + return nil +} + +func (typeDescriptor *TypeDescriptor) unpackClass(buffer *Dm_build_78) error { + + typeDescriptor.m_sqlName.m_name = buffer.Dm_build_257(typeDescriptor.getServerEncoding(), typeDescriptor.m_conn) + + typeDescriptor.m_sqlName.m_schId = int(buffer.Dm_build_207()) + + typeDescriptor.m_sqlName.m_packId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objId = int(buffer.Dm_build_207()) + + typeDescriptor.m_objVersion = int(buffer.Dm_build_207()) + + if typeDescriptor.m_objId == 4 { + return typeDescriptor.unpackClnt(buffer) + } else { + + typeDescriptor.m_size = int(buffer.Dm_build_222()) + + typeDescriptor.m_fieldsObj = make([]TypeDescriptor, typeDescriptor.m_size) + for i := 0; i < typeDescriptor.m_size; i++ { + typeDescriptor.m_fieldsObj[i] = *newTypeDescriptor(typeDescriptor.m_conn) + err := typeDescriptor.m_fieldsObj[i].unpack(buffer) + if err != nil { + return err + } + } + return nil + } + +} + +func calcChkDescLen_array(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += ULINT_SIZE + + tmp, err := calcChkDescLen(desc) + if err != nil { + return 0, err + } + + offset += tmp + + return offset, nil +} + +func calcChkDescLen_record(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += USINT_SIZE + + for i := 0; i < desc.m_size; i++ { + tmp, err := calcChkDescLen(&desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + offset += tmp + } + + return offset, nil +} + +func calcChkDescLen_class_normal(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + for i := 0; i < desc.m_size; i++ { + tmp, err := calcChkDescLen(&desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + offset += tmp + } + + return offset, nil +} + +func calcChkDescLen_class_cnlt(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += ULINT_SIZE + + switch desc.getCltnType() { + case CLTN_TYPE_IND_TABLE: + return 0, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_VARRAY, CLTN_TYPE_NST_TABLE: + + i, err := calcChkDescLen(desc.m_arrObj) + if err != nil { + return 0, err + } + + offset += i + } + + return offset, nil +} + +func calcChkDescLen_class(desc *TypeDescriptor) (int, error) { + offset := 0 + + offset += USINT_SIZE + + offset += BYTE_SIZE + + if desc.m_objId == 4 { + i, err := calcChkDescLen_class_cnlt(desc) + if err != nil { + return 0, err + } + offset += i + } else { + i, err := calcChkDescLen_class_normal(desc) + if err != nil { + return 0, err + } + offset += i + } + + return offset, nil +} + +func calcChkDescLen_buildin() int { + offset := 0 + + offset += USINT_SIZE + + offset += USINT_SIZE + + offset += USINT_SIZE + + return offset +} + +func calcChkDescLen(desc *TypeDescriptor) (int, error) { + + switch desc.getDType() { + case ARRAY, SARRAY: + return calcChkDescLen_array(desc) + + case PLTYPE_RECORD: + return calcChkDescLen_record(desc) + + case CLASS: + return calcChkDescLen_class(desc) + + default: + return calcChkDescLen_buildin(), nil + } + +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_array(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, ARRAY) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1362(typeDescriptor.m_descBuf, offset, int32(desc.m_length)) + offset += ULINT_SIZE + + return typeDescriptor.makeChkDesc(offset, desc) +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_record(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, PLTYPE_RECORD) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_size)) + offset += USINT_SIZE + var err error + for i := 0; i < desc.m_size; i++ { + offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_buildin(offset int, desc *TypeDescriptor) int { + dtype := int16(desc.getDType()) + prec := 0 + scale := 0 + + if dtype != BLOB { + prec = desc.getPrec() + scale = desc.getScale() + } + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, dtype) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(prec)) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(scale)) + offset += USINT_SIZE + + return offset +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class_normal(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_size)) + offset += USINT_SIZE + var err error + + for i := 0; i < desc.m_size; i++ { + offset, err = typeDescriptor.makeChkDesc(offset, &desc.m_fieldsObj[i]) + if err != nil { + return 0, err + } + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class_clnt(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, int16(desc.m_cltnType)) + offset += USINT_SIZE + + Dm_build_1346.Dm_build_1362(typeDescriptor.m_descBuf, offset, int32(desc.getMaxCnt())) + offset += ULINT_SIZE + + switch desc.m_cltnType { + case CLTN_TYPE_IND_TABLE: + return 0, ECGO_UNSUPPORTED_TYPE.throw() + + case CLTN_TYPE_NST_TABLE, CLTN_TYPE_VARRAY: + + return typeDescriptor.makeChkDesc(offset, desc.m_arrObj) + } + + return offset, nil +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc_class(offset int, desc *TypeDescriptor) (int, error) { + + Dm_build_1346.Dm_build_1357(typeDescriptor.m_descBuf, offset, CLASS) + offset += USINT_SIZE + + isClnt := false + if desc.m_objId == 4 { + isClnt = true + } + + if isClnt { + Dm_build_1346.Dm_build_1347(typeDescriptor.m_descBuf, offset, byte(1)) + } else { + Dm_build_1346.Dm_build_1347(typeDescriptor.m_descBuf, offset, byte(0)) + } + + offset += BYTE_SIZE + + if isClnt { + return typeDescriptor.makeChkDesc_class_clnt(offset, desc) + } else { + return typeDescriptor.makeChkDesc_class_normal(offset, desc) + } +} + +func (typeDescriptor *TypeDescriptor) makeChkDesc(offset int, subDesc *TypeDescriptor) (int, error) { + switch subDesc.getDType() { + case ARRAY, SARRAY: + return typeDescriptor.makeChkDesc_array(offset, subDesc) + + case PLTYPE_RECORD: + return typeDescriptor.makeChkDesc_record(offset, subDesc) + + case CLASS: + return typeDescriptor.makeChkDesc_class(offset, subDesc) + + default: + return typeDescriptor.makeChkDesc_buildin(offset, subDesc), nil + } + +} + +func (typeDescriptor *TypeDescriptor) getClassDescChkInfo() ([]byte, error) { + if typeDescriptor.m_descBuf != nil { + return typeDescriptor.m_descBuf, nil + } + + l, err := calcChkDescLen(typeDescriptor) + if err != nil { + return nil, err + } + typeDescriptor.m_descBuf = make([]byte, l) + + typeDescriptor.makeChkDesc(0, typeDescriptor) + return typeDescriptor.m_descBuf, nil +} diff --git a/dpi_bridge/types.go b/dpi_bridge/types.go new file mode 100644 index 0000000..0a61ba1 --- /dev/null +++ b/dpi_bridge/types.go @@ -0,0 +1,389 @@ +package main + +/* +#include +#include +#include + +// DPI primitive types matching DPItypes.h +typedef signed char sdbyte; +typedef unsigned char udbyte; +typedef signed short sdint2; +typedef unsigned short udint2; +typedef signed int sdint4; +typedef unsigned int udint4; +typedef long long int sdint8; +typedef unsigned long long int udint8; +typedef float dfloat; +typedef double ddouble; +typedef void* dpointer; + +// 64-bit platform length types +typedef sdint8 slength; +typedef udint8 ulength; + +// Function return type +typedef sdint2 DPIRETURN; + +// Handle types — all void* +typedef void* dhandle; +typedef dhandle dhenv; +typedef dhandle dhcon; +typedef dhandle dhstmt; +typedef dhandle dhdesc; +typedef dhandle dhloblctr; +typedef dhandle dhobjdesc; +typedef dhandle dhobj; +typedef dhandle dhbfile; + +// Numeric struct +#define DPI_MAX_NUMERIC_LEN 16 +typedef struct { + udbyte precision; + signed char scale; + udbyte sign; + udbyte val[DPI_MAX_NUMERIC_LEN]; +} dpi_numeric_t; + +// Timestamp struct +typedef struct { + sdint2 year; + udint2 month; + udint2 day; + udint2 hour; + udint2 minute; + udint2 second; + udint4 fraction; +} dpi_timestamp_t; + +// Date struct +typedef struct { + sdint2 year; + udint2 month; + udint2 day; +} dpi_date_t; + +// Time struct +typedef struct { + udint2 hour; + udint2 minute; + udint2 second; +} dpi_time_t; +*/ +import "C" +import "unsafe" + +// DPI return codes +const ( + DSQL_SUCCESS = C.DPIRETURN(0) + DSQL_SUCCESS_WITH_INFO = C.DPIRETURN(1) + DSQL_ERROR = C.DPIRETURN(-1) + DSQL_INVALID_HANDLE = C.DPIRETURN(-2) + DSQL_NO_DATA = C.DPIRETURN(100) + DSQL_NEED_DATA = C.DPIRETURN(99) + DSQL_STILL_EXECUTING = C.DPIRETURN(2) +) + +// Handle type identifiers +const ( + DSQL_HANDLE_ENV = 1 + DSQL_HANDLE_DBC = 2 + DSQL_HANDLE_STMT = 3 + DSQL_HANDLE_DESC = 4 +) + +// Special length/indicator values +const ( + DSQL_NULL_DATA = C.slength(-1) + DSQL_DATA_AT_EXEC = C.slength(-2) + DSQL_NTS = C.slength(-3) +) + +// Transaction operations +const ( + DSQL_COMMIT = 0 + DSQL_ROLLBACK = 1 +) + +// Parameter binding types +const ( + DSQL_PARAM_INPUT = 1 + DSQL_PARAM_INPUT_OUTPUT = 2 + DSQL_PARAM_OUTPUT = 4 + DSQL_PARAM_OUTPUT_STREAM = 16 +) + +// Fetch orientations +const ( + DSQL_FETCH_NEXT = 1 +) + +// C type codes +const ( + DSQL_C_NCHAR = 0 + DSQL_C_SSHORT = 1 + DSQL_C_USHORT = 2 + DSQL_C_SLONG = 3 + DSQL_C_ULONG = 4 + DSQL_C_FLOAT = 5 + DSQL_C_DOUBLE = 6 + DSQL_C_BIT = 7 + DSQL_C_STINYINT = 8 + DSQL_C_UTINYINT = 9 + DSQL_C_SBIGINT = 10 + DSQL_C_UBIGINT = 11 + DSQL_C_BINARY = 12 + DSQL_C_DATE = 13 + DSQL_C_TIME = 14 + DSQL_C_TIMESTAMP = 15 + DSQL_C_NUMERIC = 16 + DSQL_C_DEFAULT = 30 + DSQL_C_CLASS = 31 + DSQL_C_RECORD = 32 + DSQL_C_ARRAY = 33 + DSQL_C_SARRAY = 34 + + DSQL_C_INTERVAL_YEAR = 17 + DSQL_C_INTERVAL_MONTH = 18 + DSQL_C_INTERVAL_DAY = 19 + DSQL_C_INTERVAL_HOUR = 20 + DSQL_C_INTERVAL_MINUTE = 21 + DSQL_C_INTERVAL_SECOND = 22 + DSQL_C_INTERVAL_YEAR_TO_MONTH = 23 + DSQL_C_INTERVAL_DAY_TO_HOUR = 24 + DSQL_C_INTERVAL_DAY_TO_MINUTE = 25 + DSQL_C_INTERVAL_DAY_TO_SECOND = 26 + DSQL_C_INTERVAL_HOUR_TO_MINUTE = 27 + DSQL_C_INTERVAL_HOUR_TO_SECOND = 28 + DSQL_C_INTERVAL_MINUTE_TO_SECOND = 29 + + DSQL_C_LOB_HANDLE = 999 + DSQL_C_RSET = 1000 + DSQL_C_WCHAR = 1001 + DSQL_C_BFILE = 1002 + DSQL_C_CHAR = 1003 +) + +// SQL server type codes +const ( + DSQL_CHAR = 1 + DSQL_VARCHAR = 2 + DSQL_BIT = 3 + DSQL_TINYINT = 5 + DSQL_SMALLINT = 6 + DSQL_INT = 7 + DSQL_BIGINT = 8 + DSQL_DEC = 9 + DSQL_FLOAT = 10 + DSQL_DOUBLE = 11 + DSQL_BLOB = 12 + DSQL_BOOLEAN = 13 + DSQL_DATE = 14 + DSQL_TIME = 15 + DSQL_TIMESTAMP = 16 + DSQL_BINARY = 17 + DSQL_VARBINARY = 18 + DSQL_CLOB = 19 + DSQL_TIME_TZ = 22 + DSQL_TIMESTAMP_TZ = 23 + DSQL_CLASS = 24 + DSQL_RECORD = 25 + DSQL_ARRAY = 26 + DSQL_SARRAY = 27 + DSQL_ROWID = 28 + DSQL_RSET = 119 + DSQL_BFILE = 1000 +) + +// Environment/Connection attributes (from DPIext.h) +const ( + DSQL_ATTR_LOCAL_CODE = 12345 + DSQL_ATTR_LANG_ID = 12346 + DSQL_ATTR_TIME_ZONE = 12348 + DSQL_ATTR_DEC2DOUB_CNVT = 12350 + DSQL_ATTR_ACCESS_MODE = 101 + DSQL_ATTR_AUTOCOMMIT = 102 + DSQL_ATTR_LOGIN_TIMEOUT = 103 + DSQL_ATTR_TXN_ISOLATION = 108 + DSQL_ATTR_CURRENT_CATALOG = 109 + DSQL_ATTR_PACKET_SIZE = 112 + DSQL_ATTR_CONNECTION_TIMEOUT = 113 + DSQL_ATTR_CONNECTION_DEAD = 1209 + + DSQL_ATTR_LOGIN_PORT = 12350 + DSQL_ATTR_LOGIN_USER = 12352 + DSQL_ATTR_CURRENT_SCHEMA = 12354 + DSQL_ATTR_INSTANCE_NAME = 12355 + DSQL_ATTR_LOGIN_SERVER = 12356 + DSQL_ATTR_SERVER_CODE = 12349 + DSQL_ATTR_APP_NAME = 12357 + DSQL_ATTR_COMPRESS_MSG = 12358 + DSQL_ATTR_USE_STMT_POOL = 12359 + DSQL_ATTR_SERVER_VERSION = 12400 + DSQL_ATTR_SSL_PATH = 12401 + DSQL_ATTR_SSL_PWD = 12402 + DSQL_ATTR_MPP_LOGIN = 12403 + DSQL_ATTR_TRX_STATE = 12404 + DSQL_ATTR_UKEY_NAME = 12405 + DSQL_ATTR_UKEY_PIN = 12406 + DSQL_ATTR_RWSEPARATE = 12408 + DSQL_ATTR_RWSEPARATE_PERCENT = 12409 + DSQL_ATTR_CURSOR_ROLLBACK_BEHAVIOR = 12410 + DSQL_ATTR_OSAUTH_TYPE = 12412 + DSQL_ATTR_DDL_AUTOCOMMIT = 12414 + DSQL_ATTR_COMPATIBLE_MODE = 12424 + DSQL_ATTR_SHAKE_CRYPTO = 12426 + DSQL_ATTR_NLS_NUMERIC_CHARACTERS = 12430 + DSQL_ATTR_DM_SVC_PATH = 12431 +) + +// Statement attributes +const ( + DSQL_ATTR_QUERY_TIMEOUT = 0 + DSQL_ATTR_MAX_ROWS = 1 + DSQL_ATTR_CURSOR_TYPE = 6 + DSQL_ATTR_PARAMSET_SIZE = 22 + DSQL_ATTR_ROW_STATUS_PTR = 25 + DSQL_ATTR_ROWS_FETCHED_PTR = 26 + DSQL_ATTR_ROW_ARRAY_SIZE = 27 + DSQL_ATTR_CURSOR_SCROLLABLE = -1 + DSQL_ATTR_APP_ROW_DESC = 10010 + DSQL_ATTR_APP_PARAM_DESC = 10011 + DSQL_ATTR_IMP_ROW_DESC = 10012 + DSQL_ATTR_IMP_PARAM_DESC = 10013 + DSQL_ATTR_SQL_CHARSET = 20000 + DSQL_ATTR_IGN_BP_ERR = 20001 +) + +// Cursor types +const ( + DSQL_CURSOR_FORWARD_ONLY = 0 + DSQL_CURSOR_STATIC = 3 +) + +// Autocommit values +const ( + DSQL_AUTOCOMMIT_OFF = 0 + DSQL_AUTOCOMMIT_ON = 1 +) + +// Encoding constants (from DPIext.h) +const ( + PG_UTF8 = 1 + PG_GBK = 2 + PG_GB18030 = 10 +) + +// Diagnostics field identifiers +const ( + DSQL_DIAG_NUMBER = 1 + DSQL_DIAG_DYNAMIC_FUNCTION_CODE = 2 + DSQL_DIAG_ROW_COUNT = 3 + DSQL_DIAG_EXPLAIN = 5 + DSQL_DIAG_ROWID = 6 + DSQL_DIAG_EXECID = 7 + DSQL_DIAG_SERVER_STAT = 8 + DSQL_DIAG_MESSAGE_TEXT = 102 + DSQL_DIAG_ERROR_CODE = 103 +) + +// Statement function codes (DSQL_DIAG_DYNAMIC_FUNCTION_CODE values) +const ( + DSQL_DIAG_FUNC_CODE_INVALID = 0 + DSQL_DIAG_FUNC_CODE_SELECT = 1 + DSQL_DIAG_FUNC_CODE_INSERT = 2 + DSQL_DIAG_FUNC_CODE_DELETE = 3 + DSQL_DIAG_FUNC_CODE_UPDATE = 4 + DSQL_DIAG_FUNC_CODE_CREATE_DB = 5 + DSQL_DIAG_FUNC_CODE_CREATE_TAB = 6 + DSQL_DIAG_FUNC_CODE_DROP_TAB = 7 + DSQL_DIAG_FUNC_CODE_CALL = 28 + DSQL_DIAG_FUNC_CODE_MERGE = 69 + DSQL_DIAG_FUNC_CODE_SET_CURRENT_SCHEMA = 68 +) + +// Descriptor field identifiers +const ( + DSQL_DESC_COUNT = 1001 + DSQL_DESC_TYPE = 1002 + DSQL_DESC_LENGTH = 1003 + DSQL_DESC_PRECISION = 1005 + DSQL_DESC_SCALE = 1006 + DSQL_DESC_NULLABLE = 1008 + DSQL_DESC_INDICATOR_PTR = 1009 + DSQL_DESC_DATA_PTR = 1010 + DSQL_DESC_NAME = 1011 + DSQL_DESC_OCTET_LENGTH = 1013 + DSQL_DESC_DISPLAY_SIZE = 6 // same as DSQL_COLUMN_DISPLAY_SIZE + DSQL_DESC_PARAMETER_TYPE = 33 + DSQL_DESC_OBJ_DESCRIPTOR = 10001 + DSQL_DESC_BIND_PARAMETER_TYPE = 10003 +) + +// Column attribute identifiers +const ( + DSQL_COLUMN_COUNT = 0 + DSQL_COLUMN_NAME = 1 + DSQL_COLUMN_TYPE = 2 + DSQL_COLUMN_LENGTH = 3 + DSQL_COLUMN_PRECISION = 4 + DSQL_COLUMN_SCALE = 5 + DSQL_COLUMN_DISPLAY_SIZE = 6 + DSQL_COLUMN_NULLABLE = 7 + DSQL_COLUMN_TABLE_NAME = 15 +) + +// Nullable values +const ( + DSQL_NO_NULLS = 0 + DSQL_NULLABLE = 1 + DSQL_NULLABLE_UNKNOWN = 2 +) + +// Default TCP port +const DSQL_DEAFAULT_TCPIP_PORT = 5236 + +// ISO transaction isolation levels +const ( + ISO_LEVEL_READ_UNCOMMITTED = 0 + ISO_LEVEL_READ_COMMITTED = 1 + ISO_LEVEL_REPEATABLE_READ = 2 + ISO_LEVEL_SERIALIZABLE = 3 +) + +// Language constants +const ( + LANGUAGE_CN = 0 + LANGUAGE_EN = 1 + LANGUAGE_CNT_HK = 2 +) + +// goString converts a C sdbyte* to a Go string. If length < 0, it's NTS. +func goString(s *C.sdbyte, length C.sdint4) string { + if s == nil { + return "" + } + if length < 0 { + // null-terminated string + return C.GoString((*C.char)(unsafe.Pointer(s))) + } + return C.GoStringN((*C.char)(unsafe.Pointer(s)), C.int(length)) +} + +// cStringLen writes a Go string into a C buffer and returns the length written. +func cStringLen(dst *C.sdbyte, bufLen int, src string) C.sdint2 { + if dst == nil || bufLen <= 0 { + return C.sdint2(len(src)) + } + b := []byte(src) + n := len(b) + if n >= bufLen { + n = bufLen - 1 + } + if n > 0 { + C.memcpy(unsafe.Pointer(dst), unsafe.Pointer(&b[0]), C.size_t(n)) + } + // null terminate + *(*C.sdbyte)(unsafe.Pointer(uintptr(unsafe.Pointer(dst)) + uintptr(n))) = 0 + return C.sdint2(n) +} diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..af9d7e7 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,27 @@ +site_name: dmPython-macOS Documentation +site_description: dmPython-macOS API reference and examples +site_url: https://skhe.github.io/dmPython/ +repo_url: https://github.com/skhe/dmPython +repo_name: skhe/dmPython + +theme: + name: mkdocs + +markdown_extensions: + - tables + - toc: + permalink: true + +nav: + - 首页: index.md + - 安装指南: installation.md + - 快速开始: quickstart.md + - API 参考: api-reference.md + - 示例: + - 基本增删改查: examples/basic-crud.md + - 批量插入: examples/bulk-insert.md + - LOB 大对象操作: examples/lob-handling.md + - 存储过程调用: examples/stored-proc.md + - 连接池: examples/connection-pool.md + - 迁移指南: migration.md + - 常见问题: faq.md diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..feb7751 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,42 @@ +[build-system] +requires = ["setuptools>=68.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "dmPython-macOS" +version = "2.5.32" +description = "Python DB-API 2.0 driver for DM (Dameng) database — macOS edition with built-in Go bridge" +readme = "README.md" +license = {text = "MulanPSL-2.0"} +requires-python = ">=3.8" +authors = [ + {name = "Dameng"}, + {name = "skhe"}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: English", + "Operating System :: MacOS :: MacOS X", + "Programming Language :: C", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Database", + "Topic :: Database :: Front-Ends", +] +keywords = ["Dameng", "DM8", "database", "DB-API"] + +[project.urls] +Homepage = "https://github.com/skhe/dmPython" +Repository = "https://github.com/skhe/dmPython" +"Bug Tracker" = "https://github.com/skhe/dmPython/issues" +Changelog = "https://github.com/skhe/dmPython/blob/main/CHANGELOG.md" +"Upstream (Official)" = "https://github.com/DamengDB/dmPython" + +[tool.setuptools] +py-modules = [] +packages = [] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..dfa9fc9 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,12 @@ +[pytest] +addopts = -ra +testpaths = + tests +faulthandler_timeout = 120 +asyncio_default_fixture_loop_scope = function +markers = + requires_dm: tests requiring a reachable Dameng database instance + p0_stability: critical crash/stability guards + p1_contract: API contract tests + p2_scale: scale and stress tests + crash_guard: subprocess crash-detection tests diff --git a/scripts/check_third_party_patch.py b/scripts/check_third_party_patch.py new file mode 100755 index 0000000..ef506ee --- /dev/null +++ b/scripts/check_third_party_patch.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Validate local patched DM driver contract and patch docs.""" +from __future__ import annotations + +import sys +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +GO_MOD = ROOT / "dpi_bridge/go.mod" +PATCH_DOC = ROOT / "dpi_bridge/third_party/chunanyong_dm/PATCHES.md" +PATCH_FILE = ROOT / "dpi_bridge/third_party/chunanyong_dm/a.go" + + +def fail(msg: str) -> None: + raise RuntimeError(msg) + + +def require_contains(path: Path, needle: str) -> None: + text = path.read_text(encoding="utf-8") + if needle not in text: + fail(f"{path} missing expected content: {needle}") + + +def main() -> int: + if not GO_MOD.exists(): + fail(f"missing {GO_MOD}") + if not PATCH_DOC.exists(): + fail(f"missing {PATCH_DOC}") + if not PATCH_FILE.exists(): + fail(f"missing {PATCH_FILE}") + + require_contains(GO_MOD, "replace gitee.com/chunanyong/dm => ./third_party/chunanyong_dm") + + # Patch documentation should describe the actual patch point and its tests. + require_contains(PATCH_DOC, "File: `a.go`") + require_contains(PATCH_DOC, "Function: `dm_build_610`") + require_contains(PATCH_DOC, "test_clob_unicode_problem_patterns_roundtrip") + require_contains(PATCH_DOC, "test_clob_unicode_problem_patterns_subprocess_no_crash") + + # Patch implementation invariants for unicode chunk-boundary fix. + require_contains(PATCH_FILE, "dm_build_610(") + require_contains(PATCH_FILE, "var dm_build_615 bytes.Buffer") + require_contains(PATCH_FILE, "Avoid splitting a UTF-8 sequence at chunk boundaries.") + + print("[OK] third-party patch consistency checks passed") + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except RuntimeError as exc: + print(f"[FAIL] {exc}") + raise SystemExit(2) diff --git a/scripts/check_version_consistency.py b/scripts/check_version_consistency.py new file mode 100755 index 0000000..71fecab --- /dev/null +++ b/scripts/check_version_consistency.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +"""Check version consistency across metadata, headers, docs, and smoke script.""" +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path +from typing import Iterable + + +ROOT = Path(__file__).resolve().parents[1] + + +def _fail(msg: str) -> None: + raise RuntimeError(msg) + + +def _extract_pyproject_version() -> str: + text = (ROOT / "pyproject.toml").read_text(encoding="utf-8") + match = re.search(r'^\s*version\s*=\s*"([^"]+)"\s*$', text, re.MULTILINE) + if not match: + _fail("Cannot find [project].version in pyproject.toml") + return match.group(1) + + +def _extract_header_version() -> str: + text = (ROOT / "src/native/py_Dameng.h").read_text(encoding="utf-8") + match = re.search(r'#define\s+BUILD_VERSION_STRING\s+"([^"]+)"', text) + if not match: + _fail("Cannot find BUILD_VERSION_STRING in src/native/py_Dameng.h") + return match.group(1) + + +def _check_setup_uses_pyproject() -> None: + text = (ROOT / "setup.py").read_text(encoding="utf-8") + if "BUILD_VERSION = read_project_version()" not in text: + _fail("setup.py is not using pyproject.toml as version source (BUILD_VERSION = read_project_version())") + + +def _check_docs_version(version: str) -> None: + files = [ROOT / "README.md", ROOT / "docs/README_zh.md"] + pattern = re.compile(r"dmPython_macOS-(\d+\.\d+\.\d+)-cp312-cp312-macosx_14_0_arm64\.whl") + for path in files: + text = path.read_text(encoding="utf-8") + match = pattern.search(text) + if not match: + _fail(f"Cannot find wheel example in {path}") + if match.group(1) != version: + _fail(f"Wheel example version mismatch in {path}: {match.group(1)} != {version}") + + +def _check_smoke_script_dynamic() -> None: + path = ROOT / "scripts/test_connection.py" + text = path.read_text(encoding="utf-8") + if "get_expected_version()" not in text: + _fail("scripts/test_connection.py is missing get_expected_version()") + if re.search(r'dmPython\.version\s*==\s*"\d+\.\d+\.\d+"', text): + _fail("scripts/test_connection.py still has a hard-coded version assertion") + + +def _check_runtime_version(version: str, strict: bool) -> None: + try: + import dmPython # type: ignore + + runtime_version = getattr(dmPython, "version", "") + if runtime_version != version: + _fail(f"Runtime dmPython.version mismatch: {runtime_version} != {version}") + except Exception as exc: + if strict: + _fail(f"Runtime dmPython version check failed: {exc}") + print(f"[WARN] Runtime check skipped: {exc}") + + +def _extract_names_from_c_array(text: str, array_name: str) -> list[str]: + pattern = rf"static\s+Py(?:MethodDef|MemberDef|GetSetDef)\s+{re.escape(array_name)}\[\]\s*=\s*\{{(.*?)\n\}};" + match = re.search(pattern, text, re.DOTALL) + if not match: + _fail(f"Cannot find C array: {array_name}") + body = match.group(1) + body = re.sub(r"/\*.*?\*/", "", body, flags=re.DOTALL) + body = re.sub(r"//.*", "", body) + names = re.findall(r'\{\s*"([^"]+)"', body) + return [n for n in names if n != "NULL"] + + +def _extract_connect_keywords(connection_text: str) -> list[str]: + match = re.search( + r"static char \*keywordList\[\]\s*=\s*\{(.*?)NULL\s*\};", + connection_text, + re.DOTALL, + ) + if not match: + _fail("Cannot find connect() keywordList in Connection.c") + return re.findall(r'"([^"]+)"', match.group(1)) + + +def _missing_tokens(doc_text: str, tokens: Iterable[str]) -> list[str]: + missing = [t for t in tokens if t not in doc_text] + return sorted(set(missing)) + + +def _check_docs_structure() -> None: + required = [ + "docs/index.md", + "docs/installation.md", + "docs/quickstart.md", + "docs/api-reference.md", + "docs/examples/basic-crud.md", + "docs/examples/bulk-insert.md", + "docs/examples/lob-handling.md", + "docs/examples/stored-proc.md", + "docs/examples/connection-pool.md", + "docs/migration.md", + "docs/faq.md", + "mkdocs.yml", + ] + missing = [path for path in required if not (ROOT / path).exists()] + if missing: + _fail(f"Missing required docs files: {missing}") + + +def _check_api_docs_coverage() -> None: + api_doc = (ROOT / "docs/api-reference.md").read_text(encoding="utf-8") + # Native C sources contain mixed legacy comments; decode losslessly. + conn_c = (ROOT / "src/native/Connection.c").read_text(encoding="latin-1") + cur_c = (ROOT / "src/native/Cursor.c").read_text(encoding="latin-1") + mod_c = (ROOT / "src/native/py_Dameng.c").read_text(encoding="latin-1") + + connect_keywords = _extract_connect_keywords(conn_c) + conn_methods = _extract_names_from_c_array(conn_c, "g_ConnectionMethods") + conn_members = _extract_names_from_c_array(conn_c, "g_ConnectionMembers") + conn_getset = _extract_names_from_c_array(conn_c, "g_ConnectionCalcMembers") + cur_methods = _extract_names_from_c_array(cur_c, "g_CursorMethods") + cur_members = _extract_names_from_c_array(cur_c, "g_CursorMembers") + cur_getset = _extract_names_from_c_array(cur_c, "g_CursorCalcMembers") + mod_methods = _extract_names_from_c_array(mod_c, "g_ModuleMethods") + exceptions = re.findall(r'SetException\(module,\s*&g_\w+,\s*"([^"]+)"', mod_c) + + conn_getset = [n for n in conn_getset if not n.startswith("DSQL_ATTR_")] + + checks = { + "connect keywords": connect_keywords, + "Connection methods": conn_methods, + "Connection members": conn_members, + "Connection get/set attrs": conn_getset, + "Cursor methods": cur_methods, + "Cursor members": cur_members, + "Cursor get/set attrs": cur_getset, + "module methods": mod_methods, + "exceptions": exceptions, + } + errors: list[str] = [] + for section, tokens in checks.items(): + missing = _missing_tokens(api_doc, tokens) + if missing: + errors.append(f"{section}: {missing}") + if errors: + _fail("API docs coverage missing entries:\n" + "\n".join(errors)) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--strict-runtime", action="store_true", help="Fail when runtime dmPython check is unavailable") + parser.add_argument("--print-version", action="store_true", help="Print canonical project version") + args = parser.parse_args() + + version = _extract_pyproject_version() + if args.print_version: + print(version) + return 0 + + _check_setup_uses_pyproject() + header_version = _extract_header_version() + if header_version != version: + _fail(f"Header version mismatch: {header_version} != {version}") + + _check_docs_version(version) + _check_docs_structure() + _check_api_docs_coverage() + _check_smoke_script_dynamic() + _check_runtime_version(version, strict=args.strict_runtime) + + print(f"[OK] version consistency checks passed for {version}") + return 0 + + +if __name__ == "__main__": + try: + raise SystemExit(main()) + except RuntimeError as exc: + print(f"[FAIL] {exc}") + raise SystemExit(2) diff --git a/scripts/check_workflow_yaml.py b/scripts/check_workflow_yaml.py new file mode 100755 index 0000000..46133bc --- /dev/null +++ b/scripts/check_workflow_yaml.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +"""Validate GitHub workflow YAML syntax.""" +from __future__ import annotations + +from pathlib import Path +import sys + +import yaml + + +def main() -> int: + workflow_dir = Path(__file__).resolve().parents[1] / ".github" / "workflows" + files = sorted(workflow_dir.glob("*.yml")) + sorted(workflow_dir.glob("*.yaml")) + if not files: + print("No workflow files found.") + return 1 + + ok = True + for wf in files: + try: + yaml.safe_load(wf.read_text(encoding="utf-8")) + print(f"[OK] {wf}") + except Exception as exc: + ok = False + print(f"[FAIL] {wf}: {exc}") + + return 0 if ok else 2 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/install_docs_workflow.sh b/scripts/install_docs_workflow.sh new file mode 100755 index 0000000..30e4152 --- /dev/null +++ b/scripts/install_docs_workflow.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SRC="$ROOT_DIR/docs/ci/docs-pages.workflow.yml" +DST_DIR="$ROOT_DIR/.github/workflows" +DST="$DST_DIR/docs-pages.yml" + +if [[ ! -f "$SRC" ]]; then + echo "missing template: $SRC" >&2 + exit 1 +fi + +mkdir -p "$DST_DIR" +cp "$SRC" "$DST" + +echo "installed: $DST" + +echo "next:" +echo " git add .github/workflows/docs-pages.yml" +echo " git commit -m 'ci(docs): add pages workflow'" +echo " git push" diff --git a/scripts/release_preflight.sh b/scripts/release_preflight.sh new file mode 100755 index 0000000..bc5f2fd --- /dev/null +++ b/scripts/release_preflight.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT_DIR" + +TAG_NAME="${1:-${TAG_NAME:-}}" +if [[ -n "$TAG_NAME" ]]; then + if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "[FAIL] invalid tag format: $TAG_NAME (expected vX.Y.Z)" + exit 2 + fi +fi + +echo "[INFO] install preflight dependencies" +python3 -m pip install --quiet pyyaml build delocate + +echo "[INFO] workflow YAML syntax" +python3 scripts/check_workflow_yaml.py + +echo "[INFO] version and patch consistency" +python3 scripts/check_version_consistency.py +python3 scripts/check_third_party_patch.py + +EXPECTED_VERSION="$(python3 scripts/check_version_consistency.py --print-version)" +echo "[INFO] expected version: $EXPECTED_VERSION" + +echo "[INFO] clean previous wheel artifacts" +rm -rf dist dist_fixed + +echo "[INFO] build wheel" +python3 -m build --wheel + +mkdir -p dist_fixed +DYLD_LIBRARY_PATH=dpi_bridge delocate-wheel -w dist_fixed dist/*.whl -v + +echo "[INFO] verify wheel import in isolated env" +python3 -m venv /tmp/dmpython_release_preflight_venv +WHEEL_PATHS=("$ROOT_DIR"/dist_fixed/*.whl) +/tmp/dmpython_release_preflight_venv/bin/pip install --quiet "${WHEEL_PATHS[@]}" +ACTUAL_VERSION=$(cd /tmp && /tmp/dmpython_release_preflight_venv/bin/python - <<'PY' +import dmPython +print(dmPython.version) +PY +) +rm -rf /tmp/dmpython_release_preflight_venv + +if [[ "$ACTUAL_VERSION" != "$EXPECTED_VERSION" ]]; then + echo "[FAIL] wheel runtime version mismatch: $ACTUAL_VERSION != $EXPECTED_VERSION" + exit 2 +fi + +echo "[OK] release preflight passed for version $EXPECTED_VERSION" +if [[ -n "$TAG_NAME" ]]; then + echo "[OK] tag format validated: $TAG_NAME" +fi diff --git a/scripts/test_connection.py b/scripts/test_connection.py new file mode 100644 index 0000000..7cc0b5f --- /dev/null +++ b/scripts/test_connection.py @@ -0,0 +1,232 @@ +"""dmPython 连接达梦数据库测试脚本。 + +测试内容: +1. 基本连接 +2. 简单查询 (SELECT 1) +3. DDL — 建表、插入、查询、删除 +4. 参数化查询 +5. 事务回滚 +6. 游标属性 +7. 连接属性 +""" +import sys +import traceback +import os +from pathlib import Path + +import dmPython + +# 连接参数 — docker 容器 dm8_test 映射到宿主机 5237 +CONN_PARAMS = { + "user": os.getenv("DM_TEST_USER", "SYSDBA"), + "password": os.getenv("DM_TEST_PASSWORD", "SYSDBA001"), + "server": os.getenv("DM_TEST_HOST", "localhost"), + "port": int(os.getenv("DM_TEST_PORT", "5237")), +} + +TEST_TABLE = "DMPYTHON_TEST_TBL" +passed = 0 +failed = 0 + + +def run_test(name, func): + global passed, failed + try: + func() + print(f" [PASS] {name}") + passed += 1 + except Exception as e: + print(f" [FAIL] {name}: {e}") + traceback.print_exc() + failed += 1 + + +def _read_project_version() -> str: + pyproject = Path(__file__).resolve().parents[1] / "pyproject.toml" + for line in pyproject.read_text(encoding="utf-8").splitlines(): + stripped = line.strip() + if stripped.startswith("version = "): + value = stripped.split("=", 1)[1].strip() + return value.strip('"') + raise RuntimeError("Cannot read project version from pyproject.toml") + + +def get_expected_version() -> str: + return _read_project_version() + + +def test_version(): + assert hasattr(dmPython, "version"), "缺少 version 属性" + expected = get_expected_version() + assert dmPython.version == expected, f"版本不匹配: got={dmPython.version}, expected={expected}" + + +def test_connect(): + conn = dmPython.connect(**CONN_PARAMS) + assert conn is not None + conn.close() + + +def test_select_one(): + conn = dmPython.connect(**CONN_PARAMS) + cur = conn.cursor() + cur.execute("SELECT 1") + row = cur.fetchone() + assert row == (1,), f"期望 (1,), 实际 {row}" + cur.close() + conn.close() + + +def test_server_info(): + conn = dmPython.connect(**CONN_PARAMS) + cur = conn.cursor() + cur.execute("SELECT * FROM V$VERSION") + rows = cur.fetchall() + assert len(rows) > 0, "V$VERSION 应返回至少一行" + for row in rows: + print(f" {row}") + cur.close() + conn.close() + + +def test_ddl_and_dml(): + conn = dmPython.connect(**CONN_PARAMS) + cur = conn.cursor() + + # 清理 + try: + cur.execute(f"DROP TABLE {TEST_TABLE}") + except Exception: + pass + + # 建表 + cur.execute(f""" + CREATE TABLE {TEST_TABLE} ( + id INT PRIMARY KEY, + name VARCHAR(100), + val DECIMAL(10, 2) + ) + """) + + # 插入 + cur.execute(f"INSERT INTO {TEST_TABLE} VALUES (1, '测试数据', 3.14)") + cur.execute(f"INSERT INTO {TEST_TABLE} VALUES (2, 'dmPython', 2.718)") + conn.commit() + + # 查询 + cur.execute(f"SELECT * FROM {TEST_TABLE} ORDER BY id") + rows = cur.fetchall() + assert len(rows) == 2, f"期望 2 行, 实际 {len(rows)}" + assert rows[0][1] == "测试数据" + assert rows[1][1] == "dmPython" + + # 清理 + cur.execute(f"DROP TABLE {TEST_TABLE}") + conn.commit() + cur.close() + conn.close() + + +def test_parameterized_query(): + conn = dmPython.connect(**CONN_PARAMS) + cur = conn.cursor() + + try: + cur.execute(f"DROP TABLE {TEST_TABLE}") + except Exception: + pass + + cur.execute(f"CREATE TABLE {TEST_TABLE} (id INT, name VARCHAR(100))") + + # 参数化插入 + cur.execute(f"INSERT INTO {TEST_TABLE} VALUES (?, ?)", (1, "参数化测试")) + conn.commit() + + # 参数化查询 + cur.execute(f"SELECT name FROM {TEST_TABLE} WHERE id = ?", (1,)) + row = cur.fetchone() + assert row[0] == "参数化测试", f"期望 '参数化测试', 实际 {row[0]}" + + cur.execute(f"DROP TABLE {TEST_TABLE}") + conn.commit() + cur.close() + conn.close() + + +def test_rollback(): + conn = dmPython.connect(**CONN_PARAMS) + conn.autocommit = False + cur = conn.cursor() + + try: + cur.execute(f"DROP TABLE {TEST_TABLE}") + except Exception: + pass + + cur.execute(f"CREATE TABLE {TEST_TABLE} (id INT)") + conn.commit() + + cur.execute(f"INSERT INTO {TEST_TABLE} VALUES (999)") + conn.rollback() + + cur.execute(f"SELECT COUNT(*) FROM {TEST_TABLE}") + count = cur.fetchone()[0] + assert count == 0, f"回滚后期望 0 行, 实际 {count}" + + cur.execute(f"DROP TABLE {TEST_TABLE}") + conn.commit() + cur.close() + conn.close() + + +def test_cursor_description(): + conn = dmPython.connect(**CONN_PARAMS) + cur = conn.cursor() + cur.execute("SELECT 1 AS col_a, 'hello' AS col_b") + assert cur.description is not None + assert len(cur.description) == 2 + assert cur.description[0][0].upper() == "COL_A" + assert cur.description[1][0].upper() == "COL_B" + cur.close() + conn.close() + + +def test_connection_attributes(): + conn = dmPython.connect(**CONN_PARAMS) + # 检查 autocommit 属性 + original = conn.autocommit + conn.autocommit = True + assert conn.autocommit == True + conn.autocommit = original + conn.close() + + +def main(): + print(f"dmPython version: {dmPython.version}") + print(f"Python: {sys.executable}") + print(f"连接: {CONN_PARAMS['server']}:{CONN_PARAMS['port']}") + print() + + tests = [ + ("模块版本检查", test_version), + ("基本连接", test_connect), + ("SELECT 1", test_select_one), + ("服务器版本信息", test_server_info), + ("建表/插入/查询/删表", test_ddl_and_dml), + ("参数化查询", test_parameterized_query), + ("事务回滚", test_rollback), + ("游标 description", test_cursor_description), + ("连接属性", test_connection_attributes), + ] + + print(f"运行 {len(tests)} 个测试:") + for name, func in tests: + run_test(name, func) + + print() + print(f"结果: {passed} 通过, {failed} 失败") + return 0 if failed == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/setup.py b/setup.py index 768e956..a5393d0 100644 --- a/setup.py +++ b/setup.py @@ -1,336 +1,195 @@ -"""Distutils script for dmPython. +"""Setup script for dmPython-macOS. - python setup.py build install +Builds the dmPython C extension with the Go-based DPI bridge library, +producing a self-contained wheel that requires no DM_HOME or Go toolchain. + python -m build --wheel + # or + python setup.py build_ext --inplace """ -import sys -if sys.version_info[:2] < (3, 12): - import distutils.command - try: - import distutils.command.bdist_msi - except ImportError: - distutils.command.bdist_msi = None - try: - import distutils.command.bdist_wininst - except ImportError: - distutils.command.bdist_wininst = None - import distutils.command.bdist_rpm - import distutils.command.build - import distutils.core - import distutils.dist - import distutils.util import os import re import struct +import subprocess +import sys -if sys.version_info[:2] < (3, 12): - from distutils.errors import DistutilsSetupError as SetupError -else: - from setuptools.errors import SetupError - -# if setuptools is detected, use it to add support for eggs -if sys.version_info[:2] < (3, 12): - try: - from setuptools import setup, Extension - except: - from distutils.core import setup - from distutils.extension import Extension -else: - from setuptools import setup, Extension - -# define build constants -BUILD_VERSION = "2.5.30" -dm_version = os.environ.get("DM_VER") - -if dm_version is not None: - DAMENG_VERSION = dm_version -else: - DAMENG_VERSION = "8.1" - -# method for checking a potential Dameng home -def CheckDmHome(directoryToCheck): - global dmHome, dmLibDir - - - if sys.platform in ("win32", "cygwin"): - if sys.version_info[:2] > (3, 7): - str_pthtemp=sys.executable[0:len(sys.executable)-len(sys.executable.split('\\')[-1])]+'Lib\\site-packages\\dmPython.pth' - file=open(str_pthtemp,'w') - write_pthstr='import dpi' - file.write(write_pthstr) - file.close() - if struct.calcsize("P") == 4: - subDirs = ["bin", "debug", "release", "dpi"] - else: - subDirs = ["bin", "x64/debug", "x64/release", "dpi"] - filesToCheck = ["dmdpi.dll"] - elif sys.platform == "darwin": - subDirs = ["bin"] - filesToCheck = ["libdmdpi"] - else: - subDirs = ["bin", "build/linux/linux_build/debug", "build/linux/linux_build/release", "dpi"] - filesToCheck = ["libdmdpi.so"] - - for baseFileName in filesToCheck: - fileName = os.path.join(directoryToCheck, baseFileName) - if os.path.exists(fileName): - if os.path.basename(directoryToCheck).lower() == "bin": - dmHome = os.path.dirname(directoryToCheck) - else: - dmHome = directoryToCheck - dmLibDir = directoryToCheck - if sys.platform in ("win32", "cygwin"): - if sys.version_info[:2] > (3, 7): - str_pytemp=sys.executable[0:len(sys.executable)-len(sys.executable.split('\\')[-1])]+'Lib\\site-packages\\dpi.py' - file=open(str_pytemp,'w') - write_pystr='import os\nos.add_dll_directory(r\'' + dmLibDir + '\')' - file.write(write_pystr) - file.close() - return True - - for subDir in subDirs: - fileName = os.path.join(directoryToCheck, subDir, baseFileName) - if os.path.exists(fileName): - dmHome = directoryToCheck - dmLibDir = os.path.join(directoryToCheck, subDir) - if sys.platform in ("win32", "cygwin"): - if sys.version_info[:2] > (3, 7): - str_pytemp=sys.executable[0:len(sys.executable)-len(sys.executable.split('\\')[-1])]+'Lib\\site-packages\\dpi.py' - file=open(str_pytemp,'w') - write_pystr='import os\nos.add_dll_directory(r\'' + dmLibDir + '\')' - file.write(write_pystr) - file.close() - return True - - for subDir in subDirs: - dirName = os.path.dirname(directoryToCheck) - fileName = os.path.join(dirName, subDir, baseFileName) - if os.path.exists(fileName): - dmHome = dirName - dmLibDir = os.path.join(dirName, subDir) - if sys.platform in ("win32", "cygwin"): - if sys.version_info[:2] > (3, 7): - str_pytemp=sys.executable[0:len(sys.executable)-len(sys.executable.split('\\')[-1])]+'Lib\\site-packages\\dpi.py' - file=open(str_pytemp,'w') - write_pystr='import os\nos.add_dll_directory(r\'' + dmLibDir + '\')' - file.write(write_pystr) - file.close() - return True - - dmHome = dmLibDir = None - return False - -# try to determine the Dameng home -userDmHome = os.environ.get("DM_HOME") -if userDmHome is not None: - if not CheckDmHome(userDmHome): - messageFormat = "Dameng home (%s) does not refer to an " \ - "DM%s installation or dmdpi library missing." - raise SetupError(messageFormat % (userDmHome,DAMENG_VERSION)) -else: - for path in os.environ["PATH"].split(os.pathsep): - if CheckDmHome(path): - break - if dmHome is None: - raise SetupError("cannot locate an Dameng software " \ - "installation") - -# define some variables -if sys.platform == "win32": - libDirs = [dmLibDir, os.path.join(dmHome, "include")] - - possibleIncludeDirs = ["python/dmPython_C/dmPython", "include", "dpi/src/include", "drivers/python/dmPython", "dpi/include"] - includeDirs = [] - for dir1 in possibleIncludeDirs: - path = os.path.normpath(os.path.join(dmHome, dir1)) - if os.path.isdir(path): - includeDirs.append(path) - - if not includeDirs: - message = "cannot locate Dameng include files in %s" % dmHome - raise SetupError(message) - libs = ["dmdpi"] -else: - libDirs = [dmLibDir] - libs = ["dmdpi"] - possibleIncludeDirs = ["python/dmPython_C/dmPython", "include", "dpi/src/include", "drivers/python/dmPython", "dpi/include"] - includeDirs = [] - for dir in possibleIncludeDirs: - path = os.path.join(dmHome, dir) - if os.path.isdir(path): - includeDirs.append(path) - if not includeDirs: - raise SetupError("cannot locate Dameng include files") - -# setup extra link and compile args -extraCompileArgs = ["-DBUILD_VERSION=%s" % BUILD_VERSION] -extraLinkArgs = [] - -# extension Macros definition if on 64bit platform,add DM64,othersise use default [defineMacros]. -defineMacros = [] -if struct.calcsize("P") == 4: - defineMacros = [] -else: - defineMacros = [('DM64', None),] +from setuptools import Extension, setup +from setuptools.command.build_ext import build_ext as _build_ext + +# Directories +HERE = os.path.dirname(os.path.abspath(__file__)) +DPI_BRIDGE_DIR = os.path.join(HERE, "dpi_bridge") +NATIVE_SRC_DIR = os.path.join("src", "native") +DPI_INCLUDE_PLACEHOLDER = "__DM_DPI_INCLUDE_PLACEHOLDER__" + + +def read_project_version() -> str: + """Read the canonical package version from pyproject.toml.""" + pyproject_path = os.path.join(HERE, "pyproject.toml") + text = open(pyproject_path, encoding="utf-8").read() + match = re.search(r'^\s*version\s*=\s*"([^"]+)"\s*$', text, re.MULTILINE) + if not match: + raise RuntimeError("Cannot determine project version from pyproject.toml") + return match.group(1) + + +BUILD_VERSION = read_project_version() + +# All C source files +C_SOURCE_FILES = [ + "py_Dameng.c", + "row.c", + "Cursor.c", + "Connection.c", + "Environment.c", + "Error.c", + "Buffer.c", + "exLob.c", + "exObject.c", + "tObject.c", + "var.c", + "vCursor.c", + "vDateTime.c", + "vInterval.c", + "vLob.c", + "vNumber.c", + "vObject.c", + "vString.c", + "vlong.c", + "exBfile.c", + "vBfile.c", + "trc.c", +] +C_SOURCES = [os.path.join(NATIVE_SRC_DIR, f) for f in C_SOURCE_FILES] + + +def find_dpi_include(): + """按优先级查找 DPI 头文件目录。""" + candidates = [ + os.path.join(HERE, "dpi_include"), + ] + dm_home = os.environ.get("DM_HOME") + if dm_home: + candidates.append(os.path.join(dm_home, "include")) + candidates.append(os.path.join(dm_home, "dpi", "include")) + for d in candidates: + if os.path.isfile(os.path.join(d, "DPI.h")): + return d + raise RuntimeError( + "Cannot find DPI header files (DPI.h). Options:\n" + " 1. Place headers in ./dpi_include/\n" + " 2. Set DM_HOME to your Dameng installation directory\n" + "See README.md for details." + ) + +# Macros +define_macros = [] +if struct.calcsize("P") == 8: + define_macros.append(("DM64", None)) if sys.platform == "win32": - defineMacros.append(('WIN32', None)) - defineMacros.append(('_CRT_SECURE_NO_WARNINGS', None)) - -#extension Macro TRACE if a dmPython_trace.log needed in current directory. -#defineMacros.append(('TRACE', None)) -if sys.version_info[:2] < (3, 12): - # tweak distribution full name to include the Dameng version - class Distribution(distutils.dist.Distribution): - - def get_fullname_with_dameng_version(self): - name = self.metadata.get_fullname() - return "%s-%s" % (name, DAMENG_VERSION) - -if sys.version_info[:2] < (3, 12): - # tweak the RPM build command to include the Python and Dameng version - class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm): - - def run(self): - distutils.command.bdist_rpm.bdist_rpm.run(self) - specFile = os.path.join(self.rpm_base, "SPECS", - "%s.spec" % self.distribution.get_name()) - queryFormat = "%{name}-%{version}-%{release}.%{arch}.rpm" - command = "rpm -q --qf '%s' --specfile %s" % (queryFormat, specFile) - origFileName = os.popen(command).read() - names = origFileName.split("rpm") - for origFileName in names: - if len(origFileName) > 0: - origFileName += "rpm" - parts = origFileName.split("-") - parts.insert(2, DAMENG_VERSION) - parts.insert(3, "py%s%s" % sys.version_info[:2]) - newFileName = "-".join(parts) - self.move_file(os.path.join("dist", origFileName), os.path.join("dist", newFileName)) - -if sys.version_info[:2] < (3, 12): - # tweak the build directories to include the Dameng version - class build(distutils.command.build.build): - - def finalize_options(self): - import distutils.util - import os - import sys - platSpecifier = ".%s-%s" % \ - (distutils.util.get_platform(), sys.version[0:3]) - if self.build_platlib is None: - self.build_platlib = os.path.join(self.build_base, - "lib%s" % platSpecifier) - if self.build_temp is None: - self.build_temp = os.path.join(self.build_base, - "temp%s" % platSpecifier) - distutils.command.build.build.finalize_options(self) - - class test(distutils.core.Command): - description = "run the test suite for the extension" - user_options = [] - - def finalize_options(self): - pass - - def initialize_options(self): - pass - - def run(self): - self.run_command("build") - buildCommand = self.distribution.get_command_obj("build") - sys.path.insert(0, os.path.abspath("test")) - sys.path.insert(0, os.path.abspath(buildCommand.build_lib)) - if sys.version_info[0] < 3: - execfile(os.path.join("test", "test.py")) - else: - fileName = os.path.join("test", "test3k.py") - exec(open(fileName).read()) - - commandClasses = dict(build = build, bdist_rpm = bdist_rpm, test = test) - - # tweak the Windows installer names to include the Dameng version - if distutils.command.bdist_msi is not None: - - class bdist_msi(distutils.command.bdist_msi.bdist_msi): - - def run(self): - origMethod = self.distribution.get_fullname - self.distribution.get_fullname = \ - self.distribution.get_fullname_with_dameng_version - distutils.command.bdist_msi.bdist_msi.run(self) - self.distribution.get_fullname = origMethod - - commandClasses["bdist_msi"] = bdist_msi - - if distutils.command.bdist_wininst is not None: - - class bdist_wininst(distutils.command.bdist_wininst.bdist_wininst): + define_macros.append(("WIN32", None)) + define_macros.append(("_CRT_SECURE_NO_WARNINGS", None)) +# Keep C extension runtime version aligned with project metadata. +define_macros.append(("BUILD_VERSION_STRING", f'"{BUILD_VERSION}"')) +# Uncomment for debug tracing: +# define_macros.append(("TRACE", None)) + + +class build_ext(_build_ext): + """Custom build_ext that builds the Go bridge library before compiling.""" + + def run(self): + dpi_include_dir = find_dpi_include() + for ext in self.extensions: + ext.include_dirs = [ + dpi_include_dir if d == DPI_INCLUDE_PLACEHOLDER else d + for d in ext.include_dirs + ] + if not os.environ.get("DMPYTHON_SKIP_GO_BUILD"): + self._build_go_bridge() + super().run() + + def _build_go_bridge(self): + dylib_path = os.path.join(DPI_BRIDGE_DIR, "libdmdpi.dylib") + + # Check if Go is available + try: + subprocess.check_output(["go", "version"], stderr=subprocess.STDOUT) + except (FileNotFoundError, subprocess.CalledProcessError): + if os.path.exists(dylib_path): + print("Go not found, using pre-built libdmdpi.dylib") + return + raise RuntimeError( + "Go toolchain is required to build the DPI bridge library. " + "Install Go from https://go.dev/dl/ or set DMPYTHON_SKIP_GO_BUILD=1 " + "if you have a pre-built libdmdpi.dylib in dpi_bridge/" + ) + + print("Building Go DPI bridge library...") + subprocess.check_call( + [ + "go", "build", + "-buildmode=c-shared", + "-o", "libdmdpi.dylib", + ".", + ], + cwd=DPI_BRIDGE_DIR, + ) - def run(self): - origMethod = self.distribution.get_fullname - self.distribution.get_fullname = \ - self.distribution.get_fullname_with_dameng_version - distutils.command.bdist_wininst.bdist_wininst.run(self) - self.distribution.get_fullname = origMethod + # Set install_name so delocate and @rpath work correctly + subprocess.check_call( + [ + "install_name_tool", + "-id", "@rpath/libdmdpi.dylib", + dylib_path, + ] + ) + print("Go DPI bridge library built successfully.") - commandClasses["bdist_wininst"] = bdist_wininst -# define classifiers for the package index -classifiers = [ - "Development Status :: 1 - Mature", +extension = Extension( + name="dmPython", + sources=C_SOURCES, + include_dirs=[DPI_INCLUDE_PLACEHOLDER, os.path.join(HERE, NATIVE_SRC_DIR)], + library_dirs=[DPI_BRIDGE_DIR], + libraries=["dmdpi"], + define_macros=define_macros, + extra_link_args=["-Wl,-rpath,@loader_path"], +) + +setup( + name="dmPython-macOS", + version=BUILD_VERSION, + description="Python DB-API 2.0 driver for DM (Dameng) database — macOS edition with built-in Go bridge", + long_description=open(os.path.join(HERE, "README.md"), encoding="utf-8").read() + if os.path.exists(os.path.join(HERE, "README.md")) + else "", + long_description_content_type="text/markdown", + author="Dameng / skhe", + url="https://github.com/skhe/dmPython", + project_urls={ + "Bug Tracker": "https://github.com/skhe/dmPython/issues", + "Changelog": "https://github.com/skhe/dmPython/blob/main/CHANGELOG.md", + "Upstream (Official)": "https://github.com/DamengDB/dmPython", + }, + ext_modules=[extension], + cmdclass={"build_ext": build_ext}, + keywords="Dameng DM8 database DB-API", + license="MulanPSL-2.0", + python_requires=">=3.8", + classifiers=[ + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", - "License :: DPI Approved :: Python Software Foundation License", "Natural Language :: English", - "Operating System :: OS Independent", + "Operating System :: MacOS :: MacOS X", "Programming Language :: C", - "Programming Language :: Python", - "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", - "Topic :: Database" -] - -# setup the extension -extension = Extension( - name = "dmPython", - include_dirs = includeDirs, - libraries = libs, - library_dirs = libDirs, - extra_compile_args = extraCompileArgs, - extra_link_args = extraLinkArgs, - sources = ['py_Dameng.c','row.c','Cursor.c','Connection.c','Environment.c','Error.c','Buffer.c', - 'exLob.c','exObject.c','tObject.c', 'var.c','vCursor.c','vDateTime.c','vInterval.c','vLob.c','vNumber.c', - 'vObject.c', 'vString.c', 'vlong.c', 'exBfile.c', 'vBfile.c','trc.c'], - depends = [], - define_macros = defineMacros - ) -if sys.version_info[:2] < (3, 12): - # perform the setup - setup( - name = "dmPython", - version = BUILD_VERSION, - distclass = Distribution, - description = "Python interface to Dameng", - cmdclass = commandClasses, - long_description = \ - "Python interface to Dameng conforming to the Python DB API 2.0 " - "specification.\n" - "See http://www.python.org/topics/database/DatabaseAPI-2.0.html.", - ext_modules = [extension], - keywords = "Dameng", - license = "Python Software Foundation License", - classifiers = classifiers) -else: - setup( - name = "dmPython", - version = BUILD_VERSION, - description = "Python interface to Dameng", - long_description = \ - "Python interface to Dameng conforming to the Python DB API 2.0 " - "specification.\n" - "See http://www.python.org/topics/database/DatabaseAPI-2.0.html.", - ext_modules = [extension], - keywords = "Dameng", - license = "Python Software Foundation License", - classifiers = classifiers) - - + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Topic :: Database", + "Topic :: Database :: Front-Ends", + ], +) diff --git a/Buffer.c b/src/native/Buffer.c similarity index 100% rename from Buffer.c rename to src/native/Buffer.c diff --git a/Buffer.h b/src/native/Buffer.h similarity index 100% rename from Buffer.h rename to src/native/Buffer.h diff --git a/Connection.c b/src/native/Connection.c similarity index 100% rename from Connection.c rename to src/native/Connection.c diff --git a/Cursor.c b/src/native/Cursor.c similarity index 87% rename from Cursor.c rename to src/native/Cursor.c index 298e260..6b9ec50 100644 --- a/Cursor.c +++ b/src/native/Cursor.c @@ -12,7 +12,9 @@ #include -static +sdint4 Cursor_escape_quotes(char* dst, int dst_len, char* src, int src_len); + +static PyObject* Cursor_GetDescription( dm_Cursor *self, @@ -54,7 +56,7 @@ Cursor_SetRowCount( /************************************************************************ purpose: - ִid + �������ִ��id ************************************************************************/ static sdint2 @@ -167,9 +169,9 @@ Cursor_AllocHandle( /* purpose: set default schema /************************************************************************/ -sdint2 /* ش */ +sdint2 /* ���ش����� */ Cursor_SetSchema_And_Parsetype( - dm_Cursor* self /* IN:cursor */ + dm_Cursor* self /* IN:cursor���� */ ) { DPIRETURN rt = DSQL_SUCCESS; @@ -254,7 +256,7 @@ Cursor_New( Py_INCREF(connection->environment); self->environment = connection->environment; - // + // ��������� if (Cursor_AllocHandle(self) < 0) { Cursor_free_inner(self); @@ -263,7 +265,7 @@ Cursor_New( return NULL; } - //ģʽ + //����ģʽ if (Cursor_SetSchema_And_Parsetype(self)) { Cursor_free_inner(self); @@ -289,7 +291,7 @@ Cursor_New( self->colCount = 0; self->rowNum = 0; - //Cursor_Newãcloseȡrowcountֵ + //��Cursor_New�����ã�����close��ȡ����rowcountֵ self->totalRows = -1; self->is_iter = 0; @@ -438,7 +440,7 @@ Cursor_Close_inner( dm_Cursor* self ) { - /** ʾùCursor_Close򷵻 **/ + /** ����ʾ���ù�Cursor_Close���򷵻� **/ if (Cursor_IsOpen(self) < 0) { PyErr_Clear(); @@ -446,7 +448,7 @@ Cursor_Close_inner( Py_RETURN_NONE; } - /** δϿִоԴͷ **/ + /** ������δ�Ͽ�����ִ�о����Դ�ͷ� **/ if (self->connection->isConnected == 1) { Cursor_InternalClose(self); @@ -454,7 +456,7 @@ Cursor_Close_inner( Cursor_FreeHandle(self, 0); } - /** ͷCursorڲԴ **/ + /** �ͷ�Cursor�ڲ�������Դ **/ Cursor_free_inner(self); Cursor_init_inner(self); @@ -552,7 +554,7 @@ Cursor_GetStatementType( } self->statementType = statementType; - //bug633895 ΪտӹرպִУѱٵobjظͷţǰͷõvobject + //bug633895 ��Ϊ�������տ��������ӹرպ�ִ�У������ѱ����ٵ�obj���ظ��ͷţ�������ǰ�ͷ����õ�vobject�� if (self->col_variables == NULL) cols = 0; else @@ -570,7 +572,7 @@ Cursor_GetStatementType( return 0; } -/* жǷִйprepareȡִ */ +/* �ж��Ƿ�ִ�й�prepare������ȡִ����� */ static sdint2 Cursor_hasPrepared( @@ -580,7 +582,7 @@ Cursor_hasPrepared( int direct_flag ) { - /* ûִ䣬Ҳûִйprepare */ + /* û��ִ����䣬Ҳû��ִ�й�prepare */ if ((*statement == Py_None) && (self->statement == NULL || self->statement == Py_None)) { @@ -590,7 +592,7 @@ Cursor_hasPrepared( return -1; } - /* ڷDDL䣬Ҫٴprepare, executedirectִprepareҪȡϴִ */ + /* ���ڷ�DDL��䣬����Ҫ�ٴ�prepare, executedirect����ִ��prepare����Ҫ������ȡ�ϴ�ִ����� */ if (*statement == Py_None || *statement == self->statement) { if(!direct_flag && Cursor_IsDDL (self->statementType) < 0) @@ -606,7 +608,7 @@ Cursor_hasPrepared( return -1; } - /* 䳤Ϊ0 */ + /* ��䳤��Ϊ0 */ if (strlen((char*)buffer->ptr) == 0) { PyErr_SetString(g_ProgrammingErrorException, @@ -627,19 +629,19 @@ Cursor_clearDescExecInfo( int clear_param ) { - /* رα */ + /* �ر��α� */ Cursor_InternalClose(self); - /* Ϣ */ + /* ��������������Ϣ */ if (clear_param) { Cursor_free_paramdesc(self); } - /* Ϣ */ + /* ������������Ϣ */ Cursor_free_coldesc(self); - /** ϴִн **/ + /** ����ϴ�ִ�н�� **/ Cursor_ExecRs_Clear(self); } @@ -658,17 +660,17 @@ Cursor_InternalPrepare( DPIRETURN status = DSQL_SUCCESS; sdint2 ret; - /* жѾִprepareֱӷ */ + /* �ж�����Ѿ�ִ��prepare����ֱ�ӷ��� */ ret = Cursor_hasPrepared(self, &statement, &statementBuffer, 0); if (ret != 0) return ret; - /* ϴεִϢ */ + /* �����ϴε�������ִ����Ϣ */ Cursor_clearDescExecInfo(self, 1); // prepare statement Py_BEGIN_ALLOW_THREADS - //prepare֮ǰһΰ󶨲Ϣ + //prepare֮ǰ�����һ�ΰ󶨲�����Ϣ status = dpi_unbind_params(self->handle); status = dpi_prepare(self->handle, (sdbyte*)statementBuffer.ptr); Py_END_ALLOW_THREADS @@ -692,7 +694,7 @@ Cursor_InternalPrepare( self->rowFactory = NULL; - /* ȡϢcursor.prepareexecuteеprepareҪȡϢ */ + /* ��ȡ��������������Ϣ��cursor.prepare��execute�е�prepare����Ҫ��ȡ������Ϣ */ if (Cursor_GetParamDescFromDm(self) < 0) return -1; @@ -712,11 +714,11 @@ Cursor_InternalExecDirect( dm_Buffer statementBuffer; DPIRETURN status = DSQL_SUCCESS; - /* dpi_exec_directҪִprepareô˽ӿڻȡִ */ + /* dpi_exec_direct����Ҫִ��prepare�����ô˽ӿ����ڻ�ȡִ����� */ if (Cursor_hasPrepared(self, &statement, &statementBuffer, 1) < 0) return -1; - /* ϴεִϢ */ + /* �����ϴε�������ִ����Ϣ */ Cursor_clearDescExecInfo(self, 1); // prepare statement @@ -747,11 +749,11 @@ Cursor_InternalExecDirect( if (Cursor_GetStatementType(self) < 0) return -1; - /* ȡִнϢ */ + /* ��ȡִ�н����Ϣ */ if (Cursor_SetRowCount(self) < 0) return -1; - /* execid */ + /* ����execid */ if (Cursor_SetExecId(self)) { return -1; @@ -765,7 +767,7 @@ Cursor_InternalExecDirect( //----------------------------------------------------------------------------- // Cursor_ExecRs_Clear() -// ϴִнӰ +// ����ϴ�ִ�н��Ӱ�� //----------------------------------------------------------------------------- static void @@ -773,7 +775,7 @@ Cursor_ExecRs_Clear( dm_Cursor* self // cursor to set the rowcount on ) { - // ϴִеĽ¼ + // ����ϴ�ִ�еĽ����������¼ if (self->description != Py_None) { Py_CLEAR(self->description); @@ -827,7 +829,7 @@ Cursor_SetRowCount( if (self->statementType == DSQL_DIAG_FUNC_CODE_SELECT|| self->statementType == DSQL_DIAG_FUNC_CODE_CALL) { self->rowCount = 0; - // ¼һfetchȡʣ + // ��¼һ��fetch������ȡ�������ʣ������ self->actualRows = -1; Py_BEGIN_ALLOW_THREADS @@ -842,7 +844,7 @@ Cursor_SetRowCount( self->totalRows = (slength)rowCount; - /** Ƿڽʶ **/ + /** ���Ƿ���ڽ������ʶ **/ if (self->totalRows > 0) { self->with_rows = 1; @@ -866,7 +868,7 @@ Cursor_SetRowCount( self->totalRows = -1; } - /** ׷ӻȡlastrowid **/ + /** ׷�ӻ�ȡlastrowid **/ Py_DECREF(self->lastrowid_obj); if (self->statementType == DSQL_DIAG_FUNC_CODE_INSERT || self->statementType == DSQL_DIAG_FUNC_CODE_UPDATE || @@ -906,7 +908,7 @@ Cursor_SetRowCount( /************************************************************************ purpose: - ִid + �������ִ��id ************************************************************************/ static sdint2 @@ -917,7 +919,7 @@ Cursor_SetExecId( DPIRETURN status = DSQL_SUCCESS; udint4 execid; - /** ȡexecid **/ + /** ��ȡexecid **/ Py_DECREF(self->execid_obj); Py_BEGIN_ALLOW_THREADS @@ -968,7 +970,7 @@ Cursor_PutDataVariable( int rt = 0; Py_ssize_t i; - /* dpi_param_dataãָijҪput_dataУвput꣬ٵһΣ֪ͨ */ + /* dpi_param_data�������ã�ָ��ij��Ҫput_data���У����в���put�꣬�ٵ���һ�Σ�֪ͨ������� */ for (i = 0; i < rowsize; i ++) { rt = Cursor_PutDatadmVar_onerow(self, i); @@ -981,11 +983,11 @@ Cursor_PutDataVariable( Py_BEGIN_ALLOW_THREADS rt = dpi_param_data(self->handle, NULL); Py_END_ALLOW_THREADS - /* Ϊ0ֱӷأ˵Ҫֵ */ + /* ��Ϊ0����ֱ�ӷ��أ�˵������Ҫ��ֵ */ if (rt == DSQL_SUCCESS || rt == DSQL_PARAM_DATA_AVAILABLE) return rt; - /* ʧܣDSQL_NEED_DATA򱨴 */ + /* ����ʧ�ܣ�������DSQL_NEED_DATA���򱨴� */ if (Environment_CheckForError(self->environment, self->handle, DSQL_HANDLE_STMT, rt, "vLong_PutData():dpi_param_data") < 0) { @@ -1024,7 +1026,7 @@ Cursor_InternalExecute( status = dpi_exec(self->handle); Py_END_ALLOW_THREADS - /* NEED_DATAlong string/binary򲹳 */ + /* ��NEED_DATA����long string/binary�����򲹳����� */ if (status == DSQL_NEED_DATA) { status = Cursor_PutDataVariable(self, rowsize); @@ -1045,7 +1047,7 @@ Cursor_InternalExecute( } } - //ֵΪDSQL_PARAM_DATA_AVAILABLEʽȡ + //�������ֵΪDSQL_PARAM_DATA_AVAILABLE������ʽ��ȡ������� if (self->output_stream == 1 && status == DSQL_PARAM_DATA_AVAILABLE) { self->param_value =(PyObject**) PyMem_Malloc((self->outparam_num)*sizeof(PyObject*)); @@ -1163,7 +1165,7 @@ Cursor_InternalExecute( ret = Cursor_SetRowCount(self); - //ڰ󶨲unbind param + //���ڰ󶨲�������unbind param if (self->paramCount > 0) { Py_BEGIN_ALLOW_THREADS @@ -1226,7 +1228,7 @@ Cursor_GetColDescFromDm( DPIRETURN rt = DSQL_SUCCESS; sdint4 val_len; - /* */ + /* ������������� */ Py_BEGIN_ALLOW_THREADS rt = dpi_get_stmt_attr(self->handle, DSQL_ATTR_IMP_ROW_DESC, (dpointer)&self->hdesc_col, 0, &val_len); Py_END_ALLOW_THREADS @@ -1265,7 +1267,7 @@ Cursor_SetColVariables( return -1; } -//bug653857 nls_numeric_charactersdmPythonӿҪ֧ +//bug653857 ����nls_numeric_characters��dmPython�ӿ���Ҫ����֧�� #ifdef DSQL_ATTR_NLS_NUMERIC_CHARACTERS rt = dpi_get_con_attr(self->connection->hcon, DSQL_ATTR_NLS_NUMERIC_CHARACTERS, attr, 10, NULL); if (!DSQL_SUCCEEDED(rt) || strcmp(attr, ".,") == 0) @@ -1318,7 +1320,7 @@ Cursor_PerformDefine( return -1; } - /* Ϊ0 ֱӷ */ + /* ������Ϊ0�� ��ֱ�ӷ��� */ if (self->colCount == 0) { return 0; @@ -1329,15 +1331,15 @@ Cursor_PerformDefine( *isQuery = 1; } - /** ȡϢ **/ + /** ��ȡ����������Ϣ **/ if (Cursor_GetColDescFromDm(self) < 0) return -1; - /** а **/ + /** �����а� **/ if (Cursor_SetColVariables(self) < 0) return -1; - /** ȡϢ **/ + /** ��ȡ������Ϣ **/ desc = Cursor_GetDescription(self, NULL); if (desc == NULL) return -1; @@ -1388,7 +1390,7 @@ Cursor_GetParamDescFromDm_low( if(self->bindParamDesc[iparam].param_type == DSQL_PARAM_OUTPUT && self->bindParamDesc[iparam].sql_type != DSQL_RSET) self->outparam_num += 1; - /* ȡDSQL_DESC_NAME */ + /* ��ȡ��������DSQL_DESC_NAME */ rt = dpi_get_desc_field(self->hdesc_param, iparam + 1, DSQL_DESC_NAME, (dpointer)self->bindParamDesc[iparam].name, 128, &self->bindParamDesc[iparam].namelen); @@ -1423,7 +1425,7 @@ Cursor_GetParamDescFromDm( return 0; } - /** **/ + /** �������������� **/ Py_BEGIN_ALLOW_THREADS rt = dpi_get_stmt_attr(self->handle, DSQL_ATTR_IMP_PARAM_DESC, &self->hdesc_param, 0, &val_len); Py_END_ALLOW_THREADS @@ -1459,8 +1461,8 @@ Cursor_setParamVariablesHelper( dm_Cursor* self, PyObject* iValue, unsigned numElements, - unsigned irow, /* 󶨲кţ0-based */ - unsigned ipos, /* 󶨲ıţ1-based */ + unsigned irow, /* �󶨲������кţ�0-based */ + unsigned ipos, /* �󶨲����ı�ţ�1-based */ dm_Var* org_var, dm_Var** new_var ) @@ -1471,13 +1473,13 @@ Cursor_setParamVariablesHelper( *new_var = NULL; is_udt = dmVar_Check(iValue); - /** ѾڣΪNone滻ΪµıͣͲһ򱨴 **/ + /** �Ѿ����ڣ���ΪNone�����滻Ϊ�µı������ͣ������������Ͳ�һ�����򱨴� **/ if (org_var != NULL) { - /** Զͣ滻;򣬽ֵ뵽org_var **/ + /** �Զ������ͣ��滻;���򣬽���ֵ���뵽org_var�� **/ if (is_udt == 1) { - /** ͬһ滻 **/ + /** ����ͬһ�����������滻������ **/ if ((PyObject*)org_var != iValue) { Py_INCREF(iValue); @@ -1510,10 +1512,10 @@ Cursor_setParamVariablesHelper( } } - /** ԭޱ¶ **/ + /** ��ԭ���ޱ����������¶��� **/ if (org_var == NULL) { - /** ΪԶֱͣת;򣬸Pythonݴudt**/ + /** ��Ϊ�Զ������ͣ���ֱ��ת��;���򣬸���Python���ݴ���udt����**/ if (is_udt) { Py_INCREF(iValue); @@ -1537,7 +1539,7 @@ Cursor_setParamVariablesHelper( return 0; } -/** ݰ󶨲ƴdictҵĿֵ **/ +/** ���ݰ󶨲������ƴ�dict���ҵ�Ŀ�����ֵ **/ static PyObject* Cursor_getParamValue_FromDict( @@ -1587,7 +1589,7 @@ Cursor_getParamValue_FromDict( return iValue; } -/** òְ֧λð **/ +/** ���ò�����������֧�ְ�λ�ð� **/ static sdint2 Cursor_setParamVariables_oneRow( @@ -1604,15 +1606,15 @@ Cursor_setParamVariables_oneRow( PyObject* iValue; PyObject* dictKeys = NULL; dm_Var* new_var = NULL; - dm_VarType* new_varType = NULL; // - dm_VarType* tmp_varType = NULL; //ʱ + dm_VarType* new_varType = NULL; //�������� + dm_VarType* tmp_varType = NULL; //��ʱ���� udint4 size; int is_udt; sdint2 param_type; - DmParamDesc* bindParamDesc; // 󶨲Ϣ - int dec_flag = 0; // ǷҪiValueüı־ + DmParamDesc* bindParamDesc; // �󶨲�����Ϣ + int dec_flag = 0; // �Ƿ���Ҫ����iValue���ü����ı�־ - /** У򱨴 **/ + /** �������������У��򱨴� **/ if (parameters != NULL && parameters != Py_None) { if (PySequence_Check(parameters)) @@ -1635,7 +1637,7 @@ Cursor_setParamVariables_oneRow( } } - /* ˴param_variablesвһȣбмֵ */ + /* �˴�param_variables����������в�������һ����ȣ����б��м���ֵ */ for (iparam = 0; iparam < self->paramCount; iparam ++) { if(dec_flag) @@ -1666,26 +1668,26 @@ Cursor_setParamVariables_oneRow( } } - /* ΪPy_Noneһ */ + /* ��ΪPy_None������һ�� */ if (iValue == Py_None) { continue; } - /* ǷΪûԶ */ + /* �����Ƿ�Ϊ�û��Զ��� */ is_udt = dmVar_Check(iValue); - /* prepareʱѾ׼ÿյparam_variablesŵδֵĶ */ + /* prepareʱ�Ѿ�׼���ÿյ�param_variables�������ŵ���δ��ֵ�Ķ��� */ new_var = (dm_Var*)PyList_GET_ITEM(self->param_variables, iparam); - /* ǰеһγַNoneİ󶨲ֵ±뵽List */ + /* ��ǰ�����е�һ�γ��ַ�None�İ󶨲���ֵ�������±���������뵽List�� */ if (new_var == NULL) { new_varType = dmVar_TypeByValue(iValue, &size); if (new_varType == NULL) goto fun_end; - /* ΪͣҲΪLongStringLongBinaryת */ + /* ��Ϊ�������������������������ͣ��Ҳ�����������ΪLongString����LongBinary�������ת�� */ if (param_type == DSQL_PARAM_INPUT_OUTPUT || param_type == DSQL_PARAM_OUTPUT || param_type == DSQL_PARAM_INPUT) @@ -1696,7 +1698,7 @@ Cursor_setParamVariables_oneRow( goto fun_end; } - //sql_typeǷƼͣvarcharbytesbinary + //sql_type�Ƿ������Ƽ����ͣ������varchar������������bytes�����������binary if (bindParamDesc->sql_type == DSQL_VARCHAR && new_varType == &vt_Binary) { bindParamDesc->sql_type = DSQL_BINARY; @@ -1707,13 +1709,13 @@ Cursor_setParamVariables_oneRow( } } - // bug631212 ݿڲʹnumericʹdmPythonintʱȻʹfloatͷһʹint֮󶨲ᶪʧС + // bug631212 ������ݿ��ڲ�ʹ��numeric����ʹ��dmPython����int��������ʱ��������Ȼʹ��float���ͷ����һ��ʹ��int��֮��󶨲������ᶪʧС������ if (bindParamDesc->sql_type == DSQL_DEC && new_varType != &vt_Boolean && param_type == DSQL_PARAM_INPUT && (n_row > 1)) { new_varType = &vt_Float; } - //sql_typeǷƼͣvarchardatetimetimestamp + //sql_type�Ƿ������Ƽ����ͣ������varchar������������datetime�����������timestamp if (bindParamDesc->sql_type == DSQL_VARCHAR && new_varType == &vt_Timestamp) { bindParamDesc->sql_type = DSQL_TIMESTAMP; @@ -1722,10 +1724,10 @@ Cursor_setParamVariables_oneRow( bindParamDesc->scale = 6; } - // bug627535 ΪCLOBʱתᵼΪreturngingʱtextͲڴ˴SQLΪCLOBʱٽת + // bug627535 ���������ΪCLOB����ʱ����ת���ᵼ���������������Ϊreturnging�������ʱ����text���Ͳ���������ڴ˴��������������SQL����ΪCLOB����ʱ���ٽ���ת�� if(!((param_type == DSQL_PARAM_OUTPUT)&&(bindParamDesc->sql_type == DSQL_CLOB))) { - //python2.7гȡlong strͣʱ sql ӳ ȥ + //python2.7�г���������������ȡ������long str���ͣ���ʱ�� ��������sql���� ӳ��� �������� ȥ�� if (new_varType == &vt_String || new_varType == &vt_Binary || new_varType == &vt_LongString) { if (new_varType == tmp_varType || @@ -1738,7 +1740,7 @@ Cursor_setParamVariables_oneRow( } } - //󶨲ûͣΪֱӽò󶨣Ҫ·һnew_var + //����󶨲������û��������ͣ�������Ϊ�����������ֱ�ӽ��ò����󶨣�����Ҫ���·���һ��new_var if ((param_type == DSQL_PARAM_INPUT_OUTPUT || param_type == DSQL_PARAM_OUTPUT) && is_udt == 1) { @@ -1753,27 +1755,27 @@ Cursor_setParamVariables_oneRow( goto fun_end; } - /** Ϊͣɾ **/ + /** ��Ϊ�������ͣ����������ɾ������ **/ if (new_var->type->pythonType == &g_ObjectVarType && ObjectVar_GetParamDescAndObjHandles((dm_ObjectVar*)new_var, self->hdesc_param, iparam + 1) < 0) { goto fun_end; } - /* ɵıиֵ */ + /* �������ɵı��������и�ֵ */ if (dmVar_SetValue(new_var, irow, iValue) < 0) { goto fun_end; } } - /* ѾֵıIJбУʹ */ + /* ���Ѿ���ֵ�ı�������IJ����б��У�����ʹ�� */ PyList_SetItem(self->param_variables, iparam, new_var); continue; } - /* һ󶨣ǰѾڣУֱñֵ */ + /* һ���������󶨣�ǰ������Ѿ����ڣ��������У�ֱ�����ñ���ֵ */ if (dmVar_SetValue(new_var, irow, iValue) < 0) { goto fun_end; @@ -1819,7 +1821,7 @@ Cursor_setParamVariables( return -1; } - /** У򱨴 **/ + /** �������������У��򱨴� **/ boundByPos = PySequence_Check(parameters); if (boundByPos == 0) { @@ -1836,7 +1838,7 @@ Cursor_setParamVariables( self->setInputSizes = 0; } - /** 󶨲㹻İ󶨲ռ **/ + /** ����󶨲������������������㹻�İ󶨲����ռ� **/ if (is_many == 0) *prow_size = 1; else @@ -1844,22 +1846,22 @@ Cursor_setParamVariables( Py_CLEAR(self->param_variables); - /* listĴСlistеÿitemʾÿ󶨵ֵаʱÿitemжֵ */ + /* ��������������list�Ĵ�С��list�е�ÿ��item��ʾÿ���������󶨵�ֵ�����а�ʱÿ��item�ж��ֵ */ self->param_variables = PyList_New(self->paramCount); if (self->param_variables == NULL) { return -1; } - /* ֵδָΪNULL */ + /* ����������ֵ����δָ������ΪNULL */ for (irow = 0; irow < *prow_size; irow ++) { - /* Dzֱȡ */ + /* �Dz���ֱ��ȡ */ if (irow == 0 && is_many == 0) { tmp_param = parameters; } - else /* ȡеһ */ + else /* ����ȡ���е�һ�� */ { tmp_param = PySequence_GetItem(parameters, irow); Py_DECREF(tmp_param); @@ -1871,7 +1873,7 @@ Cursor_setParamVariables( } } - /* Ͻڰ󶨲ֵijһδ󶨹߾ΪNone˴SQL_TYPE󶨶 */ + /* ���Ͻ��������ڰ󶨲���ֵ���������ijһ��δ�󶨹����߾�ΪNone����˴�����SQL_TYPE����󶨶��� */ for (iparam = 0; iparam < self->paramCount; iparam ++) { new_var = PyList_GET_ITEM(self->param_variables, iparam); @@ -1890,7 +1892,7 @@ Cursor_setParamVariables( return -1; } - /* ͣΪͣɾ **/ + /* ������������ͣ���Ϊ�������ͣ����������ɾ������ **/ if ((self->bindParamDesc[iparam].param_type == DSQL_PARAM_INPUT_OUTPUT || self->bindParamDesc[iparam].param_type == DSQL_PARAM_OUTPUT) && new_var->type->pythonType == &g_ObjectVarType && @@ -1952,13 +1954,13 @@ sdint2 Cursor_PerformBind( dm_Cursor* self, // cursor to perform binds on PyObject* parameters, // parameters to bind - sdint2 isMany, // Ƿִжв + sdint2 isMany, // �Ƿ�ִ�ж��в��� Py_ssize_t* rowsize ) { *rowsize = 0; - /** setinputsize󶨲setinputsizeеиһ **/ + /** ��������setinputsize���󶨲������������setinputsize�е��и���һ�� **/ if (self->setInputSizes) { if (PyList_Check(self->param_variables)) @@ -1975,24 +1977,24 @@ Cursor_PerformBind( } } - /** Ϊ0ֱӷ **/ + /** ����������Ϊ0����ֱ�ӷ��� **/ if (self->paramCount == 0) return 0; - /** ݸϢ **/ + /** ���ݸ�����������Ϣ������������� **/ if (Cursor_setParamVariables(self, parameters, isMany, rowsize) < 0) return -1; - /** 󶨲 **/ + /** �󶨲��� **/ return Cursor_BindParamVariable(self, *rowsize); } -// Ϊ̬̬ܵϵͳͳһ +// �������Ϊ��̬��̬���ܵ���ϵͳ����ͳһ���������� sdint4 Cursor_ParseArgs( PyObject *args, - PyObject **specArg, // SQLȵһ - PyObject **seqArg // в + PyObject **specArg, // SQL���ȵ�һ��������� + PyObject **seqArg // �������в��� ) { Py_ssize_t argCount = PyTuple_GET_SIZE(args); @@ -2016,14 +2018,14 @@ Cursor_ParseArgs( if (argCount == 1) return 0; - // һtupleҷlistҷdictΪǶ̬ + // ����һ��������tuple�ҷ�list�ҷ�dict������Ϊ�Ƕ�̬���� itemParam_fst = PyTuple_GetItem(args, 1); if (itemParam_fst == NULL) return -1; itemParam = itemParam_fst; - // ̬ + // ��̬���� if (!PyTuple_Check(itemParam) && !PyList_Check(itemParam) && !PyDict_Check(itemParam)) { *seqArg = PyList_New(argCount - 1); @@ -2058,7 +2060,7 @@ Cursor_ParseArgs( return 0; } -/* executedirectӦdpi_exec_direct */ +/* ����executedirect��������Ӧdpi_exec_direct */ static PyObject* Cursor_ExecuteDirect( @@ -2158,7 +2160,7 @@ Cursor_Execute_inner( PyObject* paramsRet = NULL; Py_ssize_t rowsize; - /** statementΪNULL **/ + /** statementΪNULL������ **/ if (statement == NULL) { PyErr_SetString(PyExc_TypeError, "expecting a None or string statement arguement"); @@ -2227,7 +2229,7 @@ Cursor_Execute_inner( self->param_variables = NULL; } - /** CALLߴֱӷزб **/ + /** ����CALL�������ߴ��������������ֱ�ӷ��ز����б� **/ if (from_call == 1 || Cursor_outparam_exist(self)) { paramsRet = Cursor_MakeupProcParams(self); @@ -2236,7 +2238,7 @@ Cursor_Execute_inner( goto fun_end; } - /* paramsRetPyList_NEWüĬΪ1ﲻҪټ1ֱӷ */ + /* paramsRet����PyList_NEW���������ü���Ĭ��Ϊ1�����ﲻ��Ҫ�ټ�1��ֱ�ӷ��� */ //Py_INCREF(paramsRet); return paramsRet; } @@ -2253,7 +2255,7 @@ Cursor_Execute_inner( return Py_None; fun_end: - /** ִʧܣͷű **/ + /** ִ��ʧ�ܣ��ͷű��� **/ Cursor_BoundParamAndCols_Clear(self); return NULL; @@ -2268,7 +2270,7 @@ Cursor_Execute( ) { PyObject* statement = NULL; - PyObject* executeArgs = NULL; /** Ϊڲ룬ͷ **/ + PyObject* executeArgs = NULL; /** Ϊ�ڲ����룬�������ͷ� **/ PyObject* retObject = NULL; DMPYTHON_TRACE_INFO(dpy_trace(NULL, args, "ENTER Cursor_Execute\n")); @@ -2326,18 +2328,18 @@ Cursor_nextset_Inner_ex( { PyObject* ret; - /** ϴִн **/ + /** ����ϴ�ִ�н�� **/ Cursor_ExecRs_Clear(self); - /** **/ + /** ��������� **/ Cursor_free_coldesc(self); - /** жǷ񻹴ڽޣʧܣֱӷ **/ + /** �ж��Ƿ񻹴��ڽ���������ޣ�����ʧ�ܣ���ֱ�ӷ��� **/ ret = Cursor_nextset_inner(self); if (!ret || ret == Py_None) return ret; - /** ڽ **/ + /** ���ڽ���� **/ if (Cursor_PerformDefine(self, NULL) < 0) return NULL; @@ -2371,7 +2373,7 @@ Cursor_nextset( to the caller. ************************************************************************/ static -PyObject* /*py*/ +PyObject* /*����py����*/ Cursor_ContextManagerEnter( dm_Cursor* cursor, /*IN:cursor*/ PyObject* args /*IN:args*/ @@ -2388,7 +2390,7 @@ Cursor_ContextManagerEnter( cursor. ************************************************************************/ static -PyObject* /*py*/ +PyObject* /*����py����*/ Cursor_ContextManagerExit( dm_Cursor* cursor, /*IN:cursor*/ PyObject* args /*IN:args*/ @@ -2415,6 +2417,7 @@ Cursor_ExecuteMany( { PyObject* statement; PyObject* argsList; + PyObject* argsIter = NULL; PyObject* rowParams; PyObject* retObj = NULL; @@ -2425,16 +2428,17 @@ Cursor_ExecuteMany( DMPYTHON_TRACE_INFO(dpy_trace(statement, argsList, "ENTER Cursor_ExecuteMany, after parse args\n")); - if (PyIter_Check(argsList)) + argsIter = PyObject_GetIter(argsList); + if (argsIter != NULL) { Py_INCREF(Py_None); retObj = Py_None; - while(1) - { - rowParams = PyIter_Next(argsList); - if (rowParams == NULL) - break; + while(1) + { + rowParams = PyIter_Next(argsIter); + if (rowParams == NULL) + break; Py_XDECREF(retObj); retObj = Cursor_Execute_inner(self, statement, rowParams, 0, 0, 0); @@ -2447,12 +2451,23 @@ Cursor_ExecuteMany( return NULL; } - Py_DECREF(rowParams); - } - - return retObj; + Py_DECREF(rowParams); + } + + if (PyErr_Occurred()) + { + Py_XDECREF(retObj); + Py_DECREF(argsIter); + return NULL; + } + + Py_DECREF(argsIter); + + return retObj; } - + + PyErr_Clear(); + retObj = Cursor_Execute_inner(self, statement, argsList, 1, 0, 0); DMPYTHON_TRACE_INFO(dpy_trace(statement, argsList, "ENTER Cursor_ExecuteMany, Cursor_Execute_inner Per Row, %s\n", retObj == NULL ? "FAILED" : "SUCCESS")); @@ -2562,14 +2577,14 @@ Cursor_InternalFetch( return -1; } - /** fetch֮ǰarraysize **/ + /** fetch֮ǰ����������������arraysize **/ if ((int)self->arraySize < 0 || self->arraySize > ULENGTH_MAX) { PyErr_SetString(g_ErrorException, "Invalid cursor arraysize\n"); return -1; } - /** fetch֮ǰarraysize **/ + /** ����fetch֮ǰ������������arraysize **/ array_size = self->arraySize; if (self->arraySize > self->org_arraySize) { @@ -2577,7 +2592,7 @@ Cursor_InternalFetch( } rowleft = (ulength)(self->totalRows - self->rowCount); - /** ȡ֮С **/ + /** ȡ����֮���С�� **/ realToGet = array_size < rowleft ? array_size : rowleft; for (i = 0; i < PyList_GET_SIZE(self->col_variables); i ++) @@ -2621,7 +2636,7 @@ Cursor_MoreRows( dm_Cursor* self ) { - /*ʼΪ-1*/ + /*��ʼ��Ϊ-1*/ if (self->actualRows == (ulength)(-1) || self->rowNum >= self->actualRows) { @@ -2768,7 +2783,7 @@ Cursor_CreateRow_AsDict( PyDict_SetItem(dict, key, item); - /* PyDict_SetItemʹindex,keyڴ1ѭindex,keyֻһΣڴ1 */ + /* PyDict_SetItem��ʹindex,key���ڴ������1��ѭ����index,keyֻ��һ�Σ������������ڴ������1 */ Py_DECREF(item); Py_XDECREF(key); } @@ -2798,7 +2813,7 @@ Cursor_One_Fetch( } else { - return Cursor_CreateRow_AsTuple(self); /*BUG553553Ϊtuple*/ + return Cursor_CreateRow_AsTuple(self); /*BUG553553����Ϊ����tuple*/ } } @@ -2885,7 +2900,7 @@ Cursor_FetchMany( goto fun_end; } - /* rowsСδȡrowleft򷵻rowsݣ򷵻ʣ */ + /* ����rowsС��δ��ȡ����rowleft���򷵻�rows�����ݣ����򷵻�ʣ�������� */ rowleft = (ulength)(self->totalRows - self->rowCount); rowToGet = (ulength)inputRow < rowleft ? (ulength)inputRow : rowleft; @@ -2998,14 +3013,14 @@ Cursor_CalcStmtSize( dm_Cursor* self, char* procName, udint4 paramCount, - udbyte ret_value /** 0޷ֵ1зֵ **/ + udbyte ret_value /** 0���޷���ֵ��1���з���ֵ **/ ) { /************************************************************************/ - /* ʽ + /* �����ʽ�� /* begin - /* ? = func(); ==>洢 - /* proc(); ==>洢 + /* ? = func(); ==>�洢���� + /* proc(); ==>�洢���� /* end; /************************************************************************/ udint4 size = 20; /** = 5(begin)+2('"''"') + 1(' ') + 3('('')'';') + 1(' ') + 4(end;) **/ @@ -3067,7 +3082,7 @@ Cursor_MakeStmtSQL( dm_Cursor* self, char* procName, udint4 paramCount, - udbyte ret_value /** 0޷ֵ1зֵ **/ + udbyte ret_value /** 0���޷���ֵ��1���з���ֵ **/ ) { udint4 sql_len; @@ -3077,7 +3092,7 @@ Cursor_MakeStmtSQL( char* pos = NULL; sql_len = Cursor_CalcStmtSize(self, procName, paramCount, ret_value); - sql = PyMem_Malloc(sql_len + 1); /* Ԥβ */ + sql = PyMem_Malloc(sql_len + 1); /* Ԥ����β�� */ if (sql == NULL) { return PyErr_NoMemory(); @@ -3149,7 +3164,7 @@ Cursor_MakeupProcParams( return NULL; } - /** OBJECT͵ֱӷذʱĶ **/ + /** ����OBJECT���͵�����������������������ֱ�ӷ��ذ�ʱ�Ķ������� **/ if (((dm_Var*)paramVal)->type->pythonType == &g_ObjectVarType && self->bindParamDesc[iparam].param_type == DSQL_PARAM_INPUT) { @@ -3179,7 +3194,7 @@ Cursor_MakeupProcParams( return NULL; } - /** OBJECT͵ֱӷذʱĶ **/ + /** ����OBJECT���͵�����������������������ֱ�ӷ��ذ�ʱ�Ķ������� **/ if (((dm_Var*)paramVal)->type->pythonType == &g_ObjectVarType && self->bindParamDesc[iparam].param_type == DSQL_PARAM_INPUT) { @@ -3221,7 +3236,7 @@ PyObject* Cursor_CallExec_inner( dm_Cursor* self, PyObject* args, - udint4 ret_value /* ǷҪֵ */ + udint4 ret_value /* �Ƿ���Ҫ����ֵ */ ) { PyObject* nameObj = NULL; @@ -3241,7 +3256,7 @@ Cursor_CallExec_inner( return NULL; } - // + // �������� if (dmBuffer_FromObject(&buffer, nameObj, self->environment->encoding) < 0) return NULL; @@ -3255,28 +3270,28 @@ Cursor_CallExec_inner( Cursor_escape_quotes(procName, buffer.size * 2 + 1, buffer.ptr, buffer.size); dmBuffer_Clear(&buffer); - // 󶨲 + // ����󶨲������� if (parameters != NULL) paramCount = PySequence_Size(parameters); else paramCount = 0; - // SQL + // ����SQL��� sql = Cursor_MakeStmtSQL(self, procName, (udint4)paramCount, ret_value); PyMem_Free(procName); if (ret_value != 0) { - /** ҪֵNoneparametersĵһλ **/ + /** ����Ҫ����ֵ������None��parameters�ĵ�һ��λ�� **/ //Py_XINCREF(parameters); if (parameters == NULL || parameters == Py_None) { parameters = PyList_New(1); - /* PyList_SetItem:steals a reference to item - ˴Py_Noneڴطüûۼӹ - Ҫ1parametersʱϵͳPyNone1 */ + /* PyList_SetItem:��steals�� a reference to item�� + �˴�Py_None�ڴ�����������ط����ü���û���ۼӹ��� + �����Ҫ������1������parameters������ʱ���ϵͳ����PyNone������1�� */ Py_INCREF(Py_None); PyList_SetItem(parameters, 0, Py_None); } @@ -3286,7 +3301,7 @@ Cursor_CallExec_inner( } } - /** ִ **/ + /** ִ�� **/ retObj = Cursor_Execute_inner(self, sql, parameters, 0, 0, 1); Py_CLEAR(sql); Py_CLEAR(parameters); @@ -3379,7 +3394,7 @@ Cursor_GetDescription( { colinfo = &self->bindColDesc[icol]; - // ׼Ҫ7Ϣname,type_code,display_size ,internal_size, precision, scale, null_ok + // ��׼��Ҫ��7��������Ϣ��name,type_code,display_size ,internal_size, precision, scale, null_ok varType = dmVar_TypeBySQLType(colinfo->sql_type, 0); if (varType == NULL) { @@ -3403,7 +3418,7 @@ Cursor_GetDescription( colinfo->scale, colinfo->nullable); - /* Py_BuildValueʹcolnameڴ1ΣcolnameֻһΣ1 */ + /* Py_BuildValue��ʹcolname�ڴ�������1�Σ�colnameֻ��һ�Σ�������������1 */ Py_XDECREF(colname); if (colinfo == NULL) @@ -3427,7 +3442,7 @@ Cursor_GetDescription( PyDict_SetItem(colmap, key, index); - /* PyDict_SetItemʹindex,keyڴ1ѭindex,keyֻһΣڴ1 */ + /* PyDict_SetItem��ʹindex,key���ڴ������1��ѭ����index,keyֻ��һ�Σ������������ڴ������1 */ Py_DECREF(index); // SetItemString increments Py_XDECREF(key); index = NULL; @@ -3498,18 +3513,18 @@ Cursor_SetInputSizes_inner( // if number of argument is 0, then return None;else create a new one numArgs = PyTuple_Size(args); - // keywordskeywords + // �������keywords������keywords������ if (keywords) numkeywordArgs = PyDict_Size(keywords); - // argskeywordsͬʱ + // args��keywords����ͬʱ���� if (numArgs > 0 && numkeywordArgs>0) Py_RETURN_NONE; - // ڷؿ + // ����������ڷ��ؿ� if (numArgs == 0 && numkeywordArgs == 0) { return NULL; } - // keywordsڴֵ䣬򴴽 + // ���keywords���ڴ����ֵ䣬���򴴽����� if (numkeywordArgs > 0) self->param_variables = PyDict_New(); else @@ -3533,13 +3548,13 @@ Cursor_SetInputSizes_inner( if (numkeywordArgs > 0) { i = 0; - // δkeywords + // ���δ���keywords while (PyDict_Next(keywords, &i, &key, &value)) { var = dmVar_NewByType(self, value, self->bindArraySize); if (!var) return NULL; - //µֵֵԼֵ + //�����µ��ֵ��ֵ�Լ����ֵ� if (PyDict_SetItem(self->param_variables, key, (PyObject*)var) < 0) { Py_DECREF(var); @@ -3650,7 +3665,7 @@ Cursor_Var( DMPYTHON_TRACE_INFO(dpy_trace(NULL, args, "ENTER Cursor_Var\n")); - // + //�������� size = 0; bypassDecode = 0; arraySize = self->arraySize; @@ -3741,9 +3756,9 @@ static PyMethodDef g_CursorMethods[] = { static PyMemberDef g_CursorMembers[] = { { "arraysize", T_INT, offsetof(dm_Cursor, arraySize), 0 }, { "bindarraysize", T_INT, offsetof(dm_Cursor, bindArraySize), 0 }, - { "rowcount", T_INT, offsetof(dm_Cursor, totalRows), READONLY }, /** **/ - { "rownumber", T_INT, offsetof(dm_Cursor, rowCount), READONLY }, /** αڵǰλ0-based **/ - { "with_rows", T_BOOL, offsetof(dm_Cursor, with_rows), READONLY }, /** αڵǰλ0-based **/ + { "rowcount", T_INT, offsetof(dm_Cursor, totalRows), READONLY }, /** ����������� **/ + { "rownumber", T_INT, offsetof(dm_Cursor, rowCount), READONLY }, /** �α����ڵ�ǰλ��0-based **/ + { "with_rows", T_BOOL, offsetof(dm_Cursor, with_rows), READONLY }, /** �α����ڵ�ǰλ��0-based **/ { "statement", T_OBJECT, offsetof(dm_Cursor, statement), READONLY }, { "connection", T_OBJECT_EX, offsetof(dm_Cursor, connection), READONLY }, { "column_names", T_OBJECT_EX, offsetof(dm_Cursor, column_names), READONLY }, @@ -3811,4 +3826,4 @@ PyTypeObject g_CursorType = { 0, // tp_free 0, // tp_is_gc 0 // tp_bases -}; \ No newline at end of file +}; diff --git a/Environment.c b/src/native/Environment.c similarity index 100% rename from Environment.c rename to src/native/Environment.c diff --git a/Error.c b/src/native/Error.c similarity index 100% rename from Error.c rename to src/native/Error.c diff --git a/Error.h b/src/native/Error.h similarity index 100% rename from Error.h rename to src/native/Error.h diff --git a/exBfile.c b/src/native/exBfile.c similarity index 100% rename from exBfile.c rename to src/native/exBfile.c diff --git a/exLob.c b/src/native/exLob.c similarity index 100% rename from exLob.c rename to src/native/exLob.c diff --git a/exObject.c b/src/native/exObject.c similarity index 100% rename from exObject.c rename to src/native/exObject.c diff --git a/py_Dameng.c b/src/native/py_Dameng.c similarity index 100% rename from py_Dameng.c rename to src/native/py_Dameng.c diff --git a/py_Dameng.h b/src/native/py_Dameng.h similarity index 96% rename from py_Dameng.h rename to src/native/py_Dameng.h index e87f1a7..3e1b89f 100644 --- a/py_Dameng.h +++ b/src/native/py_Dameng.h @@ -20,12 +20,9 @@ extern "C" { /* Assume C declarations for C++ */ #define NAMELEN 128 -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) - -/** 需同setup.py中保持一致 **/ -#ifndef BUILD_VERSION -#define BUILD_VERSION 2.5.30 +/** 需同setup.py/pyproject.toml中保持一致 **/ +#ifndef BUILD_VERSION_STRING +#define BUILD_VERSION_STRING "2.5.32" #endif #ifndef BUILD_VERSION_MAJOR @@ -36,8 +33,6 @@ extern "C" { /* Assume C declarations for C++ */ #define BUILD_VERSION_MIN 2 #endif -#define BUILD_VERSION_STRING TOSTRING(BUILD_VERSION) - /** 常量定义 **/ #define SHUTDOWN_ABORT "ABORT" #define SHUTDOWN_IMMEDIATE "IMMEDIATE" @@ -241,4 +236,3 @@ DmIntNumber_AsInt( ); #endif // _PY_DAMENG_H - diff --git a/row.c b/src/native/row.c similarity index 100% rename from row.c rename to src/native/row.c diff --git a/row.h b/src/native/row.h similarity index 100% rename from row.h rename to src/native/row.h diff --git a/strct.h b/src/native/strct.h similarity index 100% rename from strct.h rename to src/native/strct.h diff --git a/tObject.c b/src/native/tObject.c similarity index 100% rename from tObject.c rename to src/native/tObject.c diff --git a/trc.c b/src/native/trc.c similarity index 100% rename from trc.c rename to src/native/trc.c diff --git a/trc.h b/src/native/trc.h similarity index 100% rename from trc.h rename to src/native/trc.h diff --git a/vBfile.c b/src/native/vBfile.c similarity index 100% rename from vBfile.c rename to src/native/vBfile.c diff --git a/vCursor.c b/src/native/vCursor.c similarity index 100% rename from vCursor.c rename to src/native/vCursor.c diff --git a/vDateTime.c b/src/native/vDateTime.c similarity index 100% rename from vDateTime.c rename to src/native/vDateTime.c diff --git a/vInterval.c b/src/native/vInterval.c similarity index 100% rename from vInterval.c rename to src/native/vInterval.c diff --git a/vLob.c b/src/native/vLob.c similarity index 100% rename from vLob.c rename to src/native/vLob.c diff --git a/vNumber.c b/src/native/vNumber.c similarity index 100% rename from vNumber.c rename to src/native/vNumber.c diff --git a/vObject.c b/src/native/vObject.c similarity index 100% rename from vObject.c rename to src/native/vObject.c diff --git a/vString.c b/src/native/vString.c similarity index 100% rename from vString.c rename to src/native/vString.c diff --git a/var.c b/src/native/var.c similarity index 94% rename from var.c rename to src/native/var.c index 447c82a..20614b1 100644 --- a/var.c +++ b/src/native/var.c @@ -306,12 +306,12 @@ dmVar_InternalBind( } else { - /** Ϊαͣ;Ϊ **/ + /** ��Ϊ�α����ͣ�������;�����Ϊ������� **/ if (Py_TYPE(var) == &g_CursorVarType) { paramdesc->param_type = DSQL_PARAM_INPUT_OUTPUT; - //αͣ󶨲ΪDSQL_NULL_DATA + //�α����ͣ��󶨲���������ΪDSQL_NULL_DATA for (iparam = 0; iparam < var->allocatedElements; iparam++) { var->indicator[iparam] = sizeof(dhstmt); @@ -320,18 +320,18 @@ dmVar_InternalBind( } data_ptr = (dpointer)var->data; - //Ϊʽԣ󶨲Ϊʽ + //���Ϊ���������������������ʽ������ԣ���󶨲���Ϊ��ʽ������� if(paramdesc->param_type == DSQL_PARAM_OUTPUT && var->output_stream == 1) { rt = dpi_bind_param2(var->boundCursorHandle, var->boundPos, DSQL_PARAM_OUTPUT_STREAM, var->type->cType, paramdesc->sql_type, paramdesc->prec, paramdesc->scale, - var->boundPos, var->bufferSize, var->indicator, var->actualLength); + (dpointer)(ulength)var->boundPos, var->bufferSize, var->indicator, var->actualLength); } else { if(paramdesc->sql_type == DSQL_VARCHAR) { - //ǵ󶨶еҪÿһе󳤶 + //���ǵ��󶨶��е��������Ҫ���ÿһ�е���󳤶� for(row = 0; row < var->allocatedElements; row++) { if(var->actualLength[row] > 8188 ) @@ -562,9 +562,9 @@ dmVar_TypeByValue( char buffer[200]; int result; long data; - udint8 size2 = 0; //ݳ + udint8 size2 = 0; //�������ݳ��� - /** ΪNoneʹvt_string **/ + /** ����ΪNone����ʹ��vt_string **/ if (value == Py_None) { *size = 1; @@ -576,7 +576,7 @@ dmVar_TypeByValue( if (py_String_Check(value)) { - //ȡ + //��ȡ�������� size2 = py_String_GetSize(value); if (size2 > INT_MAX) { @@ -597,8 +597,8 @@ dmVar_TypeByValue( #if PY_MAJOR_VERSION >= 3 if (PyBytes_Check(value)) { - //bug58477610GINTֵΪһС2GֵӶֶβɹԤڱ - //udint8Ȼȡ󶨲ȣINT_MAXֵ򱨴ٸֵ + //bug584776����������10G��������INT�������ֵ���������Ϊһ��С��2G��ֵ���Ӷ����ֶβ���ɹ�����Ԥ�ڱ������� + //��udint8�Ȼ�ȡ�󶨲������ȣ�������INT_MAX���ֵ���򱨴��������ٸ�ֵ��������� size2 = PyBytes_GET_SIZE(value); if (size2 > INT_MAX) { @@ -615,7 +615,7 @@ dmVar_TypeByValue( #else if (PyUnicode_Check(value)) { - //ȡ + //��ȡ�������� size2 = PyUnicode_GET_SIZE(value); if (size2 > INT_MAX) { @@ -653,10 +653,10 @@ dmVar_TypeByValue( if (PyTime_Check(value)) return &vt_Time; - //bigint⣬ȫӳ䵽vt_Integer + //��bigint�⣬����ȫӳ�䵽vt_Integer if (PyLong_Check(value)) { - /* longΧӳ䵽bigint */ + /* ����long��Χ��ӳ�䵽bigint */ data = PyLong_AsLong(value); if (data == -1 && PyErr_Occurred()) { @@ -664,7 +664,7 @@ dmVar_TypeByValue( return &vt_Bigint; } - /* INT_MAXֵҲΪBIGINTLINUXpyLong_asLongLONG_MAX(bigint) */ + /* ����INT_MAX�����ֵ��Ҳ��Ϊ��BIGINT��LINUXpyLong_asLong��������LONG_MAX(bigint������) */ if (data > INT_MAX || data < INT_MIN) { return &vt_Bigint; @@ -673,7 +673,7 @@ dmVar_TypeByValue( return &vt_Integer; } - //pythonֻdoubleֵֻͣӦvt_Double, vt_FloatǶӦfloat͵ģﲻ + //pythonֻ��double���ͣ���������ֵֻ��Ӧ��vt_Double, vt_Float�Ƕ�Ӧfloat���͵ģ����ﲻ�� if (PyFloat_Check(value)) return &vt_Double; @@ -821,7 +821,7 @@ dmVar_TypeByValue( if (size2 > INT_MAX) { - //ȳINT_MAXС򱨴 + //�������ȳ���INT_MAX��С���򱨴����� aq_sprintf(buffer, 200, "dmVar_TypeByValue(): invalid date len %lld", size2); PyErr_SetString(g_NotSupportedErrorException, buffer); } @@ -843,7 +843,7 @@ dmVar_TypeByValue( dm_VarType* dmVar_TypeBySQLType ( udint2 sqlType, // SQL type, SQL_XXX - int value_flag // LOBЧжȡLOBȡLOBеֵ + int value_flag // ��LOB������Ч�������ж���ȡLOB������ȡLOB�����е�ֵ ) { char buffer[100]; @@ -915,7 +915,7 @@ dmVar_TypeBySQLType ( case DSQL_RECORD: return &vt_Record; - /* ֶintegerʹ */ + /* �������ֶ�����integer���ʹ��� */ case DSQL_INT: case DSQL_TINYINT: case DSQL_SMALLINT: @@ -968,7 +968,7 @@ dmVar_DefaultNewByValue( dm_Cursor* cursor, // cursor to associate variable with PyObject* value, // Python value to associate unsigned numElements, // number of elements to allocate - unsigned ipos /*1-based*/ + unsigned ipos /*���������1-based*/ ) { dm_VarType* varType; @@ -976,7 +976,7 @@ dmVar_DefaultNewByValue( dm_Var* var; sdint4 size = -1; - /* value Ϊnone,Ϊݲsqltypeȡ */ + /* value Ϊnone,��Ϊ������������������������ݲ�������sqltype����ȡ�������� */ if (value == Py_None && (cursor->bindParamDesc[ipos - 1].param_type == DSQL_PARAM_INPUT_OUTPUT || cursor->bindParamDesc[ipos - 1].param_type == DSQL_PARAM_OUTPUT)) @@ -1014,7 +1014,7 @@ dmVar_DefaultNewByValue( return NULL; } - /** Ϊͣɾ **/ + /** ��Ϊ�������ͣ����������ɾ������ **/ if (var->type->pythonType == &g_ObjectVarType) { if (ObjectVar_GetParamDescAndObjHandles((dm_ObjectVar*)var, cursor->hdesc_param, ipos) < 0) @@ -1035,7 +1035,7 @@ dmVar_NewByValue( dm_Cursor* cursor, // cursor to associate variable with PyObject* value, // Python value to associate unsigned numElements, // number of elements to allocate - unsigned ipos /* 1-based */ + unsigned ipos /* ���������1-based */ ) { return dmVar_DefaultNewByValue(cursor, value, numElements, ipos); @@ -1370,7 +1370,7 @@ dmVar_SetSingleValue( return 0; } - /*valueתΪvar->datavar->indicator[arrayPos]*/ + /*��valueת��Ϊvar->data��������var->indicator[arrayPos]*/ return (*var->type->setValueProc)(var, arrayPos, value); } @@ -1652,7 +1652,7 @@ dmVar_PutDataAftExec( udint4 arrayPos // array position ) { - /* long string or long binary->DSQL_DATA_AT_EXEC */ + /* ��long string or long binary->DSQL_DATA_AT_EXEC */ if (var->actualLength[arrayPos] == DSQL_NULL_DATA || var->indicator[arrayPos] != DSQL_DATA_AT_EXEC) { diff --git a/var_pub.h b/src/native/var_pub.h similarity index 100% rename from var_pub.h rename to src/native/var_pub.h diff --git a/vlong.c b/src/native/vlong.c similarity index 100% rename from vlong.c rename to src/native/vlong.c diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..4097070 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,155 @@ +from __future__ import annotations + +import os +import subprocess +import sys +import uuid +from pathlib import Path +from typing import Callable + +import pytest + +import dmPython + + +ROOT_DIR = Path(__file__).resolve().parents[1] +DYLIB_DIR = ROOT_DIR / "dpi_bridge" + +_DM_AVAILABLE: bool | None = None +_DM_ERROR: str | None = None +_DEFAULT_BOUNDARY_SIZES = "0,1,2,255,256,1023,1024,2047,2048,4095,4096,4097,8191,8192,8193,16384" + + +def dm_conn_params() -> dict[str, object]: + return { + "user": os.getenv("DM_TEST_USER", "SYSDBA"), + "password": os.getenv("DM_TEST_PASSWORD", "SYSDBA001"), + "server": os.getenv("DM_TEST_HOST", "localhost"), + "port": int(os.getenv("DM_TEST_PORT", "5237")), + } + + +def _probe_dm() -> tuple[bool, str]: + params = dm_conn_params() + try: + conn = dmPython.connect(**params) + cur = conn.cursor() + cur.execute("SELECT 1") + cur.fetchone() + cur.close() + conn.close() + return True, "" + except Exception as exc: # pragma: no cover - probe helper + return False, str(exc) + + +def pytest_runtest_setup(item: pytest.Item) -> None: + global _DM_AVAILABLE, _DM_ERROR + + if item.get_closest_marker("requires_dm") is None: + return + + if _DM_AVAILABLE is None: + _DM_AVAILABLE, _DM_ERROR = _probe_dm() + + if not _DM_AVAILABLE: + pytest.skip(f"DM not available: {_DM_ERROR}") + + +@pytest.fixture(scope="session") +def conn_params() -> dict[str, object]: + return dm_conn_params() + + +@pytest.fixture() +def conn(conn_params): + c = dmPython.connect(**conn_params) + yield c + c.close() + + +@pytest.fixture() +def cursor(conn): + cur = conn.cursor() + yield cur + cur.close() + + +@pytest.fixture(scope="session") +def stress_rows() -> int: + return int(os.getenv("DM_TEST_STRESS_ROWS", "2000")) + + +@pytest.fixture(scope="session") +def stress_workers() -> int: + return int(os.getenv("DM_TEST_STRESS_WORKERS", "4")) + + +@pytest.fixture(scope="session") +def boundary_sizes() -> list[int]: + raw = os.getenv("DM_TEST_BOUNDARY_SIZES", _DEFAULT_BOUNDARY_SIZES) + values: list[int] = [] + for item in raw.split(","): + text = item.strip() + if not text: + continue + value = int(text) + if value < 0: + raise ValueError(f"DM_TEST_BOUNDARY_SIZES contains negative size: {value}") + values.append(value) + if not values: + raise ValueError("DM_TEST_BOUNDARY_SIZES produced an empty size list") + return values + + +@pytest.fixture(scope="session") +def churn_loops() -> int: + return int(os.getenv("DM_TEST_CHURN_LOOPS", "120")) + + +@pytest.fixture(scope="session") +def gc_loops() -> int: + return int(os.getenv("DM_TEST_GC_LOOPS", "150")) + + +@pytest.fixture() +def table_name_factory() -> Callable[[str], str]: + def _mk(prefix: str = "DMPY_TEST") -> str: + return f"{prefix}_{uuid.uuid4().hex[:10].upper()}" + + return _mk + + +@pytest.fixture() +def drop_table() -> Callable[[object, str], None]: + def _drop(cur, table_name: str) -> None: + try: + cur.execute(f"DROP TABLE {table_name}") + except Exception: + pass + + return _drop + + +@pytest.fixture() +def run_in_subprocess(conn_params) -> Callable[[str, int], subprocess.CompletedProcess[str]]: + def _run(code: str, timeout: int = 60) -> subprocess.CompletedProcess[str]: + env = os.environ.copy() + env["DM_TEST_HOST"] = str(conn_params["server"]) + env["DM_TEST_PORT"] = str(conn_params["port"]) + env["DM_TEST_USER"] = str(conn_params["user"]) + env["DM_TEST_PASSWORD"] = str(conn_params["password"]) + + dylib_path = str(DYLIB_DIR) + existing = env.get("DYLD_LIBRARY_PATH", "") + env["DYLD_LIBRARY_PATH"] = f"{dylib_path}:{existing}" if existing else dylib_path + + return subprocess.run( + [sys.executable, "-X", "faulthandler", "-c", code], + capture_output=True, + text=True, + env=env, + timeout=timeout, + ) + + return _run diff --git a/tests/integration/test_p0_clob_unicode_regression.py b/tests/integration/test_p0_clob_unicode_regression.py new file mode 100644 index 0000000..e6dc19a --- /dev/null +++ b/tests/integration/test_p0_clob_unicode_regression.py @@ -0,0 +1,175 @@ +from __future__ import annotations + +import textwrap + +import pytest + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p0_stability] + +_PROBLEM_PATTERNS = ("稳态中文🚀X", "A中文🚀", "🚀🚀🚀A") +_SIZES = (16000, 16384, 40000) + + +def _make_text(base: str, size: int) -> str: + if size <= 0: + return "" + return (base * ((size // len(base)) + 2))[:size] + + +def test_clob_unicode_problem_patterns_roundtrip(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_CLOBUNI") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB)") + rid = 1 + expected = {} + for pattern in _PROBLEM_PATTERNS: + for size in _SIZES: + payload = _make_text(pattern, size) + expected[rid] = payload + cur.execute(f"INSERT INTO {table_name} (id, c) VALUES (?, ?)", (rid, payload)) + rid += 1 + conn.commit() + + cur.execute(f"SELECT id, c FROM {table_name} ORDER BY id") + rows = cur.fetchall() + assert len(rows) == len(expected) + for row_id, value in rows: + payload = expected[row_id] + assert isinstance(value, str) + assert len(value) == len(payload) + assert value == payload + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_clob_unicode_problem_patterns_executemany_roundtrip(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_CLOBEXM") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB)") + rows = [] + rid = 1 + for pattern in _PROBLEM_PATTERNS: + for size in _SIZES: + rows.append((rid, _make_text(pattern, size))) + rid += 1 + cur.executemany(f"INSERT INTO {table_name} (id, c) VALUES (?, ?)", rows) + conn.commit() + + cur.execute(f"SELECT id, c FROM {table_name} ORDER BY id") + got = cur.fetchall() + assert len(got) == len(rows) + for (row_id, expected), (_, value) in zip(rows, got): + assert isinstance(value, str) + assert len(value) == len(expected) + assert value == expected + assert row_id >= 1 + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_clob_unicode_problem_patterns_length_contract(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_CLOBLEN") + cur = conn.cursor() + length_stable_cases = { + ("稳态中文🚀X", 16000), + ("稳态中文🚀X", 16384), + ("A中文🚀", 16000), + ("A中文🚀", 16384), + } + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, p VARCHAR(20), s INT, c CLOB)") + rid = 1 + expected = {} + for pattern in _PROBLEM_PATTERNS: + for size in _SIZES: + payload = _make_text(pattern, size) + expected[rid] = (pattern, size, payload) + cur.execute( + f"INSERT INTO {table_name} (id, p, s, c) VALUES (?, ?, ?, ?)", + (rid, pattern, size, payload), + ) + rid += 1 + conn.commit() + + for row_id, (pattern, size, payload) in expected.items(): + cur.execute(f"SELECT length(c), c FROM {table_name} WHERE id = ?", (row_id,)) + db_len, value = cur.fetchone() + assert isinstance(value, str) + assert len(value) == len(payload) + assert value == payload + if (pattern, size) in length_stable_cases: + assert int(db_len) == len(payload) + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +@pytest.mark.crash_guard +def test_clob_unicode_problem_patterns_subprocess_no_crash(run_in_subprocess): + code = textwrap.dedent( + f""" + import os + import uuid + import dmPython + + patterns = {list(_PROBLEM_PATTERNS)!r} + sizes = {list(_SIZES)!r} + + def make_text(base, size): + if size <= 0: + return "" + return (base * ((size // len(base)) + 2))[:size] + + conn = dmPython.connect( + user=os.getenv("DM_TEST_USER", "SYSDBA"), + password=os.getenv("DM_TEST_PASSWORD", "SYSDBA001"), + server=os.getenv("DM_TEST_HOST", "localhost"), + port=int(os.getenv("DM_TEST_PORT", "5237")), + ) + cur = conn.cursor() + table = "DMPY_P0_CLOBSP_" + uuid.uuid4().hex[:8].upper() + try: + cur.execute(f"CREATE TABLE {{table}} (id INT PRIMARY KEY, c CLOB)") + rid = 1 + for pattern in patterns: + for size in sizes: + payload = make_text(pattern, size) + cur.execute(f"INSERT INTO {{table}} (id, c) VALUES (?, ?)", (rid, payload)) + rid += 1 + conn.commit() + + cur.execute(f"SELECT id, c FROM {{table}} ORDER BY id") + got = cur.fetchall() + rid = 1 + for pattern in patterns: + for size in sizes: + expected = make_text(pattern, size) + row = got[rid - 1] + assert row[0] == rid + assert row[1] == expected + rid += 1 + print("OK:CLOB_UNICODE_REGRESSION") + finally: + try: + cur.execute(f"DROP TABLE {{table}}") + conn.commit() + except Exception: + pass + cur.close() + conn.close() + """ + ) + result = run_in_subprocess(code, timeout=300) + assert result.returncode == 0, ( + f"subprocess failed rc={result.returncode}\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}" + ) + assert result.returncode not in (139, -11) + assert "OK:CLOB_UNICODE_REGRESSION" in result.stdout diff --git a/tests/integration/test_p0_data_at_exec_matrix.py b/tests/integration/test_p0_data_at_exec_matrix.py new file mode 100644 index 0000000..9243c95 --- /dev/null +++ b/tests/integration/test_p0_data_at_exec_matrix.py @@ -0,0 +1,177 @@ +from __future__ import annotations + +import textwrap + +import pytest + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p0_stability] + + +def _make_clob_payload(size: int) -> str: + if size <= 0: + return "" + base = "中文🚀A" + return (base * ((size // len(base)) + 2))[:size] + + +def _make_blob_payload(size: int) -> bytes: + if size <= 0: + return b"" + return bytes((i % 256 for i in range(size))) + + +def _assert_subprocess_ok(result, label: str) -> None: + assert result.returncode == 0, ( + f"{label} failed\n" + f"return code: {result.returncode}\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + assert result.returncode not in (139, -11), ( + f"{label} segfault-like exit code: {result.returncode}\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + + +def test_data_at_exec_clob_boundary_matrix_roundtrip( + conn, table_name_factory, drop_table, boundary_sizes +): + table_name = table_name_factory("DMPY_P0_DE_C") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB)") + for idx, size in enumerate(boundary_sizes, start=1): + payload = _make_clob_payload(size) + cur.execute(f"INSERT INTO {table_name} (id, c) VALUES (?, ?)", (idx, payload)) + conn.commit() + + cur.execute(f"SELECT c FROM {table_name} WHERE id = ?", (idx,)) + value = cur.fetchone()[0] + assert isinstance(value, str), f"size={size}, type={type(value)}" + assert value == payload, f"size={size}" + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_data_at_exec_blob_boundary_matrix_roundtrip( + conn, table_name_factory, drop_table, boundary_sizes +): + table_name = table_name_factory("DMPY_P0_DE_B") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, b BLOB)") + for idx, size in enumerate(boundary_sizes, start=1): + payload = _make_blob_payload(size) + cur.execute(f"INSERT INTO {table_name} (id, b) VALUES (?, ?)", (idx, payload)) + conn.commit() + + cur.execute(f"SELECT b FROM {table_name} WHERE id = ?", (idx,)) + value = cur.fetchone()[0] + assert isinstance(value, (bytes, bytearray)), f"size={size}, type={type(value)}" + assert bytes(value) == payload, f"size={size}" + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_data_at_exec_alternating_small_large_same_statement(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_DE_ALT") + cur = conn.cursor() + sizes = [16, 16384, 64, 8192, 1, 4097, 1024, 2048] + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + sql = f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)" + for idx, size in enumerate(sizes, start=1): + c_payload = _make_clob_payload(size) + b_payload = _make_blob_payload(size) + cur.execute(sql, (idx, c_payload, b_payload)) + conn.commit() + + cur.execute(f"SELECT id, c, b FROM {table_name} ORDER BY id") + rows = cur.fetchall() + assert len(rows) == len(sizes) + for idx, row in enumerate(rows, start=1): + size = sizes[idx - 1] + assert row[0] == idx + assert row[1] == _make_clob_payload(size) + assert bytes(row[2]) == _make_blob_payload(size) + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_data_at_exec_executemany_generator_large_payloads(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_DE_EXM") + cur = conn.cursor() + sizes = [2048, 12288, 3072, 16384, 4097, 8192, 1024, 10000] + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + + def _rows(): + for idx, size in enumerate(sizes, start=1): + yield (idx, _make_clob_payload(size), _make_blob_payload(size)) + + cur.executemany(f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", _rows()) + conn.commit() + + cur.execute(f"SELECT id, c, b FROM {table_name} ORDER BY id") + rows = cur.fetchall() + assert len(rows) == len(sizes) + for row in rows: + idx = row[0] + expected_size = sizes[idx - 1] + assert row[1] == _make_clob_payload(expected_size) + assert bytes(row[2]) == _make_blob_payload(expected_size) + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +@pytest.mark.crash_guard +def test_data_at_exec_subprocess_no_segfault_matrix(run_in_subprocess, boundary_sizes): + code = textwrap.dedent( + f""" + import dmPython + import uuid + + sizes = {boundary_sizes!r} + table = "DMPY_P0_DE_SP_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5237, + ) + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {{table}} (id INT PRIMARY KEY, c CLOB, b BLOB)") + for idx, size in enumerate(sizes, start=1): + text = ("中文🚀A" * ((size // 4) + 2))[:size] if size > 0 else "" + blob = bytes((i % 256 for i in range(size))) if size > 0 else b"" + cur.execute(f"INSERT INTO {{table}} (id, c, b) VALUES (?, ?, ?)", (idx, text, blob)) + conn.commit() + cur.execute(f"SELECT c, b FROM {{table}} WHERE id = ?", (idx,)) + row = cur.fetchone() + assert row[0] == text, (size, len(row[0]), len(text)) + assert bytes(row[1]) == blob, size + print("OK:DATA_AT_EXEC_MATRIX") + finally: + try: + cur.execute(f"DROP TABLE {{table}}") + conn.commit() + except Exception: + pass + cur.close() + conn.close() + """ + ) + result = run_in_subprocess(code, timeout=240) + _assert_subprocess_ok(result, "DATA_AT_EXEC matrix subprocess") + assert "OK:DATA_AT_EXEC_MATRIX" in result.stdout diff --git a/tests/integration/test_p0_lob_boundary.py b/tests/integration/test_p0_lob_boundary.py new file mode 100644 index 0000000..687ea8c --- /dev/null +++ b/tests/integration/test_p0_lob_boundary.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +import textwrap + +import pytest + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p0_stability] + + +def _assert_subprocess_ok(result, label: str) -> None: + assert result.returncode == 0, ( + f"{label} failed\n" + f"return code: {result.returncode}\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + assert result.returncode not in (139, -11), ( + f"{label} hit segfault-like exit code: {result.returncode}\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + + +def test_clob_exact_4k_boundary_roundtrip(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_C4K") + cur = conn.cursor() + try: + payload = ("中文🚀边界" * 1000)[:4000] + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB)") + cur.execute(f"INSERT INTO {table_name} (id, c) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT c FROM {table_name} WHERE id = 1") + value = cur.fetchone()[0] + assert isinstance(value, str) + assert value == payload + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +@pytest.mark.parametrize( + ("row_id", "payload"), + [ + (1, bytes(range(256)) * 16), + (2, bytes(range(256)) * 32), + ], + ids=["blob_4k", "blob_8k"], +) +def test_blob_exact_4k_and_8k_roundtrip(conn, table_name_factory, drop_table, row_id, payload): + table_name = table_name_factory("DMPY_P0_B4K") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, b BLOB)") + cur.execute(f"INSERT INTO {table_name} (id, b) VALUES (?, ?)", (row_id, payload)) + conn.commit() + cur.execute(f"SELECT b FROM {table_name} WHERE id = ?", (row_id,)) + value = cur.fetchone()[0] + assert isinstance(value, (bytes, bytearray)) + assert bytes(value) == payload + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_clob_over_4k_roundtrip(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_C5K") + cur = conn.cursor() + try: + payload = ("中文🚀边界" * 1200)[:5000] + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB)") + cur.execute(f"INSERT INTO {table_name} (id, c) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT c FROM {table_name} WHERE id = 1") + value = cur.fetchone()[0] + assert isinstance(value, str) + assert value == payload + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_lob_null_vs_empty_contract(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P0_NULL") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + cur.execute(f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", (1, None, None)) + cur.execute(f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", (2, "", b"")) + conn.commit() + + cur.execute(f"SELECT c, b FROM {table_name} WHERE id = 1") + null_row = cur.fetchone() + assert null_row[0] is None + assert null_row[1] is None + + cur.execute(f"SELECT c, b FROM {table_name} WHERE id = 2") + empty_row = cur.fetchone() + assert empty_row[0] == "" + assert isinstance(empty_row[1], (bytes, bytearray)) + assert bytes(empty_row[1]) == b"" + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +@pytest.mark.crash_guard +def test_lob_error_path_after_close_no_segfault_subprocess(run_in_subprocess): + code = textwrap.dedent( + """ + import uuid + import dmPython + + table = "DMPY_P0_CLOSE_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5237, + ) + cur = conn.cursor() + try: + payload = ("x" * 2400) + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, c CLOB)") + cur.execute(f"INSERT INTO {table} (id, c) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT c FROM {table} WHERE id = 1") + row = cur.fetchone() + assert row and isinstance(row[0], str) + cur.execute(f"DROP TABLE {table}") + conn.commit() + finally: + cur.close() + conn.close() + + try: + cur.execute("SELECT 1") + raise AssertionError("expected closed-handle error") + except Exception as exc: + print("CLOSED_ERROR", type(exc).__name__, str(exc)) + """ + ) + result = run_in_subprocess(code) + _assert_subprocess_ok(result, "LOB close-path crash guard") + stdout = result.stdout.lower() + assert "closed_error" in stdout + assert ("closed" in stdout) or ("invalid" in stdout) or ("not open" in stdout) diff --git a/tests/integration/test_p0_stability.py b/tests/integration/test_p0_stability.py new file mode 100644 index 0000000..b274eab --- /dev/null +++ b/tests/integration/test_p0_stability.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +import textwrap + +import pytest + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p0_stability] + + +def _assert_subprocess_ok(result, label: str) -> None: + assert result.returncode == 0, ( + f"{label} failed\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + + +@pytest.mark.crash_guard +def test_lob_clob_roundtrip_no_crash(run_in_subprocess): + code = textwrap.dedent( + """ + import uuid + import dmPython + + table = "DMPY_CLOB_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5237, + ) + cur = conn.cursor() + try: + payload = ("中文🚀" * 700)[:2000] + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, c CLOB)") + cur.execute(f"INSERT INTO {table} (id, c) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT c FROM {table} WHERE id = 1") + value = cur.fetchone()[0] + assert isinstance(value, str), type(value) + assert value == payload + print("OK:CLOB") + finally: + try: + cur.execute(f"DROP TABLE {table}") + conn.commit() + except Exception: + pass + cur.close() + conn.close() + """ + ) + result = run_in_subprocess(code) + _assert_subprocess_ok(result, "CLOB roundtrip") + assert "OK:CLOB" in result.stdout + + +@pytest.mark.crash_guard +def test_lob_blob_roundtrip_no_crash(run_in_subprocess): + code = textwrap.dedent( + """ + import uuid + import dmPython + + table = "DMPY_BLOB_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5237, + ) + cur = conn.cursor() + try: + payload = bytes(range(256)) * 12 + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, b BLOB)") + cur.execute(f"INSERT INTO {table} (id, b) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT b FROM {table} WHERE id = 1") + value = cur.fetchone()[0] + assert isinstance(value, (bytes, bytearray)), type(value) + assert bytes(value) == payload + print("OK:BLOB") + finally: + try: + cur.execute(f"DROP TABLE {table}") + conn.commit() + except Exception: + pass + cur.close() + conn.close() + """ + ) + result = run_in_subprocess(code) + _assert_subprocess_ok(result, "BLOB roundtrip") + assert "OK:BLOB" in result.stdout + + +@pytest.mark.crash_guard +def test_lob_error_path_no_segfault_subprocess(run_in_subprocess): + code = textwrap.dedent( + """ + import gc + import uuid + import dmPython + + table = "DMPY_LERR_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect( + user="SYSDBA", + password="SYSDBA001", + server="localhost", + port=5237, + ) + cur = conn.cursor() + try: + payload = "x" * 3000 + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, c CLOB)") + cur.execute(f"INSERT INTO {table} (id, c) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT c FROM {table} WHERE id = 1") + row = cur.fetchone() + assert row and isinstance(row[0], str) + gc.collect() + print("OK:NO_SEGFAULT") + finally: + try: + cur.execute(f"DROP TABLE {table}") + conn.commit() + except Exception: + pass + cur.close() + conn.close() + """ + ) + result = run_in_subprocess(code) + _assert_subprocess_ok(result, "LOB crash guard") + assert "OK:NO_SEGFAULT" in result.stdout + + +def test_closed_handle_operations_raise_not_crash(conn): + cur = conn.cursor() + cur.execute("SELECT 1") + cur.close() + + with pytest.raises(Exception): + cur.execute("SELECT 1") + + conn.close() + with pytest.raises(Exception): + conn.cursor() diff --git a/tests/integration/test_p1_contract.py b/tests/integration/test_p1_contract.py new file mode 100644 index 0000000..498b13d --- /dev/null +++ b/tests/integration/test_p1_contract.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +import uuid + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p1_contract] + + +def test_context_manager_success_and_exception_paths(conn_params): + with dmPython.connect(**conn_params) as conn: + with conn.cursor() as cur: + cur.execute("SELECT 1") + assert cur.fetchone() == (1,) + + with pytest.raises(Exception): + conn.cursor() + + conn2 = None + with pytest.raises(RuntimeError): + with dmPython.connect(**conn_params) as conn2: + with conn2.cursor() as cur2: + cur2.execute("SELECT 1") + assert cur2.fetchone() == (1,) + raise RuntimeError("force context exit") + + assert conn2 is not None + with pytest.raises(Exception): + conn2.cursor() + + +def test_prepare_execute_contract(conn): + cur = conn.cursor() + table_name = f"DMPY_PREP_{uuid.uuid4().hex[:8].upper()}" + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(20))") + cur.prepare(f"INSERT INTO {table_name} VALUES (?, ?)") + assert "INSERT INTO" in str(cur.statement).upper() + + cur.execute(f"INSERT INTO {table_name} VALUES (?, ?)", (1, "ok")) + conn.commit() + + cur.execute(f"SELECT v FROM {table_name} WHERE id = 1") + assert cur.fetchone() == ("ok",) + finally: + try: + cur.execute(f"DROP TABLE {table_name}") + conn.commit() + except Exception: + pass + cur.close() + + +def test_setinputsizes_and_var_contract(cursor): + bind_vars = cursor.setinputsizes(int, str) + assert isinstance(bind_vars, list) + assert len(bind_vars) == 2 + + var_obj = cursor.var(int) + assert var_obj is not None + assert "BIGINT" in type(var_obj).__name__.upper() + + +def test_callproc_callfunc_contract(cursor): + with pytest.raises(dmPython.DatabaseError): + cursor.callproc("sp_not_exists_for_contract", []) + + with pytest.raises(dmPython.DatabaseError): + cursor.callfunc("fn_not_exists_for_contract", int, []) + + +def test_not_supported_api_contract(cursor): + not_supported_error = getattr(dmPython, "NotSupportedError", Exception) + + with pytest.raises(not_supported_error): + cursor.parse("SELECT 1") + + with pytest.raises(not_supported_error): + cursor.arrayvar(int, [1, 2, 3]) + + with pytest.raises(not_supported_error): + cursor.bindnames() + + +def test_connection_attr_contract(conn): + original_autocommit = int(conn.autocommit) + conn.autocommit = 1 + assert int(conn.autocommit) == 1 + conn.autocommit = 0 + assert int(conn.autocommit) == 0 + conn.autocommit = original_autocommit + + current_iso = int(conn.txn_isolation) + conn.txn_isolation = 2 + assert int(conn.txn_isolation) == 2 + conn.txn_isolation = current_iso + + assert isinstance(str(conn.version), str) + assert len(str(conn.version)) > 0 diff --git a/tests/integration/test_p1_contract_ext.py b/tests/integration/test_p1_contract_ext.py new file mode 100644 index 0000000..85650c4 --- /dev/null +++ b/tests/integration/test_p1_contract_ext.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p1_contract] + + +def test_executemany_generator_partial_failure_contract(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P1_EXM") + cur = conn.cursor() + original_autocommit = int(conn.autocommit) + try: + conn.autocommit = 0 + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(32))") + conn.commit() + + def row_gen(): + yield (1, "ok_1") + yield (2, "ok_2") + yield (1, "dup_pk") + + with pytest.raises(dmPython.DatabaseError) as excinfo: + cur.executemany(f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", row_gen()) + assert "[CODE:" in str(excinfo.value) + + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + count_before_rollback = int(cur.fetchone()[0]) + assert count_before_rollback >= 1 + + conn.rollback() + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + count_after_rollback = int(cur.fetchone()[0]) + assert count_after_rollback == 0 + finally: + try: + drop_table(cur, table_name) + conn.commit() + except Exception: + pass + conn.autocommit = original_autocommit + cur.close() + + +def test_cursor_reuse_after_statement_error_contract(cursor): + with pytest.raises(dmPython.DatabaseError): + cursor.execute("SELECT * FROM TABLE_NOT_EXISTS_ABC") + + cursor.execute("SELECT 1") + assert cursor.fetchone() == (1,) + + +def test_not_supported_error_message_contract_ext(cursor): + not_supported_error = getattr(dmPython, "NotSupportedError", Exception) + + with pytest.raises(not_supported_error) as parse_error: + cursor.parse("SELECT 1") + assert "not support" in str(parse_error.value).lower() + + with pytest.raises(not_supported_error) as arrayvar_error: + cursor.arrayvar(int, [1, 2, 3]) + assert "not support" in str(arrayvar_error.value).lower() + + with pytest.raises(not_supported_error) as bindnames_error: + cursor.bindnames() + assert "not support" in str(bindnames_error.value).lower() + + +def test_callproc_callfunc_argument_error_contract(cursor): + with pytest.raises(dmPython.DatabaseError) as proc_error: + cursor.callproc("sp_not_exists_for_contract", [1, "x"]) + proc_text = str(proc_error.value) + assert proc_text + assert "[CODE:" in proc_text + + with pytest.raises(dmPython.DatabaseError) as func_error: + cursor.callfunc("fn_not_exists_for_contract", int, [1, "x"]) + func_text = str(func_error.value) + assert func_text + assert "[CODE:" in func_text diff --git a/tests/integration/test_p1_cursor_state_contract.py b/tests/integration/test_p1_cursor_state_contract.py new file mode 100644 index 0000000..af2996f --- /dev/null +++ b/tests/integration/test_p1_cursor_state_contract.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import uuid + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p1_contract] + + +def _table_name(prefix: str) -> str: + return f"{prefix}_{uuid.uuid4().hex[:8].upper()}" + + +def _proc_name(prefix: str) -> str: + return f"{prefix}_{uuid.uuid4().hex[:8].upper()}" + + +def test_rowcount_lifecycle_contract(conn): + table_name = _table_name("DMPY_P1_RC") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(32))") + assert int(cur.rowcount) == -1 + + cur.execute(f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", (1, "a")) + conn.commit() + assert int(cur.rowcount) == 1 + + cur.execute(f"UPDATE {table_name} SET v = ? WHERE id = ?", ("b", 1)) + conn.commit() + assert int(cur.rowcount) == 1 + + cur.execute(f"DELETE FROM {table_name} WHERE id = ?", (1,)) + conn.commit() + assert int(cur.rowcount) == 1 + + cur.execute(f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", (2, "c")) + conn.commit() + cur.execute(f"SELECT id, v FROM {table_name} ORDER BY id") + row = cur.fetchone() + assert row == (2, "c") + assert int(cur.rowcount) >= 1 + finally: + try: + cur.execute(f"DROP TABLE {table_name}") + conn.commit() + except Exception: + pass + cur.close() + + +def test_lastrowid_contract_dml_paths(conn): + table_name = _table_name("DMPY_P1_LRID") + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(32))") + conn.commit() + cur.execute(f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", (1, "a")) + conn.commit() + lastrowid = cur.lastrowid + assert (lastrowid is None) or isinstance(lastrowid, (int, str, bytes, bytearray)) + + cur.execute(f"UPDATE {table_name} SET v = ? WHERE id = ?", ("b", 1)) + conn.commit() + _ = cur.lastrowid + finally: + try: + cur.execute(f"DROP TABLE {table_name}") + conn.commit() + except Exception: + pass + cur.close() + + +def test_error_object_contract_dmerror_fields(cursor): + with pytest.raises(dmPython.DatabaseError) as excinfo: + cursor.execute("SELECT * FROM NO_SUCH_TABLE_ABC") + + assert excinfo.value.args + dm_error = excinfo.value.args[0] + assert type(dm_error).__name__ == "DmError" + assert hasattr(dm_error, "code") + assert hasattr(dm_error, "message") + assert hasattr(dm_error, "context") + assert isinstance(dm_error.code, int) + assert isinstance(dm_error.message, str) and dm_error.message + assert isinstance(dm_error.context, str) and dm_error.context + + +def test_executemany_partial_failure_autocommit_matrix(conn): + table_name = _table_name("DMPY_P1_ACM") + cur = conn.cursor() + original_autocommit = int(conn.autocommit) + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(32))") + conn.commit() + + conn.autocommit = 0 + with pytest.raises(dmPython.DatabaseError): + cur.executemany( + f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", + [(1, "a"), (2, "b"), (1, "dup")], + ) + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert int(cur.fetchone()[0]) == 2 + conn.rollback() + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert int(cur.fetchone()[0]) == 0 + + conn.autocommit = 1 + with pytest.raises(dmPython.DatabaseError): + cur.executemany( + f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", + [(11, "x"), (12, "y"), (11, "dup")], + ) + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert int(cur.fetchone()[0]) == 2 + finally: + conn.autocommit = original_autocommit + try: + cur.execute(f"DROP TABLE {table_name}") + conn.commit() + except Exception: + pass + cur.close() + + +def test_nextset_contract_when_not_supported(cursor): + cursor.execute("SELECT 1") + assert cursor.nextset() is None + + +def test_output_stream_and_setoutputsize_contract(cursor): + assert int(cursor.output_stream) == 0 + cursor.output_stream = 1 + assert int(cursor.output_stream) == 1 + cursor.output_stream = 0 + assert int(cursor.output_stream) == 0 + + cursor.setoutputsize(2048) + cursor.setoutputsize(1024, 0) + + +def test_callproc_minimal_success_contract(conn): + proc_name = _proc_name("P_DMPY_P1_MIN") + cur = conn.cursor() + ddl = f""" + CREATE OR REPLACE PROCEDURE {proc_name}(p_in IN INT) AS + BEGIN + NULL; + END; + """ + try: + cur.execute(ddl) + conn.commit() + result = cur.callproc(proc_name, [41]) + assert isinstance(result, list) + assert result == [41] + finally: + try: + cur.execute(f"DROP PROCEDURE {proc_name}") + conn.commit() + except Exception: + pass + cur.close() diff --git a/tests/integration/test_p2_resilience_ext.py b/tests/integration/test_p2_resilience_ext.py new file mode 100644 index 0000000..a7e61e6 --- /dev/null +++ b/tests/integration/test_p2_resilience_ext.py @@ -0,0 +1,212 @@ +from __future__ import annotations + +import gc +import random +import textwrap +import threading +import uuid + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p2_scale] + +_TEXT_PATTERNS = ("中文🚀A", "稳态中文🚀X", "A中文🚀", "🚀🚀🚀A", "纯中文测试") + + +def _table_name(prefix: str) -> str: + return f"{prefix}_{uuid.uuid4().hex[:8].upper()}" + + +def _make_text(size: int) -> str: + if size <= 0: + return "" + base = _TEXT_PATTERNS[(size // 1024) % len(_TEXT_PATTERNS)] + return (base * ((size // len(base)) + 2))[:size] + + +def _make_blob(size: int) -> bytes: + if size <= 0: + return b"" + return bytes((i * 17) % 256 for i in range(size)) + + +def test_connection_close_race_during_fetch_no_crash(run_in_subprocess): + code = textwrap.dedent( + """ + import threading + import uuid + import dmPython + + table = "DMPY_P2_RACE_" + uuid.uuid4().hex[:8].upper() + conn = dmPython.connect(user="SYSDBA", password="SYSDBA001", server="localhost", port=5237) + cur = conn.cursor() + cur.execute(f"CREATE TABLE {table} (id INT PRIMARY KEY, v VARCHAR(64))") + cur.executemany(f"INSERT INTO {table} (id, v) VALUES (?, ?)", [(i, f"v{i}") for i in range(1, 2001)]) + conn.commit() + + errors = [] + + def fetch_worker(): + c = conn.cursor() + try: + c.arraysize = 64 + c.execute(f"SELECT id, v FROM {table} ORDER BY id") + while True: + rows = c.fetchmany(64) + if not rows: + break + except Exception as exc: + errors.append(type(exc).__name__) + finally: + try: + c.close() + except Exception: + pass + + def close_worker(): + try: + conn.close() + except Exception as exc: + errors.append(type(exc).__name__) + + t1 = threading.Thread(target=fetch_worker) + t1.start() + t2 = threading.Thread(target=close_worker) + t2.start() + t1.join() + t2.join() + + try: + cur2 = dmPython.connect(user="SYSDBA", password="SYSDBA001", server="localhost", port=5237).cursor() + cur2.execute(f"DROP TABLE {table}") + cur2.connection.commit() + cur2.close() + except Exception: + pass + + print("OK:RACE", ",".join(errors)) + """ + ) + result = run_in_subprocess(code, timeout=240) + assert result.returncode == 0, ( + f"race subprocess failed rc={result.returncode}\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}" + ) + assert result.returncode not in (139, -11) + assert "OK:RACE" in result.stdout + + +def test_multi_cursor_same_connection_isolation_contract(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P2_MCISO") + writer = conn.cursor() + reader1 = conn.cursor() + reader2 = conn.cursor() + try: + writer.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, v VARCHAR(64))") + conn.commit() + + for i in range(1, 101): + writer.execute(f"INSERT INTO {table_name} (id, v) VALUES (?, ?)", (i, f"v{i}")) + if i % 10 == 0: + conn.commit() + reader1.execute(f"SELECT COUNT(*) FROM {table_name}") + c1 = int(reader1.fetchone()[0]) + reader2.execute(f"SELECT MAX(id) FROM {table_name}") + c2 = int(reader2.fetchone()[0]) + assert c1 == i + assert c2 == i + conn.commit() + + reader1.execute(f"SELECT COUNT(*) FROM {table_name}") + assert int(reader1.fetchone()[0]) == 100 + finally: + drop_table(writer, table_name) + conn.commit() + reader2.close() + reader1.close() + writer.close() + + +def test_lob_boundary_randomized_medium_fuzz(conn, table_name_factory, drop_table, boundary_sizes): + table_name = table_name_factory("DMPY_P2_FUZZ") + cur = conn.cursor() + rng = random.Random(20260303) + pool = [size for size in boundary_sizes if size <= 16384] + loops = 200 + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + for i in range(1, loops + 1): + size = rng.choice(pool) + c_payload = _make_text(size) + b_payload = _make_blob(size) + cur.execute( + f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", + (i, c_payload, b_payload), + ) + if i % 20 == 0: + conn.commit() + conn.commit() + + cur.execute(f"SELECT id, c, b FROM {table_name} ORDER BY id") + rows = cur.fetchall() + assert len(rows) == loops + rng_check = random.Random(20260303) + expected_sizes = [rng_check.choice(pool) for _ in range(loops)] + for idx, row in enumerate(rows, start=1): + size = expected_sizes[idx - 1] + assert row[0] == idx + assert row[1] == _make_text(size) + assert bytes(row[2]) == _make_blob(size) + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_reconnect_after_error_burst_contract(conn_params): + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + for _ in range(30): + with pytest.raises(dmPython.DatabaseError): + cur.execute("SELECT * FROM NO_SUCH_TABLE_BURST_ABC") + cur.execute("SELECT 1") + assert cur.fetchone() == (1,) + finally: + cur.close() + conn.close() + + conn2 = dmPython.connect(**conn_params) + cur2 = conn2.cursor() + try: + cur2.execute("SELECT 1") + assert cur2.fetchone() == (1,) + finally: + cur2.close() + conn2.close() + + +def test_churn_gc_loops_env_controlled(conn_params, churn_loops, gc_loops): + for i in range(churn_loops): + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + cur.execute("SELECT 1") + assert cur.fetchone() == (1,) + finally: + cur.close() + conn.close() + + for i in range(gc_loops): + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + cur.execute("SELECT 1") + assert cur.fetchone() == (1,) + finally: + cur.close() + conn.close() + if i % 5 == 0: + gc.collect() diff --git a/tests/integration/test_p2_scale.py b/tests/integration/test_p2_scale.py new file mode 100644 index 0000000..391a82d --- /dev/null +++ b/tests/integration/test_p2_scale.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import gc +import uuid +from concurrent.futures import ThreadPoolExecutor + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p2_scale] + + +def test_large_result_fetch_consistency(conn, table_name_factory, drop_table, stress_rows): + table_name = table_name_factory("DMPY_P2_ROWS") + cur = conn.cursor() + rows = max(200, stress_rows) + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, val VARCHAR(64))") + batch = [(i, f"v{i}") for i in range(1, rows + 1)] + cur.executemany(f"INSERT INTO {table_name} (id, val) VALUES (?, ?)", batch) + conn.commit() + + cur.execute(f"SELECT id FROM {table_name} ORDER BY id") + first = cur.fetchone() + mid = cur.fetchmany(127) + tail = cur.fetchall() + got = [first[0]] + [r[0] for r in mid] + [r[0] for r in tail] + assert got == list(range(1, rows + 1)) + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_multithread_multi_connection_stability(conn_params, table_name_factory, stress_workers): + table_name = table_name_factory("DMPY_P2_CONCUR") + setup_conn = dmPython.connect(**conn_params) + setup_cur = setup_conn.cursor() + setup_cur.execute( + f"CREATE TABLE {table_name} (id INT PRIMARY KEY, worker_id INT, val VARCHAR(32))" + ) + setup_conn.commit() + setup_cur.close() + setup_conn.close() + + workers = max(2, stress_workers) + rows_per_worker = 60 + + def worker(worker_id: int) -> int: + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + for i in range(rows_per_worker): + pk = worker_id * 100000 + i + cur.execute( + f"INSERT INTO {table_name} (id, worker_id, val) VALUES (?, ?, ?)", + (pk, worker_id, f"w{worker_id}_{i}"), + ) + if i % 20 == 0: + cur.execute(f"SELECT COUNT(*) FROM {table_name} WHERE worker_id = ?", (worker_id,)) + cur.fetchone() + conn.commit() + return rows_per_worker + finally: + cur.close() + conn.close() + + with ThreadPoolExecutor(max_workers=workers) as pool: + inserted = sum(pool.map(worker, range(1, workers + 1))) + + verify_conn = dmPython.connect(**conn_params) + verify_cur = verify_conn.cursor() + try: + verify_cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert verify_cur.fetchone()[0] == inserted + finally: + try: + verify_cur.execute(f"DROP TABLE {table_name}") + verify_conn.commit() + except Exception: + pass + verify_cur.close() + verify_conn.close() + + +def test_unicode_and_long_payload_boundary(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P2_UNI") + cur = conn.cursor() + try: + payload = ("中文边界🚀" * 800)[:4000] + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, txt CLOB)") + cur.execute(f"INSERT INTO {table_name} (id, txt) VALUES (?, ?)", (1, payload)) + conn.commit() + cur.execute(f"SELECT txt FROM {table_name} WHERE id = 1") + got = cur.fetchone()[0] + assert got == payload + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_transaction_visibility_across_connections(conn_params, table_name_factory): + table_name = table_name_factory("DMPY_P2_TXN") + conn1 = dmPython.connect(**conn_params) + conn2 = dmPython.connect(**conn_params) + cur1 = conn1.cursor() + cur2 = conn2.cursor() + try: + conn1.autocommit = 0 + cur1.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY)") + conn1.commit() + + cur1.execute(f"INSERT INTO {table_name} (id) VALUES (1)") + cur2.execute(f"SELECT COUNT(*) FROM {table_name}") + assert cur2.fetchone()[0] == 0 + + conn1.commit() + cur2.execute(f"SELECT COUNT(*) FROM {table_name}") + assert cur2.fetchone()[0] == 1 + finally: + try: + cur1.execute(f"DROP TABLE {table_name}") + conn1.commit() + except Exception: + pass + cur2.close() + cur1.close() + conn2.close() + conn1.close() + + +def test_repeated_connect_cursor_gc_loop(conn_params): + loops = 120 + for i in range(loops): + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + cur.execute("SELECT 1") + assert cur.fetchone() == (1,) + cur.close() + conn.close() + if i % 15 == 0: + gc.collect() diff --git a/tests/integration/test_p2_scale_ext.py b/tests/integration/test_p2_scale_ext.py new file mode 100644 index 0000000..5e54ac2 --- /dev/null +++ b/tests/integration/test_p2_scale_ext.py @@ -0,0 +1,181 @@ +from __future__ import annotations + +import gc +from concurrent.futures import ThreadPoolExecutor + +import pytest + +import dmPython + + +pytestmark = [pytest.mark.requires_dm, pytest.mark.p2_scale] + + +def test_fetchmany_arraysize_matrix_consistency(conn, table_name_factory, drop_table, stress_rows): + table_name = table_name_factory("DMPY_P2_ARR") + cur = conn.cursor() + rows = max(512, stress_rows // 2) + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, val VARCHAR(64))") + cur.executemany( + f"INSERT INTO {table_name} (id, val) VALUES (?, ?)", + [(i, f"v{i}") for i in range(1, rows + 1)], + ) + conn.commit() + + cur.execute(f"SELECT id FROM {table_name} ORDER BY id") + baseline = [row[0] for row in cur.fetchall()] + assert baseline == list(range(1, rows + 1)) + + for arr in (1, 16, 128, 512): + c = conn.cursor() + try: + c.arraysize = arr + c.execute(f"SELECT id FROM {table_name} ORDER BY id") + first = c.fetchone() + assert first is not None + second_batch = c.fetchmany(max(1, arr // 2)) + remain = c.fetchall() + got = [first[0]] + [r[0] for r in second_batch] + [r[0] for r in remain] + assert got == baseline + finally: + c.close() + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_lob_mixed_read_write_multithread_multi_connection( + conn_params, table_name_factory, stress_workers +): + table_name = table_name_factory("DMPY_P2_LOBMT") + setup_conn = dmPython.connect(**conn_params) + setup_cur = setup_conn.cursor() + setup_cur.execute( + f"CREATE TABLE {table_name} (id INT PRIMARY KEY, worker_id INT, c CLOB, b BLOB)" + ) + setup_conn.commit() + setup_cur.close() + setup_conn.close() + + workers = max(2, stress_workers) + rows_per_worker = 15 + + def worker(worker_id: int) -> int: + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + for i in range(rows_per_worker): + pk = worker_id * 100000 + i + c_payload = (f"w{worker_id}-" + ("中🚀" * 500))[:1800] + b_payload = bytes([worker_id % 256]) * 2048 + cur.execute( + f"INSERT INTO {table_name} (id, worker_id, c, b) VALUES (?, ?, ?, ?)", + (pk, worker_id, c_payload, b_payload), + ) + cur.execute(f"SELECT c, b FROM {table_name} WHERE id = ?", (pk,)) + row = cur.fetchone() + assert row is not None + assert isinstance(row[0], str) + assert isinstance(row[1], (bytes, bytearray)) + assert row[0] == c_payload + assert bytes(row[1]) == b_payload + conn.commit() + return rows_per_worker + finally: + cur.close() + conn.close() + + with ThreadPoolExecutor(max_workers=workers) as pool: + inserted = sum(pool.map(worker, range(1, workers + 1))) + + verify_conn = dmPython.connect(**conn_params) + verify_cur = verify_conn.cursor() + try: + verify_cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert int(verify_cur.fetchone()[0]) == inserted + finally: + try: + verify_cur.execute(f"DROP TABLE {table_name}") + verify_conn.commit() + except Exception: + pass + verify_cur.close() + verify_conn.close() + + +def test_connection_churn_with_lob_roundtrip(conn_params, table_name_factory): + table_name = table_name_factory("DMPY_P2_CHURN") + setup_conn = dmPython.connect(**conn_params) + setup_cur = setup_conn.cursor() + setup_cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + setup_conn.commit() + setup_cur.close() + setup_conn.close() + + loops = 90 + try: + for i in range(1, loops + 1): + conn = dmPython.connect(**conn_params) + cur = conn.cursor() + try: + c_payload = (f"loop-{i}-" + ("文" * 200))[:1200] + b_payload = bytes([i % 256]) * 256 + cur.execute( + f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", + (i, c_payload, b_payload), + ) + conn.commit() + cur.execute(f"SELECT c, b FROM {table_name} WHERE id = ?", (i,)) + row = cur.fetchone() + assert row is not None + assert row[0] == c_payload + assert bytes(row[1]) == b_payload + cur.execute(f"DELETE FROM {table_name} WHERE id = ?", (i,)) + conn.commit() + finally: + cur.close() + conn.close() + finally: + cleanup_conn = dmPython.connect(**conn_params) + cleanup_cur = cleanup_conn.cursor() + try: + cleanup_cur.execute(f"DROP TABLE {table_name}") + cleanup_conn.commit() + except Exception: + pass + cleanup_cur.close() + cleanup_conn.close() + + +def test_long_gc_loop_with_lob_objects(conn, table_name_factory, drop_table): + table_name = table_name_factory("DMPY_P2_GCLOB") + cur = conn.cursor() + loops = 120 + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, c CLOB, b BLOB)") + conn.commit() + for i in range(1, loops + 1): + c_payload = ("gc-loop-" + ("中" * 300))[:900] + b_payload = bytes([i % 256]) * 128 + cur.execute( + f"INSERT INTO {table_name} (id, c, b) VALUES (?, ?, ?)", + (i, c_payload, b_payload), + ) + conn.commit() + + cur.execute(f"SELECT c, b FROM {table_name} WHERE id = ?", (i,)) + row = cur.fetchone() + assert row is not None + assert row[0] == c_payload + assert bytes(row[1]) == b_payload + + cur.execute(f"DELETE FROM {table_name} WHERE id = ?", (i,)) + conn.commit() + if i % 10 == 0: + gc.collect() + finally: + drop_table(cur, table_name) + conn.commit() + cur.close() diff --git a/tests/test_dm_integration.py b/tests/test_dm_integration.py new file mode 100644 index 0000000..55edc76 --- /dev/null +++ b/tests/test_dm_integration.py @@ -0,0 +1,263 @@ +"""Integration tests for dmPython against a running DM database. + +Defaults target a local Docker container: + host=localhost, port=5237, user=SYSDBA, password=SYSDBA001 +Override with environment variables: + DM_TEST_HOST, DM_TEST_PORT, DM_TEST_USER, DM_TEST_PASSWORD +""" + +from __future__ import annotations + +import datetime as dt +import os +import uuid +from decimal import Decimal + +import pytest + +import dmPython + +pytestmark = [pytest.mark.requires_dm] + + +def _conn_params() -> dict[str, object]: + return { + "user": os.getenv("DM_TEST_USER", "SYSDBA"), + "password": os.getenv("DM_TEST_PASSWORD", "SYSDBA001"), + "server": os.getenv("DM_TEST_HOST", "localhost"), + "port": int(os.getenv("DM_TEST_PORT", "5237")), + } + + +def _new_table_name(prefix: str = "DMPY_TEST") -> str: + return f"{prefix}_{uuid.uuid4().hex[:10].upper()}" + + +def _drop_table(cursor, table_name: str) -> None: + try: + cursor.execute(f"DROP TABLE {table_name}") + except Exception: + # Ignore missing table or other cleanup-time failures. + pass + + +@pytest.fixture() +def conn(): + c = dmPython.connect(**_conn_params()) + yield c + c.close() + + +@pytest.fixture() +def cursor(conn): + cur = conn.cursor() + yield cur + cur.close() + + +def test_connect_and_select_one(cursor): + cursor.execute("SELECT 1") + assert cursor.fetchone() == (1,) + + +def test_query_server_version(cursor): + cursor.execute("SELECT * FROM V$VERSION") + rows = cursor.fetchall() + assert len(rows) > 0 + + +def test_parameterized_insert_with_unicode_and_null(conn): + table_name = _new_table_name() + cur = conn.cursor() + try: + cur.execute( + f""" + CREATE TABLE {table_name} ( + id INT PRIMARY KEY, + name VARCHAR(100), + note VARCHAR(100) + ) + """ + ) + cur.execute( + f"INSERT INTO {table_name} (id, name, note) VALUES (?, ?, ?)", + (1, "中文🚀", None), + ) + conn.commit() + + cur.execute(f"SELECT name, note FROM {table_name} WHERE id = ?", (1,)) + row = cur.fetchone() + assert row[0] == "中文🚀" + assert row[1] is None + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_executemany_bulk_insert(conn): + table_name = _new_table_name() + cur = conn.cursor() + try: + cur.execute( + f"CREATE TABLE {table_name} (id INT PRIMARY KEY, val VARCHAR(32))" + ) + rows = [(1, "a"), (2, "b"), (3, "c"), (4, "d")] + cur.executemany( + f"INSERT INTO {table_name} (id, val) VALUES (?, ?)", + rows, + ) + conn.commit() + + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert cur.fetchone()[0] == 4 + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_transaction_rollback(conn): + table_name = _new_table_name() + cur = conn.cursor() + try: + conn.autocommit = False + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY)") + conn.commit() + + cur.execute(f"INSERT INTO {table_name} VALUES (100)") + conn.rollback() + + cur.execute(f"SELECT COUNT(*) FROM {table_name}") + assert cur.fetchone()[0] == 0 + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_transaction_commit_persists(conn): + table_name = _new_table_name() + cur = conn.cursor() + cur2 = conn.cursor() + try: + conn.autocommit = False + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY)") + conn.commit() + + cur.execute(f"INSERT INTO {table_name} VALUES (200)") + conn.commit() + + cur2.execute(f"SELECT COUNT(*) FROM {table_name}") + assert cur2.fetchone()[0] == 1 + finally: + _drop_table(cur, table_name) + conn.commit() + cur2.close() + cur.close() + + +def test_fetchone_fetchmany_fetchall(conn): + table_name = _new_table_name() + cur = conn.cursor() + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY)") + cur.executemany( + f"INSERT INTO {table_name} (id) VALUES (?)", + [(1,), (2,), (3,), (4,), (5,)], + ) + conn.commit() + + cur.execute(f"SELECT id FROM {table_name} ORDER BY id") + assert cur.fetchone() == (1,) + assert cur.fetchmany(2) == [(2,), (3,)] + assert cur.fetchall() == [(4,), (5,)] + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_cursor_description(cursor): + cursor.execute("SELECT 1 AS col_a, 'x' AS col_b") + assert cursor.description is not None + assert len(cursor.description) == 2 + assert cursor.description[0][0].upper() == "COL_A" + assert cursor.description[1][0].upper() == "COL_B" + + +def test_datetime_round_trip(conn): + table_name = _new_table_name() + cur = conn.cursor() + expected = dt.datetime(2024, 1, 2, 3, 4, 5) + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, ts TIMESTAMP)") + cur.execute( + f"INSERT INTO {table_name} (id, ts) VALUES (?, ?)", + (1, expected), + ) + conn.commit() + + cur.execute(f"SELECT ts FROM {table_name} WHERE id = 1") + actual = cur.fetchone()[0] + if isinstance(actual, dt.datetime): + assert actual.replace(microsecond=0) == expected + else: + assert isinstance(actual, str) + assert actual.startswith("2024-01-02 03:04:05") + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_decimal_round_trip(conn): + table_name = _new_table_name() + cur = conn.cursor() + expected = Decimal("12345.678901") + try: + cur.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, n DECIMAL(18, 6))") + cur.execute( + f"INSERT INTO {table_name} (id, n) VALUES (?, ?)", + (1, expected), + ) + conn.commit() + + cur.execute(f"SELECT n FROM {table_name} WHERE id = 1") + actual = cur.fetchone()[0] + assert Decimal(str(actual)).quantize(Decimal("0.000001")) == expected + finally: + _drop_table(cur, table_name) + conn.commit() + cur.close() + + +def test_invalid_sql_raises_database_error(cursor): + with pytest.raises(dmPython.DatabaseError): + cursor.execute("SELECT * FROM TABLE_NOT_EXISTS_ABC") + + +def test_multiple_cursors_can_read_independently(conn): + c1 = conn.cursor() + c2 = conn.cursor() + table_name = _new_table_name() + try: + c1.execute(f"CREATE TABLE {table_name} (id INT PRIMARY KEY, val VARCHAR(10))") + c1.executemany( + f"INSERT INTO {table_name} (id, val) VALUES (?, ?)", + [(1, "a"), (2, "b"), (3, "c")], + ) + conn.commit() + + c1.execute(f"SELECT id FROM {table_name} ORDER BY id") + c2.execute(f"SELECT val FROM {table_name} ORDER BY id") + + assert c1.fetchone() == (1,) + assert c2.fetchone() == ("a",) + assert c1.fetchall() == [(2,), (3,)] + assert c2.fetchall() == [("b",), ("c",)] + finally: + _drop_table(c1, table_name) + conn.commit() + c2.close() + c1.close() diff --git a/tests/test_version_metadata.py b/tests/test_version_metadata.py new file mode 100644 index 0000000..de05375 --- /dev/null +++ b/tests/test_version_metadata.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import importlib.util +from pathlib import Path +import re + +import dmPython + + +ROOT = Path(__file__).resolve().parents[1] + + +def _project_version() -> str: + text = (ROOT / "pyproject.toml").read_text(encoding="utf-8") + match = re.search(r'^\s*version\s*=\s*"([^"]+)"\s*$', text, re.MULTILINE) + assert match is not None + return match.group(1) + + +def _load_smoke_script_module(): + script_path = ROOT / "scripts" / "test_connection.py" + spec = importlib.util.spec_from_file_location("test_connection_script", script_path) + assert spec is not None + assert spec.loader is not None + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +def test_module_version_matches_project_metadata(): + assert dmPython.version == _project_version() + + +def test_smoke_script_uses_dynamic_expected_version(): + module = _load_smoke_script_module() + assert module.get_expected_version() == _project_version() + + script_text = (ROOT / "scripts" / "test_connection.py").read_text(encoding="utf-8") + assert 'dmPython.version == "2.5.30"' not in script_text