Skip to content
Merged
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
7 changes: 2 additions & 5 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,12 @@ IncludeCategories:
# Standard library
- Regex: '^<[a-z_]+>'
Priority: 4
# Windows headers
- Regex: '^<windows\.h>'
Priority: 5
# ODBC headers
- Regex: '^<sql'
Priority: 6
Priority: 5
# Third-party libraries
- Regex: '.*'
Priority: 7
Priority: 6

# Other formatting
BinPackArguments: true
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ assignees: ''
<!-- A clear and concise description of what the bug is -->

## Environment
- **OS**: <!-- e.g., macOS 14.0, Ubuntu 22.04, Windows 11 -->
- **Compiler**: <!-- e.g., GCC 11.2, Clang 14, MSVC 2022 -->
- **OS**: <!-- e.g., macOS 14.0, Ubuntu 22.04 -->
- **Compiler**: <!-- e.g., GCC 11.2, Clang 14 -->
- **SDK Version**: <!-- e.g., 0.3.0 -->
- **CMake Version**: <!-- e.g., 3.25.0 -->
- **ODBC Driver**: <!-- e.g., Simba Spark ODBC Driver 2.6.26 -->
Expand Down
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Closes #
- [ ] Added/updated tests
- [ ] All tests pass (`make test`)
- [ ] Tested manually
- [ ] Build and test workflow is successful

## Checklist
- [ ] Code follows style guidelines (`make format`)
Expand Down
116 changes: 116 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
name: Build & Test

on:
pull_request:
branches: [ main ]
push:
branches: [ main ]

jobs:
cross-platform-tests:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]

runs-on: ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
cmake \
unixodbc-dev \
libcurl4-openssl-dev \
libspdlog-dev \
libfmt-dev \
nlohmann-json3-dev \
lcov

- name: Install dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install \
cmake \
unixodbc \
curl \
spdlog \
fmt \
nlohmann-json

- name: Configure CMake
run: |
mkdir -p build
cd build
if [ "$RUNNER_OS" == "macOS" ]; then
cmake -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=/opt/homebrew ..
else
cmake -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release ..
fi

- name: Build
run: |
cd build
cmake --build . --parallel $(nproc 2>/dev/null || sysctl -n hw.ncpu)

- name: Run unit tests
run: |
cd build
ctest --output-on-failure --verbose

code-coverage:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
cmake \
unixodbc-dev \
libcurl4-openssl-dev \
libspdlog-dev \
libfmt-dev \
nlohmann-json3-dev \
lcov

- name: Configure CMake with Coverage
run: |
mkdir -p build
cd build
cmake -DBUILD_TESTS=ON \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="--coverage -g -O0" \
-DCMAKE_C_FLAGS="--coverage -g -O0" \
..

- name: Build
run: |
cd build
cmake --build . --parallel $(nproc)

- name: Run unit tests
run: |
cd build
ctest --output-on-failure --verbose

- name: Generate coverage report
run: |
cd build
lcov --capture --directory . --output-file coverage.info --ignore-errors mismatch --ignore-errors gcov
lcov --remove coverage.info '/usr/*' '*/tests/*' '*/googletest/*' --output-file coverage.info --ignore-errors unused
lcov --list coverage.info

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: ./build/coverage.info
fail_ci_if_error: false
verbose: true
56 changes: 56 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: CodeQL Security Scan

on:
pull_request:
branches: [ main ]
push:
branches: [ main ]
schedule:
# Run every Monday at 00:00 UTC
- cron: '0 0 * * 1'

jobs:
analyze:
name: Analyze C++
runs-on: ubuntu-latest
permissions:
security-events: write
actions: read
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
cmake \
unixodbc-dev \
libcurl4-openssl-dev \
libspdlog-dev \
libfmt-dev \
nlohmann-json3-dev

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: cpp
queries: security-extended

- name: Configure CMake
run: |
mkdir -p build
cd build
cmake -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Debug ..

- name: Build
run: |
cd build
cmake --build . --parallel $(nproc)

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:cpp"
38 changes: 15 additions & 23 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ option(BUILD_TESTS "Build tests" OFF)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)

# Platform-specific configuration
if(WIN32)
# Windows uses odbc32
set(ODBC_LIBRARIES odbc32)
elseif(APPLE)
if(APPLE)
# macOS: Prefer Homebrew paths on Apple Silicon
if(NOT CMAKE_PREFIX_PATH AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
list(PREPEND CMAKE_PREFIX_PATH "/opt/homebrew")
Expand Down Expand Up @@ -170,11 +167,13 @@ target_include_directories(databricks_sdk
)

# Link ODBC libraries
target_link_libraries(databricks_sdk PRIVATE
${ODBC_LIBRARIES}
spdlog::spdlog
CURL::libcurl
nlohmann_json::nlohmann_json
target_link_libraries(databricks_sdk
PRIVATE
${ODBC_LIBRARIES}
spdlog::spdlog
CURL::libcurl
PUBLIC
nlohmann_json::nlohmann_json
)

# Set library properties
Expand All @@ -183,22 +182,15 @@ set_target_properties(databricks_sdk PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
)

# Set RPATH for finding ODBC libraries at runtime (Unix/Linux/macOS only)
if(NOT WIN32)
# Use RPATH to find shared libraries relative to executable
set_target_properties(databricks_sdk PROPERTIES
BUILD_RPATH "${ODBC_LIBRARY_DIR};/usr/local/lib;/opt/homebrew/lib;/opt/local/lib"
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;/usr/local/lib;/opt/homebrew/lib;/opt/local/lib"
INSTALL_RPATH_USE_LINK_PATH TRUE
)
endif()
# Set RPATH for finding ODBC libraries at runtime
set_target_properties(databricks_sdk PROPERTIES
BUILD_RPATH "${ODBC_LIBRARY_DIR};/usr/local/lib;/opt/homebrew/lib;/opt/local/lib"
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;/usr/local/lib;/opt/homebrew/lib;/opt/local/lib"
INSTALL_RPATH_USE_LINK_PATH TRUE
)

# Compiler warnings
if(MSVC)
target_compile_options(databricks_sdk PRIVATE /W4)
else()
target_compile_options(databricks_sdk PRIVATE -Wall -Wextra -Wpedantic)
endif()
target_compile_options(databricks_sdk PRIVATE -Wall -Wextra -Wpedantic)

# Examples
if(BUILD_EXAMPLES)
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Thank you for your interest in contributing to the Databricks C++ SDK! This docu

### Prerequisites

- C++17 compatible compiler (GCC 7+, Clang 5+, MSVC 2017+)
- C++17 compatible compiler (GCC 7+, Clang 5+)
- CMake 3.14 or higher
- ODBC Driver Manager (unixODBC on Linux/macOS)
- [Simba Spark ODBC Driver](https://www.databricks.com/spark/odbc-drivers-download)
Expand Down Expand Up @@ -248,7 +248,7 @@ TEST(ClientTest, QueryWithValidParameters) {
4. **Style**: Does it follow project conventions?
5. **Performance**: Any performance implications?
6. **Security**: Any security concerns?
7. **Compatibility**: Works on Linux/macOS/Windows?
7. **Compatibility**: Works on Linux/macOS?

### Responding to Feedback

Expand Down
17 changes: 1 addition & 16 deletions include/databricks/internal/secure_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@
#include <cstring>
#include <memory>
#include <string>

#ifdef _WIN32
# include <windows.h>
#else
# include <sys/mman.h>
#endif
#include <sys/mman.h>

namespace databricks {
namespace internal {
Expand Down Expand Up @@ -86,26 +81,16 @@ template <typename T> class SecureAllocator {
* @brief Lock memory pages to prevent swapping to disk
*/
static void lock_memory(void* ptr, size_type size) noexcept {
#ifdef _WIN32
// Use VirtualLock on Windows
// Ignore failures - locking is best-effort
VirtualLock(ptr, size);
#else
// Use mlock on POSIX systems
// Ignore failures - locking is best-effort
mlock(ptr, size);
#endif
}

/**
* @brief Unlock memory pages
*/
static void unlock_memory(void* ptr, size_type size) noexcept {
#ifdef _WIN32
VirtualUnlock(ptr, size);
#else
munlock(ptr, size);
#endif
}

/**
Expand Down
3 changes: 0 additions & 3 deletions src/core/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
#include <stdexcept>
#include <thread>

#ifdef _WIN32
# include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>

Expand Down
9 changes: 8 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ FetchContent_Declare(
GIT_TAG v1.14.0
)

# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)

FetchContent_MakeAvailable(googletest)
Expand All @@ -20,13 +19,21 @@ enable_testing()
file(GLOB_RECURSE UNIT_TEST_SOURCES CONFIGURE_DEPENDS "unit/**/*.cpp")
add_executable(unit_tests ${UNIT_TEST_SOURCES})

# Find fmt package (spdlog dependency)
find_package(fmt QUIET)

target_link_libraries(unit_tests
PRIVATE
databricks_sdk
GTest::gtest_main
GTest::gmock_main
)

# Link fmt if found (needed on some systems where spdlog uses external fmt)
if(fmt_FOUND)
target_link_libraries(unit_tests PRIVATE fmt::fmt)
endif()

target_include_directories(unit_tests
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../include
Expand Down
5 changes: 3 additions & 2 deletions tests/unit/core/test_error_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "databricks/core/config.h"

#include <cstdlib>
#include <filesystem>
#include <fstream>

#include <gmock/gmock.h>
Expand Down Expand Up @@ -96,7 +97,7 @@ TEST_F(AuthConfigErrorTest, SuccessfulProfileLoading) {
setenv("HOME", home, 1);

// Create the directory if it doesn't exist
system(("mkdir -p " + std::string(home)).c_str());
std::filesystem::create_directories(home);

// Create the config file
std::string config_path = std::string(home) + "/.databrickscfg";
Expand Down Expand Up @@ -151,7 +152,7 @@ TEST_F(AuthConfigErrorTest, ProfileMissingFields) {
setenv("HOME", home, 1);

// Create the directory if it doesn't exist
system(("mkdir -p " + std::string(home)).c_str());
std::filesystem::create_directories(home);

// Create config file with only host (missing token)
std::string config_path = std::string(home) + "/.databrickscfg";
Expand Down
Loading