src/Connection.cpp
branchv_0
changeset 36 91cb012d779a
parent 32 77180ee275df
child 37 3de41719d7eb
equal deleted inserted replaced
35:cd9db43db120 36:91cb012d779a
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    16  */
    16  */
    17 
    17 
    18 #include <sqlite3.h>
    18 #include <memory>
       
    19 #include <iostream>
       
    20 
       
    21 #include <sql.h>
       
    22 #include <sqlext.h>
    19 
    23 
    20 #include "Connection.h"
    24 #include "Connection.h"
       
    25 #include "OdbcCommon.h"
    21 
    26 
    22 namespace relpipe {
    27 namespace relpipe {
    23 namespace tr {
    28 namespace tr {
    24 namespace sql {
    29 namespace sql {
    25 
    30 
    26 void Connection::begin() {
    31 Connection::Connection(void* db) : connection(db) {
    27 	sqlite3_exec((sqlite3*) db, "BEGIN", nullptr, nullptr, nullptr);
    32 	// TODO: transaction control
    28 }
       
    29 
       
    30 Connection::Connection(const char* filename) {
       
    31 	int result = sqlite3_open(filename, (sqlite3**) & db);
       
    32 	if (result != SQLITE_OK) {
       
    33 		sqlite3_close((sqlite3*) db);
       
    34 		throw SqlException(L"Unable to open SQLite database.");
       
    35 	}
       
    36 	sqlite3_enable_load_extension((sqlite3*) db, true);
       
    37 	begin();
       
    38 }
    33 }
    39 
    34 
    40 Connection::~Connection() {
    35 Connection::~Connection() {
    41 	sqlite3_close((sqlite3*) db);
    36 	SQLRETURN result = SQLDisconnect(connection);
       
    37 	// FIXME: nevyhazovat výjimky z destruktorů
       
    38 	if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to disconnect: " + std::to_wstring(result));
       
    39 	OdbcCommon::freeHandle(SQL_HANDLE_DBC, connection);
    42 }
    40 }
    43 
    41 
    44 PreparedStatement* Connection::prepareStatement(const char* sql) {
    42 PreparedStatement* Connection::prepareStatement(relpipe::reader::string_t sql) {
    45 	const char* remaining;
    43 	SQLHSTMT statement = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
    46 	sqlite3_stmt *stmt;
    44 	SQLRETURN result = SQLPrepare(statement, (SQLCHAR*) convertor.to_bytes(sql).c_str(), SQL_NTS);
    47 	int result = sqlite3_prepare((sqlite3*) db, sql, -1, &stmt, &remaining);
    45 	if (OdbcCommon::isNotSuccessful(result)) {
    48 	if (result == SQLITE_OK) return new PreparedStatement(stmt);
    46 		OdbcCommon::freeHandle(SQL_HANDLE_STMT, statement);
    49 	else throw SqlException(L"Unable to prepare SQLite statement.");
    47 		throw SqlException(L"Unable to prepare statement", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
       
    48 	}
       
    49 	return new PreparedStatement(statement);
    50 }
    50 }
    51 
    51 
    52 bool Connection::getAutoCommit() {
    52 bool Connection::getAutoCommit() {
    53 	return sqlite3_get_autocommit((sqlite3*) db);
    53 	// TODO: transaction control
       
    54 	return false;
    54 }
    55 }
    55 
    56 
    56 void Connection::setAutoCommit(bool autoCommit) {
    57 void Connection::setAutoCommit(bool autoCommit) {
    57 	bool autoCommitOld = getAutoCommit();
    58 	// TODO: transaction control
    58 	if (autoCommit && !autoCommitOld) commit();
       
    59 	else if (!autoCommit && autoCommitOld) begin();
       
    60 }
    59 }
    61 
    60 
    62 void Connection::commit() {
    61 void Connection::commit() {
    63 	sqlite3_exec((sqlite3*) db, "COMMIT", nullptr, nullptr, nullptr);
    62 	SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_COMMIT);
       
    63 	if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to COMMIT: " + std::to_wstring(result));
    64 }
    64 }
    65 
    65 
    66 void Connection::rollback() {
    66 void Connection::rollback() {
    67 	sqlite3_exec((sqlite3*) db, "ROLLBACK", nullptr, nullptr, nullptr);
    67 	SQLRETURN result = SQLEndTran(SQL_HANDLE_DBC, connection, SQL_ROLLBACK);
       
    68 	if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to ROLLBACK: " + std::to_wstring(result));
    68 }
    69 }
       
    70 
       
    71 std::vector<Connection::TableMetaData> Connection::getTables() {
       
    72 	std::vector<TableMetaData> tables;
       
    73 	SQLHSTMT statementHandle = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
       
    74 	SQLRETURN result = SQLTables(statementHandle, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0);
       
    75 	if (OdbcCommon::isNotSuccessful(result)) {
       
    76 		OdbcCommon::freeHandle(SQL_HANDLE_STMT, statementHandle);
       
    77 		throw SqlException(L"Unable get tables (prepare)", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
       
    78 	}
       
    79 	ResultSet resultSet(statementHandle);
       
    80 	while (resultSet.next()) {
       
    81 		TableMetaData tm;
       
    82 		tm.catalog = resultSet.getString(1); // FIXME: column name: table_cat
       
    83 		tm.schema = resultSet.getString(2); // FIXME: column name: table_schem
       
    84 		tm.name = resultSet.getString(3); // FIXME: column name: table_name
       
    85 		tm.type = resultSet.getString(4); // FIXME: column name: table_type
       
    86 		tables.emplace_back(tm);
       
    87 	}
       
    88 
       
    89 	return tables;
       
    90 }
       
    91 
       
    92 std::vector<Connection::TablePrivilege> Connection::getTablePrivileges() {
       
    93 	std::vector<TablePrivilege> tables;
       
    94 	SQLHSTMT statementHandle = OdbcCommon::allocateHandle(SQL_HANDLE_STMT, connection);
       
    95 	SQLRETURN result = SQLTablePrivileges(statementHandle, nullptr, 0, nullptr, 0, nullptr, 0);
       
    96 	if (OdbcCommon::isNotSuccessful(result)) {
       
    97 		OdbcCommon::freeHandle(SQL_HANDLE_STMT, statementHandle);
       
    98 		throw SqlException(L"Unable get tables (prepare)", result, SQL_HANDLE_DBC, connection); // TODO: SQL_HANDLE_STMT?
       
    99 	}
       
   100 	ResultSet resultSet(statementHandle);
       
   101 	while (resultSet.next()) {
       
   102 		TablePrivilege tp;
       
   103 		tp.catalog = resultSet.getString(1); // FIXME: column name: table_cat
       
   104 		tp.schema = resultSet.getString(2); // FIXME: column name: table_schem
       
   105 		tp.name = resultSet.getString(3); // FIXME: column name: table_name
       
   106 		tp.grantor = resultSet.getString(4); // FIXME: column name: grantor
       
   107 		tp.grantee = resultSet.getString(5); // FIXME: column name: grantee
       
   108 		tp.privilege = resultSet.getString(6); // FIXME: column name: privilege
       
   109 		tp.isGrantable = resultSet.getString(7) == L"YES"; // FIXME: column name: is_grantable
       
   110 		tables.emplace_back(tp);
       
   111 	}
       
   112 
       
   113 	return tables;
       
   114 }
       
   115 
       
   116 relpipe::reader::string_t Connection::getUserName() {
       
   117 	std::vector<char> buffer(100);
       
   118 	SQLSMALLINT stringLength;
       
   119 	SQLRETURN result = SQLGetInfo(connection, SQL_USER_NAME, buffer.data(), buffer.size(), &stringLength);
       
   120 	if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to get user name: " + std::to_wstring(result));
       
   121 	if (stringLength >= buffer.size()) throw SqlException(L"Unable to get user name: too long" + std::to_wstring(stringLength));
       
   122 	return convertor.from_bytes(buffer.data(), buffer.data() + stringLength);
       
   123 }
       
   124 
    69 
   125 
    70 }
   126 }
    71 }
   127 }
    72 }
   128 }