From d1bcba1380fec3a04e57a8fd461d11fc0c10299a Mon Sep 17 00:00:00 2001 From: lganzzzo Date: Wed, 10 Feb 2021 01:19:03 +0200 Subject: [PATCH] Ser/De: Arrays POC. --- src/oatpp-postgresql/mapping/Deserializer.hpp | 18 +- src/oatpp-postgresql/mapping/Serializer.cpp | 218 ++++++++++++++---- src/oatpp-postgresql/mapping/Serializer.hpp | 116 +++++++++- test/oatpp-postgresql/migration/ArrayTest.sql | 74 +++--- test/oatpp-postgresql/types/ArrayTest.cpp | 37 ++- 5 files changed, 361 insertions(+), 102 deletions(-) diff --git a/src/oatpp-postgresql/mapping/Deserializer.hpp b/src/oatpp-postgresql/mapping/Deserializer.hpp index 318eedf..f308df1 100644 --- a/src/oatpp-postgresql/mapping/Deserializer.hpp +++ b/src/oatpp-postgresql/mapping/Deserializer.hpp @@ -113,7 +113,7 @@ private: return nullptr; } - auto ndim = (v_int32) htonl(*((p_int32)data.data)); + auto ndim = (v_int32) ntohl(*((p_int32)data.data)); switch (ndim) { @@ -218,7 +218,7 @@ private: return oatpp::Void(nullptr, type); } - auto ndim = (v_int32) htonl(*((p_int32)data.data)); + auto ndim = (v_int32) ntohl(*((p_int32)data.data)); if(ndim == 0) { auto polymorphicDispatcher = static_cast(type->polymorphicDispatcher); return polymorphicDispatcher->createObject(); // empty array @@ -229,10 +229,10 @@ private: meta.data = &data; meta.arrayHeader = *((PgArrayHeader*) data.data); - meta.arrayHeader.ndim = (v_int32) htonl(meta.arrayHeader.ndim); - meta.arrayHeader.size = (v_int32) htonl(meta.arrayHeader.size); - meta.arrayHeader.oid = (v_int32) htonl(meta.arrayHeader.oid); - meta.arrayHeader.index = (v_int32) htonl(meta.arrayHeader.index); + meta.arrayHeader.ndim = (v_int32) ntohl(meta.arrayHeader.ndim); + meta.arrayHeader.size = (v_int32) ntohl(meta.arrayHeader.size); + meta.arrayHeader.oid = (v_int32) ntohl(meta.arrayHeader.oid); + meta.arrayHeader.index = (v_int32) ntohl(meta.arrayHeader.index); meta.dimensions = {meta.arrayHeader.size}; @@ -240,16 +240,12 @@ private: meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader)]; } else { for(v_int32 i = 0; i < meta.arrayHeader.ndim - 1; i ++) { - v_int32 dsize = htonl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2])); + v_int32 dsize = ntohl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2])); meta.dimensions.push_back(dsize); } meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader) + sizeof(v_int32) * (meta.arrayHeader.ndim - 1) * 2]; } -// for(v_int32 d : meta.dimensions) { -// OATPP_LOGD("Array", "D=%d", d); -// } - return deserializeSubArray(type, meta, 0); } diff --git a/src/oatpp-postgresql/mapping/Serializer.cpp b/src/oatpp-postgresql/mapping/Serializer.cpp index 7a5d039..61c4530 100644 --- a/src/oatpp-postgresql/mapping/Serializer.cpp +++ b/src/oatpp-postgresql/mapping/Serializer.cpp @@ -65,40 +65,65 @@ void Serializer::setSerializerMethods() { setSerializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::serializeEnum); + setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeArray2); + setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeArray2); + setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeArray2); + //// setSerializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::serializeUuid); - setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeArray); } void Serializer::setTypeOidMethods() { m_typeOidMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr); + m_arrayTypeOidMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr); setTypeOidMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::getTypeOid); setTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid); + setTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid); setTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid); + setTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid); setTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid); + setTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid); setTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid); setTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid); - setTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid); - setTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid); - setTypeOidMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::getTypeOid); + setTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid); + + setTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid); + + setTypeOidMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::get1DCollectionOid); + setTypeOidMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::get1DCollectionOid); + setTypeOidMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::get1DCollectionOid); + + setTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumTypeOid); + setArrayTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumArrayTypeOid); //// setTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid); - setTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumTypeOid); + setArrayTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid); } @@ -113,13 +138,22 @@ void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId void Serializer::setTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method) { const v_uint32 id = classId.id; - if(id < m_methods.size()) { + if(id < m_typeOidMethods.size()) { m_typeOidMethods[id] = method; } else { throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::setTypeOidMethod()]: Error. Unknown classId"); } } +void Serializer::setArrayTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method) { + const v_uint32 id = classId.id; + if(id < m_arrayTypeOidMethods.size()) { + m_arrayTypeOidMethods[id] = method; + } else { + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::setArrayTypeOidMethod()]: Error. Unknown classId"); + } +} + void Serializer::serialize(OutputData& outData, const oatpp::Void& polymorph) const { auto id = polymorph.valueType->classId.id; auto& method = m_methods[id]; @@ -146,13 +180,27 @@ Oid Serializer::getTypeOid(const oatpp::Type* type) const { } +Oid Serializer::getArrayTypeOid(const oatpp::Type* type) const { + + auto id = type->classId.id; + auto& method = m_arrayTypeOidMethods[id]; + if(method) { + return (*method)(this, type); + } + + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::getArrayTypeOid()]: " + "Error. Can't derive OID for type '" + std::string(type->classId.name) + + "'"); + +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Serializer utility functions void Serializer::serNull(OutputData& outData) { outData.dataBuffer.reset(); outData.data = nullptr; - outData.dataSize = 0; + outData.dataSize = -1; outData.dataFormat = 1; } @@ -377,6 +425,30 @@ Oid Serializer::getEnumTypeOid(const Serializer* _this, const oatpp::Type* type) } +Oid Serializer::getEnumArrayTypeOid(const Serializer* _this, const oatpp::Type* type) { + + auto polymorphicDispatcher = static_cast( + type->polymorphicDispatcher + ); + + const oatpp::Type* enumInterType = polymorphicDispatcher->getInterpretationType(); + return _this->getArrayTypeOid(enumInterType); + +} + +Oid Serializer::get1DCollectionOid(const Serializer* _this, const oatpp::Type* type) { + + while(type->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id || + type->classId.id == oatpp::AbstractList::Class::CLASS_ID.id || + type->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id) + { + type = *type->params.begin(); + } + + return _this->getArrayTypeOid(type); + +} + void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph) { (void) _this; @@ -392,46 +464,106 @@ void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, con } } -void Serializer::serializeArray(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph) { +const oatpp::Type* Serializer::getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector& dimensions) { - (void) _this; + void* currObj = polymorph.get(); + const oatpp::Type* currType = polymorph.valueType; - if(polymorph) { - auto v = polymorph.staticCast>(); + while(currType->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id || + currType->classId.id == oatpp::AbstractList::Class::CLASS_ID.id || + currType->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id) + { - // get size of header + vector size * sizeof each element (size + data) - auto dataSize = sizeof(PgArrayHeader) + v->size() * (sizeof(PgElem) + sizeof(v_float64)); - outData.dataBuffer.reset(new char[dataSize]); - outData.dataSize = dataSize; - outData.dataFormat = 1; - outData.oid = FLOAT8ARRAYOID; - outData.data = outData.dataBuffer.get(); - auto buffer = outData.data; - - // load the data in to the pgArray - auto *pgArray = reinterpret_cast(buffer); - // only support 1d float8 arrays for now - pgArray->header.ndim = htonl(1); - pgArray->header._ign = 0; - pgArray->header.oid = htonl(FLOAT8OID); - pgArray->header.size = htonl(v->size()); - pgArray->header.index = htonl(1); // postgres arrays are indexed 1..N by default - - // stuff in the elements in network order - auto *elemBuff = reinterpret_cast(pgArray->elem); - for (int i=0; i < v->size(); i++) { - *reinterpret_cast(elemBuff) = htonl(sizeof(v_float64)); - elemBuff += sizeof(v_int32); - v_float64 fValue = v->at(i); - auto pVal = reinterpret_cast(&fValue); - *reinterpret_cast(elemBuff) = htonl(*pVal >> 32); - elemBuff += sizeof(v_int32); - *reinterpret_cast(elemBuff) = htonl(*pVal & 0xFFFFFFFF); - elemBuff += sizeof(v_int32); - } - } else{ - serNull(outData); + if(currObj == nullptr) { + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::getArrayItemTypeAndDimensions()]: Error. " + "The nested container can't be null."); } + + if(currType->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id) { + + auto c = static_cast*>(currObj); + dimensions.push_back(c->size()); + currObj = (c->size() > 0) ? (*c)[0].get() : nullptr; + + } else if(currType->classId.id == oatpp::AbstractList::Class::CLASS_ID.id) { + + auto c = static_cast*>(currObj); + dimensions.push_back(c->size()); + currObj = (c->size() > 0) ? c->front().get() : nullptr; + + + } else if(currType->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id) { + + auto c = static_cast*>(currObj); + dimensions.push_back(c->size()); + currObj = (c->size() > 0) ? c->begin()->get() : nullptr; + + } + + currType = *currType->params.begin(); + + } + + return currType; + +} + +void Serializer::writeArrayHeader(data::stream::ConsistentOutputStream* stream, + Oid itemOid, + const std::vector& dimensions) +{ + + // num dimensions + v_int32 v = htonl(dimensions.size()); + stream->writeSimple(&v, sizeof(v_int32)); + + // ignore + v = 0; + stream->writeSimple(&v, sizeof(v_int32)); + + // oid + v = htonl(itemOid); + stream->writeSimple(&v, sizeof(v_int32)); + + // size + v = htonl(dimensions[0]); + stream->writeSimple(&v, sizeof(v_int32)); + + // index + v = htonl(1); + stream->writeSimple(&v, sizeof(v_int32)); + + for(v_uint32 i = 1; i < dimensions.size(); i++) { + v_int32 size = htonl(dimensions[i]); + v_int32 index = htonl(1); + stream->writeSimple(&size, sizeof(v_int32)); + stream->writeSimple(&index, sizeof(v_int32)); + } + +} + +void Serializer::serializeSubArray(data::stream::ConsistentOutputStream* stream, + const oatpp::Void& polymorph, + ArraySerializationMeta& meta, + v_int32 dimension) +{ + + const oatpp::Type* type = polymorph.valueType; + + if(data::mapping::type::__class::AbstractVector::CLASS_ID.id == type->classId.id) { + return serializeSubArray(stream, polymorph, meta, dimension); + + } else if(data::mapping::type::__class::AbstractList::CLASS_ID.id == type->classId.id) { + return serializeSubArray(stream, polymorph, meta, dimension); + + } else if(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id == type->classId.id) { + return serializeSubArray(stream, polymorph, meta, dimension); + + } + + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeSubArray()]: " + "Error. Unknown 1D collection type."); + } }}} diff --git a/src/oatpp-postgresql/mapping/Serializer.hpp b/src/oatpp-postgresql/mapping/Serializer.hpp index d1c65ca..44f47a8 100644 --- a/src/oatpp-postgresql/mapping/Serializer.hpp +++ b/src/oatpp-postgresql/mapping/Serializer.hpp @@ -25,6 +25,7 @@ #ifndef oatpp_postgresql_mapping_Serializer_hpp #define oatpp_postgresql_mapping_Serializer_hpp +#include "oatpp/core/data/stream/BufferStream.hpp" #include "oatpp/core/Types.hpp" #include @@ -38,11 +39,11 @@ class Serializer { public: struct OutputData { - Oid oid; + Oid oid = InvalidOid; std::unique_ptr dataBuffer; - char* data; - int dataSize; - int dataFormat; + char* data = nullptr; + int dataSize = -1; + int dataFormat = 1; }; public: @@ -63,16 +64,19 @@ private: private: std::vector m_methods; std::vector m_typeOidMethods; + std::vector m_arrayTypeOidMethods; public: Serializer(); void setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method); void setTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method); + void setArrayTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method); void serialize(OutputData& outData, const oatpp::Void& polymorph) const; Oid getTypeOid(const oatpp::Type* type) const; + Oid getArrayTypeOid(const oatpp::Type* type) const; private: @@ -99,7 +103,105 @@ private: static void serializeUuid(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph); - static void serializeArray(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph); + struct ArraySerializationMeta { + + const Serializer* _this; + std::vector dimensions; + + }; + + static const oatpp::Type* getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector& dimensions); + static void writeArrayHeader(data::stream::ConsistentOutputStream* stream, Oid itemOid, const std::vector& dimensions); + + static void serializeSubArray(data::stream::ConsistentOutputStream* stream, + const oatpp::Void& polymorph, + ArraySerializationMeta& meta, + v_int32 dimension); + + template + static void serializeSubArray(data::stream::ConsistentOutputStream* stream, + const oatpp::Void& polymorph, + ArraySerializationMeta& meta, + v_int32 dimension) + { + + + const oatpp::Type* type = polymorph.valueType; + const oatpp::Type* itemType = *type->params.begin(); + + if(dimension < meta.dimensions.size() - 1) { + + auto size = meta.dimensions[dimension]; + auto arr = polymorph.template staticCast(); + + if(arr->size() != size) { + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeSubArray()]. Error. " + "All nested arrays must be of the same size."); + } + + for(auto& item : *arr) { + serializeSubArray(stream, item, meta, dimension + 1); + } + + } else if(dimension == meta.dimensions.size() - 1) { + + auto size = meta.dimensions[dimension]; + auto arr = polymorph.template staticCast(); + + if(arr->size() != size) { + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeSubArray()]. Error. " + "All nested arrays must be of the same size."); + } + + for(auto& item : *arr) { + + OutputData data; + meta._this->serialize(data, item); + + v_int32 itemSize = htonl(data.dataSize); + stream->writeSimple(&itemSize, sizeof(v_int32)); + + if(data.data != nullptr) { + stream->writeSimple(data.data, data.dataSize); + } + + } + + } + + } + + template + static void serializeArray2(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph) { + + if(!polymorph) { + serNull(outData); + } + + ArraySerializationMeta meta; + meta._this = _this; + const oatpp::Type* itemType = getArrayItemTypeAndDimensions(polymorph, meta.dimensions); + + if(meta.dimensions.empty()) { + throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeArray2()]: Error. " + "Invalid array."); + } + + data::stream::BufferOutputStream stream; + writeArrayHeader(&stream, _this->getTypeOid(itemType), meta.dimensions); + + serializeSubArray(&stream, polymorph, meta, 0); + + outData.oid = _this->getArrayTypeOid(itemType); + outData.dataSize = stream.getCurrentPosition(); + outData.dataBuffer.template reset(new char[outData.dataSize]); + outData.data = outData.dataBuffer.get(); + outData.dataFormat = 1; + + std::memcpy(outData.data, stream.getData(), outData.dataSize); + + } + private: template @@ -111,6 +213,10 @@ private: static Oid getEnumTypeOid(const Serializer* _this, const oatpp::Type* type); + static Oid getEnumArrayTypeOid(const Serializer* _this, const oatpp::Type* type); + + static Oid get1DCollectionOid(const Serializer* _this, const oatpp::Type* type); + }; }}} diff --git a/test/oatpp-postgresql/migration/ArrayTest.sql b/test/oatpp-postgresql/migration/ArrayTest.sql index e9007f1..6d37da2 100644 --- a/test/oatpp-postgresql/migration/ArrayTest.sql +++ b/test/oatpp-postgresql/migration/ArrayTest.sql @@ -24,43 +24,43 @@ CREATE TABLE test_arrays2 ( f_text text[][] ); - -INSERT INTO test_arrays1 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -(null, null, null, null, null, null, null); - -INSERT INTO test_arrays1 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -('{}', '{}', '{}', '{}', '{}', '{}', '{}'); - -INSERT INTO test_arrays1 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -('{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}'); - -INSERT INTO test_arrays1 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -('{0}', '{0}', '{0}', '{0}', '{0}', '{false}', '{"", ""}'); - -INSERT INTO test_arrays1 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}'); - - -INSERT INTO test_arrays2 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -(null, null, null, null, null, null, null); - -INSERT INTO test_arrays2 -(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) -VALUES -('{}', '{}', '{}', '{}', '{}', '{}', '{}'); - +-- +-- INSERT INTO test_arrays1 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- (null, null, null, null, null, null, null); +-- +-- INSERT INTO test_arrays1 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- ('{}', '{}', '{}', '{}', '{}', '{}', '{}'); +-- +-- INSERT INTO test_arrays1 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- ('{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}'); +-- +-- INSERT INTO test_arrays1 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- ('{0}', '{0}', '{0}', '{0}', '{0}', '{false}', '{"", ""}'); +-- +-- INSERT INTO test_arrays1 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- ('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}'); +-- +-- +-- INSERT INTO test_arrays2 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- (null, null, null, null, null, null, null); +-- +-- INSERT INTO test_arrays2 +-- (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) +-- VALUES +-- ('{}', '{}', '{}', '{}', '{}', '{}', '{}'); +-- INSERT INTO test_arrays2 (f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) VALUES diff --git a/test/oatpp-postgresql/types/ArrayTest.cpp b/test/oatpp-postgresql/types/ArrayTest.cpp index 1579d33..d9ed668 100644 --- a/test/oatpp-postgresql/types/ArrayTest.cpp +++ b/test/oatpp-postgresql/types/ArrayTest.cpp @@ -41,8 +41,13 @@ class Row : public oatpp::DTO { DTO_INIT(Row, DTO); - DTO_FIELD(Float32, f_real); - DTO_FIELD(Float64, f_double); + DTO_FIELD(Vector, f_real); + DTO_FIELD(Vector, f_double); + DTO_FIELD(Vector, f_int16); + DTO_FIELD(Vector, f_int32); + DTO_FIELD(Vector, f_int64); + DTO_FIELD(Vector , f_bool); + DTO_FIELD(Vector , f_text); }; @@ -69,16 +74,16 @@ public: } QUERY(insertValues, - "INSERT INTO test_floats " - "(f_real, f_double) " + "INSERT INTO test_arrays1 " + "(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text) " "VALUES " - "(:row.f_real, :row.f_double);", + "(:row.f_real, :row.f_double, :row.f_int16, :row.f_int32, :row.f_int64, :row.f_bool, :row.f_text);", PARAM(oatpp::Object, row), PREPARE(true)) QUERY(deleteValues, "DELETE FROM test_floats;") - QUERY(selectValues, "SELECT * FROM test_arrays2;") + QUERY(selectValues, "SELECT * FROM test_arrays1;") }; @@ -95,6 +100,26 @@ void ArrayTest::onRun() { auto client = MyClient(executor); + { + auto row = Row::createShared(); + row->f_real = {nullptr, v_float32(0), 0.32}; + row->f_double = {nullptr, v_float64 (0), 0.64}; + row->f_int16 = {nullptr, v_int16(0), 16}; + row->f_int32 = {nullptr, v_int16(0), 32}; + row->f_int64 = {nullptr, v_int16(0), 64}; + row->f_bool = {nullptr, true, false}; + row->f_text = {nullptr, "", "Hello", "World!"}; + + auto res = client.insertValues(row); + if(res->isSuccess()) { + OATPP_LOGD(TAG, "OK, knownCount=%d, hasMore=%d", res->getKnownCount(), res->hasMoreToFetch()); + } else { + auto message = res->getErrorMessage(); + OATPP_LOGD(TAG, "Error, message=%s", message->c_str()); + } + + } + { auto res = client.selectValues(); if(res->isSuccess()) {