sqlite wrapper objects + execute query v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 30 Jul 2019 14:01:21 +0200
branchv_0
changeset 3 0b932e05aa9f
parent 2 362f2689cb87
child 4 925b15fb5c63
sqlite wrapper objects + execute query
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<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
-	sqlite3* db;
-	sqlite3_stmt* currentStatement;
+	std::unique_ptr<Connection> 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<AttributeMetadata> attributes) override {
@@ -75,7 +161,7 @@
 	}
 
 	void endOfPipe() {
-
+		for (const Statement& statement : configuration.statements) processStatement(statement);
 	}
 
 };