forked from dotnet/corefx
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix for OdbcParameter Error "Data type 0x23 is a deprecated large obj…
…ect..." (dotnet#24529)
- Loading branch information
Gene Lee
authored and
Paulo Janotti
committed
Oct 31, 2017
1 parent
8b4ee42
commit 83232e2
Showing
5 changed files
with
360 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/System.Data.Odbc/tests/TestCommon/CheckConnStrSetupFactAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} | ||
} | ||
} | ||
} |