mirror of
https://github.com/oatpp/oatpp-postgresql.git
synced 2024-11-27 02:39:56 +08:00
Ser/De: Arrays POC.
This commit is contained in:
parent
c5f81d5e64
commit
d1bcba1380
@ -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<const typename Collection::Class::PolymorphicDispatcher*>(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);
|
||||
|
||||
}
|
||||
|
@ -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<oatpp::AbstractVector>);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeArray2<oatpp::AbstractList>);
|
||||
setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeArray2<oatpp::AbstractUnorderedSet>);
|
||||
|
||||
////
|
||||
|
||||
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<TEXTOID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::getTypeOid<TEXTARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid<INT4OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid<INT4ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid<INT4OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid<INT4ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid<INT8OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid<INT8ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid<INT8OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid<INT8ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid<FLOAT4OID>);
|
||||
setTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid<FLOAT8OID>);
|
||||
setTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid<BOOLOID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid<FLOAT4ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::getTypeOid<FLOAT8ARRAYOID>);
|
||||
setTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid<FLOAT8OID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid<FLOAT8ARRAYOID>);
|
||||
|
||||
setTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid<BOOLOID>);
|
||||
setArrayTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid<BOOLARRAYOID>);
|
||||
|
||||
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<UUIDOID>);
|
||||
setTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumTypeOid);
|
||||
setArrayTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid<UUIDARRAYOID>);
|
||||
|
||||
}
|
||||
|
||||
@ -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<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
|
||||
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<v_int32>& dimensions) {
|
||||
|
||||
(void) _this;
|
||||
void* currObj = polymorph.get();
|
||||
const oatpp::Type* currType = polymorph.valueType;
|
||||
|
||||
if(polymorph) {
|
||||
auto v = polymorph.staticCast<oatpp::Vector<Float64>>();
|
||||
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<PgArray *>(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<p_uint8>(pgArray->elem);
|
||||
for (int i=0; i < v->size(); i++) {
|
||||
*reinterpret_cast<p_uint32>(elemBuff) = htonl(sizeof(v_float64));
|
||||
elemBuff += sizeof(v_int32);
|
||||
v_float64 fValue = v->at(i);
|
||||
auto pVal = reinterpret_cast<p_int64>(&fValue);
|
||||
*reinterpret_cast<p_uint32>(elemBuff) = htonl(*pVal >> 32);
|
||||
elemBuff += sizeof(v_int32);
|
||||
*reinterpret_cast<p_uint32>(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<std::vector<oatpp::Void>*>(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<std::list<oatpp::Void>*>(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<std::unordered_set<oatpp::Void>*>(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<v_int32>& 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<oatpp::AbstractVector>(stream, polymorph, meta, dimension);
|
||||
|
||||
} else if(data::mapping::type::__class::AbstractList::CLASS_ID.id == type->classId.id) {
|
||||
return serializeSubArray<oatpp::AbstractList>(stream, polymorph, meta, dimension);
|
||||
|
||||
} else if(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id == type->classId.id) {
|
||||
return serializeSubArray<oatpp::AbstractUnorderedSet>(stream, polymorph, meta, dimension);
|
||||
|
||||
}
|
||||
|
||||
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeSubArray()]: "
|
||||
"Error. Unknown 1D collection type.");
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -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 <libpq-fe.h>
|
||||
@ -38,11 +39,11 @@ class Serializer {
|
||||
public:
|
||||
|
||||
struct OutputData {
|
||||
Oid oid;
|
||||
Oid oid = InvalidOid;
|
||||
std::unique_ptr<char[]> 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<SerializerMethod> m_methods;
|
||||
std::vector<TypeOidMethod> m_typeOidMethods;
|
||||
std::vector<TypeOidMethod> 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<v_int32> dimensions;
|
||||
|
||||
};
|
||||
|
||||
static const oatpp::Type* getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector<v_int32>& dimensions);
|
||||
static void writeArrayHeader(data::stream::ConsistentOutputStream* stream, Oid itemOid, const std::vector<v_int32>& dimensions);
|
||||
|
||||
static void serializeSubArray(data::stream::ConsistentOutputStream* stream,
|
||||
const oatpp::Void& polymorph,
|
||||
ArraySerializationMeta& meta,
|
||||
v_int32 dimension);
|
||||
|
||||
template<class Collection>
|
||||
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<Collection>();
|
||||
|
||||
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<Collection>();
|
||||
|
||||
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<class Collection>
|
||||
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<Oid OID>
|
||||
@ -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);
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
@ -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
|
||||
|
@ -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<Float32>, f_real);
|
||||
DTO_FIELD(Vector<Float64>, f_double);
|
||||
DTO_FIELD(Vector<Int16>, f_int16);
|
||||
DTO_FIELD(Vector<Int32>, f_int32);
|
||||
DTO_FIELD(Vector<Int64>, f_int64);
|
||||
DTO_FIELD(Vector<Boolean> , f_bool);
|
||||
DTO_FIELD(Vector<String> , 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>, 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()) {
|
||||
|
Loading…
Reference in New Issue
Block a user