Skip to content

Commit

Permalink
wip: extract exception function
Browse files Browse the repository at this point in the history
- [ ] use go style call and check error flow
- [ ] create template for SQL_OK
  • Loading branch information
rupurt committed Jul 19, 2023
1 parent d8fc506 commit 887ebfa
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 75 deletions.
64 changes: 64 additions & 0 deletions src/include/exception.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

#include "duckdb.hpp"
#include "duckdb/function/table_function.hpp"

#include "sql.h"
#include "sqlext.h"

namespace duckdb {
struct OdbcDiagnostics {
std::string msg;
std::string state;
SQLINTEGER native;
};

static unique_ptr<OdbcDiagnostics> ExtractDiagnostics(SQLSMALLINT handle_type, SQLHANDLE handle) {
SQLINTEGER i = 1;
SQLINTEGER native;
SQLCHAR state[7];
SQLCHAR text[256];
SQLSMALLINT len;
SQLRETURN return_code;
auto diagnostics = make_uniq<OdbcDiagnostics>();

while (SQL_SUCCEEDED(
SQLGetDiagRec(handle_type, handle, i, state, &native, text, sizeof(text), &len))) {
diagnostics->msg += string((char *)text);
diagnostics->state = string((char *)state);
diagnostics->native = native;
i++;
}

return std::move(diagnostics);
}

static std::string SqlReturnCodeToString(SQLRETURN return_code) {
switch (return_code) {
case SQL_SUCCESS:
return "SQL_SUCCESS";
case SQL_SUCCESS_WITH_INFO:
return "SQL_SUCCESS_WITH_INFO";
case SQL_NO_DATA:
return "SQL_NO_DATA";
case SQL_ERROR:
return "SQL_ERROR";
case SQL_INVALID_HANDLE:
return "SQL_INVALID_HANDLE";
case SQL_STILL_EXECUTING:
return "SQL_STILL_EXECUTING";
case SQL_NEED_DATA:
return "SQL_NEED_DATA";
default:
return "UNKNOWN";
}
}

static void ThrowExceptionWithDiagnostics(std::string msg_prefix, SQLHANDLE handle,
SQLRETURN return_code) {
auto diagnostics = ExtractDiagnostics(SQL_HANDLE_STMT, handle);
throw Exception(msg_prefix + " return_code=" + std::to_string(return_code) + ":" +
SqlReturnCodeToString(return_code) + " msg='" + diagnostics->msg + "' state=" +
diagnostics->state + " native=" + std::to_string(diagnostics->native));
}
} // namespace duckdb
103 changes: 28 additions & 75 deletions src/include/odbc.hpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#pragma once

#include "duckdb.hpp"
#include "exception.hpp"

#include "duckdb.hpp"
#include "duckdb/function/table_function.hpp"

#include "sql.h"
#include "sqlext.h"

#include <iostream>

namespace duckdb {
struct OdbcEnvironment {
OdbcEnvironment() { handle = SQL_NULL_HENV; }
Expand All @@ -18,100 +17,43 @@ struct OdbcEnvironment {

void FreeHandle() {
if (handle != SQL_NULL_HENV) {
auto sql_return = SQLFreeHandle(SQL_HANDLE_ENV, handle);
if (sql_return == SQL_SUCCESS) {
return;
} else if (sql_return == SQL_INVALID_HANDLE) {
throw Exception("OdbcEnvironment->Init() SQLFreeHandle SQL_RETURN=" +
std::to_string(sql_return) + " SQL_INVALID_HANDLE");
} else if (sql_return == SQL_ERROR) {
throw Exception("OdbcEnvironment->Init() SQLFreeHandle SQL_RETURN=" +
std::to_string(sql_return) + " SQL_ERROR");
} else {
throw Exception("OdbcEnvironment->Init() SQLFreeHandle SQL_RETURN=" +
std::to_string(sql_return) + " UNKNOWN_SQL_RETURN");
auto return_code = SQLFreeHandle(SQL_HANDLE_ENV, handle);
if (!SQL_SUCCEEDED(return_code)) {
ThrowExceptionWithDiagnostics("OdbcEnvironment->Init() SQLFreeHandle", handle, return_code);
}
}
}

public:
void Init() {
SQLRETURN return_code;

if (handle != SQL_NULL_HENV) {
throw Exception("OdbcEnvironment->Init() handle is not null");
}

auto alloc_sql_return = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &handle);
if (alloc_sql_return == SQL_SUCCESS || alloc_sql_return == SQL_SUCCESS_WITH_INFO) {
return_code = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &handle);
if (return_code == SQL_SUCCESS || return_code == SQL_SUCCESS_WITH_INFO) {
// ok
} else if (alloc_sql_return == SQL_INVALID_HANDLE) {
} else if (return_code == SQL_INVALID_HANDLE) {
throw Exception("OdbcEnvironment->Init() SQLAllocHandle SQL_RETURN=" +
std::to_string(alloc_sql_return) + " SQL_INVALID_HANDLE");
} else if (alloc_sql_return == SQL_ERROR) {
std::to_string(return_code) + " SQL_INVALID_HANDLE");
} else if (return_code == SQL_ERROR) {
throw Exception("OdbcEnvironment->Init() SQLAllocHandle SQL_RETURN=" +
std::to_string(alloc_sql_return) + " SQL_ERROR");
std::to_string(return_code) + " SQL_ERROR");
} else {
throw Exception("OdbcEnvironment->Init() SQLAllocHandle SQL_RETURN=" +
std::to_string(alloc_sql_return) + " UNKNOWN_SQL_RETURN");
std::to_string(return_code) + " UNKNOWN_SQL_RETURN");
}

auto set_env_sql_return =
SQLSetEnvAttr(handle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER *)SQL_OV_ODBC3, 0);
if (set_env_sql_return == SQL_SUCCESS) {
return;
} else if (set_env_sql_return == SQL_INVALID_HANDLE) {
throw Exception("OdbcEnvironment->Init() SQLSetEnvAttr SQL_RETURN=" +
std::to_string(set_env_sql_return) + " SQL_INVALID_HANDLE");
} else if (set_env_sql_return == SQL_ERROR) {
throw Exception("OdbcEnvironment->Init() SQLSetEnvAttr SQL_RETURN=" +
std::to_string(set_env_sql_return) + " SQL_ERROR");
} else {
throw Exception("OdbcEnvironment->Init() SQLSetEnvAttr SQL_RETURN=" +
std::to_string(set_env_sql_return) + " UNKNOWN_SQL_RETURN");
return_code = SQLSetEnvAttr(handle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER *)SQL_OV_ODBC3, 0);
if (!SQL_SUCCEEDED(return_code)) {
ThrowExceptionWithDiagnostics("OdbcEnvironment->Init() SQLSetEnvAttr", handle, return_code);
}
}
SQLHENV Handle() const { return handle; }
};

#define MAXCOLS 1024

struct OdbcColumnDescription {
SQLCHAR name[32];
SQLSMALLINT name_length;
SQLSMALLINT sql_data_type;
SQLSMALLINT c_data_type;
SQLULEN size;
SQLULEN length;
SQLSMALLINT decimal_digits;
SQLSMALLINT nullable;
};

struct OdbcDiagnostics {
string msg;
string state;
SQLINTEGER native;
};

static unique_ptr<OdbcDiagnostics> ExtractDiagnostics(SQLSMALLINT handle_type, SQLHANDLE handle) {
SQLINTEGER i = 0;
SQLINTEGER native;
SQLCHAR state[7];
SQLCHAR text[256];
SQLSMALLINT len;
SQLRETURN diag_return;
auto diagnostics = make_uniq<OdbcDiagnostics>();

do {
diag_return = SQLGetDiagRec(handle_type, handle, ++i, state, &native, text, sizeof(text), &len);
if (SQL_SUCCEEDED(diag_return)) {
diagnostics->msg += string((char *)text);
diagnostics->state = string((char *)state);
diagnostics->native = native;
}
} while (diag_return == SQL_SUCCESS);

return std::move(diagnostics);
}

#define MAX_CONN_STR_OUT 1024

struct OdbcConnection {
Expand Down Expand Up @@ -238,6 +180,17 @@ struct OdbcConnection {
SQLHSTMT HandleConn() { return handle_conn; }
};

struct OdbcColumnDescription {
SQLCHAR name[32];
SQLSMALLINT name_length;
SQLSMALLINT sql_data_type;
SQLSMALLINT c_data_type;
SQLULEN size;
SQLULEN length;
SQLSMALLINT decimal_digits;
SQLSMALLINT nullable;
};

struct OdbcStatementOptions {
OdbcStatementOptions(SQLULEN _row_array_size) : row_array_size(_row_array_size) {}

Expand Down

0 comments on commit 887ebfa

Please sign in to comment.