Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-1729244: Issue with Large TIMESTAMP_TZ Insertion via SnowflakeDbCommand in .NET #1036

Closed
skornsek opened this issue Oct 9, 2024 · 5 comments
Assignees
Labels
bug status-fixed_awaiting_release The issue has been fixed, its PR merged, and now awaiting the next release cycle of the connector. status-triage_done Initial triage done, will be further handled by the driver team

Comments

@skornsek
Copy link

skornsek commented Oct 9, 2024

Description:
There appears to be a bug when inserting large timestamps (e.g., 9999-12-30T23:00:00.0000000+00:00) into a TIMESTAMP_TZ column using the SnowflakeDbCommand in .NET. The issue does not occur when inserting the same value manually via Snowsight.

Steps to Reproduce:

  1. Create a Snowflake table with a TIMESTAMP_TZ column, such as:

    CREATE TABLE DATES_TESTING1 (
        ID NUMBER IDENTITY,
        CODE STRING NOT NULL,
        EFF_DT TIMESTAMP_TZ,
        END_DT TIMESTAMP_TZ,
        MODIFIED TIMESTAMP_TZ
    );
  2. Execute the following .NET code to insert the large timestamp:

    using Snowflake.Data.Client;
    using Snowflake.Data.Core;
    
    string connectionString = "CONNECTION_STRING";
    
    using (var connection = new SnowflakeDbConnection())
    {
        connection.ConnectionString = connectionString;
        connection.Open();
    
        string sqlCommand = @"
                    INSERT INTO ""DATES_TESTING1"" (""CODE"", ""MODIFIED"", ""EFF_DT"", ""END_DT"")
                    SELECT  :p1, :p2, :p3, :p4";
    
        using (var command = new SnowflakeDbCommand())
        {
            command.Connection = connection;
            command.CommandText = sqlCommand;
    
            command.Parameters.Add(new SnowflakeDbParameter("p1", SFDataType.TEXT) { Value = "DOTNET 4.1.0" });
            command.Parameters.Add(new SnowflakeDbParameter("p2", SFDataType.TIMESTAMP_TZ) { Value = DateTimeOffset.Parse("2024-10-08T16:14:12.5910721+00:00") });
            command.Parameters.Add(new SnowflakeDbParameter("p3", SFDataType.TIMESTAMP_TZ) { Value = DateTimeOffset.Parse("1899-12-31T23:00:00.0000000+00:00") });
            command.Parameters.Add(new SnowflakeDbParameter("p4", SFDataType.TIMESTAMP_TZ) { Value = DateTimeOffset.Parse("9999-12-30T23:00:00.0000000+00:00") });
    
            try
            {
                int rowsAffected = command.ExecuteNonQuery();
                Console.WriteLine($"{rowsAffected} rows inserted successfully.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error executing command: {ex.Message}");
            }
        }
    }
  3. Insert the same values manually via a SQL query using Snowsight, and the END_DT is stored correctly.

    INSERT INTO DATES_TESTING1 (CODE, MODIFIED, EFF_DT, END_DT)
    SELECT 'MANUAL', '2024-10-08T16:14:12.5910721+00:00', '1899-12-31T23:00:00.0000000+00:00', '9999-12-30T23:00:00.0000000+00:00';
  4. Check the DATES_TESTING1 table, and observe that the END_DT is stored as '1816-03-29 04:56:08.066 +0000' instead of the expected value '9999-12-30T23:00:00.0000000+00:00'.

    Select * FROM DATES_TESTING1;

    image

Expected Behavior:
The large timestamp value (9999-12-30T23:00:00.0000000+00:00) should be correctly inserted into the TIMESTAMP_TZ column using SnowflakeDbCommand.

Actual Behavior:
When using SnowflakeDbCommand to insert the large timestamp, the value is stored as '1816-03-29 04:56:08.066 +0000', which is incorrect.
Dates around 2300-12-31 work. Dates bigger than 2500-12-31 also get corrupted.

Additional Information:

  • .NET SDK version: 4.1.0
  • Database: Snowflake
  • SnowflakeDbCommand library: Snowflake.Data.Core
  • Windows 11, 64-bit operating system, x64-based processor
  • .NET SDK 8.0.400

This bug seems to affect large timestamp values when inserted via .NET, but works correctly with manual SQL queries executed in Snowsight.

@skornsek skornsek added the bug label Oct 9, 2024
@github-actions github-actions bot changed the title Issue with Large TIMESTAMP_TZ Insertion via SnowflakeDbCommand in .NET SNOW-1729244: Issue with Large TIMESTAMP_TZ Insertion via SnowflakeDbCommand in .NET Oct 9, 2024
@sfc-gh-dszmolka sfc-gh-dszmolka added the status-triage_done Initial triage done, will be further handled by the driver team label Oct 9, 2024
@sfc-gh-dszmolka
Copy link
Contributor

thank you for raising this issue and providing useful details! we'll take a look

@skornsek
Copy link
Author

skornsek commented Oct 9, 2024

I was debugging some more and I think the issue could probably be here in this piece of code:

namespace Snowflake.Data.Core;

internal static class SFDataConverter
...

internal static string csharpValToSfVal(SFDataType sfDataType, object srcVal)

...
case SFDataType.TIMESTAMP_TZ:
{
	if (srcVal.GetType() != typeof(DateTimeOffset))
	{
		throw new SnowflakeDbException(SFError.INVALID_DATA_CONVERSION, srcVal, srcVal.GetType().ToString(), DbType.DateTimeOffset.ToString());
	}
	DateTimeOffset dateTimeOffset = (DateTimeOffset)srcVal;
	long utcTicks2 = dateTimeOffset.UtcTicks;
	DateTime unixEpoch = UnixEpoch;
	result = $"{(utcTicks2 - unixEpoch.Ticks) * 100} {dateTimeOffset.Offset.TotalMinutes + 1440.0}";
	break;
}

For the dates above these values are generated:

  • UtcDateTime = {08/10/2024 16:14:12} -> 1728404052591072100 1440
  • UtcDateTime = {31/12/1899 23:00:00} -> -2208992400000000000 1440
  • UtcDateTime = {30/12/9999 23:00:00} -> -4852206231933722624 1440

In Snowflake I get these values:

-- Test timestamp for 1728404052591072100 ticks with 1440 offset (UTC)
SELECT TO_TIMESTAMP_TZ((1728404052591072100 / 1000000000) + ' 1440');
-- 2024-10-08 09:38:12.591 -0700

-- Test timestamp for -2208992400000000000 ticks with 1440 offset (UTC)
SELECT TO_TIMESTAMP_TZ((-2208992400000000000 / 1000000000) + ' 1440');
-- 1899-12-31 15:24:00.000 -0800

-- Test timestamp for -4852206231933722624 ticks with 1440 offset (UTC)
SELECT TO_TIMESTAMP_TZ((-4852206231933722624 / 1000000000) + ' 1440');
-- 1816-03-28 21:28:08.066 -0752

@sfc-gh-dszmolka
Copy link
Contributor

also linking the PR we have for the fix #1038

@sfc-gh-dszmolka sfc-gh-dszmolka added status-fixed_awaiting_release The issue has been fixed, its PR merged, and now awaiting the next release cycle of the connector. and removed status-pr_pending_merge A PR is made and is under review labels Oct 21, 2024
@sfc-gh-dszmolka
Copy link
Contributor

fix is merged and will be included with the next .NET driver release cycle

@sfc-gh-dszmolka
Copy link
Contributor

released with Snowflake .NET driver v4.2.0 in October 2024 release cycle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug status-fixed_awaiting_release The issue has been fixed, its PR merged, and now awaiting the next release cycle of the connector. status-triage_done Initial triage done, will be further handled by the driver team
Projects
None yet
Development

No branches or pull requests

3 participants