SQL Server 2008, CLR-funktion, System.InvalidOperationException: Accessing members of an object from a wrong thread.

13/11/2008 - 19:05 von Olaf Pietsch | Report spam
Hallo,

wir sind dabei von SQL Server 2005 auf 2008 umzustellen.

Wir haben CLR im Einsatz und nach dem in place update des Systems wirft eine
Funktion einen Laufzeitfehler:

SELECT * FROM dbo.clrs_f_DoubleMetaphoneWordBreaker_TAB ('irgendwas
beliebiges')

Msg 6260, Level 16, State 1, Line 1
An error occurred while getting new row from user defined Table Valued
Function :
System.InvalidOperationException: Accessing members of an object from a
wrong thread.
System.InvalidOperationException:
at
System.Data.SqlServer.Internal.ClrLevelContext.XvarProxyRead(CClrXvarProxy*
pXvarProxy, UInt64 iPosition, Byte* pbBuffer, UInt32 cbCount)
at
System.Data.SqlServer.Internal.ClrLevelContext.System.Data.SqlServer.Internal.IXvarProxyAccessor.XvarProxyRead(CClrXvarProxy*
, UInt64 , Byte* , UInt32 )
at System.Data.SqlServer.Internal.StreamOnBlobHandle.Read(Byte* pbBuffer,
UInt64 offset, UInt32 count)
at System.Data.SqlServer.Internal.XvarWlobStream.Read(Char[] buffer,
Int32 offset, Int32 count)
at System.Data.SqlTypes.SqlChars.Read(Int64 offset, Char[] buffer, Int32
offsetInBuffer, Int32 count)
at System.Data.SqlTypes.SqlChars.get_Item(Int64 offset)
at
UserDefinedFunctions.<clrs_f_DM_DoubleMetaphoneWordBreaker_TAB>d__0.MoveNext()

In der vorhandenen CLR Funktion haben wir
char[] inp = InputTextString.Buffer;

ersetzt durch die String Variante
string inp = @"";
inp = InputTextString.ToString();

(Details siehe unten)

Für uns ist nun das Problem gelöst. Nur was wir nicht verstehen, wie kommt
es zu dem Fehler? Gibt es eine Änderung bei SQL Server 2008 hinsichtlich
CLR?

Hàtte da jemand vielleicht einen Hinweis.

Danke und Gruß
Olaf



Die betreffende CLR Funktion ist seit 2006 bei uns auf SQL Server 2005 im
Einsatz:

struct Wort
{
public int _ID;
public SqlString _wort;

public Wort(int ID, SqlString Wort)
{
this._ID = ID;
this._wort = Wort;
}
}

[Microsoft.SqlServer.Server.SqlFunction(
DataAccess = DataAccessKind.None
, IsDeterministic = true
, IsPrecise = true
, SystemDataAccess = SystemDataAccessKind.None
, Name = "clrs_f_DoubleMetaphoneWordBreaker_TAB"
, TableDefinition = "ID int, Wort_c Nvarchar(4000)"
, FillRowMethodName = "fill_clrs_f_DoubleMetaphoneWordBreaker_TAB"
)
]
public static IEnumerable
clrs_f_DM_DoubleMetaphoneWordBreaker_TAB(SqlChars InputTextString)
{
//Hashtable to temporarily hold parsed words
//used to easily ensure unique words only
Hashtable ht = new Hashtable();
StringBuilder sbWord=new StringBuilder();

** Verursacher **
char[] inp = InputTextString.Buffer;
char c;

if (!InputTextString.IsNull && !(InputTextString.Length == 0))
{
hier wird was getan
// Schleife über den gesamten Eingabestrom
for ( int k = 0; k < InputTextString.Length; k++)
{

}

// Rückgabe
int i = 1;
foreach (string word in ht.Keys)
{
yield return new Wort(i, word);
i++;
}


}

}

public static void fill_clrs_f_DoubleMetaphoneWordBreaker_TAB(object
row, out int ID, out SqlString wort)
{
Wort t = (Wort)row;
ID = t._ID;
wort = t._wort;
}

};



Die Änderung für SQL Server 2008:

...
public static IEnumerable
clrs_f_DM_DoubleMetaphoneWordBreaker_TAB([SqlFacet(MaxSize = -1)] SqlString
InputTextString)
{
//Hashtable to temporarily hold parsed words
//used to easily ensure unique words only
Hashtable ht = new Hashtable();
StringBuilder sbWord = new StringBuilder();

string inp = @"";
char c = ' ';

if (!InputTextString.IsNull)
{

** Änderung **
inp = InputTextString.ToString();

if (inp.Length > 0)
{

hier wird was getan
// Schleife über den gesamten Eingabestrom
for (int k = 0; k < inp.Length; k++)
und es geht so weiter wie oben.


Gruß Olaf
Ich unterstütze PASS Deutschland e.V. (http://www.sqlpass.de)
Blog (http://www.sqlpass.de/PASSUserBlogs...x?BlogID=3)
Regionalgruppe Köln/Bonn/Düsseldorf
(http://www.sqlpass.de/Regionalgrupp...fault.aspx)
 

Lesen sie die antworten

#1 Elmar Boye
14/11/2008 - 11:45 | Warnen spam
Hallo Olaf,

Olaf Pietsch schrieb:

Wir haben CLR im Einsatz und nach dem in place update des Systems wirft
eine Funktion einen Laufzeitfehler:

SELECT * FROM dbo.clrs_f_DoubleMetaphoneWordBreaker_TAB ('irgendwas
beliebiges')

Msg 6260, Level 16, State 1, Line 1
An error occurred while getting new row from user defined Table Valued
Function :
System.InvalidOperationException: Accessing members of an object from a
wrong thread.



Ich habe das hier nachvollziehen können, und für mich sieht das nach
einem Bug aus.

System.InvalidOperationException:
at
System.Data.SqlServer.Internal.ClrLevelContext.XvarProxyRead(CClrXvarProxy*
pXvarProxy, UInt64 iPosition, Byte* pbBuffer, UInt32 cbCount)
at
System.Data.SqlServer.Internal.ClrLevelContext.System.Data.SqlServer.Internal.IXvarProxyAccessor.XvarProxyRead(CClrXvarProxy*
, UInt64 , Byte* , UInt32 )



Auch wenn man den Code dazu nicht hat:
Anscheinend nutzt der SQL Server einen anderen Thread für den Proxy,
da dürfte etwas überoptimiert worden sein (zumindest für die CLR Integration).
Und eine Möglichkeit, das zu àndern habe ich der Dokumentation bisher
nicht gefunden.

Zumal Du bist wohl nicht der einzige:
<URL:http://www.solidrockstable.com/blog...D&>
(wenn nicht schon selbst gefunden).

Ich denke das wàre ein Fall für Connect - unten habe ich mal meine
verkürzte Testvariante angehàngt, wenn Du nicht den vollstàndigen
Metaphone dort posten willst (der damit nichts zu tun hat).

hier wird was getan Schleife über den gesamten Eingabestrom



for (int k = 0; k < length; k++)
{
char c = inp[k];
if (char.IsLetterOrDigit(c))
{
sbWord.Append(c);
}
else if (sbWord.Length != 0)
{
string value = sbWord.ToString();

if (!ht.ContainsKey(value))
ht.Add(value, null);
sbWord.Length = 0;
}
}


und eine Abfrage in der AdventureWorks (2008) dazu:

SELECT d.DocumentNode, w.ID, w.Wort_c
FROM Production.Document AS d
CROSS APPLY dbo.clrs_f_DoubleMetaphoneWordBreaker_TAB(d.DocumentSummary) AS w
WHERE d.DocumentSummary IS NOT NULL

Gruß Elmar

Ähnliche fragen