Skip to content

Commit 0be72a3

Browse files
committed
add validation for different precisions
1 parent 020b684 commit 0be72a3

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

ydb/core/kqp/ut/query/kqp_query_ut.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,58 @@ Y_UNIT_TEST_SUITE(KqpQuery) {
7474
UNIT_ASSERT_VALUES_EQUAL(counters.RecompileRequestGet()->Val(), 1);
7575
}
7676

77+
Y_UNIT_TEST_QUAD(DecimalOutOfPrecision, UseOltpSink, EnableParameterizedDecimal) {
78+
TKikimrSettings serverSettings;
79+
serverSettings.AppConfig.MutableTableServiceConfig()->SetEnableOltpSink(UseOltpSink);
80+
serverSettings.FeatureFlags.SetEnableParameterizedDecimal(EnableParameterizedDecimal);
81+
serverSettings.WithSampleTables = false;
82+
83+
TKikimrRunner kikimr(serverSettings);
84+
auto client = kikimr.GetQueryClient();
85+
86+
{
87+
auto ddlResult = client.ExecuteQuery(R"(
88+
CREATE TABLE DecTest (
89+
Key Int32 NOT NULL,
90+
Value Decimal(22, 9) NOT NULL,
91+
PRIMARY KEY (Key)
92+
);
93+
)", NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync();
94+
UNIT_ASSERT_C(ddlResult.IsSuccess(), ddlResult.GetIssues().ToString());
95+
}
96+
97+
// 10000000000000 in Decimal(35, 9), invalid for Decimal(22, 9)
98+
Ydb::Value value;
99+
value.set_low_128(1864712049423024128);
100+
value.set_high_128(542);
101+
auto invalidValue = TDecimalValue(value, NYdb::TDecimalType(22, 9));
102+
103+
{
104+
auto params = TParamsBuilder()
105+
.AddParam("$value").Decimal(invalidValue).Build()
106+
.Build();
107+
108+
auto writeResult = client.ExecuteQuery(R"(
109+
UPSERT INTO DecTest (Key, Value) VALUES
110+
(1, CAST(10 AS Decimal(22,9))),
111+
(2, $value),
112+
(3, $value - CAST(1 AS Decimal(22,9)));
113+
)", NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params).ExtractValueSync();
114+
115+
// TODO: Plan A, query should fail as provided value is invalid for given type.
116+
UNIT_ASSERT_C(writeResult.IsSuccess(), writeResult.GetIssues().ToString());
117+
118+
// TODO: Plan B, value for key 2 should be inf, as provided value is out of range
119+
// for given type.
120+
auto session = kikimr.GetTableClient().CreateSession().GetValueSync().GetSession();
121+
auto tableYson = ReadTableToYson(session, "/Root/DecTest");
122+
CompareYson(R"([
123+
[[1];["10"]];
124+
[[2];["inf"]];
125+
[[3];["inf"]]])", tableYson);
126+
}
127+
}
128+
77129
Y_UNIT_TEST(QueryCache) {
78130
TKikimrRunner kikimr;
79131
auto db = kikimr.GetTableClient();

ydb/library/mkql_proto/mkql_proto.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,52 @@ namespace NKikimr::NMiniKQL {
2020

2121
namespace {
2222

23+
static constexpr std::array<std::pair<NYql::NDecimal::TInt128, NYql::NDecimal::TInt128>, NYql::NDecimal::MaxPrecision + 1> DecimalBounds = {
24+
NYql::NDecimal::GetBounds<0>(),
25+
NYql::NDecimal::GetBounds<1>(),
26+
NYql::NDecimal::GetBounds<2>(),
27+
NYql::NDecimal::GetBounds<3>(),
28+
NYql::NDecimal::GetBounds<4>(),
29+
NYql::NDecimal::GetBounds<5>(),
30+
NYql::NDecimal::GetBounds<6>(),
31+
NYql::NDecimal::GetBounds<7>(),
32+
NYql::NDecimal::GetBounds<8>(),
33+
NYql::NDecimal::GetBounds<9>(),
34+
NYql::NDecimal::GetBounds<10>(),
35+
NYql::NDecimal::GetBounds<11>(),
36+
NYql::NDecimal::GetBounds<12>(),
37+
NYql::NDecimal::GetBounds<13>(),
38+
NYql::NDecimal::GetBounds<14>(),
39+
NYql::NDecimal::GetBounds<15>(),
40+
NYql::NDecimal::GetBounds<16>(),
41+
NYql::NDecimal::GetBounds<17>(),
42+
NYql::NDecimal::GetBounds<18>(),
43+
NYql::NDecimal::GetBounds<19>(),
44+
NYql::NDecimal::GetBounds<20>(),
45+
NYql::NDecimal::GetBounds<21>(),
46+
NYql::NDecimal::GetBounds<22>(),
47+
NYql::NDecimal::GetBounds<23>(),
48+
NYql::NDecimal::GetBounds<24>(),
49+
NYql::NDecimal::GetBounds<25>(),
50+
NYql::NDecimal::GetBounds<26>(),
51+
NYql::NDecimal::GetBounds<27>(),
52+
NYql::NDecimal::GetBounds<28>(),
53+
NYql::NDecimal::GetBounds<29>(),
54+
NYql::NDecimal::GetBounds<30>(),
55+
NYql::NDecimal::GetBounds<31>(),
56+
NYql::NDecimal::GetBounds<32>(),
57+
NYql::NDecimal::GetBounds<33>(),
58+
NYql::NDecimal::GetBounds<34>(),
59+
NYql::NDecimal::GetBounds<35>(),
60+
};
61+
62+
bool IsNormal(ui8 precision, NYql::NDecimal::TInt128 v) {
63+
if (precision >= DecimalBounds.size())
64+
return false;
65+
const auto& db = DecimalBounds[precision];
66+
return v > db.first && v < db.second;
67+
}
68+
2369
void ExportTypeToProtoImpl(TType* type, NKikimrMiniKQL::TType& res, const TVector<ui32>* columnOrder = nullptr);
2470

2571
Y_FORCE_INLINE void HandleKindDataExport(const TType* type, const NUdf::TUnboxedValuePod& value, Ydb::Value& res) {
@@ -1628,7 +1674,22 @@ Y_FORCE_INLINE NUdf::TUnboxedValue KindDataImport(const TType* type, const Ydb::
16281674
return MakeString(value.bytes_value());
16291675
}
16301676
case NUdf::TDataType<NUdf::TDecimal>::Id: {
1631-
return NUdf::TUnboxedValuePod(NYql::NDecimal::FromHalfs(value.low_128(), value.high_128()));
1677+
auto data = NYql::NDecimal::FromHalfs(value.low_128(), value.high_128());
1678+
auto dataType = static_cast<const TDataType*>(type);
1679+
auto schemeType = dataType->GetSchemeType();
1680+
if (schemeType != NYql::NProto::TypeIds::Decimal) {
1681+
throw yexception() << "Expected decimal type, but found " << schemeType;
1682+
}
1683+
auto decimalType = static_cast<const TDataDecimalType *>(dataType);
1684+
auto params = decimalType->GetParams();
1685+
ui8 precision = params.first;
1686+
Y_ENSURE(precision <= NYql::NDecimal::MaxPrecision, "Unsupported decimal precision: " << precision);
1687+
if (NYql::NDecimal::IsError(data)) {
1688+
throw yexception() << "Invalid Decimal value";
1689+
}
1690+
Y_ENSURE(NYql::NDecimal::IsNormal(precision, data),
1691+
"Invalid Decimal value out of the range for specified precision: " << precision);
1692+
return NUdf::TUnboxedValuePod(data);
16321693
}
16331694
default: {
16341695
throw yexception() << "Unsupported data type: " << dataType->GetSchemeType();

ydb/library/mkql_proto/mkql_proto.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ void ExportPrimitiveTypeToProto(ui32 schemeType, Ydb::Type& output);
1818
void ExportTypeToProto(TType* type, Ydb::Type& res, const TVector<ui32>* columnOrder = nullptr);
1919
void ExportValueToProto(TType* type, const NUdf::TUnboxedValuePod& value, Ydb::Value& res, const TVector<ui32>* columnOrder = nullptr);
2020

21+
bool IsNormal(ui8 precision, NYql::NDecimal::TInt128 v);
2122

2223
TType* ImportTypeFromProto(const NKikimrMiniKQL::TType& type, const TTypeEnvironment& env);
2324

0 commit comments

Comments
 (0)