-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SNOW-1271212 Fixed values uploaded to stage for bindings exceeding CL…
…IENT_STAGE_ARRAY_BINDING_THRESHOLD (#897) ### Description When number of binded values during query execution exceeds the threshold of a session parameter CLIENT_STAGE_ARRAY_BINDING_THRESHOLD then values are written as a CSV file to a stage and it get's picked during query execution. Improper values (or values truncating nanos) has been uploaded prior to this fix for date and time related columns of type: DATE, TIME, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ. ### Checklist - [x] Code compiles correctly - [x] Code is formatted according to [Coding Conventions](../CodingConventions.md) - [x] Created tests which fail without the change (if possible) - [x] All tests passing (`dotnet test`) - [x] Extended the README / documentation, if necessary - [x] Provide JIRA issue id (if possible) or GitHub issue id in PR name
- Loading branch information
1 parent
a302e0f
commit dfba44e
Showing
9 changed files
with
454 additions
and
47 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved. | ||
*/ | ||
|
||
using System; | ||
using NUnit.Framework; | ||
using Snowflake.Data.Core; | ||
|
||
namespace Snowflake.Data.Tests.UnitTests | ||
{ | ||
[TestFixture] | ||
class SFBindUploaderTest | ||
{ | ||
private readonly SFBindUploader _bindUploader = new SFBindUploader(null, "test"); | ||
|
||
[TestCase(SFDataType.DATE, "0", "1/1/1970")] | ||
[TestCase(SFDataType.DATE, "73785600000", "5/4/1972")] | ||
[TestCase(SFDataType.DATE, "1709164800000", "2/29/2024")] | ||
public void TestCsvDataConversionForDate(SFDataType dbType, string input, string expected) | ||
{ | ||
// Arrange | ||
var dateExpected = DateTime.Parse(expected); | ||
var check = SFDataConverter.csharpValToSfVal(SFDataType.DATE, dateExpected); | ||
Assert.AreEqual(check, input); | ||
// Act | ||
DateTime dateActual = DateTime.Parse(_bindUploader.GetCSVData(dbType.ToString(), input)); | ||
// Assert | ||
Assert.AreEqual(dateExpected, dateActual); | ||
} | ||
|
||
[TestCase(SFDataType.TIME, "0", "00:00:00.000000")] | ||
[TestCase(SFDataType.TIME, "100000000", "00:00:00.100000")] | ||
[TestCase(SFDataType.TIME, "1000000000", "00:00:01.000000")] | ||
[TestCase(SFDataType.TIME, "60123456000", "00:01:00.123456")] | ||
[TestCase(SFDataType.TIME, "46801000000000", "13:00:01.000000")] | ||
public void TestCsvDataConversionForTime(SFDataType dbType, string input, string expected) | ||
{ | ||
// Arrange | ||
DateTime timeExpected = DateTime.Parse(expected); | ||
var check = SFDataConverter.csharpValToSfVal(SFDataType.TIME, timeExpected); | ||
Assert.AreEqual(check, input); | ||
// Act | ||
DateTime timeActual = DateTime.Parse(_bindUploader.GetCSVData(dbType.ToString(), input)); | ||
// Assert | ||
Assert.AreEqual(timeExpected, timeActual); | ||
} | ||
|
||
[TestCase(SFDataType.TIMESTAMP_LTZ, "39600000000000", "1970-01-01T12:00:00.0000000+01:00")] | ||
[TestCase(SFDataType.TIMESTAMP_LTZ, "1341136800000000000", "2012-07-01T12:00:00.0000000+02:00")] | ||
[TestCase(SFDataType.TIMESTAMP_LTZ, "352245599987654000", "1981-02-28T23:59:59.9876540+02:00")] | ||
[TestCase(SFDataType.TIMESTAMP_LTZ, "1678868249207000000", "2023/03/15T13:17:29.207+05:00")] | ||
public void TestCsvDataConversionForTimestampLtz(SFDataType dbType, string input, string expected) | ||
{ | ||
// Arrange | ||
var timestampExpected = DateTimeOffset.Parse(expected); | ||
var check = SFDataConverter.csharpValToSfVal(SFDataType.TIMESTAMP_LTZ, timestampExpected); | ||
Assert.AreEqual(check, input); | ||
// Act | ||
var timestampActual = DateTimeOffset.Parse(_bindUploader.GetCSVData(dbType.ToString(), input)); | ||
// Assert | ||
Assert.AreEqual(timestampExpected.ToLocalTime(), timestampActual); | ||
} | ||
|
||
[TestCase(SFDataType.TIMESTAMP_TZ, "1341136800000000000 1560", "2012-07-01 12:00:00.000000 +02:00")] | ||
[TestCase(SFDataType.TIMESTAMP_TZ, "352245599987654000 1560", "1981-02-28 23:59:59.987654 +02:00")] | ||
public void TestCsvDataConversionForTimestampTz(SFDataType dbType, string input, string expected) | ||
{ | ||
// Arrange | ||
DateTimeOffset timestampExpected = DateTimeOffset.Parse(expected); | ||
var check = SFDataConverter.csharpValToSfVal(SFDataType.TIMESTAMP_TZ, timestampExpected); | ||
Assert.AreEqual(check, input); | ||
// Act | ||
DateTimeOffset timestampActual = DateTimeOffset.Parse(_bindUploader.GetCSVData(dbType.ToString(), input)); | ||
// Assert | ||
Assert.AreEqual(timestampExpected, timestampActual); | ||
} | ||
|
||
[TestCase(SFDataType.TIMESTAMP_NTZ, "1341144000000000000", "2012-07-01 12:00:00.000000")] | ||
[TestCase(SFDataType.TIMESTAMP_NTZ, "352252799987654000", "1981-02-28 23:59:59.987654")] | ||
public void TestCsvDataConversionForTimestampNtz(SFDataType dbType, string input, string expected) | ||
{ | ||
// Arrange | ||
DateTime timestampExpected = DateTime.Parse(expected); | ||
var check = SFDataConverter.csharpValToSfVal(SFDataType.TIMESTAMP_NTZ, timestampExpected); | ||
Assert.AreEqual(check, input); | ||
// Act | ||
DateTime timestampActual = DateTime.Parse(_bindUploader.GetCSVData(dbType.ToString(), input)); | ||
// Assert | ||
Assert.AreEqual(timestampExpected, timestampActual); | ||
} | ||
|
||
[TestCase(SFDataType.TEXT, "", "\"\"")] | ||
[TestCase(SFDataType.TEXT, "\"", "\"\"\"\"")] | ||
[TestCase(SFDataType.TEXT, "\n", "\"\n\"")] | ||
[TestCase(SFDataType.TEXT, "\t", "\"\t\"")] | ||
[TestCase(SFDataType.TEXT, ",", "\",\"")] | ||
[TestCase(SFDataType.TEXT, "Sample text", "Sample text")] | ||
public void TestCsvDataConversionForText(SFDataType dbType, string input, string expected) | ||
{ | ||
// Act | ||
var actual = _bindUploader.GetCSVData(dbType.ToString(), input); | ||
// Assert | ||
Assert.AreEqual(expected, actual); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System.Data; | ||
|
||
namespace Snowflake.Data.Tests.Util | ||
{ | ||
public static class DbCommandExtensions | ||
{ | ||
internal static IDbDataParameter Add(this IDbCommand command, string name, DbType dbType, object value) | ||
{ | ||
var parameter = command.CreateParameter(); | ||
parameter.ParameterName = name; | ||
parameter.DbType = dbType; | ||
parameter.Value = value; | ||
command.Parameters.Add(parameter); | ||
return parameter; | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System.Data; | ||
|
||
namespace Snowflake.Data.Tests.Util | ||
{ | ||
public static class DbConnectionExtensions | ||
{ | ||
internal static IDbCommand CreateCommand(this IDbConnection connection, string commandText) | ||
{ | ||
var command = connection.CreateCommand(); | ||
command.Connection = connection; | ||
command.CommandText = commandText; | ||
return command; | ||
} | ||
|
||
internal static int ExecuteNonQuery(this IDbConnection connection, string commandText) | ||
{ | ||
var command = connection.CreateCommand(); | ||
command.Connection = connection; | ||
command.CommandText = commandText; | ||
return command.ExecuteNonQuery(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using NUnit.Framework; | ||
|
||
namespace Snowflake.Data.Tests.Util | ||
{ | ||
public enum SFTableType | ||
{ | ||
Standard, | ||
Hybrid, | ||
Iceberg | ||
} | ||
|
||
static class TableTypeExtensions | ||
{ | ||
internal static string TableDDLCreationPrefix(this SFTableType val) => val == SFTableType.Standard ? "" : val.ToString().ToUpper(); | ||
|
||
internal static string TableDDLCreationFlags(this SFTableType val) | ||
{ | ||
if (val != SFTableType.Iceberg) | ||
return ""; | ||
var externalVolume = Environment.GetEnvironmentVariable("ICEBERG_EXTERNAL_VOLUME"); | ||
var catalog = Environment.GetEnvironmentVariable("ICEBERG_CATALOG"); | ||
var baseLocation = Environment.GetEnvironmentVariable("ICEBERG_BASE_LOCATION"); | ||
Assert.IsNotNull(externalVolume, "env ICEBERG_EXTERNAL_VOLUME not set!"); | ||
Assert.IsNotNull(catalog, "env ICEBERG_CATALOG not set!"); | ||
Assert.IsNotNull(baseLocation, "env ICEBERG_BASE_LOCATION not set!"); | ||
return $"EXTERNAL_VOLUME = '{externalVolume}' CATALOG = '{catalog}' BASE_LOCATION = '{baseLocation}'"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters