1010
1111#include < yql/essentials/minikql/computation/mkql_value_builder.h>
1212#include < yql/essentials/minikql/mkql_string_util.h>
13+ #include < yql/essentials/parser/pg_wrapper/interface/codec.h>
14+ #include < yql/essentials/parser/pg_wrapper/interface/compare.h>
15+ #include < yql/essentials/parser/pg_wrapper/postgresql/src/backend/catalog/pg_type_d.h>
1316#include < yql/essentials/public/udf/arrow/defs.h>
1417#include < yql/essentials/types/binary_json/read.h>
1518#include < yql/essentials/types/binary_json/write.h>
@@ -22,6 +25,7 @@ using namespace NYql;
2225
2326inline static constexpr size_t TEST_ARRAY_DATATYPE_SIZE = 1 << 16 ;
2427inline static constexpr size_t TEST_ARRAY_NESTED_SIZE = 1 << 8 ;
28+ inline static constexpr size_t TEST_ARRAY_PG_SIZE = TEST_ARRAY_DATATYPE_SIZE;
2529inline static constexpr ui8 DECIMAL_PRECISION = 35 ;
2630inline static constexpr ui8 DECIMAL_SCALE = 10 ;
2731inline static constexpr ui32 VARIANT_NESTED_SIZE = 260 ;
@@ -800,6 +804,18 @@ struct TTestContext {
800804 return values;
801805 }
802806
807+ TType* GetOptionalPgValueType (ui32 pgTypeId) {
808+ return TOptionalType::Create (GetPgType (pgTypeId), TypeEnv);
809+ }
810+
811+ TUnboxedValueVector CreateOptionalsPgValue (ui32 quantity, ui32 pgTypeId) {
812+ auto values = CreatePgValues (quantity, pgTypeId);
813+ for (size_t i = 0 ; i < values.size (); ++i) {
814+ values[i] = (i % 2 == 0 ) ? values[i].MakeOptional () : NUdf::TUnboxedValuePod ();
815+ }
816+ return values;
817+ }
818+
803819 TType* GetOptionalOptionalValueType () {
804820 return TOptionalType::Create (GetOptionalDataValueType (), TypeEnv);
805821 }
@@ -1151,6 +1167,37 @@ struct TTestContext {
11511167 }
11521168 return values;
11531169 }
1170+
1171+ TType* GetPgType (ui32 typeId) {
1172+ return TPgType::Create (typeId, TypeEnv);
1173+ }
1174+
1175+ TUnboxedValueVector CreatePgValues (ui32 quantity, ui32 typeId) {
1176+ TUnboxedValueVector values;
1177+ for (ui64 value = 0 ; value < quantity; ++value) {
1178+ if (value % 4 == 3 ) {
1179+ values.emplace_back (NUdf::TUnboxedValuePod ());
1180+ continue ;
1181+ }
1182+
1183+ std::string stringValue;
1184+ switch (typeId) {
1185+ case BOOLOID:
1186+ stringValue = std::to_string (value % 2 == 0 );
1187+ break ;
1188+ case INT8OID:
1189+ stringValue = std::to_string (value);
1190+ break ;
1191+ case TEXTOID:
1192+ stringValue = " text" + std::to_string (value);
1193+ break ;
1194+ default :
1195+ UNIT_ASSERT_C (false , " You need to add a new case for type " << typeId);
1196+ }
1197+ values.emplace_back (NYql::NCommon::PgValueFromNativeText (stringValue, typeId));
1198+ }
1199+ return values;
1200+ }
11541201};
11551202
11561203void AssertUnboxedValuesAreEqual (NUdf::TUnboxedValue& left, NUdf::TUnboxedValue& right, TType* type) {
@@ -1298,6 +1345,13 @@ void AssertUnboxedValuesAreEqual(NUdf::TUnboxedValue& left, NUdf::TUnboxedValue&
12981345 break ;
12991346 }
13001347
1348+ case TType::EKind::Pg: {
1349+ auto pgType = static_cast <const TPgType*>(type);
1350+ auto equate = MakePgEquate (pgType);
1351+ UNIT_ASSERT (equate->Equals (left, right));
1352+ break ;
1353+ }
1354+
13011355 default : {
13021356 UNIT_ASSERT_C (false , TStringBuilder () << " Unsupported type: " << type->GetKindAsStr ());
13031357 }
@@ -1420,6 +1474,48 @@ void TestSingularTypeConversion() {
14201474 }
14211475}
14221476
1477+ template <ui32 PgTypeId>
1478+ void TestPgTypeConversion () {
1479+ TTestContext context;
1480+
1481+ auto pgType = context.GetPgType (PgTypeId);
1482+ auto values = context.CreatePgValues (TEST_ARRAY_PG_SIZE, PgTypeId);
1483+
1484+ UNIT_ASSERT (IsArrowCompatible (pgType));
1485+
1486+ auto array = MakeArrowArray (values, pgType);
1487+ UNIT_ASSERT_C (array->ValidateFull ().ok (), array->ValidateFull ().ToString ());
1488+ UNIT_ASSERT_VALUES_EQUAL (array->length (), values.size ());
1489+
1490+ UNIT_ASSERT (array->type_id () == arrow::Type::STRING);
1491+ auto stringArray = static_pointer_cast<arrow::StringArray>(array);
1492+ UNIT_ASSERT_VALUES_EQUAL (stringArray->length (), values.size ());
1493+
1494+ if (stringArray->length () > 1 ) {
1495+ switch (PgTypeId) {
1496+ case BOOLOID:
1497+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (0 ), " t" );
1498+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (1 ), " f" );
1499+ break ;
1500+ case INT8OID:
1501+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (0 ), " 0" );
1502+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (1 ), " 1" );
1503+ break ;
1504+ case TEXTOID:
1505+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (0 ), " text0" );
1506+ UNIT_ASSERT_VALUES_EQUAL (stringArray->GetString (1 ), " text1" );
1507+ break ;
1508+ default :
1509+ UNIT_ASSERT_C (false , " You need to add a new case for type " << PgTypeId);
1510+ }
1511+ }
1512+
1513+ for (size_t i = 0 ; i < values.size (); ++i) {
1514+ auto arrowValue = ExtractUnboxedValue (array, i, pgType, context.HolderFactory );
1515+ AssertUnboxedValuesAreEqual (arrowValue, values[i], pgType);
1516+ }
1517+ }
1518+
14231519} // namespace
14241520
14251521Y_UNIT_TEST_SUITE (KqpFormats_Arrow_Conversion) {
@@ -2332,6 +2428,29 @@ Y_UNIT_TEST_SUITE(KqpFormats_Arrow_Conversion) {
23322428 }
23332429 }
23342430
2431+ Y_UNIT_TEST (NestedType_Optional_PgValue) {
2432+ TTestContext context;
2433+
2434+ auto optionalType = context.GetOptionalPgValueType (INT8OID);
2435+ auto values = context.CreateOptionalsPgValue (TEST_ARRAY_NESTED_SIZE, INT8OID);
2436+
2437+ UNIT_ASSERT (IsArrowCompatible (optionalType));
2438+
2439+ auto array = MakeArrowArray (values, optionalType);
2440+ UNIT_ASSERT_C (array->ValidateFull ().ok (), array->ValidateFull ().ToString ());
2441+ UNIT_ASSERT_VALUES_EQUAL (array->length (), values.size ());
2442+ UNIT_ASSERT (array->type_id () == arrow::Type::STRUCT);
2443+
2444+ auto structArray = static_pointer_cast<arrow::StructArray>(array);
2445+ UNIT_ASSERT_VALUES_EQUAL (structArray->num_fields (), 1 );
2446+ UNIT_ASSERT (structArray->field (0 )->type_id () == arrow::Type::STRING);
2447+
2448+ for (size_t i = 0 ; i < values.size (); ++i) {
2449+ auto arrowValue = ExtractUnboxedValue (array, i, optionalType, context.HolderFactory );
2450+ AssertUnboxedValuesAreEqual (arrowValue, values[i], optionalType);
2451+ }
2452+ }
2453+
23352454 Y_UNIT_TEST (NestedType_Optional_OptionalValue) {
23362455 TTestContext context;
23372456
@@ -2788,6 +2907,20 @@ Y_UNIT_TEST_SUITE(KqpFormats_Arrow_Conversion) {
27882907 AssertUnboxedValuesAreEqual (arrowValue, values[i], taggedType);
27892908 }
27902909 }
2910+
2911+ // Pg types
2912+ // They are converted using NYql::NCommon::PgValueToNativeText, so testing all types is not required
2913+ Y_UNIT_TEST (PgType_Bool) {
2914+ TestPgTypeConversion<BOOLOID>();
2915+ }
2916+
2917+ Y_UNIT_TEST (PgType_Int8) {
2918+ TestPgTypeConversion<INT8OID>();
2919+ }
2920+
2921+ Y_UNIT_TEST (PgType_Text) {
2922+ TestPgTypeConversion<TEXTOID>();
2923+ }
27912924}
27922925
27932926} // namespace NKikimr::NKqp::NFormats
0 commit comments