Skip to content

Commit 7b3d20f

Browse files
committed
First cut at decoding double 1d arrays
1 parent b622bdc commit 7b3d20f

File tree

1 file changed

+65
-6
lines changed

1 file changed

+65
-6
lines changed

src/oatpp-postgresql/mapping/Deserializer.cpp

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,8 @@ const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
279279

280280
case TIMESTAMPOID: return oatpp::UInt64::Class::getType();
281281

282+
case FLOAT4ARRAYOID: return oatpp::Vector<Float32>::Class::getType();
283+
282284
case UUIDOID: return oatpp::postgresql::Uuid::Class::getType();
283285

284286
}
@@ -314,21 +316,78 @@ oatpp::Void Deserializer::deserializeUuid(const Deserializer* _this, const InDat
314316

315317
}
316318

319+
// after https://stackoverflow.com/questions/4016412/postgresqls-libpq-encoding-for-binary-transport-of-array-data
320+
struct PgArray {
321+
int32_t ndim; // Number of dimensions
322+
int32_t _ign; // offset for data, removed by libpq
323+
Oid oid; // type of element in the array
324+
325+
// Start of array (1st dimension)
326+
int32_t size; // Number of elements
327+
int32_t index; // Index of first element
328+
int32_t elem; // Beginning of (size, value) elements
329+
};
330+
317331
oatpp::Void Deserializer::deserializeArray(const Deserializer* _this, const InData& data, const Type* type) {
318332

319333
(void) _this;
320334
(void) type;
321335

322-
switch(data.oid) {
323-
case FLOAT4ARRAYOID: return oatpp::Vector<Float32>();
324-
case FLOAT8ARRAYOID: return oatpp::Vector<Float64>();
336+
// Place to put our data
337+
oatpp::Void retval = nullptr;
338+
339+
// see if we handle this type
340+
switch (data.oid) {
341+
case FLOAT8ARRAYOID:
342+
break;
343+
default:
344+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeArray()]: Unhandled array type.");
325345
}
326346

327-
if(data.isNull) {
328-
return oatpp::postgresql::Uuid();
347+
// parse out the array
348+
if (!data.isNull) {
349+
auto *pgArray = reinterpret_cast<const PgArray *>(data.data);
350+
351+
// everything is in network order!!!
352+
// only handle 1d array for now
353+
if (ntohl(pgArray->ndim) > 1) {
354+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeArray()]: Dimension > 1");
355+
}
356+
357+
// make sure data is the right type
358+
if (ntohl(pgArray->oid) == FLOAT8OID) {
359+
// build the array
360+
auto vec = oatpp::Vector<Float64>::createShared();
361+
auto pElem = &pgArray->elem;
362+
auto nElem = ntohl(*pElem);
363+
for (int i = 0; i < nElem; i++) {
364+
// get element size, point to element data
365+
auto elemSize = ntohl(*pElem++);
366+
// quit if we get an empty element
367+
if (elemSize == 0) {
368+
break;
369+
}
370+
// make sure element size matches the data size
371+
if (elemSize != sizeof(v_float64)) {
372+
throw std::runtime_error(
373+
"[oatpp::postgresql::mapping::Deserializer::deserializeArray()]: Bad element size");
374+
}
375+
// get the 64 bit host order data, pointing to next element
376+
// TODO: make sure this matches element size
377+
v_int64 l1 = ntohl(*pElem++);
378+
v_int64 l2 = ntohl(*pElem++);
379+
v_int64 intVal = (l1 << 32) | l2 ;
380+
v_float64 val = *reinterpret_cast<p_float64>(&intVal);
381+
vec->push_back(val);
382+
}
383+
retval = vec;
384+
} else {
385+
throw std::runtime_error(
386+
"[oatpp::postgresql::mapping::Deserializer::deserializeArray()]: Unhandled array value type.");
387+
}
329388
}
330389

331-
return postgresql::Uuid((p_char8)data.data);
390+
return retval;
332391
}
333392

334393
}}}

0 commit comments

Comments
 (0)