Skip to content

Commit db8e4d5

Browse files
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
1 parent 33fe6e8 commit db8e4d5

File tree

3 files changed

+79
-59
lines changed

3 files changed

+79
-59
lines changed

Snowflake.Data.Tests/IntegrationTests/SFDbCommandIT.cs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public void TestCancelExecuteAsync()
129129
}
130130
catch
131131
{
132-
// assert that cancel is not triggered by timeout, but external cancellation
132+
// assert that cancel is not triggered by timeout, but external cancellation
133133
Assert.IsTrue(externalCancel.IsCancellationRequested);
134134
}
135135
Thread.Sleep(2000);
@@ -503,7 +503,7 @@ public void TestRowsAffectedOverflowInt()
503503
using (IDbConnection conn = new SnowflakeDbConnection(ConnectionString))
504504
{
505505
conn.Open();
506-
506+
507507
CreateOrReplaceTable(conn, TableName, new []{"c1 NUMBER"});
508508

509509
using (IDbCommand command = conn.CreateCommand())
@@ -608,7 +608,7 @@ public void TestSimpleLargeResultSet()
608608
conn.Close();
609609
}
610610
}
611-
611+
612612
[Test, NonParallelizable]
613613
public void TestUseV1ResultParser()
614614
{
@@ -1021,13 +1021,13 @@ public void testPutArrayBindAsync()
10211021

10221022
private void ArrayBindTest(string connstr, string tableName, int size)
10231023
{
1024-
1024+
10251025
CancellationTokenSource externalCancel = new CancellationTokenSource(TimeSpan.FromSeconds(100));
10261026
using (DbConnection conn = new SnowflakeDbConnection())
10271027
{
10281028
conn.ConnectionString = connstr;
10291029
conn.Open();
1030-
1030+
10311031
CreateOrReplaceTable(conn, tableName, new []
10321032
{
10331033
"cola INTEGER",
@@ -1197,7 +1197,7 @@ public void testExecuteScalarAsyncSelect()
11971197
{
11981198
conn.ConnectionString = ConnectionString;
11991199
conn.Open();
1200-
1200+
12011201
CreateOrReplaceTable(conn, TableName, new []{"cola INTEGER"});
12021202

12031203
using (DbCommand cmd = conn.CreateCommand())
@@ -1624,7 +1624,7 @@ public void TestGetResultsOfUnknownQueryIdWithConfiguredRetry()
16241624
conn.Close();
16251625
}
16261626
}
1627-
1627+
16281628
[Test]
16291629
public void TestSetQueryTagOverridesConnectionString()
16301630
{
@@ -1633,16 +1633,48 @@ public void TestSetQueryTagOverridesConnectionString()
16331633
string expectedQueryTag = "Test QUERY_TAG 12345";
16341634
string connectQueryTag = "Test 123";
16351635
conn.ConnectionString = ConnectionString + $";query_tag={connectQueryTag}";
1636-
1636+
16371637
conn.Open();
16381638
var command = conn.CreateCommand();
16391639
((SnowflakeDbCommand)command).QueryTag = expectedQueryTag;
16401640
// This query itself will be part of the history and will have the query tag
16411641
command.CommandText = "SELECT QUERY_TAG FROM table(information_schema.query_history_by_session())";
16421642
var queryTag = command.ExecuteScalar();
1643-
1643+
16441644
Assert.AreEqual(expectedQueryTag, queryTag);
16451645
}
16461646
}
1647+
1648+
[Test]
1649+
public void TestCommandWithCommentEmbedded()
1650+
{
1651+
using (var conn = new SnowflakeDbConnection(ConnectionString))
1652+
{
1653+
conn.Open();
1654+
var command = conn.CreateCommand();
1655+
1656+
command.CommandText = "\r\nselect '--'\r\n";
1657+
var reader = command.ExecuteReader();
1658+
1659+
Assert.IsTrue(reader.Read());
1660+
Assert.AreEqual("--", reader.GetString(0));
1661+
}
1662+
}
1663+
1664+
[Test]
1665+
public async Task TestCommandWithCommentEmbeddedAsync()
1666+
{
1667+
using (var conn = new SnowflakeDbConnection(ConnectionString))
1668+
{
1669+
conn.Open();
1670+
var command = conn.CreateCommand();
1671+
1672+
command.CommandText = "\r\nselect '--'\r\n";
1673+
var reader = await command.ExecuteReaderAsync().ConfigureAwait(false);
1674+
1675+
Assert.IsTrue(await reader.ReadAsync().ConfigureAwait(false));
1676+
Assert.AreEqual("--", reader.GetString(0));
1677+
}
1678+
}
16471679
}
16481680
}

Snowflake.Data.Tests/UnitTests/SFStatementTest.cs

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,10 @@ public void TestServiceName()
7070
[Test]
7171
public void TestTrimSqlBlockComment()
7272
{
73-
Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec();
74-
SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester);
75-
sfSession.Open();
76-
SFStatement statement = new SFStatement(sfSession);
77-
SFBaseResultSet resultSet = statement.Execute(0, "/*comment*/select 1/*comment*/", null, false, false);
78-
Assert.AreEqual(true, resultSet.Next());
79-
Assert.AreEqual("1", resultSet.GetString(0));
73+
const string SqlSource = "/*comment*/select 1/*comment*/";
74+
const string SqlExpected = "select 1";
75+
76+
Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource));
8077
}
8178

8279
/// <summary>
@@ -85,13 +82,10 @@ public void TestTrimSqlBlockComment()
8582
[Test]
8683
public void TestTrimSqlBlockCommentMultiline()
8784
{
88-
Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec();
89-
SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester);
90-
sfSession.Open();
91-
SFStatement statement = new SFStatement(sfSession);
92-
SFBaseResultSet resultSet = statement.Execute(0, "/*comment\r\ncomment*/select 1/*comment\r\ncomment*/", null, false, false);
93-
Assert.AreEqual(true, resultSet.Next());
94-
Assert.AreEqual("1", resultSet.GetString(0));
85+
const string SqlSource = "/*comment\r\ncomment*/select 1/*comment\r\ncomment*/";
86+
const string SqlExpected = "select 1";
87+
88+
Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource));
9589
}
9690

9791
/// <summary>
@@ -100,13 +94,10 @@ public void TestTrimSqlBlockCommentMultiline()
10094
[Test]
10195
public void TestTrimSqlLineComment()
10296
{
103-
Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec();
104-
SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester);
105-
sfSession.Open();
106-
SFStatement statement = new SFStatement(sfSession);
107-
SFBaseResultSet resultSet = statement.Execute(0, "--comment\r\nselect 1\r\n--comment", null, false, false);
108-
Assert.AreEqual(true, resultSet.Next());
109-
Assert.AreEqual("1", resultSet.GetString(0));
97+
const string SqlSource = "--comment\r\nselect 1\r\n--comment";
98+
const string SqlExpected = "select 1\r\n--comment";
99+
100+
Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource));
110101
}
111102

112103
/// <summary>
@@ -115,13 +106,10 @@ public void TestTrimSqlLineComment()
115106
[Test]
116107
public void TestTrimSqlLineCommentWithClosingNewline()
117108
{
118-
Mock.MockRestSessionExpiredInQueryExec restRequester = new Mock.MockRestSessionExpiredInQueryExec();
119-
SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester);
120-
sfSession.Open();
121-
SFStatement statement = new SFStatement(sfSession);
122-
SFBaseResultSet resultSet = statement.Execute(0, "--comment\r\nselect 1\r\n--comment\r\n", null, false, false);
123-
Assert.AreEqual(true, resultSet.Next());
124-
Assert.AreEqual("1", resultSet.GetString(0));
109+
const string SqlSource = "--comment\r\nselect 1\r\n--comment\r\n";
110+
const string SqlExpected = "select 1";
111+
112+
Assert.AreEqual(SqlExpected, SFStatement.TrimSql(SqlSource));
125113
}
126114

127115
[Test]

Snowflake.Data/Core/SFStatement.cs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ class SFStatement
110110
private const string SF_QUERY_RESULT_PATH = "/queries/{0}/result";
111111

112112
private const string SF_PARAM_MULTI_STATEMENT_COUNT = "MULTI_STATEMENT_COUNT";
113-
113+
114114
private const string SF_PARAM_QUERY_TAG = "QUERY_TAG";
115-
115+
116116
private const int SF_QUERY_IN_PROGRESS = 333333;
117117

118118
private const int SF_QUERY_IN_PROGRESS_ASYNC = 333334;
@@ -124,8 +124,8 @@ class SFStatement
124124
private readonly IRestRequester _restRequester;
125125

126126
private CancellationTokenSource _timeoutTokenSource;
127-
128-
// Merged cancellation token source for all cancellation signal.
127+
128+
// Merged cancellation token source for all cancellation signal.
129129
// Cancel callback will be registered under token issued by this source.
130130
private CancellationTokenSource _linkedCancellationTokenSource;
131131

@@ -151,21 +151,21 @@ internal SFStatement(SFSession session)
151151
_restRequester = session.restRequester;
152152
_queryTag = session._queryTag;
153153
}
154-
155-
internal SFStatement(SFSession session, string queryTag)
154+
155+
internal SFStatement(SFSession session, string queryTag)
156156
{
157157
SfSession = session;
158158
_restRequester = session.restRequester;
159-
_queryTag = queryTag ?? session._queryTag;
159+
_queryTag = queryTag ?? session._queryTag;
160160
}
161-
161+
162162
internal string GetBindStage() => _bindStage;
163163

164164
private void AssignQueryRequestId()
165165
{
166166
lock (_requestIdLock)
167167
{
168-
168+
169169
if (_requestId != null)
170170
{
171171
logger.Info("Another query is running.");
@@ -207,16 +207,16 @@ private SFRestRequest BuildQueryRequest(string sql, Dictionary<string, BindingDT
207207
// remove it from parameter bindings so it won't break
208208
// parameter binding feature
209209
bindings.Remove(SF_PARAM_MULTI_STATEMENT_COUNT);
210-
}
211-
210+
}
211+
212212
if (_queryTag != null)
213213
{
214214
if (bodyParameters == null)
215215
{
216216
bodyParameters = new Dictionary<string, string>();
217217
}
218218
bodyParameters[SF_PARAM_QUERY_TAG] = _queryTag;
219-
}
219+
}
220220

221221
QueryRequest postBody = new QueryRequest();
222222
postBody.sqlText = sql;
@@ -317,7 +317,7 @@ private void SetTimeout(int timeout)
317317
this._timeoutTokenSource = timeout > 0 ? new CancellationTokenSource(timeout * 1000) :
318318
new CancellationTokenSource(Timeout.InfiniteTimeSpan);
319319
}
320-
320+
321321
/// <summary>
322322
/// Register cancel callback. Two factors: either external cancellation token passed down from upper
323323
/// layer or timeout reached. Whichever comes first would trigger query cancellation.
@@ -363,7 +363,7 @@ internal async Task<SFBaseResultSet> ExecuteAsync(int timeout, string sql, Dicti
363363
}
364364

365365
registerQueryCancellationCallback(timeout, cancellationToken);
366-
366+
367367
int arrayBindingThreshold = 0;
368368
if (SfSession.ParameterMap.ContainsKey(SFSessionParameter.CLIENT_STAGE_ARRAY_BINDING_THRESHOLD))
369369
{
@@ -457,10 +457,10 @@ internal SFBaseResultSet Execute(int timeout, string sql, Dictionary<string, Bin
457457
{
458458
throw new NotImplementedException("Get and Put are not supported in async execution mode");
459459
}
460-
return ExecuteSqlWithPutGet(timeout, trimmedSql, bindings, describeOnly);
460+
return ExecuteSqlWithPutGet(timeout, sql, trimmedSql, bindings, describeOnly);
461461
}
462462

463-
return ExecuteSqlOtherThanPutGet(timeout, trimmedSql, bindings, describeOnly, asyncExec);
463+
return ExecuteSqlOtherThanPutGet(timeout, sql, bindings, describeOnly, asyncExec);
464464
}
465465
finally
466466
{
@@ -469,7 +469,7 @@ internal SFBaseResultSet Execute(int timeout, string sql, Dictionary<string, Bin
469469
}
470470
}
471471

472-
private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, Dictionary<string, BindingDTO> bindings, bool describeOnly)
472+
private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, string trimmedSql, Dictionary<string, BindingDTO> bindings, bool describeOnly)
473473
{
474474
try
475475
{
@@ -484,7 +484,7 @@ private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, Dictionary
484484
logger.Debug("PUT/GET queryId: " + (response.data != null ? response.data.queryId : "Unknown"));
485485

486486
SFFileTransferAgent fileTransferAgent =
487-
new SFFileTransferAgent(sql, SfSession, response.data, CancellationToken.None);
487+
new SFFileTransferAgent(trimmedSql, SfSession, response.data, CancellationToken.None);
488488

489489
// Start the file transfer
490490
fileTransferAgent.execute();
@@ -507,7 +507,7 @@ private SFBaseResultSet ExecuteSqlWithPutGet(int timeout, string sql, Dictionary
507507
throw new SnowflakeDbException(ex, SFError.INTERNAL_ERROR);
508508
}
509509
}
510-
510+
511511
private SFBaseResultSet ExecuteSqlOtherThanPutGet(int timeout, string sql, Dictionary<string, BindingDTO> bindings, bool describeOnly, bool asyncExec)
512512
{
513513
try
@@ -562,7 +562,7 @@ private SFBaseResultSet ExecuteSqlOtherThanPutGet(int timeout, string sql, Dicti
562562
throw;
563563
}
564564
}
565-
565+
566566
internal async Task<SFBaseResultSet> GetResultWithIdAsync(string resultId, CancellationToken cancellationToken)
567567
{
568568
var req = BuildResultRequestWithId(resultId);
@@ -938,7 +938,7 @@ internal async Task<QueryStatus> GetQueryStatusAsync(string queryId, Cancellatio
938938
/// </summary>
939939
/// <param name="originalSql">The original sql query.</param>
940940
/// <returns>The query without the blanks and comments at the beginning.</returns>
941-
private string TrimSql(string originalSql)
941+
internal static string TrimSql(string originalSql)
942942
{
943943
char[] sqlQueryBuf = originalSql.ToCharArray();
944944
var builder = new StringBuilder();
@@ -1054,7 +1054,7 @@ internal SFBaseResultSet ExecuteTransfer(string sql)
10541054
false);
10551055

10561056
PutGetStageInfo stageInfo = new PutGetStageInfo();
1057-
1057+
10581058
SFFileTransferAgent fileTransferAgent =
10591059
new SFFileTransferAgent(sql, SfSession, response.data, ref _uploadStream, _destFilename, _stagePath, CancellationToken.None);
10601060

0 commit comments

Comments
 (0)