Skip to content

Commit d1bcba1

Browse files
committed
Ser/De: Arrays POC.
1 parent c5f81d5 commit d1bcba1

File tree

5 files changed

+362
-103
lines changed

5 files changed

+362
-103
lines changed

src/oatpp-postgresql/mapping/Deserializer.hpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class Deserializer {
113113
return nullptr;
114114
}
115115

116-
auto ndim = (v_int32) htonl(*((p_int32)data.data));
116+
auto ndim = (v_int32) ntohl(*((p_int32)data.data));
117117

118118
switch (ndim) {
119119

@@ -218,7 +218,7 @@ class Deserializer {
218218
return oatpp::Void(nullptr, type);
219219
}
220220

221-
auto ndim = (v_int32) htonl(*((p_int32)data.data));
221+
auto ndim = (v_int32) ntohl(*((p_int32)data.data));
222222
if(ndim == 0) {
223223
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
224224
return polymorphicDispatcher->createObject(); // empty array
@@ -229,27 +229,23 @@ class Deserializer {
229229
meta.data = &data;
230230

231231
meta.arrayHeader = *((PgArrayHeader*) data.data);
232-
meta.arrayHeader.ndim = (v_int32) htonl(meta.arrayHeader.ndim);
233-
meta.arrayHeader.size = (v_int32) htonl(meta.arrayHeader.size);
234-
meta.arrayHeader.oid = (v_int32) htonl(meta.arrayHeader.oid);
235-
meta.arrayHeader.index = (v_int32) htonl(meta.arrayHeader.index);
232+
meta.arrayHeader.ndim = (v_int32) ntohl(meta.arrayHeader.ndim);
233+
meta.arrayHeader.size = (v_int32) ntohl(meta.arrayHeader.size);
234+
meta.arrayHeader.oid = (v_int32) ntohl(meta.arrayHeader.oid);
235+
meta.arrayHeader.index = (v_int32) ntohl(meta.arrayHeader.index);
236236

237237
meta.dimensions = {meta.arrayHeader.size};
238238

239239
if(meta.arrayHeader.ndim == 1) {
240240
meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader)];
241241
} else {
242242
for(v_int32 i = 0; i < meta.arrayHeader.ndim - 1; i ++) {
243-
v_int32 dsize = htonl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2]));
243+
v_int32 dsize = ntohl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2]));
244244
meta.dimensions.push_back(dsize);
245245
}
246246
meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader) + sizeof(v_int32) * (meta.arrayHeader.ndim - 1) * 2];
247247
}
248248

249-
// for(v_int32 d : meta.dimensions) {
250-
// OATPP_LOGD("Array", "D=%d", d);
251-
// }
252-
253249
return deserializeSubArray(type, meta, 0);
254250

255251
}

src/oatpp-postgresql/mapping/Serializer.cpp

Lines changed: 176 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -65,40 +65,65 @@ void Serializer::setSerializerMethods() {
6565

6666
setSerializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::serializeEnum);
6767

68+
setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeArray2<oatpp::AbstractVector>);
69+
setSerializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::serializeArray2<oatpp::AbstractList>);
70+
setSerializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::serializeArray2<oatpp::AbstractUnorderedSet>);
71+
6872
////
6973

7074
setSerializerMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::serializeUuid);
71-
setSerializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::serializeArray);
7275

7376
}
7477

7578
void Serializer::setTypeOidMethods() {
7679

7780
m_typeOidMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr);
81+
m_arrayTypeOidMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr);
7882

7983
setTypeOidMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::getTypeOid<TEXTOID>);
84+
setArrayTypeOidMethod(data::mapping::type::__class::String::CLASS_ID, &Serializer::getTypeOid<TEXTARRAYOID>);
8085

8186
setTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
87+
setArrayTypeOidMethod(data::mapping::type::__class::Int8::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
88+
8289
setTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
90+
setArrayTypeOidMethod(data::mapping::type::__class::UInt8::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
8391

8492
setTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid<INT2OID>);
93+
setArrayTypeOidMethod(data::mapping::type::__class::Int16::CLASS_ID, &Serializer::getTypeOid<INT2ARRAYOID>);
94+
8595
setTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid<INT4OID>);
96+
setArrayTypeOidMethod(data::mapping::type::__class::UInt16::CLASS_ID, &Serializer::getTypeOid<INT4ARRAYOID>);
8697

8798
setTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid<INT4OID>);
99+
setArrayTypeOidMethod(data::mapping::type::__class::Int32::CLASS_ID, &Serializer::getTypeOid<INT4ARRAYOID>);
100+
88101
setTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid<INT8OID>);
102+
setArrayTypeOidMethod(data::mapping::type::__class::UInt32::CLASS_ID, &Serializer::getTypeOid<INT8ARRAYOID>);
89103

90104
setTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid<INT8OID>);
105+
setArrayTypeOidMethod(data::mapping::type::__class::Int64::CLASS_ID, &Serializer::getTypeOid<INT8ARRAYOID>);
91106

92107
setTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid<FLOAT4OID>);
108+
setArrayTypeOidMethod(data::mapping::type::__class::Float32::CLASS_ID, &Serializer::getTypeOid<FLOAT4ARRAYOID>);
109+
93110
setTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid<FLOAT8OID>);
111+
setArrayTypeOidMethod(data::mapping::type::__class::Float64::CLASS_ID, &Serializer::getTypeOid<FLOAT8ARRAYOID>);
112+
94113
setTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid<BOOLOID>);
114+
setArrayTypeOidMethod(data::mapping::type::__class::Boolean::CLASS_ID, &Serializer::getTypeOid<BOOLARRAYOID>);
115+
116+
setTypeOidMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::get1DCollectionOid);
117+
setTypeOidMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Serializer::get1DCollectionOid);
118+
setTypeOidMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Serializer::get1DCollectionOid);
95119

96-
setTypeOidMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Serializer::getTypeOid<FLOAT8ARRAYOID>);
120+
setTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumTypeOid);
121+
setArrayTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumArrayTypeOid);
97122

98123
////
99124

100125
setTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid<UUIDOID>);
101-
setTypeOidMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Serializer::getEnumTypeOid);
126+
setArrayTypeOidMethod(postgresql::mapping::type::__class::Uuid::CLASS_ID, &Serializer::getTypeOid<UUIDARRAYOID>);
102127

103128
}
104129

@@ -113,13 +138,22 @@ void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId
113138

114139
void Serializer::setTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method) {
115140
const v_uint32 id = classId.id;
116-
if(id < m_methods.size()) {
141+
if(id < m_typeOidMethods.size()) {
117142
m_typeOidMethods[id] = method;
118143
} else {
119144
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::setTypeOidMethod()]: Error. Unknown classId");
120145
}
121146
}
122147

148+
void Serializer::setArrayTypeOidMethod(const data::mapping::type::ClassId& classId, TypeOidMethod method) {
149+
const v_uint32 id = classId.id;
150+
if(id < m_arrayTypeOidMethods.size()) {
151+
m_arrayTypeOidMethods[id] = method;
152+
} else {
153+
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::setArrayTypeOidMethod()]: Error. Unknown classId");
154+
}
155+
}
156+
123157
void Serializer::serialize(OutputData& outData, const oatpp::Void& polymorph) const {
124158
auto id = polymorph.valueType->classId.id;
125159
auto& method = m_methods[id];
@@ -146,13 +180,27 @@ Oid Serializer::getTypeOid(const oatpp::Type* type) const {
146180

147181
}
148182

183+
Oid Serializer::getArrayTypeOid(const oatpp::Type* type) const {
184+
185+
auto id = type->classId.id;
186+
auto& method = m_arrayTypeOidMethods[id];
187+
if(method) {
188+
return (*method)(this, type);
189+
}
190+
191+
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::getArrayTypeOid()]: "
192+
"Error. Can't derive OID for type '" + std::string(type->classId.name) +
193+
"'");
194+
195+
}
196+
149197
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150198
// Serializer utility functions
151199

152200
void Serializer::serNull(OutputData& outData) {
153201
outData.dataBuffer.reset();
154202
outData.data = nullptr;
155-
outData.dataSize = 0;
203+
outData.dataSize = -1;
156204
outData.dataFormat = 1;
157205
}
158206

@@ -377,6 +425,30 @@ Oid Serializer::getEnumTypeOid(const Serializer* _this, const oatpp::Type* type)
377425

378426
}
379427

428+
Oid Serializer::getEnumArrayTypeOid(const Serializer* _this, const oatpp::Type* type) {
429+
430+
auto polymorphicDispatcher = static_cast<const data::mapping::type::__class::AbstractEnum::PolymorphicDispatcher*>(
431+
type->polymorphicDispatcher
432+
);
433+
434+
const oatpp::Type* enumInterType = polymorphicDispatcher->getInterpretationType();
435+
return _this->getArrayTypeOid(enumInterType);
436+
437+
}
438+
439+
Oid Serializer::get1DCollectionOid(const Serializer* _this, const oatpp::Type* type) {
440+
441+
while(type->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id ||
442+
type->classId.id == oatpp::AbstractList::Class::CLASS_ID.id ||
443+
type->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id)
444+
{
445+
type = *type->params.begin();
446+
}
447+
448+
return _this->getArrayTypeOid(type);
449+
450+
}
451+
380452
void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph) {
381453

382454
(void) _this;
@@ -392,46 +464,106 @@ void Serializer::serializeUuid(const Serializer* _this, OutputData& outData, con
392464
}
393465
}
394466

395-
void Serializer::serializeArray(const Serializer* _this, OutputData& outData, const oatpp::Void& polymorph) {
396-
397-
(void) _this;
398-
399-
if(polymorph) {
400-
auto v = polymorph.staticCast<oatpp::Vector<Float64>>();
401-
402-
// get size of header + vector size * sizeof each element (size + data)
403-
auto dataSize = sizeof(PgArrayHeader) + v->size() * (sizeof(PgElem) + sizeof(v_float64));
404-
outData.dataBuffer.reset(new char[dataSize]);
405-
outData.dataSize = dataSize;
406-
outData.dataFormat = 1;
407-
outData.oid = FLOAT8ARRAYOID;
408-
outData.data = outData.dataBuffer.get();
409-
auto buffer = outData.data;
410-
411-
// load the data in to the pgArray
412-
auto *pgArray = reinterpret_cast<PgArray *>(buffer);
413-
// only support 1d float8 arrays for now
414-
pgArray->header.ndim = htonl(1);
415-
pgArray->header._ign = 0;
416-
pgArray->header.oid = htonl(FLOAT8OID);
417-
pgArray->header.size = htonl(v->size());
418-
pgArray->header.index = htonl(1); // postgres arrays are indexed 1..N by default
419-
420-
// stuff in the elements in network order
421-
auto *elemBuff = reinterpret_cast<p_uint8>(pgArray->elem);
422-
for (int i=0; i < v->size(); i++) {
423-
*reinterpret_cast<p_uint32>(elemBuff) = htonl(sizeof(v_float64));
424-
elemBuff += sizeof(v_int32);
425-
v_float64 fValue = v->at(i);
426-
auto pVal = reinterpret_cast<p_int64>(&fValue);
427-
*reinterpret_cast<p_uint32>(elemBuff) = htonl(*pVal >> 32);
428-
elemBuff += sizeof(v_int32);
429-
*reinterpret_cast<p_uint32>(elemBuff) = htonl(*pVal & 0xFFFFFFFF);
430-
elemBuff += sizeof(v_int32);
431-
}
432-
} else{
433-
serNull(outData);
467+
const oatpp::Type* Serializer::getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector<v_int32>& dimensions) {
468+
469+
void* currObj = polymorph.get();
470+
const oatpp::Type* currType = polymorph.valueType;
471+
472+
while(currType->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id ||
473+
currType->classId.id == oatpp::AbstractList::Class::CLASS_ID.id ||
474+
currType->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id)
475+
{
476+
477+
if(currObj == nullptr) {
478+
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::getArrayItemTypeAndDimensions()]: Error. "
479+
"The nested container can't be null.");
480+
}
481+
482+
if(currType->classId.id == oatpp::AbstractVector::Class::CLASS_ID.id) {
483+
484+
auto c = static_cast<std::vector<oatpp::Void>*>(currObj);
485+
dimensions.push_back(c->size());
486+
currObj = (c->size() > 0) ? (*c)[0].get() : nullptr;
487+
488+
} else if(currType->classId.id == oatpp::AbstractList::Class::CLASS_ID.id) {
489+
490+
auto c = static_cast<std::list<oatpp::Void>*>(currObj);
491+
dimensions.push_back(c->size());
492+
currObj = (c->size() > 0) ? c->front().get() : nullptr;
493+
494+
495+
} else if(currType->classId.id == oatpp::AbstractUnorderedSet::Class::CLASS_ID.id) {
496+
497+
auto c = static_cast<std::unordered_set<oatpp::Void>*>(currObj);
498+
dimensions.push_back(c->size());
499+
currObj = (c->size() > 0) ? c->begin()->get() : nullptr;
500+
434501
}
502+
503+
currType = *currType->params.begin();
504+
505+
}
506+
507+
return currType;
508+
509+
}
510+
511+
void Serializer::writeArrayHeader(data::stream::ConsistentOutputStream* stream,
512+
Oid itemOid,
513+
const std::vector<v_int32>& dimensions)
514+
{
515+
516+
// num dimensions
517+
v_int32 v = htonl(dimensions.size());
518+
stream->writeSimple(&v, sizeof(v_int32));
519+
520+
// ignore
521+
v = 0;
522+
stream->writeSimple(&v, sizeof(v_int32));
523+
524+
// oid
525+
v = htonl(itemOid);
526+
stream->writeSimple(&v, sizeof(v_int32));
527+
528+
// size
529+
v = htonl(dimensions[0]);
530+
stream->writeSimple(&v, sizeof(v_int32));
531+
532+
// index
533+
v = htonl(1);
534+
stream->writeSimple(&v, sizeof(v_int32));
535+
536+
for(v_uint32 i = 1; i < dimensions.size(); i++) {
537+
v_int32 size = htonl(dimensions[i]);
538+
v_int32 index = htonl(1);
539+
stream->writeSimple(&size, sizeof(v_int32));
540+
stream->writeSimple(&index, sizeof(v_int32));
541+
}
542+
543+
}
544+
545+
void Serializer::serializeSubArray(data::stream::ConsistentOutputStream* stream,
546+
const oatpp::Void& polymorph,
547+
ArraySerializationMeta& meta,
548+
v_int32 dimension)
549+
{
550+
551+
const oatpp::Type* type = polymorph.valueType;
552+
553+
if(data::mapping::type::__class::AbstractVector::CLASS_ID.id == type->classId.id) {
554+
return serializeSubArray<oatpp::AbstractVector>(stream, polymorph, meta, dimension);
555+
556+
} else if(data::mapping::type::__class::AbstractList::CLASS_ID.id == type->classId.id) {
557+
return serializeSubArray<oatpp::AbstractList>(stream, polymorph, meta, dimension);
558+
559+
} else if(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id == type->classId.id) {
560+
return serializeSubArray<oatpp::AbstractUnorderedSet>(stream, polymorph, meta, dimension);
561+
562+
}
563+
564+
throw std::runtime_error("[oatpp::postgresql::mapping::Serializer::serializeSubArray()]: "
565+
"Error. Unknown 1D collection type.");
566+
435567
}
436568

437569
}}}

0 commit comments

Comments
 (0)