A modern C++20 framework for building database-specific ODBC drivers with pluggable protocol support.
- Complete ODBC API: 23 ODBC functions implemented with full descriptor support
- 4 ODBC Descriptors: IRD, APD, ARD, IPD fully implemented
- Prepared Statements: Full SQLPrepare/SQLBindParameter/SQLExecute workflow
- Column Binding: SQLBindCol with automatic data population during fetch
- Single Database Per Build: Each build targets one specific database for optimal size and performance
- Pluggable Architecture: Easy to add new database protocols
- Modern C++20: Clean, type-safe interfaces
- Secure Transport: Built-in TLS/SSL support via OpenSSL
- Cross-Platform: macOS, Linux, Windows support
- Comprehensive Testing: 17 unit and integration tests with 100% pass rate
Component | Status | Functions |
---|---|---|
Core APIs | ✅ Complete | SQLAllocHandle, SQLFreeHandle, SQLConnect, SQLDisconnect |
Statement Execution | ✅ Complete | SQLExecDirect, SQLFetch, SQLGetData |
Prepared Statements | ✅ Complete | SQLPrepare, SQLExecute, SQLBindParameter |
Column Binding | ✅ Complete | SQLBindCol with auto-population |
Metadata | ✅ Complete | SQLNumResultCols, SQLDescribeCol, SQLColAttribute |
Parameter Metadata | ✅ Complete | SQLDescribeParam |
Error Handling | ✅ Complete | SQLGetDiagRec |
Driver Info | ✅ Complete | SQLGetInfo, SQLSetEnvAttr |
Descriptor | Status | Purpose |
---|---|---|
IRD | ✅ Complete | Implementation Row Descriptor - result column metadata |
APD | ✅ Complete | Application Parameter Descriptor - parameter binding |
ARD | ✅ Complete | Application Row Descriptor - column binding |
IPD | ✅ Complete | Implementation Parameter Descriptor - parameter metadata |
Database | Status | Protocol |
---|---|---|
Redshift | ✅ Production Ready | PostgreSQL Wire Protocol |
PostgreSQL | ✅ Production Ready | PostgreSQL Wire Protocol |
MySQL | 🚧 Planned | MySQL Protocol |
SQL Server | 🚧 Planned | TDS Protocol |
- CMake 3.20+
- C++20 compiler (GCC 10+, Clang 12+, MSVC 2019+)
- OpenSSL 3.0+
- unixODBC (for system integration)
# Build database-specific driver (recommended)
./build-database.sh redshift
# Or build manually
cmake -DTARGET_DATABASE=REDSHIFT -B build-redshift
cmake --build build-redshift
# Setup test environment with local ODBC configuration
source ./setup-test-env.sh
# Verify configuration
echo $ODBCINI # Should point to ./odbc.ini
echo $ODBCSYSINI # Should point to current directory
# Redshift ODBC driver
./build-database.sh redshift
# PostgreSQL ODBC driver
./build-database.sh postgresql
# Minimal build (no examples/tests)
./build-database.sh minimal
# Debug build
./build-database.sh redshift --debug
#include <sql.h>
#include <sqlext.h>
int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
// Allocate handles
SQLAllocHandle(SQL_HANDLE_ENV, nullptr, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
// Connect using DSN or connection string
SQLConnect(hdbc,
(SQLCHAR*)"DSN=RedshiftProd", SQL_NTS,
(SQLCHAR*)"username", SQL_NTS,
(SQLCHAR*)"password", SQL_NTS);
// Execute query
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
SQLExecDirect(hstmt, (SQLCHAR*)"SELECT version()", SQL_NTS);
// Fetch results
char version[512];
while (SQLFetch(hstmt) == SQL_SUCCESS) {
SQLGetData(hstmt, 1, SQL_C_CHAR, version, sizeof(version), nullptr);
printf("Version: %s\n", version);
}
// Cleanup
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
#include <sql.h>
#include <sqlext.h>
int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
// Setup handles
SQLAllocHandle(SQL_HANDLE_ENV, nullptr, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
SQLConnect(hdbc, (SQLCHAR*)"DSN=RedshiftProd", SQL_NTS, nullptr, 0, nullptr, 0);
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
// Execute query
SQLExecDirect(hstmt, (SQLCHAR*)"SELECT name, age, salary FROM employees", SQL_NTS);
// Bind columns to variables
char name[256];
SQLINTEGER age;
SQLDOUBLE salary;
SQLLEN name_len, age_len, salary_len;
SQLBindCol(hstmt, 1, SQL_C_CHAR, name, sizeof(name), &name_len);
SQLBindCol(hstmt, 2, SQL_C_SLONG, &age, 0, &age_len);
SQLBindCol(hstmt, 3, SQL_C_DOUBLE, &salary, 0, &salary_len);
// Fetch automatically populates bound variables
while (SQLFetch(hstmt) == SQL_SUCCESS) {
printf("Employee: %s, Age: %d, Salary: %.2f\n", name, age, salary);
}
// Cleanup
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
#include "core/database/database_factory.h"
using namespace rs::core::database;
int main() {
// Create connection for compiled database
auto conn = DatabaseFactory::create_connection();
// Configure connection
ConnectionSettings settings;
settings.host = "your-redshift-cluster.amazonaws.com";
settings.port = 5439;
settings.user = "username";
settings.password = "password";
settings.database = "dev";
settings.use_ssl = true;
// Connect and query
conn->connect(settings);
auto deadline = rs::util::make_deadline(std::chrono::seconds(30));
auto result = conn->execute_query("SELECT version()", deadline);
std::cout << "Version: " << result.rows[0][0] << std::endl;
return 0;
}
Option | Description |
---|---|
-DTARGET_DATABASE=REDSHIFT |
Build Redshift ODBC driver |
-DTARGET_DATABASE=POSTGRESQL |
Build PostgreSQL ODBC driver |
-DTARGET_DATABASE=MYSQL |
Build MySQL ODBC driver (future) |
-DTARGET_DATABASE=SQLSERVER |
Build SQL Server ODBC driver (future) |
Option | Default | Description |
---|---|---|
BUILD_EXAMPLES |
ON | Build example applications |
BUILD_TESTING |
ON | Build unit and integration tests |
OPENSSL_USE_STATIC_LIBS |
OFF | Link OpenSSL statically |
build-database.sh - Database-specific builds:
# Show all options
./build-database.sh --help
# Build specific database drivers
./build-database.sh redshift # Redshift-only driver
./build-database.sh postgresql # PostgreSQL-only driver
./build-database.sh minimal # Minimal Redshift (no examples/tests)
# Build options
./build-database.sh redshift --debug # Debug build
./build-database.sh redshift --clean # Clean first
setup-test-env.sh - ODBC environment setup:
# Source to set environment variables
source ./setup-test-env.sh
# Or run to check configuration
./setup-test-env.sh
# List available presets
cmake --list-presets
# Use preset
cmake --preset redshift
cmake --build --preset redshift
The examples/
directory contains:
- query_example: Basic connection and query execution
- pg_handshake_example: Connection establishment and server parameters
- extended_query_example: Prepared statements and transactions
- multi_database_example: Shows database-specific build behavior
Run examples:
# After building
./build-redshift/examples/query_example your-host.com 5439 mydb user pass
The project includes local ODBC configuration files for development and testing:
# Setup local ODBC environment
source ./setup-test-env.sh
# This sets:
# ODBCINI=./odbc.ini # Data source definitions
# ODBCSYSINI=./ # Driver definitions (odbcinst.ini)
odbc.ini - Data Source Names (DSNs):
[RedshiftTest]
Driver = ODBCPP
Description = Redshift Test Database
Server = your-cluster.redshift.amazonaws.com
Port = 5439
Database = dev
SSL = true
[PostgreSQLTest]
Driver = ODBCPP
Description = PostgreSQL Test Database
Server = localhost
Port = 5432
Database = testdb
SSL = false
odbcinst.ini - Driver Definitions:
[ODBCPP]
Description = ODBCPP Multi-Database Driver
Driver64 = /path/to/build-redshift/libodbcpp.dylib
Setup64 = /path/to/build-redshift/libodbcpp.dylib
FileUsage = 1
# Install driver system-wide
sudo cp build-redshift/libodbcpp.dylib /usr/local/lib/
sudo odbcinst -i -d -f odbcinst.ini
# Add DSNs system-wide
sudo odbcinst -i -s -f odbc.ini
- Total Tests: 17 (10 unit + 7 integration)
- Success Rate: 100% (17/17 unit tests, 39/39 integration tests)
- Coverage: All ODBC APIs, descriptors, prepared statements, column binding
# Setup test environment first
source ./setup-test-env.sh
# Build and run all tests
./build-database.sh redshift
ctest --test-dir build-redshift
# Run specific test categories
ctest --test-dir build-redshift -L unit # 10 unit tests
ctest --test-dir build-redshift -L integration # 8 integration test suites
# Test specific functionality
ctest --test-dir build-redshift -R prepared_statements
ctest --test-dir build-redshift -R descriptor_apis
ctest --test-dir build-redshift -R bind_col
- Unit Tests: No external dependencies
- Integration Tests: Require valid DSN configuration in odbc.ini
- Database Access: Integration tests need actual Redshift/PostgreSQL connection
core/
├── database/ # Database abstraction layer
│ ├── i_database_connection.h # Generic connection interface
│ ├── i_protocol_parser.h # Protocol parser interface
│ ├── database_factory.{h,cpp} # Factory for database connections
│ ├── generic_database_connection.{h,cpp} # Generic implementation
│ └── postgres/ # PostgreSQL/Redshift protocol implementation
│ ├── pg_protocol_parser.{h,cpp}
│ └── pg_messages.h
├── transport/ # Network transport layer
│ ├── i_transport.h # Transport interface
│ ├── socket_transport.{h,cpp} # TCP sockets
│ └── tls_transport.{h,cpp} # TLS/SSL transport
└── util/ # Utilities
├── deadline.h # Timeout handling
├── errors.h # Error types
└── platform.h # Platform abstractions
-
Create protocol parser:
mkdir -p core/database/mysql # Implement mysql_protocol_parser.{h,cpp}
-
Implement IProtocolParser interface:
class MySQLProtocolParser : public IProtocolParser { // Implement all virtual methods };
-
Update factory (automatic via conditional compilation)
-
Build:
cmake -DTARGET_DATABASE=MYSQL -B build-mysql
- Fork the repository
- Create feature branch:
git checkout -b feature/mysql-support
- Make changes and add tests
- Ensure all tests pass:
ctest --test-dir build
- Submit pull request
[Your License Here]
- Issues: GitHub Issues
- Documentation: See
examples/
directory - Architecture: See
docs/
directory (if available)