src/SqlHandler.h
branchv_0
changeset 36 91cb012d779a
parent 34 24c05e69d68f
child 37 3de41719d7eb
--- a/src/SqlHandler.h	Mon May 25 21:11:17 2020 +0200
+++ b/src/SqlHandler.h	Sun May 31 16:56:07 2020 +0200
@@ -75,6 +75,7 @@
 			}
 		}
 
+		// TODO: support comments at the end of the script (after last ;)
 		string_t remainingSql = scanner.getAndReset();
 		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"“");
 
@@ -85,56 +86,59 @@
 		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());
+			std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(sql.str()));
+			prepared->executeUpdate();
 		}
 	}
 
-	relpipe::writer::TypeId findType(string_t columnName, int columnIndex, const Statement& statement, std::shared_ptr<PreparedStatement> preparedStatement) {
+	relpipe::writer::TypeId findType(string_t columnName, const Statement& statement, relpipe::writer::TypeId typeFromResultSet) {
 		for (TypeCast typeCast : statement.typeCasts) if (typeCast.name == columnName) return relationalWriter->toTypeId(typeCast.type);
-		return preparedStatement->getColumType(columnIndex);
+		return typeFromResultSet;
 	}
 
 	void processStatement(const Statement& statement) {
-		std::shared_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
-		int columnCount = prepared->getColumnCount();
+		std::shared_ptr<PreparedStatement> prepared(connection->prepareStatement(statement.sql));
 		int parameterCount = statement.parameters.size();
 
 		for (int i = 0; i < parameterCount; i++) {
-			prepared->setString(i + 1, convertor.to_bytes(statement.parameters[i].value));
+			prepared->setString(i + 1, statement.parameters[i].value);
 		}
 
+		std::shared_ptr<ResultSet> resultSet(prepared->executeQuery());
+		std::shared_ptr<ResultSet::MetaData> metaData(resultSet->getMetaData());
+
+		auto columnCount = metaData->getColumnCount();
 		std::vector<relpipe::writer::AttributeMetadata> metadata;
-		for (int i = 0; i < columnCount; i++) {
-			string_t columnName = convertor.from_bytes(prepared->getColumName(i).c_str());
-			metadata.push_back({columnName, findType(columnName, i, statement, prepared)});
+		for (int columnNumber = 1; columnNumber <= columnCount; columnNumber++) {
+			auto columnDescriptor = metaData->describeColumn(columnNumber);
+			metadata.push_back({columnDescriptor.name, findType(columnDescriptor.name, statement, columnDescriptor.type)});
 		}
 		relationalWriter->startRelation(statement.relation, metadata, true);
 
-		while (prepared->next()) {
-			for (int i = 0; i < columnCount; i++) {
-				relationalWriter->writeAttribute(convertor.from_bytes(prepared->getString(i)));
+		while (resultSet->next()) {
+			for (int columnNumber = 1; columnNumber <= columnCount; columnNumber++) {
+				relationalWriter->writeAttribute(resultSet->getString(columnNumber));
 			}
 		}
 	}
 
-	std::vector<string_t> getAllRelations() {
-		std::vector<string_t> relations;
-		std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement("SELECT name FROM sqlite_master WHERE type IN ('table', 'view')"));
-		while (prepared->next()) relations.push_back(convertor.from_bytes(prepared->getString(0)));
-		return relations;
-	}
-
 	void copyRelations(const CopyRelations& copy) {
 		std::wregex pattern(copy.pattern);
-		for (string_t relation : getAllRelations()) {
-			if (regex_match(relation, pattern)) {
+		relpipe::writer::string_t userName = connection->getUserName();
+		for (Connection::TablePrivilege tableMetaData : connection->getTablePrivileges()) {
+			if (regex_match(tableMetaData.name, pattern) && tableMetaData.privilege == L"SELECT" && tableMetaData.grantee == userName) {
+				// TODO: May we have multiple SELECT permissions for same table? Copy it only once.
 				std::wstringstream select;
 				select << L"SELECT * FROM ";
-				writeIdentifier(select, relation);
+				if (tableMetaData.schema.size()) {
+					// TODO: use qualified table name also for regex matching and for relation name
+					writeIdentifier(select, tableMetaData.schema);
+					select << L".";
+				}
+				writeIdentifier(select, tableMetaData.name);
 
 				Statement statement;
-				statement.relation = copy.replace ? regex_replace(relation, pattern, copy.replacement) : relation;
+				statement.relation = copy.replace ? regex_replace(tableMetaData.name, pattern, copy.replacement) : tableMetaData.name;
 				statement.sql = select.str();
 				processStatement(statement);
 			}
@@ -170,8 +174,9 @@
 			file = ":memory:";
 		}
 
-		connection.reset(new Connection(file.c_str()));
-		connection->setAutoCommit(false);
+		connection.reset(driverManager->getConnectionByDSN(L"sqlite-memory")); // FIXME: custom DSN and files
+		connection.reset(driverManager->getConnectionByDSN(L"relpipe")); // FIXME: custom DSN and files
+		//connection->setAutoCommit(false);
 	}
 
 	virtual ~SqlHandler() {
@@ -194,8 +199,8 @@
 		}
 		sql << L"\n)";
 
-		std::unique_ptr<PreparedStatement> createTable(connection->prepareStatement(convertor.to_bytes(sql.str()).c_str()));
-		createTable->next();
+		std::unique_ptr<PreparedStatement> createTable(connection->prepareStatement(sql.str()));
+		createTable->executeUpdate();
 
 		// prepare INSERT:
 		sql = wstringstream();
@@ -207,7 +212,7 @@
 			if (i < attributes.size() - 1) sql << L",";
 		}
 		sql << L")";
-		currentInsert.reset(connection->prepareStatement(convertor.to_bytes(sql.str()).c_str()));
+		currentInsert.reset(connection->prepareStatement(sql.str()));
 	}
 
 	void attribute(const void* value, const std::type_info& typeInfo) override {
@@ -233,7 +238,7 @@
 			{
 				assert(typeInfo == typeid (string_t));
 				auto* typedValue = static_cast<const string_t*> (value);
-				currentInsert->setString(currentAttributeIndex, convertor.to_bytes(*typedValue).c_str());
+				currentInsert->setString(currentAttributeIndex, *typedValue);
 				break;
 			}
 			default:
@@ -241,7 +246,7 @@
 		}
 
 		if (currentAttributeIndex % currentReaderMetadata.size() == 0) {
-			currentInsert->next();
+			currentInsert->executeUpdate();
 			currentInsert->reset();
 			currentAttributeIndex = 0;
 		}