@@ -74,6 +74,146 @@ Y_UNIT_TEST_SUITE(KqpQuery) {
7474 UNIT_ASSERT_VALUES_EQUAL (counters.RecompileRequestGet ()->Val (), 1 );
7575 }
7676
77+ Y_UNIT_TEST_TWIN (DecimalOutOfPrecisionBulk, EnableParameterizedDecimal) {
78+ TKikimrSettings serverSettings;
79+ serverSettings.FeatureFlags .SetEnableParameterizedDecimal (EnableParameterizedDecimal);
80+ serverSettings.WithSampleTables = false ;
81+
82+ TKikimrRunner kikimr (serverSettings);
83+ auto client = kikimr.GetQueryClient ();
84+
85+ {
86+ auto ddlResult = client.ExecuteQuery (R"(
87+ CREATE TABLE DecTest (
88+ Key Int32 NOT NULL,
89+ Value Decimal(22, 9) NOT NULL,
90+ PRIMARY KEY (Key)
91+ );
92+ )" , NYdb::NQuery::TTxControl::NoTx ()).ExtractValueSync ();
93+ UNIT_ASSERT_C (ddlResult.IsSuccess (), ddlResult.GetIssues ().ToString ());
94+ }
95+
96+ // 10000000000000 in Decimal(35, 9), invalid for Decimal(22, 9)
97+ Ydb::Value value;
98+ value.set_low_128 (1864712049423024128 );
99+ value.set_high_128 (542 );
100+ auto invalidValue = TDecimalValue (value, NYdb::TDecimalType (22 , 9 ));
101+
102+ {
103+ auto db = kikimr.GetTableClient ();
104+ auto session = db.CreateSession ().GetValueSync ().GetSession ();
105+
106+ NYdb::TValueBuilder rows;
107+ rows.BeginList ();
108+ rows.AddListItem ()
109+ .BeginStruct ()
110+ .AddMember (" Key" ).Int32 (1 )
111+ .AddMember (" Value" ).Decimal (TDecimalValue (" 10" , 22 , 9 ))
112+ .EndStruct ();
113+ rows.AddListItem ()
114+ .BeginStruct ()
115+ .AddMember (" Key" ).Int32 (2 )
116+ .AddMember (" Value" ).Decimal (invalidValue)
117+ .EndStruct ();
118+ rows.AddListItem ()
119+ .BeginStruct ()
120+ .AddMember (" Key" ).Int32 (3 )
121+ .AddMember (" Value" ).Decimal (TDecimalValue (" 10000000000000" , 22 , 9 ))
122+ .EndStruct ();
123+ rows.EndList ();
124+
125+ auto resultUpsert = db.BulkUpsert (" /Root/DecTest" , rows.Build ()).GetValueSync ();
126+ // TODO: Plan A, upsert should fail as provided value is invalid for given type.
127+ UNIT_ASSERT_C (!resultUpsert.IsSuccess (), resultUpsert.GetIssues ().ToString ());
128+
129+ auto tableYson = ReadTableToYson (session, " /Root/DecTest" );
130+ // TODO: Plan B, value for key 2 should be inf, as provided value is out of range
131+ // for given type.
132+ CompareYson (R"( [])" , tableYson);
133+ }
134+ }
135+
136+ Y_UNIT_TEST_QUAD (DecimalOutOfPrecision, UseOltpSink, EnableParameterizedDecimal) {
137+ TKikimrSettings serverSettings;
138+ serverSettings.AppConfig .MutableTableServiceConfig ()->SetEnableOltpSink (UseOltpSink);
139+ serverSettings.FeatureFlags .SetEnableParameterizedDecimal (EnableParameterizedDecimal);
140+ serverSettings.WithSampleTables = false ;
141+
142+ TKikimrRunner kikimr (serverSettings);
143+ auto client = kikimr.GetQueryClient ();
144+
145+ {
146+ auto ddlResult = client.ExecuteQuery (Sprintf (R"(
147+ CREATE TABLE DecTest (
148+ Key Int32 NOT NULL,
149+ Value Decimal(22, 9),
150+ %s
151+ PRIMARY KEY (Key)
152+ );
153+ )" , EnableParameterizedDecimal ? " ValueLarge Decimal(35, 9), " : " " ), NYdb::NQuery::TTxControl::NoTx ()).ExtractValueSync ();
154+ UNIT_ASSERT_C (ddlResult.IsSuccess (), ddlResult.GetIssues ().ToString ());
155+ }
156+
157+ // 10000000000000 in Decimal(35, 9), invalid for Decimal(22, 9)
158+ Ydb::Value value;
159+ value.set_low_128 (1864712049423024128 );
160+ value.set_high_128 (542 );
161+ auto invalidValue = TDecimalValue (value, NYdb::TDecimalType (22 , 9 ));
162+
163+ auto validValue = TDecimalValue (value, NYdb::TDecimalType (35 , 9 ));
164+
165+ {
166+ auto params = TParamsBuilder ()
167+ .AddParam (" $value" ).Decimal (invalidValue).Build ()
168+ .Build ();
169+
170+ auto writeResult = client.ExecuteQuery (R"(
171+ UPSERT INTO DecTest (Key, Value) VALUES
172+ (1, CAST(10 AS Decimal(22,9))),
173+ (2, $value),
174+ (3, $value - CAST(1 AS Decimal(22,9)));
175+ )" , NYdb::NQuery::TTxControl::BeginTx ().CommitTx (), params).ExtractValueSync ();
176+
177+ // TODO: Plan A, query should fail as provided value is invalid for given type.
178+ UNIT_ASSERT_C (!writeResult.IsSuccess (), writeResult.GetIssues ().ToString ());
179+ UNIT_ASSERT_EQUAL_C (writeResult.GetStatus (), EStatus::BAD_REQUEST, writeResult.GetIssues ().ToString ());
180+
181+ // TODO: Plan B, value for key 2 should be inf, as provided value is out of range
182+ // for given type.
183+ auto session = kikimr.GetTableClient ().CreateSession ().GetValueSync ().GetSession ();
184+ auto tableYson = ReadTableToYson (session, " /Root/DecTest" );
185+ CompareYson (R"( [])" , tableYson);
186+
187+ if (EnableParameterizedDecimal)
188+ {
189+ auto paramsValid = TParamsBuilder ()
190+ .AddParam (" $value" ).Decimal (validValue).Build ()
191+ .Build ();
192+ auto writeResult = client.ExecuteQuery (R"(
193+ UPSERT INTO DecTest (Key, ValueLarge) VALUES
194+ (2, $value);
195+ )" , NYdb::NQuery::TTxControl::BeginTx ().CommitTx (), paramsValid).ExtractValueSync ();
196+
197+ // TODO: Plan A, query should fail as provided value is invalid for given type.
198+ UNIT_ASSERT_C (writeResult.IsSuccess (), writeResult.GetIssues ().ToString ());
199+ UNIT_ASSERT_EQUAL_C (writeResult.GetStatus (), EStatus::SUCCESS, writeResult.GetIssues ().ToString ());
200+
201+ auto tableYson = ReadTableToYson (session, " /Root/DecTest" );
202+ CompareYson (R"( [[[2];#;["10000000000000"]]])" , tableYson);
203+ }
204+
205+ if (EnableParameterizedDecimal)
206+ {
207+ auto writeResult = client.ExecuteQuery (R"(
208+ UPSERT INTO DecTest (Key, Value) SELECT Key, ValueLarge as Value FROM DecTest;
209+ )" , NYdb::NQuery::TTxControl::BeginTx ().CommitTx ()).ExtractValueSync ();
210+ // TODO: Plan A, query should fail as provided value is invalid for given type.
211+ UNIT_ASSERT_C (!writeResult.IsSuccess (), writeResult.GetIssues ().ToString ());
212+ UNIT_ASSERT_EQUAL_C (writeResult.GetStatus (), EStatus::GENERIC_ERROR, writeResult.GetIssues ().ToString ());
213+ }
214+ }
215+ }
216+
77217 Y_UNIT_TEST (QueryCache) {
78218 TKikimrRunner kikimr;
79219 auto db = kikimr.GetTableClient ();
0 commit comments