Skip to content

Commit 9e308a6

Browse files
committed
Ser/De. Arrays. Better Ser/De.
1 parent 28af5a2 commit 9e308a6

File tree

6 files changed

+150
-83
lines changed

6 files changed

+150
-83
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ add_library(${OATPP_THIS_MODULE_NAME}
44
oatpp-postgresql/mapping/type/Uuid.hpp
55
oatpp-postgresql/mapping/Deserializer.cpp
66
oatpp-postgresql/mapping/Deserializer.hpp
7-
oatpp-postgresql/mapping/PgArray.hpp
87
oatpp-postgresql/mapping/Oid.hpp
8+
oatpp-postgresql/mapping/PgArray.cpp
9+
oatpp-postgresql/mapping/PgArray.hpp
910
oatpp-postgresql/mapping/ResultMapper.cpp
1011
oatpp-postgresql/mapping/ResultMapper.hpp
1112
oatpp-postgresql/mapping/Serializer.cpp

src/oatpp-postgresql/mapping/Deserializer.hpp

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "PgArray.hpp"
2929

30+
#include "oatpp/core/data/stream/BufferStream.hpp"
3031
#include "oatpp/core/data/mapping/TypeResolver.hpp"
3132
#include "oatpp/core/Types.hpp"
3233

@@ -140,10 +141,19 @@ class Deserializer {
140141

141142
struct ArrayDeserializationMeta {
142143

144+
ArrayDeserializationMeta(const Deserializer* p_this,
145+
const InData* pData)
146+
: _this(p_this)
147+
, data(pData)
148+
, stream(nullptr, (p_char8)pData->data, pData->size)
149+
{
150+
ArrayUtils::readArrayHeader(&stream, arrayHeader, dimensions);
151+
}
152+
143153
const Deserializer* _this;
144154
const InData* data;
155+
data::stream::BufferInputStream stream;
145156
PgArrayHeader arrayHeader;
146-
p_char8 payload;
147157
std::vector<v_int32> dimensions;
148158

149159
};
@@ -183,17 +193,18 @@ class Deserializer {
183193

184194
for(v_int32 i = 0; i < size; i ++) {
185195

196+
v_int32 dataSize;
197+
meta.stream.readSimple(&dataSize, sizeof(v_int32));
198+
186199
InData itemData;
187200
itemData.typeResolver = meta.data->typeResolver;
188-
itemData.size = (v_int32)ntohl(*((p_int32) meta.payload));
189-
itemData.data = (const char*) (meta.payload + sizeof(v_int32));
201+
itemData.size = (v_int32) ntohl(dataSize);
202+
itemData.data = (const char*) &meta.stream.getData()[meta.stream.getCurrentPosition()];
190203
itemData.oid = meta.arrayHeader.oid;
191204
itemData.isNull = itemData.size < 0;
192205

193206
if(itemData.size > 0) {
194-
meta.payload += sizeof(v_int32) + itemData.size;
195-
} else {
196-
meta.payload += sizeof(v_int32);
207+
meta.stream.setCurrentPosition(meta.stream.getCurrentPosition() + itemData.size);
197208
}
198209

199210
const auto& item = meta._this->deserialize(itemData, itemType);
@@ -224,28 +235,7 @@ class Deserializer {
224235
return polymorphicDispatcher->createObject(); // empty array
225236
}
226237

227-
ArrayDeserializationMeta meta;
228-
meta._this = _this;
229-
meta.data = &data;
230-
231-
meta.arrayHeader = *((PgArrayHeader*) data.data);
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);
236-
237-
meta.dimensions = {meta.arrayHeader.size};
238-
239-
if(meta.arrayHeader.ndim == 1) {
240-
meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader)];
241-
} else {
242-
for(v_int32 i = 0; i < meta.arrayHeader.ndim - 1; i ++) {
243-
v_int32 dsize = ntohl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2]));
244-
meta.dimensions.push_back(dsize);
245-
}
246-
meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader) + sizeof(v_int32) * (meta.arrayHeader.ndim - 1) * 2];
247-
}
248-
238+
ArrayDeserializationMeta meta(_this, &data);
249239
return deserializeSubArray(type, meta, 0);
250240

251241
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/***************************************************************************
2+
*
3+
* Project _____ __ ____ _ _
4+
* ( _ ) /__\ (_ _)_| |_ _| |_
5+
* )(_)( /(__)\ )( (_ _)(_ _)
6+
* (_____)(__)(__)(__) |_| |_|
7+
*
8+
*
9+
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*
23+
***************************************************************************/
24+
25+
#include "PgArray.hpp"
26+
27+
#if defined(WIN32) || defined(_WIN32)
28+
#include <WinSock2.h>
29+
#else
30+
#include <arpa/inet.h>
31+
#endif
32+
33+
namespace oatpp { namespace postgresql { namespace mapping {
34+
35+
void ArrayUtils::writeArrayHeader(data::stream::ConsistentOutputStream* stream, Oid itemOid, const std::vector<v_int32>& dimensions) {
36+
37+
// num dimensions
38+
v_int32 v = htonl(dimensions.size());
39+
stream->writeSimple(&v, sizeof(v_int32));
40+
41+
// ignore
42+
v = 0;
43+
stream->writeSimple(&v, sizeof(v_int32));
44+
45+
// oid
46+
v = htonl(itemOid);
47+
stream->writeSimple(&v, sizeof(v_int32));
48+
49+
// size
50+
v = htonl(dimensions[0]);
51+
stream->writeSimple(&v, sizeof(v_int32));
52+
53+
// index
54+
v = htonl(1);
55+
stream->writeSimple(&v, sizeof(v_int32));
56+
57+
for(v_uint32 i = 1; i < dimensions.size(); i++) {
58+
v_int32 size = htonl(dimensions[i]);
59+
v_int32 index = htonl(1);
60+
stream->writeSimple(&size, sizeof(v_int32));
61+
stream->writeSimple(&index, sizeof(v_int32));
62+
}
63+
64+
}
65+
66+
void ArrayUtils::readArrayHeader(data::stream::InputStream* stream,
67+
PgArrayHeader& arrayHeader,
68+
std::vector<v_int32>& dimensions)
69+
{
70+
71+
// num dimensions
72+
v_int32 v;
73+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
74+
arrayHeader.ndim = ntohl(v);
75+
76+
// ignore
77+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
78+
79+
// oid
80+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
81+
arrayHeader.oid = ntohl(v);
82+
83+
// size
84+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
85+
arrayHeader.size = ntohl(v);
86+
87+
// index // ignore
88+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
89+
90+
dimensions.push_back(arrayHeader.size);
91+
92+
for(v_uint32 i = 1; i < arrayHeader.ndim; i++) {
93+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
94+
dimensions.push_back(ntohl(v));
95+
96+
// index // ignore
97+
stream->readExactSizeDataSimple(&v, sizeof(v_int32));
98+
}
99+
100+
}
101+
102+
}}}

src/oatpp-postgresql/mapping/PgArray.hpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,32 @@
55
#ifndef oatpp_postgresql_mapping_PgArray_hpp
66
#define oatpp_postgresql_mapping_PgArray_hpp
77

8+
#include "oatpp/core/data/stream/Stream.hpp"
89
#include "oatpp/core/Types.hpp"
910

1011
#include <libpq-fe.h>
1112

12-
struct PgElem {
13-
v_int32 size; // size of each element value (bytes)
14-
v_uint8 value[]; // Beginning of value array -- dynamically sized
15-
};
13+
namespace oatpp { namespace postgresql { namespace mapping {
1614

1715
// after https://stackoverflow.com/questions/4016412/postgresqls-libpq-encoding-for-binary-transport-of-array-data
1816
struct PgArrayHeader {
19-
PgArrayHeader() : ndim(0), _ign(0), oid(InvalidOid), size(0), index(0) {};
20-
v_int32 ndim; // Number of dimensions
21-
v_int32 _ign; // offset for data, removed by libpq
22-
Oid oid; // type of element in the array
23-
24-
// Start of array (1st dimension)
25-
v_int32 size; // Number of elements
26-
v_int32 index; // Index of first element
27-
};
2817

29-
// Layout of Postgres array in memory
30-
struct PgArray {
31-
PgArrayHeader header;
32-
PgElem elem[]; // Beginning of (size, value) elements
18+
v_int32 ndim = 0; // Number of dimensions
19+
//v_int32 _ign; // offset for data, removed by libpq
20+
Oid oid = InvalidOid; // type of element in the array
21+
22+
// Start of array (1st dimension)
23+
v_int32 size = 0; // Number of elements
24+
// v_int32 index; // Index of first element
25+
3326
};
3427

3528
template<typename T, int dim>
3629
struct MultidimensionalArray {
3730

3831
typedef oatpp::Vector<typename MultidimensionalArray<T, dim - 1>::type> type;
3932

40-
static const oatpp::Type* getClassType() {
33+
static const oatpp::Type *getClassType() {
4134
return type::Class::getType();
4235
}
4336

@@ -48,4 +41,19 @@ struct MultidimensionalArray<T, 0> {
4841
typedef T type;
4942
};
5043

44+
class ArrayUtils {
45+
public:
46+
47+
static void writeArrayHeader(data::stream::ConsistentOutputStream* stream,
48+
Oid itemOid,
49+
const std::vector<v_int32>& dimensions);
50+
51+
static void readArrayHeader(data::stream::InputStream* stream,
52+
PgArrayHeader& arrayHeader,
53+
std::vector<v_int32>& dimensions);
54+
55+
};
56+
57+
}}}
58+
5159
#endif // oatpp_postgresql_mapping_PgArray_hpp

src/oatpp-postgresql/mapping/Serializer.cpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -508,40 +508,6 @@ const oatpp::Type* Serializer::getArrayItemTypeAndDimensions(const oatpp::Void&
508508

509509
}
510510

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-
545511
void Serializer::serializeSubArray(data::stream::ConsistentOutputStream* stream,
546512
const oatpp::Void& polymorph,
547513
ArraySerializationMeta& meta,

src/oatpp-postgresql/mapping/Serializer.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#ifndef oatpp_postgresql_mapping_Serializer_hpp
2626
#define oatpp_postgresql_mapping_Serializer_hpp
2727

28+
#include "PgArray.hpp"
2829
#include "oatpp/core/data/stream/BufferStream.hpp"
2930
#include "oatpp/core/Types.hpp"
3031

@@ -117,7 +118,6 @@ class Serializer {
117118
};
118119

119120
static const oatpp::Type* getArrayItemTypeAndDimensions(const oatpp::Void& polymorph, std::vector<v_int32>& dimensions);
120-
static void writeArrayHeader(data::stream::ConsistentOutputStream* stream, Oid itemOid, const std::vector<v_int32>& dimensions);
121121

122122
static void serializeSubArray(data::stream::ConsistentOutputStream* stream,
123123
const oatpp::Void& polymorph,
@@ -194,7 +194,7 @@ class Serializer {
194194
}
195195

196196
data::stream::BufferOutputStream stream;
197-
writeArrayHeader(&stream, _this->getTypeOid(itemType), meta.dimensions);
197+
ArrayUtils::writeArrayHeader(&stream, _this->getTypeOid(itemType), meta.dimensions);
198198

199199
serializeSubArray(&stream, polymorph, meta, 0);
200200

0 commit comments

Comments
 (0)