--- a/src/Connection.cpp Mon May 25 21:11:17 2020 +0200
+++ b/src/Connection.cpp Sun May 31 16:56:07 2020 +0200
@@ -15,58 +15,114 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sqlite3.h>
+#include <memory>
+#include <iostream>
+
+#include <sql.h>
+#include <sqlext.h>
#include "Connection.h"
+#include "OdbcCommon.h"
namespace relpipe {
namespace tr {
namespace sql {
-void Connection::begin() {
- sqlite3_exec((sqlite3*) db, "BEGIN", nullptr, nullptr, nullptr);
-}
-
-Connection::Connection(const char* filename) {
- int result = sqlite3_open(filename, (sqlite3**) & db);
- if (result != SQLITE_OK) {
- sqlite3_close((sqlite3*) db);
- throw SqlException(L"Unable to open SQLite database.");
- }
- sqlite3_enable_load_extension((sqlite3*) db, true);
- begin();
+Connection::Connection(void* db) : connection(db) {
+ // TODO: transaction control
}
Connection::~Connection() {
- sqlite3_close((sqlite3*) db);
+ SQLRETURN result = SQLDisconnect(connection);
+ // FIXME: nevyhazovat výjimky z destruktorů
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to disconnect: " + std::to_wstring(result));
+ OdbcCommon::freeHandle(SQL_HANDLE_DBC, connection);
}
-PreparedStatement* Connection::prepareStatement(const char* sql) {
- const char* remaining;
- sqlite3_stmt *stmt;
- int result = sqlite3_prepare((sqlite3*) db, sql, -1, &stmt, &remaining);
- if (result == SQLITE_OK) return new PreparedStatement(stmt);
- else throw SqlException(L"Unable to prepare SQLite statement.");
+PreparedStatement* Connection::prepareStatement(relpipe::reader::string_t sql) {
+ SQLHSTMT statement = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
+ SQLRETURN result = SQLPrepare(statement, (SQLCHAR*) convertor.to_bytes(sql).c_str(), SQL_NTS);
+ if (OdbcCommon::isNotSuccessful(result)) {
+ OdbcCommon::freeHandle(SQL_HANDLE_STMT, statement);
+ throw SqlException(L"Unable to prepare statement", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
+ }
+ return new PreparedStatement(statement);
}
bool Connection::getAutoCommit() {
- return sqlite3_get_autocommit((sqlite3*) db);
+ // TODO: transaction control
+ return false;
}
void Connection::setAutoCommit(bool autoCommit) {
- bool autoCommitOld = getAutoCommit();
- if (autoCommit && !autoCommitOld) commit();
- else if (!autoCommit && autoCommitOld) begin();
+ // TODO: transaction control
}
void Connection::commit() {
- sqlite3_exec((sqlite3*) db, "COMMIT", nullptr, nullptr, nullptr);
+ SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_COMMIT);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to COMMIT: " + std::to_wstring(result));
}
void Connection::rollback() {
- sqlite3_exec((sqlite3*) db, "ROLLBACK", nullptr, nullptr, nullptr);
+ SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_ROLLBACK);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to ROLLBACK: " + std::to_wstring(result));
+}
+
+std::vector<Connection::TableMetaData> Connection::getTables() {
+ std::vector<TableMetaData> tables;
+ SQLHSTMT statementHandle = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
+ SQLRETURN result = SQLTables(statementHandle, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0);
+ if (OdbcCommon::isNotSuccessful(result)) {
+ OdbcCommon::freeHandle(SQL_HANDLE_STMT, statementHandle);
+ throw SqlException(L"Unable get tables (prepare)", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
+ }
+ ResultSet resultSet(statementHandle);
+ while (resultSet.next()) {
+ TableMetaData tm;
+ tm.catalog = resultSet.getString(1); // FIXME: column name: table_cat
+ tm.schema = resultSet.getString(2); // FIXME: column name: table_schem
+ tm.name = resultSet.getString(3); // FIXME: column name: table_name
+ tm.type = resultSet.getString(4); // FIXME: column name: table_type
+ tables.emplace_back(tm);
+ }
+
+ return tables;
}
+std::vector<Connection::TablePrivilege> Connection::getTablePrivileges() {
+ std::vector<TablePrivilege> tables;
+ SQLHSTMT statementHandle = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
+ SQLRETURN result = SQLTablePrivileges(statementHandle, nullptr, 0, nullptr, 0, nullptr, 0);
+ if (OdbcCommon::isNotSuccessful(result)) {
+ OdbcCommon::freeHandle(SQL_HANDLE_STMT, statementHandle);
+ throw SqlException(L"Unable get tables (prepare)", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
+ }
+ ResultSet resultSet(statementHandle);
+ while (resultSet.next()) {
+ TablePrivilege tp;
+ tp.catalog = resultSet.getString(1); // FIXME: column name: table_cat
+ tp.schema = resultSet.getString(2); // FIXME: column name: table_schem
+ tp.name = resultSet.getString(3); // FIXME: column name: table_name
+ tp.grantor = resultSet.getString(4); // FIXME: column name: grantor
+ tp.grantee = resultSet.getString(5); // FIXME: column name: grantee
+ tp.privilege = resultSet.getString(6); // FIXME: column name: privilege
+ tp.isGrantable = resultSet.getString(7) == L"YES"; // FIXME: column name: is_grantable
+ tables.emplace_back(tp);
+ }
+
+ return tables;
+}
+
+relpipe::reader::string_t Connection::getUserName() {
+ std::vector<char> buffer(100);
+ SQLSMALLINT stringLength;
+ SQLRETURN result = SQLGetInfo(connection, SQL_USER_NAME, buffer.data(), buffer.size(), &stringLength);
+ if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to get user name: " + std::to_wstring(result));
+ if (stringLength >= buffer.size()) throw SqlException(L"Unable to get user name: too long" + std::to_wstring(stringLength));
+ return convertor.from_bytes(buffer.data(), buffer.data() + stringLength);
+}
+
+
}
}
}