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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,33 +65,43 @@ Status SqliteTablesWithSchemaBatchReader::ReadNext(std::shared_ptr<RecordBatch>*

auto* string_array = reinterpret_cast<StringArray*>(table_name_array.get());

std::vector<std::shared_ptr<Field>> column_fields;
std::map<std::string, std::vector<std::shared_ptr<Field>>> table_columns_map;
for (int i = 0; i < table_name_array->length(); i++) {
const std::string& table_name = string_array->GetString(i);
table_columns_map[table_name];
}

while (sqlite3_step(schema_statement->GetSqlite3Stmt()) == SQLITE_ROW) {
std::string sqlite_table_name = std::string(reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 0)));
if (sqlite_table_name == table_name) {
const char* column_name = reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 1));
const char* column_type = reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 2));
int nullable = sqlite3_column_int(schema_statement->GetSqlite3Stmt(), 3);

const ColumnMetadata& column_metadata = GetColumnMetadata(
GetSqlTypeFromTypeName(column_type), sqlite_table_name.c_str());
std::shared_ptr<DataType> arrow_type;
auto status = GetArrowType(column_type).Value(&arrow_type);
if (!status.ok()) {
return Status::NotImplemented("Unknown SQLite type '", column_type,
"' for column '", column_name, "' in table '",
table_name, "': ", status);
}
column_fields.push_back(arrow::field(column_name, arrow_type, nullable == 0,
column_metadata.metadata_map()));
while (sqlite3_step(schema_statement->GetSqlite3Stmt()) == SQLITE_ROW) {
std::string table_name = std::string(reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 0)));

if (table_columns_map.contains(table_name)) {
const char* column_name = reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 1));
const char* column_type = reinterpret_cast<const char*>(
sqlite3_column_text(schema_statement->GetSqlite3Stmt(), 2));
int nullable = sqlite3_column_int(schema_statement->GetSqlite3Stmt(), 3);

const ColumnMetadata& column_metadata =
GetColumnMetadata(GetSqlTypeFromTypeName(column_type), table_name.c_str());

std::shared_ptr<DataType> arrow_type;
auto status = GetArrowType(column_type).Value(&arrow_type);
if (!status.ok()) {
return Status::NotImplemented("Unknown SQLite type '", column_type,
"' for column '", column_name, "' in table '",
table_name, "': ", status);
}
table_columns_map[table_name].push_back(arrow::field(
column_name, arrow_type, nullable == 0, column_metadata.metadata_map()));
}
}

std::vector<std::shared_ptr<Field>> column_fields;
for (int i = 0; i < table_name_array->length(); i++) {
const std::string& table_name = string_array->GetString(i);
column_fields = table_columns_map[table_name];

ARROW_ASSIGN_OR_RAISE(std::shared_ptr<Buffer> schema_buffer,
ipc::SerializeSchema(*arrow::schema(column_fields)));

Expand Down
6 changes: 3 additions & 3 deletions cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ add_library(arrow_odbc_spi_impl
spi/result_set.h
spi/result_set_metadata.h
spi/statement.h
system_dsn.cc
system_dsn.h
system_trust_store.cc
system_trust_store.h
types.h
Expand All @@ -125,9 +127,7 @@ if(WIN32)
ui/dsn_configuration_window.h
ui/window.cc
ui/window.h
win_system_dsn.cc
system_dsn.cc
system_dsn.h)
win_system_dsn.cc)
endif()

if(APPLE)
Expand Down
4 changes: 2 additions & 2 deletions cpp/src/arrow/flight/sql/odbc/odbc_impl/odbc_statement.cc
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ void ODBCStatement::SetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER value
switch (statement_attribute) {
case SQL_ATTR_APP_PARAM_DESC: {
ODBCDescriptor* desc = static_cast<ODBCDescriptor*>(value);
if (current_apd_ != desc) {
if (desc && current_apd_ != desc) {
if (current_apd_ != built_in_apd_.get()) {
current_apd_->DetachFromStatement(this, true);
}
Expand All @@ -567,7 +567,7 @@ void ODBCStatement::SetStmtAttr(SQLINTEGER statement_attribute, SQLPOINTER value
}
case SQL_ATTR_APP_ROW_DESC: {
ODBCDescriptor* desc = static_cast<ODBCDescriptor*>(value);
if (current_ard_ != desc) {
if (desc && current_ard_ != desc) {
if (current_ard_ != built_in_ard_.get()) {
current_ard_->DetachFromStatement(this, false);
}
Expand Down
14 changes: 5 additions & 9 deletions cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@

#include "arrow/flight/sql/odbc/odbc_impl/system_dsn.h"

#include "arrow/flight/sql/odbc/odbc_impl/config/configuration.h"
#include "arrow/flight/sql/odbc/odbc_impl/flight_sql_connection.h"
#include "arrow/flight/sql/odbc/odbc_impl/ui/dsn_configuration_window.h"
#include "arrow/flight/sql/odbc/odbc_impl/ui/window.h"
#include "arrow/flight/sql/odbc/odbc_impl/util.h"
#include "arrow/result.h"
#include "arrow/util/utf8.h"

#include <odbcinst.h>
#include <sstream>

namespace arrow::flight::sql::odbc {

using config::Configuration;

void PostError(DWORD error_code, LPCWSTR error_msg) {
void PostError(DWORD error_code, LPWSTR error_msg) {
#if defined _WIN32
MessageBox(NULL, error_msg, L"Error!", MB_ICONEXCLAMATION | MB_OK);
#endif // _WIN32
SQLPostInstallerError(error_code, error_msg);
}

Expand All @@ -42,7 +38,7 @@ void PostArrowUtilError(arrow::Status error_status) {
std::wstring werror_msg = arrow::util::UTF8ToWideString(error_msg).ValueOr(
L"Error during utf8 to wide string conversion");

PostError(ODBC_ERROR_GENERAL_ERR, werror_msg.c_str());
PostError(ODBC_ERROR_GENERAL_ERR, (LPWSTR)werror_msg.c_str());
}

void PostLastInstallerError() {
Expand All @@ -55,7 +51,7 @@ void PostLastInstallerError() {
buf << L"Message: \"" << msg << L"\", Code: " << code;
std::wstring error_msg = buf.str();

PostError(code, error_msg.c_str());
PostError(code, (LPWSTR)error_msg.c_str());
}

/**
Expand Down
5 changes: 4 additions & 1 deletion cpp/src/arrow/flight/sql/odbc/odbc_impl/system_dsn.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
#include "arrow/flight/sql/odbc/odbc_impl/platform.h"

#include "arrow/flight/sql/odbc/odbc_impl/config/configuration.h"
#include "arrow/flight/sql/odbc/odbc_impl/flight_sql_connection.h"
#include "arrow/status.h"

#include <odbcinst.h>

namespace arrow::flight::sql::odbc {

#if defined _WIN32
Expand Down Expand Up @@ -64,7 +67,7 @@ bool RegisterDsn(const config::Configuration& config, LPCWSTR driver);
*/
bool UnregisterDsn(const std::wstring& dsn);

void PostError(DWORD error_code, LPCWSTR error_msg);
void PostError(DWORD error_code, LPWSTR error_msg);

void PostArrowUtilError(arrow::Status error_status);
} // namespace arrow::flight::sql::odbc
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ BOOL INSTAPI ConfigDSNW(HWND hwnd_parent, WORD req, LPCWSTR wdriver,
std::wstring werror_msg =
arrow::util::UTF8ToWideString(error_msg).ValueOr(L"Error during DSN load");

PostError(err.GetNativeError(), werror_msg.c_str());
PostError(err.GetNativeError(), (LPWSTR)werror_msg.c_str());
return FALSE;
}

Expand Down
41 changes: 37 additions & 4 deletions cpp/src/arrow/flight/sql/odbc/tests/columns_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include <gtest/gtest.h>

// Many tests are disabled for MacOS due to iODBC limitations.

namespace arrow::flight::sql::odbc {

template <typename T>
Expand Down Expand Up @@ -237,6 +239,7 @@ void CheckSQLColAttribute(SQLHSTMT stmt, SQLUSMALLINT idx,
EXPECT_EQ(expected_unsigned_column, unsigned_col);
}

#ifndef __APPLE__
void CheckSQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT idx,
const std::wstring& expected_column_name,
SQLLEN expected_data_type, SQLLEN expected_display_size,
Expand Down Expand Up @@ -306,6 +309,7 @@ void CheckSQLColAttributes(SQLHSTMT stmt, SQLUSMALLINT idx,
EXPECT_EQ(expected_searchable, searchable);
EXPECT_EQ(expected_unsigned_column, unsigned_col);
}
#endif // __APPLE__

void GetSQLColAttributeString(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx,
SQLUSMALLINT field_identifier, std::wstring& value) {
Expand Down Expand Up @@ -364,6 +368,7 @@ void GetSQLColAttributeNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMAL
SQLColAttribute(stmt, idx, field_identifier, 0, 0, nullptr, value));
}

#ifndef __APPLE__
void GetSQLColAttributesNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMALLINT idx,
SQLUSMALLINT field_identifier, SQLLEN* value) {
// Execute query and check SQLColAttribute numeric attribute
Expand All @@ -377,7 +382,7 @@ void GetSQLColAttributesNumeric(SQLHSTMT stmt, const std::wstring& wsql, SQLUSMA
ASSERT_EQ(SQL_SUCCESS,
SQLColAttributes(stmt, idx, field_identifier, 0, 0, nullptr, value));
}

#endif // __APPLE__
} // namespace

TYPED_TEST(ColumnsTest, SQLColumnsTestInputData) {
Expand Down Expand Up @@ -1387,7 +1392,9 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeAllTypes) {
SQL_FALSE); // expected_unsigned_column
}

TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypesODBCVer2) {
// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypes) {
// Tests ODBC 2.0 API SQLColAttributes
this->CreateTableAllDataType();

Expand Down Expand Up @@ -1446,6 +1453,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAllTypesODBCVer2) {
SQL_PRED_NONE, // expected_searchable
SQL_FALSE); // expected_unsigned_column
}
#endif // __APPLE__

TEST_F(ColumnsRemoteTest, TestSQLColAttributeAllTypes) {
// Test assumes there is a table $scratch.ODBCTest in remote server
Expand Down Expand Up @@ -1612,7 +1620,9 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeAllTypes) {
SQL_TRUE); // expected_unsigned_column
}

TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypesODBCVer2) {
// iODBC does not support SQLColAttribute in ODBC 2.0 mode.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypes) {
// Test assumes there is a table $scratch.ODBCTest in remote server
std::wstring wsql = L"SELECT * from $scratch.ODBCTest;";
std::vector<SQLWCHAR> sql0(wsql.begin(), wsql.end());
Expand Down Expand Up @@ -1776,7 +1786,8 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributeAllTypesODBCVer2) {
SQL_TRUE); // expected_unsigned_column
}

TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypesODBCVer2) {
// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypes) {
// Tests ODBC 2.0 API SQLColAttributes
// Test assumes there is a table $scratch.ODBCTest in remote server
std::wstring wsql = L"SELECT * from $scratch.ODBCTest;";
Expand Down Expand Up @@ -1895,6 +1906,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesAllTypesODBCVer2) {
SQL_SEARCHABLE, // expected_searchable
SQL_TRUE); // expected_unsigned_column
}
#endif // __APPLE__

TYPED_TEST(ColumnsTest, TestSQLColAttributeCaseSensitive) {
// Arrow limitation: returns SQL_FALSE for case sensitive column
Expand All @@ -1910,6 +1922,8 @@ TYPED_TEST(ColumnsTest, TestSQLColAttributeCaseSensitive) {
ASSERT_EQ(SQL_FALSE, value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesCaseSensitive) {
// Arrow limitation: returns SQL_FALSE for case sensitive column
// Tests ODBC 2.0 API SQLColAttributes
Expand All @@ -1924,6 +1938,7 @@ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesCaseSensitive) {
GetSQLColAttributesNumeric(this->stmt, wsql, 28, SQL_COLUMN_CASE_SENSITIVE, &value);
ASSERT_EQ(SQL_FALSE, value);
}
#endif // __APPLE__

TEST_F(ColumnsMockTest, TestSQLColAttributeUniqueValue) {
// Mock server limitation: returns false for auto-increment column
Expand All @@ -1935,6 +1950,8 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeUniqueValue) {
ASSERT_EQ(SQL_FALSE, value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAutoIncrement) {
// Tests ODBC 2.0 API SQLColAttributes
// Mock server limitation: returns false for auto-increment column
Expand All @@ -1945,6 +1962,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesAutoIncrement) {
GetSQLColAttributeNumeric(this->stmt, wsql, 1, SQL_COLUMN_AUTO_INCREMENT, &value);
ASSERT_EQ(SQL_FALSE, value);
}
#endif // __APPLE__

TEST_F(ColumnsMockTest, TestSQLColAttributeBaseTableName) {
this->CreateTableAllDataType();
Expand All @@ -1955,6 +1973,8 @@ TEST_F(ColumnsMockTest, TestSQLColAttributeBaseTableName) {
ASSERT_EQ(std::wstring(L"AllTypesTable"), value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTableName) {
// Tests ODBC 2.0 API SQLColAttributes
this->CreateTableAllDataType();
Expand All @@ -1964,6 +1984,7 @@ TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTableName) {
GetSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_TABLE_NAME, value);
ASSERT_EQ(std::wstring(L"AllTypesTable"), value);
}
#endif // __APPLE__

TEST_F(ColumnsMockTest, TestSQLColAttributeCatalogName) {
// Mock server limitattion: mock doesn't return catalog for result metadata,
Expand All @@ -1985,6 +2006,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeCatalogName) {
ASSERT_EQ(std::wstring(L""), value);
}

// iODBC does not support SQLColAttribute in ODBC 2.0 mode.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesQualifierName) {
// Mock server limitattion: mock doesn't return catalog for result metadata,
// and the defautl catalog should be 'main'
Expand All @@ -2005,6 +2028,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesQualifierName) {
GetSQLColAttributeString(this->stmt, wsql, 1, SQL_COLUMN_QUALIFIER_NAME, value);
ASSERT_EQ(std::wstring(L""), value);
}
#endif // __APPLE__

TYPED_TEST(ColumnsTest, TestSQLColAttributeCount) {
std::wstring wsql = this->GetQueryAllDataTypes();
Expand Down Expand Up @@ -2050,6 +2074,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeSchemaName) {
ASSERT_EQ(std::wstring(L""), value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesOwnerName) {
// Tests ODBC 2.0 API SQLColAttributes
this->CreateTableAllDataType();
Expand All @@ -2071,6 +2097,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesOwnerName) {
GetSQLColAttributesString(this->stmt, wsql, 1, SQL_COLUMN_OWNER_NAME, value);
ASSERT_EQ(std::wstring(L""), value);
}
#endif // __APPLE__

TEST_F(ColumnsMockTest, TestSQLColAttributeTableName) {
this->CreateTableAllDataType();
Expand Down Expand Up @@ -2119,6 +2146,8 @@ TEST_F(ColumnsRemoteTest, TestSQLColAttributeTypeName) {
ASSERT_EQ(std::wstring(L"TIMESTAMP"), value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TEST_F(ColumnsOdbcV2MockTest, TestSQLColAttributesTypeName) {
// Tests ODBC 2.0 API SQLColAttributes
this->CreateTableAllDataType();
Expand Down Expand Up @@ -2159,6 +2188,7 @@ TEST_F(ColumnsOdbcV2RemoteTest, TestSQLColAttributesTypeName) {
GetSQLColAttributesString(this->stmt, L"", 9, SQL_COLUMN_TYPE_NAME, value);
ASSERT_EQ(std::wstring(L"TIMESTAMP"), value);
}
#endif // __APPLE__

TYPED_TEST(ColumnsTest, TestSQLColAttributeUnnamed) {
std::wstring wsql = this->GetQueryAllDataTypes();
Expand All @@ -2175,6 +2205,8 @@ TYPED_TEST(ColumnsTest, TestSQLColAttributeUpdatable) {
ASSERT_EQ(SQL_ATTR_READWRITE_UNKNOWN, value);
}

// iODBC does not support SQLColAttributes for ODBC 3.0 attributes.
#ifndef __APPLE__
TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesUpdatable) {
// Tests ODBC 2.0 API SQLColAttributes
std::wstring wsql = this->GetQueryAllDataTypes();
Expand All @@ -2183,6 +2215,7 @@ TYPED_TEST(ColumnsOdbcV2Test, TestSQLColAttributesUpdatable) {
GetSQLColAttributesNumeric(this->stmt, wsql, 1, SQL_COLUMN_UPDATABLE, &value);
ASSERT_EQ(SQL_ATTR_READWRITE_UNKNOWN, value);
}
#endif // __APPLE__

TEST_F(ColumnsMockTest, SQLDescribeColValidateInput) {
this->CreateTestTables();
Expand Down
Loading
Loading