Skip to content

Commit

Permalink
Add ConnectionAttributes parameter
Browse files Browse the repository at this point in the history
Summary: We want to have an ability to pass custom connection attributes

Test Plan: https://app.circleci.com/pipelines/github/memsql/SingleStoreNETConnector/278/workflows/cd2e809b-bef6-4e13-95ec-75f42ac6dc65

Reviewers: okramarenko-ua

Reviewed By: okramarenko-ua

Subscribers: adam, engineering-list

Differential Revision: https://grizzly.internal.memcompute.com/D62855
  • Loading branch information
Pavlo committed Jun 1, 2023
1 parent 265902f commit 04d2cef
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/SingleStoreConnector/Core/ConnectionSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public ConnectionSettings(SingleStoreConnectionStringBuilder csb)
ApplicationName = csb.ApplicationName;
AutoEnlist = csb.AutoEnlist;
CancellationTimeout = csb.CancellationTimeout;
ConnAttrsExtra = csb.ConnectionAttributes;
ConnectionTimeout = ToSigned(csb.ConnectionTimeout);
ConvertZeroDateTime = csb.ConvertZeroDateTime;
DateTimeKind = (DateTimeKind) csb.DateTimeKind;
Expand Down Expand Up @@ -247,6 +248,7 @@ private static SingleStoreGuidFormat GetEffectiveGuidFormat(SingleStoreGuidForma
public bool UseCompression { get; }
public bool UseXaTransactions { get; }

public string ConnAttrsExtra { get; set; }
public byte[]? ConnectionAttributes { get; set; }

// Helper Functions
Expand Down Expand Up @@ -311,6 +313,7 @@ private ConnectionSettings(ConnectionSettings other, string host, int port, stri
AllowZeroDateTime = other.AllowZeroDateTime;
ApplicationName = other.ApplicationName;
AutoEnlist = other.AutoEnlist;
ConnAttrsExtra = other.ConnAttrsExtra;
ConnectionTimeout = other.ConnectionTimeout;
ConvertZeroDateTime = other.ConvertZeroDateTime;
DateTimeKind = other.DateTimeKind;
Expand Down
16 changes: 13 additions & 3 deletions src/SingleStoreConnector/Core/ServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
} while (shouldRetrySsl);

if (m_supportsConnectionAttributes && cs.ConnectionAttributes is null)
cs.ConnectionAttributes = CreateConnectionAttributes(cs.ApplicationName);
cs.ConnectionAttributes = CreateConnectionAttributes(cs.ApplicationName, cs.ConnAttrsExtra);

var password = GetPassword(cs, connection);
using (var handshakeResponsePayload = HandshakeResponse41Payload.Create(initialHandshake, cs, password, m_useCompression, m_characterSet, m_supportsConnectionAttributes ? cs.ConnectionAttributes : null))
Expand Down Expand Up @@ -1822,12 +1822,12 @@ private void VerifyState(State state1, State state2, State state3, State state4,

internal SslProtocols SslProtocol => m_sslStream?.SslProtocol ?? SslProtocols.None;

private byte[] CreateConnectionAttributes(string programName)
private byte[] CreateConnectionAttributes(string programName, string connAttrsExtra)
{
Log.Trace("Session{0} creating connection attributes", m_logArguments);
var attributesWriter = new ByteBufferWriter();
attributesWriter.WriteLengthEncodedString("_client_name");
attributesWriter.WriteLengthEncodedString("SingleStoreConnector");
attributesWriter.WriteLengthEncodedString("SingleStore .NET Connector");
attributesWriter.WriteLengthEncodedString("_client_version");

var version = typeof(ServerSession).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion;
Expand Down Expand Up @@ -1865,6 +1865,16 @@ private byte[] CreateConnectionAttributes(string programName)
attributesWriter.WriteLengthEncodedString("program_name");
attributesWriter.WriteLengthEncodedString(programName!);
}
if (connAttrsExtra.Length != 0)
{
foreach (var attr in connAttrsExtra.Split(','))
{
foreach (var attrPart in attr.Split(':'))
{
attributesWriter.WriteLengthEncodedString(attrPart);
}
}
}
using var connectionAttributesPayload = attributesWriter.ToPayloadData();
var connectionAttributes = connectionAttributesPayload.Span;
var writer = new ByteBufferWriter(connectionAttributes.Length + 9);
Expand Down
19 changes: 19 additions & 0 deletions src/SingleStoreConnector/SingleStoreConnectionStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,20 @@ public string ApplicationName
set => SingleStoreConnectionStringOption.ApplicationName.SetValue(this, value);
}

/// <summary>
/// Sets connection attributes passed to SingleStore Server.
/// </summary>
[AllowNull]
[Category("Other")]
[DefaultValue("")]
[Description("Sets connection attributes passed to SingleStore Server.")]
[DisplayName("Connection Attributes")]
public string ConnectionAttributes
{
get => SingleStoreConnectionStringOption.ConnectionAttributes.GetValue(this);
set => SingleStoreConnectionStringOption.ConnectionAttributes.SetValue(this, value);
}

/// <summary>
/// Automatically enlists this connection in any active <see cref="System.Transactions.TransactionScope"/>.
/// </summary>
Expand Down Expand Up @@ -952,6 +966,7 @@ internal abstract partial class SingleStoreConnectionStringOption
public static readonly SingleStoreConnectionStringValueOption<bool> AutoEnlist;
public static readonly SingleStoreConnectionStringValueOption<int> CancellationTimeout;
public static readonly SingleStoreConnectionStringReferenceOption<string> CharacterSet;
public static readonly SingleStoreConnectionStringReferenceOption<string> ConnectionAttributes;
public static readonly SingleStoreConnectionStringValueOption<uint> ConnectionTimeout;
public static readonly SingleStoreConnectionStringValueOption<bool> ConvertZeroDateTime;
public static readonly SingleStoreConnectionStringValueOption<SingleStoreDateTimeKind> DateTimeKind;
Expand Down Expand Up @@ -1171,6 +1186,10 @@ static SingleStoreConnectionStringOption()
keys: new[] { "Application Name", "ApplicationName" },
defaultValue: ""));

AddOption(ConnectionAttributes = new(
keys: new[] { "Connection Attributes", "ConnectionAttributes" },
defaultValue: ""));

AddOption(AutoEnlist = new(
keys: new[] { "Auto Enlist", "AutoEnlist" },
defaultValue: true));
Expand Down
27 changes: 27 additions & 0 deletions tests/SideBySide/ConnectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,33 @@ public void CloneWithCopiesExistingPassword()
Assert.Equal(ConnectionState.Open, connection2.State);
}

[Fact]
public void ConnectionAttributes()
{
var attrs = "ConnectionAttributes=my_key_1:my_val_1,my_key_2:my_val_2";
using var connection = new SingleStoreConnection(AppConfig.ConnectionString + ";" + attrs);
connection.Open();

if (connection.Session.S2ServerVersion.Version.CompareTo(new Version(8, 1, 0)) >= 0)
{
using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT ATTRIBUTE_NAME, ATTRIBUTE_VALUE FROM information_schema.mv_connection_attributes;";

using var reader = cmd.ExecuteReader();
HashSet<Tuple<string, string>> dbConnAttrs = new HashSet<Tuple<string, string>>();
while (reader.Read())
{
dbConnAttrs.Add(new Tuple<string, string>(reader.GetString(0), reader.GetString(1)));
}
Tuple<string, string> expectedPair = new Tuple<string, string>("my_key_1", "my_val_1");
Assert.Contains(expectedPair, dbConnAttrs);
expectedPair = new Tuple<string, string>("my_key_2", "my_val_2");
Assert.Contains(expectedPair, dbConnAttrs);
expectedPair = new Tuple<string, string>("_client_name", "SingleStore .NET Connector");
Assert.Contains(expectedPair, dbConnAttrs);
}
}

[Fact]
public async Task ResetConnectionThrowsIfNotOpen()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public void ParseConnectionString()
"default command timeout=123;" +
#if !BASELINE
"application name=My Test Application;" +
"ConnectionAttributes=my_attr_name:my_value;" +
"cancellation timeout = -1;" +
"connectionidletimeout=30;" +
"defer connection reset=true;" +
Expand Down Expand Up @@ -194,6 +195,7 @@ public void ParseConnectionString()
Assert.Equal(123u, csb.DefaultCommandTimeout);
#if !BASELINE
Assert.Equal("My Test Application", csb.ApplicationName);
Assert.Equal("my_attr_name:my_value", csb.ConnectionAttributes);
Assert.Equal(30u, csb.ConnectionIdleTimeout);
#pragma warning disable 618
Assert.True(csb.DeferConnectionReset);
Expand Down Expand Up @@ -246,7 +248,7 @@ public void ParseConnectionString()
"Pooling=False;Connection Lifetime=15;Connection Reset=False;Defer Connection Reset=True;Connection Idle Timeout=30;" +
"Minimum Pool Size=5;Maximum Pool Size=15;DNS Check Interval=15;" +
"Allow Load Local Infile=True;Allow Public Key Retrieval=True;Allow User Variables=True;" +
"Allow Zero DateTime=True;Application Name=\"My Test Application\";Auto Enlist=False;Cancellation Timeout=-1;Character Set=latin1;" +
"Allow Zero DateTime=True;Application Name=\"My Test Application\";Connection Attributes=my_attr_name:my_value;Auto Enlist=False;Cancellation Timeout=-1;Character Set=latin1;" +
"Connection Timeout=30;Convert Zero DateTime=True;DateTime Kind=Utc;Default Command Timeout=123;Force Synchronous=True;" +
"TreatChar48AsGeographyPoint=True;GUID Format=TimeSwapBinary16;Ignore Command Transaction=True;Ignore Prepare=True;Interactive Session=True;" +
"Keep Alive=90;No Backslash Escapes=True;Old Guids=True;Persist Security Info=True;Pipelining=False;Server Redirection Mode=Required;" +
Expand Down

0 comments on commit 04d2cef

Please sign in to comment.