Imported Upstream version 5.10.0.47

Former-commit-id: d0813289fa2d35e1f8ed77530acb4fb1df441bc0
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-01-24 17:04:36 +00:00
parent 88ff76fe28
commit e46a49ecf1
5927 changed files with 226314 additions and 129848 deletions

View File

@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\dir.props" />
<PropertyGroup>
<AssemblyVersion>4.0.1.0</AssemblyVersion>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
<AssemblyKey>Open</AssemblyKey>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<ItemGroup>
<ProjectReference Include="..\ref\System.Data.Odbc.csproj">
<SupportedFramework>net461;netcoreapp2.0;$(AllXamarinFrameworks)</SupportedFramework>
</ProjectReference>
<ProjectReference Include="..\src\System.Data.Odbc.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -306,6 +306,10 @@ namespace System.Data.Common
{
return InvalidOperation(SR.GetString(SR.ADP_UninitializedParameterSize, index.ToString(CultureInfo.InvariantCulture), dataType.Name));
}
internal static InvalidOperationException QuotePrefixNotSet(string method)
{
return InvalidOperation(SR.GetString(SR.ADP_QuotePrefixNotSet, method));
}
//
// : ConnectionUtil
@@ -544,7 +548,6 @@ namespace System.Data.Common
return Argument(SR.GetString(SR.MDF_UnsupportedVersion, collectionName));
}
// global constant strings
internal const string BeginTransaction = "BeginTransaction";
internal const string ChangeDatabase = "ChangeDatabase";
@@ -560,6 +563,8 @@ namespace System.Data.Common
internal const string ParameterName = "ParameterName";
internal const string Prepare = "Prepare";
internal const string RollbackTransaction = "RollbackTransaction";
internal const string QuoteIdentifier = "QuoteIdentifier";
internal const string UnquoteIdentifier = "UnquoteIdentifier";
internal const int DecimalMaxPrecision = 29;
internal const int DecimalMaxPrecision28 = 28; // there are some cases in Odbc where we need that ...

View File

@@ -6,7 +6,7 @@ namespace System.Data.Common
{
internal static class ExternDll
{
public const string Odbc32 = "odbc.so.2";
public const string Odbc32 = "libodbc.so.2";
}
}

View File

@@ -6,7 +6,7 @@ namespace System.Data.Common
{
internal static class ExternDll
{
public const string Odbc32 = "odbc.2";
public const string Odbc32 = "libodbc.2.dylib";
}
}

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<BuildConfigurations>
netfx-Windows_NT;
netstandard;
netstandard-Linux;
netstandard-OSX;
netstandard-Windows_NT;

View File

@@ -201,6 +201,9 @@
<data name="ADP_NonPooledOpenTimeout" xml:space="preserve">
<value>Timeout attempting to open the connection. The time period elapsed prior to attempting to open the connection has been exceeded. This may have occurred because of too many simultaneous non-pooled connection attempts.</value>
</data>
<data name="ADP_QuotePrefixNotSet" xml:space="preserve">
<value>{0} requires an open connection when the quote prefix has not been set.</value>
</data>
<data name="MDF_QueryFailed" xml:space="preserve">
<value>Unable to build the '{0}' collection because execution of the SQL query failed. See the inner exception for details.</value>
</data>
@@ -328,7 +331,7 @@
<value>{0} DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{1}.</value>
</data>
<data name="ADP_InvalidCommandTimeout" xml:space="preserve">
<value>Invalid CommandTimeout value {0}; the value must be >= 0.</value>
<value>Invalid CommandTimeout value {0}; the value must be &gt;= 0.</value>
</data>
<data name="ADP_UninitializedParameterSize" xml:space="preserve">
<value>{1}[{0}]: the Size property has an invalid size of 0.</value>
@@ -426,4 +429,10 @@
<data name="Odbc_OpenConnectionNoOwner" xml:space="preserve">
<value>An internal connection does not have an owner.</value>
</data>
</root>
<data name="Odbc_PlatformNotSupported" xml:space="preserve">
<value>System.Data.ODBC is not supported on this platform.</value>
</data>
<data name="Odbc_UnixOdbcNotFound" xml:space="preserve">
<value>Dependency unixODBC with minimum version 2.3.1 is required.</value>
</data>
</root>

View File

@@ -6,6 +6,7 @@
<AssemblyName>System.Data.Odbc</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPartialFacadeAssembly Condition="'$(TargetGroup)' == 'netfx'">true</IsPartialFacadeAssembly>
<GeneratePlatformNotSupportedAssemblyMessage Condition="'$(TargetGroup)' == 'netstandard' AND '$(OSGroup)' == 'AnyOS'">SR.Odbc_PlatformNotSupported</GeneratePlatformNotSupportedAssemblyMessage>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netfx-Windows_NT-Release|AnyCPU'" />
@@ -15,7 +16,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-OSX-Release|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true'">
<ItemGroup Condition="'$(IsPartialFacadeAssembly)' != 'true' AND '$(OSGroup)' != 'AnyOS'">
<Compile Include="$(CommonPath)\System\Data\Common\AdapterUtil.cs">
<Link>Common\System\Data\Common\AdapterUtil.cs</Link>
</Compile>

View File

@@ -112,7 +112,7 @@ namespace System.Data.Odbc
{
//Random
//Means that the user can ask for the values int any order (ie: out of order).
// In order to acheive this on a forward only stream, we need to actually
// In order to achieve this on a forward only stream, we need to actually
// retreive all the value in between so they can go back to values they've skipped
for (int c = 0; c < i; c++)
{

View File

@@ -244,16 +244,49 @@ namespace System.Data.Odbc
}
}
retcode = hstmt.CloseCursor();
return rParams.ToArray(); ;
return rParams.ToArray();
}
public override string QuoteIdentifier(string unquotedIdentifier)
{
return QuoteIdentifier(unquotedIdentifier, null /* use DataAdapter.SelectCommand.Connection if available */);
}
public string QuoteIdentifier(string unquotedIdentifier, OdbcConnection connection)
{
throw ADP.NotSupported();
ADP.CheckArgumentNull(unquotedIdentifier, nameof(unquotedIdentifier));
// if the user has specificed a prefix use the user specified prefix and suffix
// otherwise get them from the provider
string quotePrefix = QuotePrefix;
string quoteSuffix = QuoteSuffix;
if (string.IsNullOrEmpty(quotePrefix))
{
if (connection == null)
{
// Use the adapter's connection if QuoteIdentifier was called from
// DbCommandBuilder instance (which does not have an overload that gets connection object)
connection = DataAdapter?.SelectCommand?.Connection;
if (connection == null)
{
throw ADP.QuotePrefixNotSet(ADP.QuoteIdentifier);
}
}
quotePrefix = connection.QuoteChar(ADP.QuoteIdentifier);
quoteSuffix = quotePrefix;
}
// by the ODBC spec "If the data source does not support quoted identifiers, a blank is returned."
// So if a blank is returned the string is returned unchanged. Otherwise the returned string is used
// to quote the string
if (!string.IsNullOrEmpty(quotePrefix) && quotePrefix != " ")
{
return ADP.BuildQuotedString(quotePrefix, quoteSuffix, unquotedIdentifier);
}
else
{
return unquotedIdentifier;
}
}
protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
@@ -273,9 +306,46 @@ namespace System.Data.Odbc
{
return UnquoteIdentifier(quotedIdentifier, null /* use DataAdapter.SelectCommand.Connection if available */);
}
public string UnquoteIdentifier(string quotedIdentifier, OdbcConnection connection)
{
throw ADP.NotSupported();
ADP.CheckArgumentNull(quotedIdentifier, nameof(quotedIdentifier));
// if the user has specificed a prefix use the user specified prefix and suffix
// otherwise get them from the provider
string quotePrefix = QuotePrefix;
string quoteSuffix = QuoteSuffix;
if (string.IsNullOrEmpty(quotePrefix))
{
if (connection == null)
{
// Use the adapter's connection if UnquoteIdentifier was called from
// DbCommandBuilder instance (which does not have an overload that gets connection object)
connection = DataAdapter?.SelectCommand?.Connection;
if (connection == null)
{
throw ADP.QuotePrefixNotSet(ADP.UnquoteIdentifier);
}
}
quotePrefix = connection.QuoteChar(ADP.UnquoteIdentifier);
quoteSuffix = quotePrefix;
}
String unquotedIdentifier;
// by the ODBC spec "If the data source does not support quoted identifiers, a blank is returned."
// So if a blank is returned the string is returned unchanged. Otherwise the returned string is used
// to unquote the string
if (!string.IsNullOrEmpty(quotePrefix) || quotePrefix != " ")
{
// ignoring the return value because it is acceptable for the quotedString to not be quoted in this
// context.
ADP.RemoveStringQuotes(quotePrefix, quoteSuffix, quotedIdentifier, out unquotedIdentifier);
}
else
{
unquotedIdentifier = quotedIdentifier;
}
return unquotedIdentifier;
}
}
}

View File

@@ -7,6 +7,7 @@ using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using SysTx = System.Transactions;
@@ -561,7 +562,14 @@ namespace System.Data.Odbc
public override void Open()
{
InnerConnection.OpenConnection(this, ConnectionFactory);
try
{
InnerConnection.OpenConnection(this, ConnectionFactory);
}
catch (DllNotFoundException e) when (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
throw new DllNotFoundException(SR.Odbc_UnixOdbcNotFound + Environment.NewLine + e.Message);
}
// SQLBUDT #276132 - need to manually enlist in some cases, because
// native ODBC doesn't know about SysTx transactions.

View File

@@ -1 +1 @@
ad1582cfe8c3a8b0f98826c045d56ff42a47603a
39db136a568642f63975380e1fdaccdb7aed06de

View File

@@ -747,26 +747,31 @@ namespace System.Data.Odbc
}
};
int cbParameterSize = GetParameterSize(value, offset, ordinal); // count of bytes for the data, for SQLBindParameter
int cbParameterSize = GetParameterSize(value, offset, ordinal); // count of bytes for the data, for SQLBindParameter
// here we upgrade the datatypes if the given values size is bigger than the types columnsize
//
// Upgrade input value type if the size of input value is bigger than the max size of the input value type.
switch (_bindtype._sql_type)
{
case ODBC32.SQL_TYPE.VARBINARY: // MDAC 74372
// Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
if ((cbParameterSize > 8000))
{ _bindtype = TypeMap._Image; } // will change to LONGVARBINARY
case ODBC32.SQL_TYPE.VARBINARY:
// Max length of VARBINARY is 8,000 of byte array.
if (size > 8000)
{
_bindtype = TypeMap._Image; // will change to LONGVARBINARY
}
break;
case ODBC32.SQL_TYPE.VARCHAR: // MDAC 74372
// Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
if ((cbParameterSize > 8000))
{ _bindtype = TypeMap._Text; } // will change to LONGVARCHAR
case ODBC32.SQL_TYPE.VARCHAR:
// Max length of VARCHAR is 8,000 of non-unicode characters.
if (size > 8000)
{
_bindtype = TypeMap._Text; // will change to LONGVARCHAR
}
break;
case ODBC32.SQL_TYPE.WVARCHAR: // MDAC 75099
// Note: per definition DbType.Binary does not support more than 8000 bytes so we change the type for binding
if ((cbParameterSize > 4000))
{ _bindtype = TypeMap._NText; } // will change to WLONGVARCHAR
case ODBC32.SQL_TYPE.WVARCHAR:
// Max length of WVARCHAR (NVARCHAR) is 4,000 of unicode characters.
if (size > 4000)
{
_bindtype = TypeMap._NText; // will change to WLONGVARCHAR
}
break;
}

View File

@@ -0,0 +1,59 @@
// 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 Xunit;
namespace System.Data.Odbc.Tests
{
public class CommandBuilderTests : IntegrationTestBase
{
[Fact(Skip = "Native dependencies missing in CI. See https://github.com/dotnet/corefx/issues/15776.")]
public void QuoteIdentifier_UseConnection()
{
var commandBuilder = new OdbcCommandBuilder();
// Get quote string
var quotedIdentifier = commandBuilder.QuoteIdentifier("Test", connection);
var qs = quotedIdentifier.Remove(quotedIdentifier.IndexOf("Test"));
Assert.NotEmpty(qs);
// Test -> 'Test'
var quotedTestString = commandBuilder.QuoteIdentifier("Source", connection);
Assert.Equal($"{qs}Source{qs}", quotedTestString);
// 'Test' -> Test
Assert.Equal("Source", commandBuilder.UnquoteIdentifier(quotedTestString, connection));
// Test' -> 'Test'''
quotedTestString = commandBuilder.QuoteIdentifier($"Test identifier{qs}", connection);
Assert.Equal($"{qs}Test identifier{qs}{qs}{qs}", quotedTestString);
// 'Test''' -> Test'
Assert.Equal($"Test identifier{qs}", commandBuilder.UnquoteIdentifier(quotedTestString, connection));
// Needs an active connection
Assert.Throws<InvalidOperationException>(() => commandBuilder.QuoteIdentifier("Test", null));
Assert.Throws<InvalidOperationException>(() => commandBuilder.QuoteIdentifier("Test"));
Assert.Throws<InvalidOperationException>(() => commandBuilder.UnquoteIdentifier("Test", null));
Assert.Throws<InvalidOperationException>(() => commandBuilder.UnquoteIdentifier("Test"));
}
[Fact(Skip = "Native dependencies missing in CI. See https://github.com/dotnet/corefx/issues/15776.")]
public void QuoteIdentifier_CustomPrefixSuffix()
{
var commandBuilder = new OdbcCommandBuilder();
// Custom prefix & suffix
commandBuilder.QuotePrefix = "'";
commandBuilder.QuoteSuffix = "'";
Assert.Equal("'Test'", commandBuilder.QuoteIdentifier("Test", connection));
Assert.Equal("'Te''st'", commandBuilder.QuoteIdentifier("Te'st", connection));
Assert.Equal("Test", commandBuilder.UnquoteIdentifier("'Test'", connection));
Assert.Equal("Te'st", commandBuilder.UnquoteIdentifier("'Te''st'", connection));
// Ensure we don't need active connection:
Assert.Equal("'Test'", commandBuilder.QuoteIdentifier("Test", null));
Assert.Equal("Test", commandBuilder.UnquoteIdentifier("'Test'", null));
}
}
}

View File

@@ -0,0 +1,23 @@
// 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 Xunit;
namespace System.Data.Odbc.Tests
{
public class DependencyCheckTest
{
[ConditionalFact(Helpers.OdbcNotAvailable)]
public void OdbcConnection_OpenWhenOdbcNotInstalled_ThrowsException()
{
if (PlatformDetection.IsWindowsServerCore && !Environment.Is64BitProcess)
return; // On 32 bit Server Core, it does not throw DllNotFoundException.
using (var connection = new OdbcConnection(ConnectionStrings.WorkingConnection))
{
Assert.Throws<DllNotFoundException>(() => connection.Open());
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace System.Data.Odbc.Tests
{
public static class Helpers
{
public const string OdbcIsAvailable = nameof(Helpers) + "." + nameof(CheckOdbcIsAvailable);
public const string OdbcNotAvailable = nameof(Helpers) + "." + nameof(CheckOdbcNotAvailable);
public static bool CheckOdbcNotAvailable() => !CheckOdbcIsAvailable();
private static bool CheckOdbcIsAvailable() =>
PlatformDetection.IsWindows ?
!PlatformDetection.IsWindowsNanoServer && (!PlatformDetection.IsWindowsServerCore || Environment.Is64BitProcess ) :
Interop.Libdl.dlopen((
PlatformDetection.IsOSX ?
"libodbc.2.dylib" :
"libodbc.so.2"
), Interop.Libdl.RTLD_NOW) != IntPtr.Zero;
}
}

View File

@@ -0,0 +1,270 @@
using System.Data.SqlClient;
using System.Text;
using Xunit;
namespace System.Data.Odbc.Tests
{
public static class OdbcParameterTests
{
[CheckConnStrSetupFact]
public static void RunTest()
{
string str1000 = null;
string str2000 = null;
string str4000 = null;
string str5000 = null;
string str8000 = "";
for (int i = 0; i < 800; i++)
{
str8000 += "0123456789";
if (i == 99)
{
str1000 = str8000;
}
else if (i == 199)
{
str2000 = str8000;
}
else if (i == 399)
{
str4000 = str8000;
}
else if (i == 499)
{
str5000 = str8000;
}
}
byte[] byte1000 = Encoding.ASCII.GetBytes(str1000);
byte[] byte2000 = Encoding.ASCII.GetBytes(str2000);
byte[] byte4000 = Encoding.ASCII.GetBytes(str4000);
byte[] byte5000 = Encoding.ASCII.GetBytes(str5000);
byte[] byte8000 = Encoding.ASCII.GetBytes(str8000);
object output = null;
int inputLength = 0;
int outputLength = 0;
RunTestProcedure("VARBINARY", 8000, byte8000, out output, out inputLength, out outputLength);
string outputStr = Encoding.ASCII.GetString(output as byte[]);
Assert.Equal(str8000, outputStr);
Assert.Equal(byte8000.Length, inputLength);
Assert.Equal(byte8000.Length, outputLength);
RunTestProcedure("VARBINARY", 8000, byte5000, out output, out inputLength, out outputLength);
outputStr = Encoding.ASCII.GetString(output as byte[]);
Assert.Equal(str8000, outputStr);
Assert.Equal(byte5000.Length, inputLength);
Assert.Equal(byte8000.Length, outputLength);
RunTestProcedure("VARBINARY", 8000, byte4000, out output, out inputLength, out outputLength);
outputStr = Encoding.ASCII.GetString(output as byte[]);
Assert.Equal(str8000, outputStr);
Assert.Equal(byte4000.Length, inputLength);
Assert.Equal(str8000.Length, outputLength);
RunTestProcedure("VARBINARY", 8000, byte2000, out output, out inputLength, out outputLength);
outputStr = Encoding.ASCII.GetString(output as byte[]);
Assert.Equal(str4000, outputStr);
Assert.Equal(byte2000.Length, inputLength);
Assert.Equal(str4000.Length, outputLength);
RunTestProcedure("VARBINARY", 8000, byte1000, out output, out inputLength, out outputLength);
outputStr = Encoding.ASCII.GetString(output as byte[]);
Assert.Equal(str2000, outputStr);
Assert.Equal(byte1000.Length, inputLength);
Assert.Equal(byte2000.Length, outputLength);
RunTestProcedure("VARCHAR", 8000, str8000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str8000, outputStr);
Assert.Equal(str8000.Length, inputLength);
Assert.Equal(str8000.Length, outputLength);
RunTestProcedure("VARCHAR", 8000, str5000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str8000, outputStr);
Assert.Equal(str5000.Length, inputLength);
Assert.Equal(str8000.Length, outputLength);
RunTestProcedure("VARCHAR", 8000, str4000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str8000, outputStr);
Assert.Equal(str4000.Length, inputLength);
Assert.Equal(str8000.Length, outputLength);
RunTestProcedure("VARCHAR", 8000, str2000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str4000, outputStr);
Assert.Equal(str2000.Length, inputLength);
Assert.Equal(str4000.Length, outputLength);
RunTestProcedure("VARCHAR", 8000, str1000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str2000, outputStr);
Assert.Equal(str1000.Length, inputLength);
Assert.Equal(str2000.Length, outputLength);
RunTestProcedure("NVARCHAR", 4000, str8000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str4000, outputStr);
Assert.Equal(str4000.Length * 2, inputLength); // since NVARCHAR takes 2 bytes per character
Assert.Equal(str4000.Length * 2, outputLength);
RunTestProcedure("NVARCHAR", 4000, str5000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str4000, outputStr);
Assert.Equal(str4000.Length * 2, inputLength);
Assert.Equal(str4000.Length * 2, outputLength);
RunTestProcedure("NVARCHAR", 4000, str4000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str4000, outputStr);
Assert.Equal(str4000.Length * 2, inputLength);
Assert.Equal(str4000.Length * 2, outputLength);
RunTestProcedure("NVARCHAR", 4000, str2000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str4000, outputStr);
Assert.Equal(str2000.Length * 2, inputLength);
Assert.Equal(str4000.Length * 2, outputLength);
RunTestProcedure("NVARCHAR", 4000, str1000, out output, out inputLength, out outputLength);
outputStr = output as string;
Assert.Equal(str2000, outputStr);
Assert.Equal(str1000.Length * 2, inputLength);
Assert.Equal(str2000.Length * 2, outputLength);
}
private static void RunTestProcedure(string procDataType, int procDataSize, object v1, out object v2, out int v3, out int v4)
{
string procName = DataTestUtility.GetUniqueName("ODBCTEST", "", "");
string removeExistingStoredProcSql =
$"IF OBJECT_ID('{procName}', 'P') IS NOT NULL " +
$"DROP PROCEDURE {procName};";
string createTestStoredProcSql =
$"CREATE PROCEDURE {procName} (" +
$"@v1 {procDataType}({procDataSize}), " +
$"@v2 {procDataType}({procDataSize}) OUT, " +
"@v3 INTEGER OUT, " +
"@v4 INTEGER OUT) " +
"AS BEGIN " +
"SET @v2 = @v1 + @v1; " +
"SET @v3 = datalength(@v1); " +
"SET @v4 = datalength(@v2); " +
"END;";
try
{
DataTestUtility.RunNonQuery(DataTestUtility.OdbcConnStr, removeExistingStoredProcSql);
DataTestUtility.RunNonQuery(DataTestUtility.OdbcConnStr, createTestStoredProcSql);
DbAccessor dbAccessUtil = new DbAccessor();
dbAccessUtil.connectSqlServer(DataTestUtility.OdbcConnStr);
dbAccessUtil.callProc("{ call "+ procName+"(?,?,?,?) }", procDataType, procDataSize, v1, out v2, out v3, out v4);
dbAccessUtil.commit();
dbAccessUtil.disconnect();
}
finally
{
DataTestUtility.RunNonQuery(DataTestUtility.OdbcConnStr, removeExistingStoredProcSql);
}
}
private class DbAccessor
{
private OdbcConnection con = null;
private OdbcTransaction trn = null;
public bool connectSqlServer(string connStr)
{
if (con == null)
{
con = new OdbcConnection(connStr);
}
con.Open();
trn = con.BeginTransaction();
return true;
}
public void disconnect()
{
if (trn != null)
{
trn.Rollback();
trn.Dispose();
trn = null;
}
if (con != null)
{
con.Close();
con.Dispose();
con = null;
}
}
public void callProc(string sql, string procDataType, int procDataSize, object v1, out object v2, out int v3, out int v4)
{
using (OdbcCommand command = new OdbcCommand(sql, con, trn))
{
command.Parameters.Clear();
command.CommandType = CommandType.StoredProcedure;
OdbcType dataType = OdbcType.NVarChar;
switch (procDataType.ToUpper())
{
case "VARBINARY":
dataType = OdbcType.VarBinary;
break;
case "VARCHAR":
dataType = OdbcType.VarChar;
break;
}
command.Parameters.Add("@v1", dataType, procDataSize);
command.Parameters.Add("@v2", dataType, procDataSize);
command.Parameters.Add("@v3", OdbcType.Int);
command.Parameters.Add("@v4", OdbcType.Int);
command.Parameters["@v1"].Direction = ParameterDirection.Input;
command.Parameters["@v2"].Direction = ParameterDirection.Output;
command.Parameters["@v3"].Direction = ParameterDirection.Output;
command.Parameters["@v4"].Direction = ParameterDirection.Output;
command.Parameters["@v1"].Value = v1;
command.ExecuteNonQuery();
v2 = command.Parameters["@v2"].Value;
v3 = Int32.Parse(command.Parameters["@v3"].Value.ToString());
v4 = Int32.Parse(command.Parameters["@v4"].Value.ToString());
}
}
public bool commit()
{
if (trn == null)
{
return false;
}
trn.Commit();
trn = null;
return true;
}
public bool rollback()
{
if (trn == null)
{
return false;
}
trn.Rollback();
trn = null;
return true;
}
}
}
}

View File

@@ -9,9 +9,21 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard-Windows_NT-Release|AnyCPU'" />
<ItemGroup>
<Compile Include="DependencyCheckTest.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="IntegrationTestBase.cs" />
<Compile Include="CommandBuilderTests.cs" />
<Compile Include="ReaderTests.cs" />
<Compile Include="SmokeTest.cs" />
<Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\libdl\Interop.dlopen.cs">
<Link>Common\Interop\Unix\libdl\Interop.dlopen.cs</Link>
</Compile>
<Compile Include="TestCommon\DataTestUtility.cs" />
<Compile Include="TestCommon\CheckConnStrSetupFactAttribute.cs" />
<Compile Include="OdbcParameterTests.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<Compile Include="ConnectionStrings.Windows.cs" />
@@ -20,4 +32,4 @@
<Compile Include="ConnectionStrings.Unix.cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -0,0 +1,19 @@
// 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 Xunit;
namespace System.Data.Odbc.Tests
{
public class CheckConnStrSetupFactAttribute : FactAttribute
{
public CheckConnStrSetupFactAttribute()
{
if(!DataTestUtility.AreConnStringsSetup())
{
Skip = "Connection Strings Not Setup";
}
}
}
}

View File

@@ -0,0 +1,48 @@
// 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.Globalization;
namespace System.Data.Odbc.Tests
{
public static class DataTestUtility
{
public static readonly string OdbcConnStr = null;
static DataTestUtility()
{
OdbcConnStr = Environment.GetEnvironmentVariable("TEST_ODBC_CONN_STR");
}
public static bool AreConnStringsSetup()
{
return !string.IsNullOrEmpty(OdbcConnStr);
}
// the name length will be no more then (16 + prefix.Length + escapeLeft.Length + escapeRight.Length)
// some providers does not support names (Oracle supports up to 30)
public static string GetUniqueName(string prefix, string escapeLeft, string escapeRight)
{
string uniqueName = string.Format("{0}{1}_{2}_{3}{4}",
escapeLeft,
prefix,
DateTime.Now.Ticks.ToString("X", CultureInfo.InvariantCulture), // up to 8 characters
Guid.NewGuid().ToString().Substring(0, 6), // take the first 6 characters only
escapeRight);
return uniqueName;
}
public static void RunNonQuery(string connectionString, string sql)
{
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
using (OdbcCommand command = new OdbcCommand(sql, connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
}
}