From 3e0871c171ff8c830d89482069c5e930b65c8c5f Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Mon, 20 May 2024 13:48:47 -0600 Subject: [PATCH 1/6] [SNOW-921048] Add linter to fail pipeline --- .EditorConfig | 61 ---------------- .editorconfig | 73 +++++++++++++++++++ .github/workflows/linter.yml | 25 ++++--- .../Core/Session/ISessionPoolEventHandler.cs | 2 +- ci/scripts/linter.sh | 24 ++++++ 5 files changed, 114 insertions(+), 71 deletions(-) delete mode 100644 .EditorConfig create mode 100644 .editorconfig create mode 100755 ci/scripts/linter.sh diff --git a/.EditorConfig b/.EditorConfig deleted file mode 100644 index 61ab3ee2c..000000000 --- a/.EditorConfig +++ /dev/null @@ -1,61 +0,0 @@ -root = true -# All files -[*.*] -indent_style = space -indent_size = 4 -insert_final_newline = true -trim_trailing_whitespace = true -charset = utf-8 -max_line_length=150 - -# Interfaces should start with I and PascalCase -dotnet_naming_rule.interfaces_begin_with_I.severity = warning -dotnet_naming_rule.interfaces_begin_with_I.symbols = interfaces -dotnet_naming_rule.interfaces_begin_with_I.style = prefix_and_pascal_case -dotnet_naming_rule.interfaces_begin_with_I.required_prefix = I -dotnet_naming_symbols.interfaces.applicable_kinds = interface -dotnet_diagnostic.interfaces_begin_with_I.severity = warning -dotnet_diagnostic.interfaces_begin_with_I.enabled = true - -# Static fields should start with _s -dotnet_naming_rule.static_fields_begin_with_s.severity = warning -dotnet_naming_rule.static_fields_begin_with_s.symbols = static_fields -dotnet_naming_rule.static_fields_begin_with_s.style = custom -dotnet_naming_rule.static_fields_begin_with_s.custom_recommended_prefix = _r -dotnet_naming_rule.static_fields_begin_with_s.required_prefix = _r -dotnet_naming_rule.static_fields_begin_with_s.capitalization = camel_case -dotnet_naming_symbols.static_fields.applicable_kinds = field -dotnet_naming_symbols.static_fields.applicable_accessibilities = public, internal, private, protected, protected_internal -dotnet_naming_symbols.static_fields.required_modifiers = static -dotnet_diagnostic.static_fields_begin_with_s.severity = warning -dotnet_diagnostic.static_fields_begin_with_s.enabled = true - -# Enforce use of Pascal case in enums, classes, const and methods -dotnet_naming_rule.enforce_pascal_case.severity = suggestion -dotnet_naming_rule.enforce_pascal_case.symbols = methods, enums, consts, public_methods, public_classes -dotnet_naming_rule.enforce_pascal_case.style = pascal_case -dotnet_naming_symbols.methods.applicable_kinds = method -dotnet_naming_symbols.enums.applicable_kinds = enum -dotnet_naming_symbols.consts.applicable_kinds = field -dotnet_naming_symbols.consts.applicable_modifiers = const -dotnet_naming_symbols.public_methods.applicable_kinds = method -dotnet_naming_symbols.public_methods.applicable_accessibilities = public -dotnet_naming_symbols.public_classes.applicable_kinds = class -dotnet_naming_symbols.public_classes.applicable_accessibilities = public -dotnet_diagnostic.enforce_pascal_case.severity = suggestion -dotnet_diagnostic.enforce_pascal_case.enabled = true - -# private and internal members should start with underscore -dotnet_naming_rule.private_and_internal_members_start_with_underscore.severity = warning -dotnet_naming_rule.private_and_internal_members_start_with_underscore.symbols = private_fields, internal_fields, private_properties, internal_properties, private_methods, internal_methods -dotnet_naming_rule.private_and_internal_members_start_with_underscore.style = underscore_prefix -dotnet_naming_symbols.private_fields.applicable_kinds = field -dotnet_naming_symbols.internal_fields.applicable_kinds = field -dotnet_naming_symbols.private_properties.applicable_kinds = property -dotnet_naming_symbols.internal_properties.applicable_kinds = property -dotnet_naming_symbols.private_methods.applicable_kinds = method -dotnet_naming_symbols.internal_methods.applicable_kinds = method -dotnet_naming_symbols.private_methods.applicable_accessibilities = private -dotnet_naming_symbols.internal_methods.applicable_accessibilities = internal -dotnet_diagnostic.private_and_internal_members_start_with_underscore.severity = warning -dotnet_diagnostic.private_and_internal_members_start_with_underscore.enabled = true diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..73ce17651 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,73 @@ +root = true +# yml files +[*.yml] +indent_style = space +indent_size = 2 + +# All files +[*.*] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 +max_line_length = 150 + +## Interfaces should start with I and PascalCase +dotnet_naming_style.prefix_and_pascal_case.required_prefix = I +dotnet_naming_style.prefix_and_pascal_case.capitalization = pascal_case +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_rule.interfaces_begin_with_I.severity = error +dotnet_naming_rule.interfaces_begin_with_I.symbols = interfaces +dotnet_naming_rule.interfaces_begin_with_I.style = prefix_and_pascal_case +dotnet_diagnostic.interfaces_begin_with_I.enabled = true + +## Static fields should start with _s +dotnet_naming_style.prefix_s.required_prefix = _s +dotnet_naming_style.prefix_s.capitalization = camel_case +dotnet_naming_rule.static_fields_begin_with_s.style = prefix_s +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.applicable_accessibilities = public, internal, private, protected, protected_internal +dotnet_naming_symbols.static_fields.required_modifiers = static +dotnet_naming_rule.static_fields_begin_with_s.severity = error +dotnet_naming_rule.static_fields_begin_with_s.symbols = static_fields +dotnet_diagnostic.static_fields_begin_with_s.enabled = true + +## Internal or private member should prefixed with _ +dotnet_naming_style.internal_prefix_.required_prefix = _ +dotnet_naming_style.internal_prefix_.capitalization = camel_case +dotnet_naming_rule.private_internal_prefix_.style = internal_prefix_ +dotnet_naming_symbols.private_internal_fields.applicable_kinds = field +dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = internal, private, protected_internal +dotnet_naming_rule.private_internal_prefix_.severity = error +dotnet_naming_rule.private_internal_prefix_.symbols = private_internal_fields +dotnet_diagnostic.private_internal_prefix_.enabled = true + +# Enforce use of Pascal case in enums, classes, const and methods +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +dotnet_naming_rule.enforce_pascal_case.style = pascal_case_style +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.consts.applicable_kinds = field +dotnet_naming_symbols.consts.applicable_modifiers = const +dotnet_naming_symbols.public_methods.applicable_kinds = method +dotnet_naming_symbols.public_methods.applicable_accessibilities = public +dotnet_naming_symbols.public_classes.applicable_kinds = class +dotnet_naming_symbols.public_classes.applicable_accessibilities = public +dotnet_naming_symbols.enum_members.applicable_kinds = enum_member +dotnet_naming_symbols.enum_members.applicable_accessibilities = * +dotnet_naming_rule.enforce_pascal_case.severity = error +dotnet_naming_rule.enforce_pascal_case.symbols = methods, enums, consts, public_methods, public_classes, enum_members +dotnet_diagnostic.enforce_pascal_case.enabled = true + + +# Naming styles for different symbol kinds +dotnet_naming_style.camel_case_style.capitalization = camel_case +dotnet_naming_rule.method_parameters_should_be_camel_case.symbols = method_parameters +dotnet_naming_rule.method_parameters_should_be_camel_case.style = camel_case_style +dotnet_naming_symbols.method_parameters.applicable_kinds = parameter +dotnet_naming_symbols.method_parameters.applicable_accessibilities = * +dotnet_naming_symbols.method_parameters.required_modifiers = * +dotnet_naming_rule.method_parameters_should_be_camel_case.severity = error +dotnet_naming_rule.enforce_pascal_case.symbols = method_parameters +dotnet_diagnostic.method_parameters_should_be_camel_case.enabled = true diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 1c00a29aa..b72f02ca9 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -13,6 +13,7 @@ on: tags: description: "Linter" required: false +permissions: { } concurrency: # older builds for the same pull request number or branch should be cancelled @@ -26,14 +27,20 @@ jobs: steps: - name: Check out Git repository uses: actions/checkout@v3 - - name: Set up .NET - uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.x' - dotnet-quality: 'ga' - - name: Run linters - uses: wearerequired/lint-action@v2 + depth: 0 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 with: - dotnet_format: true - continue_on_error: true - check_name: ${linter} run + dotnet-version: '6.0.103' + + - name: Install dotnet format + run: dotnet tool install -g dotnet-format + + - name: Add dotnet tools to PATH + run: echo "$HOME/.dotnet/tools" >> $GITHUB_PATH + + - name: Run Linter Bash Script + run: | + bash ci/scripts/linter.sh diff --git a/Snowflake.Data/Core/Session/ISessionPoolEventHandler.cs b/Snowflake.Data/Core/Session/ISessionPoolEventHandler.cs index 2b16959a2..f8d78262a 100644 --- a/Snowflake.Data/Core/Session/ISessionPoolEventHandler.cs +++ b/Snowflake.Data/Core/Session/ISessionPoolEventHandler.cs @@ -5,7 +5,7 @@ internal interface ISessionPoolEventHandler void OnNewSessionCreated(SessionPool sessionPool); void OnWaitingForSessionStarted(SessionPool sessionPool); - + void OnWaitingForSessionStarted(SessionPool sessionPool, long millisLeft); void OnWaitingForSessionSuccessful(SessionPool sessionPool); diff --git a/ci/scripts/linter.sh b/ci/scripts/linter.sh new file mode 100755 index 000000000..c4dfec3f5 --- /dev/null +++ b/ci/scripts/linter.sh @@ -0,0 +1,24 @@ +#!/bin/bash -e +# +# Apply Linter to changed files in PR +set -e +set -o pipefail + +current_branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} +git fetch --no-tags origin master:master +git fetch --no-tags origin $current_branch:$current_branch + +BASE_SHA=$(git merge-base $GITHUB_BASE_REF $current_branch) + +changed_files=$(git diff --name-only $BASE_SHA HEAD) + +echo "All files changed:" +for file in $changed_files; do + echo "$file" +done + +echo "Run dotnet restore" +dotnet restore + +echo "Running Dotnet format to changed files" +dotnet format --include $changed_files --verify-no-changes --no-restore From dbf4b4cadf6ea8ded9ca61b7ff397c65bee3e49f Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Fri, 19 Jul 2024 15:03:21 -0600 Subject: [PATCH 2/6] add verification for empty changed files --- ci/scripts/linter.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ci/scripts/linter.sh b/ci/scripts/linter.sh index c4dfec3f5..4ce73f1e0 100755 --- a/ci/scripts/linter.sh +++ b/ci/scripts/linter.sh @@ -17,6 +17,11 @@ for file in $changed_files; do echo "$file" done +if [-z "$changed_files" ]; then + echo "no changed files detected" + exit 0 +fi + echo "Run dotnet restore" dotnet restore From 0ba91adafcdb5492d2259e774d7f36cfda088c0b Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Tue, 30 Jul 2024 08:30:43 -0600 Subject: [PATCH 3/6] remove linter errors --- .editorconfig | 2 +- .../UnitTests/SFDbCommandTest.cs | 16 +- Snowflake.Data/Client/SnowflakeDbCommand.cs | 143 ++++++++---------- .../Core/Session/SFSessionProperty.cs | 117 ++++++++++---- 4 files changed, 157 insertions(+), 121 deletions(-) diff --git a/.editorconfig b/.editorconfig index 73ce17651..d9d57561d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,7 +23,7 @@ dotnet_naming_rule.interfaces_begin_with_I.style = prefix_and_pascal_case dotnet_diagnostic.interfaces_begin_with_I.enabled = true ## Static fields should start with _s -dotnet_naming_style.prefix_s.required_prefix = _s +dotnet_naming_style.prefix_s.required_prefix = s_ dotnet_naming_style.prefix_s.capitalization = camel_case dotnet_naming_rule.static_fields_begin_with_s.style = prefix_s dotnet_naming_symbols.static_fields.applicable_kinds = field diff --git a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs index 714d237d2..2673e7ff9 100644 --- a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs @@ -13,12 +13,12 @@ namespace Snowflake.Data.Tests.UnitTests [TestFixture] class SFDbCommandTest { - SnowflakeDbCommand command; + SnowflakeDbCommand _command; [SetUp] public void BeforeTest() { - command = new SnowflakeDbCommand(); + _command = new SnowflakeDbCommand(); } [Test] @@ -29,18 +29,18 @@ public void TestCommandWithConnectionAndCommandText() string commandText = "select 1"; // Act - command = new SnowflakeDbCommand(conn, commandText); + _command = new SnowflakeDbCommand(conn, commandText); // Assert - Assert.AreEqual(conn, command.Connection); - Assert.AreEqual(commandText, command.CommandText); + Assert.AreEqual(conn, _command.Connection); + Assert.AreEqual(commandText, _command.CommandText); } [Test] public void TestCommandExecuteThrowsExceptionWhenCommandTextIsNotSet() { // Act - var thrown = Assert.Throws(() => command.ExecuteScalar()); + var thrown = Assert.Throws(() => _command.ExecuteScalar()); // Assert Assert.AreEqual(thrown.Message, "Unable to execute command due to command text not being set"); @@ -50,7 +50,7 @@ public void TestCommandExecuteThrowsExceptionWhenCommandTextIsNotSet() public void TestCommandExecuteAsyncThrowsExceptionWhenCommandTextIsNotSet() { // Arrange - Task commandTask = command.ExecuteScalarAsync(CancellationToken.None); + Task commandTask = _command.ExecuteScalarAsync(CancellationToken.None); // Act var thrown = Assert.Throws(() => commandTask.Wait()); @@ -62,7 +62,7 @@ public void TestCommandExecuteAsyncThrowsExceptionWhenCommandTextIsNotSet() [Test] public void TestCommandPrepareThrowsNotImplemented() { - Assert.Throws(() => command.Prepare()); + Assert.Throws(() => _command.Prepare()); } } } diff --git a/Snowflake.Data/Client/SnowflakeDbCommand.cs b/Snowflake.Data/Client/SnowflakeDbCommand.cs index 15d8e0870..b59cb6159 100755 --- a/Snowflake.Data/Client/SnowflakeDbCommand.cs +++ b/Snowflake.Data/Client/SnowflakeDbCommand.cs @@ -16,27 +16,27 @@ namespace Snowflake.Data.Client [System.ComponentModel.DesignerCategory("Code")] public class SnowflakeDbCommand : DbCommand { - private SnowflakeDbConnection connection; + private SnowflakeDbConnection _connection; - private SFStatement sfStatement; + private SFStatement _sfStatement; - private SnowflakeDbParameterCollection parameterCollection; + private SnowflakeDbParameterCollection _parameterCollection; - private SFLogger logger = SFLoggerFactory.GetLogger(); + private SFLogger _logger = SFLoggerFactory.GetLogger(); private readonly QueryResultsAwaiter _queryResultsAwaiter = QueryResultsAwaiter.Instance; public SnowflakeDbCommand() { - logger.Debug("Constructing SnowflakeDbCommand class"); + _logger.Debug("Constructing SnowflakeDbCommand class"); // by default, no query timeout this.CommandTimeout = 0; - parameterCollection = new SnowflakeDbParameterCollection(); + _parameterCollection = new SnowflakeDbParameterCollection(); } public SnowflakeDbCommand(SnowflakeDbConnection connection) : this() { - this.connection = connection; + this._connection = connection; } public SnowflakeDbCommand(SnowflakeDbConnection connection, string cmdText) : this(connection) @@ -44,27 +44,15 @@ public SnowflakeDbCommand(SnowflakeDbConnection connection, string cmdText) : th this.CommandText = cmdText; } - public override string CommandText - { - get; set; - } + public override string CommandText { get; set; } - public override int CommandTimeout - { - get; set; - } + public override int CommandTimeout { get; set; } - public string QueryTag - { - get; set; - } + public string QueryTag { get; set; } public override CommandType CommandType { - get - { - return CommandType.Text; - } + get { return CommandType.Text; } set { @@ -77,10 +65,7 @@ public override CommandType CommandType public override bool DesignTimeVisible { - get - { - return false; - } + get { return false; } set { @@ -106,13 +91,13 @@ public override UpdateRowSource UpdatedRowSource protected override DbConnection DbConnection { - get => connection; + get => _connection; set { if (value == null) { - if (connection == null) + if (_connection == null) { return; } @@ -127,45 +112,37 @@ protected override DbConnection DbConnection throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); } - var sfc = (SnowflakeDbConnection) value; - if (connection != null && connection != sfc) + var sfc = (SnowflakeDbConnection)value; + if (_connection != null && _connection != sfc) { // Connection already set. throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); } - connection = sfc; + _connection = sfc; if (sfc.SfSession != null) { - sfStatement = new SFStatement(sfc.SfSession, QueryTag); + _sfStatement = new SFStatement(sfc.SfSession, QueryTag); } } } protected override DbParameterCollection DbParameterCollection { - get - { - return this.parameterCollection; - } + get { return this._parameterCollection; } } - protected override DbTransaction DbTransaction - { - get; - - set; - } + protected override DbTransaction DbTransaction { get; set; } public override void Cancel() { // doesn't throw exception when sfStatement is null - sfStatement?.Cancel(); + _sfStatement?.Cancel(); } public override int ExecuteNonQuery() { - logger.Debug($"ExecuteNonQuery"); + _logger.Debug($"ExecuteNonQuery"); SFBaseResultSet resultSet = ExecuteInternal(); long total = 0; do @@ -177,20 +154,20 @@ public override int ExecuteNonQuery() // exceeded max int, return -1 return -1; } + total += count; if (total > int.MaxValue) { return -1; } - } - while (resultSet.NextResult()); + } while (resultSet.NextResult()); return (int)total; } public override async Task ExecuteNonQueryAsync(CancellationToken cancellationToken) { - logger.Debug($"ExecuteNonQueryAsync"); + _logger.Debug($"ExecuteNonQueryAsync"); cancellationToken.ThrowIfCancellationRequested(); var resultSet = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); @@ -204,23 +181,23 @@ public override async Task ExecuteNonQueryAsync(CancellationToken cancellat // exceeded max int, return -1 return -1; } + total += count; if (total > int.MaxValue) { return -1; } - } - while (await resultSet.NextResultAsync(cancellationToken).ConfigureAwait(false)); + } while (await resultSet.NextResultAsync(cancellationToken).ConfigureAwait(false)); return (int)total; } public override object ExecuteScalar() { - logger.Debug($"ExecuteScalar"); + _logger.Debug($"ExecuteScalar"); SFBaseResultSet resultSet = ExecuteInternal(); - if(resultSet.Next()) + if (resultSet.Next()) return resultSet.GetValue(0); else return DBNull.Value; @@ -228,12 +205,12 @@ public override object ExecuteScalar() public override async Task ExecuteScalarAsync(CancellationToken cancellationToken) { - logger.Debug($"ExecuteScalarAsync"); + _logger.Debug($"ExecuteScalarAsync"); cancellationToken.ThrowIfCancellationRequested(); var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); - if(await result.NextAsync().ConfigureAwait(false)) + if (await result.NextAsync().ConfigureAwait(false)) return result.GetValue(0); else return DBNull.Value; @@ -246,10 +223,11 @@ public override void Prepare() public string GetQueryId() { - if (sfStatement != null) + if (_sfStatement != null) { - return sfStatement.GetQueryId(); + return _sfStatement.GetQueryId(); } + return null; } @@ -260,14 +238,14 @@ protected override DbParameter CreateDbParameter() protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { - logger.Debug($"ExecuteDbDataReader"); + _logger.Debug($"ExecuteDbDataReader"); SFBaseResultSet resultSet = ExecuteInternal(); return new SnowflakeDbDataReader(this, resultSet); } protected override async Task ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) { - logger.Debug($"ExecuteDbDataReaderAsync"); + _logger.Debug($"ExecuteDbDataReaderAsync"); try { var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); @@ -275,7 +253,7 @@ protected override async Task ExecuteDbDataReaderAsync(CommandBeha } catch (Exception ex) { - logger.Error("The command failed to execute.", ex); + _logger.Error("The command failed to execute.", ex); throw; } } @@ -287,7 +265,7 @@ protected override async Task ExecuteDbDataReaderAsync(CommandBeha /// The query id. public string ExecuteInAsyncMode() { - logger.Debug($"ExecuteInAsyncMode"); + _logger.Debug($"ExecuteInAsyncMode"); SFBaseResultSet resultSet = ExecuteInternal(asyncExec: true); return resultSet.queryId; } @@ -300,7 +278,7 @@ public string ExecuteInAsyncMode() /// The query id. public async Task ExecuteAsyncInAsyncMode(CancellationToken cancellationToken) { - logger.Debug($"ExecuteAsyncInAsyncMode"); + _logger.Debug($"ExecuteAsyncInAsyncMode"); var resultSet = await ExecuteInternalAsync(cancellationToken, asyncExec: true).ConfigureAwait(false); return resultSet.queryId; } @@ -312,8 +290,8 @@ public async Task ExecuteAsyncInAsyncMode(CancellationToken cancellation /// The query status. public QueryStatus GetQueryStatus(string queryId) { - logger.Debug($"GetQueryStatus"); - return _queryResultsAwaiter.GetQueryStatus(connection, queryId); + _logger.Debug($"GetQueryStatus"); + return _queryResultsAwaiter.GetQueryStatus(_connection, queryId); } /// @@ -324,8 +302,8 @@ public QueryStatus GetQueryStatus(string queryId) /// The query status. public async Task GetQueryStatusAsync(string queryId, CancellationToken cancellationToken) { - logger.Debug($"GetQueryStatusAsync"); - return await _queryResultsAwaiter.GetQueryStatusAsync(connection, queryId, cancellationToken); + _logger.Debug($"GetQueryStatusAsync"); + return await _queryResultsAwaiter.GetQueryStatusAsync(_connection, queryId, cancellationToken); } /// @@ -335,12 +313,12 @@ public async Task GetQueryStatusAsync(string queryId, CancellationT /// The query results. public DbDataReader GetResultsFromQueryId(string queryId) { - logger.Debug($"GetResultsFromQueryId"); + _logger.Debug($"GetResultsFromQueryId"); - Task task = _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(connection, queryId, CancellationToken.None, false); + Task task = _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, CancellationToken.None, false); task.Wait(); - SFBaseResultSet resultSet = sfStatement.GetResultWithId(queryId); + SFBaseResultSet resultSet = _sfStatement.GetResultWithId(queryId); return new SnowflakeDbDataReader(this, resultSet); } @@ -353,16 +331,16 @@ public DbDataReader GetResultsFromQueryId(string queryId) /// The query results. public async Task GetResultsFromQueryIdAsync(string queryId, CancellationToken cancellationToken) { - logger.Debug($"GetResultsFromQueryIdAsync"); + _logger.Debug($"GetResultsFromQueryIdAsync"); - await _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(connection, queryId, cancellationToken, true); + await _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, cancellationToken, true); - SFBaseResultSet resultSet = await sfStatement.GetResultWithIdAsync(queryId, cancellationToken).ConfigureAwait(false); + SFBaseResultSet resultSet = await _sfStatement.GetResultWithIdAsync(queryId, cancellationToken).ConfigureAwait(false); return new SnowflakeDbDataReader(this, resultSet); } - private static Dictionary convertToBindList(List parameters) + private static Dictionary _convertToBindList(List parameters) { if (parameters == null || parameters.Count == 0) { @@ -371,7 +349,7 @@ private static Dictionary convertToBindList(List binding = new Dictionary(); - foreach(SnowflakeDbParameter parameter in parameters) + foreach (SnowflakeDbParameter parameter in parameters) { string bindingType = ""; object bindingVal; @@ -382,7 +360,7 @@ private static Dictionary convertToBindList(List vals = new List(); - foreach(object val in (Array)parameter.Value) + foreach (object val in (Array)parameter.Value) { // if the user is using interface, SFDataType will be None and there will // a conversion from DbType to SFDataType @@ -401,6 +379,7 @@ private static Dictionary convertToBindList(List convertToBindList(List ExecuteInternalAsync(CancellationToken cancellationToken, bool describeOnly = false, bool asyncExec = false) { CheckIfCommandTextIsSet(); SetStatement(); - return sfStatement.ExecuteAsync(CommandTimeout, CommandText, convertToBindList(parameterCollection.parameterList), describeOnly, asyncExec, cancellationToken); + return _sfStatement.ExecuteAsync(CommandTimeout, CommandText, _convertToBindList(_parameterCollection.parameterList), describeOnly, + asyncExec, cancellationToken); } private void CheckIfCommandTextIsSet() @@ -461,11 +442,11 @@ private void CheckIfCommandTextIsSet() if (string.IsNullOrEmpty(CommandText)) { var errorMessage = "Unable to execute command due to command text not being set"; - logger.Error(errorMessage); + _logger.Error(errorMessage); throw new Exception(errorMessage); } } - internal string GetBindStage() => sfStatement?.GetBindStage(); + internal string GetBindStage() => _sfStatement?.GetBindStage(); } } diff --git a/Snowflake.Data/Core/Session/SFSessionProperty.cs b/Snowflake.Data/Core/Session/SFSessionProperty.cs index 226c75cb1..70bb6ccfc 100644 --- a/Snowflake.Data/Core/Session/SFSessionProperty.cs +++ b/Snowflake.Data/Core/Session/SFSessionProperty.cs @@ -21,96 +21,142 @@ internal enum SFSessionProperty { [SFSessionPropertyAttr(required = true)] ACCOUNT, + [SFSessionPropertyAttr(required = false)] DB, + [SFSessionPropertyAttr(required = false)] HOST, + [SFSessionPropertyAttr(required = true, IsSecret = true)] PASSWORD, + [SFSessionPropertyAttr(required = false, defaultValue = "443")] PORT, + [SFSessionPropertyAttr(required = false)] ROLE, + [SFSessionPropertyAttr(required = false)] SCHEMA, + [SFSessionPropertyAttr(required = false, defaultValue = "https")] SCHEME, + [SFSessionPropertyAttr(required = true, defaultValue = "")] USER, + [SFSessionPropertyAttr(required = false)] WAREHOUSE, + [SFSessionPropertyAttr(required = false, defaultValue = "300")] CONNECTION_TIMEOUT, + [SFSessionPropertyAttr(required = false, defaultValue = "snowflake")] AUTHENTICATOR, + [SFSessionPropertyAttr(required = false, defaultValue = "true")] VALIDATE_DEFAULT_PARAMETERS, + [SFSessionPropertyAttr(required = false)] PRIVATE_KEY_FILE, + [SFSessionPropertyAttr(required = false, IsSecret = true)] PRIVATE_KEY_PWD, + [SFSessionPropertyAttr(required = false, IsSecret = true)] PRIVATE_KEY, + [SFSessionPropertyAttr(required = false, IsSecret = true)] TOKEN, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] INSECUREMODE, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] USEPROXY, + [SFSessionPropertyAttr(required = false)] PROXYHOST, + [SFSessionPropertyAttr(required = false)] PROXYPORT, + [SFSessionPropertyAttr(required = false)] PROXYUSER, + [SFSessionPropertyAttr(required = false, IsSecret = true)] PROXYPASSWORD, + [SFSessionPropertyAttr(required = false)] NONPROXYHOSTS, + [SFSessionPropertyAttr(required = false)] APPLICATION, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] DISABLERETRY, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] FORCERETRYON404, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] CLIENT_SESSION_KEEP_ALIVE, + [SFSessionPropertyAttr(required = false)] GCS_USE_DOWNSCOPED_CREDENTIAL, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] FORCEPARSEERROR, + [SFSessionPropertyAttr(required = false, defaultValue = "120")] BROWSER_RESPONSE_TIMEOUT, + [SFSessionPropertyAttr(required = false, defaultValue = "300")] RETRY_TIMEOUT, + [SFSessionPropertyAttr(required = false, defaultValue = "7")] MAXHTTPRETRIES, + [SFSessionPropertyAttr(required = false)] FILE_TRANSFER_MEMORY_THRESHOLD, + [SFSessionPropertyAttr(required = false, defaultValue = "true")] INCLUDERETRYREASON, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] DISABLEQUERYCONTEXTCACHE, + [SFSessionPropertyAttr(required = false)] CLIENT_CONFIG_FILE, + [SFSessionPropertyAttr(required = false, defaultValue = "true")] DISABLE_CONSOLE_LOGIN, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] ALLOWUNDERSCORESINHOST, + [SFSessionPropertyAttr(required = false)] QUERY_TAG, + [SFSessionPropertyAttr(required = false, defaultValue = "10")] MAXPOOLSIZE, + [SFSessionPropertyAttr(required = false, defaultValue = "2")] MINPOOLSIZE, + [SFSessionPropertyAttr(required = false, defaultValue = "Destroy")] CHANGEDSESSION, + [SFSessionPropertyAttr(required = false, defaultValue = "30s")] WAITINGFORIDLESESSIONTIMEOUT, + [SFSessionPropertyAttr(required = false, defaultValue = "60m")] EXPIRATIONTIMEOUT, + [SFSessionPropertyAttr(required = false, defaultValue = "true")] POOLINGENABLED, + [SFSessionPropertyAttr(required = false, defaultValue = "false")] DISABLE_SAML_URL_CHECK } @@ -126,7 +172,7 @@ class SFSessionPropertyAttr : Attribute class SFSessionProperties : Dictionary { - private static SFLogger logger = SFLoggerFactory.GetLogger(); + private static SFLogger s_logger = SFLoggerFactory.GetLogger(); internal string ConnectionStringWithoutSecrets { get; set; } @@ -158,20 +204,23 @@ public override bool Equals(object obj) { return false; } + if (!this.ContainsKey(sessionProperty)) { continue; } + if (!this[sessionProperty].Equals(prop[sessionProperty])) { return false; } } + return true; } catch (InvalidCastException) { - logger.Warn("Invalid casting to SFSessionProperties"); + s_logger.Warn("Invalid casting to SFSessionProperties"); return false; } } @@ -183,7 +232,7 @@ public override int GetHashCode() internal static SFSessionProperties ParseConnectionString(string connectionString, SecureString password) { - logger.Info("Start parsing connection string."); + s_logger.Info("Start parsing connection string."); var builder = new DbConnectionStringBuilder(); try { @@ -191,31 +240,32 @@ internal static SFSessionProperties ParseConnectionString(string connectionStrin } catch (ArgumentException e) { - logger.Warn("Invalid connectionString", e); + s_logger.Warn("Invalid connectionString", e); throw new SnowflakeDbException(e, - SFError.INVALID_CONNECTION_STRING, - e.Message); + SFError.INVALID_CONNECTION_STRING, + e.Message); } + var properties = new SFSessionProperties(); var keys = new string[builder.Keys.Count]; var values = new string[builder.Values.Count]; builder.Keys.CopyTo(keys, 0); - builder.Values.CopyTo(values,0); + builder.Values.CopyTo(values, 0); properties.ConnectionStringWithoutSecrets = BuildConnectionStringWithoutSecrets(ref keys, ref values); - for(var i=0; i 0) + if (keyVal.Length > 0) { var tokens = keyVal.Split(new string[] { "=" }, StringSplitOptions.None); var propertyName = tokens[0].ToUpper(); @@ -357,7 +412,7 @@ private static void UpdatePropertiesForSpecialCases(SFSessionProperties properti { var sessionProperty = (SFSessionProperty)Enum.Parse( typeof(SFSessionProperty), propertyName); - properties[sessionProperty]= ProcessObjectEscapedCharacters(tokens[1]); + properties[sessionProperty] = ProcessObjectEscapedCharacters(tokens[1]); } break; @@ -383,7 +438,7 @@ private static void UpdatePropertiesForSpecialCases(SFSessionProperties properti private static string ProcessObjectEscapedCharacters(string objectValue) { var match = Regex.Match(objectValue, "^\"(.*)\"$"); - if(match.Success) + if (match.Success) { var replaceEscapedQuotes = match.Groups[1].Value.Replace("\"\"", "\""); return $"\"{replaceEscapedQuotes}\""; @@ -399,7 +454,7 @@ private static void ValidateAccountDomain(SFSessionProperties properties) return; if (IsAccountRegexMatched(account)) return; - logger.Error($"Invalid account {account}"); + s_logger.Error($"Invalid account {account}"); throw new SnowflakeDbException( new Exception("Invalid account"), SFError.INVALID_CONNECTION_PARAMETER_VALUE, @@ -421,14 +476,14 @@ private static void CheckSessionProperties(SFSessionProperties properties) !properties.ContainsKey(sessionProperty)) { SnowflakeDbException e = new SnowflakeDbException(SFError.MISSING_CONNECTION_PROPERTY, sessionProperty); - logger.Error("Missing connection property", e); + s_logger.Error("Missing connection property", e); throw e; } if (IsRequired(sessionProperty, properties) && string.IsNullOrEmpty(properties[sessionProperty])) { SnowflakeDbException e = new SnowflakeDbException(SFError.MISSING_CONNECTION_PROPERTY, sessionProperty); - logger.Error("Empty connection property", e); + s_logger.Error("Empty connection property", e); throw e; } @@ -436,7 +491,7 @@ private static void CheckSessionProperties(SFSessionProperties properties) string defaultVal = sessionProperty.GetAttribute().defaultValue; if (defaultVal != null && !properties.ContainsKey(sessionProperty)) { - logger.Debug($"Session property {sessionProperty} set to default value: {defaultVal}"); + s_logger.Debug($"Session property {sessionProperty} set to default value: {defaultVal}"); properties.Add(sessionProperty, defaultVal); } } @@ -457,13 +512,13 @@ private static void ValidateFileTransferMaxBytesInMemoryProperty(SFSessionProper } catch (Exception e) { - logger.Error($"Value for parameter {propertyName} could not be parsed"); + s_logger.Error($"Value for parameter {propertyName} could not be parsed"); throw new SnowflakeDbException(e, SFError.INVALID_CONNECTION_PARAMETER_VALUE, maxBytesInMemoryString, propertyName); } if (maxBytesInMemory <= 0) { - logger.Error($"Value for parameter {propertyName} should be greater than 0"); + s_logger.Error($"Value for parameter {propertyName} should be greater than 0"); throw new SnowflakeDbException( new Exception($"Value for parameter {propertyName} should be greater than 0"), SFError.INVALID_CONNECTION_PARAMETER_VALUE, maxBytesInMemoryString, propertyName); @@ -490,7 +545,7 @@ private static bool IsRequired(SFSessionProperty sessionProperty, SFSessionPrope else if (sessionProperty.Equals(SFSessionProperty.USER)) { var authenticatorDefined = - properties.TryGetValue(SFSessionProperty.AUTHENTICATOR, out var authenticator); + properties.TryGetValue(SFSessionProperty.AUTHENTICATOR, out var authenticator); var authenticatorsWithoutUsername = new List() { @@ -523,7 +578,7 @@ private static bool ParseAllowUnderscoresInHost(SFSessionProperties properties) } catch (Exception e) { - logger.Warn("Unable to parse property 'allowUnderscoresInHost'", e); + s_logger.Warn("Unable to parse property 'allowUnderscoresInHost'", e); } return allowUnderscoresInHost; From 08dfa0376343f447ce1d7253bed5514fd4ed7804 Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Tue, 30 Jul 2024 08:51:48 -0600 Subject: [PATCH 4/6] fix format --- Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs index 619922a81..68798aacd 100644 --- a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. */ From 7dc5bc3eb2fcb2497ca5c39a201200a9ee343f84 Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Tue, 30 Jul 2024 08:55:43 -0600 Subject: [PATCH 5/6] fix build error after merge --- Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs | 2 +- Snowflake.Data/Core/Session/SFSessionProperty.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs index 68798aacd..a496dbbbd 100644 --- a/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs +++ b/Snowflake.Data.Tests/UnitTests/SFDbCommandTest.cs @@ -62,7 +62,7 @@ public void TestCommandExecuteAsyncThrowsExceptionWhenCommandTextIsNotSet() [Test] public void TestCommandPrepareShouldNotThrowsException() { - Assert.DoesNotThrow(() => command.Prepare()); + Assert.DoesNotThrow(() => _command.Prepare()); } } } diff --git a/Snowflake.Data/Core/Session/SFSessionProperty.cs b/Snowflake.Data/Core/Session/SFSessionProperty.cs index 11543aea9..a15d5fbe3 100644 --- a/Snowflake.Data/Core/Session/SFSessionProperty.cs +++ b/Snowflake.Data/Core/Session/SFSessionProperty.cs @@ -333,7 +333,7 @@ internal static SFSessionProperties ParseConnectionString(string connectionStrin properties.Add(SFSessionProperty.HOST, hostName); s_logger.Info($"Compose host name: {hostName}"); } - logger.Info(ResolveConnectionAreaMessage(properties[SFSessionProperty.HOST])); + s_logger.Info(ResolveConnectionAreaMessage(properties[SFSessionProperty.HOST])); // Trim the account name to remove the region and cloud platform if any were provided // because the login request data does not expect region and cloud information to be From 9e16e6bf19323409f55074499df60554d6a60dfe Mon Sep 17 00:00:00 2001 From: Steven Lizano Date: Tue, 30 Jul 2024 10:27:11 -0600 Subject: [PATCH 6/6] fix charset --- Snowflake.Data/Client/SnowflakeDbCommand.cs | 910 +++++++++--------- .../Core/Session/SFSessionProperty.cs | 33 +- 2 files changed, 471 insertions(+), 472 deletions(-) diff --git a/Snowflake.Data/Client/SnowflakeDbCommand.cs b/Snowflake.Data/Client/SnowflakeDbCommand.cs index ac6ee5b1c..b8e00f737 100755 --- a/Snowflake.Data/Client/SnowflakeDbCommand.cs +++ b/Snowflake.Data/Client/SnowflakeDbCommand.cs @@ -1,455 +1,455 @@ -/* - * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved. - */ - -using System; -using Snowflake.Data.Core; -using System.Data.Common; -using System.Data; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Snowflake.Data.Log; - -namespace Snowflake.Data.Client -{ - [System.ComponentModel.DesignerCategory("Code")] - public class SnowflakeDbCommand : DbCommand - { - private SnowflakeDbConnection _connection; - - private SFStatement _sfStatement; - - private SnowflakeDbParameterCollection _parameterCollection; - - private SFLogger _logger = SFLoggerFactory.GetLogger(); - - private readonly QueryResultsAwaiter _queryResultsAwaiter = QueryResultsAwaiter.Instance; - - public SnowflakeDbCommand() - { - _logger.Debug("Constructing SnowflakeDbCommand class"); - // by default, no query timeout - this.CommandTimeout = 0; - _parameterCollection = new SnowflakeDbParameterCollection(); - } - - public SnowflakeDbCommand(SnowflakeDbConnection connection) : this() - { - this._connection = connection; - } - - public SnowflakeDbCommand(SnowflakeDbConnection connection, string cmdText) : this(connection) - { - this.CommandText = cmdText; - } - - public override string CommandText { get; set; } - - public override int CommandTimeout { get; set; } - - public string QueryTag { get; set; } - - public override CommandType CommandType - { - get { return CommandType.Text; } - - set - { - if (value != CommandType.Text) - { - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - } - } - - public override bool DesignTimeVisible - { - get { return false; } - - set - { - if (value) - { - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - } - } - - public override UpdateRowSource UpdatedRowSource - { - get => UpdateRowSource.None; - - set - { - if (value != UpdateRowSource.None) - { - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - } - } - - protected override DbConnection DbConnection - { - get => _connection; - - set - { - if (value == null) - { - if (_connection == null) - { - return; - } - - // Unsetting connection not supported. - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - - if (!(value is SnowflakeDbConnection)) - { - // Must be of type SnowflakeDbConnection. - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - - var sfc = (SnowflakeDbConnection)value; - if (_connection != null && _connection != sfc) - { - // Connection already set. - throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); - } - - _connection = sfc; - if (sfc.SfSession != null) - { - _sfStatement = new SFStatement(sfc.SfSession, QueryTag); - } - } - } - - protected override DbParameterCollection DbParameterCollection - { - get { return this._parameterCollection; } - } - - protected override DbTransaction DbTransaction { get; set; } - - public override void Cancel() - { - // doesn't throw exception when sfStatement is null - _sfStatement?.Cancel(); - } - - public override int ExecuteNonQuery() - { - _logger.Debug($"ExecuteNonQuery"); - SFBaseResultSet resultSet = ExecuteInternal(); - long total = 0; - do - { - if (resultSet.HasResultSet()) continue; - int count = resultSet.CalculateUpdateCount(); - if (count < 0) - { - // exceeded max int, return -1 - return -1; - } - - total += count; - if (total > int.MaxValue) - { - return -1; - } - } while (resultSet.NextResult()); - - return (int)total; - } - - public override async Task ExecuteNonQueryAsync(CancellationToken cancellationToken) - { - _logger.Debug($"ExecuteNonQueryAsync"); - cancellationToken.ThrowIfCancellationRequested(); - - var resultSet = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); - long total = 0; - do - { - if (resultSet.HasResultSet()) continue; - int count = resultSet.CalculateUpdateCount(); - if (count < 0) - { - // exceeded max int, return -1 - return -1; - } - - total += count; - if (total > int.MaxValue) - { - return -1; - } - } while (await resultSet.NextResultAsync(cancellationToken).ConfigureAwait(false)); - - return (int)total; - } - - public override object ExecuteScalar() - { - _logger.Debug($"ExecuteScalar"); - SFBaseResultSet resultSet = ExecuteInternal(); - - if (resultSet.Next()) - return resultSet.GetValue(0); - else - return DBNull.Value; - } - - public override async Task ExecuteScalarAsync(CancellationToken cancellationToken) - { - _logger.Debug($"ExecuteScalarAsync"); - cancellationToken.ThrowIfCancellationRequested(); - - var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); - - if (await result.NextAsync().ConfigureAwait(false)) - return result.GetValue(0); - else - return DBNull.Value; - } - - /// - /// Prepares the command for execution. - /// This method is currently not implemented and acts as a no-operation (Noop). - /// - public override void Prepare() - { - } - - public string GetQueryId() - { - if (_sfStatement != null) - { - return _sfStatement.GetQueryId(); - } - - return null; - } - - protected override DbParameter CreateDbParameter() - { - return new SnowflakeDbParameter(); - } - - protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) - { - _logger.Debug($"ExecuteDbDataReader"); - SFBaseResultSet resultSet = ExecuteInternal(); - return new SnowflakeDbDataReader(this, resultSet); - } - - protected override async Task ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) - { - _logger.Debug($"ExecuteDbDataReaderAsync"); - try - { - var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); - return new SnowflakeDbDataReader(this, result); - } - catch (Exception ex) - { - _logger.Error("The command failed to execute.", ex); - throw; - } - } - - /// - /// Execute a query in async mode. - /// Async mode means the server will respond immediately with the query ID and execute the query asynchronously - /// - /// The query id. - public string ExecuteInAsyncMode() - { - _logger.Debug($"ExecuteInAsyncMode"); - SFBaseResultSet resultSet = ExecuteInternal(asyncExec: true); - return resultSet.queryId; - } - - /// - /// Executes an asynchronous query in async mode. - /// Async mode means the server will respond immediately with the query ID and execute the query asynchronously - /// - /// - /// The query id. - public async Task ExecuteAsyncInAsyncMode(CancellationToken cancellationToken) - { - _logger.Debug($"ExecuteAsyncInAsyncMode"); - var resultSet = await ExecuteInternalAsync(cancellationToken, asyncExec: true).ConfigureAwait(false); - return resultSet.queryId; - } - - /// - /// Gets the query status based on query ID. - /// - /// - /// The query status. - public QueryStatus GetQueryStatus(string queryId) - { - _logger.Debug($"GetQueryStatus"); - return _queryResultsAwaiter.GetQueryStatus(_connection, queryId); - } - - /// - /// Gets the query status based on query ID. - /// - /// - /// - /// The query status. - public async Task GetQueryStatusAsync(string queryId, CancellationToken cancellationToken) - { - _logger.Debug($"GetQueryStatusAsync"); - return await _queryResultsAwaiter.GetQueryStatusAsync(_connection, queryId, cancellationToken); - } - - /// - /// Gets the query results based on query ID. - /// - /// - /// The query results. - public DbDataReader GetResultsFromQueryId(string queryId) - { - _logger.Debug($"GetResultsFromQueryId"); - - Task task = _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, CancellationToken.None, false); - task.Wait(); - - SFBaseResultSet resultSet = _sfStatement.GetResultWithId(queryId); - - return new SnowflakeDbDataReader(this, resultSet); - } - - /// - /// Gets the query results based on query ID. - /// - /// - /// - /// The query results. - public async Task GetResultsFromQueryIdAsync(string queryId, CancellationToken cancellationToken) - { - _logger.Debug($"GetResultsFromQueryIdAsync"); - - await _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, cancellationToken, true); - - SFBaseResultSet resultSet = await _sfStatement.GetResultWithIdAsync(queryId, cancellationToken).ConfigureAwait(false); - - return new SnowflakeDbDataReader(this, resultSet); - } - - private static Dictionary _convertToBindList(List parameters) - { - if (parameters == null || parameters.Count == 0) - { - return null; - } - else - { - Dictionary binding = new Dictionary(); - foreach (SnowflakeDbParameter parameter in parameters) - { - string bindingType = ""; - object bindingVal; - - if (parameter.Value.GetType().IsArray && - // byte array and char array will not be treated as array binding - parameter.Value.GetType().GetElementType() != typeof(char) && - parameter.Value.GetType().GetElementType() != typeof(byte)) - { - List vals = new List(); - foreach (object val in (Array)parameter.Value) - { - // if the user is using interface, SFDataType will be None and there will - // a conversion from DbType to SFDataType - // if the user is using concrete class, they should specify SFDataType. - if (parameter.SFDataType == SFDataType.None) - { - Tuple typeAndVal = SFDataConverter - .csharpTypeValToSfTypeVal(parameter.DbType, val); - - bindingType = typeAndVal.Item1; - vals.Add(typeAndVal.Item2); - } - else - { - bindingType = parameter.SFDataType.ToString(); - vals.Add(SFDataConverter.csharpValToSfVal(parameter.SFDataType, val)); - } - } - - bindingVal = vals; - } - else - { - if (parameter.SFDataType == SFDataType.None) - { - Tuple typeAndVal = SFDataConverter - .csharpTypeValToSfTypeVal(parameter.DbType, parameter.Value); - bindingType = typeAndVal.Item1; - bindingVal = typeAndVal.Item2; - } - else - { - bindingType = parameter.SFDataType.ToString(); - bindingVal = SFDataConverter.csharpValToSfVal(parameter.SFDataType, parameter.Value); - } - } - - binding[parameter.ParameterName] = new BindingDTO(bindingType, bindingVal); - } - - return binding; - } - } - - private void SetStatement() - { - if (_connection == null) - { - throw new SnowflakeDbException(SFError.EXECUTE_COMMAND_ON_CLOSED_CONNECTION); - } - - var session = (_connection as SnowflakeDbConnection).SfSession; - - // SetStatement is called when executing a command. If SfSession is null - // the connection has never been opened. Exception might be a bit vague. - if (session == null) - throw new SnowflakeDbException(SFError.EXECUTE_COMMAND_ON_CLOSED_CONNECTION); - - this._sfStatement = new SFStatement(session, QueryTag); - } - - private SFBaseResultSet ExecuteInternal(bool describeOnly = false, bool asyncExec = false) - { - CheckIfCommandTextIsSet(); - SetStatement(); - return _sfStatement.Execute(CommandTimeout, CommandText, _convertToBindList(_parameterCollection.parameterList), describeOnly, asyncExec); - } - - private Task ExecuteInternalAsync(CancellationToken cancellationToken, bool describeOnly = false, bool asyncExec = false) - { - CheckIfCommandTextIsSet(); - SetStatement(); - return _sfStatement.ExecuteAsync(CommandTimeout, CommandText, _convertToBindList(_parameterCollection.parameterList), describeOnly, - asyncExec, cancellationToken); - } - - private void CheckIfCommandTextIsSet() - { - if (string.IsNullOrEmpty(CommandText)) - { - var errorMessage = "Unable to execute command due to command text not being set"; - _logger.Error(errorMessage); - throw new Exception(errorMessage); - } - } - - internal string GetBindStage() => _sfStatement?.GetBindStage(); - } -} +/* + * Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved. + */ + +using System; +using Snowflake.Data.Core; +using System.Data.Common; +using System.Data; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Snowflake.Data.Log; + +namespace Snowflake.Data.Client +{ + [System.ComponentModel.DesignerCategory("Code")] + public class SnowflakeDbCommand : DbCommand + { + private SnowflakeDbConnection _connection; + + private SFStatement _sfStatement; + + private SnowflakeDbParameterCollection _parameterCollection; + + private SFLogger _logger = SFLoggerFactory.GetLogger(); + + private readonly QueryResultsAwaiter _queryResultsAwaiter = QueryResultsAwaiter.Instance; + + public SnowflakeDbCommand() + { + _logger.Debug("Constructing SnowflakeDbCommand class"); + // by default, no query timeout + this.CommandTimeout = 0; + _parameterCollection = new SnowflakeDbParameterCollection(); + } + + public SnowflakeDbCommand(SnowflakeDbConnection connection) : this() + { + this._connection = connection; + } + + public SnowflakeDbCommand(SnowflakeDbConnection connection, string cmdText) : this(connection) + { + this.CommandText = cmdText; + } + + public override string CommandText { get; set; } + + public override int CommandTimeout { get; set; } + + public string QueryTag { get; set; } + + public override CommandType CommandType + { + get { return CommandType.Text; } + + set + { + if (value != CommandType.Text) + { + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + } + } + + public override bool DesignTimeVisible + { + get { return false; } + + set + { + if (value) + { + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + } + } + + public override UpdateRowSource UpdatedRowSource + { + get => UpdateRowSource.None; + + set + { + if (value != UpdateRowSource.None) + { + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + } + } + + protected override DbConnection DbConnection + { + get => _connection; + + set + { + if (value == null) + { + if (_connection == null) + { + return; + } + + // Unsetting connection not supported. + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + + if (!(value is SnowflakeDbConnection)) + { + // Must be of type SnowflakeDbConnection. + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + + var sfc = (SnowflakeDbConnection)value; + if (_connection != null && _connection != sfc) + { + // Connection already set. + throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE); + } + + _connection = sfc; + if (sfc.SfSession != null) + { + _sfStatement = new SFStatement(sfc.SfSession, QueryTag); + } + } + } + + protected override DbParameterCollection DbParameterCollection + { + get { return this._parameterCollection; } + } + + protected override DbTransaction DbTransaction { get; set; } + + public override void Cancel() + { + // doesn't throw exception when sfStatement is null + _sfStatement?.Cancel(); + } + + public override int ExecuteNonQuery() + { + _logger.Debug($"ExecuteNonQuery"); + SFBaseResultSet resultSet = ExecuteInternal(); + long total = 0; + do + { + if (resultSet.HasResultSet()) continue; + int count = resultSet.CalculateUpdateCount(); + if (count < 0) + { + // exceeded max int, return -1 + return -1; + } + + total += count; + if (total > int.MaxValue) + { + return -1; + } + } while (resultSet.NextResult()); + + return (int)total; + } + + public override async Task ExecuteNonQueryAsync(CancellationToken cancellationToken) + { + _logger.Debug($"ExecuteNonQueryAsync"); + cancellationToken.ThrowIfCancellationRequested(); + + var resultSet = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); + long total = 0; + do + { + if (resultSet.HasResultSet()) continue; + int count = resultSet.CalculateUpdateCount(); + if (count < 0) + { + // exceeded max int, return -1 + return -1; + } + + total += count; + if (total > int.MaxValue) + { + return -1; + } + } while (await resultSet.NextResultAsync(cancellationToken).ConfigureAwait(false)); + + return (int)total; + } + + public override object ExecuteScalar() + { + _logger.Debug($"ExecuteScalar"); + SFBaseResultSet resultSet = ExecuteInternal(); + + if (resultSet.Next()) + return resultSet.GetValue(0); + else + return DBNull.Value; + } + + public override async Task ExecuteScalarAsync(CancellationToken cancellationToken) + { + _logger.Debug($"ExecuteScalarAsync"); + cancellationToken.ThrowIfCancellationRequested(); + + var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); + + if (await result.NextAsync().ConfigureAwait(false)) + return result.GetValue(0); + else + return DBNull.Value; + } + + /// + /// Prepares the command for execution. + /// This method is currently not implemented and acts as a no-operation (Noop). + /// + public override void Prepare() + { + } + + public string GetQueryId() + { + if (_sfStatement != null) + { + return _sfStatement.GetQueryId(); + } + + return null; + } + + protected override DbParameter CreateDbParameter() + { + return new SnowflakeDbParameter(); + } + + protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) + { + _logger.Debug($"ExecuteDbDataReader"); + SFBaseResultSet resultSet = ExecuteInternal(); + return new SnowflakeDbDataReader(this, resultSet); + } + + protected override async Task ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) + { + _logger.Debug($"ExecuteDbDataReaderAsync"); + try + { + var result = await ExecuteInternalAsync(cancellationToken).ConfigureAwait(false); + return new SnowflakeDbDataReader(this, result); + } + catch (Exception ex) + { + _logger.Error("The command failed to execute.", ex); + throw; + } + } + + /// + /// Execute a query in async mode. + /// Async mode means the server will respond immediately with the query ID and execute the query asynchronously + /// + /// The query id. + public string ExecuteInAsyncMode() + { + _logger.Debug($"ExecuteInAsyncMode"); + SFBaseResultSet resultSet = ExecuteInternal(asyncExec: true); + return resultSet.queryId; + } + + /// + /// Executes an asynchronous query in async mode. + /// Async mode means the server will respond immediately with the query ID and execute the query asynchronously + /// + /// + /// The query id. + public async Task ExecuteAsyncInAsyncMode(CancellationToken cancellationToken) + { + _logger.Debug($"ExecuteAsyncInAsyncMode"); + var resultSet = await ExecuteInternalAsync(cancellationToken, asyncExec: true).ConfigureAwait(false); + return resultSet.queryId; + } + + /// + /// Gets the query status based on query ID. + /// + /// + /// The query status. + public QueryStatus GetQueryStatus(string queryId) + { + _logger.Debug($"GetQueryStatus"); + return _queryResultsAwaiter.GetQueryStatus(_connection, queryId); + } + + /// + /// Gets the query status based on query ID. + /// + /// + /// + /// The query status. + public async Task GetQueryStatusAsync(string queryId, CancellationToken cancellationToken) + { + _logger.Debug($"GetQueryStatusAsync"); + return await _queryResultsAwaiter.GetQueryStatusAsync(_connection, queryId, cancellationToken); + } + + /// + /// Gets the query results based on query ID. + /// + /// + /// The query results. + public DbDataReader GetResultsFromQueryId(string queryId) + { + _logger.Debug($"GetResultsFromQueryId"); + + Task task = _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, CancellationToken.None, false); + task.Wait(); + + SFBaseResultSet resultSet = _sfStatement.GetResultWithId(queryId); + + return new SnowflakeDbDataReader(this, resultSet); + } + + /// + /// Gets the query results based on query ID. + /// + /// + /// + /// The query results. + public async Task GetResultsFromQueryIdAsync(string queryId, CancellationToken cancellationToken) + { + _logger.Debug($"GetResultsFromQueryIdAsync"); + + await _queryResultsAwaiter.RetryUntilQueryResultIsAvailable(_connection, queryId, cancellationToken, true); + + SFBaseResultSet resultSet = await _sfStatement.GetResultWithIdAsync(queryId, cancellationToken).ConfigureAwait(false); + + return new SnowflakeDbDataReader(this, resultSet); + } + + private static Dictionary _convertToBindList(List parameters) + { + if (parameters == null || parameters.Count == 0) + { + return null; + } + else + { + Dictionary binding = new Dictionary(); + foreach (SnowflakeDbParameter parameter in parameters) + { + string bindingType = ""; + object bindingVal; + + if (parameter.Value.GetType().IsArray && + // byte array and char array will not be treated as array binding + parameter.Value.GetType().GetElementType() != typeof(char) && + parameter.Value.GetType().GetElementType() != typeof(byte)) + { + List vals = new List(); + foreach (object val in (Array)parameter.Value) + { + // if the user is using interface, SFDataType will be None and there will + // a conversion from DbType to SFDataType + // if the user is using concrete class, they should specify SFDataType. + if (parameter.SFDataType == SFDataType.None) + { + Tuple typeAndVal = SFDataConverter + .csharpTypeValToSfTypeVal(parameter.DbType, val); + + bindingType = typeAndVal.Item1; + vals.Add(typeAndVal.Item2); + } + else + { + bindingType = parameter.SFDataType.ToString(); + vals.Add(SFDataConverter.csharpValToSfVal(parameter.SFDataType, val)); + } + } + + bindingVal = vals; + } + else + { + if (parameter.SFDataType == SFDataType.None) + { + Tuple typeAndVal = SFDataConverter + .csharpTypeValToSfTypeVal(parameter.DbType, parameter.Value); + bindingType = typeAndVal.Item1; + bindingVal = typeAndVal.Item2; + } + else + { + bindingType = parameter.SFDataType.ToString(); + bindingVal = SFDataConverter.csharpValToSfVal(parameter.SFDataType, parameter.Value); + } + } + + binding[parameter.ParameterName] = new BindingDTO(bindingType, bindingVal); + } + + return binding; + } + } + + private void SetStatement() + { + if (_connection == null) + { + throw new SnowflakeDbException(SFError.EXECUTE_COMMAND_ON_CLOSED_CONNECTION); + } + + var session = (_connection as SnowflakeDbConnection).SfSession; + + // SetStatement is called when executing a command. If SfSession is null + // the connection has never been opened. Exception might be a bit vague. + if (session == null) + throw new SnowflakeDbException(SFError.EXECUTE_COMMAND_ON_CLOSED_CONNECTION); + + this._sfStatement = new SFStatement(session, QueryTag); + } + + private SFBaseResultSet ExecuteInternal(bool describeOnly = false, bool asyncExec = false) + { + CheckIfCommandTextIsSet(); + SetStatement(); + return _sfStatement.Execute(CommandTimeout, CommandText, _convertToBindList(_parameterCollection.parameterList), describeOnly, asyncExec); + } + + private Task ExecuteInternalAsync(CancellationToken cancellationToken, bool describeOnly = false, bool asyncExec = false) + { + CheckIfCommandTextIsSet(); + SetStatement(); + return _sfStatement.ExecuteAsync(CommandTimeout, CommandText, _convertToBindList(_parameterCollection.parameterList), describeOnly, + asyncExec, cancellationToken); + } + + private void CheckIfCommandTextIsSet() + { + if (string.IsNullOrEmpty(CommandText)) + { + var errorMessage = "Unable to execute command due to command text not being set"; + _logger.Error(errorMessage); + throw new Exception(errorMessage); + } + } + + internal string GetBindStage() => _sfStatement?.GetBindStage(); + } +} diff --git a/Snowflake.Data/Core/Session/SFSessionProperty.cs b/Snowflake.Data/Core/Session/SFSessionProperty.cs index a15d5fbe3..d76f2c865 100644 --- a/Snowflake.Data/Core/Session/SFSessionProperty.cs +++ b/Snowflake.Data/Core/Session/SFSessionProperty.cs @@ -413,29 +413,28 @@ private static void UpdatePropertiesForSpecialCases(SFSessionProperties properti case "SCHEMA": case "WAREHOUSE": case "ROLE": - { - if (tokens.Length == 2) { - var sessionProperty = (SFSessionProperty)Enum.Parse( - typeof(SFSessionProperty), propertyName); - properties[sessionProperty] = ProcessObjectEscapedCharacters(tokens[1]); + if (tokens.Length == 2) + { + var sessionProperty = (SFSessionProperty)Enum.Parse( + typeof(SFSessionProperty), propertyName); + properties[sessionProperty] = ProcessObjectEscapedCharacters(tokens[1]); + } + + break; } - - break; - } case "USER": case "PASSWORD": - { - - var sessionProperty = (SFSessionProperty)Enum.Parse( - typeof(SFSessionProperty), propertyName); - if (!properties.ContainsKey(sessionProperty)) { - properties.Add(sessionProperty, ""); - } + var sessionProperty = (SFSessionProperty)Enum.Parse( + typeof(SFSessionProperty), propertyName); + if (!properties.ContainsKey(sessionProperty)) + { + properties.Add(sessionProperty, ""); + } - break; - } + break; + } } } }