From c803ab485f4a03441e779fa74d6e31f0c0a28ae4 Mon Sep 17 00:00:00 2001 From: Dariusz Stempniak Date: Wed, 11 Oct 2023 21:20:23 +0200 Subject: [PATCH] SNOW-893834 after CR --- .../IntegrationTests/SFDbDataReaderIT.cs | 201 +++++++----------- .../IntegrationTests/SFReusableChunkTest.cs | 12 +- .../UnitTests/ArrowResultChunkTest.cs | 23 +- .../UnitTests/ArrowResultSetTest.cs | 71 ++++--- .../SnowflakeDbConnectionWithResultFormat.cs | 44 ---- .../Util/TestDataGenarator.cs | 6 + .../Client/SnowflakeDbDataReader.cs | 6 +- Snowflake.Data/Core/ArrowResultSet.cs | 20 +- Snowflake.Data/Core/SFBaseResultSet.cs | 2 +- Snowflake.Data/Core/SFResultSet.cs | 4 +- 10 files changed, 164 insertions(+), 225 deletions(-) delete mode 100644 Snowflake.Data.Tests/Util/SnowflakeDbConnectionWithResultFormat.cs diff --git a/Snowflake.Data.Tests/IntegrationTests/SFDbDataReaderIT.cs b/Snowflake.Data.Tests/IntegrationTests/SFDbDataReaderIT.cs index 66b7cc1b0..3b55ff682 100755 --- a/Snowflake.Data.Tests/IntegrationTests/SFDbDataReaderIT.cs +++ b/Snowflake.Data.Tests/IntegrationTests/SFDbDataReaderIT.cs @@ -37,11 +37,8 @@ private void ValidateResultFormat(IDataReader reader) [Test] public void TestRecordsAffected() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola NUMBER"}); IDbCommand cmd = conn.CreateCommand(); @@ -60,7 +57,7 @@ public void TestRecordsAffected() Assert.AreEqual(0, count); // Reader's RecordsAffected should be available even if the connection is closed - conn.Close(); + CloseConnection(conn); Assert.AreEqual(3, reader.RecordsAffected); } } @@ -68,11 +65,8 @@ public void TestRecordsAffected() [Test] public void TestGetNumber() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola NUMBER"}); IDbCommand cmd = conn.CreateCommand(); @@ -122,7 +116,7 @@ public void TestGetNumber() Assert.IsFalse(reader.Read()); reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -130,11 +124,8 @@ public void TestGetNumber() [Test] public void TestGetDouble() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola DOUBLE"}); IDbCommand cmd = conn.CreateCommand(); @@ -176,7 +167,7 @@ public void TestGetDouble() Assert.IsFalse(reader.Read()); reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -226,11 +217,8 @@ public void TestGetTime(string inputTimeStr, int? precision) [TestCase("23:59:59.123456789")] public void TestGetTimeSpan(string inputTimeStr) { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - // Insert data int fractionalPartIndex = inputTimeStr.IndexOf('.'); var precision = fractionalPartIndex > 0 ? inputTimeStr.Length - (inputTimeStr.IndexOf('.') + 1) : 0; @@ -266,7 +254,7 @@ public void TestGetTimeSpan(string inputTimeStr) Assert.AreEqual(dateTimeTime.Second, timeSpanTime.Seconds); Assert.AreEqual(dateTimeTime.Millisecond, timeSpanTime.Milliseconds); - conn.Close(); + CloseConnection(conn); } } @@ -274,11 +262,8 @@ public void TestGetTimeSpan(string inputTimeStr) public void TestGetTimeSpanError() { // Only Time data can be retrieved using GetTimeSpan, other type will fail - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "C1 NUMBER", @@ -329,7 +314,7 @@ public void TestGetTimeSpanError() try { - var xxx = ((SnowflakeDbDataReader)reader).GetTimeSpan(i); + ((SnowflakeDbDataReader)reader).GetTimeSpan(i); Assert.Fail("Data should not be converted to TIME"); } catch (SnowflakeDbException e) @@ -356,7 +341,7 @@ public void TestGetTimeSpanError() reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -373,11 +358,8 @@ private void TestGetDateAndOrTime(string inputTimeStr, int? precision, SFDataTyp inputTime = DateTime.ParseExact(inputTimeStr, "yyyy-MM-dd HH:mm:ss.fffffff", CultureInfo.InvariantCulture); } - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { $"cola {dataType}{ (precision == null ? string.Empty : $"({precision})" )}" @@ -446,7 +428,7 @@ private void TestGetDateAndOrTime(string inputTimeStr, int? precision, SFDataTyp reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -479,11 +461,8 @@ public void TestGetTimestampNTZ(string inputTimeStr, int? precision) [TestCase(-14)] public void TestGetTimestampTZ(int timezoneOffsetInHours) { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola TIMESTAMP_TZ"}); DateTimeOffset now = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(timezoneOffsetInHours)); @@ -514,7 +493,7 @@ public void TestGetTimestampTZ(int timezoneOffsetInHours) Assert.AreEqual(now, dtOffset); Assert.AreEqual(now.Offset, dtOffset.Offset); - conn.Close(); + CloseConnection(conn); } } @@ -522,11 +501,8 @@ public void TestGetTimestampTZ(int timezoneOffsetInHours) [Test] public void TestGetTimestampLTZ() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola TIMESTAMP_LTZ"}); DateTimeOffset now = DateTimeOffset.Now; @@ -558,18 +534,15 @@ public void TestGetTimestampLTZ() Assert.AreEqual(now, dtOffset); Assert.AreEqual(now.Offset, dtOffset.Offset); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestGetBoolean() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola BOOLEAN"}); IDbCommand cmd = conn.CreateCommand(); @@ -595,18 +568,15 @@ public void TestGetBoolean() Assert.IsTrue(reader.GetBoolean(0)); reader.Close(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestGetBinary() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "col1 BINARY", @@ -740,18 +710,15 @@ public void TestGetBinary() reader.Close(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestGetChars() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "col1 VARCHAR(50)", @@ -887,18 +854,15 @@ public void TestGetChars() reader.Close(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestGetStream() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "col1 VARCHAR(50)", @@ -963,7 +927,7 @@ public void TestGetStream() reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -971,11 +935,8 @@ public void TestGetStream() [Test] public void TestGetValueIndexOutOfBound() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = "select 1"; IDataReader reader = cmd.ExecuteReader(); @@ -1005,18 +966,15 @@ public void TestGetValueIndexOutOfBound() } reader.Close(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestBasicDataReader() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - using (IDbCommand cmd = conn.CreateCommand()) { cmd.CommandText = "select 1 as colone, 2 as coltwo"; @@ -1069,18 +1027,15 @@ public void TestBasicDataReader() } } - conn.Close(); + CloseConnection(conn); } } [Test] public void TestReadOutNullVal() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "a INTEGER", @@ -1108,18 +1063,15 @@ public void TestReadOutNullVal() } } - conn.Close(); + CloseConnection(conn); } } [Test] public void TestGetGuid() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola STRING"}); IDbCommand cmd = conn.CreateCommand(); @@ -1155,7 +1107,7 @@ public void TestGetGuid() reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -1163,11 +1115,8 @@ public void TestGetGuid() public void TestCopyCmdUpdateCount() { var stageName = TestName; - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola STRING"}); IDbCommand cmd = conn.CreateCommand(); @@ -1190,7 +1139,7 @@ public void TestCopyCmdUpdateCount() cmd.CommandText = $"drop stage {stageName}"; cmd.ExecuteNonQuery(); - conn.Close(); + CloseConnection(conn); } } @@ -1198,11 +1147,8 @@ public void TestCopyCmdUpdateCount() public void TestCopyCmdResultSet() { var stageName = TestName; - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new []{"cola STRING"}); IDbCommand cmd = conn.CreateCommand(); @@ -1235,18 +1181,15 @@ public void TestCopyCmdResultSet() cmd.CommandText = $"drop stage {stageName}"; cmd.ExecuteNonQuery(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestRetrieveSemiStructuredData() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "cola VARIANT", @@ -1268,18 +1211,15 @@ public void TestRetrieveSemiStructuredData() Assert.AreEqual("{\n \"key\": \"value\"\n}", reader.GetString(2)); } - conn.Close(); + CloseConnection(conn); } } [Test] public void TestResultSetMetadata() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - CreateOrReplaceTable(conn, TableName, new [] { "c1 NUMBER(20, 4)", @@ -1343,18 +1283,15 @@ public void TestResultSetMetadata() Assert.AreEqual(true, row[SchemaTableColumn.AllowDBNull]); } - conn.Close(); + CloseConnection(conn); } } [Test] public void TestHasRows() { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = "select 1 where 1=2"; @@ -1364,18 +1301,15 @@ public void TestHasRows() Assert.IsFalse(reader.HasRows); reader.Close(); - conn.Close(); + CloseConnection(conn); } } [Test] public void TestHasRowsMultiStatement() { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = "select 1;" + "select 1 where 1=2;" + @@ -1415,7 +1349,7 @@ public void TestHasRowsMultiStatement() Assert.IsFalse(reader.HasRows); reader.Close(); - conn.Close(); + CloseConnection(conn); } } @@ -1432,11 +1366,8 @@ public void TestHasRowsMultiStatement() [TestCase("9999999999999999999999999.99")] // Decimal + scale public void TestNumericValues(string testValue) { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = "select " + testValue; using (SnowflakeDbDataReader reader = (SnowflakeDbDataReader)cmd.ExecuteReader()) @@ -1469,6 +1400,7 @@ public void TestNumericValues(string testValue) Assert.Throws(() => reader.GetByte(0)); } } + CloseConnection(conn); } } } @@ -1482,11 +1414,8 @@ public void TestNumericValues(string testValue) [TestCase("9999-12-31 23:59:59.9999999 +0000", 9)] public void TestTimestampTz(string testValue, int scale) { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = $"select '{testValue}'::TIMESTAMP_TZ({scale})"; @@ -1500,6 +1429,8 @@ public void TestTimestampTz(string testValue, int scale) Assert.AreEqual(expectedValue, reader.GetValue(0)); } + + CloseConnection(conn); } } @@ -1510,11 +1441,8 @@ public void TestTimestampTz(string testValue, int scale) [TestCase("9999-12-31 23:59:59.9999999 +0000", 9)] public void TestTimestampLtz(string testValue, int scale) { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = $"select '{testValue}'::TIMESTAMP_LTZ({scale})"; @@ -1528,6 +1456,8 @@ public void TestTimestampLtz(string testValue, int scale) Assert.AreEqual(expectedValue, reader.GetValue(0)); } + + CloseConnection(conn); } } @@ -1537,11 +1467,8 @@ public void TestTimestampLtz(string testValue, int scale) [TestCase("9999-12-31 23:59:59.9999999", 9)] public void TestTimestampNtz(string testValue, int scale) { - using (DbConnection conn = new SnowflakeDbConnectionWithResultFormat(_resultFormat)) + using (var conn = CreateAndOpenConnection()) { - conn.ConnectionString = ConnectionString; - conn.Open(); - DbCommand cmd = conn.CreateCommand(); cmd.CommandText = $"select '{testValue}'::TIMESTAMP_NTZ({scale})"; @@ -1555,7 +1482,23 @@ public void TestTimestampNtz(string testValue, int scale) Assert.AreEqual(expectedValue, reader.GetValue(0)); } + + CloseConnection(conn); } - } + } + + private DbConnection CreateAndOpenConnection() + { + var conn = new SnowflakeDbConnection(ConnectionString); + conn.Open(); + SessionParameterAlterer.SetResultFormat(conn, _resultFormat); + return conn; + } + + private void CloseConnection(DbConnection conn) + { + SessionParameterAlterer.RestoreResultFormat(conn); + conn.Close(); + } } -} \ No newline at end of file +} diff --git a/Snowflake.Data.Tests/IntegrationTests/SFReusableChunkTest.cs b/Snowflake.Data.Tests/IntegrationTests/SFReusableChunkTest.cs index ab215f465..1dcc4ddc2 100644 --- a/Snowflake.Data.Tests/IntegrationTests/SFReusableChunkTest.cs +++ b/Snowflake.Data.Tests/IntegrationTests/SFReusableChunkTest.cs @@ -16,11 +16,12 @@ class SFReusableChunkTest : SFBaseTest [Test] public void TestDelCharPr431() { - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(ResultFormat.JSON)) + using (IDbConnection conn = new SnowflakeDbConnection()) { conn.ConnectionString = ConnectionString; conn.Open(); + SessionParameterAlterer.SetResultFormat(conn, ResultFormat.JSON); CreateOrReplaceTable(conn, TableName, new []{"col STRING"}); IDbCommand cmd = conn.CreateCommand(); @@ -51,6 +52,7 @@ public void TestDelCharPr431() } Assert.AreEqual(largeTableRowCount, rowCount); + SessionParameterAlterer.RestoreResultFormat(conn); // Reader's RecordsAffected should be available even if the connection is closed conn.Close(); } @@ -62,11 +64,12 @@ public void TestParseJson() IChunkParserFactory previous = ChunkParserFactory.Instance; ChunkParserFactory.Instance = new TestChunkParserFactory(1); - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(ResultFormat.JSON)) + using (IDbConnection conn = new SnowflakeDbConnection()) { conn.ConnectionString = ConnectionString; conn.Open(); + SessionParameterAlterer.SetResultFormat(conn, ResultFormat.JSON); CreateOrReplaceTable(conn, TableName, new []{"src VARIANT"}); IDbCommand cmd = conn.CreateCommand(); @@ -110,6 +113,7 @@ select parse_json('{{ } Assert.AreEqual(500, rowCount); + SessionParameterAlterer.RestoreResultFormat(conn); // Reader's RecordsAffected should be available even if the connection is closed conn.Close(); } @@ -122,11 +126,12 @@ public void TestChunkRetry() IChunkParserFactory previous = ChunkParserFactory.Instance; ChunkParserFactory.Instance = new TestChunkParserFactory(6); // lower than default retry of 7 - using (IDbConnection conn = new SnowflakeDbConnectionWithResultFormat(ResultFormat.JSON)) + using (IDbConnection conn = new SnowflakeDbConnection()) { conn.ConnectionString = ConnectionString; conn.Open(); + SessionParameterAlterer.SetResultFormat(conn, ResultFormat.JSON); CreateOrReplaceTable(conn, TableName, new []{"col STRING"}); IDbCommand cmd = conn.CreateCommand(); @@ -157,6 +162,7 @@ public void TestChunkRetry() } Assert.AreEqual(largeTableRowCount, rowCount); + SessionParameterAlterer.RestoreResultFormat(conn); // Reader's RecordsAffected should be available even if the connection is closed conn.Close(); } diff --git a/Snowflake.Data.Tests/UnitTests/ArrowResultChunkTest.cs b/Snowflake.Data.Tests/UnitTests/ArrowResultChunkTest.cs index 0bbfd3b54..3ea66f0be 100755 --- a/Snowflake.Data.Tests/UnitTests/ArrowResultChunkTest.cs +++ b/Snowflake.Data.Tests/UnitTests/ArrowResultChunkTest.cs @@ -9,6 +9,7 @@ using Apache.Arrow.Types; using NUnit.Framework; using Snowflake.Data.Core; +using Snowflake.Data.Tests.Util; namespace Snowflake.Data.Tests.UnitTests { @@ -185,7 +186,7 @@ public void TestExtractCellReturnsNumber16() [Test] public void TestExtractCellReturnsNumber8() { - var testValues = new sbyte[] { 0, 127, -120 }; + var testValues = new sbyte[] { 0, 127, -128 }; var sfType = SFDataType.FIXED; for (var scale = 0; scale <= 9; ++scale) @@ -220,7 +221,7 @@ public void TestExtractCellReturnsText() var testValues = new string[] { "", - "AAA $ BBB & CCC * (ZZZ) aaa zzz `~!@#$%^&*()_+-={}|[]\\;':\",./<>?" + TestDataGenarator.StringWithUnicode }; var sfType = SFDataType.TEXT; var scale = 0; @@ -234,7 +235,7 @@ public void TestExtractCellReturnsArray() var testValues = new string[] { "", - "AAA $ BBB & CCC * (ZZZ) aaa zzz `~!@#$%^&*()_+-={}|[]\\;':\",./<>?" + TestDataGenarator.StringWithUnicode }; var sfType = SFDataType.ARRAY; var scale = 0; @@ -404,9 +405,19 @@ public static RecordBatch PrepareRecordBatch(SFDataType sfType, long scale, obje case SFDataType.ARRAY: case SFDataType.VARIANT: case SFDataType.OBJECT: - column = new StringArray.Builder() - .AppendRange(values as string[]) - .Build(); + switch (values) + { + case string[] arr: + column = new StringArray.Builder() + .AppendRange(arr) + .Build(); + break; + case char[] arr: + column = new StringArray.Builder() + .AppendRange(arr.Select(ch => ch.ToString())) + .Build(); + break; + } break; case SFDataType.BINARY: diff --git a/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs b/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs index 7fbe8792e..1bd0974f0 100755 --- a/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs +++ b/Snowflake.Data.Tests/UnitTests/ArrowResultSetTest.cs @@ -13,6 +13,7 @@ using Apache.Arrow.Ipc; using NUnit.Framework; using Snowflake.Data.Core; +using Snowflake.Data.Tests.Util; namespace Snowflake.Data.Tests.UnitTests { @@ -146,18 +147,16 @@ public void TestGetNumber16() [Test] public void TestGetNumber8() { - var testValues = new sbyte[] { 0, 127, -120 }; + var testValues = new sbyte[] { 0, 127, -128 }; TestGetNumber(testValues); } private void TestGetNumber(IEnumerable testValues) { - var sfType = SFDataType.FIXED; - for (var scale = 0; scale <= 9; ++scale) { - PrepareTestCase(sfType, scale, testValues); + PrepareTestCase(SFDataType.FIXED, scale, testValues); foreach (var testValue in testValues) { @@ -196,9 +195,8 @@ private void TestGetNumber(IEnumerable testValues) public void TestGetBoolean() { var testValues = new bool[] { true, false }; - var sfType = SFDataType.BOOLEAN; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.BOOLEAN, 0, testValues); foreach (var testValue in testValues) { @@ -212,9 +210,8 @@ public void TestGetBoolean() public void TestGetReal() { var testValues = new double[] { 0, Double.MinValue, Double.MaxValue }; - var sfType = SFDataType.REAL; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.REAL, 0, testValues); foreach (var testValue in testValues) { @@ -230,11 +227,10 @@ public void TestGetText() var testValues = new string[] { "", - "AAA $ BBB & CCC * (ZZZ) aaa zzz `~!@#$%^&*()_+-={}|[]\\;':\",./<>?" + TestDataGenarator.StringWithUnicode }; - var sfType = SFDataType.TEXT; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.TEXT, 0, testValues); foreach (var testValue in testValues) { @@ -244,26 +240,43 @@ public void TestGetText() } } + [Test] + public void TestGetTextWithOneChar() + { + var testValues = + TestDataGenarator.AsciiCodes.ToCharArray() + .Append(TestDataGenarator.SnowflakeUnicode) + .ToArray(); + + PrepareTestCase(SFDataType.TEXT, 0, testValues); + + foreach (var testValue in testValues) + { + _arrowResultSet.Next(); + Assert.AreEqual(testValue, _arrowResultSet.GetChar(ColumnIndex)); + } + } + [Test] public void TestGetArray() { var testValues = new string[] { "", - "AAA $ BBB & CCC * (ZZZ) aaa zzz `~!@#$%^&*()_+-={}|[]\\;':\",./<>?" + TestDataGenarator.StringWithUnicode }; - var sfType = SFDataType.ARRAY; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.ARRAY, 0, testValues); foreach (var testValue in testValues) { _arrowResultSet.Next(); Assert.AreEqual(testValue, _arrowResultSet.GetValue(ColumnIndex)); - char[] buffer = new char[100]; + char[] buffer = new char[1000]; var len = _arrowResultSet.GetChars(ColumnIndex, 0, buffer, 0, buffer.Length); - Assert.AreEqual(testValue.Length, len); - Assert.AreEqual(testValue, new String(buffer, 0, (int)len)); + var str = new String(buffer, 0, (int)len); + Assert.AreEqual(testValue, str); + Assert.AreEqual(testValue.Length, str.Length); } } @@ -275,9 +288,8 @@ public void TestGetBinary() new byte[] { }, new byte[] { 0, 19, 33, 200, 10, 13, 255 } }; - var sfType = SFDataType.BINARY; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.BINARY, 0, testValues); foreach (var testValue in testValues) { _arrowResultSet.Next(); @@ -299,9 +311,8 @@ public void TestGetDate() DateTime.Parse("0001-01-01"), DateTime.Parse("9999-12-31") }; - var sfType = SFDataType.DATE; - PrepareTestCase(sfType, 0, testValues); + PrepareTestCase(SFDataType.DATE, 0, testValues); foreach (var testValue in testValues) { @@ -320,12 +331,11 @@ public void TestGetTime() DateTime.Parse("0001-01-01 00:00:00.0000000"), DateTime.Parse("9999-12-31 23:59:59.9999999") }; - var sfType = SFDataType.TIME; - + for (var scale = 0; scale <= 7; ++scale) { var values = ArrowResultChunkTest.TruncateValues(testValues, scale); - PrepareTestCase(sfType, scale, values); + PrepareTestCase(SFDataType.TIME, scale, values); foreach (var testValue in values) { @@ -348,12 +358,11 @@ public void TestGetTimestampTz() DateTimeOffset.Parse("0001-01-01 00:00:00.0000000 +0000"), DateTimeOffset.Parse("9999-12-31 23:59:59.9999999 +0000"), }; - var sfType = SFDataType.TIMESTAMP_TZ; - + for (var scale = 0; scale <= 9; ++scale) { var values = ArrowResultChunkTest.TruncateValues(testValues, scale); - PrepareTestCase(sfType, scale, values); + PrepareTestCase(SFDataType.TIMESTAMP_TZ, scale, values); foreach (var testValue in values) { @@ -372,12 +381,11 @@ public void TestGetTimestampLtz() DateTimeOffset.Parse("0001-01-01 00:00:00.0000000 +0000").ToLocalTime(), DateTimeOffset.Parse("9999-12-31 23:59:59.9999999 +0000").ToLocalTime(), }; - var sfType = SFDataType.TIMESTAMP_LTZ; for (var scale = 0; scale <= 9; ++scale) { var values = ArrowResultChunkTest.TruncateValues(testValues, scale); - PrepareTestCase(sfType, scale, values); + PrepareTestCase(SFDataType.TIMESTAMP_LTZ, scale, values); foreach (var testValue in values) { @@ -396,12 +404,11 @@ public void TestGetTimestampNtz() DateTime.Parse("0001-01-01 00:00:00.0000000"), DateTime.Parse("9999-12-31 23:59:59.9999999") }; - var sfType = SFDataType.TIMESTAMP_NTZ; - + for (var scale = 0; scale <= 9; ++scale) { var values = ArrowResultChunkTest.TruncateValues(testValues, scale); - PrepareTestCase(sfType, scale, values); + PrepareTestCase(SFDataType.TIMESTAMP_NTZ, scale, values); foreach (var testValue in values) { diff --git a/Snowflake.Data.Tests/Util/SnowflakeDbConnectionWithResultFormat.cs b/Snowflake.Data.Tests/Util/SnowflakeDbConnectionWithResultFormat.cs deleted file mode 100644 index 3a8e4e815..000000000 --- a/Snowflake.Data.Tests/Util/SnowflakeDbConnectionWithResultFormat.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Snowflake.Data.Client; -using Snowflake.Data.Core; - -namespace Snowflake.Data.Tests.Util -{ - class SnowflakeDbConnectionWithResultFormat : SnowflakeDbConnection - { - private readonly ResultFormat _resultFormat; - - public SnowflakeDbConnectionWithResultFormat(ResultFormat resultFormat) - { - _resultFormat = resultFormat; - } - - public override void Open() - { - base.Open(); - - SessionParameterAlterer.SetResultFormat(this, _resultFormat); - } - - public override Task OpenAsync(CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - public override void Close() - { - if (IsOpen()) - SessionParameterAlterer.RestoreResultFormat(this); - - base.Close(); - } - - public override Task CloseAsync(CancellationToken cancellationToken) - { - throw new NotSupportedException(); - } - - } -} \ No newline at end of file diff --git a/Snowflake.Data.Tests/Util/TestDataGenarator.cs b/Snowflake.Data.Tests/Util/TestDataGenarator.cs index ded300a2b..27dda5ab0 100644 --- a/Snowflake.Data.Tests/Util/TestDataGenarator.cs +++ b/Snowflake.Data.Tests/Util/TestDataGenarator.cs @@ -3,6 +3,7 @@ */ using System; +using System.Linq; namespace Snowflake.Data.Tests.Util { @@ -16,6 +17,11 @@ public class TestDataGenarator private static string s_digitChars = "0" + s_nonZeroDigits; private static string s_letterChars = s_lowercaseChars + s_uppercaseChars; private static string s_alphanumericChars = s_letterChars + s_digitChars; + + public static string AsciiCodes => new String(Enumerable.Range(0, 256).Select(ch => (char)ch).ToArray()); + public static char SnowflakeUnicode => '\u2744'; + public static string EmojiUnicode => "\uD83D\uDE00"; + public static string StringWithUnicode => AsciiCodes + SnowflakeUnicode + EmojiUnicode; public static bool NextBool() { diff --git a/Snowflake.Data/Client/SnowflakeDbDataReader.cs b/Snowflake.Data/Client/SnowflakeDbDataReader.cs index 3a99043d8..20ca1f7ba 100755 --- a/Snowflake.Data/Client/SnowflakeDbDataReader.cs +++ b/Snowflake.Data/Client/SnowflakeDbDataReader.cs @@ -164,7 +164,7 @@ public override long GetChars(int ordinal, long dataOffset, char[] buffer, int b public override string GetDataTypeName(int ordinal) { - resultSet.ThrowIfOutOfBand(ordinal); + resultSet.ThrowIfOutOfBounds(ordinal); return resultSet.sfResultSetMetaData.GetColumnTypeByIndex(ordinal).ToString(); } @@ -195,7 +195,7 @@ public override IEnumerator GetEnumerator() public override Type GetFieldType(int ordinal) { - resultSet.ThrowIfOutOfBand(ordinal); + resultSet.ThrowIfOutOfBounds(ordinal); return resultSet.sfResultSetMetaData.GetCSharpTypeByIndex(ordinal); } @@ -226,7 +226,7 @@ public override long GetInt64(int ordinal) public override string GetName(int ordinal) { - resultSet.ThrowIfOutOfBand(ordinal); + resultSet.ThrowIfOutOfBounds(ordinal); return resultSet.sfResultSetMetaData.GetColumnNameByIndex(ordinal); } diff --git a/Snowflake.Data/Core/ArrowResultSet.cs b/Snowflake.Data/Core/ArrowResultSet.cs index 7ccf5d767..496d2867b 100755 --- a/Snowflake.Data/Core/ArrowResultSet.cs +++ b/Snowflake.Data/Core/ArrowResultSet.cs @@ -144,7 +144,7 @@ internal override bool Rewind() private object GetObjectInternal(int ordinal) { ThrowIfClosed(); - ThrowIfOutOfBand(ordinal); + ThrowIfOutOfBounds(ordinal); var type = sfResultSetMetaData.GetTypesByIndex(ordinal).Item1; var scale = sfResultSetMetaData.GetScaleByIndex(ordinal); @@ -161,11 +161,11 @@ internal override object GetValue(int ordinal) if (value == DBNull.Value) return value; - var dstType = sfResultSetMetaData.GetCSharpTypeByIndex(ordinal); - if (value is decimal ret) return ret; + var dstType = sfResultSetMetaData.GetCSharpTypeByIndex(ordinal); + return Convert.ChangeType(value, dstType); } @@ -384,8 +384,18 @@ private long ReadSubset(int ordinal, long dataOffset, T[] buffer, int bufferO var value = GetObjectInternal(ordinal); var type = sfResultSetMetaData.GetColumnTypeByIndex(ordinal); - var data = type == SFDataType.BINARY ? (byte[])value : Encoding.ASCII.GetBytes(value.ToString()); - + Array data; + if (type == SFDataType.BINARY) + data = (byte[])value; + else if (typeof(T) == typeof(byte)) + data = Encoding.ASCII.GetBytes(value.ToString()); + else + data = value.ToString().ToCharArray(); + + // https://docs.microsoft.com/en-us/dotnet/api/system.data.idatarecord.getbytes?view=net-5.0#remarks + // If you pass a buffer that is null, GetBytes returns the length of the row in bytes. + // https://docs.microsoft.com/en-us/dotnet/api/system.data.idatarecord.getchars?view=net-5.0#remarks + // If you pass a buffer that is null, GetChars returns the length of the field in characters. if (buffer == null) { return data.Length; diff --git a/Snowflake.Data/Core/SFBaseResultSet.cs b/Snowflake.Data/Core/SFBaseResultSet.cs index 96ff554ee..348865c1d 100755 --- a/Snowflake.Data/Core/SFBaseResultSet.cs +++ b/Snowflake.Data/Core/SFBaseResultSet.cs @@ -90,7 +90,7 @@ internal void ThrowIfClosed() throw new SnowflakeDbException(SFError.DATA_READER_ALREADY_CLOSED); } - internal void ThrowIfOutOfBand(int ordinal) + internal void ThrowIfOutOfBounds(int ordinal) { if (ordinal < 0 || ordinal >= columnCount) throw new SnowflakeDbException(SFError.COLUMN_INDEX_OUT_OF_BOUND, ordinal); diff --git a/Snowflake.Data/Core/SFResultSet.cs b/Snowflake.Data/Core/SFResultSet.cs index 703e9c8e7..764ce0907 100755 --- a/Snowflake.Data/Core/SFResultSet.cs +++ b/Snowflake.Data/Core/SFResultSet.cs @@ -178,7 +178,7 @@ internal override bool Rewind() internal UTF8Buffer GetObjectInternal(int ordinal) { ThrowIfClosed(); - ThrowIfOutOfBand(ordinal); + ThrowIfOutOfBounds(ordinal); return _currentChunk.ExtractCell(ordinal); } @@ -269,7 +269,7 @@ internal override long GetInt64(int ordinal) internal override string GetString(int ordinal) { - ThrowIfOutOfBand(ordinal); + ThrowIfOutOfBounds(ordinal); var type = sfResultSetMetaData.GetColumnTypeByIndex(ordinal); switch (type)