From 256be007b7ee1e4bfabe04d3b78145fe0e2b08c9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 25 Oct 2023 15:42:03 +0200 Subject: [PATCH] Arrow/Parquet: add support for reading list (or map) of struct (relates to #8606) --- autotest/generate_parquet_test_file.py | 276 +++++++- autotest/ogr/data/arrow/test.feather | Bin 30226 -> 39954 bytes autotest/ogr/data/parquet/all_geoms.parquet | Bin 3390 -> 3391 bytes .../ogr/data/parquet/nested_types.parquet | Bin 44529 -> 57854 bytes autotest/ogr/data/parquet/test.parquet | Bin 59272 -> 72316 bytes .../data/parquet/test_single_group.parquet | Bin 38974 -> 47515 bytes autotest/ogr/ogr_parquet.py | 113 ++- .../arrow_common/ograrrowlayer.hpp | 647 +++++++++++------- 8 files changed, 762 insertions(+), 274 deletions(-) diff --git a/autotest/generate_parquet_test_file.py b/autotest/generate_parquet_test_file.py index 2768254d2c26..6ea918fe4451 100644 --- a/autotest/generate_parquet_test_file.py +++ b/autotest/generate_parquet_test_file.py @@ -56,6 +56,7 @@ def generate_test_parquet(): import pathlib import struct + import numpy as np import pandas as pd import pyarrow as pa import pyarrow.parquet as pq @@ -280,16 +281,51 @@ def generate_test_parquet(): ], type=pa.list_(pa.float64()), ) + list_decimal128 = pa.array( + [ + [decimal.Decimal("1234.567")], + [decimal.Decimal("-1234.567")], + None, + [None], + [decimal.Decimal("-1234.567")], + ], + type=pa.list_(pa.decimal128(7, 3)), + ) + list_decimal256 = pa.array( + [ + [decimal.Decimal("1234.567")], + [decimal.Decimal("-1234.567")], + None, + [None], + [decimal.Decimal("-1234.567")], + ], + type=pa.list_(pa.decimal256(7, 3)), + ) list_string = pa.array( [ None if i == 2 + else [None] + if i == 4 else [ "".join(["%c" % (65 + j + k) for k in range(1 + j)]) for j in range(i) ] for i in range(5) ] ) + list_large_string = pa.array( + [ + None + if i == 2 + else [None] + if i == 4 + else [ + "".join(["%c" % (65 + j + k) for k in range(1 + j)]) for j in range(i) + ] + for i in range(5) + ], + type=pa.list_(pa.large_string()), + ) fixed_size_list_boolean = pa.array( [[True, False], [False, True], [True, False], [False, True], [True, False]], type=pa.list_(pa.bool_(), 2), @@ -332,6 +368,8 @@ def generate_test_parquet(): [{"a": 1, "b": 2.5, "c": {"d": "e", "f": "g"}, "h": [5, 6], "i": 3}] * 5 ) + list_struct = pa.array([[{"a": 1, "b": 2.5}, {"a": 3, "c": 4.5}]] * 5) + # struct_val = { "a": 5 } # for i in range(123): # struct_val = { "a": struct_val } @@ -387,10 +425,52 @@ def generate_test_parquet(): [[("x", 1.5), ("y", None)], [("z", 3)], None, [], []], type=pa.map_(pa.string(), pa.float64()), ) + map_decimal128 = pa.array( + [ + [("x", decimal.Decimal("1234.567")), ("y", None)], + [("z", decimal.Decimal("-1234.567"))], + None, + [], + [], + ], + type=pa.map_(pa.string(), pa.decimal128(7, 3)), + ) + map_decimal256 = pa.array( + [ + [("x", decimal.Decimal("1234.567")), ("y", None)], + [("z", decimal.Decimal("-1234.567"))], + None, + [], + [], + ], + type=pa.map_(pa.string(), pa.decimal256(7, 3)), + ) map_string = pa.array( [[("x", "x_val"), ("y", None)], [("z", "z_val")], None, [], []], type=pa.map_(pa.string(), pa.string()), ) + map_large_string = pa.array( + [[("x", "x_val"), ("y", None)], [("z", "z_val")], None, [], []], + type=pa.map_(pa.string(), pa.large_string()), + ) + map_list_string = pa.array( + [[("x", ["x_val"]), ("y", None)], [("z", [None, "z_val"])], None, [], []], + type=pa.map_(pa.string(), pa.list_(pa.string())), + ) + map_large_list_string = pa.array( + [[("x", ["x_val"]), ("y", None)], [("z", [None, "z_val"])], None, [], []], + type=pa.map_(pa.string(), pa.large_list(pa.string())), + ) + map_fixed_size_list_string = pa.array( + [ + [("x", ["x_val", None]), ("y", [None, None])], + [("z", [None, "z_val"])], + None, + [], + [], + ], + type=pa.map_(pa.string(), pa.list_(pa.string(), 2)), + ) indices = pa.array([0, 1, 2, None, 2], type=pa.int32()) dictionary = pa.array(["foo", "bar", "baz"]) @@ -453,7 +533,10 @@ def generate_test_parquet(): "list_int64", "list_float32", "list_float64", + "list_decimal128", + "list_decimal256", "list_string", + "list_large_string", "fixed_size_list_boolean", "fixed_size_list_uint8", "fixed_size_list_int8", @@ -467,6 +550,7 @@ def generate_test_parquet(): "fixed_size_list_float64", "fixed_size_list_string", "struct_field", + "list_struct", "map_boolean", "map_uint8", "map_int8", @@ -478,8 +562,13 @@ def generate_test_parquet(): "map_int64", "map_float32", "map_float64", + "map_decimal128", + "map_decimal256", "map_string", - # "map_list", + "map_large_string", + "map_list_string", + "map_large_list_string", + "map_fixed_size_list_string", "dict", "geometry", ] @@ -523,6 +612,61 @@ def generate_test_parquet(): import pyarrow.feather as feather + float16 = pa.array( + [None if i == 2 else np.float16(1.5 + i) for i in range(5)], type=pa.float16() + ) + list_float16 = pa.array( + [ + None + if i == 2 + else [ + None if j == 0 else np.float16(0.5 + j + i * (i - 1) // 2) + for j in range(i) + ] + for i in range(5) + ], + type=pa.list_(pa.float16()), + ) + map_float16 = pa.array( + [[("x", np.float16(1.5)), ("y", None)], [("z", np.float16(3))], None, [], []], + type=pa.map_(pa.string(), pa.float16()), + ) + list_list_float16 = pa.array( + [ + None + if i == 2 + else [ + None if j == 0 else [np.float16(0.5 + j + i * (i - 1) // 2)] + for j in range(i) + ] + for i in range(5) + ], + type=pa.list_(pa.list_(pa.float16())), + ) + names += ["float16", "list_float16", "list_list_float16", "map_float16"] + locals_ = locals() + table = pa.table([locals_[x] for x in names], names=names) + + my_schema = table.schema.with_metadata( + { + "geo": json.dumps( + { + "version": "0.1.0", + "primary_column": "geometry", + "columns": { + "geometry": { + "crs": wkt_epsg_4326, + "bbox": [0, 2, 4, 2], + "encoding": "WKB", + } + }, + } + ) + } + ) + + table = table.cast(my_schema) + feather.write_feather(table, HERE / "ogr/data/arrow/test.feather") @@ -620,8 +764,10 @@ def generate_parquet_wkt_with_dict(): def generate_nested_types(): + import decimal import pathlib + import numpy as np import pyarrow as pa import pyarrow.parquet as pq @@ -818,11 +964,122 @@ def generate_nested_types(): type=pa.map_(pa.string(), pa.map_(pa.string(), pa.string())), ) + list_list_bool = pa.array( + [[[True], None, [False, None, True]], None, [[False]], [], []], + type=pa.list_(pa.list_(pa.bool_())), + ) + + list_list_uint8 = pa.array( + [[[1], None, [2, None, 3]], None, [[4]], [], []], + type=pa.list_(pa.list_(pa.uint8())), + ) + + list_list_int8 = pa.array( + [[[1], None, [-2, None, 3]], None, [[-4]], [], []], + type=pa.list_(pa.list_(pa.int8())), + ) + + list_list_uint16 = pa.array( + [[[1], None, [2, None, 3]], None, [[4]], [], []], + type=pa.list_(pa.list_(pa.uint16())), + ) + + list_list_int16 = pa.array( + [[[1], None, [-2, None, 3]], None, [[-4]], [], []], + type=pa.list_(pa.list_(pa.int16())), + ) + + list_list_uint32 = pa.array( + [[[1], None, [2, None, 3]], None, [[4]], [], []], + type=pa.list_(pa.list_(pa.uint32())), + ) + + list_list_int32 = pa.array( + [[[1], None, [-2, None, 3]], None, [[-4]], [], []], + type=pa.list_(pa.list_(pa.int32())), + ) + + list_list_uint64 = pa.array( + [[[1], None, [2, None, 3]], None, [[4]], [], []], + type=pa.list_(pa.list_(pa.uint64())), + ) + + list_list_int64 = pa.array( + [[[1], None, [-2, None, 3]], None, [[-4]], [], []], + type=pa.list_(pa.list_(pa.int64())), + ) + + list_list_float16 = pa.array( + [ + [[np.float16(1.5)], None, [np.float16(2.5), None, np.float16(3.5)]], + None, + [[np.float16(4.5)]], + [], + [], + ], + type=pa.list_(pa.list_(pa.float16())), + ) + + list_list_float32 = pa.array( + [[[1.5], None, [-2.5, None, 3.5]], None, [[-4.5]], [], []], + type=pa.list_(pa.list_(pa.float32())), + ) + + list_list_float64 = pa.array( + [[[1.5], None, [-2.5, None, 3.5]], None, [[-4.5]], [], []], + type=pa.list_(pa.list_(pa.float64())), + ) + + list_list_decimal128 = pa.array( + [ + [ + [decimal.Decimal("1234.567")], + None, + [decimal.Decimal("-1234.567"), None, decimal.Decimal("1234.567")], + ], + None, + [[decimal.Decimal("-1234.567")]], + [], + [], + ], + type=pa.list_(pa.list_(pa.decimal128(7, 3))), + ) + + list_list_decimal256 = pa.array( + [ + [ + [decimal.Decimal("1234.567")], + None, + [decimal.Decimal("-1234.567"), None, decimal.Decimal("1234.567")], + ], + None, + [[decimal.Decimal("-1234.567")]], + [], + [], + ], + type=pa.list_(pa.list_(pa.decimal256(7, 3))), + ) + list_list_string = pa.array( [[["a"], None, ["b", None, "cd"]], None, [["efg"]], [], []], type=pa.list_(pa.list_(pa.string())), ) + list_list_large_string = pa.array( + [[["a"], None, ["b", None, "cd"]], None, [["efg"]], [], []], + type=pa.list_(pa.list_(pa.large_string())), + ) + + list_large_list_string = pa.array( + [[["a"], None, ["b", None, "cd"]], None, [["efg"]], [], []], + type=pa.list_(pa.large_list(pa.string())), + ) + + list_fixed_size_list_string = pa.array( + [[["a", "b"]], None, [["e", "f"]], [["g", "h"]], [["i", "j"]]], + type=pa.list_(pa.list_(pa.string(), 2)), + ) + list_map_string = pa.array( [[[("a", "b"), ("c", "d")], [("e", "f")]], None, [None], [], []], type=pa.list_(pa.map_(pa.string(), pa.string())), @@ -852,7 +1109,24 @@ def generate_nested_types(): "map_map_float32", "map_map_float64", "map_map_string", + "list_list_bool", + "list_list_uint8", + "list_list_int8", + "list_list_uint16", + "list_list_int16", + "list_list_uint32", + "list_list_int32", + "list_list_uint64", + "list_list_int64", + # "list_list_float16", + "list_list_float32", + "list_list_float64", + "list_list_decimal128", + "list_list_decimal256", "list_list_string", + "list_list_large_string", + "list_large_list_string", + "list_fixed_size_list_string", "list_map_string", ] diff --git a/autotest/ogr/data/arrow/test.feather b/autotest/ogr/data/arrow/test.feather index b4e222f8c6eaccd4fd6227ce27dd58b209bfb7a4..04c167e762a748ad020285c1e24baf4afba7a926 100644 GIT binary patch literal 39954 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 delta 5660 zcmeHLQA}Is75;7Pi|rW4P^TC}jB8SG*hUF3#MUTt8pu$_QZKDEq-hb=B8^s2#-ylX zY80C+EKbH2!l}A!$^+8+z(d5CU=vT1EA@egiV=wiRH2DYRYIr%laY!^ZM^TlJ||&U z@%tV)(z*Bl&iT&yziVIr_xBx}wU1?OzT;=ky#B)@O66gh@Gajld)tFQpFUfX>{3c? zhm@LvUxatU{qU74rS8Hn!Movp_)1Wz8F&ib3}2~KY6Si!JP2QYQK<>|AUqCt!Iuu8 z4?G3$f&1YL0j1LLSU@G!+zU#bgFE2k6)1!+mt$gh5I*BqDgoc#k0N*w{-IB)Hh88C zIry?ysq^riec-@@@Vg$I-AeVkz%NxQYbezLPdSzP#GzCG-d9os#db8eVPg0wK8;Q| za;o`0h2N{UAG%K`-#b;ldOx2>&=$er62>!hZ>X9QeivmtF6UiDy!3;iO1g77K+9M5 zQOUl8hT}m#e{P2+ePL$|!#=v_tEQ>2gW^M8d+!4}J=A2Rk;putv(BjJ!b3fUT?PJQ zmMkITr=k6Yk{n80tMmjV9jp2Lz^YjiUehHu^>LvjjZ6k5^`-4?&^fzGlUJIIRYW5X z>9Q|sPd_B%myO0z%yjV~JsGYyH1Rx!z9!=iqKhWaZJ=))9b#1OuQjqr99pBW@8#0g z7DQ{-XmWp((F4-eHM4Jajo!K1=p096iM|?cpv+Z=u>jQkC2e>co$B*^zJorxR%d_b za|#dFI}-?`>8)#Zbbi=nq<~hwq|?4e=M;vkCNq(x`Qb*VBb(13rSi1?u)UNicNlGm zy#JN%Yn;RIPS%t#pQUg`y>kYUtVy5ymEZXpP$%8GR!IqOzzD48^F8Y(duE;HD;kY{ zM8?zzP)RAT*VD3*&*T14Z|3z^Vgvyb8#MVsqrH2Bj-{K7 zK}4oD$QOv($2aJMbc?ZwhVIN9PjT-v1Yji_-Rp$|7{ zBNX*{bI-DioAmCDdSgx(&xJwsfss4df_% zAY8V%tJNJUAE~BPRe%OcU7mj-gS%ZV=jb1$QR5Rp#}-XiwwB>GIE5}c*||kNBkFnd zh?{CcyXUW*ohoF{{#$2lYI%z;kF>j^AnV#1Di76_T{TM!SK33zL#-6~jl(_0oDt1& z{|zXPidni>)#5X6t0zp@F`M+6GbmdGB;1BK^;OikFCeNX>Zc(z`2zfVIqUl|Lz z+@ErKQKx-Jx3x%R!|I_N+q5y#;yco=)G36`3q>dt^}GwH83Wri8N!8fcFN59f{zP5 z^j)yBP2uWxPd!4qKJwVCKLe<CjZ&|st|ap=P8zgRm%j$@OQXH3{RNd_FQ}p3@PZh6coey$)at_!Y_t9X{))G zB1inmZx;$xuf9=tnPB;{201UvW-a_;_=NPt16P}TH?abK_F;3Nz`{{*Jx3DUKnQ{x zIgqmCi{V$8KV|YUzy3XFTd*_`ECmYN2W`TSFfK&#qh&1oge5OnZl09RKf8YHAGkoS zc!DwZL#AaIA7-3m%up4>4NM4PAEXU?Fw;7Kzo|zuL4pZ_`z<)d_%PjTt)-P#e^Od6 zaYkD2SStP4lWCKDGh>;lo3UKlAmc(6_I=OCNhJctnIIEn7|R4pmi&$-uQ!j{L_nNz zA&Ld_xfoX|0{WQ{qOG>taP+AR#xjlG$L_XbSY~NvzFcO4vGngR;G_}(X$xVT zu?SdTEFy|w5wOF25ui8c+C)IJiE&rg72>MbLKt8y0>&9LT@}M3V2=4BVAay!RHA=X zA|S@nL}8ocD#WXrd<7F0LWZ#j$Vn#_Pz;NJ zV0D2gWgUz~KqAQj`2-A^1G-p zo9Q$2&^z^eOfvoVAN|5H-ThX|O)Ee93BCIBzfkOAq^lQ9y=BzXYbi^$IKcFK0c~+v zyD--Ig|Lp|FS&WdI|F^D>lYjLUNqn%+X4IUR(^1|!j{{o+( B@a_Nr diff --git a/autotest/ogr/data/parquet/all_geoms.parquet b/autotest/ogr/data/parquet/all_geoms.parquet index 297e3f15754ac1948f5eabcb2d34d14a32b76816..b9731a068014d2171a622f853491cbcbe1b389a9 100644 GIT binary patch delta 105 zcmdldwO>jwz%j^Bltpw47ZCY~@`*BR6kN{4C@^^^Q!SAE!Q9HvAj-rb${;ELq!<`P sStg%m)`7@yz+^VJvUGDWDohsSl@c*D)HBdCkd%=DD$e6%U;vp90L_yW=l}o! delta 104 zcmdllwNFYgz%j^Bltpw47ZCY~@`KzuZ7wGR1ITy)tx^<- diff --git a/autotest/ogr/data/parquet/nested_types.parquet b/autotest/ogr/data/parquet/nested_types.parquet index b3ba80887c6b39db83b9b60fb2afddbdf10c5ffa..ab0ad5fd4233bd4438ee91483dc1bfa6b4f5ea04 100644 GIT binary patch literal 57854 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 diff --git a/autotest/ogr/data/parquet/test.parquet b/autotest/ogr/data/parquet/test.parquet index b1322fdafa8c8042101ebf2ff0b49e0f6a1fdbac..342d6d45b558f4a9aa76c536bf0a8df0353c0f23 100644 GIT binary patch delta 16104 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 delta 8822 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 IB99CEKja7dZ~y=R diff --git a/autotest/ogr/data/parquet/test_single_group.parquet b/autotest/ogr/data/parquet/test_single_group.parquet index d8536c302b92c3d0f421d4a8bbeb6daff5f78a18..ab3389767511ee757cf576b956eef59e5ad01673 100644 GIT binary patch delta 9294 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 delta 4421 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 zkO8JWOS|(valueType))) || - (itemTypeId == arrow::Type::LIST && + ((itemTypeId == arrow::Type::LIST || + itemTypeId == arrow::Type::LARGE_LIST || + itemTypeId == arrow::Type::FIXED_SIZE_LIST) && IsHandledListType( std::static_pointer_cast(valueType))); } @@ -355,9 +362,12 @@ inline bool OGRArrowLayer::MapArrowTypeToOGR( eSubType = OFSTFloat32; break; case arrow::Type::DOUBLE: + case arrow::Type::DECIMAL128: + case arrow::Type::DECIMAL256: eType = OFTRealList; break; case arrow::Type::STRING: + case arrow::Type::LARGE_STRING: eType = OFTStringList; break; default: @@ -910,153 +920,382 @@ OGRArrowLayer::GetGeometryTypeFromString(const std::string &osType) return eGeomType; } +static CPLJSONObject GetObjectAsJSON(const arrow::Array *array, + const size_t nIdx); + /************************************************************************/ -/* ReadList() */ +/* AddToArray() */ /************************************************************************/ -static CPLJSONObject ReadMap(const arrow::MapArray *array, int64_t nIdxInArray); +static void AddToArray(CPLJSONArray &oArray, const arrow::Array *array, + const size_t nIdx) +{ + switch (array->type()->id()) + { + case arrow::Type::BOOL: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::UINT8: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::INT8: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::UINT16: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::INT16: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::INT32: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::UINT32: + { + oArray.Add(static_cast( + static_cast(array)->Value(nIdx))); + break; + } + case arrow::Type::INT64: + { + oArray.Add(static_cast( + static_cast(array)->Value(nIdx))); + break; + } + case arrow::Type::UINT64: + { + oArray.Add(static_cast( + static_cast(array)->Value(nIdx))); + break; + } + case arrow::Type::HALF_FLOAT: + { + const uint16_t nFloat16 = + static_cast(array)->Value(nIdx); + uint32_t nFloat32 = CPLHalfToFloat(nFloat16); + float f; + memcpy(&f, &nFloat32, sizeof(nFloat32)); + oArray.Add(f); + break; + } + case arrow::Type::FLOAT: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::DOUBLE: + { + oArray.Add( + static_cast(array)->Value(nIdx)); + break; + } + case arrow::Type::DECIMAL128: + case arrow::Type::DECIMAL256: + { + oArray.Add(CPLAtof(static_cast(array) + ->FormatValue(nIdx) + .c_str())); + break; + } + case arrow::Type::STRING: + { + oArray.Add( + static_cast(array)->GetString( + nIdx)); + break; + } + case arrow::Type::LARGE_STRING: + { + oArray.Add( + static_cast(array)->GetString( + nIdx)); + break; + } + case arrow::Type::LIST: + case arrow::Type::LARGE_LIST: + case arrow::Type::FIXED_SIZE_LIST: + case arrow::Type::MAP: + case arrow::Type::STRUCT: + { + oArray.Add(GetObjectAsJSON(array, nIdx)); + break; + } -template -static CPLJSONArray ReadList(const ArrayType *array, int64_t nIdxInArray) + default: + { + CPLDebug("ARROW", "AddToArray(): unexpected data type %s", + array->type()->ToString().c_str()); + break; + } + } +} + +/************************************************************************/ +/* GetListAsJSON() */ +/************************************************************************/ + +template +static CPLJSONObject GetListAsJSON(const ArrowType *array, + const size_t nIdxInArray) { const auto values = std::static_pointer_cast(array->values()); const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); + const auto nCount = array->value_length(nIdxInArray); CPLJSONArray oArray; - for (int k = 0; k < nCount; k++) + for (auto k = decltype(nCount){0}; k < nCount; k++) { if (values->IsNull(nIdxStart + k)) oArray.AddNull(); else - oArray.Add(static_cast(values->Value(nIdxStart + k))); + AddToArray(oArray, values.get(), nIdxStart + k); } return oArray; } -template -static CPLJSONArray ReadList(const ArrayType *array, int64_t nIdxInArray) +/************************************************************************/ +/* AddToDict() */ +/************************************************************************/ + +static void AddToDict(CPLJSONObject &oDict, const std::string &osKey, + const arrow::Array *array, const size_t nIdx) { - switch (array->value_type()->id()) + switch (array->type()->id()) { case arrow::Type::BOOL: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::UINT8: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::INT8: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::UINT16: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::INT16: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::INT32: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::UINT32: { - return ReadList(array, nIdxInArray); + oDict.Add(osKey, + static_cast( + static_cast(array)->Value( + nIdx))); + break; } case arrow::Type::INT64: { - return ReadList(array, nIdxInArray); + oDict.Add(osKey, + static_cast( + static_cast(array)->Value( + nIdx))); + break; } case arrow::Type::UINT64: { - return ReadList(array, nIdxInArray); + oDict.Add(osKey, + static_cast( + static_cast(array)->Value( + nIdx))); + break; } case arrow::Type::HALF_FLOAT: { - return ReadList(array, nIdxInArray); + const uint16_t nFloat16 = + static_cast(array)->Value(nIdx); + uint32_t nFloat32 = CPLHalfToFloat(nFloat16); + float f; + memcpy(&f, &nFloat32, sizeof(nFloat32)); + oDict.Add(osKey, f); + break; } case arrow::Type::FLOAT: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } case arrow::Type::DOUBLE: { - return ReadList(array, nIdxInArray); + oDict.Add( + osKey, + static_cast(array)->Value(nIdx)); + break; } - case arrow::Type::STRING: + case arrow::Type::DECIMAL128: + case arrow::Type::DECIMAL256: { - CPLJSONArray oArray; - const auto values = - std::static_pointer_cast(array->values()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - for (int k = 0; k < nCount; k++) - { - if (values->IsNull(nIdxStart + k)) - { - oArray.AddNull(); - } - else - { - oArray.Add(values->GetString(nIdxStart + k)); - } - } - return oArray; + oDict.Add(osKey, + CPLAtof(static_cast(array) + ->FormatValue(nIdx) + .c_str())); + break; } - case arrow::Type::LIST: + case arrow::Type::STRING: { - CPLJSONArray oArray; - const auto values = - std::static_pointer_cast(array->values()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - for (int k = 0; k < nCount; k++) - { - if (values->IsNull(nIdxStart + k)) - { - oArray.AddNull(); - } - else - { - oArray.Add(ReadList(values.get(), nIdxStart + k)); - } - } - return oArray; + oDict.Add(osKey, + static_cast(array)->GetString( + nIdx)); + break; } - + case arrow::Type::LARGE_STRING: + { + oDict.Add(osKey, static_cast(array) + ->GetString(nIdx)); + break; + } + case arrow::Type::LIST: + case arrow::Type::LARGE_LIST: + case arrow::Type::FIXED_SIZE_LIST: case arrow::Type::MAP: + case arrow::Type::STRUCT: { - CPLJSONArray oArray; - const auto values = - std::static_pointer_cast(array->values()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - for (int k = 0; k < nCount; k++) - { - if (values->IsNull(nIdxStart + k)) - { - oArray.AddNull(); - } - else - { - oArray.Add(ReadMap(values.get(), nIdxStart + k)); - } - } - return oArray; + oDict.Add(osKey, GetObjectAsJSON(array, nIdx)); + break; } default: { - CPLDebug("ARROW", "ReadList(): unexpected data type %s", - array->values()->type()->ToString().c_str()); + CPLDebug("ARROW", "AddToDict(): unexpected data type %s", + array->type()->ToString().c_str()); break; } } - return CPLJSONArray(); +} + +/************************************************************************/ +/* GetMapAsJSON() */ +/************************************************************************/ + +static CPLJSONObject GetMapAsJSON(const arrow::Array *array, + const size_t nIdxInArray) +{ + const auto mapArray = static_cast(array); + const auto keys = + std::static_pointer_cast(mapArray->keys()); + const auto values = mapArray->items(); + const auto nIdxStart = mapArray->value_offset(nIdxInArray); + const int nCount = mapArray->value_length(nIdxInArray); + CPLJSONObject oRoot; + for (int k = 0; k < nCount; k++) + { + if (!keys->IsNull(nIdxStart + k)) + { + const auto osKey = keys->GetString(nIdxStart + k); + if (!values->IsNull(nIdxStart + k)) + AddToDict(oRoot, osKey, values.get(), nIdxStart + k); + else + oRoot.AddNull(osKey); + } + } + return oRoot; +} + +/************************************************************************/ +/* GetStructureAsJSON() */ +/************************************************************************/ + +static CPLJSONObject GetStructureAsJSON(const arrow::Array *array, + const size_t nIdxInArray) +{ + CPLJSONObject oRoot; + const auto structArray = static_cast(array); + const auto structArrayType = structArray->type(); + for (int i = 0; i < structArrayType->num_fields(); ++i) + { + const auto field = structArray->field(i); + if (!field->IsNull(nIdxInArray)) + { + AddToDict(oRoot, structArrayType->field(i)->name(), field.get(), + nIdxInArray); + } + else + oRoot.AddNull(structArrayType->field(i)->name()); + } + + return oRoot; +} + +/************************************************************************/ +/* GetObjectAsJSON() */ +/************************************************************************/ + +static CPLJSONObject GetObjectAsJSON(const arrow::Array *array, + const size_t nIdxInArray) +{ + switch (array->type()->id()) + { + case arrow::Type::MAP: + return GetMapAsJSON(array, nIdxInArray); + case arrow::Type::LIST: + return GetListAsJSON(static_cast(array), + nIdxInArray); + case arrow::Type::LARGE_LIST: + return GetListAsJSON( + static_cast(array), nIdxInArray); + case arrow::Type::FIXED_SIZE_LIST: + return GetListAsJSON( + static_cast(array), + nIdxInArray); + case arrow::Type::STRUCT: + return GetStructureAsJSON(array, nIdxInArray); + default: + { + CPLError(CE_Failure, CPLE_AppDefined, + "GetObjectAsJSON(): unhandled value format: %s", + array->type()->ToString().c_str()); + return CPLJSONObject(); + } + } } template @@ -1152,8 +1391,26 @@ static void ReadList(OGRFeature *poFeature, int i, int64_t nIdxInArray, } case arrow::Type::HALF_FLOAT: { - ReadListDouble(poFeature, i, nIdxInArray, - array); + const auto values = std::static_pointer_cast( + array->values()); + const auto nIdxStart = array->value_offset(nIdxInArray); + const int nCount = array->value_length(nIdxInArray); + std::vector aValues; + aValues.reserve(nCount); + for (int k = 0; k < nCount; k++) + { + if (values->IsNull(nIdxStart + k)) + aValues.push_back(std::numeric_limits::quiet_NaN()); + else + { + const uint16_t nFloat16 = values->Value(nIdxStart + k); + uint32_t nFloat32 = CPLHalfToFloat(nFloat16); + float f; + memcpy(&f, &nFloat32, sizeof(nFloat32)); + aValues.push_back(f); + } + } + poFeature->SetField(i, nCount, aValues.data()); break; } case arrow::Type::FLOAT: @@ -1167,6 +1424,26 @@ static void ReadList(OGRFeature *poFeature, int i, int64_t nIdxInArray, array); break; } + case arrow::Type::DECIMAL128: + case arrow::Type::DECIMAL256: + { + const auto values = + std::static_pointer_cast(array->values()); + const auto nIdxStart = array->value_offset(nIdxInArray); + const int nCount = array->value_length(nIdxInArray); + std::vector aValues; + aValues.reserve(nCount); + for (int k = 0; k < nCount; k++) + { + if (values->IsNull(nIdxStart + k)) + aValues.push_back(std::numeric_limits::quiet_NaN()); + else + aValues.push_back( + CPLAtof(values->FormatValue(nIdxStart + k).c_str())); + } + poFeature->SetField(i, nCount, aValues.data()); + break; + } case arrow::Type::STRING: { const auto values = @@ -1185,12 +1462,33 @@ static void ReadList(OGRFeature *poFeature, int i, int64_t nIdxInArray, poFeature->SetField(i, aosList.List()); break; } - + case arrow::Type::LARGE_STRING: + { + const auto values = + std::static_pointer_cast( + array->values()); + const auto nIdxStart = array->value_offset(nIdxInArray); + const auto nCount = array->value_length(nIdxInArray); + CPLStringList aosList; + for (auto k = decltype(nCount){0}; k < nCount; k++) + { + if (values->IsNull(nIdxStart + k)) + aosList.AddString( + ""); // we cannot have null strings in a list + else + aosList.AddString(values->GetString(nIdxStart + k).c_str()); + } + poFeature->SetField(i, aosList.List()); + break; + } case arrow::Type::LIST: + case arrow::Type::LARGE_LIST: + case arrow::Type::FIXED_SIZE_LIST: case arrow::Type::MAP: + case arrow::Type::STRUCT: { poFeature->SetField(i, - ReadList(array, nIdxInArray) + GetListAsJSON(array, nIdxInArray) .Format(CPLJSONObject::PrettyFormat::Plain) .c_str()); break; @@ -1205,160 +1503,6 @@ static void ReadList(OGRFeature *poFeature, int i, int64_t nIdxInArray, } } -/************************************************************************/ -/* ReadMap() */ -/************************************************************************/ - -template -static CPLJSONObject ReadMap(const arrow::MapArray *array, int64_t nIdxInArray) -{ - const auto keys = - std::static_pointer_cast(array->keys()); - const auto values = std::static_pointer_cast(array->items()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - CPLJSONObject oRoot; - for (int k = 0; k < nCount; k++) - { - if (!keys->IsNull(nIdxStart + k)) - { - const auto osKey = keys->GetString(nIdxStart + k); - if (!values->IsNull(nIdxStart + k)) - oRoot.Add(osKey, - static_cast(values->Value(nIdxStart + k))); - else - oRoot.AddNull(osKey); - } - } - return oRoot; -} - -static CPLJSONObject ReadMap(const arrow::MapArray *array, int64_t nIdxInArray) -{ - const auto mapType = - static_cast(array->data()->type.get()); - const auto itemTypeId = mapType->item_type()->id(); - if (mapType->key_type()->id() == arrow::Type::STRING) - { - if (itemTypeId == arrow::Type::BOOL) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::UINT8) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::INT8) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::UINT16) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::INT16) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::UINT32) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::INT32) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::UINT64) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::INT64) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::FLOAT) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::DOUBLE) - { - return ReadMap(array, nIdxInArray); - } - else if (itemTypeId == arrow::Type::STRING) - { - const auto keys = - std::static_pointer_cast(array->keys()); - const auto values = - std::static_pointer_cast(array->items()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - CPLJSONObject oRoot; - for (int k = 0; k < nCount; k++) - { - if (!keys->IsNull(nIdxStart + k)) - { - const auto osKey = keys->GetString(nIdxStart + k); - if (!values->IsNull(nIdxStart + k)) - oRoot.Add(osKey, values->GetString(nIdxStart + k)); - else - oRoot.AddNull(osKey); - } - } - return oRoot; - } - else if (itemTypeId == arrow::Type::LIST) - { - const auto keys = - std::static_pointer_cast(array->keys()); - const auto values = - std::static_pointer_cast(array->items()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - CPLJSONObject oRoot; - for (int k = 0; k < nCount; k++) - { - if (!keys->IsNull(nIdxStart + k)) - { - const auto osKey = keys->GetString(nIdxStart + k); - if (!values->IsNull(nIdxStart + k)) - oRoot.Add(osKey, ReadList(values.get(), nIdxStart + k)); - else - oRoot.AddNull(osKey); - } - } - return oRoot; - } - else if (itemTypeId == arrow::Type::MAP) - { - const auto keys = - std::static_pointer_cast(array->keys()); - const auto values = - std::static_pointer_cast(array->items()); - const auto nIdxStart = array->value_offset(nIdxInArray); - const int nCount = array->value_length(nIdxInArray); - CPLJSONObject oRoot; - for (int k = 0; k < nCount; k++) - { - if (!keys->IsNull(nIdxStart + k)) - { - const auto osKey = keys->GetString(nIdxStart + k); - if (!values->IsNull(nIdxStart + k)) - oRoot.Add(osKey, ReadMap(values.get(), nIdxStart + k)); - else - oRoot.AddNull(osKey); - } - } - return oRoot; - } - else - { - CPLDebug("ARROW", "ReadMap(): unexpected data type %s", - array->items()->type()->ToString().c_str()); - } - } - return CPLJSONObject(); -} - /************************************************************************/ /* SetPointsOfLine() */ /************************************************************************/ @@ -1636,8 +1780,11 @@ inline OGRFeature *OGRArrowLayer::ReadFeature( { const auto castArray = static_cast(array); - poFeature->SetFieldSameTypeUnsafe( - i, castArray->Value(nIdxInBatch)); + const uint16_t nFloat16 = castArray->Value(nIdxInBatch); + uint32_t nFloat32 = CPLHalfToFloat(nFloat16); + float f; + memcpy(&f, &nFloat32, sizeof(nFloat32)); + poFeature->SetFieldSameTypeUnsafe(i, f); break; } case arrow::Type::FLOAT: @@ -1763,18 +1910,10 @@ inline OGRFeature *OGRArrowLayer::ReadFeature( } case arrow::Type::DECIMAL128: - { - const auto castArray = - static_cast(array); - poFeature->SetField( - i, CPLAtof(castArray->FormatValue(nIdxInBatch).c_str())); - break; - } - case arrow::Type::DECIMAL256: { const auto castArray = - static_cast(array); + static_cast(array); poFeature->SetField( i, CPLAtof(castArray->FormatValue(nIdxInBatch).c_str())); break; @@ -1838,7 +1977,7 @@ inline OGRFeature *OGRArrowLayer::ReadFeature( const auto castArray = static_cast(array); poFeature->SetField( - i, ReadMap(castArray, nIdxInBatch) + i, GetMapAsJSON(castArray, nIdxInBatch) .Format(CPLJSONObject::PrettyFormat::Plain) .c_str()); break; @@ -2911,9 +3050,11 @@ inline bool OGRArrowLayer::SkipToNextFeatureDueToAttributeFilter() const { const auto castArray = static_cast(array); - if (!ConstraintEvaluator( - constraint, - static_cast(castArray->Value(m_nIdxInBatch)))) + const uint16_t nFloat16 = castArray->Value(m_nIdxInBatch); + uint32_t nFloat32 = CPLHalfToFloat(nFloat16); + float f; + memcpy(&f, &nFloat32, sizeof(nFloat32)); + if (!ConstraintEvaluator(constraint, static_cast(f))) { return true; }