Skip to content

Commit

Permalink
Merge pull request #89 from snowflakedb/pr-84
Browse files Browse the repository at this point in the history
Pr 84
  • Loading branch information
howryu authored Oct 30, 2018
2 parents f2bb8cb + 2ea7582 commit 66d4239
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 15 deletions.
9 changes: 9 additions & 0 deletions Snowflake.Data.Tests/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ Copyright (c) 2012-2017 Snowflake Computing Inc. All rights reserved.
<appender-ref ref="MyRollingFileAppender" />
</root>
</log4net>

<!-- used in SFDbFactoryIT.cs to test registering DbProviderFactoryClass -->
<system.data>
<DbProviderFactories>
<add name="Snowflake" invariant="Snowflake.Data"
type="Snowflake.Data.Client.SnowflakeDbFactory, Snowflake.Data, Culture=neutral, PublicKeyToken=null"
description="Snowflake Provider" />
</DbProviderFactories>
</system.data>

<!--
=========== Enable Network debug log ===============
Expand Down
39 changes: 39 additions & 0 deletions Snowflake.Data.Tests/SFDbFactoryIT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2012-2017 Snowflake Computing Inc. All rights reserved.
*/

namespace Snowflake.Data.Tests
{
using NUnit.Framework;
using Snowflake.Data;
using System.Data.Common;

[TestFixture]
class SFDbFactoryIT : SFBaseTest
{
[Test]
public void TestSimpleDbFactory()
{
#if NET46
DbProviderFactory factory = DbProviderFactories.GetFactory("Snowflake.Data");
#else
// In .NET Standard, DbProviderFactories is gone.
// Reference https://weblog.west-wind.com/posts/2017/Nov/27/Working-around-the-lack-of-dynamic-DbProviderFactory-loading-in-NET-Core
// for more details
DbProviderFactory factory = Snowflake.Data.Client.SnowflakeDbFactory.Instance;
#endif
DbCommand command = factory.CreateCommand();
DbConnection connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
connection.Open();
// set commnad's connection object
command.Connection = connection;

command.CommandText = "select 1";
object res = command.ExecuteScalar();
Assert.AreEqual(1, res);

connection.Close();
}
}
}
45 changes: 36 additions & 9 deletions Snowflake.Data/Client/SnowflakeDbCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ public class SnowflakeDbCommand : DbCommand

private SFLogger logger = SFLoggerFactory.GetLogger<SnowflakeDbCommand>();

public SnowflakeDbCommand()
{
logger.Debug("Constucting SnowflakeDbCommand class");
// by default, no query timeout
this.CommandTimeout = 0;
parameterCollection = new SnowflakeDbParameterCollection();
}

public SnowflakeDbCommand(SnowflakeDbConnection connection)
{
logger.Debug("Constucting SnowflakeDbCommand class");
Expand Down Expand Up @@ -79,10 +87,7 @@ public override bool DesignTimeVisible

public override UpdateRowSource UpdatedRowSource
{
get
{
return UpdateRowSource.None;
}
get => UpdateRowSource.None;

set
{
Expand All @@ -95,14 +100,36 @@ public override UpdateRowSource UpdatedRowSource

protected override DbConnection DbConnection
{
get
{
return connection;
}
get => connection;

set
{
throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE);
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;
sfStatement = new SFStatement(sfc.SfSession);
}
}

Expand Down
114 changes: 114 additions & 0 deletions Snowflake.Data/Client/SnowflakeDbCommandBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System.Data;
using System.Data.Common;
using System.Globalization;

namespace Snowflake.Data.Client
{
public class SnowflakeDbCommandBuilder : DbCommandBuilder
{
/// <summary>
/// Initializes a new instance of the <see cref="SnowflakeDbCommandBuilder"/> class.
/// </summary>
public SnowflakeDbCommandBuilder()
: this(null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="SnowflakeDbCommandBuilder"/> class.
/// </summary>
/// <param name="adapter">The adapter.</param>
public SnowflakeDbCommandBuilder(SnowflakeDbDataAdapter adapter)
{
DataAdapter = adapter;
QuotePrefix = "\"";
QuoteSuffix = "\"";
}

/// <summary>
/// Gets or sets the beginning character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
/// </summary>
/// <returns>
/// The beginning character or characters to use. The default is an empty string.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
public sealed override string QuotePrefix
{
get => base.QuotePrefix;
// TODO: Why should it be possible to remove the QuotePrefix?
set => base.QuotePrefix = string.IsNullOrEmpty(value) ? value : "\"";
}

/// <summary>
/// Gets or sets the ending character or characters to use when specifying database objects (for example, tables or columns) whose names contain characters such as spaces or reserved tokens.
/// </summary>
/// <returns>
/// The ending character or characters to use. The default is an empty string.
/// </returns>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" PathDiscovery="*AllFiles*" />
/// </PermissionSet>
public sealed override string QuoteSuffix
{
get => base.QuoteSuffix;
// TODO: Why should it be possible to remove the QuoteSuffix?
set => base.QuoteSuffix = string.IsNullOrEmpty(value) ? value : "\"";
}

/// <summary>
/// Applies the parameter information.
/// </summary>
/// <param name="p">The parameter.</param>
/// <param name="row">The row.</param>
/// <param name="statementType">Type of the statement.</param>
/// <param name="whereClause">if set to <c>true</c> [where clause].</param>
protected override void ApplyParameterInfo(DbParameter p, DataRow row, StatementType statementType, bool whereClause)
{
var param = (SnowflakeDbParameter)p;
param.DbType = (DbType)row[SchemaTableColumn.ProviderType];
}

/// <summary>
/// Returns the name of the specified parameter in the format of #.
/// </summary>
/// <param name="parameterOrdinal">The number to be included as part of the parameter's name..</param>
/// <returns>
/// The name of the parameter with the specified number appended as part of the parameter name.
/// </returns>
protected override string GetParameterName(int parameterOrdinal)
{
return string.Format(CultureInfo.InvariantCulture, "{0}", parameterOrdinal);
}

/// <summary>
/// Returns the full parameter name, given the partial parameter name.
/// </summary>
/// <param name="parameterName">The partial name of the parameter.</param>
/// <returns>
/// The full parameter name corresponding to the partial parameter name requested.
/// </returns>
protected override string GetParameterName(string parameterName)
{
return string.Format(CultureInfo.InvariantCulture, "{0}", parameterName);
}

/// <summary>
/// Returns the placeholder for the parameter in the associated SQL statement.
/// </summary>
/// <param name="parameterOrdinal">The number to be included as part of the parameter's name.</param>
/// <returns>
/// The name of the parameter with the specified number appended.
/// </returns>
protected override string GetParameterPlaceholder(int parameterOrdinal)
{
return GetParameterName(parameterOrdinal);
}

/// <inheritdoc />
protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
{
}
}
}
15 changes: 12 additions & 3 deletions Snowflake.Data/Client/SnowflakeDbConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,26 +83,28 @@ public override void ChangeDatabase(string databaseName)

public override void Close()
{
logger.Debug($"Close Connection.");
logger.Debug("Close Connection.");

if (_connectionState != ConnectionState.Closed && SfSession != null)
{
SfSession.close();
_connectionState = ConnectionState.Closed;
}

_connectionState = ConnectionState.Closed;
}

public override void Open()
{
logger.Debug($"Open Connection.");
logger.Debug("Open Connection.");
SetSession();
SfSession.Open();
OnSessionEstablished();
}

public override Task OpenAsync(CancellationToken cancellationToken)
{
logger.Debug($"Open Connection Async.");
logger.Debug("Open Connection Async.");
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);

Expand All @@ -124,6 +126,13 @@ private void OnSessionEstablished()

protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
// Parameterless BeginTransaction() method of the super class calls this method with IsolationLevel.Unspecified,
// Change the isolation level to ReadCommitted
if (isolationLevel == IsolationLevel.Unspecified)
{
isolationLevel = IsolationLevel.ReadCommitted;
}

return new SnowflakeDbTransaction(isolationLevel, this);
}

Expand Down
11 changes: 11 additions & 0 deletions Snowflake.Data/Client/SnowflakeDbConnectionStringBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text;

namespace Snowflake.Data.Client
{
public class SnowflakeDbConnectionStringBuilder : DbConnectionStringBuilder
{
}
}
39 changes: 39 additions & 0 deletions Snowflake.Data/Client/SnowflakeDbFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Data.Common;

namespace Snowflake.Data.Client
{
public sealed class SnowflakeDbFactory : DbProviderFactory
{
public static readonly SnowflakeDbFactory Instance = new SnowflakeDbFactory();

/// <summary>
/// Returns a strongly typed <see cref="DbCommand"/> instance.
/// </summary>
public override DbCommand CreateCommand() => new SnowflakeDbCommand();

/// <summary>
/// Returns a strongly typed <see cref="DbConnection"/> instance.
/// </summary>
public override DbConnection CreateConnection() => new SnowflakeDbConnection();

/// <summary>
/// Returns a strongly typed <see cref="DbParameter"/> instance.
/// </summary>
public override DbParameter CreateParameter() => new SnowflakeDbParameter();

/// <summary>
/// Returns a strongly typed <see cref="DbConnectionStringBuilder"/> instance.
/// </summary>
public override DbConnectionStringBuilder CreateConnectionStringBuilder() => new SnowflakeDbConnectionStringBuilder();

/// <summary>
/// Returns a strongly typed <see cref="DbCommandBuilder"/> instance.
/// </summary>
public override DbCommandBuilder CreateCommandBuilder() => new SnowflakeDbCommandBuilder();

/// <summary>
/// Returns a strongly typed <see cref="DbDataAdapter"/> instance.
/// </summary>
public override DbDataAdapter CreateDataAdapter() => new SnowflakeDbDataAdapter();
}
}
2 changes: 1 addition & 1 deletion Snowflake.Data/Client/SnowflakeDbTransaction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public SnowflakeDbTransaction(IsolationLevel isolationLevel, SnowflakeDbConnecti
throw new SnowflakeDbException(SFError.UNSUPPORTED_FEATURE);
}

this.isolationLevel = IsolationLevel;
this.isolationLevel = isolationLevel;
this.connection = connection;

using (IDbCommand command = connection.CreateCommand())
Expand Down
4 changes: 2 additions & 2 deletions Snowflake.Data/Core/SFSessionProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ internal static SFSessionProperties parseConnectionString(String connectionStrin
}
catch (ArgumentException e)
{
logger.Warn($"Property {token[0]} not found ignored.");
logger.Warn($"Property {token[0]} not found ignored.", e);
}
}
else
{
string invalidStringDetail = String.Format("Invalid kay value pair {0}", keyVal);
string invalidStringDetail = String.Format("Invalid key value pair {0}", keyVal);
SnowflakeDbException e = new SnowflakeDbException(SFError.INVALID_CONNECTION_STRING,
new object[] { invalidStringDetail });
logger.Error("Invalid string.", e);
Expand Down

0 comments on commit 66d4239

Please sign in to comment.