--- a/bash-completion.sh Sat May 23 23:58:50 2020 +0200
+++ b/bash-completion.sh Mon May 25 19:36:06 2020 +0200
@@ -46,6 +46,7 @@
"--copy-renamed"
"--file"
"--file-keep"
+ "--list-data-sources"
)
COMPREPLY=($(compgen -W "${OPTIONS[*]}" -- "$w0"))
fi
--- a/nbproject/configurations.xml Sat May 23 23:58:50 2020 +0200
+++ b/nbproject/configurations.xml Mon May 25 19:36:06 2020 +0200
@@ -43,6 +43,9 @@
<df root="." name="0">
<df name="src">
<in>Connection.cpp</in>
+ <in>DriverManager.cpp</in>
+ <in>DriverManager.h</in>
+ <in>OdbcCommon.h</in>
<in>PreparedStatement.cpp</in>
<in>SqlException.h</in>
<in>relpipe-tr-sql.cpp</in>
@@ -99,6 +102,12 @@
<ccTool flags="0">
</ccTool>
</item>
+ <item path="src/DriverManager.cpp" ex="false" tool="1" flavor2="0">
+ <ccTool flags="0">
+ </ccTool>
+ </item>
+ <item path="src/OdbcCommon.h" ex="false" tool="3" flavor2="0">
+ </item>
<item path="src/PreparedStatement.cpp" ex="false" tool="1" flavor2="0">
<ccTool flags="0">
</ccTool>
@@ -143,6 +152,12 @@
<preBuildFirst>true</preBuildFirst>
</preBuild>
</makefileType>
+ <item path="src/DriverManager.cpp" ex="false" tool="1" flavor2="0">
+ </item>
+ <item path="src/DriverManager.h" ex="false" tool="3" flavor2="0">
+ </item>
+ <item path="src/OdbcCommon.h" ex="false" tool="3" flavor2="0">
+ </item>
<item path="src/SqlException.h" ex="false" tool="3" flavor2="0">
</item>
<item path="src/relpipe-tr-sql.cpp" ex="false" tool="1" flavor2="0">
--- a/src/CLIParser.h Sat May 23 23:58:50 2020 +0200
+++ b/src/CLIParser.h Mon May 25 19:36:06 2020 +0200
@@ -54,6 +54,7 @@
static const string_t OPTION_COPY_RENAMED;
static const string_t OPTION_FILE;
static const string_t OPTION_FILE_KEEP;
+ static const string_t OPTION_LIST_DATA_SOURCES;
Configuration parse(const std::vector<string_t>& arguments) {
Configuration c;
@@ -87,6 +88,8 @@
else if (value == L"true") c.keepFile = KeepFile::Always;
else if (value == L"false") c.keepFile = KeepFile::Never;
else throw relpipe::cli::RelpipeCLIException(L"Unsupported keep-file value: " + value + L" Expecting: true, false, auto", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
+ } else if (option == OPTION_LIST_DATA_SOURCES) {
+ c.listDataSources = true;
} else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
}
addQuery(c, currentQuery); // last relation
@@ -109,6 +112,7 @@
const string_t CLIParser::OPTION_COPY_RENAMED = L"--copy-renamed";
const string_t CLIParser::OPTION_FILE = L"--file";
const string_t CLIParser::OPTION_FILE_KEEP = L"--file-keep";
+const string_t CLIParser::OPTION_LIST_DATA_SOURCES = L"--list-data-sources";
}
}
--- a/src/CMakeLists.txt Sat May 23 23:58:50 2020 +0200
+++ b/src/CMakeLists.txt Mon May 25 19:36:06 2020 +0200
@@ -16,10 +16,13 @@
set(EXECUTABLE_FILE "relpipe-tr-sql")
set(EXECUTABLE_FILE_IN "relpipe-in-sql")
+# ODBC libraries:
+include("FindODBC.cmake")
+
# Relpipe libraries:
INCLUDE(FindPkgConfig)
pkg_check_modules (RELPIPE_LIBS relpipe-lib-reader.cpp relpipe-lib-writer.cpp relpipe-lib-cli.cpp sqlite3)
-include_directories(${RELPIPE_LIBS_INCLUDE_DIRS})
+include_directories(${RELPIPE_LIBS_INCLUDE_DIRS} ${ODBC_INCLUDE_DIRS})
link_directories(${RELPIPE_LIBS_LIBRARY_DIRS})
# Add ASan AddressSanitizer
@@ -32,13 +35,14 @@
${EXECUTABLE_FILE}
PreparedStatement.cpp
Connection.cpp
+ DriverManager.cpp
relpipe-tr-sql.cpp
)
ADD_CUSTOM_TARGET(in_mode_symlink ALL COMMAND ${CMAKE_COMMAND} -E create_symlink ${EXECUTABLE_FILE} ${EXECUTABLE_FILE_IN})
# Link libraries:
-target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES})
+target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES} ${ODBC_LIBRARIES})
set_property(TARGET ${EXECUTABLE_FILE} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE)
install(TARGETS ${EXECUTABLE_FILE} DESTINATION bin)
--- a/src/Configuration.h Sat May 23 23:58:50 2020 +0200
+++ b/src/Configuration.h Mon May 25 19:36:06 2020 +0200
@@ -121,6 +121,8 @@
std::wistream* sqlAfterRelational = nullptr;
std::vector<CopyRelations> copyRelations;
+
+ relpipe::writer::boolean_t listDataSources = false;
virtual ~Configuration() {
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DriverManager.cpp Mon May 25 19:36:06 2020 +0200
@@ -0,0 +1,62 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <cstring>
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include "SqlException.h"
+#include "DriverManager.h"
+#include "OdbcCommon.h"
+
+namespace relpipe {
+namespace tr {
+namespace sql {
+
+DriverManager::DriverManager() {
+ env = OdbcCommon::allocateHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE);
+ SQLRETURN result = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, 0);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to set ODBC version"); // TODO:, result, SQL_HANDLE_ENV, environment);
+}
+
+DriverManager::~DriverManager() {
+ OdbcCommon::freeHandle(SQL_HANDLE_ENV, env);
+}
+
+std::vector<DriverManager::DataSource> DriverManager::getDataSources() {
+ std::vector<DriverManager::DataSource> list;
+ SQLCHAR name[SQL_MAX_DSN_LENGTH + 1];
+ SQLCHAR description[255];
+ memset(name, 0, sizeof (name));
+ memset(description, 0, sizeof (description));
+ SQLSMALLINT nameLength;
+ SQLSMALLINT descriptionLength;
+ while (true) {
+ SQLRETURN result = SQLDataSources(env, SQL_FETCH_NEXT, name, sizeof (name), &nameLength, description, sizeof (description), &descriptionLength);
+ // TODO: check nameLength and descriptionLength whether values were truncated?
+ if (OdbcCommon::isSuccessful(result)) list.push_back({convertor.from_bytes((char*) name), convertor.from_bytes((char*) description)});
+ else if (result == SQL_NO_DATA_FOUND) break;
+ else throw SqlException(L"Unable to list data sources: " + std::to_wstring(result));
+ }
+ return list;
+}
+
+
+}
+}
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/DriverManager.h Mon May 25 19:36:06 2020 +0200
@@ -0,0 +1,51 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <vector>
+#include <codecvt>
+#include <locale>
+
+#include <relpipe/reader/typedefs.h>
+
+#include "SqlException.h"
+
+namespace relpipe {
+namespace tr {
+namespace sql {
+
+class DriverManager {
+private:
+ void* env;
+ std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
+
+public:
+
+ class DataSource {
+ public:
+ relpipe::reader::string_t name;
+ relpipe::reader::string_t description;
+ };
+
+ DriverManager();
+ virtual ~DriverManager();
+ std::vector<DataSource> getDataSources();
+};
+
+}
+}
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/FindODBC.cmake Mon May 25 19:36:06 2020 +0200
@@ -0,0 +1,231 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindODBC
+--------
+
+Find an Open Database Connectivity (ODBC) include directory and library.
+
+On Windows, when building with Visual Studio, this module assumes the ODBC
+library is provided by the available Windows SDK.
+
+On Unix, this module allows to search for ODBC library provided by
+unixODBC or iODBC implementations of ODBC API.
+This module reads hint about location of the config program:
+
+.. variable:: ODBC_CONFIG
+
+ Location of odbc_config or iodbc-config program
+
+Otherwise, this module tries to find the config program,
+first from unixODBC, then from iODBC.
+If no config program found, this module searches for ODBC header
+and library in list of known locations.
+
+Imported targets
+^^^^^^^^^^^^^^^^
+
+This module defines the following :prop_tgt:`IMPORTED` targets:
+
+.. variable:: ODBC::ODBC
+
+ Imported target for using the ODBC library, if found.
+
+Result variables
+^^^^^^^^^^^^^^^^
+
+.. variable:: ODBC_FOUND
+
+ Set to true if ODBC library found, otherwise false or undefined.
+
+.. variable:: ODBC_INCLUDE_DIRS
+
+ Paths to include directories listed in one variable for use by ODBC client.
+ May be empty on Windows, where the include directory corresponding to the
+ expected Windows SDK is already available in the compilation environment.
+
+.. variable:: ODBC_LIBRARIES
+
+ Paths to libraries to linked against to use ODBC.
+ May just a library name on Windows, where the library directory corresponding
+ to the expected Windows SDK is already available in the compilation environment.
+
+.. variable:: ODBC_CONFIG
+
+ Path to unixODBC or iODBC config program, if found or specified.
+
+Cache variables
+^^^^^^^^^^^^^^^
+
+For users who wish to edit and control the module behavior, this module
+reads hints about search locations from the following variables:
+
+.. variable:: ODBC_INCLUDE_DIR
+
+ Path to ODBC include directory with ``sql.h`` header.
+
+.. variable:: ODBC_LIBRARY
+
+ Path to ODBC library to be linked.
+
+These variables should not be used directly by project code.
+
+Limitations
+^^^^^^^^^^^
+
+On Windows, this module does not search for iODBC.
+On Unix, there is no way to prefer unixODBC over iODBC, or vice versa,
+other than providing the config program location using the ``ODBC_CONFIG``.
+This module does not allow to search for a specific ODBC driver.
+
+#]=======================================================================]
+
+# Define lists used internally
+set(_odbc_include_paths)
+set(_odbc_lib_paths)
+set(_odbc_lib_names)
+set(_odbc_required_libs_names)
+
+### Try Windows Kits ##########################################################
+if(WIN32)
+ # List names of ODBC libraries on Windows
+ if(NOT MINGW)
+ set(ODBC_LIBRARY odbc32.lib)
+ else()
+ set(ODBC_LIBRARY libodbc32.a)
+ endif()
+ set(_odbc_lib_names odbc32;)
+
+ # List additional libraries required to use ODBC library
+ if(MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "Intel")
+ set(_odbc_required_libs_names odbccp32;ws2_32)
+ elseif(MINGW)
+ set(_odbc_required_libs_names odbccp32)
+ endif()
+endif()
+
+### Try unixODBC or iODBC config program ######################################
+if (UNIX)
+ find_program(ODBC_CONFIG
+ NAMES odbc_config iodbc-config
+ DOC "Path to unixODBC or iODBC config program")
+ mark_as_advanced(ODBC_CONFIG)
+endif()
+
+if (UNIX AND ODBC_CONFIG)
+ # unixODBC and iODBC accept unified command line options
+ execute_process(COMMAND ${ODBC_CONFIG} --cflags
+ OUTPUT_VARIABLE _cflags OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${ODBC_CONFIG} --libs
+ OUTPUT_VARIABLE _libs OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ # Collect paths of include directories from CFLAGS
+ separate_arguments(_cflags NATIVE_COMMAND "${_cflags}")
+ foreach(arg IN LISTS _cflags)
+ if("${arg}" MATCHES "^-I(.*)$")
+ list(APPEND _odbc_include_paths "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ unset(_cflags)
+
+ # Collect paths of library names and directories from LIBS
+ separate_arguments(_libs NATIVE_COMMAND "${_libs}")
+ foreach(arg IN LISTS _libs)
+ if("${arg}" MATCHES "^-L(.*)$")
+ list(APPEND _odbc_lib_paths "${CMAKE_MATCH_1}")
+ elseif("${arg}" MATCHES "^-l(.*)$")
+ set(_lib_name ${CMAKE_MATCH_1})
+ string(REGEX MATCH "odbc" _is_odbc ${_lib_name})
+ if(_is_odbc)
+ list(APPEND _odbc_lib_names ${_lib_name})
+ else()
+ list(APPEND _odbc_required_libs_names ${_lib_name})
+ endif()
+ unset(_lib_name)
+ endif()
+ endforeach()
+ unset(_libs)
+endif()
+
+### Try unixODBC or iODBC in include/lib filesystems ##########################
+if (UNIX AND NOT ODBC_CONFIG)
+ # List names of both ODBC libraries, unixODBC and iODBC
+ set(_odbc_lib_names odbc;iodbc;unixodbc;)
+endif()
+
+### Find include directories ##################################################
+find_path(ODBC_INCLUDE_DIR
+ NAMES sql.h
+ PATHS ${_odbc_include_paths})
+
+if(NOT ODBC_INCLUDE_DIR AND WIN32)
+ set(ODBC_INCLUDE_DIR "")
+endif()
+
+### Find libraries ############################################################
+if(NOT ODBC_LIBRARY)
+ find_library(ODBC_LIBRARY
+ NAMES ${_odbc_lib_names}
+ PATHS ${_odbc_lib_paths}
+ PATH_SUFFIXES odbc)
+
+ foreach(_lib IN LISTS _odbc_required_libs_names)
+ find_library(_lib_path
+ NAMES ${_lib}
+ PATHS ${_odbc_lib_paths} # system parths or collected from ODBC_CONFIG
+ PATH_SUFFIXES odbc)
+ if(_lib_path)
+ list(APPEND _odbc_required_libs_paths ${_lib_path})
+ endif()
+ unset(_lib_path CACHE)
+ endforeach()
+endif()
+
+# Unset internal lists as no longer used
+unset(_odbc_include_paths)
+unset(_odbc_lib_paths)
+unset(_odbc_lib_names)
+unset(_odbc_required_libs_names)
+
+### Set result variables ######################################################
+set(_odbc_required_vars ODBC_LIBRARY)
+if(NOT WIN32)
+ list(APPEND _odbc_required_vars ODBC_INCLUDE_DIR)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(ODBC DEFAULT_MSG ${_odbc_required_vars})
+
+unset(_odbc_required_vars)
+
+mark_as_advanced(ODBC_LIBRARY ODBC_INCLUDE_DIR)
+
+set(ODBC_INCLUDE_DIRS ${ODBC_INCLUDE_DIR})
+list(APPEND ODBC_LIBRARIES ${ODBC_LIBRARY})
+list(APPEND ODBC_LIBRARIES ${_odbc_required_libs_paths})
+
+### Import targets ############################################################
+if(ODBC_FOUND)
+ if(NOT TARGET ODBC::ODBC)
+ if(IS_ABSOLUTE "${ODBC_LIBRARY}")
+ add_library(ODBC::ODBC UNKNOWN IMPORTED)
+ set_target_properties(ODBC::ODBC PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${ODBC_LIBRARY}")
+ else()
+ add_library(ODBC::ODBC INTERFACE IMPORTED)
+ set_target_properties(ODBC::ODBC PROPERTIES
+ IMPORTED_LIBNAME "${ODBC_LIBRARY}")
+ endif()
+ set_target_properties(ODBC::ODBC PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${ODBC_INCLUDE_DIR}")
+
+ if(_odbc_required_libs_paths)
+ set_property(TARGET ODBC::ODBC APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES "${_odbc_required_libs_paths}")
+ endif()
+ endif()
+endif()
+
+unset(_odbc_required_libs_paths)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/OdbcCommon.h Mon May 25 19:36:06 2020 +0200
@@ -0,0 +1,53 @@
+/**
+ * Relational pipes
+ * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <sql.h>
+
+#include "SqlException.h"
+
+namespace relpipe {
+namespace tr {
+namespace sql {
+
+class OdbcCommon {
+public:
+
+ static bool isSuccessful(SQLRETURN result) {
+ return result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO;
+ }
+
+ static bool isNotSuccessful(SQLRETURN result) {
+ return !isSuccessful(result);
+ }
+
+ static SQLHANDLE allocateHandle(SQLSMALLINT type, SQLHANDLE input) {
+ SQLHANDLE output;
+ SQLRETURN result = SQLAllocHandle(type, input, &output);
+ if (isNotSuccessful(result)) throw SqlException(L"Unable to allocate handle " + std::to_wstring(type));
+ return output;
+ }
+
+ static void freeHandle(SQLSMALLINT type, SQLHANDLE handle) {
+ SQLRETURN result = SQLFreeHandle(type, handle);
+ if (isNotSuccessful(result)) throw SqlException(L"Unable to free handle of type: " + std::to_wstring(type));
+ }
+};
+
+}
+}
+}
\ No newline at end of file
--- a/src/SqlHandler.h Sat May 23 23:58:50 2020 +0200
+++ b/src/SqlHandler.h Mon May 25 19:36:06 2020 +0200
@@ -39,6 +39,7 @@
#include "SqlInputScanner.h"
#include "PreparedStatement.h"
#include "Connection.h"
+#include "DriverManager.h"
namespace relpipe {
namespace tr {
@@ -54,6 +55,7 @@
Configuration configuration;
boolean_t fileAlreadyExisted = false;
writer::RelationalWriter* relationalWriter;
+ DriverManager* driverManager;
std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
vector<AttributeMetadata> currentReaderMetadata;
integer_t currentAttributeIndex = 0;
@@ -156,7 +158,7 @@
public:
- SqlHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration) : relationalWriter(relationalWriter), configuration(configuration) {
+ SqlHandler(writer::RelationalWriter* relationalWriter, DriverManager* driverManager, Configuration& configuration) : relationalWriter(relationalWriter), driverManager(driverManager), configuration(configuration) {
std::string file;
if (configuration.file.size()) {
file = convertor.to_bytes(configuration.file);
@@ -270,6 +272,18 @@
} // else: we had no file, everything was in memory
}
+ static void listDataSources(writer::RelationalWriter* relationalWriter, DriverManager* driverManager) {
+ relationalWriter->startRelation(L"data_source",{
+ {L"name", writer::TypeId::STRING},
+ {L"description", writer::TypeId::STRING}
+ }, true);
+
+ for (DriverManager::DataSource ds : driverManager->getDataSources()) {
+ relationalWriter->writeAttribute(ds.name);
+ relationalWriter->writeAttribute(ds.description);
+ }
+ }
+
};
}
--- a/src/relpipe-tr-sql.cpp Sat May 23 23:58:50 2020 +0200
+++ b/src/relpipe-tr-sql.cpp Mon May 25 19:36:06 2020 +0200
@@ -36,6 +36,7 @@
#include "SqlHandler.h"
#include "CLIParser.h"
#include "Configuration.h"
+#include "DriverManager.h"
using namespace relpipe::cli;
using namespace relpipe::reader;
@@ -52,19 +53,23 @@
CLIParser cliParser;
Configuration configuration = cliParser.parse(cli.arguments());
- if (std::regex_match(cli.programName(), std::wregex(L"^(.*/)?relpipe-in-sql$"))) {
+ std::shared_ptr<DriverManager> driverManager = std::make_shared<DriverManager>();
+ std::shared_ptr<writer::RelationalWriter> writer(writer::Factory::create(std::cout));
+
+ if (configuration.listDataSources) {
+ // --list-data-sources:
+ SqlHandler::listDataSources(writer.get(), driverManager.get());
+ } else if (std::regex_match(cli.programName(), std::wregex(L"^(.*/)?relpipe-in-sql$"))) {
// relpipe-in-sql:
if (cli.arguments().size() == 0) configuration.copyRelations.push_back({L".*", L"", false});
- std::shared_ptr<writer::RelationalWriter> writer(writer::Factory::create(std::cout));
configuration.sqlBeforeRelational = isatty(fileno(stdin)) ? nullptr : &std::wcin;
configuration.sqlAfterRelational = nullptr;
- SqlHandler handler(writer.get(), configuration);
+ SqlHandler handler(writer.get(), driverManager.get(), configuration);
handler.endOfPipe();
} else {
// relpipe-tr-sql:
std::shared_ptr<reader::RelationalReader> reader(reader::Factory::create(std::cin));
- std::shared_ptr<writer::RelationalWriter> writer(writer::Factory::create(std::cout));
- SqlHandler handler(writer.get(), configuration);
+ SqlHandler handler(writer.get(), driverManager.get(), configuration);
reader->addHandler(&handler);
reader->process();
}