diff --git a/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/DatabaseObject.cs b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/DatabaseObject.cs
new file mode 100644
index 0000000000..2dc539b5f5
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/DatabaseObject.cs
@@ -0,0 +1,263 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text;
+using System.Threading;
+
+namespace Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
+
+///
+/// Base class for a transient database object (such as a table, type or
+/// stored procedure.)
+///
+public abstract class DatabaseObject : IDisposable
+{
+ private readonly bool _shouldDrop;
+
+ protected SqlConnection Connection { get; }
+
+ public string Name { get; }
+
+ protected DatabaseObject(SqlConnection connection, string name, string definition, bool shouldCreate, bool shouldDrop)
+ {
+ _shouldDrop = shouldDrop;
+
+ Connection = connection;
+ Name = name;
+
+ if (shouldCreate)
+ {
+ EnsureConnectionOpen();
+ DropObject();
+ CreateObject(definition);
+ }
+ }
+
+ private void EnsureConnectionOpen()
+ {
+ const int MaxWaits = 2;
+ int counter = MaxWaits;
+
+ if (Connection.State is System.Data.ConnectionState.Closed)
+ {
+ Connection.Open();
+ }
+ while (counter-- > 0 && Connection.State is System.Data.ConnectionState.Connecting)
+ {
+ Thread.Sleep(80);
+ }
+ }
+
+ ///
+ /// Generate a new GUID and return the characters from its 1st and 4th
+ /// parts, as shown here:
+ ///
+ ///
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
+ /// ^^^^^^^^ ^^^^
+ ///
+ ///
+ /// These 12 characters are concatenated together without any
+ /// separators. These 2 parts typically comprise a timestamp and clock
+ /// sequence, most likely to be unique for tests that generate names in
+ /// quick succession.
+ ///
+ private static string GetGuidParts()
+ {
+ var guid = Guid.NewGuid().ToString();
+ // GOTCHA: The slice operator is inclusive of the start index and
+ // exclusive of the end index!
+ return guid.Substring(0, 8) + guid.Substring(19, 4);
+ }
+
+ ///
+ /// Generate a long unique database object name, whose maximum length is
+ /// 96 characters, with the format:
+ ///
+ /// {Prefix}_{GuidParts}_{UserName}_{MachineName}
+ ///
+ /// The Prefix will be truncated to satisfy the overall maximum length.
+ ///
+ /// The GUID Parts will be the characters from the 1st and 4th blocks
+ /// from a traditional string representation, as shown here:
+ ///
+ ///
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
+ /// ^^^^^^^^ ^^^^
+ ///
+ ///
+ /// These 2 parts typically comprise a timestamp and clock sequence,
+ /// most likely to be unique for tests that generate names in quick
+ /// succession. The 12 characters are concatenated together without any
+ /// separators.
+ ///
+ /// The UserName and MachineName are obtained from the Environment,
+ /// and will be truncated to satisfy the maximum overall length.
+ ///
+ ///
+ ///
+ /// The prefix to use when generating the unique name, truncated to at
+ /// most 32 characters.
+ ///
+ /// This should not contain any characters that cannot be used in
+ /// database object names. See:
+ ///
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
+ ///
+ ///
+ ///
+ /// When true, the entire generated name will be enclosed in square
+ /// brackets, for example:
+ ///
+ /// [MyPrefix_7ff01cb811f0_test_user_ci_agent_machine_name]
+ ///
+ ///
+ ///
+ /// A unique database object name, no more than 96 characters long.
+ ///
+ public static string GenerateLongName(string prefix, bool escape = true)
+ {
+ StringBuilder name = new(96);
+
+ if (escape)
+ {
+ name.Append('[');
+ }
+
+ if (prefix.Length > 32)
+ {
+ prefix = prefix.Substring(0, 32);
+ }
+
+ name.Append(prefix);
+ name.Append('_');
+ name.Append(GetGuidParts());
+ name.Append('_');
+
+ var suffix =
+ Environment.UserName + '_' +
+ Environment.MachineName;
+
+ int maxSuffixLength = 96 - name.Length;
+ if (escape)
+ {
+ --maxSuffixLength;
+ }
+ if (suffix.Length > maxSuffixLength)
+ {
+ suffix = suffix.Substring(0, maxSuffixLength);
+ }
+
+ name.Append(suffix);
+
+ if (escape)
+ {
+ name.Append(']');
+ }
+
+ return name.ToString();
+ }
+
+ ///
+ /// Generate a short unique database object name, whose maximum length
+ /// is 30 characters, with the format:
+ ///
+ /// {Prefix}_{GuidParts}
+ ///
+ /// The Prefix will be truncated to satisfy the overall maximum length.
+ ///
+ /// The GUID parts will be the characters from the 1st and 4th blocks
+ /// from a traditional string representation, as shown here:
+ ///
+ ///
+ /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
+ /// ^^^^^^^^ ^^^^
+ ///
+ ///
+ /// These 2 parts typically comprise a timestamp and clock sequence,
+ /// most likely to be unique for tests that generate names in quick
+ /// succession. The 12 characters are concatenated together without any
+ /// separators.
+ ///
+ ///
+ ///
+ /// The prefix to use when generating the unique name, truncated to at
+ /// most 18 characters when withBracket is false, and 16 characters when
+ /// withBracket is true.
+ ///
+ /// This should not contain any characters that cannot be used in
+ /// database object names. See:
+ ///
+ /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
+ ///
+ ///
+ ///
+ /// When true, the entire generated name will be enclosed in square
+ /// brackets, for example:
+ ///
+ /// [MyPrefix_7ff01cb811f0]
+ ///
+ ///
+ ///
+ /// A unique database object name, no more than 30 characters long.
+ ///
+ public static string GenerateShortName(string prefix, bool escape = true)
+ {
+ StringBuilder name = new(30);
+
+ if (escape)
+ {
+ name.Append('[');
+ }
+
+ int maxPrefixLength = escape ? 16 : 18;
+ if (prefix.Length > maxPrefixLength)
+ {
+ prefix = prefix.Substring(0, maxPrefixLength);
+ }
+
+ name.Append(prefix);
+ name.Append('_');
+ name.Append(GetGuidParts());
+
+ if (escape)
+ {
+ name.Append(']');
+ }
+
+ return name.ToString();
+ }
+
+ ///
+ /// Creates the object with a given definition.
+ ///
+ /// Definition of the object to create.
+ ///
+ /// By the time this is called, will be open.
+ ///
+ protected abstract void CreateObject(string definition);
+
+ ///
+ /// Drops the object created by .
+ ///
+ ///
+ /// By the time this is called, will be open.
+ /// Must not throw an exception if the object does not exist.
+ ///
+ protected abstract void DropObject();
+
+ public void Dispose()
+ {
+ if (_shouldDrop)
+ {
+ EnsureConnectionOpen();
+ DropObject();
+ }
+ // This explicitly does not drop the wrapped SqlConnection; this is sometimes
+ // used in a loop to create multiple UDTs.
+
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/StoredProcedure.cs b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/StoredProcedure.cs
new file mode 100644
index 0000000000..d1b60612d1
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/StoredProcedure.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
+
+///
+/// A transient stored procedure, created at the start of its scope and dropped when disposed.
+///
+public sealed class StoredProcedure : DatabaseObject
+{
+ ///
+ /// Initializes a new instance of the StoredProcedure class using the specified SQL connection,
+ /// name and definition.
+ ///
+ ///
+ /// If a stored procedure with the specified name already exists, it will be dropped automatically
+ /// before creation.
+ ///
+ /// The SQL connection used to interact with the database.
+ /// The stored procedure name. Can begin with '#' or '##' to indicate a temporary procedure.
+ /// The SQL definition of the stored procedure.
+ public StoredProcedure(SqlConnection connection, string prefix, string definition)
+ : base(connection, GenerateLongName(prefix), definition, shouldCreate: true, shouldDrop: true)
+ {
+ }
+
+ protected override void CreateObject(string definition)
+ {
+ using SqlCommand createCommand = new($"CREATE PROCEDURE {Name} {definition}", Connection);
+
+ createCommand.ExecuteNonQuery();
+ }
+
+ protected override void DropObject()
+ {
+ using SqlCommand dropCommand = new($"IF (OBJECT_ID('{Name}') IS NOT NULL) DROP PROCEDURE {Name}", Connection);
+
+ dropCommand.ExecuteNonQuery();
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/Table.cs b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/Table.cs
new file mode 100644
index 0000000000..2838ae2272
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/Table.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
+
+///
+/// A transient table, created at the start of its scope and dropped when disposed.
+///
+public sealed class Table : DatabaseObject
+{
+ ///
+ /// Initializes a new instance of the Table class using the specified SQL connection, table name prefix, and table
+ /// definition.
+ ///
+ ///
+ /// If a table with the specified name already exists, it will be dropped automatically before
+ /// creation.
+ ///
+ /// The SQL connection used to interact with the database.
+ /// The prefix for the table name. Can begin with '#' or '##' to indicate a temporary table.
+ /// The SQL definition describing the structure of the table, including columns and data types.
+ public Table(SqlConnection connection, string prefix, string definition)
+ : base(connection, GenerateLongName(prefix), definition, shouldCreate: true, shouldDrop: true)
+ {
+ }
+
+ protected override void CreateObject(string definition)
+ {
+ using SqlCommand createCommand = new($"CREATE TABLE {Name} {definition}", Connection);
+
+ createCommand.ExecuteNonQuery();
+ }
+
+ protected override void DropObject()
+ {
+ using SqlCommand dropCommand = new($"IF (OBJECT_ID('{Name}') IS NOT NULL) DROP TABLE {Name}", Connection);
+
+ dropCommand.ExecuteNonQuery();
+ }
+
+ ///
+ /// Deletes all data from the table.
+ ///
+ public void DeleteData()
+ {
+ using SqlCommand deleteCommand = new($"DELETE FROM {Name}", Connection);
+
+ deleteCommand.ExecuteNonQuery();
+ }
+
+ ///
+ /// Truncates the table.
+ ///
+ public void Truncate()
+ {
+ using SqlCommand truncateCommand = new($"TRUNCATE TABLE {Name}", Connection);
+
+ truncateCommand.ExecuteNonQuery();
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/UserDefinedType.cs b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/UserDefinedType.cs
new file mode 100644
index 0000000000..6d536d7550
--- /dev/null
+++ b/src/Microsoft.Data.SqlClient/tests/Common/Fixtures/DatabaseObjects/UserDefinedType.cs
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
+
+///
+/// A transient user-defined type, created at the start of its scope and dropped when disposed.
+///
+public sealed class UserDefinedType : DatabaseObject
+{
+ ///
+ /// Initializes a new instance of the UserDefinedType class using the specified SQL connection,
+ /// name and definition.
+ ///
+ ///
+ /// If a user-defined type with the specified name already exists, it will be dropped automatically
+ /// before creation.
+ ///
+ /// The SQL connection used to interact with the database.
+ /// The type name.
+ /// The SQL definition of the type.
+ public UserDefinedType(SqlConnection connection, string prefix, string definition)
+ : base(connection, "[dbo]." + GenerateLongName(prefix), definition, shouldCreate: true, shouldDrop: true)
+ {
+ }
+
+ protected override void CreateObject(string definition)
+ {
+ using SqlCommand createCommand = new($"CREATE TYPE {Name} AS {definition}", Connection);
+
+ createCommand.ExecuteNonQuery();
+ }
+
+ protected override void DropObject()
+ {
+ using SqlCommand dropCommand = new($"IF (OBJECT_ID('{Name}') IS NOT NULL) DROP TYPE {Name}", Connection);
+
+ dropCommand.ExecuteNonQuery();
+ }
+}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
index 7d63e9b98f..1c16e90ac4 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs
@@ -735,44 +735,28 @@ public async Task TestExecuteReaderAsyncWithLargeQuery(string connectionString)
int columnsCount = 50;
// Arrange - drops the table with long name and re-creates it with 52 columns (ID, name, ColumnName0..49)
- try
- {
- CreateTable(connectionString, tableName, columnsCount);
- string name = "nobody";
+ using SqlConnection connection = new SqlConnection(connectionString);
+ await connection.OpenAsync();
- using (SqlConnection connection = new SqlConnection(connectionString))
- {
- await connection.OpenAsync();
- // This creates a "select top 100" query that has over 40k characters
- using (SqlCommand sqlCommand = new SqlCommand(GenerateSelectQuery(tableName, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"),
- connection,
- transaction: null,
- columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled))
- {
- sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int);
- sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar, name.Length);
+ using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects.Table wideTable = new(connection, tableName, GenerateBitTableDefinition(columnsCount));
+ string name = "nobody";
- sqlCommand.Parameters[0].Value = 0;
- sqlCommand.Parameters[1].Value = name;
+ // This creates a "select top 100" query that has over 40k characters
+ using SqlCommand sqlCommand = new(GenerateSelectQuery(wideTable.Name, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"),
+ connection,
+ transaction: null,
+ columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled);
+ sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int);
+ sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar, name.Length);
- // Act and Assert
- // Test that execute reader async does not throw an exception.
- // The table is empty so there should be no results; however, the bug previously found is that it causes a TDS RPC exception on enclave.
- using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync())
- {
- Assert.False(sqlDataReader.HasRows, "The table should be empty");
- }
- }
- }
- }
- catch
- {
- throw;
- }
- finally
- {
- DropTableIfExists(connectionString, tableName);
- }
+ sqlCommand.Parameters[0].Value = 0;
+ sqlCommand.Parameters[1].Value = name;
+
+ // Act and Assert
+ // Test that execute reader async does not throw an exception.
+ // The table is empty so there should be no results; however, the bug previously found is that it causes a TDS RPC exception on enclave.
+ using SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync();
+ Assert.False(sqlDataReader.HasRows, "The table should be empty");
}
[ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.IsTargetReadyForAeWithKeyStore))]
@@ -3055,30 +3039,15 @@ private void CleanUpTable(string connString, string tableName)
}
}
- private static void CreateTable(string connString, string tableName, int columnsCount)
- => DataTestUtility.RunNonQuery(connString, GenerateCreateQuery(tableName, columnsCount));
- ///
- /// Drops the table if the specified table exists
- ///
- /// The connection string to the database
- /// The name of the table to be dropped
- private static void DropTableIfExists(string connString, string tableName)
- {
- using var sqlConnection = new SqlConnection(connString);
- sqlConnection.Open();
- DataTestUtility.DropTable(sqlConnection, tableName);
- }
-
///
- /// Generates the query for creating a table with the number of bit columns specified.
+ /// Generates the definition of a table with the number of bit columns specified.
///
/// The name of the table
/// The number of columns for the table
///
- private static string GenerateCreateQuery(string tableName, int columnsCount)
+ private static string GenerateBitTableDefinition(int columnsCount)
{
StringBuilder builder = new StringBuilder();
- builder.Append(string.Format("CREATE TABLE [dbo].[{0}]", tableName));
builder.Append('(');
builder.AppendLine("[ID][bigint] NOT NULL,");
builder.AppendLine("[Name] [varchar] (200) NOT NULL");
@@ -3104,16 +3073,16 @@ private static string GenerateSelectQuery(string tableName, int columnsCount, in
{
StringBuilder builder = new StringBuilder();
builder.AppendLine($"SELECT TOP 100");
- builder.AppendLine($"[{tableName}].[ID],");
- builder.AppendLine($"[{tableName}].[Name]");
+ builder.AppendLine($"{tableName}.[ID],");
+ builder.AppendLine($"{tableName}.[Name]");
for (int i = 0; i < columnsCount; i++)
{
builder.Append(",");
- builder.AppendLine($"[{tableName}].[ColumnName{i}]");
+ builder.AppendLine($"{tableName}.[ColumnName{i}]");
}
- string extra = string.IsNullOrEmpty(where) ? $"(NOLOCK) [{tableName}]" : where;
- builder.AppendLine($"FROM [{tableName}] {extra};");
+ string extra = string.IsNullOrEmpty(where) ? $"(NOLOCK) {tableName}" : where;
+ builder.AppendLine($"FROM {tableName} {extra};");
StringBuilder builder2 = new StringBuilder();
for (int i = 0; i < repeat; i++)
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
index 3b4245d84f..01049191c5 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
@@ -22,6 +22,7 @@
using System.Threading.Tasks;
using Azure.Core;
using Azure.Identity;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
using Microsoft.Data.SqlClient.TestUtilities;
using Microsoft.Identity.Client;
using Xunit;
@@ -638,177 +639,11 @@ public static bool DoesHostAddressContainBothIPv4AndIPv6()
}
}
- // Generate a new GUID and return the characters from its 1st and 4th
- // parts, as shown here:
- //
- // 7ff01cb8-88c7-11f0-b433-00155d7e531e
- // ^^^^^^^^ ^^^^
- //
- // These 12 characters are concatenated together without any
- // separators. These 2 parts typically comprise a timestamp and clock
- // sequence, most likely to be unique for tests that generate names in
- // quick succession.
- private static string GetGuidParts()
- {
- var guid = Guid.NewGuid().ToString();
- // GOTCHA: The slice operator is inclusive of the start index and
- // exclusive of the end index!
- return guid.Substring(0, 8) + guid.Substring(19, 4);
- }
-
- ///
- /// Generate a short unique database object name, whose maximum length
- /// is 30 characters, with the format:
- ///
- /// _
- ///
- /// The Prefix will be truncated to satisfy the overall maximum length.
- ///
- /// The GUID parts will be the characters from the 1st and 4th blocks
- /// from a traditional string representation, as shown here:
- ///
- /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
- /// ^^^^^^^^ ^^^^
- ///
- /// These 2 parts typically comprise a timestamp and clock sequence,
- /// most likely to be unique for tests that generate names in quick
- /// succession. The 12 characters are concatenated together without any
- /// separators.
- ///
- ///
- ///
- /// The prefix to use when generating the unique name, truncated to at
- /// most 18 characters when withBracket is false, and 16 characters when
- /// withBracket is true.
- ///
- /// This should not contain any characters that cannot be used in
- /// database object names. See:
- ///
- /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
- ///
- ///
- ///
- /// When true, the entire generated name will be enclosed in square
- /// brackets, for example:
- ///
- /// [MyPrefix_7ff01cb811f0]
- ///
- ///
- ///
- /// A unique database object name, no more than 30 characters long.
- ///
- public static string GetShortName(string prefix, bool withBracket = true)
- {
- StringBuilder name = new(30);
-
- if (withBracket)
- {
- name.Append('[');
- }
-
- int maxPrefixLength = withBracket ? 16 : 18;
- if (prefix.Length > maxPrefixLength)
- {
- prefix = prefix.Substring(0, maxPrefixLength);
- }
-
- name.Append(prefix);
- name.Append('_');
- name.Append(GetGuidParts());
-
- if (withBracket)
- {
- name.Append(']');
- }
-
- return name.ToString();
- }
-
- ///
- /// Generate a long unique database object name, whose maximum length is
- /// 96 characters, with the format:
- ///
- /// ___
- ///
- /// The Prefix will be truncated to satisfy the overall maximum length.
- ///
- /// The GUID Parts will be the characters from the 1st and 4th blocks
- /// from a traditional string representation, as shown here:
- ///
- /// 7ff01cb8-88c7-11f0-b433-00155d7e531e
- /// ^^^^^^^^ ^^^^
- ///
- /// These 2 parts typically comprise a timestamp and clock sequence,
- /// most likely to be unique for tests that generate names in quick
- /// succession. The 12 characters are concatenated together without any
- /// separators.
- ///
- /// The UserName and MachineName are obtained from the Environment,
- /// and will be truncated to satisfy the maximum overall length.
- ///
- ///
- ///
- /// The prefix to use when generating the unique name, truncated to at
- /// most 32 characters.
- ///
- /// This should not contain any characters that cannot be used in
- /// database object names. See:
- ///
- /// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
- ///
- ///
- ///
- /// When true, the entire generated name will be enclosed in square
- /// brackets, for example:
- ///
- /// [MyPrefix_7ff01cb811f0_test_user_ci_agent_machine_name]
- ///
- ///
- ///
- /// A unique database object name, no more than 96 characters long.
- ///
- public static string GetLongName(string prefix, bool withBracket = true)
- {
- StringBuilder name = new(96);
+ public static string GetShortName(string prefix, bool withBracket = true) =>
+ DatabaseObject.GenerateShortName(prefix, withBracket);
- if (withBracket)
- {
- name.Append('[');
- }
-
- if (prefix.Length > 32)
- {
- prefix = prefix.Substring(0, 32);
- }
-
- name.Append(prefix);
- name.Append('_');
- name.Append(GetGuidParts());
- name.Append('_');
-
- var suffix =
- Environment.UserName + '_' +
- Environment.MachineName;
-
- int maxSuffixLength = 96 - name.Length;
- if (withBracket)
- {
- --maxSuffixLength;
- }
- if (suffix.Length > maxSuffixLength)
- {
- suffix = suffix.Substring(0, maxSuffixLength);
- }
-
- name.Append(suffix);
-
- if (withBracket)
- {
- name.Append(']');
- }
-
- return name.ToString();
- }
+ public static string GetLongName(string prefix, bool withBracket = true) =>
+ DatabaseObject.GenerateLongName(prefix, withBracket);
public static void CreateTable(SqlConnection sqlConnection, string tableName, string createBody)
{
@@ -841,15 +676,6 @@ public static void DropTable(SqlConnection sqlConnection, string tableName)
}
}
- public static void DropUserDefinedType(SqlConnection sqlConnection, string typeName)
- {
- ResurrectConnection(sqlConnection);
- using (SqlCommand cmd = new SqlCommand(string.Format("IF (TYPE_ID('{0}') IS NOT NULL) \n DROP TYPE {0}", typeName), sqlConnection))
- {
- cmd.ExecuteNonQuery();
- }
- }
-
public static void DropStoredProcedure(SqlConnection sqlConnection, string spName)
{
ResurrectConnection(sqlConnection);
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs
index eee3b2d515..cbba92153a 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonStreamTest.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -13,6 +13,7 @@
using Xunit;
using Xunit.Abstractions;
using Newtonsoft.Json.Linq;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
@@ -164,15 +165,20 @@ private void DeleteFile(string filename)
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonStreaming()
{
- GenerateJsonFile(1000, _jsonFile);
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
+ try
{
+ GenerateJsonFile(1000, _jsonFile);
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
connection.Open();
- var tableName = DataTestUtility.GetLongName("jsonTab");
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
- StreamJsonFileToServer(connection, tableName);
- PrintJsonDataToFile(connection, tableName);
+
+ using Table jsonTable = new(connection, "jsonTab", "(data json)");
+
+ StreamJsonFileToServer(connection, jsonTable.Name);
+ PrintJsonDataToFile(connection, jsonTable.Name);
CompareJsonFiles();
+ }
+ finally
+ {
DeleteFile(_jsonFile);
DeleteFile(_outputFile);
}
@@ -181,15 +187,20 @@ public void TestJsonStreaming()
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public async Task TestJsonStreamingAsync()
{
- GenerateJsonFile(1000, _jsonFile);
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
+ try
{
+ GenerateJsonFile(1000, _jsonFile);
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
await connection.OpenAsync();
- var tableName = DataTestUtility.GetLongName("jsonTab");
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
- await StreamJsonFileToServerAsync(connection, tableName);
- await PrintJsonDataToFileAsync(connection, tableName);
+
+ using Table jsonTable = new(connection, "jsonTab", "(data json)");
+
+ await StreamJsonFileToServerAsync(connection, jsonTable.Name);
+ await PrintJsonDataToFileAsync(connection, jsonTable.Name);
CompareJsonFiles();
+ }
+ finally
+ {
DeleteFile(_jsonFile);
DeleteFile(_outputFile);
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs
index 516f9d1750..0652251447 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -11,19 +11,20 @@
using Xunit.Abstractions;
using System.Text.Json;
using Microsoft.Data.SqlTypes;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class JsonTest
{
+ private const string JsonDataString = "[{\"name\":\"Dave\",\"skills\":[\"Python\"]},{\"name\":\"Ron\",\"surname\":\"Peter\"}]";
+
private readonly ITestOutputHelper _output;
public JsonTest(ITestOutputHelper output)
{
_output = output;
}
-
- private static readonly string JsonDataString = "[{\"name\":\"Dave\",\"skills\":[\"Python\"]},{\"name\":\"Ron\",\"surname\":\"Peter\"}]";
private void ValidateRowsAffected(int rowsAffected)
{
@@ -76,380 +77,264 @@ private void ValidateNullJson(SqlDataReader reader)
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonWrite()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string spName = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string spCreate = "CREATE PROCEDURE " + spName + " (@jsonData json) AS " + tableInsert;
+ using Table jsonTable = new(connection, nameof(TestJsonWrite), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ using StoredProcedure insertJsonProcedure = new(connection, nameof(TestJsonWrite), $"(@jsonData json) AS {tableInsert}");
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
- {
- connection.Open();
+ using SqlCommand command = connection.CreateCommand();
- using (SqlCommand command = connection.CreateCommand())
- {
- //Create Table
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
-
- //Create SP for writing json values
- DataTestUtility.DropStoredProcedure(connection, spName);
- command.CommandText = spCreate;
- command.ExecuteNonQuery();
-
- command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- command.Parameters.Add(parameter);
-
- //Test 1
- //Write json value using a parameterized query
- parameter.Value = JsonDataString;
- int rowsAffected = command.ExecuteNonQuery();
- ValidateRowsAffected(rowsAffected);
-
- //Test 2
- //Write a SqlString type as json
- parameter.Value = new SqlString(JsonDataString);
- int rowsAffected2 = command.ExecuteNonQuery();
- ValidateRowsAffected(rowsAffected2);
-
- //Test 3
- //Write json value using SP
- using (SqlCommand command2 = connection.CreateCommand())
- {
- command2.CommandText = spName;
- command2.CommandType = CommandType.StoredProcedure;
- var parameter2 = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter2.Value = JsonDataString;
- command2.Parameters.Add(parameter2);
- int rowsAffected3 = command2.ExecuteNonQuery();
- ValidateRowsAffected(rowsAffected3);
- }
-
- //Test 4
- // Write json value using a parameterized query with SqlJson type
- parameter.Value = new SqlJson(JsonDataString);
- int rowsAffected4 = command.ExecuteNonQuery();
- ValidateRowsAffected(rowsAffected4);
-
- DataTestUtility.DropTable(connection, tableName);
- DataTestUtility.DropStoredProcedure(connection, spName);
- }
+ command.CommandText = tableInsert;
+ var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
+ command.Parameters.Add(parameter);
+
+ //Test 1
+ //Write json value using a parameterized query
+ parameter.Value = JsonDataString;
+ int rowsAffected = command.ExecuteNonQuery();
+ ValidateRowsAffected(rowsAffected);
+
+ //Test 2
+ //Write a SqlString type as json
+ parameter.Value = new SqlString(JsonDataString);
+ int rowsAffected2 = command.ExecuteNonQuery();
+ ValidateRowsAffected(rowsAffected2);
+
+ //Test 3
+ //Write json value using SP
+ using (SqlCommand command2 = connection.CreateCommand())
+ {
+ command2.CommandText = insertJsonProcedure.Name;
+ command2.CommandType = CommandType.StoredProcedure;
+ command2.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ int rowsAffected3 = command2.ExecuteNonQuery();
+ ValidateRowsAffected(rowsAffected3);
}
+
+ //Test 4
+ // Write json value using a parameterized query with SqlJson type
+ parameter.Value = new SqlJson(JsonDataString);
+ int rowsAffected4 = command.ExecuteNonQuery();
+ ValidateRowsAffected(rowsAffected4);
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public async Task TestJsonWriteAsync()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string spName = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ await connection.OpenAsync();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string spCreate = "CREATE PROCEDURE " + spName + " (@jsonData json) AS " + tableInsert;
+ using Table jsonTable = new(connection, nameof(TestJsonWriteAsync), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ using StoredProcedure insertJsonProcedure = new(connection, nameof(TestJsonWriteAsync), $"(@jsonData json) AS {tableInsert}");
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
- {
- await connection.OpenAsync();
+ using SqlCommand command = connection.CreateCommand();
+ command.CommandText = tableInsert;
+ SqlParameter parameter = new("@jsonData", SqlDbTypeExtensions.Json);
+ command.Parameters.Add(parameter);
- using (SqlCommand command = connection.CreateCommand())
- {
- //Create Table
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
-
- //Create SP for writing json values
- DataTestUtility.DropStoredProcedure(connection, spName);
- command.CommandText = spCreate;
- await command.ExecuteNonQueryAsync();
-
- command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- command.Parameters.Add(parameter);
-
- //Test 1
- //Write json value using a parameterized query
- parameter.Value = JsonDataString;
- int rowsAffected = await command.ExecuteNonQueryAsync();
- ValidateRowsAffected(rowsAffected);
-
- //Test 2
- //Write a SqlString type as json
- parameter.Value = new SqlString(JsonDataString);
- int rowsAffected2 = await command.ExecuteNonQueryAsync();
- ValidateRowsAffected(rowsAffected2);
-
- //Test 3
- //Write json value using SP
- using (SqlCommand command2 = connection.CreateCommand())
- {
- command2.CommandText = spName;
- command2.CommandType = CommandType.StoredProcedure;
- var parameter2 = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter2.Value = JsonDataString;
- command2.Parameters.Add(parameter2);
- int rowsAffected3 = await command.ExecuteNonQueryAsync();
- ValidateRowsAffected(rowsAffected3);
- }
-
- //Test 4
- // Write json value using a parameterized query with SqlJson type
- parameter.Value = new SqlJson(JsonDataString);
- int rowsAffected4 = await command.ExecuteNonQueryAsync();
- ValidateRowsAffected(rowsAffected4);
-
- DataTestUtility.DropTable(connection, tableName);
- DataTestUtility.DropStoredProcedure(connection, spName);
- }
+ //Test 1
+ //Write json value using a parameterized query
+ parameter.Value = JsonDataString;
+ int rowsAffected = await command.ExecuteNonQueryAsync();
+ ValidateRowsAffected(rowsAffected);
+
+ //Test 2
+ //Write a SqlString type as json
+ parameter.Value = new SqlString(JsonDataString);
+ int rowsAffected2 = await command.ExecuteNonQueryAsync();
+ ValidateRowsAffected(rowsAffected2);
+
+ //Test 3
+ //Write json value using SP
+ using (SqlCommand command2 = connection.CreateCommand())
+ {
+ command2.CommandText = insertJsonProcedure.Name;
+ command2.CommandType = CommandType.StoredProcedure;
+ command2.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ int rowsAffected3 = await command.ExecuteNonQueryAsync();
+ ValidateRowsAffected(rowsAffected3);
}
+
+ //Test 4
+ // Write json value using a parameterized query with SqlJson type
+ parameter.Value = new SqlJson(JsonDataString);
+ int rowsAffected4 = await command.ExecuteNonQueryAsync();
+ ValidateRowsAffected(rowsAffected4);
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonRead()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string spName = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string tableRead = "SELECT * FROM " + tableName;
- string spCreate = "CREATE PROCEDURE " + spName + " AS " + tableRead;
+ using Table jsonTable = new(connection, nameof(TestJsonRead), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ string tableRead = $"SELECT * FROM {jsonTable.Name}";
+ using StoredProcedure readJsonProcedure = new(connection, nameof(TestJsonRead), $"AS {tableRead}");
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
+ using SqlCommand command = connection.CreateCommand();
+
+ //Insert sample json data
+ //This will be used for reading
+ command.CommandText = tableInsert;
+ command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ command.ExecuteNonQuery();
+
+ //Test 1
+ //Read json value using query
+ command.CommandText = tableRead;
+ using (SqlDataReader reader = command.ExecuteReader())
{
- connection.Open();
- using (SqlCommand command = connection.CreateCommand())
- {
- //Create Table
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
-
- //Create SP for reading from json column
- DataTestUtility.DropStoredProcedure(connection, spName);
- command.CommandText = spCreate;
- command.ExecuteNonQuery();
-
- //Insert sample json data
- //This will be used for reading
- command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter.Value = JsonDataString;
- command.Parameters.Add(parameter);
- command.ExecuteNonQuery();
-
- //Test 1
- //Read json value using query
- command.CommandText = tableRead;
- var reader = command.ExecuteReader();
- ValidateRows(reader);
-
- //Test 2
- //Read the column metadata
- ValidateSchema(reader);
- reader.Close();
-
- //Test 3
- //Read json value using SP
- using (SqlCommand command2 = connection.CreateCommand())
- {
- command2.CommandText = spName;
- command2.CommandType = CommandType.StoredProcedure;
- var reader2 = command2.ExecuteReader();
- ValidateRows(reader2);
- reader2.Close();
- }
-
- DataTestUtility.DropTable(connection, tableName);
- DataTestUtility.DropStoredProcedure(connection, spName);
- }
+ ValidateRows(reader);
+
+ //Test 2
+ //Read the column metadata
+ ValidateSchema(reader);
}
+
+ //Test 3
+ //Read json value using SP
+ using SqlCommand command2 = connection.CreateCommand();
+ command2.CommandText = readJsonProcedure.Name;
+ command2.CommandType = CommandType.StoredProcedure;
+ using SqlDataReader reader2 = command2.ExecuteReader();
+ ValidateRows(reader2);
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public async Task TestJsonReadAsync()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string spName = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ await connection.OpenAsync();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string tableRead = "SELECT * FROM " + tableName;
- string spCreate = "CREATE PROCEDURE " + spName + " AS " + tableRead;
+ using Table jsonTable = new(connection, nameof(TestJsonReadAsync), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ string tableRead = $"SELECT * FROM {jsonTable.Name}";
+ using StoredProcedure readJsonProcedure = new(connection, nameof(TestJsonRead), $"AS {tableRead}");
+
+ using SqlCommand command = connection.CreateCommand();
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
+ //Insert sample json data
+ //This will be used for reading
+ command.CommandText = tableInsert;
+ command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ await command.ExecuteNonQueryAsync();
+
+ //Test 1
+ //Read json value using query
+ command.CommandText = tableRead;
+ using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
- await connection.OpenAsync();
- using (SqlCommand command = connection.CreateCommand())
- {
- //Create Table
- DataTestUtility.CreateTable(connection, tableName, "(data json)");
-
- //Create SP for reading from json column
- DataTestUtility.DropStoredProcedure(connection, spName);
- command.CommandText = spCreate;
- await command.ExecuteNonQueryAsync();
-
- //Insert sample json data
- //This will be used for reading
- command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter.Value = JsonDataString;
- command.Parameters.Add(parameter);
- await command.ExecuteNonQueryAsync();
-
- //Test 1
- //Read json value using query
- command.CommandText = tableRead;
- var reader = await command.ExecuteReaderAsync();
- await ValidateRowsAsync(reader);
-
- //Test 2
- //Read the column metadata
- ValidateSchema(reader);
- reader.Close();
-
- //Test 3
- //Read json value using SP
- using (SqlCommand command2 = connection.CreateCommand())
- {
- command2.CommandText = spName;
- command2.CommandType = CommandType.StoredProcedure;
- var reader2 = await command2.ExecuteReaderAsync();
- await ValidateRowsAsync(reader2);
- reader2.Close();
- }
-
- DataTestUtility.DropTable(connection, tableName);
- DataTestUtility.DropStoredProcedure(connection, spName);
- }
+ await ValidateRowsAsync(reader);
+
+ //Test 2
+ //Read the column metadata
+ ValidateSchema(reader);
}
+
+ //Test 3
+ //Read json value using SP
+ using SqlCommand command2 = connection.CreateCommand();
+ command2.CommandText = readJsonProcedure.Name;
+ command2.CommandType = CommandType.StoredProcedure;
+ using SqlDataReader reader2 = await command2.ExecuteReaderAsync();
+ await ValidateRowsAsync(reader2);
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestNullJson()
{
- string tableName = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string tableRead = "SELECT * FROM " + tableName;
+ using Table jsonTable = new(connection, nameof(TestNullJson), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ string tableRead = $"SELECT * FROM {jsonTable.Name}";
- using SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString);
- connection.Open();
using SqlCommand command = connection.CreateCommand();
- //Create Table
- DataTestUtility.CreateTable(connection, tableName, "(Data json)");
-
//Insert Null value
command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter.Value = DBNull.Value;
- command.Parameters.Add(parameter);
+ command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = DBNull.Value });
command.ExecuteNonQuery();
//Query the table
command.CommandText = tableRead;
- var reader = command.ExecuteReader();
+ using SqlDataReader reader = command.ExecuteReader();
ValidateNullJson(reader);
-
- reader.Close();
- DataTestUtility.DropTable(connection, tableName);
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonAPIs()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
- string tableRead = "SELECT * FROM " + tableName;
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
+ using Table jsonTable = new(connection, nameof(TestJsonAPIs), "(data json)");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@jsonData)";
+ string tableRead = $"SELECT * FROM {jsonTable.Name}";
+
+ using SqlCommand command = connection.CreateCommand();
+ //Insert
+ command.CommandText = tableInsert;
+ command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ command.ExecuteNonQuery();
+
+ // Query the table
+ command.CommandText = tableRead;
+ using SqlDataReader reader = command.ExecuteReader();
+ while (reader.Read())
{
- connection.Open();
- using (SqlCommand command = connection.CreateCommand())
- {
- try
- {
- // Create Table
- DataTestUtility.CreateTable(connection, tableName, "(Data json)");
-
- //Insert
- command.CommandText = tableInsert;
- var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
- parameter.Value = JsonDataString;
- command.Parameters.Add(parameter);
- command.ExecuteNonQuery();
-
- // Query the table
- command.CommandText = tableRead;
- using (var reader = command.ExecuteReader())
- {
- while (reader.Read())
- {
- string data = reader.GetFieldValue(0);
- Assert.Equal(JsonDataString, data);
- JsonDocument jsonDocument = reader.GetFieldValue(0);
- Assert.Equal(JsonDataString, jsonDocument.RootElement.ToString());
- Assert.Equal("json", reader.GetDataTypeName(0));
- Assert.Equal("System.String", reader.GetFieldType(0).ToString());
- Assert.Equal(JsonDataString, reader.GetSqlJson(0).Value);
- }
- }
- }
- finally
- {
- DataTestUtility.DropTable(connection, tableName);
- }
- }
+ string data = reader.GetFieldValue(0);
+ Assert.Equal(JsonDataString, data);
+ JsonDocument jsonDocument = reader.GetFieldValue(0);
+ Assert.Equal(JsonDataString, jsonDocument.RootElement.ToString());
+ Assert.Equal("json", reader.GetDataTypeName(0));
+ Assert.Equal("System.String", reader.GetFieldType(0).ToString());
+ Assert.Equal(JsonDataString, reader.GetSqlJson(0).Value);
}
}
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonWithMARS()
{
- string table1Name = DataTestUtility.GenerateObjectName();
- string table2Name = DataTestUtility.GenerateObjectName();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString + "MultipleActiveResultSets=True;");
+ connection.Open();
+
+ using Table jsonTable1 = new(connection, nameof(TestJsonWithMARS), "(Data json)");
+ using Table jsonTable2 = new(connection, nameof(TestJsonWithMARS), "(Id int, Data json)");
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString + "MultipleActiveResultSets=True;"))
+ // Insert Data
+ string table1Insert = $"INSERT INTO {jsonTable1.Name} VALUES ('{JsonDataString}')";
+ string table2Insert = $"INSERT INTO {jsonTable2.Name} VALUES (1,'{JsonDataString}')";
+ using (SqlCommand command = connection.CreateCommand())
{
- connection.Open();
- try
+ command.CommandText = table1Insert;
+ command.ExecuteNonQuery();
+ command.CommandText = table2Insert;
+ command.ExecuteNonQuery();
+ }
+
+ // Read Data
+ using SqlCommand command1 = new($"select * from {jsonTable1.Name}", connection);
+ using SqlCommand command2 = new($"select * from {jsonTable2.Name}", connection);
+
+ using (SqlDataReader reader1 = command1.ExecuteReader())
+ {
+ while (reader1.Read())
{
- // Create Table
- DataTestUtility.CreateTable(connection, table1Name, "(Data json)");
- DataTestUtility.CreateTable(connection, table2Name, "(Id int, Data json)");
-
- // Insert Data
- string table1Insert = "INSERT INTO " + table1Name + " VALUES ('" + JsonDataString + "')";
- string table2Insert = "INSERT INTO " + table2Name + " VALUES (1,'" + JsonDataString + "')";
- using (SqlCommand command = connection.CreateCommand())
- {
- command.CommandText = table1Insert;
- command.ExecuteNonQuery();
- command.CommandText = table2Insert;
- command.ExecuteNonQuery();
- }
-
- // Read Data
- using (SqlCommand command1 = new SqlCommand("select * from " + table1Name, connection))
- using (SqlCommand command2 = new SqlCommand("select * from " + table2Name, connection))
- {
- using (SqlDataReader reader1 = command1.ExecuteReader())
- {
- while (reader1.Read())
- {
- Assert.Equal(JsonDataString, reader1["data"]);
- }
-
- using (SqlDataReader reader2 = command2.ExecuteReader())
- {
- while (reader2.Read())
- {
- Assert.Equal(1, reader2["Id"]);
- Assert.Equal(JsonDataString, reader2["data"]);
- }
- }
- }
- }
+ Assert.Equal(JsonDataString, reader1["data"]);
}
- finally
+
+ using SqlDataReader reader2 = command2.ExecuteReader();
+ while (reader2.Read())
{
- DataTestUtility.DropTable(connection, table1Name);
- DataTestUtility.DropTable(connection, table2Name);
+ Assert.Equal(1, reader2["Id"]);
+ Assert.Equal(JsonDataString, reader2["data"]);
}
}
}
@@ -457,53 +342,34 @@ public void TestJsonWithMARS()
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAzureServer), nameof(DataTestUtility.IsNotManagedInstance))]
public void TestJsonSPParams()
{
- string tableName = DataTestUtility.GenerateObjectName();
- string procName = DataTestUtility.GenerateObjectName();
- string tableInsert = $"INSERT INTO {tableName} VALUES (@id, @jsonData)";
- string tableRead = $"SELECT * FROM {tableName}";
-
- using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
- {
- connection.Open();
- try
- {
- // Create Table
- DataTestUtility.CreateTable(connection, tableName, "(Id int, Data json)");
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- // Create Stored Procedure
- string createSP = $@"
+ using Table jsonTable = new(connection, nameof(TestJsonSPParams), "(Id int, Data json)");
+ using StoredProcedure readJsonProcedure = new(connection, nameof(TestJsonRead), $@"
@id int,
@jsonData json OUTPUT
AS
BEGIN
- SELECT @jsonData = (SELECT Data FROM {tableName} WHERE Id = @id)
- END;";
- DataTestUtility.CreateSP(connection, procName, createSP);
-
- // Insert Data
- using (SqlCommand command = new SqlCommand(tableInsert, connection))
- {
- command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Value = 1 });
- command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
- command.ExecuteNonQuery();
- }
-
- // Execute Stored Procedure
- using (SqlCommand spCommand = new SqlCommand(procName, connection))
- {
- spCommand.CommandType = CommandType.StoredProcedure;
- spCommand.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Direction = ParameterDirection.Input, Value = 1 });
- SqlParameter outputParam = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Direction = ParameterDirection.Output };
- spCommand.Parameters.Add(outputParam);
- spCommand.ExecuteNonQuery();
- Assert.Equal(JsonDataString, (string)outputParam.Value);
- }
- }
- finally
- {
- DataTestUtility.DropTable(connection, tableName);
- }
- }
+ SELECT @jsonData = (SELECT Data FROM {jsonTable.Name} WHERE Id = @id)
+ END;");
+ string tableInsert = $"INSERT INTO {jsonTable.Name} VALUES (@id, @jsonData)";
+
+ // Insert Data
+ using SqlCommand command = new(tableInsert, connection);
+ command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Value = 1 });
+ command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString });
+ command.ExecuteNonQuery();
+
+ // Execute Stored Procedure
+ using SqlCommand spCommand = new(readJsonProcedure.Name, connection);
+
+ spCommand.CommandType = CommandType.StoredProcedure;
+ spCommand.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Direction = ParameterDirection.Input, Value = 1 });
+ SqlParameter outputParam = new("@jsonData", SqlDbTypeExtensions.Json) { Direction = ParameterDirection.Output };
+ spCommand.Parameters.Add(outputParam);
+ spCommand.ExecuteNonQuery();
+ Assert.Equal(JsonDataString, (string)outputParam.Value);
}
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs
index a4cd63b0c1..b3ca97e0d1 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs
@@ -12,6 +12,8 @@
using Xunit;
using System.Globalization;
using Microsoft.Data.SqlClient.Tests.Common;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
+
#if !NETFRAMEWORK
@@ -120,49 +122,32 @@ public static void CodeCoverageSqlClient()
public static void Test_Copy_SqlParameter()
{
using var conn = new SqlConnection(s_connString);
- string cTableName = DataTestUtility.GetLongName("#tmp");
- try
- {
- // Create tmp table
- var sCreateTable = "IF NOT EXISTS(";
- sCreateTable += $"SELECT * FROM sysobjects WHERE name= '{ cTableName }' and xtype = 'U')";
- sCreateTable += $"CREATE TABLE { cTableName }( BinValue binary(16) null)";
+ conn.Open();
- conn.Open();
- var cmd = new SqlCommand(sCreateTable, conn);
- cmd.ExecuteNonQuery();
+ using Table binTable = new(conn, "#tmp", "(BinValue binary(16) null)");
- var dt = new DataTable("SourceDataTable");
- dt.Columns.Add("SourceBinValue", typeof(byte[]));
+ using var dt = new DataTable("SourceDataTable");
+ dt.Columns.Add("SourceBinValue", typeof(byte[]));
- dt.Rows.Add(Guid.NewGuid().ToByteArray());
- dt.Rows.Add(DBNull.Value);
+ dt.Rows.Add(Guid.NewGuid().ToByteArray());
+ dt.Rows.Add(DBNull.Value);
- var cmdInsert = new SqlCommand
- {
- UpdatedRowSource = UpdateRowSource.None,
- Connection = conn,
+ using var cmdInsert = new SqlCommand
+ {
+ UpdatedRowSource = UpdateRowSource.None,
+ Connection = conn,
- CommandText = $"INSERT { cTableName } (BinValue) "
- };
- cmdInsert.CommandText += "Values(@BinValue)";
- cmdInsert.Parameters.Add("@BinValue", SqlDbType.Binary, 16, "SourceBinValue");
+ CommandText = $"INSERT {binTable.Name} (BinValue) VALUES (@BinValue)"
+ };
+ cmdInsert.Parameters.Add("@BinValue", SqlDbType.Binary, 16, "SourceBinValue");
- var da = new SqlDataAdapter
- {
- InsertCommand = cmdInsert,
- UpdateBatchSize = 2,
- AcceptChangesDuringUpdate = false
- };
- da.Update(dt);
- }
- finally
+ using var da = new SqlDataAdapter
{
- // End of test, cleanup tmp table;
- var sDropTable = $"DROP TABLE IF EXISTS {cTableName}";
- using SqlCommand cmd = new(sDropTable, conn);
- cmd.ExecuteNonQuery();
- }
+ InsertCommand = cmdInsert,
+ UpdateBatchSize = 2,
+ AcceptChangesDuringUpdate = false
+ };
+ da.Update(dt);
}
// TODO Synapse: Remove dependency on Northwind database
@@ -170,8 +155,8 @@ public static void Test_Copy_SqlParameter()
public static void Test_SqlParameter_Constructor()
{
using var conn = new SqlConnection(s_connString);
- var dataTable = new DataTable();
- var adapter = new SqlDataAdapter
+ using var dataTable = new DataTable();
+ using var adapter = new SqlDataAdapter
{
SelectCommand = new SqlCommand("SELECT CustomerID, ContactTitle FROM dbo.Customers WHERE ContactTitle = @ContactTitle", conn)
};
@@ -202,7 +187,7 @@ public static void Test_WithEnumValue_ShouldInferToUnderlyingType()
{
using var conn = new SqlConnection(s_connString);
conn.Open();
- var cmd = new SqlCommand("select @input", conn);
+ using var cmd = new SqlCommand("select @input", conn);
cmd.Parameters.AddWithValue("@input", MyEnum.B);
object value = cmd.ExecuteScalar();
Assert.Equal(MyEnum.B, (MyEnum)value);
@@ -213,7 +198,7 @@ public static void Test_WithOutputEnumParameter_ShouldReturnEnum()
{
using var conn = new SqlConnection(s_connString);
conn.Open();
- var cmd = new SqlCommand("set @output = @input", conn);
+ using var cmd = new SqlCommand("set @output = @input", conn);
cmd.Parameters.AddWithValue("@input", MyEnum.B);
SqlParameter outputParam = cmd.CreateParameter();
outputParam.ParameterName = "@output";
@@ -229,7 +214,7 @@ public static void Test_WithDecimalValue_ShouldReturnDecimal()
{
using var conn = new SqlConnection(s_connString);
conn.Open();
- var cmd = new SqlCommand("select @foo", conn);
+ using var cmd = new SqlCommand("select @foo", conn);
cmd.Parameters.AddWithValue("@foo", new SqlDecimal(0.5));
var result = (decimal)cmd.ExecuteScalar();
Assert.Equal((decimal)0.5, result);
@@ -242,7 +227,7 @@ public static void Test_WithGuidValue_ShouldReturnGuid()
using var conn = new SqlConnection(s_connString);
conn.Open();
var expectedGuid = Guid.NewGuid();
- var cmd = new SqlCommand("select @input", conn);
+ using var cmd = new SqlCommand("select @input", conn);
cmd.Parameters.AddWithValue("@input", expectedGuid);
var result = cmd.ExecuteScalar();
@@ -262,67 +247,41 @@ public static void Test_WithGuidValue_ShouldReturnGuid()
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
public static void TestParametersWithDatatablesTVPInsert()
{
- SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString);
int x = 4, y = 5;
- DataTable table = new()
+ using DataTable table = new()
{
Columns = { { "x", typeof(int) }, { "y", typeof(int) } },
Rows = { { x, y } }
};
- using SqlConnection connection = new(builder.ConnectionString);
- string tableName = DataTestUtility.GetLongName("Table");
- string procName = DataTestUtility.GetLongName("Proc");
- string typeName = DataTestUtility.GetShortName("Type");
- try
- {
- connection.Open();
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandText = $"CREATE TYPE {typeName} AS TABLE (x INT, y INT)";
- cmd.ExecuteNonQuery();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- cmd.CommandText = $"CREATE TABLE {tableName} (x INT, y INT)";
- cmd.ExecuteNonQuery();
+ using UserDefinedType udtCoordPair = new(connection, "Type", "TABLE (x INT, y INT)");
+ using Table tableCoordPair = new(connection, "Table", "(x INT, y INT)");
+ using StoredProcedure spInsertCoordPair = new(connection, "Proc", $"@TVP {udtCoordPair.Name} READONLY AS " +
+ $"SET NOCOUNT ON INSERT INTO {tableCoordPair.Name}(x, y) SELECT * FROM @TVP");
- cmd.CommandText = $"CREATE PROCEDURE {procName} @TVP {typeName} READONLY AS " +
- $"SET NOCOUNT ON INSERT INTO {tableName}(x, y) SELECT * FROM @TVP";
- cmd.ExecuteNonQuery();
+ using SqlCommand cmd = connection.CreateCommand();
+ // Update Data Using TVPs
+ cmd.CommandText = spInsertCoordPair.Name;
+ cmd.CommandType = CommandType.StoredProcedure;
- }
- using (SqlCommand cmd = connection.CreateCommand())
- {
- // Update Data Using TVPs
- cmd.CommandText = procName;
- cmd.CommandType = CommandType.StoredProcedure;
-
- SqlParameter parameter = cmd.Parameters.AddWithValue("@TVP", table);
- parameter.TypeName = typeName;
+ SqlParameter parameter = cmd.Parameters.AddWithValue("@TVP", table);
+ parameter.TypeName = udtCoordPair.Name;
- cmd.ExecuteNonQuery();
+ cmd.ExecuteNonQuery();
- // Verify if the data was updated
- cmd.CommandText = "select * from " + tableName;
- cmd.CommandType = CommandType.Text;
- using SqlDataReader reader = cmd.ExecuteReader();
- DataTable dbData = new();
- dbData.Load(reader);
- Assert.Equal(1, dbData.Rows.Count);
- Assert.Equal(x, dbData.Rows[0][0]);
- Assert.Equal(y, dbData.Rows[0][1]);
- }
- }
- finally
- {
- using SqlCommand cmd = connection.CreateCommand();
- cmd.CommandText = "DROP PROCEDURE " + procName;
- cmd.ExecuteNonQuery();
- cmd.CommandText = "DROP TABLE " + tableName;
- cmd.ExecuteNonQuery();
- cmd.CommandText = "DROP TYPE " + typeName;
- cmd.ExecuteNonQuery();
- }
+ // Verify if the data was updated
+ cmd.CommandText = $"select * from {tableCoordPair.Name}";
+ cmd.CommandType = CommandType.Text;
+ using SqlDataReader reader = cmd.ExecuteReader();
+ using DataTable dbData = new();
+ dbData.Load(reader);
+ Assert.Equal(1, dbData.Rows.Count);
+ Assert.Equal(x, dbData.Rows[0][0]);
+ Assert.Equal(y, dbData.Rows[0][1]);
}
#if !NETFRAMEWORK
@@ -331,8 +290,6 @@ public static void TestParametersWithDatatablesTVPInsert()
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
public static void TestParametersWithSqlRecordsTVPInsert()
{
- SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString);
-
SqlGeography geog = SqlGeography.Point(43, -81, 4326);
SqlMetaData[] metadata = new SqlMetaData[]
@@ -353,181 +310,127 @@ public static void TestParametersWithSqlRecordsTVPInsert()
record2,
};
- using SqlConnection connection = new(builder.ConnectionString);
- string procName = DataTestUtility.GetLongName("Proc");
- string typeName = DataTestUtility.GetShortName("Type");
- try
- {
- connection.Open();
-
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandText = $"CREATE TYPE {typeName} AS TABLE([Id] [uniqueidentifier] NULL, [geom] [geography] NULL)";
- cmd.ExecuteNonQuery();
+ using SqlConnection connection = new(DataTestUtility.TCPConnectionString);
+ connection.Open();
- cmd.CommandText = @$"CREATE PROCEDURE {procName}
- @newRoads as {typeName} READONLY
- AS
- BEGIN
- SELECT* FROM @newRoads
- END";
- cmd.ExecuteNonQuery();
+ using UserDefinedType udtGeographyTable = new(connection, "Type", "TABLE ([Id] [uniqueidentifier] NULL, [geom] [geography] NULL)");
+ using StoredProcedure spSelectFromTvp = new(connection, "Proc", $"@newRoads as {udtGeographyTable.Name} READONLY AS SELECT * FROM @newRoads");
- }
- using (SqlCommand cmd = connection.CreateCommand())
- {
- // Update Data Using TVPs
- cmd.CommandText = procName;
- cmd.CommandType = CommandType.StoredProcedure;
+ using SqlCommand cmd = connection.CreateCommand();
- SqlParameter param = new SqlParameter("@newRoads", SqlDbType.Structured);
- param.Value = featureInserts;
- param.TypeName = typeName;
+ // Update Data Using TVPs
+ cmd.CommandText = spSelectFromTvp.Name;
+ cmd.CommandType = CommandType.StoredProcedure;
- cmd.Parameters.Add(param);
+ SqlParameter param = new SqlParameter("@newRoads", SqlDbType.Structured);
+ param.Value = featureInserts;
+ param.TypeName = udtGeographyTable.Name;
- using var reader = cmd.ExecuteReader();
+ cmd.Parameters.Add(param);
- Assert.True(reader.HasRows);
+ using var reader = cmd.ExecuteReader();
- int count = 0;
- while (reader.Read())
- {
- Assert.NotNull(reader[0]);
- Assert.NotNull(reader[1]);
- count++;
- }
+ Assert.True(reader.HasRows);
- Assert.Equal(2, count);
- }
- }
- finally
+ int count = 0;
+ while (reader.Read())
{
- using SqlCommand cmd = connection.CreateCommand();
- cmd.CommandText = "DROP PROCEDURE " + procName;
- cmd.ExecuteNonQuery();
- cmd.CommandText = "DROP TYPE " + typeName;
- cmd.ExecuteNonQuery();
+ Assert.NotNull(reader[0]);
+ Assert.NotNull(reader[1]);
+ count++;
}
+
+ Assert.Equal(2, count);
}
[Trait("Category", "flaky")]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
public static void TestDateOnlyTVPDataTable_CommandSP()
{
- string tableTypeName = "[dbo]." + DataTestUtility.GetLongName("UDTTTestDateOnlyTVP");
- string spName = DataTestUtility.GetLongName("spTestDateOnlyTVP");
- SqlConnection connection = new(s_connString);
- try
- {
- connection.Open();
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)";
- cmd.ExecuteNonQuery();
- cmd.CommandText = $"CREATE PROCEDURE {spName} (@dates {tableTypeName} READONLY) AS SELECT COUNT(*) FROM @dates";
- cmd.ExecuteNonQuery();
- }
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandText = spName;
- cmd.CommandType = CommandType.StoredProcedure;
-
- DataTable dtTest = new();
- dtTest.Columns.Add(new DataColumn("DateColumn", typeof(DateOnly)));
- dtTest.Columns.Add(new DataColumn("TimeColumn", typeof(TimeOnly)));
- var dataRow = dtTest.NewRow();
- dataRow["DateColumn"] = new DateOnly(2023, 11, 15);
- dataRow["TimeColumn"] = new TimeOnly(12, 30, 45);
- dtTest.Rows.Add(dataRow);
-
- cmd.Parameters.Add(new SqlParameter
- {
- ParameterName = "@dates",
- SqlDbType = SqlDbType.Structured,
- TypeName = tableTypeName,
- Value = dtTest,
- });
+ using SqlConnection connection = new(s_connString);
- cmd.ExecuteNonQuery();
- }
- }
- finally
+ connection.Open();
+
+ using UserDefinedType udtTableType = new(connection, "UDTTTestDateOnlyTVP", "TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)");
+ using StoredProcedure storedProcedure = new(connection, "spTestDateOnlyTVP", $"(@dates {udtTableType.Name} READONLY) AS SELECT COUNT(*) FROM @dates");
+ using SqlCommand cmd = connection.CreateCommand();
+
+ cmd.CommandText = storedProcedure.Name;
+ cmd.CommandType = CommandType.StoredProcedure;
+
+ DataTable dtTest = new();
+ dtTest.Columns.Add(new DataColumn("DateColumn", typeof(DateOnly)));
+ dtTest.Columns.Add(new DataColumn("TimeColumn", typeof(TimeOnly)));
+
+ DataRow dataRow = dtTest.NewRow();
+ dataRow["DateColumn"] = new DateOnly(2023, 11, 15);
+ dataRow["TimeColumn"] = new TimeOnly(12, 30, 45);
+ dtTest.Rows.Add(dataRow);
+
+ cmd.Parameters.Add(new SqlParameter
{
- DataTestUtility.DropStoredProcedure(connection, spName);
- DataTestUtility.DropUserDefinedType(connection, tableTypeName);
- }
+ ParameterName = "@dates",
+ SqlDbType = SqlDbType.Structured,
+ TypeName = udtTableType.Name,
+ Value = dtTest,
+ });
+
+ cmd.ExecuteNonQuery();
}
[Trait("Category", "flaky")]
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
public static void TestDateOnlyTVPSqlDataRecord_CommandSP()
{
- string tableTypeName = "[dbo]." + DataTestUtility.GetLongName("UDTTTestDateOnlySqlDataRecordTVP");
- string spName = DataTestUtility.GetLongName("spTestDateOnlySqlDataRecordTVP");
- SqlConnection connection = new(s_connString);
- try
- {
- connection.Open();
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)";
- cmd.ExecuteNonQuery();
- cmd.CommandText = $"CREATE PROCEDURE {spName} (@dates {tableTypeName} READONLY) AS SELECT COUNT(*) FROM @dates";
- cmd.ExecuteNonQuery();
- }
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandText = spName;
- cmd.CommandType = CommandType.StoredProcedure;
+ using SqlConnection connection = new(s_connString);
- SqlMetaData[] metadata = new SqlMetaData[]
- {
- new SqlMetaData("DateColumn", SqlDbType.Date),
- new SqlMetaData("TimeColumn", SqlDbType.Time)
- };
+ connection.Open();
- SqlDataRecord record1 = new SqlDataRecord(metadata);
- record1.SetValues(new DateOnly(2023, 11, 15), new TimeOnly(12, 30, 45));
+ using UserDefinedType udtTableType = new(connection, "UDTTTestDateOnlySqlDataRecordTVP", "TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)");
+ using StoredProcedure storedProcedure = new(connection, "spTestDateOnlySqlDataRecordTVP", $"(@dates {udtTableType.Name} READONLY) AS SELECT COUNT(*) FROM @dates");
+ using SqlCommand cmd = connection.CreateCommand();
- SqlDataRecord record2 = new SqlDataRecord(metadata);
- record2.SetValues(new DateOnly(2025, 11, 15), new TimeOnly(13, 31, 46));
+ cmd.CommandText = storedProcedure.Name;
+ cmd.CommandType = CommandType.StoredProcedure;
- IList featureInserts = new List
+ SqlMetaData[] metadata = new SqlMetaData[]
+ {
+ new SqlMetaData("DateColumn", SqlDbType.Date),
+ new SqlMetaData("TimeColumn", SqlDbType.Time)
+ };
+
+ SqlDataRecord record1 = new SqlDataRecord(metadata);
+ record1.SetValues(new DateOnly(2023, 11, 15), new TimeOnly(12, 30, 45));
+
+ SqlDataRecord record2 = new SqlDataRecord(metadata);
+ record2.SetValues(new DateOnly(2025, 11, 15), new TimeOnly(13, 31, 46));
+
+ IList featureInserts = new List
{
record1,
record2,
};
- cmd.Parameters.Add(new SqlParameter
- {
- ParameterName = "@dates",
- SqlDbType = SqlDbType.Structured,
- TypeName = tableTypeName,
- Value = featureInserts,
- });
+ cmd.Parameters.Add(new SqlParameter
+ {
+ ParameterName = "@dates",
+ SqlDbType = SqlDbType.Structured,
+ TypeName = udtTableType.Name,
+ Value = featureInserts,
+ });
- using var reader = cmd.ExecuteReader();
+ using var reader = cmd.ExecuteReader();
- Assert.True(reader.HasRows);
+ Assert.True(reader.HasRows);
- int count = 0;
- while (reader.Read())
- {
- Assert.NotNull(reader[0]);
- count++;
- }
-
- Assert.Equal(1, count);
- }
- }
- finally
+ int count = 0;
+ while (reader.Read())
{
- DataTestUtility.DropStoredProcedure(connection, spName);
- DataTestUtility.DropUserDefinedType(connection, tableTypeName);
+ Assert.NotNull(reader[0]);
+ count++;
}
+
+ Assert.Equal(1, count);
}
#endif
@@ -587,33 +490,29 @@ public static void TestScaledDecimalParameter_CommandInsert(string connectionStr
{
using LocalAppContextSwitchesHelper appContextSwitchesHelper = new();
- string tableName = DataTestUtility.GetLongName("TestDecimalParameterCMD");
- using SqlConnection connection = InitialDatabaseTable(connectionString, tableName);
- try
+ using SqlConnection connection = new(connectionString);
+ connection.Open();
+
+ using Table decimalTable = new(connection, "TestDecimalParameterCMD", "(Id INT, Value Decimal(38, 2))");
+
+ using (SqlCommand cmd = connection.CreateCommand())
{
- using (SqlCommand cmd = connection.CreateCommand())
- {
- appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
+ appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
- var p = new SqlParameter("@Value", null)
- {
- Precision = 18,
- Scale = 2
- };
- cmd.Parameters.Add(p);
- for (int i = 0; i < s_testValues.Length; i++)
- {
- p.Value = s_testValues[i];
- cmd.CommandText = $"INSERT INTO {tableName} (Id, [Value]) VALUES({i}, @Value)";
- cmd.ExecuteNonQuery();
- }
+ var p = new SqlParameter("@Value", null)
+ {
+ Precision = 18,
+ Scale = 2
+ };
+ cmd.Parameters.Add(p);
+ for (int i = 0; i < s_testValues.Length; i++)
+ {
+ p.Value = s_testValues[i];
+ cmd.CommandText = $"INSERT INTO {decimalTable.Name} (Id, [Value]) VALUES({i}, @Value)";
+ cmd.ExecuteNonQuery();
}
- Assert.True(ValidateInsertedValues(connection, tableName, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
- }
- finally
- {
- DataTestUtility.DropTable(connection, tableName);
}
+ Assert.True(ValidateInsertedValues(connection, decimalTable.Name, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
}
[Theory]
@@ -622,33 +521,29 @@ public static void TestScaledDecimalParameter_BulkCopy(string connectionString,
{
using LocalAppContextSwitchesHelper appContextSwitchesHelper = new();
- string tableName = DataTestUtility.GetLongName("TestDecimalParameterBC");
- using SqlConnection connection = InitialDatabaseTable(connectionString, tableName);
- try
+ using SqlConnection connection = new(connectionString);
+ connection.Open();
+
+ using Table decimalTable = new(connection, "TestDecimalParameterCMD", "(Id INT, Value Decimal(38, 2))");
+
+ using (SqlBulkCopy bulkCopy = new(connection))
{
- using (SqlBulkCopy bulkCopy = new(connection))
+ using DataTable table = new(decimalTable.Name);
+ table.Columns.Add("Id", typeof(int));
+ table.Columns.Add("Value", typeof(decimal));
+ for (int i = 0; i < s_testValues.Length; i++)
{
- DataTable table = new(tableName);
- table.Columns.Add("Id", typeof(int));
- table.Columns.Add("Value", typeof(decimal));
- for (int i = 0; i < s_testValues.Length; i++)
- {
- DataRow newRow = table.NewRow();
- newRow["Id"] = i;
- newRow["Value"] = s_testValues[i];
- table.Rows.Add(newRow);
- }
-
- bulkCopy.DestinationTableName = tableName;
- appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
- bulkCopy.WriteToServer(table);
+ DataRow newRow = table.NewRow();
+ newRow["Id"] = i;
+ newRow["Value"] = s_testValues[i];
+ table.Rows.Add(newRow);
}
- Assert.True(ValidateInsertedValues(connection, tableName, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
- }
- finally
- {
- DataTestUtility.DropTable(connection, tableName);
+
+ bulkCopy.DestinationTableName = decimalTable.Name;
+ appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
+ bulkCopy.WriteToServer(table);
}
+ Assert.True(ValidateInsertedValues(connection, decimalTable.Name, truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
}
// Synapse: Parse error at line: 2, column: 8: Incorrect syntax near 'TYPE'.
@@ -659,45 +554,40 @@ public static void TestScaledDecimalTVP_CommandSP(string connectionString, bool
{
using LocalAppContextSwitchesHelper appContextSwitchesHelper = new();
- string tableName = DataTestUtility.GetLongName("TestDecimalParameterBC");
- string tableTypeName = DataTestUtility.GetLongName("UDTTTestDecimalParameterBC");
- string spName = DataTestUtility.GetLongName("spTestDecimalParameterBC");
- using SqlConnection connection = InitialDatabaseUDTT(connectionString, tableName, tableTypeName, spName);
- try
+ using SqlConnection connection = new(connectionString);
+ connection.Open();
+
+ using Table decimalTable = new(connection, "TestDecimalParameterBC", "(Id INT, Value Decimal(38, 2))");
+ using UserDefinedType udtDecimal = new(connection, "UDTTTestDecimalParameterBC", "TABLE (Id INT, Value Decimal(38, 2))");
+ using StoredProcedure insertDecimalSp = new(connection, "spTestDecimalParameterBC",
+ $"(@tvp {udtDecimal.Name} READONLY) AS \n INSERT INTO {decimalTable.Name} (Id, Value) SELECT * FROM @tvp ORDER BY Id");
+
+ using (SqlCommand cmd = connection.CreateCommand())
{
- using (SqlCommand cmd = connection.CreateCommand())
+ var p = new SqlParameter("@tvp", SqlDbType.Structured)
{
- var p = new SqlParameter("@tvp", SqlDbType.Structured)
- {
- TypeName = $"dbo.{tableTypeName}"
- };
- cmd.CommandText = spName;
- cmd.CommandType = CommandType.StoredProcedure;
- cmd.Parameters.Add(p);
-
- DataTable table = new(tableName);
- table.Columns.Add("Id", typeof(int));
- table.Columns.Add("Value", typeof(decimal));
- for (int i = 0; i < s_testValues.Length; i++)
- {
- DataRow newRow = table.NewRow();
- newRow["Id"] = i;
- newRow["Value"] = s_testValues[i];
- table.Rows.Add(newRow);
- }
- p.Value = table;
- appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
- cmd.ExecuteNonQuery();
+ TypeName = udtDecimal.Name
+ };
+ cmd.CommandText = insertDecimalSp.Name;
+ cmd.CommandType = CommandType.StoredProcedure;
+ cmd.Parameters.Add(p);
+
+ DataTable table = new(decimalTable.Name);
+ table.Columns.Add("Id", typeof(int));
+ table.Columns.Add("Value", typeof(decimal));
+ for (int i = 0; i < s_testValues.Length; i++)
+ {
+ DataRow newRow = table.NewRow();
+ newRow["Id"] = i;
+ newRow["Value"] = s_testValues[i];
+ table.Rows.Add(newRow);
}
- // TVP always rounds data without attention to the configuration.
- Assert.True(ValidateInsertedValues(connection, tableName, false && truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
- }
- finally
- {
- DataTestUtility.DropTable(connection, tableName);
- DataTestUtility.DropStoredProcedure(connection, spName);
- DataTestUtility.DropUserDefinedType(connection, tableTypeName);
+ p.Value = table;
+ appContextSwitchesHelper.TruncateScaledDecimal = truncateScaledDecimal;
+ cmd.ExecuteNonQuery();
}
+ // TVP always rounds data without attention to the configuration.
+ Assert.True(ValidateInsertedValues(connection, decimalTable.Name, false && truncateScaledDecimal), $"Invalid test happened with connection string [{connection.ConnectionString}]");
}
#region Decimal parameter test setup
@@ -706,35 +596,6 @@ public static void TestScaledDecimalTVP_CommandSP(string connectionString, bool
private static readonly decimal[] s_expectedTruncatedValues = new[] { 4210862852.86m, 19.15m, 19.15m, 19.15m };
private const string TruncateDecimalSwitch = "Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal";
- private static SqlConnection InitialDatabaseUDTT(string cnnString, string tableName, string tableTypeName, string spName)
- {
- SqlConnection connection = new(cnnString);
- connection.Open();
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TABLE {tableName} (Id INT, Value Decimal(38, 2)) \n";
- cmd.CommandText += $"CREATE TYPE {tableTypeName} AS TABLE (Id INT, Value Decimal(38, 2)) ";
- cmd.ExecuteNonQuery();
- cmd.CommandText = $"CREATE PROCEDURE {spName} (@tvp {tableTypeName} READONLY) AS \n INSERT INTO {tableName} (Id, Value) SELECT * FROM @tvp ORDER BY Id";
- cmd.ExecuteNonQuery();
- }
- return connection;
- }
-
- private static SqlConnection InitialDatabaseTable(string cnnString, string tableName)
- {
- SqlConnection connection = new(cnnString);
- connection.Open();
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TABLE {tableName} (Id INT, Value Decimal(38, 2))";
- cmd.ExecuteNonQuery();
- }
- return connection;
- }
-
private static bool ValidateInsertedValues(SqlConnection connection, string tableName, bool truncateScaledDecimal)
{
bool exceptionHit;
@@ -748,7 +609,7 @@ private static bool ValidateInsertedValues(SqlConnection connection, string tabl
cmd.CommandText = $"SELECT [Value] FROM {tableName} ORDER BY Id ASC";
cmd.CommandType = CommandType.Text;
using SqlDataReader reader = cmd.ExecuteReader();
- DataTable dbData = new();
+ using DataTable dbData = new();
dbData.Load(reader);
Assert.Equal(expectedValues.Length, dbData.Rows.Count);
for (int i = 0; i < expectedValues.Length; i++)
@@ -787,15 +648,6 @@ private enum MyEnum
B = 2
}
- private static void ExecuteNonQueryCommand(string connectionString, string cmdText)
- {
- using SqlConnection conn = new(connectionString);
- using SqlCommand cmd = conn.CreateCommand();
- conn.Open();
- cmd.CommandText = cmdText;
- cmd.ExecuteNonQuery();
- }
-
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))]
private static void EnableOptimizedParameterBinding_ParametersAreUsedByName()
{
@@ -946,36 +798,20 @@ private static void EnableOptimizedParameterBinding_ReturnSucceeds()
{
int firstInput = 12;
- string sprocName = DataTestUtility.GetShortName("P");
- // input, output
- string createSprocQuery =
- "CREATE PROCEDURE " + sprocName + " @in int " +
- "AS " +
- "RETURN(@in)";
-
- string dropSprocQuery = "DROP PROCEDURE " + sprocName;
-
- try
- {
- ExecuteNonQueryCommand(DataTestUtility.TCPConnectionString, createSprocQuery);
+ using var connection = new SqlConnection(DataTestUtility.TCPConnectionString);
+ connection.Open();
- using var connection = new SqlConnection(DataTestUtility.TCPConnectionString);
- connection.Open();
+ using StoredProcedure sproc = new(connection, "P", "@in int AS RETURN(@in)");
- using var command = new SqlCommand(sprocName, connection) { CommandType = CommandType.StoredProcedure };
- command.EnableOptimizedParameterBinding = true;
- command.Parameters.AddWithValue("@in", firstInput);
- SqlParameter returnParameter = command.Parameters.AddWithValue("@retval", 0);
- returnParameter.Direction = ParameterDirection.ReturnValue;
+ using var command = new SqlCommand(sproc.Name, connection) { CommandType = CommandType.StoredProcedure };
+ command.EnableOptimizedParameterBinding = true;
+ command.Parameters.AddWithValue("@in", firstInput);
+ SqlParameter returnParameter = command.Parameters.AddWithValue("@retval", 0);
+ returnParameter.Direction = ParameterDirection.ReturnValue;
- command.ExecuteNonQuery();
+ command.ExecuteNonQuery();
- Assert.Equal(firstInput, Convert.ToInt32(returnParameter.Value));
- }
- finally
- {
- ExecuteNonQueryCommand(DataTestUtility.TCPConnectionString, dropSprocQuery);
- }
+ Assert.Equal(firstInput, Convert.ToInt32(returnParameter.Value));
}
[SkipOnPlatform(TestPlatforms.OSX, "Flaky on macOS: https://sqlclientdrivers.visualstudio.com/ADO.Net/_workitems/edit/42351")]
@@ -999,7 +835,7 @@ public static void ClosedConnection_SqlParameterValueTest()
private static void RunParameterTest()
{
- var cancellationToken = new CancellationTokenSource(50);
+ using var cancellationToken = new CancellationTokenSource(50);
var expectedGuid = Guid.NewGuid();
using var connection = new SqlConnection(DataTestUtility.TCPConnectionString);
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlGraphTables.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlGraphTables.cs
index d83693080f..e78c3f680d 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlGraphTables.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlGraphTables.cs
@@ -2,9 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System;
using System.Data;
-using System.Data.Common;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
using Xunit;
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.SqlBulkCopyTests
@@ -15,7 +14,6 @@ public class SqlGraphTables
public void WriteToServer_CopyToSqlGraphNodeTable_Succeeds()
{
string connectionString = DataTestUtility.TCPConnectionString;
- string destinationTable = DataTestUtility.GetShortName("SqlGraphNodeTable");
using SqlConnection dstConn = new SqlConnection(connectionString);
using DataTable nodes = new DataTable()
@@ -30,20 +28,12 @@ public void WriteToServer_CopyToSqlGraphNodeTable_Succeeds()
nodes.Rows.Add($"Name {i}");
}
- try
- {
- DataTestUtility.CreateTable(dstConn, destinationTable, "(Id INT PRIMARY KEY IDENTITY(1,1), [Name] VARCHAR(100)) AS NODE");
-
- using SqlBulkCopy nodeCopy = new SqlBulkCopy(dstConn);
+ using Table dstNodeTable = new(dstConn, "SqlGraphNodeTable", "(Id INT PRIMARY KEY IDENTITY(1,1), [Name] VARCHAR(100)) AS NODE");
+ using SqlBulkCopy nodeCopy = new SqlBulkCopy(dstConn);
- nodeCopy.DestinationTableName = destinationTable;
- nodeCopy.ColumnMappings.Add("Name", "Name");
- nodeCopy.WriteToServer(nodes);
- }
- finally
- {
- DataTestUtility.DropTable(dstConn, destinationTable);
- }
+ nodeCopy.DestinationTableName = dstNodeTable.Name;
+ nodeCopy.ColumnMappings.Add("Name", "Name");
+ nodeCopy.WriteToServer(nodes);
}
}
}
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs
index 74e6aaa277..490bfe74b4 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs
@@ -1,10 +1,11 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Data;
using Microsoft.Data.SqlClient.Server;
+using Microsoft.Data.SqlClient.Tests.Common.Fixtures.DatabaseObjects;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
@@ -32,7 +33,6 @@ public DateTimeOffsetVariableScale(DateTimeOffset dateTimeOffset, int scale)
public class UdtDateTimeOffsetTest
{
private readonly string _connectionString = null;
- private readonly string _udtTableType = DataTestUtility.GetLongName("DataTimeOffsetTableType");
private readonly ITestOutputHelper _testOutputHelper;
public UdtDateTimeOffsetTest(ITestOutputHelper testOutputHelper)
@@ -47,30 +47,24 @@ public void SelectFromSqlParameterShouldSucceed()
{
using SqlConnection connection = new(_connectionString);
connection.Open();
- SetupUserDefinedTableType(connection, _udtTableType);
- try
+ using UserDefinedType udtTableType = new(connection, nameof(SelectFromSqlParameterShouldSucceed), "TABLE ([Value] DATETIMEOFFSET(1) NOT NULL)");
+
+ DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, 500, TimeSpan.Zero);
+ var param = new SqlParameter
{
- DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, 500, TimeSpan.Zero);
- var param = new SqlParameter
- {
- ParameterName = "@params",
- SqlDbType = SqlDbType.Structured,
- TypeName = $"dbo.{_udtTableType}",
- Value = new DateTimeOffsetList[] { new DateTimeOffsetList(dateTimeOffset) }
- };
+ ParameterName = "@params",
+ SqlDbType = SqlDbType.Structured,
+ TypeName = udtTableType.Name,
+ Value = new DateTimeOffsetList[] { new DateTimeOffsetList(dateTimeOffset) }
+ };
- using (var cmd = connection.CreateCommand())
- {
- cmd.CommandText = "SELECT * FROM @params";
- cmd.Parameters.Add(param);
- var result = cmd.ExecuteScalar();
- Assert.Equal(dateTimeOffset, result);
- }
- }
- finally
+ using (var cmd = connection.CreateCommand())
{
- DataTestUtility.DropUserDefinedType(connection, _udtTableType);
+ cmd.CommandText = "SELECT * FROM @params";
+ cmd.Parameters.Add(param);
+ var result = cmd.ExecuteScalar();
+ Assert.Equal(dateTimeOffset, result);
}
}
@@ -87,7 +81,8 @@ public void DateTimeOffsetAllScalesTestShouldSucceed()
for (int scale = fromScale; scale <= toScale; scale++)
{
- string tvpTypeName = DataTestUtility.GetLongName("tvpType"); // Need a unique name per scale, else we get errors. See https://github.com/dotnet/SqlClient/issues/3011
+ // Need a unique name per scale, else we get errors. See https://github.com/dotnet/SqlClient/issues/3011
+ using UserDefinedType udtTableType = new(connection, "tvpType", $"TABLE ([Value] DATETIMEOFFSET({scale}) NOT NULL)");
DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, TimeSpan.Zero);
@@ -95,63 +90,32 @@ public void DateTimeOffsetAllScalesTestShouldSucceed()
TimeSpan subSeconds = TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond / Math.Pow(10, scale)));
dateTimeOffset = dateTimeOffset.Add(subSeconds);
- DataTestUtility.DropUserDefinedType(connection, tvpTypeName);
+ var param = new SqlParameter
+ {
+ ParameterName = "@params",
+ SqlDbType = SqlDbType.Structured,
+ Scale = (byte)scale,
+ TypeName = udtTableType.Name,
+ Value = new DateTimeOffsetVariableScale[] { new DateTimeOffsetVariableScale(dateTimeOffset, scale) }
+ };
- try
+ using (var cmd = connection.CreateCommand())
{
- SetupDateTimeOffsetTableType(connection, tvpTypeName, scale);
+ cmd.CommandText = "SELECT * FROM @params";
+ cmd.Parameters.Add(param);
- var param = new SqlParameter
+ object result = null;
+ try
{
- ParameterName = "@params",
- SqlDbType = SqlDbType.Structured,
- Scale = (byte)scale,
- TypeName = $"dbo.{tvpTypeName}",
- Value = new DateTimeOffsetVariableScale[] { new DateTimeOffsetVariableScale(dateTimeOffset, scale) }
- };
-
- using (var cmd = connection.CreateCommand())
+ result = cmd.ExecuteScalar();
+ Assert.Equal(dateTimeOffset, result);
+ }
+ catch (Exception)
{
- cmd.CommandText = "SELECT * FROM @params";
- cmd.Parameters.Add(param);
-
- object result = null;
- try
- {
- result = cmd.ExecuteScalar();
- Assert.Equal(dateTimeOffset, result);
- }
- catch (Exception)
- {
- _testOutputHelper.WriteLine($"{DateTime.UtcNow:O}: Failed for scale {scale} DateTimeOffset: {dateTimeOffset} Result: {result ?? "No result"}");
- throw;
- }
+ _testOutputHelper.WriteLine($"{DateTime.UtcNow:O}: Failed for scale {scale} DateTimeOffset: {dateTimeOffset} Result: {result ?? "No result"}");
+ throw;
}
}
- finally
- {
- DataTestUtility.DropUserDefinedType(connection, tvpTypeName);
- }
- }
- }
-
- private static void SetupUserDefinedTableType(SqlConnection connection, string tableTypeName)
- {
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([Value] DATETIMEOFFSET(1) NOT NULL) ";
- cmd.ExecuteNonQuery();
- }
- }
-
- private static void SetupDateTimeOffsetTableType(SqlConnection connection, string tableTypeName, int scale)
- {
- using (SqlCommand cmd = connection.CreateCommand())
- {
- cmd.CommandType = CommandType.Text;
- cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([Value] DATETIMEOFFSET({scale}) NOT NULL) ";
- cmd.ExecuteNonQuery();
}
}
}