aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormonster <monster@ydb.tech>2022-12-07 17:04:29 +0300
committermonster <monster@ydb.tech>2022-12-07 17:04:29 +0300
commit37030c245fe253ac59f915e72acb74d5e677cca0 (patch)
treef25d4f235103a29ba8030b738d56436d685a88ab
parent16d51715c1fec430a7c77ae6f569a202dc1ae12e (diff)
downloadydb-37030c245fe253ac59f915e72acb74d5e677cca0.tar.gz
pg array types support; more tests
-rw-r--r--ydb/core/kqp/ut/pg/kqp_pg_ut.cpp430
-rw-r--r--ydb/core/scheme/scheme_types_defs.h2
-rw-r--r--ydb/library/yql/parser/pg_wrapper/comp_factory.cpp217
-rw-r--r--ydb/library/yql/parser/pg_wrapper/interface/type_desc.h6
-rw-r--r--ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp2
5 files changed, 472 insertions, 185 deletions
diff --git a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
index a2a1dd6d31a..ef4192ffe17 100644
--- a/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
+++ b/ydb/core/kqp/ut/pg/kqp_pg_ut.cpp
@@ -1,5 +1,7 @@
#include <ydb/core/kqp/ut/common/kqp_ut_common.h>
+#include <ydb/library/yql/parser/pg_catalog/catalog.h>
+
extern "C" {
#include "postgres.h"
#include "catalog/pg_type_d.h"
@@ -17,147 +19,301 @@ Y_UNIT_TEST_SUITE(KqpPg) {
Y_UNIT_TEST(CreateTableBulkUpsertAndRead) {
TKikimrRunner kikimr;
- auto db = kikimr.GetTableClient();
- auto session = db.CreateSession().GetValueSync().GetSession();
-
- auto builder = TTableBuilder()
- .AddNullableColumn("boolean", makePgType(BOOLOID))
- .AddNullableColumn("char", makePgType(CHAROID))
- .AddNullableColumn("int2", makePgType(INT2OID))
- .AddNullableColumn("int4", makePgType(INT4OID))
- .AddNullableColumn("int8", makePgType(INT8OID))
- .AddNullableColumn("float4", makePgType(FLOAT4OID))
- .AddNullableColumn("float8", makePgType(FLOAT8OID))
- .AddNullableColumn("text", makePgType(TEXTOID))
- .AddNullableColumn("bytea", makePgType(BYTEAOID))
- .AddNullableColumn("bpchar", makePgType(BPCHAROID))
- .AddNullableColumn("varchar", makePgType(VARCHAROID))
- .SetPrimaryKeyColumn("int2")
- .SetPrimaryKeyColumn("int4")
- .SetPrimaryKeyColumn("int8")
- .SetPrimaryKeyColumn("float4")
- .SetPrimaryKeyColumn("float8")
- .SetPrimaryKeyColumn("text")
- .SetPrimaryKeyColumn("bytea")
- .SetPrimaryKeyColumn("bpchar");
-
- auto result = session.CreateTable("/Root/Pg", builder.Build()).GetValueSync();
- UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
-
- NYdb::TValueBuilder rows;
- rows.BeginList();
- for (size_t i = 0; i < 10; ++i) {
- auto boolVal = true;
- TString boolStr((const char*)&boolVal, sizeof(boolVal));
- auto charVal = (char)i;
- TString charStr((const char*)&charVal, sizeof(charVal));
- auto int2Val = (i16)i;
- TString int2Str((const char*)&int2Val, sizeof(int2Val));
- auto int4Val = (i32)i;
- TString int4Str((const char*)&int4Val, sizeof(int4Val));
- auto int8Val = (i64)i;
- TString int8Str((const char*)&int8Val, sizeof(int8Val));
- auto float4Val = (float)i;
- TString float4Str((const char*)&float4Val, sizeof(float4Val));
- auto float8Val = (double)i;
- TString float8Str((const char*)&float8Val, sizeof(float8Val));
- TString textStr = Sprintf("text %" PRIu64, i);
- TString byteaStr = Sprintf("bytea %" PRIu64, i);
- TString bpcharStr = Sprintf("bpchar %" PRIu64, i);
- TString varcharStr = Sprintf("varchar %" PRIu64, i);
-
- rows.AddListItem()
- .BeginStruct()
- .AddMember("boolean").Pg(TPgValue(TPgValue::VK_BINARY, boolStr, makePgType(BOOLOID)))
- .AddMember("char").Pg(TPgValue(TPgValue::VK_BINARY, charStr, makePgType(CHAROID)))
- .AddMember("int2").Pg(TPgValue(TPgValue::VK_BINARY, int2Str, makePgType(INT2OID)))
- .AddMember("int4").Pg(TPgValue(TPgValue::VK_BINARY, int4Str, makePgType(INT4OID)))
- .AddMember("int8").Pg(TPgValue(TPgValue::VK_BINARY, int8Str, makePgType(INT8OID)))
- .AddMember("float4").Pg(TPgValue(TPgValue::VK_BINARY, float4Str, makePgType(FLOAT4OID)))
- .AddMember("float8").Pg(TPgValue(TPgValue::VK_BINARY, float8Str, makePgType(FLOAT8OID)))
- .AddMember("text").Pg(TPgValue(TPgValue::VK_BINARY, textStr, makePgType(TEXTOID)))
- .AddMember("bytea").Pg(TPgValue(TPgValue::VK_BINARY, byteaStr, makePgType(BYTEAOID)))
- .AddMember("bpchar").Pg(TPgValue(TPgValue::VK_BINARY, bpcharStr, makePgType(BPCHAROID)))
- .AddMember("varchar").Pg(TPgValue(TPgValue::VK_BINARY, varcharStr, makePgType(VARCHAROID)))
- .EndStruct();
- }
- rows.EndList();
-
- result = db.BulkUpsert("/Root/Pg", rows.Build()).GetValueSync();
- UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
-
- session.Close().GetValueSync();
-
- auto readSettings = TReadTableSettings()
- .AppendColumns("boolean")
- .AppendColumns("char")
- .AppendColumns("int2")
- .AppendColumns("int4")
- .AppendColumns("int8")
- .AppendColumns("float4")
- .AppendColumns("float8")
- .AppendColumns("text")
- .AppendColumns("bytea")
- .AppendColumns("bpchar")
- .AppendColumns("varchar");
-
- auto it = session.ReadTable("/Root/Pg", readSettings).GetValueSync();
- UNIT_ASSERT_C(it.IsSuccess(), result.GetIssues().ToString());
-
- bool eos = false;
- while (!eos) {
- auto part = it.ReadNext().ExtractValueSync();
- if (!part.IsSuccess()) {
- eos = true;
- UNIT_ASSERT_C(part.EOS(), result.GetIssues().ToString());
- continue;
+
+ auto testSingleType = [&kikimr] (ui32 id, bool isKey,
+ std::function<TString(size_t)> binaryIn,
+ std::function<TString(size_t)> textOut)
+ {
+ auto db = kikimr.GetTableClient();
+ auto session = db.CreateSession().GetValueSync().GetSession();
+
+ TTableBuilder builder;
+ if (isKey) {
+ builder.AddNullableColumn("key", makePgType(id));
+ } else {
+ builder.AddNullableColumn("key", makePgType(INT2OID));
+ }
+ builder.AddNullableColumn("value", makePgType(id));
+ builder.SetPrimaryKeyColumn("key");
+
+ auto tableName = Sprintf("/Root/Pg%u", id);
+ auto result = session.CreateTable(tableName, builder.Build()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ NYdb::TValueBuilder rows;
+ rows.BeginList();
+ for (size_t i = 0; i < 10; ++i) {
+ auto str = binaryIn(i);
+ if (isKey) {
+ rows.AddListItem()
+ .BeginStruct()
+ .AddMember("key").Pg(TPgValue(TPgValue::VK_BINARY, str, makePgType(id)))
+ .AddMember("value").Pg(TPgValue(TPgValue::VK_BINARY, str, makePgType(id)))
+ .EndStruct();
+ } else {
+ auto int2Val = (i16)i;
+ TString int2Str((const char*)&int2Val, sizeof(int2Val));
+ rows.AddListItem()
+ .BeginStruct()
+ .AddMember("key").Pg(TPgValue(TPgValue::VK_BINARY, int2Str, makePgType(INT2OID)))
+ .AddMember("value").Pg(TPgValue(TPgValue::VK_BINARY, str, makePgType(id)))
+ .EndStruct();
+ }
}
- auto resultSet = part.ExtractPart();
- TResultSetParser parser(resultSet);
- for (size_t i = 0; parser.TryNextRow(); ++i) {
- auto boolVal = true;
- TString boolStr((const char*)&boolVal, sizeof(boolVal));
- auto charVal = (char)i;
- TString charStr((const char*)&charVal, sizeof(charVal));
- auto int2Val = (i16)i;
- TString int2Str((const char*)&int2Val, sizeof(int2Val));
- auto int4Val = (i32)i;
- TString int4Str((const char*)&int4Val, sizeof(int4Val));
- auto int8Val = (i64)i;
- TString int8Str((const char*)&int8Val, sizeof(int8Val));
- auto float4Val = (float)i;
- TString float4Str((const char*)&float4Val, sizeof(float4Val));
- auto float8Val = (double)i;
- TString float8Str((const char*)&float8Val, sizeof(float8Val));
- TString textStr = Sprintf("text %" PRIu64, i);
- TString byteaStr = Sprintf("bytea %" PRIu64, i);
- TString bpcharStr = Sprintf("bpchar %" PRIu64, i);
- TString varcharStr = Sprintf("varchar %" PRIu64, i);
-
-#define COLUMN(type, valStr) \
- { \
- auto& column = parser.ColumnParser(type); \
- column.OpenOptional(); \
- UNIT_ASSERT_VALUES_EQUAL(valStr, column.GetPg().Content_); \
- column.CloseOptional(); \
+ rows.EndList();
+
+ result = db.BulkUpsert(tableName, rows.Build()).GetValueSync();
+ UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
+
+ auto readSettings = TReadTableSettings()
+ .AppendColumns("key")
+ .AppendColumns("value");
+
+ auto it = session.ReadTable(tableName, readSettings).GetValueSync();
+ UNIT_ASSERT_C(it.IsSuccess(), result.GetIssues().ToString());
+
+ bool eos = false;
+ while (!eos) {
+ auto part = it.ReadNext().ExtractValueSync();
+ if (!part.IsSuccess()) {
+ eos = true;
+ UNIT_ASSERT_C(part.EOS(), result.GetIssues().ToString());
+ continue;
+ }
+ auto resultSet = part.ExtractPart();
+ TResultSetParser parser(resultSet);
+ for (size_t i = 0; parser.TryNextRow(); ++i) {
+ auto check = [&parser, &id] (const TString& column, const TString& expected) {
+ auto& c = parser.ColumnParser(column);
+ c.OpenOptional();
+ UNIT_ASSERT_VALUES_EQUAL(expected, NPg::PgNativeTextFromNativeBinary(c.GetPg().Content_, id));
+ Cerr << expected << Endl;
+ c.CloseOptional();
+ };
+ auto expected = textOut(i);
+ if (isKey) {
+ check("key", expected);
+ }
+ check("value", expected);
}
- COLUMN("boolean", boolStr);
- COLUMN("char", charStr);
- COLUMN("int2", int2Str);
- COLUMN("int4", int4Str);
- COLUMN("int8", int8Str);
- COLUMN("float4", float4Str);
- COLUMN("float8", float8Str);
- COLUMN("text", textStr);
- COLUMN("bytea", byteaStr);
- COLUMN("bpchar", bpcharStr);
- COLUMN("varchar", varcharStr);
-#undef COLUMN
}
- }
- }
- Y_UNIT_TEST(EmptyQuery) {
+ session.Close().GetValueSync();
+ };
+
+ auto testType = [&] (ui32 id, bool isKey,
+ std::function<TString(size_t)> binaryIn,
+ std::function<TString(size_t)> textOut,
+ std::function<TString(TString)> arrayPrint = [] (auto s) { return Sprintf("{%s,%s}", s.c_str(), s.c_str()); })
+ {
+ testSingleType(id, isKey, binaryIn, textOut);
+
+ auto arrayId = NYql::NPg::LookupType(id).ArrayTypeId;
+
+ auto binaryInArray = [&] (auto i) {
+ auto binary = binaryIn(i);
+ auto str = NPg::PgNativeTextFromNativeBinary(binary, id);
+ auto arrayStr = arrayPrint(str);
+ return NPg::PgNativeBinaryFromNativeText(arrayStr, arrayId);
+ };
+ auto textOutArray = [&] (auto i) {
+ auto str = textOut(i);
+ return arrayPrint(str);
+ };
+
+ testSingleType(arrayId, false, binaryInArray, textOutArray);
+ };
+
+ auto testByteaType = [&] () {
+ testSingleType(BYTEAOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("bytea %u", i), BYTEAOID); },
+ [] (auto i) { return Sprintf("\\x627974656120%x", i + 48); });
+
+ testSingleType(BYTEAARRAYOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("{a%u, b%u}", i, i + 10), BYTEAARRAYOID); },
+ [] (auto i) { return Sprintf("{\"\\\\x61%x\",\"\\\\x6231%x\"}", i + 48, i + 48); });
+ };
+
+ testType(BOOLOID, true,
+ [] (auto i) { auto val = (bool)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return TString(i ? "t" : "f"); });
+
+ testType(CHAROID, true,
+ [] (auto i) { auto val = (char)(i + '0'); return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%c", (char)(i + '0')); });
+
+ testType(INT2OID, true,
+ [] (auto i) { auto val = (i16)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%u", i); });
+
+ testType(INT4OID, true,
+ [] (auto i) { auto val = (i32)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%u", i); });
+
+ testType(INT8OID, true,
+ [] (auto i) { auto val = (i64)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%u", i); });
+
+ testType(FLOAT4OID, true,
+ [] (auto i) { auto val = (float)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%g", (float)i); });
+
+ testType(FLOAT8OID, true,
+ [] (auto i) { auto val = (double)i; return TString((const char*)&val, sizeof(val)); },
+ [] (auto i) { return Sprintf("%lg", (double)i); });
+
+ testByteaType();
+
+ testType(TEXTOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("text %u", i), TEXTOID); },
+ [] (auto i) { return Sprintf("text %u", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(BPCHAROID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("bpchar %u", i), BPCHAROID); },
+ [] (auto i) { return Sprintf("bpchar %u", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(VARCHAROID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("varchar %u", i), VARCHAROID); },
+ [] (auto i) { return Sprintf("varchar %u", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(NAMEOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("name %u", i), NAMEOID); },
+ [] (auto i) { return Sprintf("name %u", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(NUMERICOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%lg", i + 0.12345), NUMERICOID); },
+ [] (auto i) { return Sprintf("%lg", i + 0.12345); });
+
+// testType(DATEOID, true,
+// [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("1970-01-%02u", i + 1), DATEOID); },
+// [] (auto i) { return Sprintf("1970-01-%02u", i + 1); });
+
+// testType(TIMEOID, true,
+// [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%02u:01:02.345", i), TIMEOID); },
+// [] (auto i) { return ""; });
+
+// testType(TIMESTAMPOID, true,
+// [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("1970-01-01 %02u:01:02.345", i), TIMESTAMPOID); },
+// [] (auto i) { return ""; });
+
+ testType(TIMETZOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%02u:01:02.345-03", i), TIMETZOID); },
+ [] (auto i) { return Sprintf("%02u:01:02.345-03", i); });
+
+// testType(TIMESTAMPTZOID, true,
+// [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("1970-01-01 %02u:01:02.345 -3:00", i), TIMESTAMPTZOID); },
+// [] (auto i) { return ""; });
+
+ testType(INTERVALOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("P01-02-03T04:05:%02u", i), INTERVALOID); },
+ [] (auto i) { return Sprintf("1 year 2 mons 3 days 04:05:%02u", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(BITOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'), BITOID); },
+ [] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); });
+
+ testType(VARBITOID, true,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'), VARBITOID); },
+ [] (auto i) { return Sprintf("%c%c%c%c", (i&8)?'1':'0', (i&4)?'1':'0', (i&2)?'1':'0', (i&1)?'1':'0'); });
+
+ testType(POINTOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("(10, %u)", i), POINTOID); },
+ [] (auto i) { return Sprintf("(10,%u)", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(LINEOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("{1, 2, %u}", i), LINEOID); },
+ [] (auto i) { return Sprintf("{1,2,%u}", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(LSEGOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("[(0, 0), (1, %u)]", i), LSEGOID); },
+ [] (auto i) { return Sprintf("[(0,0),(1,%u)]", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(BOXOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("(1, %u), (0, 0)", i + 1), BOXOID); },
+ [] (auto i) { return Sprintf("(1,%u),(0,0)", i + 1); },
+ [] (auto s) { return Sprintf("{%s;%s}", s.c_str(), s.c_str()); });
+
+ testType(PATHOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("((0, 1), (2, 3), (4, %u))", i), PATHOID); },
+ [] (auto i) { return Sprintf("((0,1),(2,3),(4,%u))", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(POLYGONOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("((0, 1), (2, 3), (4, %u))", i), POLYGONOID); },
+ [] (auto i) { return Sprintf("((0,1),(2,3),(4,%u))", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(CIRCLEOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("<(0, 1), %u>", i), CIRCLEOID); },
+ [] (auto i) { return Sprintf("<(0,1),%u>", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(INETOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("128.%u.0.0/16", i), INETOID); },
+ [] (auto i) { return Sprintf("128.%u.0.0/16", i); });
+
+ testType(CIDROID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("128.%u.0.0/16", i), CIDROID); },
+ [] (auto i) { return Sprintf("128.%u.0.0/16", i); });
+
+ testType(MACADDROID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("08:00:2b:01:02:%02u", i), MACADDROID); },
+ [] (auto i) { return Sprintf("08:00:2b:01:02:%02u", i); });
+
+ testType(MACADDR8OID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("08:00:2b:01:02:03:04:%02u", i), MACADDR8OID); },
+ [] (auto i) { return Sprintf("08:00:2b:01:02:03:04:%02u", i); });
+
+ testType(UUIDOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("00000000-0000-0000-0000-0000000000%02u", i), UUIDOID); },
+ [] (auto i) { return Sprintf("00000000-0000-0000-0000-0000000000%02u", i); });
+
+ testType(JSONOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("[%u]", i), JSONOID); },
+ [] (auto i) { return Sprintf("[%u]", i); });
+
+ testType(JSONBOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("[%u]", i), JSONBOID); },
+ [] (auto i) { return Sprintf("[%u]", i); });
+
+ testType(JSONPATHOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("$[%u]", i), JSONPATHOID); },
+ [] (auto i) { return Sprintf("$[%u]", i); });
+
+ testType(XMLOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("<a>%u</a>", i), XMLOID); },
+ [] (auto i) { return Sprintf("<a>%u</a>", i); });
+
+ testType(TSQUERYOID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("a&b%u", i), TSQUERYOID); },
+ [] (auto i) { return Sprintf("'a' & 'b%u'", i); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(TSVECTOROID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("a:1 b:%u", i + 2), TSVECTOROID); },
+ [] (auto i) { return Sprintf("'a':1 'b':%u", i + 2); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ testType(INT2VECTOROID, false,
+ [] (auto i) { return NPg::PgNativeBinaryFromNativeText(Sprintf("%u %u %u", i, i + 1, i + 2), INT2VECTOROID); },
+ [] (auto i) { return Sprintf("%u %u %u", i, i + 1, i + 2); },
+ [] (auto s) { return Sprintf("{\"%s\",\"%s\"}", s.c_str(), s.c_str()); });
+
+ // TODO: varchar as a key
+ // TODO: date/time types (?)
+ // TODO: money (uses PGLC_localeconv())
+ // TODO: native range/multirange types (use get_range_io_data())
+ }
+
+ Y_UNIT_TEST(EmptyQuery) {
auto kikimr = DefaultKikimrRunner();
NYdb::NScripting::TScriptingClient client(kikimr.GetDriver());
diff --git a/ydb/core/scheme/scheme_types_defs.h b/ydb/core/scheme/scheme_types_defs.h
index 9e51f936fd9..7e3e604f71d 100644
--- a/ydb/core/scheme/scheme_types_defs.h
+++ b/ydb/core/scheme/scheme_types_defs.h
@@ -60,7 +60,7 @@ inline ui32 GetFixedSize(TTypeInfo typeInfo) {
KIKIMR_FOREACH_TYPE(KIKIMR_TYPE_MACRO)
#undef KIKIMR_TYPE_MACRO
case NTypeIds::Pg:
- return NPg::TypeDescGetTypeLen(typeInfo.GetTypeDesc());
+ return NPg::TypeDescGetStoredSize(typeInfo.GetTypeDesc());
default:
return 0;
}
diff --git a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
index e0b4d7e2efa..741eecedcb7 100644
--- a/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
+++ b/ydb/library/yql/parser/pg_wrapper/comp_factory.cpp
@@ -2936,55 +2936,74 @@ public:
explicit TPgTypeDescriptor(const NYql::NPg::TTypeDesc& desc)
: NYql::NPg::TTypeDesc(desc)
{
- // TODO: btarraycmp and hash_array for array types
- if (CompareProcId) {
- InitFunc(CompareProcId, &CompareProcInfo, 2, 2);
- }
- if (HashProcId) {
- InitFunc(HashProcId, &HashProcInfo, 1, 1);
- }
- if (ReceiveFuncId) {
- InitFunc(ReceiveFuncId, &ReceiveFuncInfo, 1, 3);
- }
- if (SendFuncId) {
- InitFunc(SendFuncId, &SendFuncInfo, 1, 1);
+ if (TypeId == ArrayTypeId) {
+ const auto& typeDesc = NYql::NPg::LookupType(ElementTypeId);
+ if (typeDesc.CompareProcId) {
+ CompareProcId = NYql::NPg::LookupProc("btarraycmp", { 0, 0 }).ProcId;
+ }
+ if (typeDesc.HashProcId) {
+ HashProcId = NYql::NPg::LookupProc("hash_array", { 0 }).ProcId;
+ }
+ if (typeDesc.ReceiveFuncId) {
+ ReceiveFuncId = NYql::NPg::LookupProc("array_recv", { 0, 0, 0 }).ProcId;
+ }
+ if (typeDesc.SendFuncId) {
+ SendFuncId = NYql::NPg::LookupProc("array_send", { 0 }).ProcId;
+ }
+ if (typeDesc.InFuncId) {
+ InFuncId = NYql::NPg::LookupProc("array_in", { 0, 0, 0 }).ProcId;
+ }
+ if (typeDesc.OutFuncId) {
+ OutFuncId = NYql::NPg::LookupProc("array_out", { 0 }).ProcId;
+ }
+ } else {
+ StoredSize = TypeLen < 0 ? 0 : TypeLen;
+ if (TypeId == NAMEOID) {
+ StoredSize = 0; // store 'name' as usual string
+ }
}
}
int Compare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR) const {
NMiniKQL::TScopedAlloc alloc(__LOCATION__);
NMiniKQL::TPAllocScope scope;
+ Datum datumL = 0, datumR = 0;
+ Y_DEFER {
+ if (!PassByValue) {
+ if (datumL)
+ pfree((void*)datumL);
+ if (datumR)
+ pfree((void*)datumR);
+ }
+ };
PG_TRY();
{
- Datum datumL, datumR;
if (PassByValue) {
datumL = ScalarDatumFromData(dataL, sizeL);
datumR = ScalarDatumFromData(dataR, sizeR);
} else {
- datumL = Unpack(dataL, sizeL);
- datumR = Unpack(dataR, sizeR);
+ datumL = PointerDatumFromData(dataL, sizeL);
+ datumR = PointerDatumFromData(dataR, sizeR);
}
-
+ FmgrInfo finfo;
+ InitFunc(CompareProcId, &finfo, 2, 2);
LOCAL_FCINFO(callInfo, 2);
Zero(*callInfo);
- callInfo->flinfo = (FmgrInfo*)&CompareProcInfo;
+ callInfo->flinfo = &finfo;
callInfo->nargs = 2;
callInfo->fncollation = DEFAULT_COLLATION_OID;
callInfo->isnull = false;
callInfo->args[0] = { datumL, false };
callInfo->args[1] = { datumR, false };
- auto result = CompareProcInfo.fn_addr(callInfo);
+ auto result = finfo.fn_addr(callInfo);
Y_ENSURE(!callInfo->isnull);
- if (!PassByValue) {
- pfree((void*)datumL);
- pfree((void*)datumR);
- }
return DatumGetInt32(result);
}
PG_CATCH();
{
// TODO
+ Y_VERIFY(false, "PG error in Compare");
}
PG_END_TRY();
return 0;
@@ -2993,40 +3012,141 @@ public:
ui64 Hash(const char* data, size_t size) const {
NMiniKQL::TScopedAlloc alloc(__LOCATION__);
NMiniKQL::TPAllocScope scope;
+ Datum datum = 0;
+ Y_DEFER {
+ if (!PassByValue && datum) {
+ pfree((void*)datum);
+ }
+ };
PG_TRY();
{
- Datum datum;
if (PassByValue) {
datum = ScalarDatumFromData(data, size);
} else {
- datum = Unpack(data, size);
+ datum = PointerDatumFromData(data, size);
}
+ FmgrInfo finfo;
+ InitFunc(HashProcId, &finfo, 1, 1);
+ LOCAL_FCINFO(callInfo, 1);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 1;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { datum, false };
+
+ auto result = finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+ return DatumGetUInt32(result);
+ }
+ PG_CATCH();
+ {
+ // TODO
+ Y_VERIFY(false, "PG error in Hash");
+ }
+ PG_END_TRY();
+ return 0;
+ }
+ TString NativeBinaryFromNativeText(const TString& str) const {
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TPAllocScope scope;
+ Datum datum = 0;
+ text* serialized = nullptr;
+ Y_DEFER {
+ if (!PassByValue && datum) {
+ pfree((void*)datum);
+ }
+ if (serialized) {
+ pfree(serialized);
+ }
+ };
+ PG_TRY();
+ {
+ {
+ FmgrInfo finfo;
+ InitFunc(InFuncId, &finfo, 1, 3);
+ LOCAL_FCINFO(callInfo, 3);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 3;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { (Datum)str.c_str(), false };
+ callInfo->args[1] = { ObjectIdGetDatum(NMiniKQL::MakeTypeIOParam(*this)), false };
+ callInfo->args[2] = { Int32GetDatum(-1), false };
+
+ datum = finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+ }
+ FmgrInfo finfo;
+ InitFunc(SendFuncId, &finfo, 1, 1);
LOCAL_FCINFO(callInfo, 1);
Zero(*callInfo);
- callInfo->flinfo = (FmgrInfo*)&HashProcInfo;
+ callInfo->flinfo = &finfo;
callInfo->nargs = 1;
callInfo->fncollation = DEFAULT_COLLATION_OID;
callInfo->isnull = false;
callInfo->args[0] = { datum, false };
- auto result = HashProcInfo.fn_addr(callInfo);
+ serialized = (text*)finfo.fn_addr(callInfo);
Y_ENSURE(!callInfo->isnull);
- if (!PassByValue) {
+ return TString(NMiniKQL::GetVarBuf(serialized));
+ }
+ PG_CATCH();
+ {
+ // TODO
+ Y_VERIFY(false, "PG error in NativeBinaryFromNativeText");
+ }
+ PG_END_TRY();
+ return 0;
+ }
+
+ TString NativeTextFromNativeBinary(const TString& binary) const {
+ NMiniKQL::TScopedAlloc alloc(__LOCATION__);
+ NMiniKQL::TPAllocScope scope;
+ Datum datum = 0;
+ char* str = nullptr;
+ Y_DEFER {
+ if (!PassByValue && datum) {
pfree((void*)datum);
}
- return DatumGetUInt32(result);
+ if (str) {
+ pfree(str);
+ }
+ };
+ PG_TRY();
+ {
+ if (PassByValue) {
+ datum = ScalarDatumFromData(binary.Data(), binary.Size());
+ } else {
+ datum = PointerDatumFromData(binary.Data(), binary.Size());
+ }
+ FmgrInfo finfo;
+ InitFunc(OutFuncId, &finfo, 1, 1);
+ LOCAL_FCINFO(callInfo, 1);
+ Zero(*callInfo);
+ callInfo->flinfo = &finfo;
+ callInfo->nargs = 1;
+ callInfo->fncollation = DEFAULT_COLLATION_OID;
+ callInfo->isnull = false;
+ callInfo->args[0] = { datum, false };
+
+ str = (char*)finfo.fn_addr(callInfo);
+ Y_ENSURE(!callInfo->isnull);
+ return TString(str);
}
PG_CATCH();
{
// TODO
+ Y_VERIFY(false, "PG error in NativeTextFromNativeBinary");
}
PG_END_TRY();
return 0;
}
private:
- inline Datum ScalarDatumFromData(const char* data, size_t size) const {
+ Datum ScalarDatumFromData(const char* data, size_t size) const {
switch (TypeId) {
case BOOLOID:
Y_ENSURE(size == sizeof(bool));
@@ -3058,29 +3178,31 @@ private:
}
}
- Datum Unpack(const char* data, size_t size) const {
+ Datum PointerDatumFromData(const char* data, size_t size) const {
StringInfoData stringInfo;
stringInfo.data = (char*)data;
stringInfo.len = size;
stringInfo.maxlen = size;
stringInfo.cursor = 0;
+ FmgrInfo finfo;
+ InitFunc(ReceiveFuncId, &finfo, 1, 3);
LOCAL_FCINFO(callInfo, 3);
Zero(*callInfo);
- callInfo->flinfo = (FmgrInfo*)&ReceiveFuncInfo;
+ callInfo->flinfo = &finfo;
callInfo->nargs = 3;
callInfo->fncollation = DEFAULT_COLLATION_OID;
callInfo->isnull = false;
callInfo->args[0] = { (Datum)&stringInfo, false };
- callInfo->args[1] = { ObjectIdGetDatum(NKikimr::NMiniKQL::MakeTypeIOParam(*this)), false };
+ callInfo->args[1] = { ObjectIdGetDatum(NMiniKQL::MakeTypeIOParam(*this)), false };
callInfo->args[2] = { Int32GetDatum(-1), false };
- auto result = ReceiveFuncInfo.fn_addr(callInfo);
+ auto result = finfo.fn_addr(callInfo);
Y_ENSURE(!callInfo->isnull);
return result;
}
- static void InitFunc(ui32 funcId, FmgrInfo* info, ui32 argCountMin, ui32 argCountMax) {
+ static inline void InitFunc(ui32 funcId, FmgrInfo* info, ui32 argCountMin, ui32 argCountMax) {
Zero(*info);
Y_ENSURE(funcId);
fmgr_info(funcId, info);
@@ -3088,11 +3210,8 @@ private:
Y_ENSURE(info->fn_nargs >= argCountMin && info->fn_nargs <= argCountMax);
}
-private:
- FmgrInfo CompareProcInfo;
- FmgrInfo HashProcInfo;
- FmgrInfo ReceiveFuncInfo;
- FmgrInfo SendFuncInfo;
+public:
+ ui32 StoredSize = 0; // size in local db, 0 for variable size
};
class TPgTypeDescriptors {
@@ -3122,9 +3241,6 @@ public:
private:
void InitType(ui32 pgTypeId, const NYql::NPg::TTypeDesc& type) {
- if (type.TypeId == type.ArrayTypeId) { // TODO: support arrays
- return;
- }
PgTypeDescriptors[pgTypeId] = TPgTypeDescriptor(type);
ByName[type.Name] = pgTypeId;
}
@@ -3166,12 +3282,11 @@ bool TypeDescIsComparable(void* typeDesc) {
return static_cast<TPgTypeDescriptor*>(typeDesc)->CompareProcId != 0;
}
-ui32 TypeDescGetTypeLen(void* typeDesc) {
+ui32 TypeDescGetStoredSize(void* typeDesc) {
if (!typeDesc) {
return 0;
}
- i32 res = static_cast<TPgTypeDescriptor*>(typeDesc)->TypeLen;
- return res < 0 ? 0 : (ui32)res;
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->StoredSize;
}
int PgNativeBinaryCompare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR, void* typeDesc) {
@@ -3182,4 +3297,16 @@ ui64 PgNativeBinaryHash(const char* data, size_t size, void* typeDesc) {
return static_cast<TPgTypeDescriptor*>(typeDesc)->Hash(data, size);
}
+TString PgNativeBinaryFromNativeText(const TString& str, ui32 pgTypeId) {
+ auto* typeDesc = TypeDescFromPgTypeId(pgTypeId);
+ Y_VERIFY(typeDesc);
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->NativeBinaryFromNativeText(str);
+}
+
+TString PgNativeTextFromNativeBinary(const TString& binary, ui32 pgTypeId) {
+ auto* typeDesc = TypeDescFromPgTypeId(pgTypeId);
+ Y_VERIFY(typeDesc);
+ return static_cast<TPgTypeDescriptor*>(typeDesc)->NativeTextFromNativeBinary(binary);
+}
+
} // namespace NKikimr::NPg
diff --git a/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h b/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
index 533db3b90b2..277f9faf334 100644
--- a/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
+++ b/ydb/library/yql/parser/pg_wrapper/interface/type_desc.h
@@ -11,10 +11,14 @@ const char* PgTypeNameFromTypeDesc(void* typeDesc);
void* TypeDescFromPgTypeName(const TStringBuf name);
bool TypeDescIsComparable(void* typeDesc);
-ui32 TypeDescGetTypeLen(void* typeDesc);
+ui32 TypeDescGetStoredSize(void* typeDesc);
int PgNativeBinaryCompare(const char* dataL, size_t sizeL, const char* dataR, size_t sizeR, void* typeDesc);
ui64 PgNativeBinaryHash(const char* data, size_t size, void* typeDesc);
+// for tests
+TString PgNativeBinaryFromNativeText(const TString& str, ui32 pgTypeId);
+TString PgNativeTextFromNativeBinary(const TString& binary, ui32 pgTypeId);
+
} // namespace NKikimr::NPg
diff --git a/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp b/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
index bc2fedc05a5..020bc146d5f 100644
--- a/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
+++ b/ydb/library/yql/sql/pg_dummy/pg_sql_dummy.cpp
@@ -294,7 +294,7 @@ bool TypeDescIsComparable(void* typeDesc) {
throw yexception() << "PG types are not supported";
}
-ui32 TypeDescGetTypeLen(void* typeDesc) {
+ui32 TypeDescGetStoredSize(void* typeDesc) {
Y_UNUSED(typeDesc);
throw yexception() << "PG types are not supported";
}