process SQL input in the relpipe-in-sql mode v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 26 Oct 2019 17:45:37 +0200
branchv_0
changeset 15 0ecde5272f8e
parent 14 eacacf060755
child 16 3c51a2c32c86
process SQL input in the relpipe-in-sql mode
nbproject/configurations.xml
src/Configuration.h
src/SqlHandler.h
src/relpipe-tr-sql.cpp
--- a/nbproject/configurations.xml	Fri Oct 25 12:33:00 2019 +0200
+++ b/nbproject/configurations.xml	Sat Oct 26 17:45:37 2019 +0200
@@ -93,8 +93,6 @@
           <preBuildFirst>true</preBuildFirst>
         </preBuild>
       </makefileType>
-      <item path="src/SqlException.h" ex="false" tool="3" flavor2="0">
-      </item>
       <item path="src/relpipe-tr-sql.cpp" ex="false" tool="1" flavor2="0">
         <ccTool flags="0">
         </ccTool>
--- a/src/Configuration.h	Fri Oct 25 12:33:00 2019 +0200
+++ b/src/Configuration.h	Sat Oct 26 17:45:37 2019 +0200
@@ -75,7 +75,17 @@
 	KeepFile keepFile = KeepFile::Automatic;
 
 	std::vector<Statement> statements;
+
+	/**
+	 * SQL script to be executed before the relational input.
+	 */
+	std::wistream* sqlBeforeRelational = nullptr;
 	
+	/**
+	 * SQL script to be executed after the relational input.
+	 */
+	std::wistream* sqlAfterRelational = nullptr;
+
 	std::wstring dumpRelations;
 
 	virtual ~Configuration() {
--- a/src/SqlHandler.h	Fri Oct 25 12:33:00 2019 +0200
+++ b/src/SqlHandler.h	Sat Oct 26 17:45:37 2019 +0200
@@ -150,6 +150,30 @@
 	std::unique_ptr<Connection> connection;
 	std::unique_ptr<PreparedStatement> currentInsert;
 
+	bool readNextSqlStatement(std::wistream* input, std::wstringstream* sql) {
+		sql->str(L"");
+		sql->clear();
+
+		for (wchar_t ch; *input >> ch;) {
+			*sql << ch;
+			if (ch == L';' && sqlite3_complete(convertor.to_bytes(sql->str()).c_str())) return true;
+		}
+
+		string_t remainingSql = sql->str();
+		for (wchar_t ch : remainingSql) if (ch != L' ' && ch != L'\n' && ch != L'\r' && ch != L'\t') throw SqlException(L"Unexpected EOF, missing „;“ after: „" + remainingSql + L"“");
+
+		return false;
+	}
+
+	void processSqlInput(std::wistream* input) {
+		if (input == nullptr) return;
+		*input >> std::ws >> std::noskipws;
+		for (std::wstringstream sql; readNextSqlStatement(input, &sql);) {
+			std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(sql.str()).c_str()));
+			while (prepared->next());
+		}
+	}
+
 	void processStatement(const Statement& statement) {
 		std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
 		int columnCount = prepared->getColumnCount();
@@ -300,9 +324,15 @@
 	}
 
 	void endOfPipe() {
+		// process optional SQL input
+		processSqlInput(configuration.sqlBeforeRelational);
+
 		// run the transformation – process all statements:
 		for (const Statement& statement : configuration.statements) processStatement(statement);
 
+		// process optional SQL input
+		processSqlInput(configuration.sqlAfterRelational);
+
 		// pass-through some relations:
 		if (configuration.dumpRelations.size()) dumpRelations();
 
--- a/src/relpipe-tr-sql.cpp	Fri Oct 25 12:33:00 2019 +0200
+++ b/src/relpipe-tr-sql.cpp	Sat Oct 26 17:45:37 2019 +0200
@@ -55,6 +55,8 @@
 		if (std::regex_match(cli.programName(), std::wregex(L"^(.*/)?relpipe-in-sql$"))) {
 			// relpipe-in-sql:
 			std::shared_ptr<writer::RelationalWriter> writer(writer::Factory::create(std::cout));
+			configuration.sqlBeforeRelational = isatty(fileno(stdin)) ? nullptr : &std::wcin;
+			configuration.sqlAfterRelational = nullptr;
 			SqlHandler handler(writer.get(), configuration);
 			handler.endOfPipe();
 		} else {