Skip to content

Commit

Permalink
SNOW-834812 Adding connection parameter QUERY_TAG. (#916)
Browse files Browse the repository at this point in the history
### Description
Adding connection parameter QUERY_TAG.

### 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
  • Loading branch information
sfc-gh-jsieminska authored Apr 19, 2024
1 parent 47235fb commit 14cf8a5
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 6 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ The following table lists all valid connection properties:
<br />

| Connection Property | Required | Comment |
| ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|--------------------------------| -------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ACCOUNT | Yes | Your full account name might include additional segments that identify the region and cloud platform where your account is hosted |
| APPLICATION | No | **_Snowflake partner use only_**: Specifies the name of a partner application to connect through .NET. The name must match the following pattern: ^\[A-Za-z](\[A-Za-z0-9.-]){1,50}$ (one letter followed by 1 to 50 letter, digit, .,- or, \_ characters). |
| DB | No | |
Expand Down Expand Up @@ -163,10 +163,11 @@ The following table lists all valid connection properties:
| PROXYPORT | Depends | The port number of the proxy server. <br/> <br/> If USEPROXY is set to `true`, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYUSER | No | The username for authenticating to the proxy server. <br/> <br/> This parameter was introduced in v2.0.4. |
| PROXYPASSWORD | Depends | The password for authenticating to the proxy server. <br/> <br/> If USEPROXY is `true` and PROXYUSER is set, you must set this parameter. <br/> <br/> This parameter was introduced in v2.0.4. |
| NONPROXYHOSTS | No | The list of hosts that the driver should connect to directly, bypassing the proxy server. Separate the hostnames with a pipe symbol (\|). You can also use an asterisk (`*`) as a wildcard. <br/> The host target value should fully match with any item from the proxy host list to bypass the proxy server. <br/> <br/> This parameter was introduced in v2.0.4. |
| NONPROXYHOSTS | No | The list of hosts that the driver should connect to directly, bypassing the proxy server. Separate the hostnames with a pipe symbol (\|). You can also use an asterisk (`*`) as a wildcard. <br/> The host target value should fully match with any item from the proxy host list to bypass the proxy server. <br/> <br/> This parameter was introduced in v2.0.4. |
| FILE_TRANSFER_MEMORY_THRESHOLD | No | The maximum number of bytes to store in memory used in order to provide a file encryption. If encrypting/decrypting file size exceeds provided value a temporary file will be created and the work will be continued in the temporary file instead of memory. <br/> If no value provided 1MB will be used as a default value (that is 1048576 bytes). <br/> It is possible to configure any integer value bigger than zero representing maximal number of bytes to reside in memory. |
| CLIENT_CONFIG_FILE | No | The location of the client configuration json file. In this file you can configure easy logging feature. |
| ALLOWUNDERSCORESINHOST | No | Specifies whether to allow underscores in account names. This impacts PrivateLink customers whose account names contain underscores. In this situation, you must override the default value by setting allowUnderscoresInHost to true. |
| QUERY_TAG | No | Optional string that can be used to tag queries and other SQL statements executed within a connection. The tags are displayed in the output of the QUERY_HISTORY , QUERY_HISTORY_BY_* functions. |

<br />

Expand Down
18 changes: 18 additions & 0 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2224,6 +2224,24 @@ public void TestNativeOktaSuccess()
}
}

[Test]
public void TestConnectStringWithQueryTag()
{
using (var conn = new SnowflakeDbConnection())
{
string expectedQueryTag = "Test QUERY_TAG 12345";
conn.ConnectionString = ConnectionString + $";query_tag={expectedQueryTag}";

conn.Open();
var command = conn.CreateCommand();
// 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);
}
}

}
}

Expand Down
35 changes: 34 additions & 1 deletion Snowflake.Data.Tests/UnitTests/SFSessionPropertyTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,38 @@ public static IEnumerable<TestCase> ConnectionStringTestCases()
{ SFSessionProperty.ALLOWUNDERSCORESINHOST, "true" }
}
};
var testQueryTag = "Test QUERY_TAG 12345";
var testCaseQueryTag = new TestCase()
{
ConnectionString = $"ACCOUNT={defAccount};USER={defUser};PASSWORD={defPassword};QUERY_TAG={testQueryTag}",
ExpectedProperties = new SFSessionProperties()
{
{ SFSessionProperty.ACCOUNT, $"{defAccount}" },
{ SFSessionProperty.USER, defUser },
{ SFSessionProperty.HOST, $"{defAccount}.snowflakecomputing.com" },
{ SFSessionProperty.AUTHENTICATOR, defAuthenticator },
{ SFSessionProperty.SCHEME, defScheme },
{ SFSessionProperty.CONNECTION_TIMEOUT, defConnectionTimeout },
{ SFSessionProperty.PASSWORD, defPassword },
{ SFSessionProperty.PORT, defPort },
{ SFSessionProperty.VALIDATE_DEFAULT_PARAMETERS, "true" },
{ SFSessionProperty.USEPROXY, "false" },
{ SFSessionProperty.INSECUREMODE, "false" },
{ SFSessionProperty.DISABLERETRY, "false" },
{ SFSessionProperty.FORCERETRYON404, "false" },
{ SFSessionProperty.CLIENT_SESSION_KEEP_ALIVE, "false" },
{ SFSessionProperty.FORCEPARSEERROR, "false" },
{ SFSessionProperty.BROWSER_RESPONSE_TIMEOUT, defBrowserResponseTime },
{ SFSessionProperty.RETRY_TIMEOUT, defRetryTimeout },
{ SFSessionProperty.MAXHTTPRETRIES, defMaxHttpRetries },
{ SFSessionProperty.INCLUDERETRYREASON, defIncludeRetryReason },
{ SFSessionProperty.DISABLEQUERYCONTEXTCACHE, defDisableQueryContextCache },
{ SFSessionProperty.DISABLE_CONSOLE_LOGIN, defDisableConsoleLogin },
{ SFSessionProperty.ALLOWUNDERSCORESINHOST, "false" },
{ SFSessionProperty.QUERY_TAG, testQueryTag }
}
};

return new TestCase[]
{
simpleTestCase,
Expand All @@ -482,7 +514,8 @@ public static IEnumerable<TestCase> ConnectionStringTestCases()
testCaseWithDisableConsoleLogin,
testCaseComplicatedAccountName,
testCaseUnderscoredAccountName,
testCaseUnderscoredAccountNameWithEnabledAllowUnderscores
testCaseUnderscoredAccountNameWithEnabledAllowUnderscores,
testCaseQueryTag
};
}

Expand Down
18 changes: 16 additions & 2 deletions Snowflake.Data/Core/SFStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +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;
Expand Down Expand Up @@ -141,10 +143,13 @@ class SFStatement
// the query id of the last query
string _lastQueryId = null;

private string _queryTag = null;

internal SFStatement(SFSession session)
{
SfSession = session;
_restRequester = session.restRequester;
_queryTag = session._queryTag;
}

internal string GetBindStage() => _bindStage;
Expand Down Expand Up @@ -195,7 +200,16 @@ private SFRestRequest BuildQueryRequest(string sql, Dictionary<string, BindingDT
// remove it from parameter bindings so it won't break
// parameter binding feature
bindings.Remove(SF_PARAM_MULTI_STATEMENT_COUNT);
}
}

if (_queryTag != null)
{
if (bodyParameters == null)
{
bodyParameters = new Dictionary<string, string>();
}
bodyParameters[SF_PARAM_QUERY_TAG] = _queryTag;
}

QueryRequest postBody = new QueryRequest();
postBody.sqlText = sql;
Expand Down
3 changes: 3 additions & 0 deletions Snowflake.Data/Core/Session/SFSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public class SFSession

internal int _maxRetryTimeout;

internal String _queryTag;

internal void ProcessLoginResponse(LoginResponse authnResponse)
{
if (authnResponse.success)
Expand Down Expand Up @@ -168,6 +170,7 @@ internal SFSession(
connectionTimeout = extractedProperties.TimeoutDuration();
properties.TryGetValue(SFSessionProperty.CLIENT_CONFIG_FILE, out var easyLoggingConfigFile);
_easyLoggingStarter.Init(easyLoggingConfigFile);
properties.TryGetValue(SFSessionProperty.QUERY_TAG, out _queryTag);
_maxRetryCount = extractedProperties.maxHttpRetries;
_maxRetryTimeout = extractedProperties.retryTimeout;
}
Expand Down
4 changes: 3 additions & 1 deletion Snowflake.Data/Core/Session/SFSessionProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ internal enum SFSessionProperty
[SFSessionPropertyAttr(required = false, defaultValue = "true")]
DISABLE_CONSOLE_LOGIN,
[SFSessionPropertyAttr(required = false, defaultValue = "false")]
ALLOWUNDERSCORESINHOST
ALLOWUNDERSCORESINHOST,
[SFSessionPropertyAttr(required = false)]
QUERY_TAG
}

class SFSessionPropertyAttr : Attribute
Expand Down

0 comments on commit 14cf8a5

Please sign in to comment.