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 } |