From 6a1d49365caceb77cee52fe5d87a78f014b9d785 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 15 Sep 2025 16:34:54 -0700 Subject: [PATCH 01/10] Switch to use Arrow's logging --- .../odbcabstraction/include/odbcabstraction/logger.h | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h index 6249df98834..5048bb1a12e 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h @@ -23,18 +23,12 @@ #include +#include "arrow/util/logging.h" + // The logger using spdlog is deprecated and will be replaced. // TODO: mirgate logging to use Arrow's internal logging system -#define __LAZY_LOG(LEVEL, ...) \ - do { \ - driver::odbcabstraction::Logger* logger = \ - driver::odbcabstraction::Logger::GetInstance(); \ - if (logger) { \ - logger->log(driver::odbcabstraction::LogLevel::LogLevel_##LEVEL, \ - [&]() { return fmt::format(__VA_ARGS__); }); \ - } \ - } while (0) +#define __LAZY_LOG(LEVEL, ...) ARROW_LOG(LEVEL) << __VA_ARGS__; #define LOG_DEBUG(...) __LAZY_LOG(DEBUG, __VA_ARGS__) #define LOG_INFO(...) __LAZY_LOG(INFO, __VA_ARGS__) #define LOG_ERROR(...) __LAZY_LOG(ERROR, __VA_ARGS__) From 7be4440f57e829b876e658193e4f8e3a7862f55b Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 15 Sep 2025 17:16:41 -0700 Subject: [PATCH 02/10] Remove spdlog --- LICENSE.txt | 43 -- cpp/src/arrow/flight/sql/odbc/CMakeLists.txt | 15 +- .../sql/odbc/flight_sql/flight_sql_driver.cc | 77 -- .../include/flight_sql/flight_sql_driver.h | 2 - cpp/src/arrow/flight/sql/odbc/odbc_api.cc | 5 +- .../sql/odbc/odbcabstraction/CMakeLists.txt | 7 - .../include/odbcabstraction/logger.h | 38 - .../include/odbcabstraction/spd_logger.h | 54 -- .../include/odbcabstraction/spi/driver.h | 3 - .../include/odbcabstraction/utils.h | 6 - .../flight/sql/odbc/odbcabstraction/logger.cc | 32 - .../sql/odbc/odbcabstraction/spd_logger.cc | 70 -- .../flight/sql/odbc/odbcabstraction/utils.cc | 55 -- cpp/src/arrow/vendored/whereami/whereami.cc | 674 ------------------ cpp/src/arrow/vendored/whereami/whereami.h | 68 -- cpp/vcpkg.json | 1 - 16 files changed, 4 insertions(+), 1146 deletions(-) delete mode 100644 cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spd_logger.h delete mode 100644 cpp/src/arrow/flight/sql/odbc/odbcabstraction/logger.cc delete mode 100644 cpp/src/arrow/flight/sql/odbc/odbcabstraction/spd_logger.cc delete mode 100644 cpp/src/arrow/vendored/whereami/whereami.cc delete mode 100644 cpp/src/arrow/vendored/whereami/whereami.h diff --git a/LICENSE.txt b/LICENSE.txt index 2c90f0313d7..08d4f988ac1 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2280,46 +2280,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - --------------------------------------------------------------------------------- -The files cpp/src/arrow/vendored/whereami/whereami.h, -cpp/src/arrow/vendored/whereami/whereami.cc are adapted from -Grégory Pakosz's whereami library (https://github.com/gpakosz/whereami) -It is dual licensed under both the WTFPLv2 and MIT licenses. - -The WTFPLv2 License - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. - 1. Bla bla bla - 2. Montesqieu et camembert, vive la France, zut alors! - -The MIT License (MIT) -Copyright Gregory Pakosz - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 975559c2626..9412f81a967 100644 --- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt @@ -22,9 +22,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) add_custom_target(arrow_flight_sql_odbc) -# Ensure fmt is loaded as header only -add_compile_definitions(FMT_HEADER_ONLY) - if(WIN32) if(MSVC_VERSION GREATER_EQUAL 1900) set(ODBCINST legacy_stdio_definitions odbccp32 shlwapi) @@ -39,15 +36,6 @@ endif() add_definitions(-DUNICODE=1) -include(FetchContent) -fetchcontent_declare(spdlog - URL https://github.com/gabime/spdlog/archive/refs/tags/v1.15.3.zip - CONFIGURE_COMMAND - "" - BUILD_COMMAND - "") -fetchcontent_makeavailable(spdlog) - add_subdirectory(flight_sql) add_subdirectory(odbcabstraction) add_subdirectory(tests) @@ -104,8 +92,7 @@ add_arrow_lib(arrow_flight_sql_odbc ${ODBC_LIBRARIES} ${ODBCINST} odbcabstraction - arrow_odbc_spi_impl - spdlog::spdlog) + arrow_odbc_spi_impl) foreach(LIB_TARGET ${ARROW_FLIGHT_SQL_ODBC_LIBRARIES}) target_compile_definitions(${LIB_TARGET} PRIVATE ARROW_FLIGHT_SQL_ODBC_EXPORTING) diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc index 0736dac8486..0b217b7a952 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc @@ -20,44 +20,16 @@ #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" #include "arrow/flight/sql/odbc/flight_sql/utils.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/platform.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spd_logger.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h" #include "arrow/util/io_util.h" -#define DEFAULT_MAXIMUM_FILE_SIZE 16777216 -#define CONFIG_FILE_NAME "arrow-odbc.ini" -#define CONFIG_FILE_PATH "CONFIG_FILE_PATH" - namespace driver { namespace flight_sql { using odbcabstraction::Connection; -using odbcabstraction::LogLevel; using odbcabstraction::OdbcVersion; -using odbcabstraction::SPDLogger; - -namespace { -LogLevel ToLogLevel(int64_t level) { - switch (level) { - case 0: - return LogLevel::LogLevel_TRACE; - case 1: - return LogLevel::LogLevel_DEBUG; - case 2: - return LogLevel::LogLevel_INFO; - case 3: - return LogLevel::LogLevel_WARN; - case 4: - return LogLevel::LogLevel_ERROR; - default: - return LogLevel::LogLevel_OFF; - } -} -} // namespace FlightSqlDriver::FlightSqlDriver() : diagnostics_("Apache Arrow", "Flight SQL", OdbcVersion::V_3), version_("0.9.0.0") { - RegisterLog(); // Register Kernel functions to library ThrowIfNotOK(arrow::compute::Initialize()); } @@ -70,54 +42,5 @@ odbcabstraction::Diagnostics& FlightSqlDriver::GetDiagnostics() { return diagnos void FlightSqlDriver::SetVersion(std::string version) { version_ = std::move(version); } -void FlightSqlDriver::RegisterLog() { - std::string config_path = arrow::internal::GetEnvVar(CONFIG_FILE_PATH).ValueOr(""); - if (config_path.empty()) { - return; - } - - odbcabstraction::PropertyMap propertyMap; - driver::odbcabstraction::ReadConfigFile(propertyMap, config_path, CONFIG_FILE_NAME); - - auto log_enable_iterator = propertyMap.find(std::string(SPDLogger::LOG_ENABLED)); - auto log_enabled = log_enable_iterator != propertyMap.end() - ? odbcabstraction::AsBool(log_enable_iterator->second) - : false; - if (!log_enabled.get()) { - return; - } - - auto log_path_iterator = propertyMap.find(std::string(SPDLogger::LOG_PATH)); - auto log_path = log_path_iterator != propertyMap.end() ? log_path_iterator->second : ""; - if (log_path.empty()) { - return; - } - - auto log_level_iterator = propertyMap.find(std::string(SPDLogger::LOG_LEVEL)); - auto log_level = ToLogLevel(log_level_iterator != propertyMap.end() - ? std::stoi(log_level_iterator->second) - : 1); - if (log_level == odbcabstraction::LogLevel_OFF) { - return; - } - - auto maximum_file_size_iterator = - propertyMap.find(std::string(SPDLogger::MAXIMUM_FILE_SIZE)); - auto maximum_file_size = maximum_file_size_iterator != propertyMap.end() - ? std::stoi(maximum_file_size_iterator->second) - : DEFAULT_MAXIMUM_FILE_SIZE; - - auto maximum_file_quantity_iterator = - propertyMap.find(std::string(SPDLogger::FILE_QUANTITY)); - auto maximum_file_quantity = maximum_file_quantity_iterator != propertyMap.end() - ? std::stoi(maximum_file_quantity_iterator->second) - : 1; - - std::unique_ptr logger(new odbcabstraction::SPDLogger()); - - logger->init(maximum_file_quantity, maximum_file_size, log_path, log_level); - odbcabstraction::Logger::SetInstance(std::move(logger)); -} - } // namespace flight_sql } // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h index 48f2a16416a..ca6d197bb46 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h @@ -37,8 +37,6 @@ class FlightSqlDriver : public odbcabstraction::Driver { odbcabstraction::Diagnostics& GetDiagnostics() override; void SetVersion(std::string version) override; - - void RegisterLog() override; }; }; // namespace flight_sql diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 82a167b3c16..cd3bf30132b 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -41,8 +41,9 @@ namespace arrow { SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) { - LOG_DEBUG("SQLAllocHandle called with type: {}, parent: {}, result: {}", type, parent, - fmt::ptr(result)); + LOG_DEBUG("SQLAllocHandle called with type: " << type << ", parent: " << parent + << ", result: " + << static_cast(result);); *result = nullptr; diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt index dd8b6dd2f1e..e8b5c4a63dd 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt @@ -22,9 +22,7 @@ add_library(odbcabstraction include/odbcabstraction/diagnostics.h include/odbcabstraction/error_codes.h include/odbcabstraction/exceptions.h - include/odbcabstraction/logger.h include/odbcabstraction/platform.h - include/odbcabstraction/spd_logger.h include/odbcabstraction/types.h include/odbcabstraction/utils.h include/odbcabstraction/odbc_impl/attribute_utils.h @@ -44,10 +42,7 @@ add_library(odbcabstraction diagnostics.cc encoding.cc exceptions.cc - logger.cc - spd_logger.cc utils.cc - ../../../../vendored/whereami/whereami.cc odbc_impl/odbc_connection.cc odbc_impl/odbc_descriptor.cc odbc_impl/odbc_environment.cc @@ -62,5 +57,3 @@ set_target_properties(odbcabstraction ${CMAKE_BINARY_DIR}/$/lib RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$/lib) - -target_link_libraries(odbcabstraction PUBLIC spdlog::spdlog) diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h index 5048bb1a12e..22d7d7643b6 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h @@ -17,49 +17,11 @@ #pragma once -#include -#include -#include - -#include - #include "arrow/util/logging.h" -// The logger using spdlog is deprecated and will be replaced. -// TODO: mirgate logging to use Arrow's internal logging system - #define __LAZY_LOG(LEVEL, ...) ARROW_LOG(LEVEL) << __VA_ARGS__; #define LOG_DEBUG(...) __LAZY_LOG(DEBUG, __VA_ARGS__) #define LOG_INFO(...) __LAZY_LOG(INFO, __VA_ARGS__) #define LOG_ERROR(...) __LAZY_LOG(ERROR, __VA_ARGS__) #define LOG_TRACE(...) __LAZY_LOG(TRACE, __VA_ARGS__) #define LOG_WARN(...) __LAZY_LOG(WARN, __VA_ARGS__) - -namespace driver { -namespace odbcabstraction { - -enum LogLevel { - LogLevel_TRACE, - LogLevel_DEBUG, - LogLevel_INFO, - LogLevel_WARN, - LogLevel_ERROR, - LogLevel_OFF -}; - -class Logger { - protected: - Logger() = default; - - public: - static Logger* GetInstance(); - static void SetInstance(std::unique_ptr logger); - - virtual ~Logger() = default; - - virtual void log(LogLevel level, - const std::function& build_message) = 0; -}; - -} // namespace odbcabstraction -} // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spd_logger.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spd_logger.h deleted file mode 100644 index 08672b9e7c2..00000000000 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spd_logger.h +++ /dev/null @@ -1,54 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#pragma once - -#include "odbcabstraction/logger.h" - -#include -#include - -#include - -namespace driver { -namespace odbcabstraction { - -class SPDLogger : public Logger { - protected: - std::shared_ptr logger_; - - public: - static constexpr std::string_view LOG_LEVEL = "LogLevel"; - static constexpr std::string_view LOG_PATH = "LogPath"; - static constexpr std::string_view MAXIMUM_FILE_SIZE = "MaximumFileSize"; - static constexpr std::string_view FILE_QUANTITY = "FileQuantity"; - static constexpr std::string_view LOG_ENABLED = "LogEnabled"; - - SPDLogger() = default; - ~SPDLogger() = default; - SPDLogger(SPDLogger& other) = delete; - - void operator=(const SPDLogger&) = delete; - void init(int64_t fileQuantity, int64_t maxFileSize, const std::string& fileNamePrefix, - LogLevel level); - - void log(LogLevel level, - const std::function& build_message) override; -}; - -} // namespace odbcabstraction -} // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h index 61d570574c7..417f10d091f 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h @@ -45,9 +45,6 @@ class Driver { /// \brief Sets the driver version. virtual void SetVersion(std::string version) = 0; - - /// \brief Register a log to be used by the system. - virtual void RegisterLog() = 0; }; } // namespace odbcabstraction diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h index 6e1fe5739be..5e541a1d45f 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h @@ -17,9 +17,7 @@ #pragma once -#include #include -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/connection.h" namespace driver { @@ -51,9 +49,5 @@ boost::optional AsBool(const Connection::ConnPropertyMap& connPropertyMap, boost::optional AsInt32(int32_t min_value, const Connection::ConnPropertyMap& connPropertyMap, const std::string_view& property_name); - -void ReadConfigFile(PropertyMap& properties, const std::string& configPath, - const std::string& configFileName); - } // namespace odbcabstraction } // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/logger.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/logger.cc deleted file mode 100644 index 8b105a2f0b6..00000000000 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/logger.cc +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" - -namespace driver { -namespace odbcabstraction { - -static std::unique_ptr odbc_logger_ = nullptr; - -Logger* Logger::GetInstance() { return odbc_logger_.get(); } - -void Logger::SetInstance(std::unique_ptr logger) { - odbc_logger_ = std::move(logger); -} - -} // namespace odbcabstraction -} // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/spd_logger.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/spd_logger.cc deleted file mode 100644 index 322ae5e5da1..00000000000 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/spd_logger.cc +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "odbcabstraction/spd_logger.h" - -#include "odbcabstraction/logger.h" - -#include -#include -#include - -#include - -namespace driver { -namespace odbcabstraction { -namespace { -inline spdlog::level::level_enum ToSpdLogLevel(LogLevel level) { - switch (level) { - case LogLevel_TRACE: - return spdlog::level::trace; - case LogLevel_DEBUG: - return spdlog::level::debug; - case LogLevel_INFO: - return spdlog::level::info; - case LogLevel_WARN: - return spdlog::level::warn; - case LogLevel_ERROR: - return spdlog::level::err; - default: - return spdlog::level::off; - } -} -} // namespace - -void SPDLogger::init(int64_t fileQuantity, int64_t maxFileSize, - const std::string& fileNamePrefix, LogLevel level) { - logger_ = spdlog::rotating_logger_mt( - "ODBC Logger", fileNamePrefix, maxFileSize, fileQuantity); - - logger_->set_level(ToSpdLogLevel(level)); -} - -void SPDLogger::log(LogLevel level, - const std::function& build_message) { - auto level_set = logger_->level(); - spdlog::level::level_enum spdlog_level = ToSpdLogLevel(level); - if (level_set == spdlog::level::off || level_set > spdlog_level) { - return; - } - - const std::string& message = build_message(); - logger_->log(spdlog_level, message); -} - -} // namespace odbcabstraction -} // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc index 6feb7ff3be2..a63d0c02fe3 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc @@ -14,18 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. - -#include "arrow/vendored/whereami/whereami.h" - #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h" -#include -#include - #include -#include -#include -#include namespace driver { namespace odbcabstraction { @@ -65,51 +56,5 @@ boost::optional AsInt32(int32_t min_value, } return boost::none; } - -std::string GetModulePath() { - std::vector path; - int length, dirname_length; - length = wai_getModulePath(NULL, 0, &dirname_length); - - if (length != 0) { - path.resize(length); - wai_getModulePath(path.data(), length, &dirname_length); - } else { - throw DriverException("Could not find module path."); - } - - return std::string(path.begin(), path.begin() + dirname_length); -} - -void ReadConfigFile(PropertyMap& properties, const std::string& config_path, - const std::string& config_file_name) { - std::ifstream config_file; - auto config_file_path = config_path + "/" + config_file_name; - config_file.open(config_file_path); - - if (config_file.fail()) { - auto error_msg = "Arrow Flight SQL ODBC driver config file not found on \"" + - config_file_path + "\""; - std::cerr << error_msg << std::endl; - - throw DriverException(error_msg); - } - - std::string temp_config; - - boost::char_separator separator("="); - while (config_file.good()) { - config_file >> temp_config; - boost::tokenizer> tokenizer(temp_config, separator); - - auto iterator = tokenizer.begin(); - - std::string key = *iterator; - std::string value = *++iterator; - - properties[key] = std::move(value); - } -} - } // namespace odbcabstraction } // namespace driver diff --git a/cpp/src/arrow/vendored/whereami/whereami.cc b/cpp/src/arrow/vendored/whereami/whereami.cc deleted file mode 100644 index 94437361ec0..00000000000 --- a/cpp/src/arrow/vendored/whereami/whereami.cc +++ /dev/null @@ -1,674 +0,0 @@ -// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses -// without any warranty. -// by Gregory Pakosz (@gpakosz) -// https://github.com/gpakosz/whereami -// Copyright 2024 Gregory Pakosz - -// in case you want to #include "whereami.c" in a larger compilation unit -#if !defined(WHEREAMI_H) -# include "whereami.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__linux__) || defined(__CYGWIN__) -# undef _DEFAULT_SOURCE -# define _DEFAULT_SOURCE -#elif defined(__APPLE__) -# undef _DARWIN_C_SOURCE -# define _DARWIN_C_SOURCE -# define _DARWIN_BETTER_REALPATH -#endif - -#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC) -# include -#endif - -#if !defined(WAI_MALLOC) -# define WAI_MALLOC(size) malloc(size) -#endif - -#if !defined(WAI_FREE) -# define WAI_FREE(p) free(p) -#endif - -#if !defined(WAI_REALLOC) -# define WAI_REALLOC(p, size) realloc(p, size) -#endif - -#ifndef WAI_NOINLINE -# if defined(_MSC_VER) -# define WAI_NOINLINE __declspec(noinline) -# elif defined(__GNUC__) -# define WAI_NOINLINE __attribute__((noinline)) -# else -# error unsupported compiler -# endif -#endif - -#if defined(_MSC_VER) -# define WAI_RETURN_ADDRESS() _ReturnAddress() -#elif defined(__GNUC__) -# define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) -#else -# error unsupported compiler -#endif - -#if defined(_WIN32) - -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# if defined(_MSC_VER) -# pragma warning(push, 3) -# endif -# include -# include -# if defined(_MSC_VER) -# pragma warning(pop) -# endif -# include - -static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, - int* dirname_length) { - wchar_t buffer1[MAX_PATH]; - wchar_t buffer2[MAX_PATH]; - wchar_t* path = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { - DWORD size; - int length_, length__; - - size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0])); - - if (size == 0) { - break; - } else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0]))) { - DWORD size_ = size; - do { - wchar_t* path_; - - path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2); - if (!path_) break; - size_ *= 2; - path = path_; - size = GetModuleFileNameW(module, path, size_); - } while (size == size_); - - if (size == size_) break; - } else { - path = buffer1; - } - - if (!_wfullpath(buffer2, path, MAX_PATH)) break; - length_ = (int)wcslen(buffer2); - length__ = - WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, out, capacity, NULL, NULL); - - if (length__ == 0) - length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL); - if (length__ == 0) break; - - if (length__ <= capacity && dirname_length) { - int i; - - for (i = length__ - 1; i >= 0; --i) { - if (out[i] == '\\') { - *dirname_length = i; - break; - } - } - } - - length = length__; - } - - if (path != buffer1) WAI_FREE(path); - - return ok ? length : -1; -} - -WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getExecutablePath)(char* out, int capacity, - int* dirname_length) { - return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length); -} - -WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, - int* dirname_length) { - HMODULE module; - int length = -1; - -# if defined(_MSC_VER) -# pragma warning(push) -# pragma warning(disable : 4054) -# endif - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (LPCTSTR)WAI_RETURN_ADDRESS(), &module)) -# if defined(_MSC_VER) -# pragma warning(pop) -# endif - { - length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length); - } - - return length; -} - -#elif defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || \ - defined(WAI_USE_PROC_SELF_EXE) - -# include -# include -# if defined(__linux__) -# include -# else -# include -# endif -# ifndef __STDC_FORMAT_MACROS -# define __STDC_FORMAT_MACROS -# endif -# include - -# if !defined(WAI_PROC_SELF_EXE) -# if defined(__sun) -# define WAI_PROC_SELF_EXE "/proc/self/path/a.out" -# else -# define WAI_PROC_SELF_EXE "/proc/self/exe" -# endif -# endif - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { - resolved = realpath(WAI_PROC_SELF_EXE, buffer); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - return ok ? length : -1; -} - -# if !defined(WAI_PROC_SELF_MAPS_RETRY) -# define WAI_PROC_SELF_MAPS_RETRY 5 -# endif - -# if !defined(WAI_PROC_SELF_MAPS) -# if defined(__sun) -# define WAI_PROC_SELF_MAPS "/proc/self/map" -# else -# define WAI_PROC_SELF_MAPS "/proc/self/maps" -# endif -# endif - -# if defined(__ANDROID__) || defined(ANDROID) -# include -# include -# include -# endif - -WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, - int* dirname_length) { - int length = -1; - FILE* maps = NULL; - - for (int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r) { - maps = fopen(WAI_PROC_SELF_MAPS, "r"); - if (!maps) break; - - for (;;) { - char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX]; - uint64_t low, high; - char perms[5]; - uint64_t offset; - uint32_t major, minor; - char path[PATH_MAX]; - uint32_t inode; - - if (!fgets(buffer, sizeof(buffer), maps)) break; - - if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, - &high, perms, &offset, &major, &minor, &inode, path) == 8) { - uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS(); - if (low <= addr && addr <= high) { - char* resolved; - - resolved = realpath(path, buffer); - if (!resolved) break; - - length = (int)strlen(resolved); -# if defined(__ANDROID__) || defined(ANDROID) - if (length > 4 && buffer[length - 1] == 'k' && buffer[length - 2] == 'p' && - buffer[length - 3] == 'a' && buffer[length - 4] == '.') { - int fd = open(path, O_RDONLY); - if (fd == -1) { - length = -1; // retry - break; - } - - char* begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0); - if (begin == MAP_FAILED) { - close(fd); - length = -1; // retry - break; - } - - char* p = begin + offset - 30; // minimum size of local file header - while (p >= begin) { // scan backwards - if (*((uint32_t*)p) == 0x04034b50UL) { // local file header signature found - uint16_t length_ = *((uint16_t*)(p + 26)); - - if (length + 2 + length_ < (int)sizeof(buffer)) { - memcpy(&buffer[length], "!/", 2); - memcpy(&buffer[length + 2], p + 30, length_); - length += 2 + length_; - } - - break; - } - - --p; - } - - munmap(begin, offset); - close(fd); - } -# endif - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - - break; - } - } - } - - fclose(maps); - maps = NULL; - - if (length != -1) break; - } - - return length; -} - -#elif defined(__APPLE__) - -# include -# include - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* path = buffer1; - char* resolved = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { - uint32_t size = (uint32_t)sizeof(buffer1); - if (_NSGetExecutablePath(path, &size) == -1) { - path = (char*)WAI_MALLOC(size); - if (!_NSGetExecutablePath(path, &size)) break; - } - - resolved = realpath(path, buffer2); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - if (path != buffer1) WAI_FREE(path); - - return ok ? length : -1; -} - -WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, - int* dirname_length) { - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for (;;) { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#elif defined(__QNXNTO__) - -# include - -# if !defined(WAI_PROC_SELF_EXE) -# define WAI_PROC_SELF_EXE "/proc/self/exefile" -# endif - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* resolved = NULL; - FILE* self_exe = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { - self_exe = fopen(WAI_PROC_SELF_EXE, "r"); - if (!self_exe) break; - - if (!fgets(buffer1, sizeof(buffer1), self_exe)) break; - - resolved = realpath(buffer1, buffer2); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - fclose(self_exe); - - return ok ? length : -1; -} - -WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) { - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for (;;) { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) || defined(__OpenBSD__) - -# include -# include - -# if defined(__OpenBSD__) - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { - char buffer1[4096]; - char buffer2[PATH_MAX]; - char buffer3[PATH_MAX]; - char** argv = (char**)buffer1; - char* resolved = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { - int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; - size_t size; - - if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0) break; - - if (size > sizeof(buffer1)) { - argv = (char**)WAI_MALLOC(size); - if (!argv) break; - } - - if (sysctl(mib, 4, argv, &size, NULL, 0) != 0) break; - - if (strchr(argv[0], '/')) { - resolved = realpath(argv[0], buffer2); - if (!resolved) break; - } else { - const char* PATH = getenv("PATH"); - if (!PATH) break; - - size_t argv0_length = strlen(argv[0]); - - const char* begin = PATH; - while (1) { - const char* separator = strchr(begin, ':'); - const char* end = separator ? separator : begin + strlen(begin); - - if (end - begin > 0) { - if (*(end - 1) == '/') --end; - - if (((end - begin) + 1 + argv0_length + 1) <= sizeof(buffer2)) { - memcpy(buffer2, begin, end - begin); - buffer2[end - begin] = '/'; - memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1); - - resolved = realpath(buffer2, buffer3); - if (resolved) break; - } - } - - if (!separator) break; - - begin = ++separator; - } - - if (!resolved) break; - } - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - if (argv != (char**)buffer1) WAI_FREE(argv); - - return ok ? length : -1; -} - -# else - -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { - char buffer1[PATH_MAX]; - char buffer2[PATH_MAX]; - char* path = buffer1; - char* resolved = NULL; - int length = -1; - bool ok; - - for (ok = false; !ok; ok = true) { -# if defined(__NetBSD__) - int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; -# else - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; -# endif - size_t size = sizeof(buffer1); - - if (sysctl(mib, 4, path, &size, NULL, 0) != 0) break; - - resolved = realpath(path, buffer2); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - return ok ? length : -1; -} - -# endif - -WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, - int* dirname_length) { - char buffer[PATH_MAX]; - char* resolved = NULL; - int length = -1; - - for (;;) { - Dl_info info; - - if (dladdr(WAI_RETURN_ADDRESS(), &info)) { - resolved = realpath(info.dli_fname, buffer); - if (!resolved) break; - - length = (int)strlen(resolved); - if (length <= capacity) { - memcpy(out, resolved, length); - - if (dirname_length) { - int i; - - for (i = length - 1; i >= 0; --i) { - if (out[i] == '/') { - *dirname_length = i; - break; - } - } - } - } - } - - break; - } - - return length; -} - -#else - -# error unsupported platform - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/cpp/src/arrow/vendored/whereami/whereami.h b/cpp/src/arrow/vendored/whereami/whereami.h deleted file mode 100644 index abb137bbefa..00000000000 --- a/cpp/src/arrow/vendored/whereami/whereami.h +++ /dev/null @@ -1,68 +0,0 @@ -// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses -// without any warranty. -// by Gregory Pakosz (@gpakosz) -// https://github.com/gpakosz/whereami -// Copyright 2024 Gregory Pakosz - -#ifndef WHEREAMI_H -#define WHEREAMI_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WAI_FUNCSPEC -# define WAI_FUNCSPEC -#endif -#ifndef WAI_PREFIX -# define WAI_PREFIX(function) wai_##function -#endif - -/** - * Returns the path to the current executable. - * - * Usage: - * - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to - * retrieve the length of the path - * - allocate the destination buffer with `path = (char*)malloc(length + 1);` - * - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the - * path - * - add a terminal NUL character with `path[length] = '\0';` - * - * @param out destination buffer, optional - * @param capacity destination buffer capacity - * @param dirname_length optional recipient for the length of the dirname part - * of the path. - * - * @return the length of the executable path on success (without a terminal NUL - * character), otherwise `-1` - */ -WAI_FUNCSPEC -int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length); - -/** - * Returns the path to the current module - * - * Usage: - * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve - * the length of the path - * - allocate the destination buffer with `path = (char*)malloc(length + 1);` - * - call `wai_getModulePath(path, length, NULL)` again to retrieve the path - * - add a terminal NUL character with `path[length] = '\0';` - * - * @param out destination buffer, optional - * @param capacity destination buffer capacity - * @param dirname_length optional recipient for the length of the dirname part - * of the path. - * - * @return the length of the module path on success (without a terminal NUL - * character), otherwise `-1` - */ -WAI_FUNCSPEC -int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length); - -#ifdef __cplusplus -} -#endif - -#endif // #ifndef WHEREAMI_H diff --git a/cpp/vcpkg.json b/cpp/vcpkg.json index 95e6ac83071..68f20663b59 100644 --- a/cpp/vcpkg.json +++ b/cpp/vcpkg.json @@ -54,7 +54,6 @@ "rapidjson", "re2", "snappy", - "spdlog", "sqlite3", "thrift", "utf8proc", From 74eebe31f06c6d4ec2f68179899ef2b1ce04577e Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 15 Sep 2025 17:34:12 -0700 Subject: [PATCH 03/10] Adhere to Arrow's logging --- cpp/src/arrow/flight/sql/odbc/entry_points.cc | 40 +-- cpp/src/arrow/flight/sql/odbc/odbc_api.cc | 262 ++++++++++-------- 2 files changed, 164 insertions(+), 138 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/entry_points.cc b/cpp/src/arrow/flight/sql/odbc/entry_points.cc index 38b4a1fc8ed..611175c8e62 100644 --- a/cpp/src/arrow/flight/sql/odbc/entry_points.cc +++ b/cpp/src/arrow/flight/sql/odbc/entry_points.cc @@ -178,7 +178,7 @@ SQLRETURN SQL_API SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLI } SQLRETURN SQL_API SQLCancel(SQLHSTMT stmt) { - LOG_DEBUG("SQLCancel called with stmt: {}", stmt); + LOG_DEBUG("SQLCancel called with stmt: " << stmt); return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLCancel is not implemented", "IM001"); @@ -225,18 +225,19 @@ SQLRETURN SQL_API SQLForeignKeys(SQLHSTMT stmt, SQLWCHAR* pKCatalogName, SQLSMALLINT fKCatalogNameLength, SQLWCHAR* fKSchemaName, SQLSMALLINT fKSchemaNameLength, SQLWCHAR* fKTableName, SQLSMALLINT fKTableNameLength) { - LOG_DEBUG( - "SQLForeignKeysW called with stmt: {}, pKCatalogName: {}, " - "pKCatalogNameLength: " - "{}, pKSchemaName: {}, pKSchemaNameLength: {}, pKTableName: {}, pKTableNameLength: " - "{}, " - "fKCatalogName: {}, fKCatalogNameLength: {}, fKSchemaName: {}, fKSchemaNameLength: " - "{}, " - "fKTableName: {}, fKTableNameLength : {}", - stmt, fmt::ptr(pKCatalogName), pKCatalogNameLength, fmt::ptr(pKSchemaName), - pKSchemaNameLength, fmt::ptr(pKTableName), pKTableNameLength, - fmt::ptr(fKCatalogName), fKCatalogNameLength, fmt::ptr(fKSchemaName), - fKSchemaNameLength, fmt::ptr(fKTableName), fKTableNameLength); + LOG_DEBUG("SQLForeignKeysW called with stmt: " + << stmt << ", pKCatalogName: " << static_cast(pKCatalogName) + << ", pKCatalogNameLength: " << pKCatalogNameLength + << ", pKSchemaName: " << static_cast(pKSchemaName) + << ", pKSchemaNameLength: " << pKSchemaNameLength + << ", pKTableName: " << static_cast(pKTableName) + << ", pKTableNameLength: " << pKTableNameLength + << ", fKCatalogName: " << static_cast(fKCatalogName) + << ", fKCatalogNameLength: " << fKCatalogNameLength + << ", fKSchemaName: " << static_cast(fKSchemaName) + << ", fKSchemaNameLength: " << fKSchemaNameLength + << ", fKTableName: " << static_cast(fKTableName) + << ", fKTableNameLength: " << fKTableNameLength); return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLForeignKeysW is not implemented", "IM001"); @@ -270,12 +271,13 @@ SQLRETURN SQL_API SQLPrimaryKeys(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, SQLSMALLINT tableNameLength) { - LOG_DEBUG( - "SQLPrimaryKeysW called with stmt: {}, catalogName: {}, " - "catalogNameLength: " - "{}, schemaName: {}, schemaNameLength: {}, tableName: {}, tableNameLength: {}", - stmt, fmt::ptr(catalogName), catalogNameLength, fmt::ptr(schemaName), - schemaNameLength, fmt::ptr(tableName), tableNameLength); + LOG_DEBUG("SQLPrimaryKeysW called with stmt: " + << stmt << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength); return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLPrimaryKeysW is not implemented", "IM001"); diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index cd3bf30132b..2c9af34a75d 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -43,7 +43,7 @@ namespace arrow { SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) { LOG_DEBUG("SQLAllocHandle called with type: " << type << ", parent: " << parent << ", result: " - << static_cast(result);); + << static_cast(result)); *result = nullptr; @@ -137,7 +137,7 @@ SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) } SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) { - LOG_DEBUG("SQLFreeHandle called with type: {}, handle: {}", type, handle); + LOG_DEBUG("SQLFreeHandle called with type: " << type << ", handle: " << handle); switch (type) { case SQL_HANDLE_ENV: { @@ -204,6 +204,8 @@ SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) { } SQLRETURN SQLFreeStmt(SQLHSTMT handle, SQLUSMALLINT option) { + LOG_DEBUG("SQLAllocHandle called with handle: " << handle << ", option: " << option); + switch (option) { case SQL_CLOSE: { using ODBC::ODBCStatement; @@ -262,11 +264,11 @@ SQLRETURN SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr) { // TODO: Implement additional fields types // https://github.com/apache/arrow/issues/46573 - LOG_DEBUG( - "SQLGetDiagFieldW called with handleType: {}, handle: {}, recNumber: {}, " - "diagIdentifier: {}, diagInfoPtr: {}, bufferLength: {}, stringLengthPtr: {}", - handleType, handle, recNumber, diagIdentifier, diagInfoPtr, bufferLength, - fmt::ptr(stringLengthPtr)); + LOG_DEBUG("SQLGetDiagFieldW called with handleType: " + << handleType << ", handle: " << handle << ", recNumber: " << recNumber + << ", diagIdentifier: " << diagIdentifier << ", diagInfoPtr: " << diagInfoPtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr)); using driver::odbcabstraction::Diagnostics; using ODBC::GetStringAttribute; @@ -521,12 +523,13 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT re SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, SQLWCHAR* messageText, SQLSMALLINT bufferLength, SQLSMALLINT* textLengthPtr) { - LOG_DEBUG( - "SQLGetDiagRecW called with handleType: {}, handle: {}, recNumber: {}, " - "sqlState: {}, nativeErrorPtr: {}, messageText: {}, bufferLength: {}, " - "textLengthPtr: {}", - handleType, handle, recNumber, fmt::ptr(sqlState), fmt::ptr(nativeErrorPtr), - fmt::ptr(messageText), bufferLength, fmt::ptr(textLengthPtr)); + LOG_DEBUG("SQLGetDiagRecW called with handleType: " + << handleType << ", handle: " << handle << ", recNumber: " << recNumber + << ", sqlState: " << static_cast(sqlState) + << ", nativeErrorPtr: " << static_cast(nativeErrorPtr) + << ", messageText: " << static_cast(messageText) + << ", bufferLength: " << bufferLength + << ", textLengthPtr: " << static_cast(textLengthPtr)); using driver::odbcabstraction::Diagnostics; using ODBC::GetStringAttribute; @@ -609,10 +612,10 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT re SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* strLenPtr) { - LOG_DEBUG( - "SQLGetEnvAttr called with env: {}, attr: {}, valuePtr: {}, " - "bufferLength: {}, strLenPtr: {}", - env, attr, valuePtr, bufferLength, fmt::ptr(strLenPtr)); + LOG_DEBUG("SQLGetEnvAttr called with env: " + << env << ", attr: " << attr << ", valuePtr: " << valuePtr + << ", bufferLength: " << bufferLength + << ", strLenPtr: " << static_cast(strLenPtr)); using driver::odbcabstraction::DriverException; using ODBC::ODBCEnvironment; @@ -669,10 +672,9 @@ SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER strLen) { - LOG_DEBUG( - "SQLSetEnvAttr called with env: {}, attr: {}, valuePtr: {}, " - "strLen: {}", - env, attr, valuePtr, strLen); + LOG_DEBUG("SQLSetEnvAttr called with env: " << env << ", attr: " << attr + << ", valuePtr: " << valuePtr + << ", strLen: " << strLen); using driver::odbcabstraction::DriverException; using ODBC::ODBCEnvironment; @@ -720,10 +722,10 @@ SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* stringLengthPtr) { - LOG_DEBUG( - "SQLGetConnectAttrW called with conn: {}, attribute: {}, valuePtr: {}, " - "bufferLength: {}, stringLengthPtr: {}", - conn, attribute, valuePtr, bufferLength, fmt::ptr(stringLengthPtr)); + LOG_DEBUG("SQLGetConnectAttrW called with conn: " + << conn << ", attribute: " << attribute << ", valuePtr: " << valuePtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr)); using driver::odbcabstraction::Connection; using ODBC::ODBCConnection; @@ -738,9 +740,9 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER value SQLRETURN SQLSetConnectAttr(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER valueLen) { - LOG_DEBUG( - "SQLSetConnectAttrW called with conn: {}, attr: {}, valuePtr: {}, valueLen: {}", - conn, attr, valuePtr, valueLen); + LOG_DEBUG("SQLSetConnectAttrW called with conn: " << conn << ", attr: " << attr + << ", valuePtr: " << valuePtr + << ", valueLen: " << valueLen); using driver::odbcabstraction::Connection; using ODBC::ODBCConnection; @@ -760,13 +762,15 @@ SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLSMALLINT outConnectionStringBufferLen, SQLSMALLINT* outConnectionStringLen, SQLUSMALLINT driverCompletion) { - LOG_DEBUG( - "SQLDriverConnectW called with conn: {}, windowHandle: {}, inConnectionString: {}, " - "inConnectionStringLen: {}, outConnectionString: {}, outConnectionStringBufferLen: " - "{}, outConnectionStringLen: {}, driverCompletion: {}", - conn, fmt::ptr(windowHandle), fmt::ptr(inConnectionString), inConnectionStringLen, - fmt::ptr(outConnectionString), outConnectionStringBufferLen, - fmt::ptr(outConnectionStringLen), driverCompletion); + LOG_DEBUG("SQLDriverConnectW called with conn: " + << conn << ", windowHandle: " << static_cast(windowHandle) + << ", inConnectionString: " << static_cast(inConnectionString) + << ", inConnectionStringLen: " << inConnectionStringLen + << ", outConnectionString: " << static_cast(outConnectionString) + << ", outConnectionStringBufferLen: " << outConnectionStringBufferLen + << ", outConnectionStringLen: " + << static_cast(outConnectionStringLen) + << ", driverCompletion: " << driverCompletion); // TODO: Implement FILEDSN and SAVEFILE keywords according to the spec // https://github.com/apache/arrow/issues/46449 @@ -836,11 +840,12 @@ SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, SQLSMALLINT passwordLen) { - LOG_DEBUG( - "SQLConnectW called with conn: {}, dsnName: {}, dsnNameLen: {}, userName: {}, " - "userNameLen: {}, password: {}, passwordLen: {}", - conn, fmt::ptr(dsnName), dsnNameLen, fmt::ptr(userName), userNameLen, - fmt::ptr(password), passwordLen); + LOG_DEBUG("SQLConnectW called with conn: " + << conn << ", dsnName: " << static_cast(dsnName) + << ", dsnNameLen: " << dsnNameLen << ", userName: " + << static_cast(userName) << ", userNameLen: " << userNameLen + << ", password: " << static_cast(password) + << ", passwordLen: " << passwordLen); using driver::flight_sql::FlightSqlConnection; using driver::flight_sql::config::Configuration; @@ -874,7 +879,7 @@ SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, } SQLRETURN SQLDisconnect(SQLHDBC conn) { - LOG_DEBUG("SQLDisconnect called with conn: {}", conn); + LOG_DEBUG("SQLDisconnect called with conn: " << conn); using ODBC::ODBCConnection; @@ -889,10 +894,10 @@ SQLRETURN SQLDisconnect(SQLHDBC conn) { SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, SQLSMALLINT bufLen, SQLSMALLINT* stringLengthPtr) { - LOG_DEBUG( - "SQLGetInfo called with conn: {}, infoType: {}, infoValuePtr: {}, bufLen: {}, " - "stringLengthPtr: {}", - conn, infoType, infoValuePtr, bufLen, fmt::ptr(stringLengthPtr)); + LOG_DEBUG("SQLGetInfo called with conn: " + << conn << ", infoType: " << infoType << ", infoValuePtr: " << infoValuePtr + << ", bufLen: " << bufLen + << ", stringLengthPtr: " << static_cast(stringLengthPtr)); using ODBC::ODBCConnection; @@ -913,10 +918,11 @@ SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePt SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* stringLengthPtr) { - LOG_DEBUG( - "SQLGetStmtAttrW called with stmt: {}, attribute: {}, valuePtr: {}, " - "bufferLength: {}, stringLengthPtr: {}", - stmt, attribute, valuePtr, bufferLength, fmt::ptr(stringLengthPtr)); + LOG_DEBUG("SQLGetStmtAttrW called with stmt: " + << stmt << ", attribute: " << attribute << ", valuePtr: " << valuePtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr)); + using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -932,10 +938,10 @@ SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePt SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER stringLength) { - LOG_DEBUG( - "SQLSetStmtAttrW called with stmt: {}, attribute: {}, valuePtr: {}, " - "stringLength: {}", - stmt, attribute, valuePtr, stringLength); + LOG_DEBUG("SQLSetStmtAttrW called with stmt: " << stmt << ", attribute: " << attribute + << ", valuePtr: " << valuePtr + << ", stringLength: " << stringLength); + using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -950,8 +956,10 @@ SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePt } SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) { - LOG_DEBUG("SQLExecDirectW called with stmt: {}, queryText: {}, textLength: {}", stmt, - fmt::ptr(queryText), textLength); + LOG_DEBUG("SQLExecDirectW called with stmt: " << stmt << ", queryText: " + << static_cast(queryText) + << ", textLength: " << textLength); + using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -966,8 +974,10 @@ SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLengt } SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) { - LOG_DEBUG("SQLPrepareW called with stmt: {}, queryText: {}, textLength: {}", stmt, - fmt::ptr(queryText), textLength); + LOG_DEBUG("SQLPrepareW called with stmt: " << stmt << ", queryText: " + << static_cast(queryText) + << ", textLength: " << textLength); + using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -981,7 +991,7 @@ SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) } SQLRETURN SQLExecute(SQLHSTMT stmt) { - LOG_DEBUG("SQLExecute called with stmt: {}", stmt); + LOG_DEBUG("SQLExecute called with stmt: " << stmt); using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. @@ -995,7 +1005,7 @@ SQLRETURN SQLExecute(SQLHSTMT stmt) { } SQLRETURN SQLFetch(SQLHSTMT stmt) { - LOG_DEBUG("SQLFetch called with stmt: {}", stmt); + LOG_DEBUG("SQLFetch called with stmt: " << stmt); using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1021,11 +1031,11 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, SQLUSMALLINT* rowStatusArray) { // GH-47110: SQLExtendedFetch should return SQL_SUCCESS_WITH_INFO for certain diag // states - LOG_DEBUG( - "SQLExtendedFetch called with stmt: {}, fetchOrientation: {}, fetchOffset: {}, " - "rowCountPtr: {}, rowStatusArray: {}", - stmt, fetchOrientation, fetchOffset, fmt::ptr(rowCountPtr), - fmt::ptr(rowStatusArray)); + LOG_DEBUG("SQLExtendedFetch called with stmt: " + << stmt << ", fetchOrientation: " << fetchOrientation << ", fetchOffset: " + << fetchOffset << ", rowCountPtr: " << static_cast(rowCountPtr) + << ", rowStatusArray: " << static_cast(rowStatusArray)); + using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1039,7 +1049,8 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, // The SQL_ROWSET_SIZE statement attribute specifies the number of rows in the // rowset. SQLULEN rowSetSize = statement->GetRowsetSize(); - LOG_DEBUG("SQL_ROWSET_SIZE value for SQLExtendedFetch: {}", rowSetSize); + LOG_DEBUG("SQL_ROWSET_SIZE value for SQLExtendedFetch: " << rowSetSize); + if (statement->Fetch(static_cast(rowSetSize), rowCountPtr, rowStatusArray)) { return SQL_SUCCESS; } else { @@ -1051,8 +1062,10 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT fetchOrientation, SQLLEN fetchOffset) { - LOG_DEBUG("SQLFetchScroll called with stmt: {}, fetchOrientation: {}, fetchOffset: {}", - stmt, fetchOrientation, fetchOffset); + LOG_DEBUG("SQLFetchScroll called with stmt: " << stmt << ", fetchOrientation: " + << fetchOrientation + << ", fetchOffset: " << fetchOffset); + using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1078,10 +1091,11 @@ SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT fetchOrientation, SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType, SQLPOINTER dataPtr, SQLLEN bufferLength, SQLLEN* indicatorPtr) { - LOG_DEBUG( - "SQLBindCol called with stmt: {}, recordNumber: {}, cType: {}, " - "dataPtr: {}, bufferLength: {}, strLen_or_IndPtr: {}", - stmt, recordNumber, cType, dataPtr, bufferLength, fmt::ptr(indicatorPtr)); + LOG_DEBUG("SQLBindCol called with stmt: " + << stmt << ", recordNumber: " << recordNumber << ", cType: " << cType + << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength + << ", strLen_or_IndPtr: " << static_cast(indicatorPtr)); + using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1094,7 +1108,8 @@ SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType } SQLRETURN SQLCloseCursor(SQLHSTMT stmt) { - LOG_DEBUG("SQLCloseCursor called with stmt: {}", stmt); + LOG_DEBUG("SQLCloseCursor called with stmt: " << stmt); + using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { ODBCStatement* statement = reinterpret_cast(stmt); @@ -1111,10 +1126,10 @@ SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType // GH-46979: support SQL_C_GUID data type // GH-46980: support Interval data types // GH-46985: return warning message instead of error on float truncation case - LOG_DEBUG( - "SQLGetData called with stmt: {}, recordNumber: {}, cType: {}, " - "dataPtr: {}, bufferLength: {}, indicatorPtr: {}", - stmt, recordNumber, cType, dataPtr, bufferLength, fmt::ptr(indicatorPtr)); + LOG_DEBUG("SQLGetData called with stmt: " + << stmt << ", recordNumber: " << recordNumber << ", cType: " << cType + << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength + << ", indicatorPtr: " << static_cast(indicatorPtr)); using ODBC::ODBCStatement; @@ -1125,7 +1140,8 @@ SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType } SQLRETURN SQLMoreResults(SQLHSTMT stmt) { - LOG_DEBUG("SQLMoreResults called with stmt: {}", stmt); + LOG_DEBUG("SQLMoreResults called with stmt: " << stmt); + using ODBC::ODBCStatement; // Multiple result sets not supported. Return SQL_NO_DATA by default. return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1135,8 +1151,9 @@ SQLRETURN SQLMoreResults(SQLHSTMT stmt) { } SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) { - LOG_DEBUG("SQLNumResultCols called with stmt: {}, columnCountPtr: {}", stmt, - fmt::ptr(columnCountPtr)); + LOG_DEBUG("SQLNumResultCols called with stmt: " + << stmt << ", columnCountPtr: " << static_cast(columnCountPtr)); + using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { ODBCStatement* statement = reinterpret_cast(stmt); @@ -1146,8 +1163,9 @@ SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) { } SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCountPtr) { - LOG_DEBUG("SQLRowCount called with stmt: {}, columnCountPtr: {}", stmt, - fmt::ptr(rowCountPtr)); + LOG_DEBUG("SQLRowCount called with stmt: " << stmt << ", columnCountPtr: " + << static_cast(rowCountPtr)); + using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { ODBCStatement* statement = reinterpret_cast(stmt); @@ -1160,15 +1178,16 @@ SQLRETURN SQLTables(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNam SQLWCHAR* schemaName, SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, SQLSMALLINT tableNameLength, SQLWCHAR* tableType, SQLSMALLINT tableTypeLength) { - LOG_DEBUG( - "SQLTables called with stmt: {}, catalogName: {}, catalogNameLength: " - "{}, " - "schemaName: {}, schemaNameLength: {}, tableName: {}, tableNameLength: {}, " - "tableType: {}, " - "tableTypeLength: {}", - stmt, fmt::ptr(catalogName), catalogNameLength, fmt::ptr(schemaName), - schemaNameLength, fmt::ptr(tableName), tableNameLength, fmt::ptr(tableType), - tableTypeLength); + LOG_DEBUG("SQLTables called with stmt: " + << stmt << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength + << ", tableType: " << static_cast(tableType) + << ", tableTypeLength: " << tableTypeLength); + using ODBC::ODBCStatement; using ODBC::SqlWcharToString; @@ -1193,15 +1212,15 @@ SQLRETURN SQLColumns(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNa SQLWCHAR* columnName, SQLSMALLINT columnNameLength) { // GH-47159: Return NUM_PREC_RADIX based on whether COLUMN_SIZE contains number of // digits or bits - LOG_DEBUG( - "SQLColumnsW called with stmt: {}, catalogName: {}, catalogNameLength: " - "{}, " - "schemaName: {}, schemaNameLength: {}, tableName: {}, tableNameLength: {}, " - "columnName: {}, " - "columnNameLength: {}", - stmt, fmt::ptr(catalogName), catalogNameLength, fmt::ptr(schemaName), - schemaNameLength, fmt::ptr(tableName), tableNameLength, fmt::ptr(columnName), - columnNameLength); + LOG_DEBUG("SQLColumnsW called with stmt: " + << stmt << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength + << ", columnName: " << static_cast(columnName) + << ", columnNameLength: " << columnNameLength); using ODBC::ODBCStatement; using ODBC::SqlWcharToString; @@ -1226,12 +1245,13 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLUSMALLINT fieldIdentifier, SQLPOINTER characterAttributePtr, SQLSMALLINT bufferLength, SQLSMALLINT* outputLength, SQLLEN* numericAttributePtr) { - LOG_DEBUG( - "SQLColAttributeW called with stmt: {}, recordNumber: {}, " - "fieldIdentifier: {}, characterAttributePtr: {}, bufferLength: {}, " - "outputLength: {}, numericAttributePtr: {}", - stmt, recordNumber, fieldIdentifier, characterAttributePtr, bufferLength, - fmt::ptr(outputLength), fmt::ptr(numericAttributePtr)); + LOG_DEBUG("SQLColAttributeW called with stmt: " + << stmt << ", recordNumber: " << recordNumber << ", fieldIdentifier: " + << fieldIdentifier << ", characterAttributePtr: " << characterAttributePtr + << ", bufferLength: " << bufferLength << ", outputLength: " + << static_cast(outputLength) << ", numericAttributePtr: " + << static_cast(numericAttributePtr)); + using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1320,7 +1340,8 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT dataType) { // GH-47237 return SQL_PRED_CHAR and SQL_PRED_BASIC for // appropriate data types in `SEARCHABLE` field - LOG_DEBUG("SQLGetTypeInfoW called with stmt: {} dataType: {}", stmt, dataType); + LOG_DEBUG("SQLGetTypeInfoW called with stmt: " << stmt << " dataType: " << dataType); + using ODBC::ODBCStatement; return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { ODBCStatement* statement = reinterpret_cast(stmt); @@ -1379,12 +1400,13 @@ SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT dataType) { SQLRETURN SQLNativeSql(SQLHDBC connectionHandle, SQLWCHAR* inStatementText, SQLINTEGER inStatementTextLength, SQLWCHAR* outStatementText, SQLINTEGER bufferLength, SQLINTEGER* outStatementTextLength) { - LOG_DEBUG( - "SQLNativeSqlW called with connectionHandle: {}, inStatementText: {}, " - "inStatementTextLength: {}, outStatementText: {}, bufferLength: {}, " - "outStatementTextLength: {}", - connectionHandle, fmt::ptr(inStatementText), inStatementTextLength, - fmt::ptr(outStatementText), bufferLength, fmt::ptr(outStatementTextLength)); + LOG_DEBUG("SQLNativeSqlW called with connectionHandle: " + << connectionHandle + << ", inStatementText: " << static_cast(inStatementText) + << ", inStatementTextLength: " << inStatementTextLength + << ", outStatementText: " << static_cast(outStatementText) + << ", bufferLength: " << bufferLength << ", outStatementTextLength: " + << static_cast(outStatementTextLength)); using driver::odbcabstraction::Diagnostics; using ODBC::GetAttributeSQLWCHAR; @@ -1408,13 +1430,15 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT columnNumber, SQLWCHAR* col SQLSMALLINT bufferLength, SQLSMALLINT* nameLengthPtr, SQLSMALLINT* dataTypePtr, SQLULEN* columnSizePtr, SQLSMALLINT* decimalDigitsPtr, SQLSMALLINT* nullablePtr) { - LOG_DEBUG( - "SQLDescribeColW called with stmt: {}, columnNumber: {}, " - "columnName: {}, bufferLength: {}, nameLengthPtr: {}, dataTypePtr: {}, " - "columnSizePtr: {}, decimalDigitsPtr: {}, nullablePtr: {}", - stmt, columnNumber, fmt::ptr(columnName), bufferLength, fmt::ptr(nameLengthPtr), - fmt::ptr(dataTypePtr), fmt::ptr(columnSizePtr), fmt::ptr(decimalDigitsPtr), - fmt::ptr(nullablePtr)); + LOG_DEBUG("SQLDescribeColW called with stmt: " + << stmt << ", columnNumber: " << columnNumber << ", columnName: " + << static_cast(columnName) << ", bufferLength: " << bufferLength + << ", nameLengthPtr: " << static_cast(nameLengthPtr) + << ", dataTypePtr: " << static_cast(dataTypePtr) + << ", columnSizePtr: " << static_cast(columnSizePtr) + << ", decimalDigitsPtr: " << static_cast(decimalDigitsPtr) + << ", nullablePtr: " << static_cast(nullablePtr)); + using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; From f77bfdaef739c0c6f2e9768f3d19fe4da7c2b8f2 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 22 Sep 2025 15:37:57 -0700 Subject: [PATCH 04/10] Use Arrow Log to enable logging --- cpp/cmake_modules/DefineOptions.cmake | 3 -- .../sql/odbc/flight_sql/flight_sql_driver.cc | 42 +++++++++++++++++++ .../include/flight_sql/flight_sql_driver.h | 2 + .../include/odbcabstraction/spi/driver.h | 3 ++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/cpp/cmake_modules/DefineOptions.cmake b/cpp/cmake_modules/DefineOptions.cmake index 234b9b177cb..3f1f6bf53ff 100644 --- a/cpp/cmake_modules/DefineOptions.cmake +++ b/cpp/cmake_modules/DefineOptions.cmake @@ -111,9 +111,6 @@ macro(resolve_option_dependencies) if(NOT WIN32 AND NOT APPLE) set(ARROW_FLIGHT_SQL_ODBC OFF) endif() - if(MSVC_TOOLCHAIN) - set(ARROW_USE_GLOG OFF) - endif() # Tests are crashed with mold + sanitizer checks. if(ARROW_USE_ASAN OR ARROW_USE_TSAN diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc index 0b217b7a952..e9bd79a5c79 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc @@ -19,9 +19,37 @@ #include "arrow/compute/api.h" #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" #include "arrow/flight/sql/odbc/flight_sql/utils.h" +#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/platform.h" #include "arrow/util/io_util.h" +#define ODBC_LOG_PATH "ARROW_ODBC_LOG_PATH" +#define ODBC_LOG_LEVEL "ARROW_ODBC_LOG_LEVEL" + +using arrow::util::ArrowLogLevel; + +namespace { +/// Return the corresponding ArrowLogLevel. Debug level is returned by default. +ArrowLogLevel ToLogLevel(int64_t level) { + switch (level) { + case -2: + return ArrowLogLevel::ARROW_TRACE; + case -1: + return ArrowLogLevel::ARROW_DEBUG; + case 0: + return ArrowLogLevel::ARROW_INFO; + case 1: + return ArrowLogLevel::ARROW_WARNING; + case 2: + return ArrowLogLevel::ARROW_ERROR; + case 3: + return ArrowLogLevel::ARROW_FATAL; + default: + return ArrowLogLevel::ARROW_DEBUG; + } +} +} // namespace + namespace driver { namespace flight_sql { @@ -30,6 +58,7 @@ using odbcabstraction::OdbcVersion; FlightSqlDriver::FlightSqlDriver() : diagnostics_("Apache Arrow", "Flight SQL", OdbcVersion::V_3), version_("0.9.0.0") { + RegisterLog(); // Register Kernel functions to library ThrowIfNotOK(arrow::compute::Initialize()); } @@ -42,5 +71,18 @@ odbcabstraction::Diagnostics& FlightSqlDriver::GetDiagnostics() { return diagnos void FlightSqlDriver::SetVersion(std::string version) { version_ = std::move(version); } +void FlightSqlDriver::RegisterLog() { + std::string log_level_str = arrow::internal::GetEnvVar(ODBC_LOG_LEVEL).ValueOr(""); + if (log_level_str.empty()) { + return; + } + std::string log_path = arrow::internal::GetEnvVar(ODBC_LOG_PATH).ValueOr(""); + auto log_level = ToLogLevel(std::stoi(log_level_str)); + + // Enable driver logging. Log files are not supported on Windows yet, since GLOG is not + // tested fully on Windows. + arrow::util::ArrowLog::StartArrowLog("arrow-flight-sql-odbc", log_level, log_path); +} + } // namespace flight_sql } // namespace driver diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h index ca6d197bb46..48f2a16416a 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h @@ -37,6 +37,8 @@ class FlightSqlDriver : public odbcabstraction::Driver { odbcabstraction::Diagnostics& GetDiagnostics() override; void SetVersion(std::string version) override; + + void RegisterLog() override; }; }; // namespace flight_sql diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h index 417f10d091f..61d570574c7 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/driver.h @@ -45,6 +45,9 @@ class Driver { /// \brief Sets the driver version. virtual void SetVersion(std::string version) = 0; + + /// \brief Register a log to be used by the system. + virtual void RegisterLog() = 0; }; } // namespace odbcabstraction From fca9832212cc378b3497cde44dcbb4cbca10f38f Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 22 Sep 2025 15:38:33 -0700 Subject: [PATCH 05/10] Add `ARROW_USE_GLOG OFF` back It is up to Arrow community to enable GLOG on Windows --- cpp/cmake_modules/DefineOptions.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/cmake_modules/DefineOptions.cmake b/cpp/cmake_modules/DefineOptions.cmake index 3f1f6bf53ff..234b9b177cb 100644 --- a/cpp/cmake_modules/DefineOptions.cmake +++ b/cpp/cmake_modules/DefineOptions.cmake @@ -111,6 +111,9 @@ macro(resolve_option_dependencies) if(NOT WIN32 AND NOT APPLE) set(ARROW_FLIGHT_SQL_ODBC OFF) endif() + if(MSVC_TOOLCHAIN) + set(ARROW_USE_GLOG OFF) + endif() # Tests are crashed with mold + sanitizer checks. if(ARROW_USE_ASAN OR ARROW_USE_TSAN From 79fa39b78a7018fa1bc5419c5d6a19e99762f6cc Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 22 Sep 2025 16:06:49 -0700 Subject: [PATCH 06/10] Add logging README --- cpp/src/arrow/flight/sql/odbc/README | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/README b/cpp/src/arrow/flight/sql/odbc/README index da9857b7ecc..1e0b68aa858 100644 --- a/cpp/src/arrow/flight/sql/odbc/README +++ b/cpp/src/arrow/flight/sql/odbc/README @@ -1,4 +1,4 @@ -Steps to Register the 64-bit Apache Arrow ODBC driver on Windows +## Steps to Register the 64-bit Apache Arrow ODBC driver on Windows After the build succeeds, the ODBC DLL will be located in `build\debug\Debug` for a debug build and `build\release\Release` for a release build. @@ -18,9 +18,26 @@ After the build succeeds, the ODBC DLL will be located in If the registration is successful, then Apache Arrow Flight SQL ODBC Driver should show as an available ODBC driver in the x64 ODBC Driver Manager. -Steps to Generate Windows Installer +## Steps to Generate Windows Installer 1. Build with `ARROW_FLIGHT_SQL_ODBC=ON` and `ARROW_FLIGHT_SQL_ODBC_INSTALLER=ON`. 2. `cd` to `build` folder. 3. Run `cpack`. If the generation is successful, you will find `Apache Arrow Flight SQL ODBC--win64.msi` generated under the `build` folder. + + +## Steps to Enable Logging +Arrow Flight SQL ODBC driver uses Arrow's internal logging framework. By default, the log messages are printed to the terminal. +1. Set environment variable `ARROW_ODBC_LOG_LEVEL` to any of the following valid value. + +| LogLevel | Description | +|----------|-------------| +| -2 | TRACE | +| -1 | DEBUG | +| 0 | INFO | +| 1 | WARNING | +| 2 | ERROR | +| 3 | FATAL | +| Empty String or not set | No log messages displayed.| + +2. On non-Windows platform, set `ARROW_ODBC_LOG_PATH` to a valid path for log files. `ARROW_USE_GLOG=ON` is required for driver to write into log files. Note that `ARROW_USE_GLOG` is disabled on Windows platform since plasma using `glog` is not fully tested on windows. \ No newline at end of file From 7345021ce8bc11ef2c0af2b3e59776ad2ed8873e Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 22 Sep 2025 16:27:24 -0700 Subject: [PATCH 07/10] register kernel function conditionally Resolves errors of kernel function already registered --- .../sql/odbc/flight_sql/flight_sql_driver.cc | 14 ++++++++++++-- .../include/flight_sql/flight_sql_driver.h | 3 +++ .../arrow/flight/sql/odbc/tests/connection_test.cc | 3 +++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc index e9bd79a5c79..10c4d0d092b 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc @@ -59,8 +59,7 @@ using odbcabstraction::OdbcVersion; FlightSqlDriver::FlightSqlDriver() : diagnostics_("Apache Arrow", "Flight SQL", OdbcVersion::V_3), version_("0.9.0.0") { RegisterLog(); - // Register Kernel functions to library - ThrowIfNotOK(arrow::compute::Initialize()); + RegisterComputeKernels(); } std::shared_ptr FlightSqlDriver::CreateConnection(OdbcVersion odbc_version) { @@ -71,6 +70,17 @@ odbcabstraction::Diagnostics& FlightSqlDriver::GetDiagnostics() { return diagnos void FlightSqlDriver::SetVersion(std::string version) { version_ = std::move(version); } +void FlightSqlDriver::RegisterComputeKernels() { + auto registry = arrow::compute::GetFunctionRegistry(); + + // strptime is one of the required compute functions + auto strptime_func = registry->GetFunction("strptime"); + if (!strptime_func.ok()) { + // Register Kernel functions to library + ThrowIfNotOK(arrow::compute::Initialize()); + } +} + void FlightSqlDriver::RegisterLog() { std::string log_level_str = arrow::internal::GetEnvVar(ODBC_LOG_LEVEL).ValueOr(""); if (log_level_str.empty()) { diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h index 48f2a16416a..b11c52a5c38 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h @@ -38,6 +38,9 @@ class FlightSqlDriver : public odbcabstraction::Driver { void SetVersion(std::string version) override; + /// Register Arrow Compute kernels once. + void RegisterComputeKernels(); + void RegisterLog() override; }; diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc index 21d4ef4f8b5..5ba7a01638e 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc @@ -836,6 +836,9 @@ TYPED_TEST(FlightSQLODBCTestBase, TestConnect) { // Verifies connect and disconnect works on its own this->connect(); this->disconnect(); + + this->connect(); + this->disconnect(); } TYPED_TEST(FlightSQLODBCTestBase, TestSQLAllocFreeStmt) { From c4c1bfcb353d9d3e610cdce3bdcc3f6681f832c5 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Mon, 22 Sep 2025 16:45:09 -0700 Subject: [PATCH 08/10] Remove log files support We can work + test on log file support on macOS/Linux phase --- cpp/src/arrow/flight/sql/odbc/README | 2 +- cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/src/arrow/flight/sql/odbc/README b/cpp/src/arrow/flight/sql/odbc/README index 1e0b68aa858..03f7f7390a3 100644 --- a/cpp/src/arrow/flight/sql/odbc/README +++ b/cpp/src/arrow/flight/sql/odbc/README @@ -40,4 +40,4 @@ Arrow Flight SQL ODBC driver uses Arrow's internal logging framework. By default | 3 | FATAL | | Empty String or not set | No log messages displayed.| -2. On non-Windows platform, set `ARROW_ODBC_LOG_PATH` to a valid path for log files. `ARROW_USE_GLOG=ON` is required for driver to write into log files. Note that `ARROW_USE_GLOG` is disabled on Windows platform since plasma using `glog` is not fully tested on windows. \ No newline at end of file +The Windows ODBC driver currently does not support writing log files. `ARROW_USE_GLOG` is required to write log files, and `ARROW_USE_GLOG` is disabled on Windows platform since plasma using `glog` is not fully tested on windows. diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc index 10c4d0d092b..56a968e1a09 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc @@ -23,7 +23,6 @@ #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/platform.h" #include "arrow/util/io_util.h" -#define ODBC_LOG_PATH "ARROW_ODBC_LOG_PATH" #define ODBC_LOG_LEVEL "ARROW_ODBC_LOG_LEVEL" using arrow::util::ArrowLogLevel; @@ -86,12 +85,11 @@ void FlightSqlDriver::RegisterLog() { if (log_level_str.empty()) { return; } - std::string log_path = arrow::internal::GetEnvVar(ODBC_LOG_PATH).ValueOr(""); auto log_level = ToLogLevel(std::stoi(log_level_str)); // Enable driver logging. Log files are not supported on Windows yet, since GLOG is not // tested fully on Windows. - arrow::util::ArrowLog::StartArrowLog("arrow-flight-sql-odbc", log_level, log_path); + arrow::util::ArrowLog::StartArrowLog("arrow-flight-sql-odbc", log_level); } } // namespace flight_sql From fca34475315a4673de06a0a61b4d944765fb3137 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Tue, 23 Sep 2025 10:28:41 -0700 Subject: [PATCH 09/10] Address todos for PR --- cpp/src/arrow/flight/sql/odbc/entry_points.cc | 44 +-- .../sql/odbc/flight_sql/flight_sql_driver.cc | 2 +- .../sql/odbc/flight_sql/win_system_dsn.cc | 4 +- cpp/src/arrow/flight/sql/odbc/odbc_api.cc | 266 +++++++++--------- .../include/odbcabstraction/logger.h | 27 -- .../flight/sql/odbc/tests/connection_test.cc | 3 - 6 files changed, 162 insertions(+), 184 deletions(-) delete mode 100644 cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h diff --git a/cpp/src/arrow/flight/sql/odbc/entry_points.cc b/cpp/src/arrow/flight/sql/odbc/entry_points.cc index 611175c8e62..bcf93f6a983 100644 --- a/cpp/src/arrow/flight/sql/odbc/entry_points.cc +++ b/cpp/src/arrow/flight/sql/odbc/entry_points.cc @@ -35,7 +35,7 @@ #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_environment.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_statement.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" +#include "arrow/util/logging.h" SQLRETURN SQL_API SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) { return arrow::SQLAllocHandle(type, parent, result); @@ -178,7 +178,7 @@ SQLRETURN SQL_API SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLI } SQLRETURN SQL_API SQLCancel(SQLHSTMT stmt) { - LOG_DEBUG("SQLCancel called with stmt: " << stmt); + ARROW_LOG(DEBUG) << "SQLCancel called with stmt: " << stmt; return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLCancel is not implemented", "IM001"); @@ -225,19 +225,19 @@ SQLRETURN SQL_API SQLForeignKeys(SQLHSTMT stmt, SQLWCHAR* pKCatalogName, SQLSMALLINT fKCatalogNameLength, SQLWCHAR* fKSchemaName, SQLSMALLINT fKSchemaNameLength, SQLWCHAR* fKTableName, SQLSMALLINT fKTableNameLength) { - LOG_DEBUG("SQLForeignKeysW called with stmt: " - << stmt << ", pKCatalogName: " << static_cast(pKCatalogName) - << ", pKCatalogNameLength: " << pKCatalogNameLength - << ", pKSchemaName: " << static_cast(pKSchemaName) - << ", pKSchemaNameLength: " << pKSchemaNameLength - << ", pKTableName: " << static_cast(pKTableName) - << ", pKTableNameLength: " << pKTableNameLength - << ", fKCatalogName: " << static_cast(fKCatalogName) - << ", fKCatalogNameLength: " << fKCatalogNameLength - << ", fKSchemaName: " << static_cast(fKSchemaName) - << ", fKSchemaNameLength: " << fKSchemaNameLength - << ", fKTableName: " << static_cast(fKTableName) - << ", fKTableNameLength: " << fKTableNameLength); + ARROW_LOG(DEBUG) << "SQLForeignKeysW called with stmt: " << stmt + << ", pKCatalogName: " << static_cast(pKCatalogName) + << ", pKCatalogNameLength: " << pKCatalogNameLength + << ", pKSchemaName: " << static_cast(pKSchemaName) + << ", pKSchemaNameLength: " << pKSchemaNameLength + << ", pKTableName: " << static_cast(pKTableName) + << ", pKTableNameLength: " << pKTableNameLength + << ", fKCatalogName: " << static_cast(fKCatalogName) + << ", fKCatalogNameLength: " << fKCatalogNameLength + << ", fKSchemaName: " << static_cast(fKSchemaName) + << ", fKSchemaNameLength: " << fKSchemaNameLength + << ", fKTableName: " << static_cast(fKTableName) + << ", fKTableNameLength: " << fKTableNameLength; return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLForeignKeysW is not implemented", "IM001"); @@ -271,13 +271,13 @@ SQLRETURN SQL_API SQLPrimaryKeys(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNameLength, SQLWCHAR* schemaName, SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, SQLSMALLINT tableNameLength) { - LOG_DEBUG("SQLPrimaryKeysW called with stmt: " - << stmt << ", catalogName: " << static_cast(catalogName) - << ", catalogNameLength: " << catalogNameLength - << ", schemaName: " << static_cast(schemaName) - << ", schemaNameLength: " << schemaNameLength - << ", tableName: " << static_cast(tableName) - << ", tableNameLength: " << tableNameLength); + ARROW_LOG(DEBUG) << "SQLPrimaryKeysW called with stmt: " << stmt + << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength; return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { throw driver::odbcabstraction::DriverException("SQLPrimaryKeysW is not implemented", "IM001"); diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc index 56a968e1a09..c7d32c91adc 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_driver.cc @@ -19,9 +19,9 @@ #include "arrow/compute/api.h" #include "arrow/flight/sql/odbc/flight_sql/flight_sql_connection.h" #include "arrow/flight/sql/odbc/flight_sql/utils.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/platform.h" #include "arrow/util/io_util.h" +#include "arrow/util/logging.h" #define ODBC_LOG_LEVEL "ARROW_ODBC_LOG_LEVEL" diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc index 2017936dd90..d213975cf13 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/win_system_dsn.cc @@ -32,7 +32,7 @@ #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/ui/window.h" #include "arrow/flight/sql/odbc/flight_sql/system_dsn.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/exceptions.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" +#include "arrow/util/logging.h" #include #include @@ -87,7 +87,7 @@ bool DisplayConnectionWindow(void* windowParent, Configuration& config, properties = config.GetProperties(); return true; } else { - LOG_INFO("Dialog is cancelled by user"); + ARROW_LOG(INFO) << "Dialog is cancelled by user"; return false; } } diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc index 2c9af34a75d..7dc5fdb0f41 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbc_api.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbc_api.cc @@ -21,7 +21,6 @@ #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/config/configuration.h" #include "arrow/flight/sql/odbc/flight_sql/include/flight_sql/flight_sql_driver.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/diagnostics.h" -#include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/attribute_utils.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/encoding_utils.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_connection.h" @@ -29,6 +28,7 @@ #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_environment.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/odbc_impl/odbc_statement.h" #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/spi/connection.h" +#include "arrow/util/logging.h" #if defined _WIN32 || defined _WIN64 // For displaying DSN Window @@ -41,9 +41,9 @@ namespace arrow { SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) { - LOG_DEBUG("SQLAllocHandle called with type: " << type << ", parent: " << parent - << ", result: " - << static_cast(result)); + ARROW_LOG(DEBUG) << "SQLAllocHandle called with type: " << type + << ", parent: " << parent + << ", result: " << static_cast(result); *result = nullptr; @@ -137,7 +137,8 @@ SQLRETURN SQLAllocHandle(SQLSMALLINT type, SQLHANDLE parent, SQLHANDLE* result) } SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) { - LOG_DEBUG("SQLFreeHandle called with type: " << type << ", handle: " << handle); + ARROW_LOG(DEBUG) << "SQLFreeHandle called with type: " << type + << ", handle: " << handle; switch (type) { case SQL_HANDLE_ENV: { @@ -204,7 +205,8 @@ SQLRETURN SQLFreeHandle(SQLSMALLINT type, SQLHANDLE handle) { } SQLRETURN SQLFreeStmt(SQLHSTMT handle, SQLUSMALLINT option) { - LOG_DEBUG("SQLAllocHandle called with handle: " << handle << ", option: " << option); + ARROW_LOG(DEBUG) << "SQLAllocHandle called with handle: " << handle + << ", option: " << option; switch (option) { case SQL_CLOSE: { @@ -264,11 +266,12 @@ SQLRETURN SQLGetDiagField(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT SQLSMALLINT bufferLength, SQLSMALLINT* stringLengthPtr) { // TODO: Implement additional fields types // https://github.com/apache/arrow/issues/46573 - LOG_DEBUG("SQLGetDiagFieldW called with handleType: " - << handleType << ", handle: " << handle << ", recNumber: " << recNumber - << ", diagIdentifier: " << diagIdentifier << ", diagInfoPtr: " << diagInfoPtr - << ", bufferLength: " << bufferLength - << ", stringLengthPtr: " << static_cast(stringLengthPtr)); + ARROW_LOG(DEBUG) << "SQLGetDiagFieldW called with handleType: " << handleType + << ", handle: " << handle << ", recNumber: " << recNumber + << ", diagIdentifier: " << diagIdentifier + << ", diagInfoPtr: " << diagInfoPtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr); using driver::odbcabstraction::Diagnostics; using ODBC::GetStringAttribute; @@ -523,13 +526,13 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT re SQLWCHAR* sqlState, SQLINTEGER* nativeErrorPtr, SQLWCHAR* messageText, SQLSMALLINT bufferLength, SQLSMALLINT* textLengthPtr) { - LOG_DEBUG("SQLGetDiagRecW called with handleType: " - << handleType << ", handle: " << handle << ", recNumber: " << recNumber - << ", sqlState: " << static_cast(sqlState) - << ", nativeErrorPtr: " << static_cast(nativeErrorPtr) - << ", messageText: " << static_cast(messageText) - << ", bufferLength: " << bufferLength - << ", textLengthPtr: " << static_cast(textLengthPtr)); + ARROW_LOG(DEBUG) << "SQLGetDiagRecW called with handleType: " << handleType + << ", handle: " << handle << ", recNumber: " << recNumber + << ", sqlState: " << static_cast(sqlState) + << ", nativeErrorPtr: " << static_cast(nativeErrorPtr) + << ", messageText: " << static_cast(messageText) + << ", bufferLength: " << bufferLength + << ", textLengthPtr: " << static_cast(textLengthPtr); using driver::odbcabstraction::Diagnostics; using ODBC::GetStringAttribute; @@ -612,10 +615,9 @@ SQLRETURN SQLGetDiagRec(SQLSMALLINT handleType, SQLHANDLE handle, SQLSMALLINT re SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* strLenPtr) { - LOG_DEBUG("SQLGetEnvAttr called with env: " - << env << ", attr: " << attr << ", valuePtr: " << valuePtr - << ", bufferLength: " << bufferLength - << ", strLenPtr: " << static_cast(strLenPtr)); + ARROW_LOG(DEBUG) << "SQLGetEnvAttr called with env: " << env << ", attr: " << attr + << ", valuePtr: " << valuePtr << ", bufferLength: " << bufferLength + << ", strLenPtr: " << static_cast(strLenPtr); using driver::odbcabstraction::DriverException; using ODBC::ODBCEnvironment; @@ -672,9 +674,8 @@ SQLRETURN SQLGetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER strLen) { - LOG_DEBUG("SQLSetEnvAttr called with env: " << env << ", attr: " << attr - << ", valuePtr: " << valuePtr - << ", strLen: " << strLen); + ARROW_LOG(DEBUG) << "SQLSetEnvAttr called with env: " << env << ", attr: " << attr + << ", valuePtr: " << valuePtr << ", strLen: " << strLen; using driver::odbcabstraction::DriverException; using ODBC::ODBCEnvironment; @@ -722,10 +723,10 @@ SQLRETURN SQLSetEnvAttr(SQLHENV env, SQLINTEGER attr, SQLPOINTER valuePtr, SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* stringLengthPtr) { - LOG_DEBUG("SQLGetConnectAttrW called with conn: " - << conn << ", attribute: " << attribute << ", valuePtr: " << valuePtr - << ", bufferLength: " << bufferLength - << ", stringLengthPtr: " << static_cast(stringLengthPtr)); + ARROW_LOG(DEBUG) << "SQLGetConnectAttrW called with conn: " << conn + << ", attribute: " << attribute << ", valuePtr: " << valuePtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr); using driver::odbcabstraction::Connection; using ODBC::ODBCConnection; @@ -740,9 +741,9 @@ SQLRETURN SQLGetConnectAttr(SQLHDBC conn, SQLINTEGER attribute, SQLPOINTER value SQLRETURN SQLSetConnectAttr(SQLHDBC conn, SQLINTEGER attr, SQLPOINTER valuePtr, SQLINTEGER valueLen) { - LOG_DEBUG("SQLSetConnectAttrW called with conn: " << conn << ", attr: " << attr - << ", valuePtr: " << valuePtr - << ", valueLen: " << valueLen); + ARROW_LOG(DEBUG) << "SQLSetConnectAttrW called with conn: " << conn + << ", attr: " << attr << ", valuePtr: " << valuePtr + << ", valueLen: " << valueLen; using driver::odbcabstraction::Connection; using ODBC::ODBCConnection; @@ -762,15 +763,17 @@ SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLSMALLINT outConnectionStringBufferLen, SQLSMALLINT* outConnectionStringLen, SQLUSMALLINT driverCompletion) { - LOG_DEBUG("SQLDriverConnectW called with conn: " - << conn << ", windowHandle: " << static_cast(windowHandle) - << ", inConnectionString: " << static_cast(inConnectionString) - << ", inConnectionStringLen: " << inConnectionStringLen - << ", outConnectionString: " << static_cast(outConnectionString) - << ", outConnectionStringBufferLen: " << outConnectionStringBufferLen - << ", outConnectionStringLen: " - << static_cast(outConnectionStringLen) - << ", driverCompletion: " << driverCompletion); + ARROW_LOG(DEBUG) << "SQLDriverConnectW called with conn: " << conn + << ", windowHandle: " << static_cast(windowHandle) + << ", inConnectionString: " + << static_cast(inConnectionString) + << ", inConnectionStringLen: " << inConnectionStringLen + << ", outConnectionString: " + << static_cast(outConnectionString) + << ", outConnectionStringBufferLen: " << outConnectionStringBufferLen + << ", outConnectionStringLen: " + << static_cast(outConnectionStringLen) + << ", driverCompletion: " << driverCompletion; // TODO: Implement FILEDSN and SAVEFILE keywords according to the spec // https://github.com/apache/arrow/issues/46449 @@ -840,12 +843,13 @@ SQLRETURN SQLDriverConnect(SQLHDBC conn, SQLHWND windowHandle, SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, SQLWCHAR* userName, SQLSMALLINT userNameLen, SQLWCHAR* password, SQLSMALLINT passwordLen) { - LOG_DEBUG("SQLConnectW called with conn: " - << conn << ", dsnName: " << static_cast(dsnName) - << ", dsnNameLen: " << dsnNameLen << ", userName: " - << static_cast(userName) << ", userNameLen: " << userNameLen - << ", password: " << static_cast(password) - << ", passwordLen: " << passwordLen); + ARROW_LOG(DEBUG) << "SQLConnectW called with conn: " << conn + << ", dsnName: " << static_cast(dsnName) + << ", dsnNameLen: " << dsnNameLen + << ", userName: " << static_cast(userName) + << ", userNameLen: " << userNameLen + << ", password: " << static_cast(password) + << ", passwordLen: " << passwordLen; using driver::flight_sql::FlightSqlConnection; using driver::flight_sql::config::Configuration; @@ -879,7 +883,7 @@ SQLRETURN SQLConnect(SQLHDBC conn, SQLWCHAR* dsnName, SQLSMALLINT dsnNameLen, } SQLRETURN SQLDisconnect(SQLHDBC conn) { - LOG_DEBUG("SQLDisconnect called with conn: " << conn); + ARROW_LOG(DEBUG) << "SQLDisconnect called with conn: " << conn; using ODBC::ODBCConnection; @@ -894,10 +898,10 @@ SQLRETURN SQLDisconnect(SQLHDBC conn) { SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePtr, SQLSMALLINT bufLen, SQLSMALLINT* stringLengthPtr) { - LOG_DEBUG("SQLGetInfo called with conn: " - << conn << ", infoType: " << infoType << ", infoValuePtr: " << infoValuePtr - << ", bufLen: " << bufLen - << ", stringLengthPtr: " << static_cast(stringLengthPtr)); + ARROW_LOG(DEBUG) << "SQLGetInfo called with conn: " << conn + << ", infoType: " << infoType << ", infoValuePtr: " << infoValuePtr + << ", bufLen: " << bufLen + << ", stringLengthPtr: " << static_cast(stringLengthPtr); using ODBC::ODBCConnection; @@ -918,10 +922,10 @@ SQLRETURN SQLGetInfo(SQLHDBC conn, SQLUSMALLINT infoType, SQLPOINTER infoValuePt SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER bufferLength, SQLINTEGER* stringLengthPtr) { - LOG_DEBUG("SQLGetStmtAttrW called with stmt: " - << stmt << ", attribute: " << attribute << ", valuePtr: " << valuePtr - << ", bufferLength: " << bufferLength - << ", stringLengthPtr: " << static_cast(stringLengthPtr)); + ARROW_LOG(DEBUG) << "SQLGetStmtAttrW called with stmt: " << stmt + << ", attribute: " << attribute << ", valuePtr: " << valuePtr + << ", bufferLength: " << bufferLength + << ", stringLengthPtr: " << static_cast(stringLengthPtr); using ODBC::ODBCStatement; @@ -938,9 +942,9 @@ SQLRETURN SQLGetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePt SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePtr, SQLINTEGER stringLength) { - LOG_DEBUG("SQLSetStmtAttrW called with stmt: " << stmt << ", attribute: " << attribute - << ", valuePtr: " << valuePtr - << ", stringLength: " << stringLength); + ARROW_LOG(DEBUG) << "SQLSetStmtAttrW called with stmt: " << stmt + << ", attribute: " << attribute << ", valuePtr: " << valuePtr + << ", stringLength: " << stringLength; using ODBC::ODBCStatement; @@ -956,9 +960,9 @@ SQLRETURN SQLSetStmtAttr(SQLHSTMT stmt, SQLINTEGER attribute, SQLPOINTER valuePt } SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) { - LOG_DEBUG("SQLExecDirectW called with stmt: " << stmt << ", queryText: " - << static_cast(queryText) - << ", textLength: " << textLength); + ARROW_LOG(DEBUG) << "SQLExecDirectW called with stmt: " << stmt + << ", queryText: " << static_cast(queryText) + << ", textLength: " << textLength; using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. @@ -974,9 +978,9 @@ SQLRETURN SQLExecDirect(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLengt } SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) { - LOG_DEBUG("SQLPrepareW called with stmt: " << stmt << ", queryText: " - << static_cast(queryText) - << ", textLength: " << textLength); + ARROW_LOG(DEBUG) << "SQLPrepareW called with stmt: " << stmt + << ", queryText: " << static_cast(queryText) + << ", textLength: " << textLength; using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. @@ -991,7 +995,7 @@ SQLRETURN SQLPrepare(SQLHSTMT stmt, SQLWCHAR* queryText, SQLINTEGER textLength) } SQLRETURN SQLExecute(SQLHSTMT stmt) { - LOG_DEBUG("SQLExecute called with stmt: " << stmt); + ARROW_LOG(DEBUG) << "SQLExecute called with stmt: " << stmt; using ODBC::ODBCStatement; // The driver is built to handle SELECT statements only. @@ -1005,7 +1009,7 @@ SQLRETURN SQLExecute(SQLHSTMT stmt) { } SQLRETURN SQLFetch(SQLHSTMT stmt) { - LOG_DEBUG("SQLFetch called with stmt: " << stmt); + ARROW_LOG(DEBUG) << "SQLFetch called with stmt: " << stmt; using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1031,10 +1035,11 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, SQLUSMALLINT* rowStatusArray) { // GH-47110: SQLExtendedFetch should return SQL_SUCCESS_WITH_INFO for certain diag // states - LOG_DEBUG("SQLExtendedFetch called with stmt: " - << stmt << ", fetchOrientation: " << fetchOrientation << ", fetchOffset: " - << fetchOffset << ", rowCountPtr: " << static_cast(rowCountPtr) - << ", rowStatusArray: " << static_cast(rowStatusArray)); + ARROW_LOG(DEBUG) << "SQLExtendedFetch called with stmt: " << stmt + << ", fetchOrientation: " << fetchOrientation + << ", fetchOffset: " << fetchOffset + << ", rowCountPtr: " << static_cast(rowCountPtr) + << ", rowStatusArray: " << static_cast(rowStatusArray); using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1049,7 +1054,7 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, // The SQL_ROWSET_SIZE statement attribute specifies the number of rows in the // rowset. SQLULEN rowSetSize = statement->GetRowsetSize(); - LOG_DEBUG("SQL_ROWSET_SIZE value for SQLExtendedFetch: " << rowSetSize); + ARROW_LOG(DEBUG) << "SQL_ROWSET_SIZE value for SQLExtendedFetch: " << rowSetSize; if (statement->Fetch(static_cast(rowSetSize), rowCountPtr, rowStatusArray)) { return SQL_SUCCESS; @@ -1062,9 +1067,9 @@ SQLRETURN SQLExtendedFetch(SQLHSTMT stmt, SQLUSMALLINT fetchOrientation, SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT fetchOrientation, SQLLEN fetchOffset) { - LOG_DEBUG("SQLFetchScroll called with stmt: " << stmt << ", fetchOrientation: " - << fetchOrientation - << ", fetchOffset: " << fetchOffset); + ARROW_LOG(DEBUG) << "SQLFetchScroll called with stmt: " << stmt + << ", fetchOrientation: " << fetchOrientation + << ", fetchOffset: " << fetchOffset; using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1091,10 +1096,10 @@ SQLRETURN SQLFetchScroll(SQLHSTMT stmt, SQLSMALLINT fetchOrientation, SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType, SQLPOINTER dataPtr, SQLLEN bufferLength, SQLLEN* indicatorPtr) { - LOG_DEBUG("SQLBindCol called with stmt: " - << stmt << ", recordNumber: " << recordNumber << ", cType: " << cType - << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength - << ", strLen_or_IndPtr: " << static_cast(indicatorPtr)); + ARROW_LOG(DEBUG) << "SQLBindCol called with stmt: " << stmt + << ", recordNumber: " << recordNumber << ", cType: " << cType + << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength + << ", strLen_or_IndPtr: " << static_cast(indicatorPtr); using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1108,7 +1113,7 @@ SQLRETURN SQLBindCol(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType } SQLRETURN SQLCloseCursor(SQLHSTMT stmt) { - LOG_DEBUG("SQLCloseCursor called with stmt: " << stmt); + ARROW_LOG(DEBUG) << "SQLCloseCursor called with stmt: " << stmt; using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1126,10 +1131,10 @@ SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType // GH-46979: support SQL_C_GUID data type // GH-46980: support Interval data types // GH-46985: return warning message instead of error on float truncation case - LOG_DEBUG("SQLGetData called with stmt: " - << stmt << ", recordNumber: " << recordNumber << ", cType: " << cType - << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength - << ", indicatorPtr: " << static_cast(indicatorPtr)); + ARROW_LOG(DEBUG) << "SQLGetData called with stmt: " << stmt + << ", recordNumber: " << recordNumber << ", cType: " << cType + << ", dataPtr: " << dataPtr << ", bufferLength: " << bufferLength + << ", indicatorPtr: " << static_cast(indicatorPtr); using ODBC::ODBCStatement; @@ -1140,7 +1145,7 @@ SQLRETURN SQLGetData(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLSMALLINT cType } SQLRETURN SQLMoreResults(SQLHSTMT stmt) { - LOG_DEBUG("SQLMoreResults called with stmt: " << stmt); + ARROW_LOG(DEBUG) << "SQLMoreResults called with stmt: " << stmt; using ODBC::ODBCStatement; // Multiple result sets not supported. Return SQL_NO_DATA by default. @@ -1151,8 +1156,8 @@ SQLRETURN SQLMoreResults(SQLHSTMT stmt) { } SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) { - LOG_DEBUG("SQLNumResultCols called with stmt: " - << stmt << ", columnCountPtr: " << static_cast(columnCountPtr)); + ARROW_LOG(DEBUG) << "SQLNumResultCols called with stmt: " << stmt + << ", columnCountPtr: " << static_cast(columnCountPtr); using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1163,8 +1168,8 @@ SQLRETURN SQLNumResultCols(SQLHSTMT stmt, SQLSMALLINT* columnCountPtr) { } SQLRETURN SQLRowCount(SQLHSTMT stmt, SQLLEN* rowCountPtr) { - LOG_DEBUG("SQLRowCount called with stmt: " << stmt << ", columnCountPtr: " - << static_cast(rowCountPtr)); + ARROW_LOG(DEBUG) << "SQLRowCount called with stmt: " << stmt + << ", columnCountPtr: " << static_cast(rowCountPtr); using ODBC::ODBCStatement; return ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1178,15 +1183,15 @@ SQLRETURN SQLTables(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNam SQLWCHAR* schemaName, SQLSMALLINT schemaNameLength, SQLWCHAR* tableName, SQLSMALLINT tableNameLength, SQLWCHAR* tableType, SQLSMALLINT tableTypeLength) { - LOG_DEBUG("SQLTables called with stmt: " - << stmt << ", catalogName: " << static_cast(catalogName) - << ", catalogNameLength: " << catalogNameLength - << ", schemaName: " << static_cast(schemaName) - << ", schemaNameLength: " << schemaNameLength - << ", tableName: " << static_cast(tableName) - << ", tableNameLength: " << tableNameLength - << ", tableType: " << static_cast(tableType) - << ", tableTypeLength: " << tableTypeLength); + ARROW_LOG(DEBUG) << "SQLTables called with stmt: " << stmt + << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength + << ", tableType: " << static_cast(tableType) + << ", tableTypeLength: " << tableTypeLength; using ODBC::ODBCStatement; using ODBC::SqlWcharToString; @@ -1212,15 +1217,15 @@ SQLRETURN SQLColumns(SQLHSTMT stmt, SQLWCHAR* catalogName, SQLSMALLINT catalogNa SQLWCHAR* columnName, SQLSMALLINT columnNameLength) { // GH-47159: Return NUM_PREC_RADIX based on whether COLUMN_SIZE contains number of // digits or bits - LOG_DEBUG("SQLColumnsW called with stmt: " - << stmt << ", catalogName: " << static_cast(catalogName) - << ", catalogNameLength: " << catalogNameLength - << ", schemaName: " << static_cast(schemaName) - << ", schemaNameLength: " << schemaNameLength - << ", tableName: " << static_cast(tableName) - << ", tableNameLength: " << tableNameLength - << ", columnName: " << static_cast(columnName) - << ", columnNameLength: " << columnNameLength); + ARROW_LOG(DEBUG) << "SQLColumnsW called with stmt: " << stmt + << ", catalogName: " << static_cast(catalogName) + << ", catalogNameLength: " << catalogNameLength + << ", schemaName: " << static_cast(schemaName) + << ", schemaNameLength: " << schemaNameLength + << ", tableName: " << static_cast(tableName) + << ", tableNameLength: " << tableNameLength + << ", columnName: " << static_cast(columnName) + << ", columnNameLength: " << columnNameLength; using ODBC::ODBCStatement; using ODBC::SqlWcharToString; @@ -1245,12 +1250,14 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLUSMALLINT fieldIdentifier, SQLPOINTER characterAttributePtr, SQLSMALLINT bufferLength, SQLSMALLINT* outputLength, SQLLEN* numericAttributePtr) { - LOG_DEBUG("SQLColAttributeW called with stmt: " - << stmt << ", recordNumber: " << recordNumber << ", fieldIdentifier: " - << fieldIdentifier << ", characterAttributePtr: " << characterAttributePtr - << ", bufferLength: " << bufferLength << ", outputLength: " - << static_cast(outputLength) << ", numericAttributePtr: " - << static_cast(numericAttributePtr)); + ARROW_LOG(DEBUG) << "SQLColAttributeW called with stmt: " << stmt + << ", recordNumber: " << recordNumber + << ", fieldIdentifier: " << fieldIdentifier + << ", characterAttributePtr: " << characterAttributePtr + << ", bufferLength: " << bufferLength + << ", outputLength: " << static_cast(outputLength) + << ", numericAttributePtr: " + << static_cast(numericAttributePtr); using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; @@ -1340,7 +1347,8 @@ SQLRETURN SQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT recordNumber, SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT dataType) { // GH-47237 return SQL_PRED_CHAR and SQL_PRED_BASIC for // appropriate data types in `SEARCHABLE` field - LOG_DEBUG("SQLGetTypeInfoW called with stmt: " << stmt << " dataType: " << dataType); + ARROW_LOG(DEBUG) << "SQLGetTypeInfoW called with stmt: " << stmt + << " dataType: " << dataType; using ODBC::ODBCStatement; return ODBC::ODBCStatement::ExecuteWithDiagnostics(stmt, SQL_ERROR, [=]() { @@ -1400,13 +1408,12 @@ SQLRETURN SQLGetTypeInfo(SQLHSTMT stmt, SQLSMALLINT dataType) { SQLRETURN SQLNativeSql(SQLHDBC connectionHandle, SQLWCHAR* inStatementText, SQLINTEGER inStatementTextLength, SQLWCHAR* outStatementText, SQLINTEGER bufferLength, SQLINTEGER* outStatementTextLength) { - LOG_DEBUG("SQLNativeSqlW called with connectionHandle: " - << connectionHandle - << ", inStatementText: " << static_cast(inStatementText) - << ", inStatementTextLength: " << inStatementTextLength - << ", outStatementText: " << static_cast(outStatementText) - << ", bufferLength: " << bufferLength << ", outStatementTextLength: " - << static_cast(outStatementTextLength)); + ARROW_LOG(DEBUG) << "SQLNativeSqlW called with connectionHandle: " << connectionHandle + << ", inStatementText: " << static_cast(inStatementText) + << ", inStatementTextLength: " << inStatementTextLength + << ", outStatementText: " << static_cast(outStatementText) + << ", bufferLength: " << bufferLength << ", outStatementTextLength: " + << static_cast(outStatementTextLength); using driver::odbcabstraction::Diagnostics; using ODBC::GetAttributeSQLWCHAR; @@ -1430,14 +1437,15 @@ SQLRETURN SQLDescribeCol(SQLHSTMT stmt, SQLUSMALLINT columnNumber, SQLWCHAR* col SQLSMALLINT bufferLength, SQLSMALLINT* nameLengthPtr, SQLSMALLINT* dataTypePtr, SQLULEN* columnSizePtr, SQLSMALLINT* decimalDigitsPtr, SQLSMALLINT* nullablePtr) { - LOG_DEBUG("SQLDescribeColW called with stmt: " - << stmt << ", columnNumber: " << columnNumber << ", columnName: " - << static_cast(columnName) << ", bufferLength: " << bufferLength - << ", nameLengthPtr: " << static_cast(nameLengthPtr) - << ", dataTypePtr: " << static_cast(dataTypePtr) - << ", columnSizePtr: " << static_cast(columnSizePtr) - << ", decimalDigitsPtr: " << static_cast(decimalDigitsPtr) - << ", nullablePtr: " << static_cast(nullablePtr)); + ARROW_LOG(DEBUG) << "SQLDescribeColW called with stmt: " << stmt + << ", columnNumber: " << columnNumber + << ", columnName: " << static_cast(columnName) + << ", bufferLength: " << bufferLength + << ", nameLengthPtr: " << static_cast(nameLengthPtr) + << ", dataTypePtr: " << static_cast(dataTypePtr) + << ", columnSizePtr: " << static_cast(columnSizePtr) + << ", decimalDigitsPtr: " << static_cast(decimalDigitsPtr) + << ", nullablePtr: " << static_cast(nullablePtr); using ODBC::ODBCDescriptor; using ODBC::ODBCStatement; diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h deleted file mode 100644 index 22d7d7643b6..00000000000 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/logger.h +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#pragma once - -#include "arrow/util/logging.h" - -#define __LAZY_LOG(LEVEL, ...) ARROW_LOG(LEVEL) << __VA_ARGS__; -#define LOG_DEBUG(...) __LAZY_LOG(DEBUG, __VA_ARGS__) -#define LOG_INFO(...) __LAZY_LOG(INFO, __VA_ARGS__) -#define LOG_ERROR(...) __LAZY_LOG(ERROR, __VA_ARGS__) -#define LOG_TRACE(...) __LAZY_LOG(TRACE, __VA_ARGS__) -#define LOG_WARN(...) __LAZY_LOG(WARN, __VA_ARGS__) diff --git a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc index 5ba7a01638e..21d4ef4f8b5 100644 --- a/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc +++ b/cpp/src/arrow/flight/sql/odbc/tests/connection_test.cc @@ -836,9 +836,6 @@ TYPED_TEST(FlightSQLODBCTestBase, TestConnect) { // Verifies connect and disconnect works on its own this->connect(); this->disconnect(); - - this->connect(); - this->disconnect(); } TYPED_TEST(FlightSQLODBCTestBase, TestSQLAllocFreeStmt) { From 6f90723c9f6adfc09c8d088534fef674951d7552 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Tue, 23 Sep 2025 10:58:36 -0700 Subject: [PATCH 10/10] Put whereami back * `GetModulePath` can be used to fetch the co-located TLS file --- LICENSE.txt | 43 ++ .../odbc/flight_sql/flight_sql_connection.cc | 1 + .../sql/odbc/odbcabstraction/CMakeLists.txt | 1 + .../flight/sql/odbc/odbcabstraction/utils.cc | 19 + cpp/src/arrow/vendored/whereami/whereami.cc | 674 ++++++++++++++++++ cpp/src/arrow/vendored/whereami/whereami.h | 68 ++ 6 files changed, 806 insertions(+) create mode 100644 cpp/src/arrow/vendored/whereami/whereami.cc create mode 100644 cpp/src/arrow/vendored/whereami/whereami.h diff --git a/LICENSE.txt b/LICENSE.txt index 08d4f988ac1..2c90f0313d7 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2280,3 +2280,46 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------------- +The files cpp/src/arrow/vendored/whereami/whereami.h, +cpp/src/arrow/vendored/whereami/whereami.cc are adapted from +Grégory Pakosz's whereami library (https://github.com/gpakosz/whereami) +It is dual licensed under both the WTFPLv2 and MIT licenses. + +The WTFPLv2 License + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + 1. Bla bla bla + 2. Montesqieu et camembert, vive la France, zut alors! + +The MIT License (MIT) +Copyright Gregory Pakosz + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc index c87c394fc31..527e9520dd2 100644 --- a/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc +++ b/cpp/src/arrow/flight/sql/odbc/flight_sql/flight_sql_connection.cc @@ -151,6 +151,7 @@ std::shared_ptr LoadFlightSslConfigs( AsBool(connPropertyMap, FlightSqlConnection::USE_SYSTEM_TRUST_STORE) .value_or(SYSTEM_TRUST_STORE_DEFAULT); + // GH-47630: find co-located TLS certificate if `trusted certs` path is not specified auto trusted_certs_iterator = connPropertyMap.find(std::string(FlightSqlConnection::TRUSTED_CERTS)); auto trusted_certs = trusted_certs_iterator != connPropertyMap.end() diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt index e8b5c4a63dd..530388a877e 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/CMakeLists.txt @@ -43,6 +43,7 @@ add_library(odbcabstraction encoding.cc exceptions.cc utils.cc + ../../../../vendored/whereami/whereami.cc odbc_impl/odbc_connection.cc odbc_impl/odbc_descriptor.cc odbc_impl/odbc_environment.cc diff --git a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc index a63d0c02fe3..09b5980d345 100644 --- a/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc +++ b/cpp/src/arrow/flight/sql/odbc/odbcabstraction/utils.cc @@ -14,6 +14,9 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. + +#include "arrow/vendored/whereami/whereami.h" + #include "arrow/flight/sql/odbc/odbcabstraction/include/odbcabstraction/utils.h" #include @@ -56,5 +59,21 @@ boost::optional AsInt32(int32_t min_value, } return boost::none; } + +std::string GetModulePath() { + std::vector path; + int length, dirname_length; + length = wai_getModulePath(NULL, 0, &dirname_length); + + if (length != 0) { + path.resize(length); + wai_getModulePath(path.data(), length, &dirname_length); + } else { + throw DriverException("Could not find module path."); + } + + return std::string(path.begin(), path.begin() + dirname_length); +} + } // namespace odbcabstraction } // namespace driver diff --git a/cpp/src/arrow/vendored/whereami/whereami.cc b/cpp/src/arrow/vendored/whereami/whereami.cc new file mode 100644 index 00000000000..94437361ec0 --- /dev/null +++ b/cpp/src/arrow/vendored/whereami/whereami.cc @@ -0,0 +1,674 @@ +// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses +// without any warranty. +// by Gregory Pakosz (@gpakosz) +// https://github.com/gpakosz/whereami +// Copyright 2024 Gregory Pakosz + +// in case you want to #include "whereami.c" in a larger compilation unit +#if !defined(WHEREAMI_H) +# include "whereami.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__linux__) || defined(__CYGWIN__) +# undef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#elif defined(__APPLE__) +# undef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE +# define _DARWIN_BETTER_REALPATH +#endif + +#if !defined(WAI_MALLOC) || !defined(WAI_FREE) || !defined(WAI_REALLOC) +# include +#endif + +#if !defined(WAI_MALLOC) +# define WAI_MALLOC(size) malloc(size) +#endif + +#if !defined(WAI_FREE) +# define WAI_FREE(p) free(p) +#endif + +#if !defined(WAI_REALLOC) +# define WAI_REALLOC(p, size) realloc(p, size) +#endif + +#ifndef WAI_NOINLINE +# if defined(_MSC_VER) +# define WAI_NOINLINE __declspec(noinline) +# elif defined(__GNUC__) +# define WAI_NOINLINE __attribute__((noinline)) +# else +# error unsupported compiler +# endif +#endif + +#if defined(_MSC_VER) +# define WAI_RETURN_ADDRESS() _ReturnAddress() +#elif defined(__GNUC__) +# define WAI_RETURN_ADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) +#else +# error unsupported compiler +#endif + +#if defined(_WIN32) + +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# if defined(_MSC_VER) +# pragma warning(push, 3) +# endif +# include +# include +# if defined(_MSC_VER) +# pragma warning(pop) +# endif +# include + +static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, + int* dirname_length) { + wchar_t buffer1[MAX_PATH]; + wchar_t buffer2[MAX_PATH]; + wchar_t* path = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { + DWORD size; + int length_, length__; + + size = GetModuleFileNameW(module, buffer1, sizeof(buffer1) / sizeof(buffer1[0])); + + if (size == 0) { + break; + } else if (size == (DWORD)(sizeof(buffer1) / sizeof(buffer1[0]))) { + DWORD size_ = size; + do { + wchar_t* path_; + + path_ = (wchar_t*)WAI_REALLOC(path, sizeof(wchar_t) * size_ * 2); + if (!path_) break; + size_ *= 2; + path = path_; + size = GetModuleFileNameW(module, path, size_); + } while (size == size_); + + if (size == size_) break; + } else { + path = buffer1; + } + + if (!_wfullpath(buffer2, path, MAX_PATH)) break; + length_ = (int)wcslen(buffer2); + length__ = + WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, out, capacity, NULL, NULL); + + if (length__ == 0) + length__ = WideCharToMultiByte(CP_UTF8, 0, buffer2, length_, NULL, 0, NULL, NULL); + if (length__ == 0) break; + + if (length__ <= capacity && dirname_length) { + int i; + + for (i = length__ - 1; i >= 0; --i) { + if (out[i] == '\\') { + *dirname_length = i; + break; + } + } + } + + length = length__; + } + + if (path != buffer1) WAI_FREE(path); + + return ok ? length : -1; +} + +WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getExecutablePath)(char* out, int capacity, + int* dirname_length) { + return WAI_PREFIX(getModulePath_)(NULL, out, capacity, dirname_length); +} + +WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, + int* dirname_length) { + HMODULE module; + int length = -1; + +# if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4054) +# endif + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR)WAI_RETURN_ADDRESS(), &module)) +# if defined(_MSC_VER) +# pragma warning(pop) +# endif + { + length = WAI_PREFIX(getModulePath_)(module, out, capacity, dirname_length); + } + + return length; +} + +#elif defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__) || defined(__sun) || \ + defined(WAI_USE_PROC_SELF_EXE) + +# include +# include +# if defined(__linux__) +# include +# else +# include +# endif +# ifndef __STDC_FORMAT_MACROS +# define __STDC_FORMAT_MACROS +# endif +# include + +# if !defined(WAI_PROC_SELF_EXE) +# if defined(__sun) +# define WAI_PROC_SELF_EXE "/proc/self/path/a.out" +# else +# define WAI_PROC_SELF_EXE "/proc/self/exe" +# endif +# endif + +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { + char buffer[PATH_MAX]; + char* resolved = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { + resolved = realpath(WAI_PROC_SELF_EXE, buffer); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + return ok ? length : -1; +} + +# if !defined(WAI_PROC_SELF_MAPS_RETRY) +# define WAI_PROC_SELF_MAPS_RETRY 5 +# endif + +# if !defined(WAI_PROC_SELF_MAPS) +# if defined(__sun) +# define WAI_PROC_SELF_MAPS "/proc/self/map" +# else +# define WAI_PROC_SELF_MAPS "/proc/self/maps" +# endif +# endif + +# if defined(__ANDROID__) || defined(ANDROID) +# include +# include +# include +# endif + +WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, + int* dirname_length) { + int length = -1; + FILE* maps = NULL; + + for (int r = 0; r < WAI_PROC_SELF_MAPS_RETRY; ++r) { + maps = fopen(WAI_PROC_SELF_MAPS, "r"); + if (!maps) break; + + for (;;) { + char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX]; + uint64_t low, high; + char perms[5]; + uint64_t offset; + uint32_t major, minor; + char path[PATH_MAX]; + uint32_t inode; + + if (!fgets(buffer, sizeof(buffer), maps)) break; + + if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, + &high, perms, &offset, &major, &minor, &inode, path) == 8) { + uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS(); + if (low <= addr && addr <= high) { + char* resolved; + + resolved = realpath(path, buffer); + if (!resolved) break; + + length = (int)strlen(resolved); +# if defined(__ANDROID__) || defined(ANDROID) + if (length > 4 && buffer[length - 1] == 'k' && buffer[length - 2] == 'p' && + buffer[length - 3] == 'a' && buffer[length - 4] == '.') { + int fd = open(path, O_RDONLY); + if (fd == -1) { + length = -1; // retry + break; + } + + char* begin = (char*)mmap(0, offset, PROT_READ, MAP_SHARED, fd, 0); + if (begin == MAP_FAILED) { + close(fd); + length = -1; // retry + break; + } + + char* p = begin + offset - 30; // minimum size of local file header + while (p >= begin) { // scan backwards + if (*((uint32_t*)p) == 0x04034b50UL) { // local file header signature found + uint16_t length_ = *((uint16_t*)(p + 26)); + + if (length + 2 + length_ < (int)sizeof(buffer)) { + memcpy(&buffer[length], "!/", 2); + memcpy(&buffer[length + 2], p + 30, length_); + length += 2 + length_; + } + + break; + } + + --p; + } + + munmap(begin, offset); + close(fd); + } +# endif + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + + break; + } + } + } + + fclose(maps); + maps = NULL; + + if (length != -1) break; + } + + return length; +} + +#elif defined(__APPLE__) + +# include +# include + +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { + char buffer1[PATH_MAX]; + char buffer2[PATH_MAX]; + char* path = buffer1; + char* resolved = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { + uint32_t size = (uint32_t)sizeof(buffer1); + if (_NSGetExecutablePath(path, &size) == -1) { + path = (char*)WAI_MALLOC(size); + if (!_NSGetExecutablePath(path, &size)) break; + } + + resolved = realpath(path, buffer2); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + if (path != buffer1) WAI_FREE(path); + + return ok ? length : -1; +} + +WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, + int* dirname_length) { + char buffer[PATH_MAX]; + char* resolved = NULL; + int length = -1; + + for (;;) { + Dl_info info; + + if (dladdr(WAI_RETURN_ADDRESS(), &info)) { + resolved = realpath(info.dli_fname, buffer); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + break; + } + + return length; +} + +#elif defined(__QNXNTO__) + +# include + +# if !defined(WAI_PROC_SELF_EXE) +# define WAI_PROC_SELF_EXE "/proc/self/exefile" +# endif + +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { + char buffer1[PATH_MAX]; + char buffer2[PATH_MAX]; + char* resolved = NULL; + FILE* self_exe = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { + self_exe = fopen(WAI_PROC_SELF_EXE, "r"); + if (!self_exe) break; + + if (!fgets(buffer1, sizeof(buffer1), self_exe)) break; + + resolved = realpath(buffer1, buffer2); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + fclose(self_exe); + + return ok ? length : -1; +} + +WAI_FUNCSPEC +int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length) { + char buffer[PATH_MAX]; + char* resolved = NULL; + int length = -1; + + for (;;) { + Dl_info info; + + if (dladdr(WAI_RETURN_ADDRESS(), &info)) { + resolved = realpath(info.dli_fname, buffer); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + break; + } + + return length; +} + +#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || defined(__OpenBSD__) + +# include +# include + +# if defined(__OpenBSD__) + +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { + char buffer1[4096]; + char buffer2[PATH_MAX]; + char buffer3[PATH_MAX]; + char** argv = (char**)buffer1; + char* resolved = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { + int mib[4] = {CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV}; + size_t size; + + if (sysctl(mib, 4, NULL, &size, NULL, 0) != 0) break; + + if (size > sizeof(buffer1)) { + argv = (char**)WAI_MALLOC(size); + if (!argv) break; + } + + if (sysctl(mib, 4, argv, &size, NULL, 0) != 0) break; + + if (strchr(argv[0], '/')) { + resolved = realpath(argv[0], buffer2); + if (!resolved) break; + } else { + const char* PATH = getenv("PATH"); + if (!PATH) break; + + size_t argv0_length = strlen(argv[0]); + + const char* begin = PATH; + while (1) { + const char* separator = strchr(begin, ':'); + const char* end = separator ? separator : begin + strlen(begin); + + if (end - begin > 0) { + if (*(end - 1) == '/') --end; + + if (((end - begin) + 1 + argv0_length + 1) <= sizeof(buffer2)) { + memcpy(buffer2, begin, end - begin); + buffer2[end - begin] = '/'; + memcpy(buffer2 + (end - begin) + 1, argv[0], argv0_length + 1); + + resolved = realpath(buffer2, buffer3); + if (resolved) break; + } + } + + if (!separator) break; + + begin = ++separator; + } + + if (!resolved) break; + } + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + if (argv != (char**)buffer1) WAI_FREE(argv); + + return ok ? length : -1; +} + +# else + +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length) { + char buffer1[PATH_MAX]; + char buffer2[PATH_MAX]; + char* path = buffer1; + char* resolved = NULL; + int length = -1; + bool ok; + + for (ok = false; !ok; ok = true) { +# if defined(__NetBSD__) + int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; +# else + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; +# endif + size_t size = sizeof(buffer1); + + if (sysctl(mib, 4, path, &size, NULL, 0) != 0) break; + + resolved = realpath(path, buffer2); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + return ok ? length : -1; +} + +# endif + +WAI_NOINLINE WAI_FUNCSPEC int WAI_PREFIX(getModulePath)(char* out, int capacity, + int* dirname_length) { + char buffer[PATH_MAX]; + char* resolved = NULL; + int length = -1; + + for (;;) { + Dl_info info; + + if (dladdr(WAI_RETURN_ADDRESS(), &info)) { + resolved = realpath(info.dli_fname, buffer); + if (!resolved) break; + + length = (int)strlen(resolved); + if (length <= capacity) { + memcpy(out, resolved, length); + + if (dirname_length) { + int i; + + for (i = length - 1; i >= 0; --i) { + if (out[i] == '/') { + *dirname_length = i; + break; + } + } + } + } + } + + break; + } + + return length; +} + +#else + +# error unsupported platform + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/cpp/src/arrow/vendored/whereami/whereami.h b/cpp/src/arrow/vendored/whereami/whereami.h new file mode 100644 index 00000000000..abb137bbefa --- /dev/null +++ b/cpp/src/arrow/vendored/whereami/whereami.h @@ -0,0 +1,68 @@ +// (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses +// without any warranty. +// by Gregory Pakosz (@gpakosz) +// https://github.com/gpakosz/whereami +// Copyright 2024 Gregory Pakosz + +#ifndef WHEREAMI_H +#define WHEREAMI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WAI_FUNCSPEC +# define WAI_FUNCSPEC +#endif +#ifndef WAI_PREFIX +# define WAI_PREFIX(function) wai_##function +#endif + +/** + * Returns the path to the current executable. + * + * Usage: + * - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to + * retrieve the length of the path + * - allocate the destination buffer with `path = (char*)malloc(length + 1);` + * - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the + * path + * - add a terminal NUL character with `path[length] = '\0';` + * + * @param out destination buffer, optional + * @param capacity destination buffer capacity + * @param dirname_length optional recipient for the length of the dirname part + * of the path. + * + * @return the length of the executable path on success (without a terminal NUL + * character), otherwise `-1` + */ +WAI_FUNCSPEC +int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length); + +/** + * Returns the path to the current module + * + * Usage: + * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve + * the length of the path + * - allocate the destination buffer with `path = (char*)malloc(length + 1);` + * - call `wai_getModulePath(path, length, NULL)` again to retrieve the path + * - add a terminal NUL character with `path[length] = '\0';` + * + * @param out destination buffer, optional + * @param capacity destination buffer capacity + * @param dirname_length optional recipient for the length of the dirname part + * of the path. + * + * @return the length of the module path on success (without a terminal NUL + * character), otherwise `-1` + */ +WAI_FUNCSPEC +int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length); + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef WHEREAMI_H