Kinetica   C#   API  Version 7.2.3.1
AsyncDataTypeTests.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Threading.Tasks;
5 using Newtonsoft.Json;
6 using Xunit;
8 using kinetica;
9 
10 namespace Kinetica.AsyncTests
11 {
15  [Trait("Category", "Integration")]
16  [Trait("Category", "Async")]
17  public class AsyncDataTypeTests
18  {
19  #region Boolean Type Tests
20 
21  [Fact]
23  {
24  using var ctx = new TestContext("async_bool_type");
25  var tableName = ctx.QualifiedTable("bool_test");
26 
27  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, active BOOLEAN, PRIMARY KEY(id))");
28  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, TRUE), (2, FALSE)");
29 
30  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName} ORDER BY id");
31 
32  Assert.Equal(2, response.total_number_of_records);
33 
34  var record1 = response.data[0];
35  record1.TryGetValue("active", out var active1);
36  Assert.Equal(1, Convert.ToInt32(active1));
37  Assert.True(Convert.ToBoolean(active1));
38 
39  var record2 = response.data[1];
40  record2.TryGetValue("active", out var active2);
41  Assert.Equal(0, Convert.ToInt32(active2));
42  Assert.False(Convert.ToBoolean(active2));
43  }
44 
45  #endregion
46 
47  #region Array Type Tests
48 
49  [Fact]
51  {
52  using var ctx = new TestContext("async_array_int");
53  var tableName = ctx.QualifiedTable("array_int_test");
54 
55  // Use INTEGER[N] syntax for array columns
56  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, int_values INTEGER[5], PRIMARY KEY(id))");
57  // Insert array values using JSON syntax
58  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, '[1, 2, 3, 4, 5]')");
59 
60  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
61 
62  Assert.Equal(1, response.total_number_of_records);
63 
64  var record = response.data[0];
65  record.TryGetValue("int_values", out var valuesObj);
66 
67  // Array is stored as JSON string
68  var valuesStr = valuesObj?.ToString();
69  Assert.NotNull(valuesStr);
70 
71  // Parse the JSON array
72  var values = JsonConvert.DeserializeObject<int[]>(valuesStr!);
73  Assert.NotNull(values);
74  Assert.Equal(5, values!.Length);
75  Assert.Equal(new[] { 1, 2, 3, 4, 5 }, values);
76  }
77 
78  [Fact]
80  {
81  using var ctx = new TestContext("async_array_double");
82  var tableName = ctx.QualifiedTable("array_double_test");
83 
84  // Use DOUBLE[N] syntax for array columns
85  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, double_values DOUBLE[3], PRIMARY KEY(id))");
86  // Insert array values using JSON syntax
87  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, '[1.1, 2.2, 3.3]')");
88 
89  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
90 
91  Assert.Equal(1, response.total_number_of_records);
92 
93  var record = response.data[0];
94  record.TryGetValue("double_values", out var valuesObj);
95 
96  var valuesStr = valuesObj?.ToString();
97  Assert.NotNull(valuesStr);
98 
99  var values = JsonConvert.DeserializeObject<double[]>(valuesStr!);
100  Assert.NotNull(values);
101  Assert.Equal(3, values!.Length);
102  Assert.Equal(1.1, values[0], 5);
103  Assert.Equal(2.2, values[1], 5);
104  Assert.Equal(3.3, values[2], 5);
105  }
106 
107  #endregion
108 
109  #region Decimal Type Tests
110 
111  [Fact]
113  {
114  using var ctx = new TestContext("async_decimal_8byte");
115  var tableName = ctx.QualifiedTable("decimal_8byte_test");
116 
117  // DECIMAL(18,4) uses 8 bytes (precision <= 18)
118  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, amount DECIMAL(18,4), PRIMARY KEY(id))");
119  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, 12345.6789)");
120 
121  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
122 
123  Assert.Equal(1, response.total_number_of_records);
124 
125  var record = response.data[0];
126  record.TryGetValue("amount", out var amountObj);
127 
128  // Decimal is stored as a string
129  var amountStr = amountObj?.ToString();
130  Assert.NotNull(amountStr);
131 
132  var amount = decimal.Parse(amountStr!);
133  // DECIMAL(18,4) - 4 decimal places
134  Assert.Equal(12345.6789m, amount);
135  }
136 
137  [Fact]
139  {
140  using var ctx = new TestContext("async_decimal_8byte_custom");
141  var tableName = ctx.QualifiedTable("decimal_custom_test");
142 
143  // DECIMAL(10,2) uses 8 bytes (precision <= 18)
144  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, price DECIMAL(10,2), PRIMARY KEY(id))");
145  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, 99999999.99)");
146 
147  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
148 
149  Assert.Equal(1, response.total_number_of_records);
150 
151  var record = response.data[0];
152  record.TryGetValue("price", out var priceObj);
153 
154  var priceStr = priceObj?.ToString();
155  Assert.NotNull(priceStr);
156 
157  var price = decimal.Parse(priceStr!);
158  Assert.Equal(99999999.99m, price);
159  }
160 
161  [Fact]
163  {
164  using var ctx = new TestContext("async_decimal_12byte");
165  var tableName = ctx.QualifiedTable("decimal_12byte_test");
166 
167  // DECIMAL(26,13) uses 12 bytes (precision > 18)
168  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, big_amount DECIMAL(26,13), PRIMARY KEY(id))");
169  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, 1234567890123.1234567890123)");
170 
171  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
172 
173  Assert.Equal(1, response.total_number_of_records);
174 
175  var record = response.data[0];
176  record.TryGetValue("big_amount", out var amountObj);
177 
178  var amountStr = amountObj?.ToString();
179  Assert.NotNull(amountStr);
180 
181  var amount = decimal.Parse(amountStr!);
182  // Verify the high-precision decimal was stored and retrieved correctly
183  Assert.True(Math.Abs(amount - 1234567890123.1234567890123m) < 0.0000000001m);
184  }
185 
186  [Fact]
188  {
189  using var ctx = new TestContext("async_decimal_12byte_max");
190  var tableName = ctx.QualifiedTable("decimal_max_test");
191 
192  // DECIMAL(26,13) for large values
193  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, big_val DECIMAL(26,13), PRIMARY KEY(id))");
194  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, 9999999999999.9999999999999)");
195 
196  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
197 
198  Assert.Equal(1, response.total_number_of_records);
199 
200  var record = response.data[0];
201  record.TryGetValue("big_val", out var valObj);
202 
203  var valStr = valObj?.ToString();
204  Assert.NotNull(valStr);
205 
206  var val = decimal.Parse(valStr!);
207  Assert.True(Math.Abs(val - 9999999999999.9999999999999m) < 0.0000000001m);
208  }
209 
210  [Fact]
212  {
213  using var ctx = new TestContext("async_decimal_12byte_neg");
214  var tableName = ctx.QualifiedTable("decimal_neg_test");
215 
216  // DECIMAL(26,13) for negative values
217  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, neg_val DECIMAL(26,13), PRIMARY KEY(id))");
218  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, -1234567890123.1234567890123)");
219 
220  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
221 
222  Assert.Equal(1, response.total_number_of_records);
223 
224  var record = response.data[0];
225  record.TryGetValue("neg_val", out var valObj);
226 
227  var valStr = valObj?.ToString();
228  Assert.NotNull(valStr);
229 
230  var val = decimal.Parse(valStr!);
231  Assert.True(Math.Abs(val - (-1234567890123.1234567890123m)) < 0.0000000001m);
232  }
233 
234  [Fact]
236  {
237  using var ctx = new TestContext("async_decimal_typeinfo");
238  var tableName = ctx.QualifiedTable("decimal_typeinfo_test");
239 
240  // Create table with both 8-byte and 12-byte decimal columns
241  await ctx.Kinetica.ExecuteSqlAsync($@"CREATE TABLE {tableName} (
242  id INT,
243  small_decimal DECIMAL(10,2),
244  default_decimal DECIMAL(18,4),
245  big_decimal DECIMAL(26,13),
246  PRIMARY KEY(id))");
247 
248  var ktype = KineticaType.fromTable(ctx.Kinetica, tableName);
249  var columns = ktype.getColumns();
250 
251  // Check small_decimal (8-byte, precision=10, scale=2)
252  var smallDecCol = columns.FirstOrDefault(c => c.getName() == "small_decimal");
253  Assert.NotNull(smallDecCol);
254  Assert.True(smallDecCol!.isDecimal());
255  Assert.Equal(10, smallDecCol.getDecimalPrecision());
256  Assert.Equal(2, smallDecCol.getDecimalScale());
257  Assert.Equal(8, smallDecCol.getDecimalByteSize());
258 
259  // Check default_decimal (8-byte, precision=18, scale=4)
260  var defaultDecCol = columns.FirstOrDefault(c => c.getName() == "default_decimal");
261  Assert.NotNull(defaultDecCol);
262  Assert.True(defaultDecCol!.isDecimal());
263  Assert.Equal(18, defaultDecCol.getDecimalPrecision());
264  Assert.Equal(4, defaultDecCol.getDecimalScale());
265  Assert.Equal(8, defaultDecCol.getDecimalByteSize());
266 
267  // Check big_decimal (12-byte, precision=26, scale=13)
268  var bigDecCol = columns.FirstOrDefault(c => c.getName() == "big_decimal");
269  Assert.NotNull(bigDecCol);
270  Assert.True(bigDecCol!.isDecimal());
271  Assert.Equal(26, bigDecCol.getDecimalPrecision());
272  Assert.Equal(13, bigDecCol.getDecimalScale());
273  Assert.Equal(12, bigDecCol.getDecimalByteSize());
274  }
275 
276  [Fact]
278  {
279  // Verify the decimal constants match the Java API (not async, just a constant check)
280  Assert.Equal(18, KineticaType.Column.DEFAULT_DECIMAL_PRECISION);
281  Assert.Equal(4, KineticaType.Column.DEFAULT_DECIMAL_SCALE);
282  Assert.Equal(18, KineticaType.Column.DECIMAL8_MAX_PRECISION);
283  }
284 
285  #endregion
286 
287  #region WKT Geometry Type Tests
288 
289  [Fact]
290  public async Task WKT_Point_ReadsCorrectlyAsync()
291  {
292  using var ctx = new TestContext("async_wkt_point");
293  var tableName = ctx.QualifiedTable("wkt_point_test");
294 
295  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, location GEOMETRY, PRIMARY KEY(id))");
296  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, ST_GEOMFROMTEXT('POINT(-122.4194 37.7749)'))");
297 
298  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT id, ST_ASTEXT(location) as location_wkt FROM {tableName}");
299 
300  Assert.Equal(1, response.total_number_of_records);
301 
302  var record = response.data[0];
303  record.TryGetValue("location_wkt", out var wktObj);
304 
305  var wkt = wktObj?.ToString();
306  Assert.NotNull(wkt);
307  Assert.Contains("POINT", wkt!);
308  }
309 
310  [Fact]
312  {
313  using var ctx = new TestContext("async_wkt_polygon");
314  var tableName = ctx.QualifiedTable("wkt_polygon_test");
315 
316  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, area GEOMETRY, PRIMARY KEY(id))");
317  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, ST_GEOMFROMTEXT('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'))");
318 
319  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT id, ST_ASTEXT(area) as area_wkt FROM {tableName}");
320 
321  Assert.Equal(1, response.total_number_of_records);
322 
323  var record = response.data[0];
324  record.TryGetValue("area_wkt", out var wktObj);
325 
326  var wkt = wktObj?.ToString();
327  Assert.NotNull(wkt);
328  Assert.Contains("POLYGON", wkt!);
329  }
330 
331  #endregion
332 
333  #region Other Type Tests
334 
335  [Fact]
336  public async Task UUID_ReadsCorrectlyAsync()
337  {
338  using var ctx = new TestContext("async_uuid");
339  var tableName = ctx.QualifiedTable("uuid_test");
340 
341  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, uid UUID, PRIMARY KEY(id))");
342  // Use a static UUID value since Kinetica doesn't have a UUID() function
343  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, '550e8400-e29b-41d4-a716-446655440000')");
344 
345  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
346 
347  Assert.Equal(1, response.total_number_of_records);
348 
349  var record = response.data[0];
350  record.TryGetValue("uid", out var uidObj);
351 
352  var uidStr = uidObj?.ToString();
353  Assert.NotNull(uidStr);
354  // UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
355  Assert.Matches(@"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", uidStr!.ToLower());
356  }
357 
358  [Fact]
359  public async Task JSON_ReadsCorrectlyAsync()
360  {
361  using var ctx = new TestContext("async_json");
362  var tableName = ctx.QualifiedTable("json_test");
363 
364  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, metadata JSON, PRIMARY KEY(id))");
365  // Use simpler JSON without nested quotes
366  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, '{{\"name\":\"test\",\"value\":123}}')");
367 
368  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
369 
370  Assert.Equal(1, response.total_number_of_records);
371 
372  var record = response.data[0];
373  record.TryGetValue("metadata", out var jsonObj);
374 
375  var jsonStr = jsonObj?.ToString();
376  Assert.NotNull(jsonStr);
377 
378  // Parse and verify JSON
379  var parsed = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonStr!);
380  Assert.NotNull(parsed);
381  Assert.True(parsed!.ContainsKey("name"));
382  }
383 
384  [Fact]
385  public async Task ULONG_ReadsCorrectlyAsync()
386  {
387  using var ctx = new TestContext("async_ulong");
388  var tableName = ctx.QualifiedTable("ulong_test");
389 
390  // Use LONG since ULONG syntax varies by Kinetica version
391  await ctx.Kinetica.ExecuteSqlAsync($"CREATE TABLE {tableName} (id INT, big_number LONG, PRIMARY KEY(id))");
392  await ctx.Kinetica.ExecuteSqlAsync($"INSERT INTO {tableName} VALUES (1, 9223372036854775807)"); // Max LONG
393 
394  var response = await ctx.Kinetica.ExecuteSqlAsync($"SELECT * FROM {tableName}");
395 
396  Assert.Equal(1, response.total_number_of_records);
397 
398  var record = response.data[0];
399  record.TryGetValue("big_number", out var numberObj);
400 
401  Assert.NotNull(numberObj);
402  Assert.Equal(9223372036854775807L, Convert.ToInt64(numberObj));
403  }
404 
405  [Fact]
407  {
408  using var ctx = new TestContext("async_type_from_table");
409  var tableName = ctx.QualifiedTable("type_identification_test");
410 
411  await ctx.Kinetica.ExecuteSqlAsync($@"CREATE TABLE {tableName} (
412  id INT,
413  name VARCHAR(64),
414  value DOUBLE,
415  count LONG,
416  active INT,
417  PRIMARY KEY(id))");
418 
419  var ktype = KineticaType.fromTable(ctx.Kinetica, tableName);
420  var columns = ktype.getColumns();
421 
422  Assert.Equal(5, columns.Count);
423 
424  var idCol = columns.FirstOrDefault(c => c.getName() == "id");
425  Assert.NotNull(idCol);
426 
427  var nameCol = columns.FirstOrDefault(c => c.getName() == "name");
428  Assert.NotNull(nameCol);
429 
430  var valueCol = columns.FirstOrDefault(c => c.getName() == "value");
431  Assert.NotNull(valueCol);
432  }
433 
434  #endregion
435  }
436 }
Async tests for various data type handling in Kinetica.
Test context that manages schema and cleanup for integration tests.
Definition: TestContext.cs:11
static KineticaType fromTable(Kinetica kinetica, string tableName)
Create a KineticaType object based on an existing table in the database.
IList< Column > getColumns()
async Task Decimal_8Byte_CustomPrecisionScale_ReadsCorrectlyAsync()