Skip to content

Commit c5f81d5

Browse files
authored
Merge pull request #2 from lganzzzo/AddFloatArrays
Add float arrays
2 parents 2b1b204 + f71a962 commit c5f81d5

File tree

5 files changed

+204
-40
lines changed

5 files changed

+204
-40
lines changed

src/oatpp-postgresql/mapping/Deserializer.cpp

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,9 @@ oatpp::Void Deserializer::deserializeEnum(const Deserializer* _this, const InDat
256256

257257
}
258258

259-
const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
259+
const oatpp::Type* Deserializer::guessAnyType(const InData& data) {
260260

261-
switch(oid) {
261+
switch(data.oid) {
262262

263263
case TEXTOID:
264264
case VARCHAROID: return oatpp::String::Class::getType();
@@ -279,20 +279,20 @@ const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
279279
// Arrays
280280

281281
case TEXTARRAYOID:
282-
case VARCHARARRAYOID: return oatpp::Vector<oatpp::String>::Class::getType();
282+
case VARCHARARRAYOID: return generateMultidimensionalArrayType<oatpp::String>(data);
283283

284-
case INT2ARRAYOID: return oatpp::Vector<oatpp::Int16>::Class::getType();
285-
case INT4ARRAYOID: return oatpp::Vector<oatpp::Int32>::Class::getType();
286-
case INT8ARRAYOID: return oatpp::Vector<oatpp::Int64>::Class::getType();
284+
case INT2ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int16>(data);
285+
case INT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int32>(data);
286+
case INT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int64>(data);
287287

288-
case FLOAT4ARRAYOID: return oatpp::Vector<oatpp::Float32>::Class::getType();
289-
case FLOAT8ARRAYOID: return oatpp::Vector<oatpp::Float64>::Class::getType();
288+
case FLOAT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float32>(data);
289+
case FLOAT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float64>(data);
290290

291-
case BOOLARRAYOID: return oatpp::Vector<oatpp::Boolean>::Class::getType();
291+
case BOOLARRAYOID: return generateMultidimensionalArrayType<oatpp::Boolean>(data);
292292

293-
case TIMESTAMPARRAYOID: return oatpp::Vector<oatpp::UInt64>::Class::getType();
293+
case TIMESTAMPARRAYOID: return generateMultidimensionalArrayType<oatpp::UInt64>(data);
294294

295-
case UUIDARRAYOID: return oatpp::Vector<oatpp::postgresql::Uuid>::Class::getType();
295+
case UUIDARRAYOID: return generateMultidimensionalArrayType<oatpp::postgresql::Uuid>(data);
296296

297297
}
298298

@@ -303,7 +303,11 @@ oatpp::Void Deserializer::deserializeAny(const Deserializer* _this, const InData
303303

304304
(void) type;
305305

306-
const Type* valueType = guessAnyType(data.oid);
306+
if(data.isNull) {
307+
return oatpp::Any();
308+
}
309+
310+
const Type* valueType = guessAnyType(data);
307311
if(valueType == nullptr) {
308312
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeAny()]: Error. Unknown OID.");
309313
}
@@ -327,4 +331,25 @@ oatpp::Void Deserializer::deserializeUuid(const Deserializer* _this, const InDat
327331

328332
}
329333

334+
oatpp::Void Deserializer::deserializeSubArray(const Type* type,
335+
ArrayDeserializationMeta& meta,
336+
v_int32 dimension)
337+
{
338+
339+
if(data::mapping::type::__class::AbstractVector::CLASS_ID.id == type->classId.id) {
340+
return deserializeSubArray<oatpp::AbstractVector>(type, meta, dimension);
341+
342+
} else if(data::mapping::type::__class::AbstractList::CLASS_ID.id == type->classId.id) {
343+
return deserializeSubArray<oatpp::AbstractList>(type, meta, dimension);
344+
345+
} else if(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id == type->classId.id) {
346+
return deserializeSubArray<oatpp::AbstractUnorderedSet>(type, meta, dimension);
347+
348+
}
349+
350+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeSubArray()]: "
351+
"Error. Unknown 1D collection type.");
352+
353+
}
354+
330355
}}}

src/oatpp-postgresql/mapping/Deserializer.hpp

Lines changed: 132 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class Deserializer {
6969
static v_int64 deInt8(const InData& data);
7070
static v_int64 deInt(const InData& data);
7171

72-
static const oatpp::Type* guessAnyType(Oid oid);
72+
static const oatpp::Type* guessAnyType(const InData& data);
7373
private:
7474
std::vector<DeserializerMethod> m_methods;
7575
public:
@@ -106,44 +106,151 @@ class Deserializer {
106106

107107
static oatpp::Void deserializeUuid(const Deserializer* _this, const InData& data, const Type* type);
108108

109+
template<typename T>
110+
static const oatpp::Type* generateMultidimensionalArrayType(const InData& data) {
111+
112+
if(data.size < sizeof(v_int32)) {
113+
return nullptr;
114+
}
115+
116+
auto ndim = (v_int32) htonl(*((p_int32)data.data));
117+
118+
switch (ndim) {
119+
120+
case 0: return MultidimensionalArray<T, 1>::getClassType();
121+
case 1: return MultidimensionalArray<T, 1>::getClassType();
122+
case 2: return MultidimensionalArray<T, 2>::getClassType();
123+
case 3: return MultidimensionalArray<T, 3>::getClassType();
124+
case 4: return MultidimensionalArray<T, 4>::getClassType();
125+
case 5: return MultidimensionalArray<T, 5>::getClassType();
126+
case 6: return MultidimensionalArray<T, 6>::getClassType();
127+
case 7: return MultidimensionalArray<T, 7>::getClassType();
128+
case 8: return MultidimensionalArray<T, 8>::getClassType();
129+
case 9: return MultidimensionalArray<T, 9>::getClassType();
130+
case 10: return MultidimensionalArray<T, 10>::getClassType(); // Max 10 dimensions should be enough :)
131+
132+
default:
133+
break;
134+
135+
}
136+
137+
return nullptr;
138+
139+
}
140+
141+
struct ArrayDeserializationMeta {
142+
143+
const Deserializer* _this;
144+
const InData* data;
145+
PgArrayHeader arrayHeader;
146+
p_char8 payload;
147+
std::vector<v_int32> dimensions;
148+
149+
};
150+
151+
static oatpp::Void deserializeSubArray(const Type* type,
152+
ArrayDeserializationMeta& meta,
153+
v_int32 dimension);
154+
155+
template<class Collection>
156+
static oatpp::Void deserializeSubArray(const Type* type,
157+
ArrayDeserializationMeta& meta,
158+
v_int32 dimension)
159+
{
160+
161+
if(dimension < meta.dimensions.size() - 1) {
162+
163+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
164+
auto itemType = *type->params.begin();
165+
auto listWrapper = polymorphicDispatcher->createObject();
166+
167+
auto size = meta.dimensions[dimension];
168+
169+
for(v_int32 i = 0; i < size; i ++) {
170+
const auto& item = deserializeSubArray(itemType, meta, dimension + 1);
171+
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
172+
}
173+
174+
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
175+
176+
} else if(dimension == meta.dimensions.size() - 1) {
177+
178+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
179+
auto itemType = *type->params.begin();
180+
auto listWrapper = polymorphicDispatcher->createObject();
181+
182+
auto size = meta.dimensions[dimension];
183+
184+
for(v_int32 i = 0; i < size; i ++) {
185+
186+
InData itemData;
187+
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));
190+
itemData.oid = meta.arrayHeader.oid;
191+
itemData.isNull = itemData.size < 0;
192+
193+
if(itemData.size > 0) {
194+
meta.payload += sizeof(v_int32) + itemData.size;
195+
} else {
196+
meta.payload += sizeof(v_int32);
197+
}
198+
199+
const auto& item = meta._this->deserialize(itemData, itemType);
200+
201+
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
202+
203+
}
204+
205+
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
206+
207+
}
208+
209+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeSubArray()]: "
210+
"Error. Invalid state: dimension >= dimensions.size().");
211+
212+
}
213+
109214
template<class Collection>
110215
static oatpp::Void deserializeArray2(const Deserializer* _this, const InData& data, const Type* type) {
111216

112217
if(data.isNull) {
113218
return oatpp::Void(nullptr, type);
114219
}
115220

116-
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
117-
auto itemType = *type->params.begin(); // Get "wanted" type of the list item
118-
auto listWrapper = polymorphicDispatcher->createObject(); // Instantiate list of the "wanted" type
221+
auto ndim = (v_int32) htonl(*((p_int32)data.data));
222+
if(ndim == 0) {
223+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
224+
return polymorphicDispatcher->createObject(); // empty array
225+
}
119226

120-
PgArrayHeader* arr = (PgArrayHeader*) data.data;
121-
arr->size = (v_int32) htonl(arr->size);
122-
arr->oid = (v_int32) htonl(arr->oid);
123-
p_char8 payload = (p_char8) &data.data[sizeof(PgArrayHeader)];
227+
ArrayDeserializationMeta meta;
228+
meta._this = _this;
229+
meta.data = &data;
124230

125-
for(v_int32 i = 0; i < arr->size; i ++) {
231+
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);
126236

127-
InData itemData;
128-
itemData.typeResolver = data.typeResolver;
129-
itemData.size = (v_int32)ntohl(*((p_int32) payload));
130-
itemData.data = (const char*) (payload + sizeof(v_int32));
131-
itemData.oid = arr->oid;
132-
itemData.isNull = itemData.size < 0;
237+
meta.dimensions = {meta.arrayHeader.size};
133238

134-
if(itemData.size > 0) {
135-
payload += sizeof(v_int32) + itemData.size;
136-
} else {
137-
payload += sizeof(v_int32);
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 = htonl( * ((p_int32) &data.data[sizeof(PgArrayHeader) + i * sizeof(v_int32) * 2]));
244+
meta.dimensions.push_back(dsize);
138245
}
139-
140-
const auto& item = _this->deserialize(itemData, itemType);
141-
142-
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
143-
246+
meta.payload = (p_char8) &data.data[sizeof(PgArrayHeader) + sizeof(v_int32) * (meta.arrayHeader.ndim - 1) * 2];
144247
}
145248

146-
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
249+
// for(v_int32 d : meta.dimensions) {
250+
// OATPP_LOGD("Array", "D=%d", d);
251+
// }
252+
253+
return deserializeSubArray(type, meta, 0);
147254

148255
}
149256

src/oatpp-postgresql/mapping/PgArray.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,20 @@ struct PgArray {
3232
PgElem elem[]; // Beginning of (size, value) elements
3333
};
3434

35+
template<typename T, int dim>
36+
struct MultidimensionalArray {
37+
38+
typedef oatpp::Vector<typename MultidimensionalArray<T, dim - 1>::type> type;
39+
40+
static const oatpp::Type* getClassType() {
41+
return type::Class::getType();
42+
}
43+
44+
};
45+
46+
template<typename T>
47+
struct MultidimensionalArray<T, 0> {
48+
typedef T type;
49+
};
50+
3551
#endif // oatpp_postgresql_mapping_PgArray_hpp

test/oatpp-postgresql/migration/ArrayTest.sql

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ CREATE TABLE test_arrays1 (
1414
);
1515

1616
CREATE TABLE test_arrays2 (
17-
f_real real[][],
17+
f_real real[][][],
1818
f_double double precision[][],
1919

2020
f_int16 smallint[][],
@@ -48,4 +48,20 @@ VALUES
4848
INSERT INTO test_arrays1
4949
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
5050
VALUES
51-
('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}');
51+
('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}');
52+
53+
54+
INSERT INTO test_arrays2
55+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
56+
VALUES
57+
(null, null, null, null, null, null, null);
58+
59+
INSERT INTO test_arrays2
60+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
61+
VALUES
62+
('{}', '{}', '{}', '{}', '{}', '{}', '{}');
63+
64+
INSERT INTO test_arrays2
65+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
66+
VALUES
67+
('{ {{0, 1}, {10, 11}}, {{0, 1}, {10, 11}} }', '{{0, 1}, {0, 1}}', '{{0, 1}, {0, 1}}', '{{0, 1}, {0, 1}}', '{{0, 1}, {0, 1}}', '{{true, false}, {true, false}}', '{{"Hello_1", "World_1"}, {Hello_2, World_2}}');

test/oatpp-postgresql/types/ArrayTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class MyClient : public oatpp::orm::DbClient {
7878
QUERY(deleteValues,
7979
"DELETE FROM test_floats;")
8080

81-
QUERY(selectValues, "SELECT * FROM test_arrays1;")
81+
QUERY(selectValues, "SELECT * FROM test_arrays2;")
8282

8383
};
8484

0 commit comments

Comments
 (0)