# HG changeset patch # User František Kučera # Date 1564488081 -7200 # Node ID 0b932e05aa9f5c35cf074e1329cb32dafb3f9003 # Parent 362f2689cb87708b7cce28aa333a0e07ecf4cce9 sqlite wrapper objects + execute query diff -r 362f2689cb87 -r 0b932e05aa9f src/SqlHandler.h --- a/src/SqlHandler.h Mon Jul 29 19:49:12 2019 +0200 +++ b/src/SqlHandler.h Tue Jul 30 14:01:21 2019 +0200 @@ -44,26 +44,112 @@ using namespace relpipe::reader; using namespace relpipe::reader::handlers; +class PreparedStatement { +private: + sqlite3_stmt* stmt; + +public: + + PreparedStatement(sqlite3_stmt* stmt) : stmt(stmt) { + } + + virtual ~PreparedStatement() { + sqlite3_finalize(stmt); + } + + void setString(int parameterIndex, std::string value) { + int result = sqlite3_bind_text(stmt, parameterIndex, value.c_str(), -1, SQLITE_TRANSIENT); + if (result != SQLITE_OK) throw SqlException(L"Unable to set SQLite parameter."); + } + + void setNull(int parameterIndex) { + int result = sqlite3_bind_null(stmt, parameterIndex); + if (result != SQLITE_OK) throw SqlException(L"Unable to set SQLite parameter."); + } + + bool next() { + int result = sqlite3_step(stmt); + if (result == SQLITE_ROW) return true; + else if (result == SQLITE_DONE) return false; + else throw SqlException(L"Error while iterating over SQLite result."); + } + + int getColumnCount() { + return sqlite3_column_count(stmt); + } + + std::string getColumName(int columnIndex) { + const char* name = sqlite3_column_name(stmt, columnIndex); + if (name) return name; + else throw SqlException(L"Unable to get SQLite column name."); + } + + // TODO: sqlite3_column_type + + std::string getString(int columnIndex) { + return (char *) sqlite3_column_text(stmt, columnIndex); + } + +}; + +class Connection { +private: + sqlite3* db; +public: + + Connection(const char* filename) { + int result = sqlite3_open(filename, &db); + if (result != SQLITE_OK) throw SqlException(L"Unable to open SQLite database."); + } + + virtual ~Connection() { + sqlite3_close(db); + } + + PreparedStatement prepareStatement(const char* sql) { + const char* remaining; + sqlite3_stmt *stmt; + int result = sqlite3_prepare(db, sql, -1, &stmt, &remaining); + if (result == SQLITE_OK) return PreparedStatement(stmt); + else throw SqlException(L"Unable to prepare SQLite statement."); + } + +}; + class SqlHandler : public RelationalReaderStringHandler { private: Configuration configuration; writer::RelationalWriter* relationalWriter; std::wstring_convert> convertor; // TODO: support also other encodings - sqlite3* db; - sqlite3_stmt* currentStatement; + std::unique_ptr connection; + + void processStatement(const Statement& statement) { + PreparedStatement prepared = connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()); + int columnCount = prepared.getColumnCount(); + int parameterCount = statement.parameters.size(); + + for (int i = 0; i < parameterCount; i++) { + prepared.setString(i + 1, convertor.to_bytes(statement.parameters[i].value)); + } + + for (int i = 0; i < columnCount; i++) { + printf("column %d ~ %s\n", i, prepared.getColumName(i).c_str()); + } + + while (prepared.next()) { + for (int i = 0; i < columnCount; i++) { + printf("column %d ~ %s = %s\n", i, prepared.getColumName(i).c_str(), prepared.getString(i).c_str()); + } + } + } public: SqlHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration) : relationalWriter(relationalWriter), configuration(configuration) { - int error = sqlite3_open(":memory:", &db); - if (error) { - sqlite3_close(db); - throw SqlException(L"Unable to open sqlite database."); - } + connection.reset(new Connection(":memory:")); } virtual ~SqlHandler() { - sqlite3_close(db); } void startRelation(string_t name, vector attributes) override { @@ -75,7 +161,7 @@ } void endOfPipe() { - + for (const Statement& statement : configuration.statements) processStatement(statement); } };