Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ Ubuntu 24.04:
```bash
sudo apt-get -y update
sudo apt-get -y install build-essential ca-certificates ccache clang cmake git \
libidn11-dev libssl-dev lld ninja-build pkg-config python3 ragel unixodbc-dev yasm
libidn11-dev libssl-dev lld ninja-build odbcinst pkg-config python3 ragel \
unixodbc-dev yasm
```

`unixodbc-dev` is only required when configuring with `YDB_SDK_ODBC=ON`.
Expand All @@ -36,16 +37,19 @@ Fedora 43:

```bash
sudo dnf install -y ccache cmake gcc gcc-c++ git libidn-devel \
ninja-build openssl-devel openssl-devel-engine pkgconf-pkg-config python3 ragel yasm
ninja-build openssl-devel openssl-devel-engine pkgconf-pkg-config python3 ragel \
unixODBC-devel yasm
```

macOS 14:

```bash
xcode-select --install # if the Command Line Tools are not installed yet
brew install ccache cmake git libidn ninja openssl@3 python ragel yasm
brew install ccache cmake git libidn libiodbc ninja openssl@3 python ragel yasm
```

`libiodbc` is only required when configuring with `YDB_SDK_ODBC=ON`.

### Clone the ydb-cpp-sdk repository

```bash
Expand Down Expand Up @@ -84,18 +88,21 @@ The SDK can be packaged as Debian development packages with CPack. The complete
- `libydb-cpp-iam-dev` — IAM credentials plugin;
- `libydb-cpp-otel-metrics-dev` — OpenTelemetry metrics plugin;
- `libydb-cpp-otel-tracing-dev` — OpenTelemetry tracing plugin (requires `libydb-cpp-otel-metrics-dev` for OTel headers/libs).
- `ydb-odbc` — YDB ODBC driver and unixODBC registration template.

The CPack-only packaging flow is intended for Ubuntu 24.04. It builds and
installs the Google common-protos package before packaging the four SDK
components, so all five packages use the distro protobuf ABI:
installs the Google common-protos package before packaging the SDK components,
so all six packages use the distro protobuf ABI:

```bash
./scripts/build_cpack_deb_packages.sh build-deb/packages
```

The generated `.deb` files are placed into `build-deb/packages/` and install
under `/usr/share/yandex`. The IAM and OTel packages require the matching core
version; tracing additionally requires the matching metrics package.
The generated `.deb` files are placed into `build-deb/packages/`. SDK files
install under `/usr/share/yandex`; the ODBC driver installs under the system
multiarch library directory with its template under `/usr/share/ydb-odbc`.
The IAM and OTel packages require the matching core version; tracing
additionally requires the matching metrics package.

To smoke-test generated `.deb` packages with the sample consumer project:

Expand Down
1 change: 1 addition & 0 deletions cmake/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ function(vcs_info Tgt)
DEPENDS ${YDB_SDK_SOURCE_DIR}/scripts/vcs_info.py ${YDB_SDK_SOURCE_DIR}/scripts/c_templates/svn_interface.c ${CMAKE_CURRENT_BINARY_DIR}/vcs_info.json
)
target_sources(${Tgt} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/__vcs_version__.c)
target_include_directories(${Tgt} PRIVATE ${YDB_SDK_SOURCE_DIR})
endfunction()

function(resources Tgt Output)
Expand Down
10 changes: 4 additions & 6 deletions cmake/dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,11 @@ else()
NAME RapidJSON
GITHUB_REPOSITORY Tencent/rapidjson
GIT_TAG v${YDB_SDK_RAPIDJSON_VERSION}
EXCLUDE_FROM_ALL YES
OPTIONS
"RAPIDJSON_BUILD_DOC OFF"
"RAPIDJSON_BUILD_EXAMPLES OFF"
"RAPIDJSON_BUILD_TESTS OFF"
"RAPIDJSON_BUILD_THIRDPARTY_GTEST OFF"
DOWNLOAD_ONLY YES
)
# RapidJSON is header-only. Adding its CMake project would globally set
# RULE_LAUNCH_COMPILE and RULE_LAUNCH_LINK when ccache is installed,
# duplicating our compiler launcher and wrapping non-compiler commands.
if(NOT TARGET RapidJSON::RapidJSON)
add_library(RapidJSON::RapidJSON INTERFACE IMPORTED GLOBAL)
target_include_directories(RapidJSON::RapidJSON INTERFACE
Expand Down
6 changes: 5 additions & 1 deletion cmake/testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,13 @@ if (YDB_SDK_ODBC)
target_compile_definitions(${ODBC_TEST_NAME}
PRIVATE
ODBC_DRIVER_PATH="$<TARGET_FILE:ydb-odbc>"
ODBC_TEST_ODBCINI="${CMAKE_BINARY_DIR}/odbc/odbc.ini"
ODBC_DRIVER_VERSION="${YDB_SDK_VERSION}"
ODBC_TEST_ODBCINI="${YDB_ODBC_TEST_INI}"
ODBC_TEST_ODBCSYSINI="${CMAKE_BINARY_DIR}/odbc"
)
if (ODBC_LIBRARY MATCHES "[iI][oO][dD][bB][cC]")
target_compile_definitions(${ODBC_TEST_NAME} PRIVATE ODBC_TEST_IODBC=1)
endif()

add_dependencies(${ODBC_TEST_NAME} ydb-odbc)
endfunction()
Expand Down
56 changes: 54 additions & 2 deletions odbc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,36 @@ add_library(ydb-odbc SHARED
src/descriptor.cpp
)

get_filename_component(_ydb_odbc_library_dir "${ODBC_LIBRARY}" DIRECTORY)
get_filename_component(_ydb_odbc_library_name "${ODBC_LIBRARY}" NAME)
if (WIN32)
set(_ydb_odbcinst_names odbccp32)
elseif (_ydb_odbc_library_name MATCHES "[iI][oO][dD][bB][cC]")
set(_ydb_odbcinst_names iodbcinst)
else()
set(_ydb_odbcinst_names odbcinst)
endif()
find_library(YDB_ODBCINST_LIBRARY
NAMES ${_ydb_odbcinst_names}
HINTS "${_ydb_odbc_library_dir}"
REQUIRED
)
unset(_ydb_odbc_library_dir)
unset(_ydb_odbc_library_name)
unset(_ydb_odbcinst_names)

target_include_directories(ydb-odbc
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
${ODBC_INCLUDE_DIRS}
)

target_compile_definitions(ydb-odbc
PRIVATE
YDB_ODBC_DRIVER_VERSION="${YDB_SDK_VERSION}"
)

target_link_libraries(ydb-odbc
PRIVATE
YDB-CPP-SDK::Query
Expand All @@ -34,10 +57,24 @@ target_link_libraries(ydb-odbc
YDB-CPP-SDK::Credentials
YDB-CPP-SDK::Helpers
YDB-CPP-SDK::Iam
ODBC::ODBC
odbcinst
${YDB_ODBCINST_LIBRARY}
)

if (APPLE)
add_executable(ydb-odbc-register-macos
packaging/register_macos.cpp
)
target_include_directories(ydb-odbc-register-macos
PRIVATE
${ODBC_INCLUDE_DIRS}
)
target_link_libraries(ydb-odbc-register-macos
PRIVATE
${YDB_ODBCINST_LIBRARY}
)
add_dependencies(ydb-odbc ydb-odbc-register-macos)
endif()

set_target_properties(ydb-odbc PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
Expand Down Expand Up @@ -118,6 +155,21 @@ install(TARGETS ydb-odbc
COMPONENT ydb-odbc
)

if (APPLE)
install(CODE "
if (\"\$ENV{DESTDIR}\" STREQUAL \"\")
execute_process(
COMMAND \"$<TARGET_FILE:ydb-odbc-register-macos>\"
\"${YDB_ODBC_DRIVER_PATH}\"
RESULT_VARIABLE _ydb_odbc_register_result
)
if (NOT _ydb_odbc_register_result EQUAL 0)
message(FATAL_ERROR \"Failed to register the YDB ODBC driver with iODBC\")
endif()
endif()
" COMPONENT ydb-odbc)
endif()

if (YDB_SDK_EXAMPLES)
add_subdirectory(examples)
endif()
Expand Down
117 changes: 102 additions & 15 deletions odbc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,39 @@ ODBC driver for YDB.

## Requirements

- CMake 3.10 or higher
- CMake 3.22 or higher
- C/C++ compiler with C11 and C++20 support
- YDB C++ SDK (build with `YDB_SDK_ODBC=ON`)
- unixODBC development packages (`unixodbc`, `unixodbc-dev` on Debian/Ubuntu)
- Linux: unixODBC development packages and `odbcinst`
- macOS: iODBC development headers and the OpenLink iODBC SDK frameworks

Static dependencies under `~/ydb_deps` must be built with
`-DCMAKE_POSITION_INDEPENDENT_CODE=ON` when linking the shared ODBC driver. See the
main [README](../README.md) dependency install section.
Dependencies are fetched at the versions pinned by the standalone SDK build.

## Supported platforms

| Platform | Driver manager | Status |
| --- | --- | --- |
| Linux | unixODBC | Source build; Ubuntu 24.04 amd64 package and automated API/consumer tests |
| macOS | iODBC 3.52.16 | Source build matching the application architecture; verified on arm64 |
| Windows | — | Not currently packaged or validated |

## Build

```bash
cmake --preset release-test-clang
cmake --build build --target ydb-odbc -j$(nproc)
cmake --preset release-clang -DYDB_SDK_ODBC=ON -DYDB_SDK_EXAMPLES=OFF
cmake --build build --target ydb-odbc --parallel
```

The shared library is produced as `build/odbc/libydb-odbc.so`.
The shared library is `build/odbc/libydb-odbc.so` on Linux and
`build/odbc/libydb-odbc.dylib` on macOS.

## Install
## Linux installation

```bash
cmake --install build --prefix /usr/local
cmake --preset release-clang -DYDB_SDK_ODBC=ON -DYDB_SDK_EXAMPLES=OFF \
-DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build --target ydb-odbc --parallel
sudo cmake --install build --component ydb-odbc
sudo odbcinst -i -d -f /usr/local/share/ydb-odbc/odbcinst.ini
```

Expand All @@ -34,14 +45,54 @@ This installs `libydb-odbc` and its unixODBC registration template. The
and unregisters the driver when the package is removed. `odbc.ini` is not
installed or modified — create your own DSN (see below).

## macOS installation

Use Homebrew iODBC to build the driver. Also install the current
[OpenLink iODBC SDK](https://www.iodbc.org/dataspace/doc/iodbc/wiki/iodbcWiki/Downloads),
which supplies the universal `iODBC.framework` and `iODBCinst.framework` under
`/Library/Frameworks`. The driver itself must contain the architecture used by
the client process.

Pin all ODBC paths so CMake cannot mix unixODBC libraries with iODBC headers.
The static installer, IDN, and OpenSSL libraries keep the installed driver free
of Homebrew runtime paths:

```bash
brew install libidn libiodbc openssl@3
IODBC_ROOT="$(brew --prefix libiodbc)"
IDN_ROOT="$(brew --prefix libidn)"
OPENSSL_ROOT="$(brew --prefix openssl@3)"
cmake --preset release-clang \
-DYDB_SDK_ODBC=ON \
-DYDB_SDK_EXAMPLES=OFF \
-DODBC_CONFIG="${IODBC_ROOT}/bin/iodbc-config" \
-DODBC_INCLUDE_DIR="${IODBC_ROOT}/include" \
-DODBC_LIBRARY="${IODBC_ROOT}/lib/libiodbc.dylib" \
-DYDB_ODBCINST_LIBRARY="${IODBC_ROOT}/lib/libiodbcinst.a" \
-DIDN_LIBRARIES="${IDN_ROOT}/lib/libidn.a" \
-DOPENSSL_ROOT_DIR="${OPENSSL_ROOT}" \
-DOPENSSL_USE_STATIC_LIBS=ON \
-DYDB_ODBC_INSTALL_LIBDIR=/Library/ODBC/YDB \
-DYDB_ODBC_INSTALL_DATADIR=/Library/ODBC/YDB
cmake --build build --target ydb-odbc --parallel
sudo cmake --install build --component ydb-odbc
otool -L /Library/ODBC/YDB/libydb-odbc.dylib
```

The install command registers the driver and a local `YDB` system DSN in
`/Library/ODBC/odbcinst.ini` and `/Library/ODBC/odbc.ini`. Existing sections
for other drivers and data sources are preserved. The final `otool` output
must not contain build-directory or Homebrew paths.

## Configuration

For `SQLConnect("YDB", ...)`, `isql -v YDB`, or `Driver=YDB`.

**`odbcinst.ini`** — driver registration template (generated on build/install).
Section `[YDB]` is the driver name used as `Driver=YDB` in connection strings
and DSNs. `Driver` and `Setup` are the full path to `libydb-odbc.so`. Register
the template with `odbcinst -i -d -f`; the Debian package does this for you.
and DSNs. `Driver` and `Setup` are the full path to the platform driver library.
Register the template with `odbcinst -i -d -f`; the Debian package does this
for you.

```ini
[YDB]
Expand All @@ -50,7 +101,10 @@ Driver=/path/to/libydb-odbc.so
Setup=/path/to/libydb-odbc.so
```

**`odbc.ini`** — DSN named `YDB`. In section `[YDB]`: `Driver` is the registered driver name, `Server` is the YDB endpoint, `Database` is the database path. Use `/etc/odbc.ini` or set `ODBCINI` to your file path.
**`odbc.ini`** — DSN named `YDB`. In section `[YDB]`, `Driver` is the
registered driver name or an absolute driver-library path, `Endpoint` (or its
`Server` alias) is the YDB endpoint, and `Database` is the database path. On
Linux use `~/.odbc.ini` or `/etc/odbc.ini`; `ODBCINI` can override the path.

```ini
[ODBC Data Sources]
Expand All @@ -63,6 +117,38 @@ Database=/local
AuthMode=Anonymous
```

On macOS, `sudo cmake --install build --component ydb-odbc` writes the
following sections to `/Library/ODBC/odbcinst.ini` and
`/Library/ODBC/odbc.ini`. They are shown here for reference and for manual
registration of an already-built driver.

```ini
; /Library/ODBC/odbcinst.ini
[ODBC Drivers]
YDB ODBC Driver=Installed

[YDB ODBC Driver]
Description=YDB ODBC Driver
Driver=/Library/ODBC/YDB/libydb-odbc.dylib
Setup=/Library/ODBC/YDB/libydb-odbc.dylib
```

```ini
; /Library/ODBC/odbc.ini
[ODBC Data Sources]
YDB=YDB ODBC Driver

[YDB]
Driver=/Library/ODBC/YDB/libydb-odbc.dylib
Endpoint=grpc://localhost:2136
Database=/local
AuthMode=Anonymous
```

For a non-sandboxed per-user setup, the equivalent macOS files live under
`~/Library/ODBC`. Verify the DSN with
`"$(brew --prefix libiodbc)/bin/iodbctest" "DSN=YDB"`.

`SQLDriverConnect` may also combine a DSN with explicit attributes. Values in
the connection string take precedence over values from the DSN. The user name
and password passed to `SQLConnect` take precedence over `User` and `Password`
Expand Down Expand Up @@ -155,8 +241,9 @@ For statements without an applicable count, it returns `-1`.

## Parameters

`?` placeholders are rewritten to `$p1`, `$p2`, ... with auto-generated `DECLARE $pN AS <type>?;`
from `SQLBindParameter` types. YDB-native `$pN` syntax also works.
`?` placeholders are rewritten to `$p1`, `$p2`, ... with auto-generated
`DECLARE` statements derived from `SQLBindParameter` types. Null values use an
optional YDB type. YDB-native `$pN` syntax also works.

## License

Expand Down
Loading
Loading