From 1847ba70d721b1c4598719567a0416d8552a9444 Mon Sep 17 00:00:00 2001 From: Stepan Burlakov Date: Wed, 4 Dec 2024 12:25:25 +0200 Subject: [PATCH] feat: Fir 38077 ecosystem support for geography type for net (#113) --- .../FireboltDotNetSdk.Tests.csproj | 1 + .../Integration/ExecuteTest.cs | 30 +++++++++++++++++++ .../Integration/IntegrationTest.cs | 2 +- .../Unit/ColumnTypeTest.cs | 2 ++ FireboltNETSDK/Client/FireboltDataReader.cs | 4 ++- FireboltNETSDK/FireboltDotNetSdk.csproj | 1 + FireboltNETSDK/Utils/Types.cs | 8 +++-- 7 files changed, 44 insertions(+), 4 deletions(-) diff --git a/FireboltDotNetSdk.Tests/FireboltDotNetSdk.Tests.csproj b/FireboltDotNetSdk.Tests/FireboltDotNetSdk.Tests.csproj index 70d54789..9753e57d 100644 --- a/FireboltDotNetSdk.Tests/FireboltDotNetSdk.Tests.csproj +++ b/FireboltDotNetSdk.Tests/FireboltDotNetSdk.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/FireboltDotNetSdk.Tests/Integration/ExecuteTest.cs b/FireboltDotNetSdk.Tests/Integration/ExecuteTest.cs index d07f7c19..d4c5fbac 100644 --- a/FireboltDotNetSdk.Tests/Integration/ExecuteTest.cs +++ b/FireboltDotNetSdk.Tests/Integration/ExecuteTest.cs @@ -813,6 +813,36 @@ public void ThrowsStructuredExceptionOnJSONErrorBody() Assert.That(exception.Message, Does.Contain("Unable to cast text 'blue' to integer")); } + [Test] + [Category("v2")] + [Category("engine-v2")] + public void SelectInsertGeography() + { + var conn = new FireboltConnection(USER_CONNECTION_STRING); conn.Open(); + String cleanup = "DROP TABLE IF EXISTS test_geography"; + String createTableQuery = "CREATE FACT TABLE test_geography (g GEOGRAPHY)"; + String insertQuery = "INSERT INTO test_geography (g) VALUES (@g)"; + String selectQuery = "SELECT g FROM test_geography"; + String point = "POINT(1 2)"; + String pointHex = "0101000020E6100000FEFFFFFFFFFFEF3F0000000000000040"; + + CreateCommand(conn, cleanup).ExecuteNonQuery(); + CreateCommand(conn, createTableQuery).ExecuteNonQuery(); + DbCommand insert = CreateCommand(conn, insertQuery); + insert.Prepare(); + insert.Parameters.Add(CreateParameter(insert, "@g", point)); + insert.ExecuteNonQuery(); + + DbCommand select = CreateCommand(conn, selectQuery); + using (DbDataReader reader = select.ExecuteReader()) + { + Assert.That(reader.Read(), Is.EqualTo(true)); + Assert.That(reader.GetString(0), Is.EqualTo(pointHex)); + Assert.That(reader.GetFieldType(0), Is.EqualTo(typeof(string))); + Assert.That(reader.Read(), Is.EqualTo(false)); + } + } + private void CreateDropFillTableWithArrays(string type1, Array? inta1, Type expType1, string type2, Array? inta2, Type expType2, string type3, Array? inta3, Type expType3) { using (var conn = new FireboltConnection(USER_CONNECTION_STRING)) diff --git a/FireboltDotNetSdk.Tests/Integration/IntegrationTest.cs b/FireboltDotNetSdk.Tests/Integration/IntegrationTest.cs index a4362315..2f798ebb 100644 --- a/FireboltDotNetSdk.Tests/Integration/IntegrationTest.cs +++ b/FireboltDotNetSdk.Tests/Integration/IntegrationTest.cs @@ -64,7 +64,7 @@ public void SetUp() { Database = EnvWithDefault("FIREBOLT_DATABASE"); Endpoint = GetEnvironmentVariable("FIREBOLT_ENDPOINT"); - Env = EnvWithDefault("FIREBOLT_ENV", "dev"); + Env = EnvWithDefault("FIREBOLT_ENV", "staging"); // Endpoint is not specified by CI/CD (YAML) for v2 where account and engine name are mandatory. Account = Endpoint == null ? EnvWithDefault("FIREBOLT_ACCOUNT") : GetEnvironmentVariable("FIREBOLT_ACCOUNT"); Engine = Endpoint == null ? EnvWithDefault("FIREBOLT_ENGINE_NAME") : GetEnvironmentVariable("FIREBOLT_ENGINE_NAME"); diff --git a/FireboltDotNetSdk.Tests/Unit/ColumnTypeTest.cs b/FireboltDotNetSdk.Tests/Unit/ColumnTypeTest.cs index d1bc3778..c02778fe 100644 --- a/FireboltDotNetSdk.Tests/Unit/ColumnTypeTest.cs +++ b/FireboltDotNetSdk.Tests/Unit/ColumnTypeTest.cs @@ -94,6 +94,8 @@ public void CreateColumnTypeWithNullableArrayOfArrayTypeTest() [TestCase("integer null", FireboltDataType.Int, true)] [TestCase("double null", FireboltDataType.Double, true)] [TestCase("double", FireboltDataType.Double, false)] + [TestCase("geography", FireboltDataType.Geography, false)] + [TestCase("geography null", FireboltDataType.Geography, true)] public void CreateColumnTypeWithProvidedColumnTypeNamesTest(String columnTypeName, FireboltDataType expectedType, bool expectedIsNullable) { ColumnType columnType = ColumnType.Of(columnTypeName); diff --git a/FireboltNETSDK/Client/FireboltDataReader.cs b/FireboltNETSDK/Client/FireboltDataReader.cs index 31e8efb4..4628439f 100644 --- a/FireboltNETSDK/Client/FireboltDataReader.cs +++ b/FireboltNETSDK/Client/FireboltDataReader.cs @@ -36,6 +36,7 @@ public sealed class FireboltDataReader : DbDataReader private QueryResult _queryResult; private int _depth; private int _currentRowIndex = -1; + private const int matchTimeoutSeconds = 60; private static IDictionary typesMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "boolean", typeof(bool) }, @@ -59,6 +60,7 @@ public sealed class FireboltDataReader : DbDataReader { "string", typeof(string) }, { "text", typeof(string) }, + { "geography", typeof(string) }, { "date", typeof(DateTime) }, { "datetime", typeof(DateTime) }, @@ -281,7 +283,7 @@ private Type GetTypeByName(string typeName) private string Remove(string str, string regex) { - return Regex.Replace(str, regex, "", RegexOptions.IgnoreCase); + return Regex.Replace(str, regex, "", RegexOptions.IgnoreCase, TimeSpan.FromSeconds(matchTimeoutSeconds)); } private bool IsArrayType(string typeName) diff --git a/FireboltNETSDK/FireboltDotNetSdk.csproj b/FireboltNETSDK/FireboltDotNetSdk.csproj index 4a22249d..79cabea8 100644 --- a/FireboltNETSDK/FireboltDotNetSdk.csproj +++ b/FireboltNETSDK/FireboltDotNetSdk.csproj @@ -45,6 +45,7 @@ + diff --git a/FireboltNETSDK/Utils/Types.cs b/FireboltNETSDK/Utils/Types.cs index 12dd6a3c..02b5cfe3 100644 --- a/FireboltNETSDK/Utils/Types.cs +++ b/FireboltNETSDK/Utils/Types.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Text.RegularExpressions; +using FireboltDotNetSdk.Client; using FireboltDotNetSdk.Exception; using FireboltDotNetSdk.Utils; using Newtonsoft.Json; @@ -15,13 +16,14 @@ namespace FireboltDoNetSdk.Utils public enum FireboltDataType { String, Long, Int, Float, Double, Null, Decimal, Date, DateTime, TimestampNtz, TimestampTz, - Boolean, Array, Short, ByteA + Boolean, Array, Short, ByteA, Geography } public static class TypesConverter { //Regex that matches the string Nullable(), where type is the type that we need to capture. private const string NullableTypePattern = @"Nullable\(([^)]+)\)"; + private const int matchTimeoutSeconds = 60; internal static IDictionary doubleInfinity = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "inf", double.PositiveInfinity }, @@ -66,6 +68,7 @@ public static class TypesConverter case FireboltDataType.Decimal: return Convert.ToDecimal(str.Trim('"')); case FireboltDataType.String: + case FireboltDataType.Geography: return str; case FireboltDataType.DateTime: case FireboltDataType.TimestampTz: @@ -145,6 +148,7 @@ public static FireboltDataType MapColumnTypeToFireboltDataType(string columnType "boolean" => FireboltDataType.Boolean, "array" => FireboltDataType.Array, "bytea" => FireboltDataType.ByteA, + "geography" => FireboltDataType.Geography, _ => throw new FireboltException("The data type returned from the server is not supported: " + columnType), }; return csharpType; @@ -152,7 +156,7 @@ public static FireboltDataType MapColumnTypeToFireboltDataType(string columnType public static string GetFullColumnTypeName(Meta meta) { - Match nullableMatch = Regex.Match(meta.Type, NullableTypePattern); + Match nullableMatch = Regex.Match(meta.Type, NullableTypePattern, RegexOptions.None, TimeSpan.FromSeconds(matchTimeoutSeconds)); var type = nullableMatch.Success ? nullableMatch.Groups[1].Value : meta.Type; return type; }