src/Connection.cpp
branchv_0
changeset 36 91cb012d779a
parent 32 77180ee275df
child 37 3de41719d7eb
--- 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);
+}
+
+
 }
 }
 }