2 using System.Collections.Generic;
4 using System.Text.RegularExpressions;
17 private enum ColumnType
45 private struct DecimalInfo
51 private static readonly Regex DECIMAL_REGEX =
new Regex(
@"decimal\s*\(\s*(\d+)\s*,\s*(\d+)\s*\)", RegexOptions.IgnoreCase);
54 private readonly IList<int> _routingColumnIndices;
55 private readonly IList<ColumnType> _columnTypes;
56 private readonly IDictionary<int, DecimalInfo> _decimalInfos;
57 private readonly IList<string> _routingColumnNames;
58 private int _bufferSize;
67 _ktype = ktype ??
throw new ArgumentNullException(nameof(ktype));
69 _routingColumnIndices =
new List<int>();
70 _columnTypes =
new List<ColumnType>();
71 _decimalInfos =
new Dictionary<int, DecimalInfo>();
72 _routingColumnNames =
new List<string>();
75 bool hasTimestamp =
false;
78 int trackIdColumnIdx = -1;
81 for (
int i = 0; i < columns.Count; ++i)
85 switch (column.getName())
104 _routingColumnIndices.Add(i);
108 _routingColumnIndices.Add(i);
113 if (!isPrimaryKey && hasTimestamp && hasX && hasY && trackIdColumnIdx != -1)
115 if (_routingColumnIndices.Count == 0)
117 _routingColumnIndices.Add(trackIdColumnIdx);
119 else if (_routingColumnIndices.Count != 1 || _routingColumnIndices[0] != trackIdColumnIdx)
121 throw new KineticaException(
"Cannot have a shard key other than 'TRACKID' for track tables.");
126 foreach (
int i
in _routingColumnIndices)
129 _routingColumnNames.Add(column.getName());
131 switch (column.getType())
134 _columnTypes.Add(ColumnType.FLOAT);
139 _columnTypes.Add(ColumnType.DOUBLE);
146 _columnTypes.Add(ColumnType.INT8);
151 _columnTypes.Add(ColumnType.INT16);
156 _columnTypes.Add(ColumnType.INT);
164 _columnTypes.Add(ColumnType.TIMESTAMP);
168 _columnTypes.Add(ColumnType.LONG);
174 DetermineStringColumnType(column);
188 var properties = column.getProperties();
192 _columnTypes.Add(ColumnType.CHAR1);
197 _columnTypes.Add(ColumnType.CHAR2);
202 _columnTypes.Add(ColumnType.CHAR4);
207 _columnTypes.Add(ColumnType.CHAR8);
212 _columnTypes.Add(ColumnType.CHAR16);
217 _columnTypes.Add(ColumnType.CHAR32);
222 _columnTypes.Add(ColumnType.CHAR64);
227 _columnTypes.Add(ColumnType.CHAR128);
232 _columnTypes.Add(ColumnType.CHAR256);
237 _columnTypes.Add(ColumnType.DATE);
242 _columnTypes.Add(ColumnType.DATETIME);
247 _columnTypes.Add(ColumnType.TIME);
252 _columnTypes.Add(ColumnType.IPV4);
258 var decimalMatch = DECIMAL_REGEX.Match(
string.Join(
",", properties));
261 if (decimalMatch.Success)
263 precision =
int.Parse(decimalMatch.Groups[1].Value);
264 scale =
int.Parse(decimalMatch.Groups[2].Value);
267 _decimalInfos[_columnTypes.Count] =
new DecimalInfo { Precision = precision, Scale = scale };
271 _columnTypes.Add(ColumnType.DECIMAL);
276 _columnTypes.Add(ColumnType.DECIMAL_BIG);
283 _columnTypes.Add(ColumnType.STRING);
293 return _routingColumnIndices.Count > 0;
301 return _routingColumnNames;
311 if (_bufferSize == 0)
314 var expression =
new StringBuilder(
"(");
316 for (
int i = 0; i < _routingColumnIndices.Count; ++i)
319 expression.Append(
" and ");
322 string columnName = column.
getName();
325 object? value =
null;
326 if (keyValues.ContainsKey(columnName))
328 value = keyValues[columnName];
334 expression.Append(
"is_null(");
335 expression.Append(columnName);
336 expression.Append(
")");
341 expression.Append(
"(");
342 expression.Append(columnName);
343 expression.Append(
" = ");
346 switch (_columnTypes[i])
348 case ColumnType.CHAR1:
349 case ColumnType.CHAR2:
350 case ColumnType.CHAR4:
351 case ColumnType.CHAR8:
352 case ColumnType.CHAR16:
353 case ColumnType.CHAR32:
354 case ColumnType.CHAR64:
355 case ColumnType.CHAR128:
356 case ColumnType.CHAR256:
357 case ColumnType.DATE:
358 case ColumnType.DATETIME:
359 case ColumnType.IPV4:
360 case ColumnType.STRING:
361 case ColumnType.TIME:
363 var strValue = value.ToString()?.Replace(
"'",
"''") ??
"";
364 expression.Append(
"'");
365 expression.Append(strValue);
366 expression.Append(
"'");
369 case ColumnType.DECIMAL:
370 case ColumnType.DECIMAL_BIG:
371 if (value is decimal d)
372 expression.Append(d.ToString(System.Globalization.CultureInfo.InvariantCulture));
374 expression.Append(Convert.ToDecimal(value).ToString(System.Globalization.CultureInfo.InvariantCulture));
377 case ColumnType.DOUBLE:
378 if (value is
double dbl)
379 expression.Append(dbl.ToString(System.Globalization.CultureInfo.InvariantCulture));
381 expression.Append(Convert.ToDouble(value).ToString(System.Globalization.CultureInfo.InvariantCulture));
384 case ColumnType.FLOAT:
385 if (value is
float f)
386 expression.Append(f.ToString(System.Globalization.CultureInfo.InvariantCulture));
388 expression.Append(Convert.ToSingle(value).ToString(System.Globalization.CultureInfo.InvariantCulture));
393 expression.Append(value.ToString());
397 expression.Append(
")");
400 expression.Append(
")");
401 return expression.ToString();
409 internal RecordKey? Build(IDictionary<string, object?> keyValues)
411 if (_bufferSize == 0)
416 for (
int i = 0; i < _routingColumnIndices.Count; ++i)
419 string columnName = column.
getName();
421 object? value =
null;
422 if (keyValues.ContainsKey(columnName))
424 value = keyValues[columnName];
428 switch (_columnTypes[i])
430 case ColumnType.CHAR1:
433 case ColumnType.CHAR2:
436 case ColumnType.CHAR4:
439 case ColumnType.CHAR8:
442 case ColumnType.CHAR16:
443 key.
addCharN(value?.ToString(), 16);
445 case ColumnType.CHAR32:
446 key.
addCharN(value?.ToString(), 32);
448 case ColumnType.CHAR64:
449 key.
addCharN(value?.ToString(), 64);
451 case ColumnType.CHAR128:
452 key.
addCharN(value?.ToString(), 128);
454 case ColumnType.CHAR256:
455 key.
addCharN(value?.ToString(), 256);
457 case ColumnType.DATE:
458 key.
addDate(value?.ToString() ??
"");
460 case ColumnType.DATETIME:
463 case ColumnType.DECIMAL:
465 var info = _decimalInfos.ContainsKey(i) ? _decimalInfos[i] :
new DecimalInfo { Precision = 18, Scale = 4 };
467 key.
addDecimal(
null, info.Precision, info.Scale);
471 var decimalStr = Convert.ToDecimal(value).ToString(System.Globalization.CultureInfo.InvariantCulture);
472 key.
addDecimal(decimalStr, info.Precision, info.Scale);
476 case ColumnType.DECIMAL_BIG:
480 var info = _decimalInfos.ContainsKey(i) ? _decimalInfos[i] :
new DecimalInfo { Precision = 28, Scale = 4 };
482 key.
addDecimal(
null, info.Precision, info.Scale);
485 var decimalStr = Convert.ToDecimal(value).ToString(System.Globalization.CultureInfo.InvariantCulture);
486 key.
addDecimal(decimalStr, info.Precision, info.Scale);
490 case ColumnType.DOUBLE:
496 case ColumnType.FLOAT:
500 key.
addFloat(Convert.ToSingle(value));
506 key.
addInt(Convert.ToInt32(value));
508 case ColumnType.INT8:
512 key.
addInt8(Convert.ToSByte(value));
514 case ColumnType.INT16:
518 key.
addInt16(Convert.ToInt16(value));
520 case ColumnType.IPV4:
521 key.
addIPv4(value?.ToString() ??
"");
523 case ColumnType.LONG:
524 case ColumnType.TIMESTAMP:
528 key.
addLong(Convert.ToInt64(value));
530 case ColumnType.STRING:
533 case ColumnType.TIME:
534 key.
addTime(value?.ToString() ??
"");
const string CHAR64
This property provides optimized memory, disk and query performance for string columns.
const string INT16
This property provides optimized memory and query performance for int columns.
void addCharN(string value, int N)
Appends a charN value to the buffer.
void addInt8(int? value)
Add an 8-bit integer to the buffer.
const string CHAR128
This property provides optimized memory, disk and query performance for string columns.
const string SHARD_KEY
This property indicates that this column will be part of (or the entire) shard key.
void addInt16(int? value)
Add a short (two bytes) to the buffer.
void addDecimal(string value, int precision, int scale)
Adds a decimal value to the buffer with specified precision and scale.
const string CHAR1
This property provides optimized memory, disk and query performance for string columns.
void addDate(string value)
Adds a string to the buffer that has the 'date' property.
Builds expressions and routing keys for GenericRecord and dictionary-based records.
void addInt(int? value)
Add an integer to the buffer.
A binary key used for shard routing.
const string TIMESTAMP
Valid only for 'long' columns.
void computeHashes()
Compute the hash of the key in the buffer.
GenericRecordKeyBuilder(bool isPrimaryKey, KineticaType ktype)
Creates a GenericRecordKeyBuilder for the given KineticaType.
const string TIME
Valid only for 'string' columns.
const string DECIMAL
Valid only for 'string' columns.
const string IPV4
This property provides optimized memory, disk and query performance for string columns representing I...
const string CHAR2
This property provides optimized memory, disk and query performance for string columns.
void addTime(string value)
Adds a string to the buffer that has the 'time' property.
const string CHAR8
This property provides optimized memory, disk and query performance for string columns.
bool HasKey()
Returns whether this builder has any routing key columns.
const string CHAR32
This property provides optimized memory, disk and query performance for string columns.
const string CHAR256
This property provides optimized memory, disk and query performance for string columns.
const string PRIMARY_KEY
This property indicates that this column will be part of (or the entire) primary key.
Column properties used for Kinetica types.
void addString(string value)
Add a string to the buffer.
IList< Column > getColumns()
void addIPv4(string value)
Adds a string to the buffer that has the 'ipv4' property.
const string DATETIME
Valid only for 'string' columns.
void addLong(long? value)
Add a long to the buffer.
string getName()
Returns the name of the column.
void addDouble(double? value)
Add a double to the buffer.
void addDateTime(string value)
Adds a string to the buffer that has the 'datetime' property.
const string INT8
This property provides optimized memory and query performance for int columns.
const string CHAR16
This property provides optimized memory, disk and query performance for string columns.
void addFloat(float? value)
Add a float to the buffer.
const string CHAR4
This property provides optimized memory, disk and query performance for string columns.
const string DATE
Valid only for 'string' columns.
string? BuildExpression(IDictionary< string, object?> keyValues)
Builds a SQL expression for looking up records by key values.
IList< string > GetRoutingColumnNames()
Gets the names of the routing key columns.