diff --git a/csharp/test/Drivers/Snowflake/DriverTests.cs b/csharp/test/Drivers/Snowflake/DriverTests.cs index 9d1a7af128..ea3574fca2 100644 --- a/csharp/test/Drivers/Snowflake/DriverTests.cs +++ b/csharp/test/Drivers/Snowflake/DriverTests.cs @@ -39,12 +39,45 @@ public class DriverTests : IDisposable readonly AdbcDriver _snowflakeDriver; readonly AdbcDatabase _database; readonly AdbcConnection _connection; + readonly List _tableTypes; + + public static IEnumerable GetPatterns(string name) + { + if (string.IsNullOrEmpty(name)) yield break; + + yield return new object[] { name }; + yield return new object[] { $"{DriverTests.GetPartialNameForPatternMatch(name)}%" }; + yield return new object[] { $"{DriverTests.GetPartialNameForPatternMatch(name).ToLower()}%" }; + yield return new object[] { $"{DriverTests.GetPartialNameForPatternMatch(name).ToUpper()}%" }; + yield return new object[] { $"_{DriverTests.GetNameWithoutFirstChatacter(name)}" }; + yield return new object[] { $"_{DriverTests.GetNameWithoutFirstChatacter(name).ToLower()}" }; + yield return new object[] { $"_{DriverTests.GetNameWithoutFirstChatacter(name).ToUpper()}" }; + } + + public static IEnumerable CatalogNamePatternData() + { + string databaseName = SnowflakeTestingUtils.TestConfiguration?.Metadata.Catalog; + return GetPatterns(databaseName); + } + + public static IEnumerable DbSchemasNamePatternData() + { + string dbSchemaName = SnowflakeTestingUtils.TestConfiguration?.Metadata.Schema; + return GetPatterns(dbSchemaName); + } + + public static IEnumerable TableNamePatternData() + { + string tableName = SnowflakeTestingUtils.TestConfiguration?.Metadata.Table; + return GetPatterns(tableName); + } public DriverTests() { Skip.IfNot(Utils.CanExecuteTestConfig(SnowflakeTestingUtils.SNOWFLAKE_TEST_CONFIG_VARIABLE)); - _testConfiguration = Utils.LoadTestConfiguration(SnowflakeTestingUtils.SNOWFLAKE_TEST_CONFIG_VARIABLE); + _testConfiguration = SnowflakeTestingUtils.TestConfiguration; + _tableTypes = new List { "BASE TABLE", "VIEW" }; Dictionary parameters = new Dictionary(); Dictionary options = new Dictionary(); _snowflakeDriver = SnowflakeTestingUtils.GetSnowflakeAdbcDriver(_testConfiguration, out parameters); @@ -110,109 +143,49 @@ public void CanGetInfo() } } - /// - /// Validates if the driver can call GetObjects with GetObjectsDepth as Catalogs. - /// - [SkippableFact, Order(3)] - public void CanGetObjectsCatalogs() - { - string databaseName = _testConfiguration.Metadata.Catalog; - - using IArrowArrayStream stream = _connection.GetObjects( - depth: AdbcConnection.GetObjectsDepth.Catalogs, - catalogPattern: databaseName, - dbSchemaPattern: null, - tableNamePattern: null, - tableTypes: new List { "BASE TABLE", "VIEW" }, - columnNamePattern: null); - - using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; - - List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, null); - - AdbcCatalog catalog = catalogs.FirstOrDefault(); - - Assert.True(catalog != null, "catalog should not be null"); - Assert.Equal(databaseName, catalog.Name); - } - /// /// Validates if the driver can call GetObjects with GetObjectsDepth as Catalogs and CatalogName passed as a pattern. /// - [SkippableFact, Order(3)] - public void CanGetObjectsCatalogsWithPattern() + [SkippableTheory, Order(3)] + [MemberData(nameof(CatalogNamePatternData))] + public void CanGetObjectsCatalogs(string catalogPattern) { string databaseName = _testConfiguration.Metadata.Catalog; string schemaName = _testConfiguration.Metadata.Schema; - string partialDatabaseName = GetPartialNameForPatternMatch(databaseName); - using IArrowArrayStream stream = _connection.GetObjects( depth: AdbcConnection.GetObjectsDepth.Catalogs, - catalogPattern: $"{partialDatabaseName}%", + catalogPattern: catalogPattern, dbSchemaPattern: null, tableNamePattern: null, - tableTypes: new List { "BASE TABLE", "VIEW" }, + tableTypes: _tableTypes, columnNamePattern: null); using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, null); - - AdbcCatalog catalog = catalogs.FirstOrDefault(); + AdbcCatalog catalog = catalogs.Where((catalog) => string.Equals(catalog.Name, databaseName)).FirstOrDefault(); Assert.True(catalog != null, "catalog should not be null"); - Assert.StartsWith(databaseName, catalog.Name); - } - - /// - /// Validates if the driver can call GetObjects with GetObjectsDepth as DbSchemas. - /// - [SkippableFact, Order(3)] - public void CanGetObjectsDbSchemas() - { - // need to add the database - string databaseName = _testConfiguration.Metadata.Catalog; - string schemaName = _testConfiguration.Metadata.Schema; - - using IArrowArrayStream stream = _connection.GetObjects( - depth: AdbcConnection.GetObjectsDepth.DbSchemas, - catalogPattern: databaseName, - dbSchemaPattern: schemaName, - tableNamePattern: null, - tableTypes: new List { "BASE TABLE", "VIEW" }, - columnNamePattern: null); - - using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; - - List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, schemaName); - - List dbSchemas = catalogs - .Select(s => s.DbSchemas) - .FirstOrDefault(); - AdbcDbSchema dbSchema = dbSchemas.FirstOrDefault(); - - Assert.True(dbSchema != null, "dbSchema should not be null"); - Assert.Equal(schemaName, dbSchema.Name); } /// /// Validates if the driver can call GetObjects with GetObjectsDepth as DbSchemas with DbSchemaName as a pattern. /// - [SkippableFact, Order(3)] - public void CanGetObjectsDbSchemasWithPattern() + [SkippableTheory, Order(3)] + [MemberData(nameof(DbSchemasNamePatternData))] + public void CanGetObjectsDbSchemas(string dbSchemaPattern) { // need to add the database string databaseName = _testConfiguration.Metadata.Catalog; string schemaName = _testConfiguration.Metadata.Schema; - string partialSchemaName = GetPartialNameForPatternMatch(schemaName); using IArrowArrayStream stream = _connection.GetObjects( depth: AdbcConnection.GetObjectsDepth.DbSchemas, catalogPattern: databaseName, - dbSchemaPattern: $"{partialSchemaName}%", + dbSchemaPattern: dbSchemaPattern, tableNamePattern: null, - tableTypes: new List { "BASE TABLE", "VIEW" }, + tableTypes: _tableTypes, columnNamePattern: null); using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; @@ -220,66 +193,32 @@ public void CanGetObjectsDbSchemasWithPattern() List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, schemaName); List dbSchemas = catalogs - .Select(s => s.DbSchemas) + .Where(c => string.Equals(c.Name, databaseName)) + .Select(c => c.DbSchemas) .FirstOrDefault(); - AdbcDbSchema dbSchema = dbSchemas.FirstOrDefault(); + AdbcDbSchema dbSchema = dbSchemas.Where((dbSchema) => string.Equals(dbSchema.Name, schemaName)).FirstOrDefault(); Assert.True(dbSchema != null, "dbSchema should not be null"); - Assert.StartsWith(partialSchemaName, dbSchema.Name); - } - - /// - /// Validates if the driver can call GetObjects with GetObjectsDepth as Tables. - /// - [SkippableFact, Order(3)] - public void CanGetObjectsTables() - { - // need to add the database - string databaseName = _testConfiguration.Metadata.Catalog; - string schemaName = _testConfiguration.Metadata.Schema; - string tableName = _testConfiguration.Metadata.Table; - - using IArrowArrayStream stream = _connection.GetObjects( - depth: AdbcConnection.GetObjectsDepth.All, - catalogPattern: databaseName, - dbSchemaPattern: schemaName, - tableNamePattern: tableName, - tableTypes: new List { "BASE TABLE", "VIEW" }, - columnNamePattern: null); - - using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; - - List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, schemaName); - - List tables = catalogs - .Select(s => s.DbSchemas) - .FirstOrDefault() - .Select(t => t.Tables) - .FirstOrDefault(); - AdbcTable table = tables.FirstOrDefault(); - - Assert.True(table != null, "table should not be null"); - Assert.Equal(tableName, table.Name); } /// /// Validates if the driver can call GetObjects with GetObjectsDepth as Tables with TableName as a pattern. /// - [SkippableFact, Order(3)] - public void CanGetObjectsTablesWithPattern() + [SkippableTheory, Order(3)] + [MemberData(nameof(TableNamePatternData))] + public void CanGetObjectsTables(string tableNamePattern) { // need to add the database string databaseName = _testConfiguration.Metadata.Catalog; string schemaName = _testConfiguration.Metadata.Schema; string tableName = _testConfiguration.Metadata.Table; - string partialTableName = GetPartialNameForPatternMatch(tableName); using IArrowArrayStream stream = _connection.GetObjects( depth: AdbcConnection.GetObjectsDepth.All, catalogPattern: databaseName, dbSchemaPattern: schemaName, - tableNamePattern: $"{partialTableName}%", - tableTypes: new List { "BASE TABLE", "VIEW" }, + tableNamePattern: tableNamePattern, + tableTypes: _tableTypes, columnNamePattern: null); using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; @@ -287,14 +226,15 @@ public void CanGetObjectsTablesWithPattern() List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, schemaName); List tables = catalogs - .Select(s => s.DbSchemas) + .Where(c => string.Equals(c.Name, databaseName)) + .Select(c => c.DbSchemas) .FirstOrDefault() - .Select(t => t.Tables) + .Where(s => string.Equals(s.Name, schemaName)) + .Select(s => s.Tables) .FirstOrDefault(); - AdbcTable table = tables.FirstOrDefault(); + AdbcTable table = tables.Where((table) => string.Equals(table.Name, tableName)).FirstOrDefault(); Assert.True(table != null, "table should not be null"); - Assert.StartsWith(partialTableName, table.Name); } /// @@ -314,7 +254,7 @@ public void CanGetObjectsAll() catalogPattern: databaseName, dbSchemaPattern: schemaName, tableNamePattern: tableName, - tableTypes: new List { "BASE TABLE", "VIEW" }, + tableTypes: _tableTypes, columnNamePattern: columnName); using RecordBatch recordBatch = stream.ReadNextRecordBatchAsync().Result; @@ -322,11 +262,14 @@ public void CanGetObjectsAll() List catalogs = GetObjectsParser.ParseCatalog(recordBatch, databaseName, schemaName); List columns = catalogs - .Select(s => s.DbSchemas) + .Where(c => string.Equals(c.Name, databaseName)) + .Select(c => c.DbSchemas) .FirstOrDefault() - .Select(t => t.Tables) + .Where(s => string.Equals(s.Name, schemaName)) + .Select(s => s.Tables) .FirstOrDefault() - .Select(c => c.Columns) + .Where(t => string.Equals(t.Name, tableName)) + .Select(t => t.Columns) .FirstOrDefault(); Assert.True(columns != null, "Columns cannot be null"); @@ -411,13 +354,20 @@ public void CanExecuteQuery() Tests.DriverTests.CanExecuteQuery(queryResult, _testConfiguration.ExpectedResultsCount); } - private string GetPartialNameForPatternMatch(string name) + private static string GetPartialNameForPatternMatch(string name) { if (string.IsNullOrEmpty(name) || name.Length == 1) return name; return name.Substring(0, name.Length / 2); } + private static string GetNameWithoutFirstChatacter(string name) + { + if (string.IsNullOrEmpty(name)) return name; + + return name.Substring(1); + } + public void Dispose() { _connection.Dispose(); diff --git a/csharp/test/Drivers/Snowflake/SnowflakeTestingUtils.cs b/csharp/test/Drivers/Snowflake/SnowflakeTestingUtils.cs index 0da3eff777..18fcafb65f 100644 --- a/csharp/test/Drivers/Snowflake/SnowflakeTestingUtils.cs +++ b/csharp/test/Drivers/Snowflake/SnowflakeTestingUtils.cs @@ -15,11 +15,13 @@ * limitations under the License. */ +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Apache.Arrow.Adbc.C; +using Xunit; namespace Apache.Arrow.Adbc.Tests.Drivers.Interop.Snowflake { @@ -40,8 +42,22 @@ internal class SnowflakeParameters internal class SnowflakeTestingUtils { + internal static readonly SnowflakeTestConfiguration TestConfiguration; + internal const string SNOWFLAKE_TEST_CONFIG_VARIABLE = "SNOWFLAKE_TEST_CONFIG_FILE"; + static SnowflakeTestingUtils() + { + try + { + TestConfiguration = Utils.LoadTestConfiguration(SnowflakeTestingUtils.SNOWFLAKE_TEST_CONFIG_VARIABLE); + } + catch (InvalidOperationException ex) + { + Console.WriteLine(ex.Message); + } + } + /// /// Gets a the Snowflake ADBC driver with settings from the /// . @@ -66,12 +82,12 @@ out Dictionary parameters { SnowflakeParameters.USE_HIGH_PRECISION, testConfiguration.UseHighPrecision.ToString().ToLowerInvariant() } }; - if(!string.IsNullOrWhiteSpace(testConfiguration.Host)) + if (!string.IsNullOrWhiteSpace(testConfiguration.Host)) { parameters[SnowflakeParameters.HOST] = testConfiguration.Host; } - if(!string.IsNullOrWhiteSpace(testConfiguration.Database)) + if (!string.IsNullOrWhiteSpace(testConfiguration.Database)) { parameters[SnowflakeParameters.DATABASE] = testConfiguration.Database; } @@ -120,9 +136,9 @@ internal static string[] GetQueries(SnowflakeTestConfiguration testConfiguration { string modifiedLine = line; - foreach(string key in placeholderValues.Keys) + foreach (string key in placeholderValues.Keys) { - if(modifiedLine.Contains(key)) + if (modifiedLine.Contains(key)) modifiedLine = modifiedLine.Replace(key, placeholderValues[key]); } diff --git a/csharp/test/Drivers/Snowflake/ValueTests.cs b/csharp/test/Drivers/Snowflake/ValueTests.cs index 84b4af8466..511a46d1d6 100644 --- a/csharp/test/Drivers/Snowflake/ValueTests.cs +++ b/csharp/test/Drivers/Snowflake/ValueTests.cs @@ -41,7 +41,7 @@ public class ValueTests : IDisposable public ValueTests() { Skip.IfNot(Utils.CanExecuteTestConfig(SnowflakeTestingUtils.SNOWFLAKE_TEST_CONFIG_VARIABLE)); - _snowflakeTestConfiguration = Utils.LoadTestConfiguration(SnowflakeTestingUtils.SNOWFLAKE_TEST_CONFIG_VARIABLE); + _snowflakeTestConfiguration = SnowflakeTestingUtils.TestConfiguration; Dictionary parameters = new Dictionary(); Dictionary options = new Dictionary(); AdbcDriver snowflakeDriver = SnowflakeTestingUtils.GetSnowflakeAdbcDriver(_snowflakeTestConfiguration, out parameters); @@ -55,7 +55,7 @@ public ValueTests() /// Validates if driver can send and receive specific Integer values correctly /// These Snowflake types are equivalent: NUMBER(38,0),INT,INTEGER,BIGINT,SMALLINT,TINYINT,BYTEINT /// - [Theory] + [SkippableTheory] [InlineData(-1)] [InlineData(0)] [InlineData(1)] @@ -69,7 +69,7 @@ public void TestIntegerSanity(int value) /// /// Validates if driver can handle the largest / smallest numbers /// - [Theory] + [SkippableTheory] [InlineData("99999999999999999999999999999999999999")] [InlineData("-99999999999999999999999999999999999999")] public void TestIntegerMinMax(string value) @@ -82,7 +82,7 @@ public void TestIntegerMinMax(string value) /// /// Validates if driver can handle smaller Number type correctly /// - [Theory] + [SkippableTheory] [InlineData(-1)] [InlineData(0)] [InlineData(1)] @@ -98,7 +98,7 @@ public void TestSmallNumberRange(int value) /// /// Validates if driver correctly errors out when the values exceed the column's limit /// - [Theory] + [SkippableTheory] [InlineData(-100)] [InlineData(100)] [InlineData(int.MaxValue)] @@ -113,7 +113,7 @@ public void TestSmallNumberRangeOverlimit(int value) /// /// Validates if driver can handle a large scale Number type correctly /// - [Theory] + [SkippableTheory] [InlineData("0")] [InlineData("-2.003")] [InlineData("4.85")] @@ -129,7 +129,7 @@ public void TestLargeScaleNumberRange(string value) /// /// Validates if driver can error handle when input goes beyond a large scale Number type /// - [Theory] + [SkippableTheory] [InlineData("-10")] [InlineData("10")] [InlineData("99999999999999999999999999999999999999")] @@ -144,7 +144,7 @@ public void TestLargeScaleNumberOverlimit(string value) /// /// Validates if driver can handle a small scale Number type correctly /// - [Theory] + [SkippableTheory] [InlineData("0")] [InlineData("4.85")] [InlineData("-999999999999999999999999999999999999.99")] @@ -159,7 +159,7 @@ public void TestSmallScaleNumberRange(string value) /// /// Validates if driver can error handle when an insert goes beyond a small scale Number type correctly /// - [Theory] + [SkippableTheory] [InlineData("-99999999999999999999999999999999999999")] [InlineData("99999999999999999999999999999999999999")] public void TestSmallScaleNumberOverlimit(string value) @@ -174,7 +174,7 @@ public void TestSmallScaleNumberOverlimit(string value) /// Tests that decimals are rounded as expected. /// Snowflake allows inserts of scales beyond the data type size, but storage of value will round it up or down /// - [Theory] + [SkippableTheory] [InlineData(2.467, 2.47)] [InlineData(-672.613, -672.61)] public void TestRoundingNumbers(decimal input, decimal output) @@ -192,7 +192,7 @@ public void TestRoundingNumbers(decimal input, decimal output) /// Validates if driver can handle floating point number type correctly /// These Snowflake types are equivalent: FLOAT,FLOAT4,FLOAT8,DOUBLE,DOUBLE PRECISION,REAL /// - [Theory] + [SkippableTheory] [InlineData(0)] [InlineData(0.2)] [InlineData(15e-03)] diff --git a/go/adbc/driver/snowflake/connection.go b/go/adbc/driver/snowflake/connection.go index 1b2d72ef70..e96799933f 100644 --- a/go/adbc/driver/snowflake/connection.go +++ b/go/adbc/driver/snowflake/connection.go @@ -282,10 +282,10 @@ func (c *cnxn) getObjectsDbSchemas(ctx context.Context, depth adbc.ObjectDepth, conditions := make([]string, 0) if catalog != nil && *catalog != "" { - conditions = append(conditions, ` CATALOG_NAME LIKE '`+*catalog+`'`) + conditions = append(conditions, ` CATALOG_NAME ILIKE '`+*catalog+`'`) } if dbSchema != nil && *dbSchema != "" { - conditions = append(conditions, ` SCHEMA_NAME LIKE '`+*dbSchema+`'`) + conditions = append(conditions, ` SCHEMA_NAME ILIKE '`+*dbSchema+`'`) } cond := strings.Join(conditions, " AND ")