improve --keep-file option: default is auto = file will be kept, if it was present before the transformation v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Tue, 22 Oct 2019 16:04:56 +0200
branchv_0
changeset 12 0b38339b871b
parent 11 ccf19c7e7adf
child 13 19580b27ade2
improve --keep-file option: default is auto = file will be kept, if it was present before the transformation
src/CLIParser.h
src/Configuration.h
src/SqlHandler.h
--- a/src/CLIParser.h	Tue Oct 22 16:04:23 2019 +0200
+++ b/src/CLIParser.h	Tue Oct 22 16:04:56 2019 +0200
@@ -70,7 +70,11 @@
 			} else if (option == OPTION_FILE) {
 				c.file = readNext(arguments, i);
 			} else if (option == OPTION_KEEP_FILE) {
-				c.keepFile = true;
+				string_t value = readNext(arguments, i);
+				if (value == L"auto") c.keepFile = KeepFile::Automatic;
+				else if (value == L"true") c.keepFile = KeepFile::Always;
+				else if (value == L"false") c.keepFile = KeepFile::Never;
+				else throw relpipe::cli::RelpipeCLIException(L"Unsupported keep-file value: " + value + L" Expecting: true, false, auto", relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
 			} else throw relpipe::cli::RelpipeCLIException(L"Unsupported CLI option: " + option, relpipe::cli::CLI::EXIT_CODE_BAD_CLI_ARGUMENTS);
 		}
 		addQuery(c, currentQuery); // last relation
--- a/src/Configuration.h	Tue Oct 22 16:04:23 2019 +0200
+++ b/src/Configuration.h	Tue Oct 22 16:04:56 2019 +0200
@@ -49,6 +49,15 @@
 	std::vector<Parameter> parameters;
 };
 
+enum class KeepFile {
+	/** The file will be kept even if it was created during this transformation, so all the input data will stay on the disk. */
+	Always,
+	/** The file will be deleted at the end of this transformation – even if the file already existed. This is potentially dangerous, because we can unintentionally delete a database file. */
+	Never,
+	/** The file will be kept only if it was already present before the transformation. */
+	Automatic
+};
+
 class Configuration {
 public:
 
@@ -61,9 +70,9 @@
 	relpipe::writer::string_t file;
 
 	/**
-	 * If true, the file (if any was created) will not be deleted when this transformation finishes.
+	 * see KeepFile documentation
 	 */
-	relpipe::writer::boolean_t keepFile = false;
+	KeepFile keepFile = KeepFile::Automatic;
 
 	std::vector<Statement> statements;
 
--- a/src/SqlHandler.h	Tue Oct 22 16:04:23 2019 +0200
+++ b/src/SqlHandler.h	Tue Oct 22 16:04:56 2019 +0200
@@ -24,6 +24,7 @@
 #include <codecvt>
 #include <unistd.h>
 #include <cassert>
+#include <sys/stat.h>
 
 #include <sqlite3.h>
 
@@ -140,6 +141,7 @@
 class SqlHandler : public RelationalReaderValueHandler {
 private:
 	Configuration configuration;
+	boolean_t fileAlreadyExisted = false;
 	writer::RelationalWriter* relationalWriter;
 	std::wstring_convert<codecvt_utf8<wchar_t>> convertor; // TODO: support also other encodings
 	vector<AttributeMetadata> currentReaderMetadata;
@@ -186,7 +188,17 @@
 public:
 
 	SqlHandler(writer::RelationalWriter* relationalWriter, Configuration& configuration) : relationalWriter(relationalWriter), configuration(configuration) {
-		std::string file = configuration.file.size() ? convertor.to_bytes(configuration.file) : ":memory:";
+		std::string file;
+		if (configuration.file.size()) {
+			file = convertor.to_bytes(configuration.file);
+
+			// in C++17 we can use: std::filesystem::exists()
+			struct stat fileStat;
+			fileAlreadyExisted = (stat(file.c_str(), &fileStat) == 0);
+		} else {
+			file = ":memory:";
+		}
+
 		connection.reset(new Connection(file.c_str()));
 	}
 
@@ -255,7 +267,7 @@
 			default:
 				throw SqlException(L"Unsupported type in attribute()");
 		}
-		
+
 		if (currentAttributeIndex % currentReaderMetadata.size() == 0) {
 			currentInsert->next();
 			currentInsert->reset();
@@ -264,12 +276,17 @@
 	}
 
 	void endOfPipe() {
+		// run the transformation – process all statements:
 		for (const Statement& statement : configuration.statements) processStatement(statement);
 
-		if (configuration.file.size() && !configuration.keepFile) {
-			int result = unlink(convertor.to_bytes(configuration.file).c_str());
-			if (result) throw SqlException(L"Unable to delete SQLite file.");
-		}
+		// delete or keep the file:
+		if (configuration.file.size()) {
+			if (configuration.keepFile == KeepFile::Never || (configuration.keepFile == KeepFile::Automatic && !fileAlreadyExisted)) {
+				std::wcerr << L"will unlink file" << std::endl;
+				int result = unlink(convertor.to_bytes(configuration.file).c_str());
+				if (result) throw SqlException(L"Unable to delete SQLite file.");
+			}
+		} // else: we had no file, everything was in memory
 	}
 
 };