J'ai écrit un certain nombre de fonctions SQL CLR (UDF) qui lisent des données à partir d'une base de données DB2 externe hébergée sur IBM iSeries. IBM DB2 .Net Provider). Pour que la fonction dispose des autorisations nécessaires pour lire ces données, je dois décorer la fonction avec l'attribut SqlFunction ayant la propriété DataAccess définie sur DataAccessKind.Read. Je déploie également l'assemblée en tant que UNSAFE.Comment autoriser une fonction SQL CLR à s'exécuter dans un plan de requête parallèle et disposer également d'autorisations d'accès aux données
Le temps requis pour lire les données de la base de données DB2 est relativement lent (par exemple, 3 ms pour l'ExecuteScalar le plus simple). J'utilise ces fonctions définies par l'utilisateur pour fusionner efficacement les données de la base de données DB2 dans les vues de serveur SQL Server.
Par exemple, supposons que mon UDF est défini comme
[SqlFunction(DataAccess = DataAccessKind.Read, IsDeterministic = true)]
public static SqlMoney GetCostPrice(SqlString partNumber)
{
decimal costPrice;
// open DB2 connection and retrieve cost price for part
return new SqlMoney(costPrice);
}
puis utilisez dans mon View SQL comme:
select Parts.PartNumber,
dbo.GetCostPrice(Parts.PartNumber) as CostPrice
from Parts
Les problèmes de mauvaise performance pourrait être significativement impacté si je pouvais courir mon Vues SQL avec un plan de requête parallèle.
Des techniques documentées expliquent comment forcer un plan de requête à s'exécuter en parallèle plutôt qu'en série, mais ces techniques ont des limitations imposées par SQL Server, dont une fonction SQL CLR définie DOIT avoir DataAccess = DataAccessKind.None. Mais si je mets DataAcessKind à None, alors je reçois une exception lorsque j'essaie d'ouvrir une connexion DbConnection dans la fonction.
Et c'est mon problème! Comment puis-je exécuter mon fichier UDF dans un plan de requête parallèle tout en lui permettant de lire les données de la base de données externe? La meilleure idée que je dois aborder est de hard-code DataAccess = DataAccessKind.None dans mon attribut SqlFunction et puis, à l'exécution, dans le corps de la fonction élever des autorisations avec Code Access Security de sorte que le code suivant a des autorisations pour ouvrir les objets DbConnection.
Mais je n'arrive pas à comprendre comment faire? A titre d'expérience, je l'ai essayé ce qui suit
[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true)]
public static SqlMoney TestFunction()
{
var sqlPerm = new SqlClientPermission(PermissionState.Unrestricted);
sqlPerm.Assert();
using (var conn = new SqlConnection("context connection=true"))
{
conn.Open();
}
return new SqlMoney();
}
et invoquer de SQL Server Management Studio avec:
select dbo.TestFunction()
mais je continue à obtenir une exception de sécurité ...
A. Une erreur NET Framework s'est produite pendant l'exécution de la routine ou de l'agrégat "TestFunction" définie par l'utilisateur: System.InvalidOperationException: L'accès aux données n'est pas autorisé dans ce contexte. Soit le contexte est une fonction ou une méthode non marquée avec DataAccessKind.Read ou SystemDataAccessKind.Read, est un rappel pour obtenir des données à partir de la méthode FillRow d'une fonction de valeur table, ou est une méthode de validation UDT. System.InvalidOperationException: à System.Data.SqlServer.Internal.ClrLevelContext.CheckSqlAccessReturnCode (SqlAccessApiReturnCode Erc) à System.Data.SqlServer.Internal.ClrLevelContext.GetCurrentContext (SmiEventSink évier, Boolean throwIfNotASqlClrThread, Boolean fAllowImpersonation) à Microsoft.SqlServer .Server.InProcLink.GetCurrentContext (SmiEventSink eventSink) à Microsoft.SqlServer.Server.SmiContextFactory.GetCurrentContext() à System.Data.SqlClient.SqlConnectionFactory.GetContextConnection (options de sqlConnectionString, objet providerInfo, DbConnection owningConnection) à System.Data.SqlClient.SqlConnectionFactory.CreateConnection (options DbConnectionOptions, objet poolGroupProviderInfo, piscine DbConnectionPool, DbConnection owningConnection) à System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection (DbConnection owningConnection, DbConnectionPoolGroup poolGroup) à System.Data.ProviderBase.DbConnectionFactory.GetConnection (DbConnection owningConnection) à System.Data.ProviderBase.DbConnectionClosed.OpenConnection (DbConnection outerConnection, DbConnectionFactory connectionFactory) à System.Data.SqlClient.SqlConnection.Open () à UserDefinedFunctions.UserDefinedFunctions.TestFunction()
Quelqu'un a-t-il des idées?
Merci d'avance.
(BTW, je suis en cours d'exécution sur SQL 2008 en utilisant .Net 3.5)
Pourquoi ne pas utiliser une base de données connectée? –
Que voulez-vous dire "base de données connectée"? Vous voulez dire un serveur lié ??? (Désolé si je suis épais!) – Kev
https://msdn.microsoft.com/en-us/library/ms188279.aspx –