--- a/include/relpipe/reader/handlers/RelationalReaderStringHandler.h Mon Aug 27 00:06:14 2018 +0200
+++ b/include/relpipe/reader/handlers/RelationalReaderStringHandler.h Mon Sep 03 23:40:12 2018 +0200
@@ -13,6 +13,11 @@
public:
virtual void attribute(const string_t& value) = 0;
+
+ // TODO: null values:
+ // a) special constant for null value
+ // b) virtual void attribute(const string_t& value, boolean_t isNull) = 0;
+ // c) virtual void null() = 0;
};
--- a/src/DataTypeReader.h Mon Aug 27 00:06:14 2018 +0200
+++ b/src/DataTypeReader.h Mon Sep 03 23:40:12 2018 +0200
@@ -1,5 +1,8 @@
#pragma once
+#include <sstream>
+#include <functional>
+
#include "DataTypeReaderBase.h"
namespace relpipe {
@@ -20,6 +23,16 @@
return toString(readValue(input));
}
+ virtual void read(std::istream &input, std::function<void(const void *, const std::type_info&) > handler) override {
+ T value = readValue(input);
+ handler(&value, typeid (T));
+ }
+
+ virtual void read(std::istream &input, std::function<void(const string_t&, const void *, const std::type_info&) > handler) override {
+ T value = readValue(input);
+ handler(toString(value), &value, typeid (T));
+ }
+
virtual string_t toString(const T& value) = 0;
};
--- a/src/DataTypeReaderBase.h Mon Aug 27 00:06:14 2018 +0200
+++ b/src/DataTypeReaderBase.h Mon Sep 03 23:40:12 2018 +0200
@@ -1,6 +1,7 @@
#pragma once
#include <string>
+#include <functional>
#include "../include/relpipe/reader/TypeId.h"
#include "../include/relpipe/reader/typedefs.h"
@@ -24,6 +25,8 @@
};
/**
+ * TODO: delete, use handler?
+ *
* @param input input stream, should be at position where the value is to be read; the stream will not be closed afred reading
* @return read value in form of the string representation of given data type.
* E.g. integer 123 is returned as a character string "123",
@@ -33,6 +36,22 @@
virtual string_t readString(std::istream &input) = 0;
/**
+ * The value is read from the input and then passed to the handler.
+ *
+ * @param input
+ * @param handler
+ */
+ virtual void read(std::istream &input, std::function<void(const void *, const std::type_info&) > handler) = 0;
+
+ /**
+ * TODO: documentation
+ *
+ * @param input
+ * @param handler
+ */
+ virtual void read(std::istream &input, std::function<void(const string_t&, const void *, const std::type_info&) > handler) = 0;
+
+ /**
* @param dataType data type code as defined in DDP L0
* @return whether this class supports conversions of this type
*/
--- a/src/StreamRelationalReader.h Mon Aug 27 00:06:14 2018 +0200
+++ b/src/StreamRelationalReader.h Mon Sep 03 23:40:12 2018 +0200
@@ -29,6 +29,7 @@
types::IntegerDataTypeReader integerReader;
types::StringDataTypeReader stringReader;
std::vector<DataTypeReaderBase*> readers = {&booleanReader, &integerReader, &stringReader};
+
std::vector<handlers::RelationalReaderStringHadler*> stringHandlers;
std::vector<handlers::RelationalReaderValueHadler*> valueHandlers;
@@ -45,6 +46,26 @@
* types of columns in the current table
*/
std::vector<TypeId> columnTypes;
+ std::vector<string_t> columnNames;
+ std::vector<std::pair<string_t, TypeId>> columns;
+
+ /**
+ * TODO: remove?
+ */
+ string_t readString(std::istream &input, const TypeId typeId) {
+ for (DataTypeReaderBase* reader : readers) if (reader->supports(typeId)) return reader->readString(input);
+ throw RelpipeReaderException(L"Unsupported data type: " + (int) typeId);
+ }
+
+ void read(std::istream &input, std::function<void(const void *, const std::type_info&) > handler, const TypeId typeId) {
+ for (DataTypeReaderBase* reader : readers) if (reader->supports(typeId)) return reader->read(input, handler);
+ throw RelpipeReaderException(L"Unsupported data type: " + (int) typeId);
+ }
+
+ void read(std::istream &input, std::function<void(const string_t&, const void *, const std::type_info&) > handler, const TypeId typeId) {
+ for (DataTypeReaderBase* reader : readers) if (reader->supports(typeId)) return reader->read(input, handler);
+ throw RelpipeReaderException(L"Unsupported data type: " + (int) typeId);
+ }
public:
@@ -66,29 +87,95 @@
}
void process() override {
- for (int i = 0; i < stringHandlers.size(); i++) {
- // FIXME: parse and call methods
- stringHandlers[i]->startRelation(L"TODO: table",{
- {L"a", TypeId::STRING},
- {L"b", TypeId::STRING},
- {L"c", TypeId::STRING}
- });
+
+ while (true) {
+ integer_t dataPart;
+ try {
+ dataPart = integerReader.readValue(input);
+ // output << "dataPart: " << dataPart << endl;
+ } catch (RelpipeReaderException e) {
+ if (input.eof() && input.gcount() == 0) {
+ if (dataPart == DATA_PART_ROW) {
+ // last part was row
+ // input was fully read
+ // we are finished
+ // TODO: printCachedData(output); ???
+ return;
+ } else if (dataPart == DATA_PART_START) {
+ // Empty relation might be weird but it is valid data.
+ // Actually, it is not so weird as it looks.
+ // fwprintf(stderr, L"Warning: The table has no rows. Weird… but OK.\n");
+ return;
+ } else {
+ // in current format, there is no other data part
+ // so this will never happen
+ // but maybe later…
+ throw RelpipeReaderException(L"Unexpected EOF");
+ }
+ } else if (input.eof()) {
+ fwprintf(stderr, L"Error: found some unexpected data on the input stream: %d\n", input.gcount());
+ throw e;
+ } else {
+ // other error
+ throw e;
+ }
+ }
+
+ if (dataPart == DATA_PART_START) {
+ // Print data of previous table
+ // TODO: if (values.size() > 0) printCachedData(output); ???
+
+ // Read table name
+ string_t tableName = stringReader.readValue(input);
+
+ // Read column count
+ columnCount = integerReader.readValue(input);
+
+ columnTypes.resize(columnCount);
+ columnNames.resize(columnCount);
+ columns.resize(columnCount);
+
+ // Read column names
+ for (int i = 0; i < columnCount; i++) {
+ columnNames[i] = stringReader.readValue(input);
+ }
+
+ // Read column types
+ for (int i = 0; i < columnCount; i++) {
+ TypeId typeId = (TypeId) integerReader.readValue(input); // TODO: přetypování OK?
+ string_t typeCode = toTypeCode(typeId); // validate typeId TODO: je potřeba?
+ columnTypes[i] = typeId;
+ }
+
+ for (int i = 0; i < columnCount; i++) {
+ columns[i] = {columnNames[i], columnTypes[i]};
+ }
+
+ for (int i = 0; i < stringHandlers.size(); i++) stringHandlers[i]->startRelation(tableName, columns);
+ for (int i = 0; i < valueHandlers.size(); i++) valueHandlers[i]->startRelation(tableName, columns);
+
+ } else if (dataPart == DATA_PART_ROW) {
+ for (int i = 0; i < columnCount; i++) {
+ TypeId typeId = columnTypes[i];
+
+ if (stringHandlers.empty()) {
+ read(input, [&](const void * rawValue, const std::type_info & typeInfo) {
+ for (int i = 0; i < valueHandlers.size(); i++) valueHandlers[i]->attribute(rawValue, typeInfo);
+ }, typeId);
+ } else {
+ read(input, [&](const string_t& stringValue, const void * rawValue, const std::type_info & typeInfo) {
+ for (int i = 0; i < stringHandlers.size(); i++) stringHandlers[i]->attribute(stringValue);
+ for (int i = 0; i < valueHandlers.size(); i++) valueHandlers[i]->attribute(rawValue, typeInfo);
+ }, typeId);
+ }
+ }
+
+ } else {
+ throw RelpipeReaderException(L"Unknown data part");
+ }
}
- for (int i = 0; i < valueHandlers.size(); i++) {
- // FIXME: parse and call methods
- valueHandlers[i]->startRelation(L"TODO: table value",{
- {L"av", TypeId::STRING},
- {L"bv", TypeId::STRING},
- {L"cv", TypeId::STRING}
- });
- }
-
- // FIXME: parse and call methods
- for (int row = 0; row < 3; row++) {
- for (int i = 0; i < stringHandlers.size(); i++) stringHandlers[i]->attribute(L"x");
-
- }
+ throw RelpipeReaderException(L"Unexpected exception"); // should never happen
}