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