From 2119080ab3f84be658b92cae0deae415ceb7f9c2 Mon Sep 17 00:00:00 2001 From: Juan Martinez Ramirez <126511805+sfc-gh-jmartinez@users.noreply.github.com> Date: Wed, 29 May 2024 16:25:19 -0600 Subject: [PATCH 1/3] SNOW-991583: Assembly delay sign (#956) ### Description Add delay sign for Snowflake Data assemblies. ### Checklist - [x] Code compiles correctly - [x] Code is formatted according to [Coding Conventions](../blob/master/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 --- Snowflake.Data.Tests/Snowflake.Data.Tests.csproj | 9 +++++++++ Snowflake.Data/Snowflake.Data.csproj | 13 +++++++++++-- deploy.bat | 6 +++++- sign/publicKey.snk | Bin 0 -> 160 bytes 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 sign/publicKey.snk diff --git a/Snowflake.Data.Tests/Snowflake.Data.Tests.csproj b/Snowflake.Data.Tests/Snowflake.Data.Tests.csproj index 0188d4552..aad9b2e84 100644 --- a/Snowflake.Data.Tests/Snowflake.Data.Tests.csproj +++ b/Snowflake.Data.Tests/Snowflake.Data.Tests.csproj @@ -11,6 +11,9 @@ true 9 $(SEQUENTIAL_ENV) + ..\sign\publicKey.snk + true + true @@ -37,6 +40,12 @@ + + + publicKey.snk + + + full True diff --git a/Snowflake.Data/Snowflake.Data.csproj b/Snowflake.Data/Snowflake.Data.csproj index 4caf957af..e43d61ea1 100644 --- a/Snowflake.Data/Snowflake.Data.csproj +++ b/Snowflake.Data/Snowflake.Data.csproj @@ -15,6 +15,9 @@ 3.1.0 Full 7.3 + ..\sign\publicKey.snk + true + true @@ -40,9 +43,9 @@ - + - + @@ -64,4 +67,10 @@ + + + + publicKey.snk + + diff --git a/deploy.bat b/deploy.bat index 90d0bb00f..6b808c371 100644 --- a/deploy.bat +++ b/deploy.bat @@ -5,6 +5,10 @@ SET API_KEY=%2 SET ROOT_DIR=%~dp0 cd %ROOT_DIR% -dotnet pack Snowflake.Data\Snowflake.Data.csproj -c Release --force -v n --output %ROOT_DIR% +dotnet build Snowflake.Data\Snowflake.Data.csproj -c Release --force -v n + +REM command to sign with strong name Snowflake.Data.dll should be here + +dotnet pack Snowflake.Data\Snowflake.Data.csproj -c Release --force -v n --no-build --output %ROOT_DIR% dotnet nuget push Snowflake.Data.%VERSION%.nupkg -k %API_KEY% -s https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/sign/publicKey.snk b/sign/publicKey.snk new file mode 100644 index 0000000000000000000000000000000000000000..7b78e9478ea641690a3c56b25873d25402a34366 GIT binary patch literal 160 zcmV;R0AK$ABme*efB*oL000060ssI2Bme+XQ$aBR1ONa50098OS!6uFG3mR$c_0ZK zIqbcdi#`x7_GE(#Gx02)gNp}7HiDFlwQIaVLlOD`oomV+z>CS%MucX6-IU$&K=hf+ zwr7EFw7A3faw literal 0 HcmV?d00001 From 33fe6e89af03d3589411d0b7ce9d47e8b7a6478b Mon Sep 17 00:00:00 2001 From: Krzysztof Nozderko Date: Fri, 7 Jun 2024 09:54:58 +0200 Subject: [PATCH 2/3] SNOW-1463590 Bump BouncyCastle.Cryptography dependency to 2.3.1 (#964) ### Description SNOW-1463590 Bump BouncyCastle.Cryptography dependency to 2.3.1 ### Checklist - [x] Code compiles correctly - [x] Code is formatted according to [Coding Conventions](../blob/master/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 --- Snowflake.Data/Snowflake.Data.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Snowflake.Data/Snowflake.Data.csproj b/Snowflake.Data/Snowflake.Data.csproj index e43d61ea1..c66ce5594 100644 --- a/Snowflake.Data/Snowflake.Data.csproj +++ b/Snowflake.Data/Snowflake.Data.csproj @@ -29,7 +29,7 @@ - + From db8e4d590fee9ee1c7e9047ef7e59b74d91b5591 Mon Sep 17 00:00:00 2001 From: Dariusz Stempniak Date: Fri, 7 Jun 2024 09:57:09 +0200 Subject: [PATCH 3/3] SNOW-1433638 sql trimming only for PUT/GET detection (#957) ### Description SNOW-1433638 sql trimming only for PUT/GET detection Symbol -- cannot be treated as a string. ### Checklist - [x] Code compiles correctly - [x] Code is formatted according to [Coding Conventions](../blob/master/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 --- .../IntegrationTests/SFDbCommandIT.cs | 50 +++++++++++++++---- .../UnitTests/SFStatementTest.cs | 44 ++++++---------- Snowflake.Data/Core/SFStatement.cs | 44 ++++++++-------- 3 files changed, 79 insertions(+), 59 deletions(-) diff --git a/Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs b/Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs index 3a3cfb82f..8891e2e2a 100755 --- a/Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs +++ b/Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs @@ -129,7 +129,7 @@ public void TestCancelExecuteAsync() } catch { - // assert that cancel is not triggered by timeout, but external cancellation + // assert that cancel is not triggered by timeout, but external cancellation Assert.IsTrue(externalCancel.IsCancellationRequested); } Thread.Sleep(2000); @@ -503,7 +503,7 @@ public void TestRowsAffectedOverflowInt() using (IDbConnection conn = new SnowflakeDbConnection(ConnectionString)) { conn.Open(); - + CreateOrReplaceTable(conn, TableName, new []{"c1 NUMBER"}); using (IDbCommand command = conn.CreateCommand()) @@ -608,7 +608,7 @@ public void TestSimpleLargeResultSet() conn.Close(); } } - + [Test, NonParallelizable] public void TestUseV1ResultParser() { @@ -1021,13 +1021,13 @@ public void testPutArrayBindAsync() private void ArrayBindTest(string connstr, string tableName, int size) { - + CancellationTokenSource externalCancel = new CancellationTokenSource(TimeSpan.FromSeconds(100)); using (DbConnection conn = new SnowflakeDbConnection()) { conn.ConnectionString = connstr; conn.Open(); - + CreateOrReplaceTable(conn, tableName, new [] { "cola INTEGER", @@ -1197,7 +1197,7 @@ public void testExecuteScalarAsyncSelect() { conn.ConnectionString = ConnectionString; conn.Open(); - + CreateOrReplaceTable(conn, TableName, new []{"cola INTEGER"}); using (DbCommand cmd = conn.CreateCommand()) @@ -1624,7 +1624,7 @@ public void TestGetResultsOfUnknownQueryIdWithConfiguredRetry() conn.Close(); } } - + [Test] public void TestSetQueryTagOverridesConnectionString() { @@ -1633,16 +1633,48 @@ public void TestSetQueryTagOverridesConnectionString() string expectedQueryTag = "Test QUERY_TAG 12345"; string connectQueryTag = "Test 123"; conn.ConnectionString = ConnectionString + $";query_tag={connectQueryTag}"; - + conn.Open(); var command = conn.CreateCommand(); ((SnowflakeDbCommand)command).QueryTag = expectedQueryTag; // This query itself will be part of the history and will have the query tag command.CommandText = "SELECT QUERY_TAG FROM table(information_schema.query_history_by_session())"; var queryTag = command.ExecuteScalar(); - + Assert.AreEqual(expectedQueryTag, queryTag); } } + + [Test] + public void TestCommandWithCommentEmbedded() + { + using (var conn = new SnowflakeDbConnection(ConnectionString)) + { + conn.Open(); + var command = conn.CreateCommand(); + + command.CommandText = "\r\nselect '--'\r\n"; + var reader = command.ExecuteReader(); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("--", reader.GetString(0)); + } + } + + [Test] + public async Task TestCommandWithCommentEmbeddedAsync() + { + using (var conn = new SnowflakeDbConnection(ConnectionString)) + { + conn.Open(); + var command = conn.CreateCommand(); + + command.CommandText = "\r\nselect '--'\r\n"; + var reader = await command.ExecuteReaderAsync().ConfigureAwait(false); + + Assert.IsTrue(await reader.ReadAsync().ConfigureAwait(false)); + Assert.AreEqual("--", reader.GetString(0)); + } + } } } diff --git a/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs b/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs index 24f0f4b0a..3f131e924 100755 --- a/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFStatementTest.cs @@ -70,13 +70,10 @@ public void TestServiceName() [Test] public void TestTrimSqlBlockComment() { - Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec(); - SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester); - sfSession.Open(); - SFStatement statement = new SFStatement(sfSession); - SFBaseResultSet resultSet = statement.Execute(0, "/*comment*/select 1/*comment*/", null, false, false); - Assert.AreEqual(true, resultSet.Next()); - Assert.AreEqual("1", resultSet.GetString(0)); + const string SqlSource = "/*comment*/select 1/*comment*/"; + const string SqlExpected = "select 1"; + + Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource)); } /// @@ -85,13 +82,10 @@ public void TestTrimSqlBlockComment() [Test] public void TestTrimSqlBlockCommentMultiline() { - Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec(); - SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester); - sfSession.Open(); - SFStatement statement = new SFStatement(sfSession); - SFBaseResultSet resultSet = statement.Execute(0, "/*comment\r\ncomment*/select 1/*comment\r\ncomment*/", null, false, false); - Assert.AreEqual(true, resultSet.Next()); - Assert.AreEqual("1", resultSet.GetString(0)); + const string SqlSource = "/*comment\r\ncomment*/select 1/*comment\r\ncomment*/"; + const string SqlExpected = "select 1"; + + Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource)); } /// @@ -100,13 +94,10 @@ public void TestTrimSqlBlockCommentMultiline() [Test] public void TestTrimSqlLineComment() { - Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec(); - SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester); - sfSession.Open(); - SFStatement statement = new SFStatement(sfSession); - SFBaseResultSet resultSet = statement.Execute(0, "--comment\r\nselect 1\r\n--comment", null, false, false); - Assert.AreEqual(true, resultSet.Next()); - Assert.AreEqual("1", resultSet.GetString(0)); + const string SqlSource = "--comment\r\nselect 1\r\n--comment"; + const string SqlExpected = "select 1\r\n--comment"; + + Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource)); } /// @@ -115,13 +106,10 @@ public void TestTrimSqlLineComment() [Test] public void TestTrimSqlLineCommentWithClosingNewline() { - Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec(); - SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester); - sfSession.Open(); - SFStatement statement = new SFStatement(sfSession); - SFBaseResultSet resultSet = statement.Execute(0, "--comment\r\nselect 1\r\n--comment\r\n", null, false, false); - Assert.AreEqual(true, resultSet.Next()); - Assert.AreEqual("1", resultSet.GetString(0)); + const string SqlSource = "--comment\r\nselect 1\r\n--comment\r\n"; + const string SqlExpected = "select 1"; + + Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource)); } [Test] diff --git a/Snowflake.Data/Core/SFStatement.cs b/Snowflake.Data/Core/SFStatement.cs index 787bfa5de..e84690d54 100644 --- a/Snowflake.Data/Core/SFStatement.cs +++ b/Snowflake.Data/Core/SFStatement.cs @@ -110,9 +110,9 @@ class SFStatement private const string SF_QUERY_RESULT_PATH = "/queries/{0}/result"; private const string SF_PARAM_MULTI_STATEMENT_COUNT = "MULTI_STATEMENT_COUNT"; - + private const string SF_PARAM_QUERY_TAG = "QUERY_TAG"; - + private const int SF_QUERY_IN_PROGRESS = 333333; private const int SF_QUERY_IN_PROGRESS_ASYNC = 333334; @@ -124,8 +124,8 @@ class SFStatement private readonly IRestRequester _restRequester; private CancellationTokenSource _timeoutTokenSource; - - // Merged cancellation token source for all cancellation signal. + + // Merged cancellation token source for all cancellation signal. // Cancel callback will be registered under token issued by this source. private CancellationTokenSource _linkedCancellationTokenSource; @@ -151,21 +151,21 @@ internal SFStatement(SFSession session) _restRequester = session.restRequester; _queryTag = session._queryTag; } - - internal SFStatement(SFSession session, string queryTag) + + internal SFStatement(SFSession session, string queryTag) { SfSession = session; _restRequester = session.restRequester; - _queryTag = queryTag ?? session._queryTag; + _queryTag = queryTag ?? session._queryTag; } - + internal string GetBindStage() => _bindStage; private void AssignQueryRequestId() { lock (_requestIdLock) { - + if (_requestId != null) { logger.Info("Another query is running."); @@ -207,8 +207,8 @@ private SFRestRequest BuildQueryRequest(string sql, Dictionary(); } bodyParameters[SF_PARAM_QUERY_TAG] = _queryTag; - } + } QueryRequest postBody = new QueryRequest(); postBody.sqlText = sql; @@ -317,7 +317,7 @@ private void SetTimeout(int timeout) this._timeoutTokenSource = timeout > 0 ? new CancellationTokenSource(timeout * 1000) : new CancellationTokenSource(Timeout.InfiniteTimeSpan); } - + /// /// Register cancel callback. Two factors: either external cancellation token passed down from upper /// layer or timeout reached. Whichever comes first would trigger query cancellation. @@ -363,7 +363,7 @@ internal async Task ExecuteAsync(int timeout, string sql, Dicti } registerQueryCancellationCallback(timeout, cancellationToken); - + int arrayBindingThreshold = 0; if (SfSession.ParameterMap.ContainsKey(SFSessionParameter.CLIENT_STAGE_ARRAY_BINDING_THRESHOLD)) { @@ -457,10 +457,10 @@ internal SFBaseResultSet Execute(int timeout, string sql, Dictionary bindings, bool describeOnly) + private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, string trimmedSql, Dictionary bindings, bool describeOnly) { try { @@ -484,7 +484,7 @@ private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, Dictionary logger.Debug("PUT/GET queryId: " + (response.data != null ? response.data.queryId : "Unknown")); SFFileTransferAgent fileTransferAgent = - new SFFileTransferAgent(sql, SfSession, response.data, CancellationToken.None); + new SFFileTransferAgent(trimmedSql, SfSession, response.data, CancellationToken.None); // Start the file transfer fileTransferAgent.execute(); @@ -507,7 +507,7 @@ private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, Dictionary throw new SnowflakeDbException(ex, SFError.INTERNAL_ERROR); } } - + private SFBaseResultSet ExecuteSqlOtherThanPutGet(int timeout, string sql, Dictionary bindings, bool describeOnly, bool asyncExec) { try @@ -562,7 +562,7 @@ private SFBaseResultSet ExecuteSqlOtherThanPutGet(int timeout, string sql, Dicti throw; } } - + internal async Task GetResultWithIdAsync(string resultId, CancellationToken cancellationToken) { var req = BuildResultRequestWithId(resultId); @@ -938,7 +938,7 @@ internal async Task GetQueryStatusAsync(string queryId, Cancellatio /// /// The original sql query. /// The query without the blanks and comments at the beginning. - private string TrimSql(string originalSql) + internal static string TrimSql(string originalSql) { char[] sqlQueryBuf = originalSql.ToCharArray(); var builder = new StringBuilder(); @@ -1054,7 +1054,7 @@ internal SFBaseResultSet ExecuteTransfer(string sql) false); PutGetStageInfo stageInfo = new PutGetStageInfo(); - + SFFileTransferAgent fileTransferAgent = new SFFileTransferAgent(sql, SfSession, response.data, ref _uploadStream, _destFilename, _stagePath, CancellationToken.None);