Skip to content

Commit 8b39e36

Browse files
authored
Allow zero decimal scale (#10168)
1 parent dc9f405 commit 8b39e36

File tree

6 files changed

+242
-96
lines changed

6 files changed

+242
-96
lines changed

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

+43-17
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ Y_UNIT_TEST_SUITE(KqpParams) {
609609
.AddParam("$ParamDouble").Double(40.5).Build()
610610
.AddParam("$ParamDecimal").Decimal(TDecimalValue("50.5", 22, 9)).Build()
611611
.AddParam("$ParamDecimal35").Decimal(TDecimalValue("655555555555555.5", 35, 10)).Build()
612+
.AddParam("$ParamDecimal0").Decimal(TDecimalValue("9", 1, 0)).Build()
612613
.AddParam("$ParamDyNumber").DyNumber("60.5").Build()
613614
.AddParam("$ParamString").String("StringValue").Build()
614615
.AddParam("$ParamUtf8").Utf8("Utf8Value").Build()
@@ -670,6 +671,7 @@ Y_UNIT_TEST_SUITE(KqpParams) {
670671
DECLARE $ParamDouble AS Double;
671672
DECLARE $ParamDecimal AS Decimal(22, 9);
672673
DECLARE $ParamDecimal35 AS Decimal(35, 10);
674+
DECLARE $ParamDecimal0 AS Decimal(1, 0);
673675
DECLARE $ParamDyNumber AS DyNumber;
674676
DECLARE $ParamString AS String;
675677
DECLARE $ParamUtf8 AS Utf8;
@@ -704,6 +706,7 @@ Y_UNIT_TEST_SUITE(KqpParams) {
704706
$ParamDouble AS ValueDouble,
705707
$ParamDecimal AS ValueDecimal,
706708
$ParamDecimal35 AS ValueDecimal35,
709+
$ParamDecimal0 AS ValueDecimal0,
707710
$ParamDyNumber AS ValueDyNumber,
708711
$ParamString AS ValueString,
709712
$ParamUtf8 AS ValueUtf8,
@@ -729,13 +732,13 @@ Y_UNIT_TEST_SUITE(KqpParams) {
729732

730733
auto actual = ReformatYson(FormatResultSetYson(result.GetResultSet(0)));
731734
auto expected1 = ReformatYson(R"([[
732-
%true;-5;5u;-8;8u;-10;10u;-20;20u;30.5;40.5;"50.5";"655555555555555.5";".605e2";"StringValue";"Utf8Value";"[{Value=50}]";
735+
%true;-5;5u;-8;8u;-10;10u;-20;20u;30.5;40.5;"50.5";"655555555555555.5";"9";".605e2";"StringValue";"Utf8Value";"[{Value=50}]";
733736
"[{\"Value\":60}]";"[{\"Value\":70}]";18271u;1578755093u;1578863917000000u;3600;"2022-03-14,GMT";
734737
"2022-03-14T00:00:00,GMT";"2022-03-14T00:00:00.123000,GMT";["Opt"];["Tuple0";1];[17u;19u];[];["Paul";-5];
735738
[["Key2";20u];["Key1";10u]]
736739
]])");
737740
auto expected2 = ReformatYson(R"([[
738-
%true;-5;5u;-8;8u;-10;10u;-20;20u;30.5;40.5;"50.5";"655555555555555.5";".605e2";"StringValue";"Utf8Value";"[{Value=50}]";
741+
%true;-5;5u;-8;8u;-10;10u;-20;20u;30.5;40.5;"50.5";"655555555555555.5";"9";".605e2";"StringValue";"Utf8Value";"[{Value=50}]";
739742
"[{\"Value\":60}]";"[{\"Value\":70}]";18271u;1578755093u;1578863917000000u;3600;"2022-03-14,GMT";
740743
"2022-03-14T00:00:00,GMT";"2022-03-14T00:00:00.123000,GMT";["Opt"];["Tuple0";1];[17u;19u];[];["Paul";-5];
741744
[["Key1";10u];["Key2";20u]]
@@ -793,6 +796,7 @@ Y_UNIT_TEST_SUITE(KqpParams) {
793796
--!syntax_v1
794797
CREATE TABLE Table (
795798
Key Int32,
799+
Value1 Decimal(1,0),
796800
Value22 Decimal(22,9),
797801
Value35 Decimal(35,10),
798802
PRIMARY KEY (Key)
@@ -814,18 +818,19 @@ Y_UNIT_TEST_SUITE(KqpParams) {
814818
auto execSelectQuery = [&] (const TString& query, const NYdb::TParams& params) -> std::tuple<NYdb::EStatus, TString, TResultSet> {
815819
if (QueryService) {
816820
auto result = queryClient.ExecuteQuery(query, NYdb::NQuery::TTxControl::BeginTx().CommitTx(), params).ExtractValueSync();
817-
return {result.GetStatus(), result.GetIssues().ToString(), result.GetResultSet(0)};
821+
return {result.GetStatus(), result.GetIssues().ToString(), result.GetResultSets().size() ? result.GetResultSet(0) : TResultSet({})};
818822
}
819823
else {
820824
auto result = session.ExecuteDataQuery(query, TTxControl::BeginTx().CommitTx(), params).ExtractValueSync();
821-
return {result.GetStatus(), result.GetIssues().ToString(), result.GetResultSet(0)};
825+
return {result.GetStatus(), result.GetIssues().ToString(), result.GetResultSets().size() ? result.GetResultSet(0) : TResultSet({})};
822826
}
823827
};
824828

825829
// Good case
826830
{
827831
auto upsertParams = tableClient.GetParamsBuilder()
828832
.AddParam("$key").Int32(1).Build()
833+
.AddParam("$value1").Decimal(TDecimalValue("9", 1, 0)).Build()
829834
.AddParam("$value22").Decimal(TDecimalValue("123.321", 22, 9)).Build()
830835
.AddParam("$value35").Decimal(TDecimalValue("555555555555555.1234567890", 35, 10)).Build()
831836
.Build();
@@ -834,26 +839,28 @@ Y_UNIT_TEST_SUITE(KqpParams) {
834839
{
835840
auto [status, issues] = execUpsertQuery(Q1_(R"(
836841
DECLARE $key AS Int32;
842+
DECLARE $value1 AS Decimal(1,0);
837843
DECLARE $value22 AS Decimal(22,9);
838844
DECLARE $value35 AS Decimal(35,10);
839845
840-
UPSERT INTO Table (Key, Value22, Value35) VALUES
841-
($key, $value22, $value35);
846+
UPSERT INTO Table (Key, Value1, Value22, Value35) VALUES
847+
($key, $value1, $value22, $value35);
842848
)"), upsertParams);
843849
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
844850
}
845851
// No upsert parameters is declared
846852
{
847853
auto [status, issues] = execUpsertQuery(Q1_(R"(
848-
UPSERT INTO Table (Key, Value22, Value35) VALUES
849-
($key, $value22, $value35);
854+
UPSERT INTO Table (Key, Value1, Value22, Value35) VALUES
855+
($key, $value1, $value22, $value35);
850856
)"), upsertParams);
851857
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
852858
}
853859

854-
TString expected = R"([[[1];["123.321"];["555555555555555.123456789"]]])";
860+
TString expected = R"([[[1];["9"];["123.321"];["555555555555555.123456789"]]])";
855861
auto selectParams = tableClient.GetParamsBuilder()
856862
.AddParam("$key").Int32(1).Build()
863+
.AddParam("$value1").Decimal(TDecimalValue("9", 1, 0)).Build()
857864
.AddParam("$value22").Decimal(TDecimalValue("123.321", 22, 9)).Build()
858865
.AddParam("$value35").Decimal(TDecimalValue("555555555555555.1234567890", 35, 10)).Build()
859866
.Build();
@@ -862,10 +869,11 @@ Y_UNIT_TEST_SUITE(KqpParams) {
862869
{
863870
auto [status, issues, resultSet] = execSelectQuery(Q1_(R"(
864871
DECLARE $key AS Int32;
872+
DECLARE $value1 AS Decimal(1,0);
865873
DECLARE $value22 AS Decimal(22,9);
866874
DECLARE $value35 AS Decimal(35,10);
867875
868-
SELECT * FROM Table WHERE Key = $key AND Value22 = $value22 AND Value35 = $value35;
876+
SELECT * FROM Table WHERE Key = $key AND Value1 = $value1 AND Value22 = $value22 AND Value35 = $value35;
869877
)"), selectParams);
870878
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
871879
CompareYson(expected, FormatResultSetYson(resultSet));
@@ -874,13 +882,27 @@ Y_UNIT_TEST_SUITE(KqpParams) {
874882
// No select parameters is declared
875883
{
876884
auto [status, issues, resultSet] = execSelectQuery(Q1_(R"(
877-
SELECT * FROM Table WHERE Key = $key AND Value22 = $value22 AND Value35 = $value35;
885+
SELECT * FROM Table WHERE Key = $key AND Value1 = $value1 AND Value22 = $value22 AND Value35 = $value35;
878886
)"), selectParams);
879887
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
880888
CompareYson(expected, FormatResultSetYson(resultSet));
881889
}
882890
}
883891

892+
// Declare wrong decimal params
893+
{
894+
auto params = tableClient.GetParamsBuilder()
895+
.AddParam("$value99").Decimal(TDecimalValue("0", 99, 99)).Build()
896+
.Build();
897+
898+
auto [status, issues, _] = execSelectQuery(Q1_(R"(
899+
DECLARE $value99 AS Decimal(99,99);
900+
SELECT $value99 AS value99;
901+
)"), params);
902+
UNIT_ASSERT_VALUES_EQUAL(status, EStatus::GENERIC_ERROR);
903+
UNIT_ASSERT_STRING_CONTAINS(issues, "Invalid decimal precision: 99");
904+
}
905+
884906
// Declare decimal params mismatch
885907
{
886908
auto upsertParams = tableClient.GetParamsBuilder()
@@ -940,35 +962,39 @@ Y_UNIT_TEST_SUITE(KqpParams) {
940962
{
941963
auto upsertParams = tableClient.GetParamsBuilder()
942964
.AddParam("$key").Int32(1001).Build()
965+
.AddParam("$value1").Decimal(TDecimalValue("10", 1, 0)).Build()
943966
.AddParam("$value22").Decimal(TDecimalValue("12345678901234567890.1234567891", 22, 9)).Build()
944967
.AddParam("$value35").Decimal(TDecimalValue("1234567890123456789012345678901234567890.1234567891", 35, 10)).Build()
945968
.Build();
946969

947970
auto [status, issues] = execUpsertQuery(Q1_(R"(
948971
DECLARE $key AS Int32;
972+
DECLARE $value1 AS Decimal(1,0);
949973
DECLARE $value22 AS Decimal(22,9);
950974
DECLARE $value35 AS Decimal(35,10);
951975
952-
UPSERT INTO Table (Key, Value22, Value35) VALUES
953-
($key, $value22, $value35);
976+
UPSERT INTO Table (Key, Value1, Value22, Value35) VALUES
977+
($key, $value1, $value22, $value35);
954978
)"), upsertParams);
955979
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
956980
}
957981
// Good case: Upsert inf Decimal
958982
{
959983
auto upsertParams = tableClient.GetParamsBuilder()
960984
.AddParam("$key").Int32(1002).Build()
985+
.AddParam("$value1").Decimal(TDecimalValue("inf", 1, 0)).Build()
961986
.AddParam("$value22").Decimal(TDecimalValue("inf", 22, 9)).Build()
962987
.AddParam("$value35").Decimal(TDecimalValue("inf", 35, 10)).Build()
963988
.Build();
964989

965990
auto [status, issues] = execUpsertQuery(Q1_(R"(
966991
DECLARE $key AS Int32;
992+
DECLARE $value1 AS Decimal(1,0);
967993
DECLARE $value22 AS Decimal(22,9);
968994
DECLARE $value35 AS Decimal(35,10);
969995
970-
UPSERT INTO Table (Key, Value22, Value35) VALUES
971-
($key, $value22, $value35);
996+
UPSERT INTO Table (Key, Value1, Value22, Value35) VALUES
997+
($key, $value1, $value22, $value35);
972998
)"), upsertParams);
973999
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
9741000
}
@@ -980,8 +1006,8 @@ Y_UNIT_TEST_SUITE(KqpParams) {
9801006
)"), emptyParams);
9811007
UNIT_ASSERT_VALUES_EQUAL_C(status, EStatus::SUCCESS, issues);
9821008
TString expected = R"([
983-
[[1001];["inf"];["inf"]];
984-
[[1002];["inf"];["inf"]]
1009+
[[1001];["inf"];["inf"];["inf"]];
1010+
[[1002];["inf"];["inf"];["inf"]]
9851011
])";
9861012
TString actual = FormatResultSetYson(resultSet);
9871013
CompareYson(expected, actual);

ydb/core/kqp/ut/scheme/kqp_scheme_ut.cpp

+35-8
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,16 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
22942294
);)", tableName.c_str(), precision, scale);
22952295
auto createResult = session.ExecuteSchemeQuery(createQuery).GetValueSync();
22962296

2297+
if (precision == 0) {
2298+
UNIT_ASSERT_VALUES_EQUAL_C(createResult.GetStatus(), EStatus::GENERIC_ERROR, createResult.GetIssues().ToString());
2299+
UNIT_ASSERT_STRING_CONTAINS(createResult.GetIssues().ToString(), "Invalid decimal precision");
2300+
return;
2301+
}
2302+
if (precision == 33) {
2303+
UNIT_ASSERT_VALUES_EQUAL_C(createResult.GetStatus(), EStatus::GENERIC_ERROR, createResult.GetIssues().ToString());
2304+
UNIT_ASSERT_STRING_CONTAINS(createResult.GetIssues().ToString(), "Invalid decimal parameters");
2305+
return;
2306+
}
22972307
if (precision == 36) {
22982308
UNIT_ASSERT_VALUES_EQUAL_C(createResult.GetStatus(), EStatus::GENERIC_ERROR, createResult.GetIssues().ToString());
22992309
UNIT_ASSERT_STRING_CONTAINS(createResult.GetIssues().ToString(), "Invalid decimal precision");
@@ -2324,10 +2334,13 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
23242334
UNIT_ASSERT_VALUES_EQUAL(decimalType.Scale, scale);
23252335
};
23262336

2337+
createAndCheck(0, 0);
2338+
createAndCheck(1, 0);
23272339
createAndCheck(2, 1);
23282340
createAndCheck(22, 9);
2329-
createAndCheck(35, 9);
2341+
createAndCheck(35, 10);
23302342
createAndCheck(22, 20);
2343+
createAndCheck(33, 34);
23312344
createAndCheck(36, 35);
23322345
createAndCheck(999, 99);
23332346
}
@@ -2969,6 +2982,16 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
29692982
)", tableName.c_str(), columnName.c_str(), precision, scale);
29702983
auto result = session.ExecuteSchemeQuery(query).GetValueSync();
29712984

2985+
if (precision == 0) {
2986+
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::GENERIC_ERROR, result.GetIssues().ToString());
2987+
UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), "Invalid decimal precision");
2988+
return;
2989+
}
2990+
if (precision == 33) {
2991+
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::GENERIC_ERROR, result.GetIssues().ToString());
2992+
UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), "Invalid decimal parameters");
2993+
return;
2994+
}
29722995
if (precision == 36) {
29732996
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::GENERIC_ERROR, result.GetIssues().ToString());
29742997
UNIT_ASSERT_STRING_CONTAINS(result.GetIssues().ToString(), "Invalid decimal precision");
@@ -2983,18 +3006,21 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
29833006
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString());
29843007
};
29853008

3009+
addColumn(0, 0);
3010+
addColumn(1, 0);
29863011
addColumn(2, 1);
29873012
addColumn(22, 9);
2988-
addColumn(35, 9);
3013+
addColumn(35, 10);
29893014
addColumn(22, 20);
3015+
addColumn(33, 34);
29903016
addColumn(36, 35);
29913017
addColumn(999, 99);
29923018

29933019
TDescribeTableResult describe = session.DescribeTable(tableName).GetValueSync();
29943020
UNIT_ASSERT_EQUAL_C(describe.GetStatus(), EStatus::SUCCESS, describe.GetIssues().ToString());
29953021
auto tableDesc = describe.GetTableDescription();
29963022
TVector<TTableColumn> columns = tableDesc.GetTableColumns();
2997-
UNIT_ASSERT_VALUES_EQUAL(columns.size(), 6);
3023+
UNIT_ASSERT_VALUES_EQUAL(columns.size(), 7);
29983024

29993025
auto checkColumn = [&] (ui64 columnIdx, ui32 precision, ui32 scale) {
30003026
TType valueType = columns[columnIdx].Type;
@@ -3003,16 +3029,17 @@ Y_UNIT_TEST_SUITE(KqpScheme) {
30033029
UNIT_ASSERT_EQUAL(optionalKind, TTypeParser::ETypeKind::Optional);
30043030
parser.OpenOptional();
30053031
auto kind = parser.GetKind();
3006-
UNIT_ASSERT_EQUAL(kind, TTypeParser::ETypeKind::Decimal);
3032+
UNIT_ASSERT_VALUES_EQUAL(kind, TTypeParser::ETypeKind::Decimal);
30073033
TDecimalType decimalType = parser.GetDecimal();
30083034
UNIT_ASSERT_VALUES_EQUAL(decimalType.Precision, precision);
30093035
UNIT_ASSERT_VALUES_EQUAL(decimalType.Scale, scale);
30103036
};
30113037

3012-
checkColumn(2, 2, 1);
3013-
checkColumn(3, 22, 9);
3014-
checkColumn(4, 35,9);
3015-
checkColumn(5, 22, 20);
3038+
checkColumn(0,22, 20);
3039+
checkColumn(3, 1, 0);
3040+
checkColumn(4, 2, 1);
3041+
checkColumn(5, 22,9);
3042+
checkColumn(6, 35, 10);
30163043
}
30173044

30183045
Y_UNIT_TEST(CreateUserWithPassword) {

ydb/core/scheme_types/scheme_decimal_type.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@
1111

1212
namespace NKikimr::NScheme {
1313

14+
TDecimalType::TDecimalType(ui32 precision, ui32 scale)
15+
: Precision(precision)
16+
, Scale(scale)
17+
{
18+
TString error;
19+
Y_ABORT_UNLESS(Validate(precision, scale, error), "%s", error.c_str());
20+
}
21+
22+
bool TDecimalType::operator==(const TDecimalType& other) const {
23+
return Precision == other.Precision && Scale == other.Scale;
24+
}
25+
1426
TString TDecimalType::CellValueToString(const std::pair<ui64, i64>& cellValue) const {
1527
return NYql::NDecimal::ToString(NYql::NDecimal::FromHalfs(cellValue.first, cellValue.second),
1628
Precision, Scale);
@@ -44,6 +56,10 @@ const std::optional<TDecimalType> TDecimalType::ParseTypeName(const TStringBuf&
4456
}
4557

4658
bool TDecimalType::Validate(ui32 precision, ui32 scale, TString& error) {
59+
if (precision == 0) {
60+
error = Sprintf("Decimal precision should not be zero");
61+
return false;
62+
}
4763
if (precision > NKikimr::NScheme::DECIMAL_MAX_PRECISION) {
4864
error = Sprintf("Decimal precision %u should be less than %u", precision, NKikimr::NScheme::DECIMAL_MAX_PRECISION);
4965
return false;

ydb/core/scheme_types/scheme_decimal_type.h

+3-11
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,17 @@ namespace NKikimr::NScheme {
1111

1212
class TDecimalType {
1313
public:
14-
constexpr TDecimalType(ui32 precision, ui32 scale)
15-
: Precision(precision)
16-
, Scale(scale)
17-
{
18-
Y_ABORT_UNLESS(Precision);
19-
Y_ABORT_UNLESS(Scale);
20-
}
14+
TDecimalType(ui32 precision, ui32 scale);
2115

22-
constexpr bool operator==(const TDecimalType& other) const {
23-
return Precision == other.Precision && Scale == other.Scale;
24-
}
16+
bool operator==(const TDecimalType& other) const;
2517

2618
TString CellValueToString(const std::pair<ui64, i64>& cellValue) const;
2719
void CellValueToStream(const std::pair<ui64, i64>& cellValue, IOutputStream& out) const;
2820

2921
static const std::optional<TDecimalType> ParseTypeName(const TStringBuf& typeName);
3022
static bool Validate(ui32 precision, ui32 scale, TString& error);
3123

32-
constexpr static TDecimalType Default() {
24+
static TDecimalType Default() {
3325
return TDecimalType(DECIMAL_PRECISION, DECIMAL_SCALE);
3426
}
3527
private:

0 commit comments

Comments
 (0)