2010-11-30 3 views
2

Je cours du code C# à l'intérieur d'une fonction CLR et en cours d'exécution dans un comportement étrange.Erreur CLR SQL ou bogue?

Lorsque le code suivant fonctionne:

SqlCommand cmd = new SqlCommand(); 
    cmd.CommandText = "SELECT * FROM Vertica_GetVerticaServer_vw WHERE verticaServer IS NOT NULL ORDER BY NEWID()"; 

    using (cmd.Connection = GetSQLConnection()) 
    { 
    cmd.Connection.Open(); 
    SqlDataReader r = cmd.ExecuteReader(); 

    while (r.Read()) 
    { 
     return r.GetString(0); 
    } 
    } 

Cette erreur est renvoyée (trace complète de la pile correspondante ci-dessous):

instructions Select inclus dans une fonction ne peut pas renvoyer des données à un client. Cependant, quand je cours le même code, moins le "ORDER BY NEWID()" (utilisé pour randomiser le résultat) et à la place exécutez le "ORDER BY NEWID()" à l'intérieur de la vue, je n'obtiens pas d'erreurs: Quelqu'un sait ce qu'il se passe ici?

SqlCommand cmd = new SqlCommand(); 
    cmd.CommandText = "SELECT * FROM Vertica_GetVerticaServer_vw WHERE verticaServer IS NOT NULL");// ORDER BY NEWID()"; 

    using (cmd.Connection = GetSQLConnection()) 
    { 
    cmd.Connection.Open(); 
    SqlDataReader r = cmd.ExecuteReader(); 

    while (r.Read()) 
    { 
     return r.GetString(0); 
    } 
    } 
    throw new Exception("Could not get Vertica Server name"); 

Cela ressemble à un bug, mais peut-être qu'il me manque quelque chose à propos du NEWID()?

(Note, j'ai testé avec GETDATE() à la place pour voir si c'était un problème avec le déterminisme, et cela a aussi fonctionné ...).

pleine Stack Trace:

---> System.Data.SqlClient.SqlException: instructions Select incluses dans une fonction ne peut pas renvoyer des données à un client. System.Data.SqlClient.SqlException: à System.Data.SqlClient.SqlConnection.OnError (exception de SqlException, Boolean breakConnection) à System.Data.SqlClient.SqlDataReaderSmi.InternalNextResult (Boolean ignoreNonFatalMessages) à System.Data.SqlClient. SqlDataReaderSmi.NextResult() à System.Data.SqlClient.SqlCommand.RunExecuteReaderSmi (CommandBehavior cmdBehavior, runBehavior runBehavior, Boolean returnStream) à System.Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, runBehavior runBehavior, Boolean returnStream, méthode String, Résultat DbAsyncResult) à System.Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, méthode String) à System.Data.SqlClie nt.SqlCommand.ExecuteReader (Comportement CommandBehavior, méthode String) à System.Data.SqlClient.SqlCommand.ExecuteReader() à Aggregation.AggregateDataManager.GetVerticaServer()

Comme demandé, voici la configuration du CLR TVF:

 [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "FillRowAggregates", TableDefinition = "listId int, pricingDate datetime, value decimal", DataAccess=DataAccessKind.Read)] 
    public static IEnumerable CalculateListAggregatePricing(int listId, DateTime start, DateTime end, int WeightTypeId) 
    { 
     DataRequest d = new DataRequest(); 
     d.Start = start; 
     d.Finish = end; 
     d.Metric = Metric.GetSharePricingMetric(); 
     d.Metric.Weight = WeightType.Equal; 
     _listId = listId; 
     List<ConstituentInfo> ci = new List<ConstituentInfo>(); 
     foreach (int i in AggregateDataManager.GetConstituents(listId)) 
      ci.Add(new ConstituentInfo(i, end)); 

     switch (WeightTypeId) 
     { 
      case 0: 
       EqualWeightInterpreterForSQLCLR e = new EqualWeightInterpreterForSQLCLR(); 
       return e.GetIndex(d, ci, false); 
      case 1: 
       MarketCapWeightInterpreterForSQLCLR mc = new MarketCapWeightInterpreterForSQLCLR(); 
       return mc.GetIndex(d, ci, false); 
      case 2: 
       PriceWeightInterpreterForSQLCLR p = new PriceWeightInterpreterForSQLCLR(); 
       return p.GetIndex(d, ci, false); 
     } 
     throw new Exception("Invalid Weight Type"); 

    } 

    public static void FillRowAggregates(Object o, out SqlInt32 listId, out SqlDateTime pricingDate, out SqlDecimal value) 
    { 
     DataPoint dp = (DataPoint)o; 

     listId = _listId; 
     pricingDate = dp.PricingDate; 
     value = (SqlDecimal)dp.Value; 
    } 

La connexion est construite par les WeightedInterpreters.

+0

Quel est l'exemple de code complet pour la fonction CLR et comment elle est utilisée. Si cela est supposé être un TVF, vous devez fournir la méthode enumerable et la méthode FillRow, qui ne sont pas au-dessus. Si c'est votre utilisation exacte de SQLCLR, pourquoi? Cela s'est avéré être plus lent que d'utiliser TSQL seul pour cela. –

+0

Est-ce que 'GetSQLConnection' utilise une chaîne de connexion de contexte? Par exemple, 'return new SqlConnection (" context connection = true ");'. –

+0

@Johnathan Oui, c'est un TVF, je vais éditer fournir les fonctions. La fonction atteint réellement un SGBD séparé (Vertica) pour extraire des données, puis effectue une agrégation complexe BEAUCOUP plus lente dans TSQL. – eric

Répondre

0

Avez-vous essayé quelque chose comme TOP 99.99999 POURCENTAGE?