--- a/src/SqlHandler.h Fri Dec 13 22:19:41 2019 +0100
+++ b/src/SqlHandler.h Sat Dec 14 14:00:36 2019 +0100
@@ -103,21 +103,25 @@
else throw SqlException(L"Unable to get SQLite column name.");
}
- relpipe::writer::TypeId getColumType(int columnIndex) {
+ relpipe::writer::TypeId getColumType(int columnIndex, relpipe::writer::TypeId defaultType = relpipe::writer::TypeId::STRING) {
const char* type = sqlite3_column_decltype(stmt, columnIndex);
// TODO: sqlite3_column_decltype returns value only for columns of existing tables, not for dynamic expressions – SQLite uses dynamic types
+ // maybe we could write a function/module that returns result set metadata for given query (before executing it)
+ // or use at least explicit casts in SQL and modify sqlite3_column_decltype() function or add some new one to return such casted type
+ //
// fprintf(stderr, "%d → %s\n", columnIndex, type);
// SELECT typeof(1+1); == "integer"
// https://www.sqlite.org/c3ref/column_decltype.html – sqlite3_column_decltype
// https://www.sqlite.org/c3ref/column_blob.html – sqlite3_column_type
// https://www.sqlite.org/datatype3.html – Datatypes In SQLite Version 3
// https://dba.stackexchange.com/questions/203220/sqlite-what-is-the-use-of-specifying-data-types
+ // https://www.mail-archive.com/sqlite-users@mailinglists.sqlite.org/msg118093.html
if (type == nullptr) return relpipe::writer::TypeId::STRING;
else if (strcmp(type, "integer") == 0) return relpipe::writer::TypeId::INTEGER;
else if (strcmp(type, "text") == 0) return relpipe::writer::TypeId::STRING;
- else return relpipe::writer::TypeId::STRING;
+ else return defaultType;
// TODO: support also other data types
}
@@ -202,8 +206,13 @@
}
}
+ relpipe::writer::TypeId findType(string_t columnName, int columnIndex, const Statement& statement, std::shared_ptr<PreparedStatement> preparedStatement) {
+ for (TypeCast typeCast : statement.typeCasts) if (typeCast.name == columnName) return relationalWriter->toTypeId(typeCast.type);
+ return preparedStatement->getColumType(columnIndex);
+ }
+
void processStatement(const Statement& statement) {
- std::unique_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
+ std::shared_ptr<PreparedStatement> prepared(connection->prepareStatement(convertor.to_bytes(statement.sql).c_str()));
int columnCount = prepared->getColumnCount();
int parameterCount = statement.parameters.size();
@@ -212,7 +221,10 @@
}
std::vector<relpipe::writer::AttributeMetadata> metadata;
- for (int i = 0; i < columnCount; i++) metadata.push_back({convertor.from_bytes(prepared->getColumName(i).c_str()), prepared->getColumType(i)});
+ 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)});
+ }
relationalWriter->startRelation(statement.relation, metadata, true);
while (prepared->next()) {