Ошибка генерации UDA, недостаточный размер буфера - PullRequest
1 голос
/ 23 ноября 2010

У меня есть UDA в SQL 2005, который продолжает генерировать приведенную ниже ошибку.Я предполагаю, что это, скорее всего, связано с ограничением максимального размера в 8000 байт .... Есть ли способ обойти это, чтобы обойти это?Какие-либо предложения об избежании этого ограничения в 2005 году?Я знаю, что в 2008 году якобы были сняты эти ограничения, но я пока не могу обновиться.

A .NET Framework error occurred during execution of user-defined routine or aggregate "CommaListConcatenate": 
System.Data.SqlTypes.SqlTypeException: The buffer is insufficient. Read or write operation failed.
System.Data.SqlTypes.SqlTypeException: 
   at System.Data.SqlTypes.SqlBytes.Write(Int64 offset, Byte[] buffer, Int32 offsetInBuffer, Int32 count)
   at System.Data.SqlTypes.StreamOnSqlBytes.Write(Byte[] buffer, Int32 offset, Int32 count)
   at System.IO.BinaryWriter.Write(String value)
   at TASQLCLR.CommaListConcatenate.Write(BinaryWriter w)

Ответы [ 2 ]

5 голосов
/ 04 февраля 2011

Для SQL 2005 вы можете решить ограничение в 8000 байт, превратив один параметр в несколько параметров с помощью разделителя.Мне не нужно было вдаваться в детали, но вы можете найти ответ здесь: http://www.mssqltips.com/tip.asp?tip=2043

Для SQL 2008 вам нужно передать MaxByteSize как -1.Если вы попытаетесь передать число больше 8000, SQL не позволит вам создать агрегат, жалуясь на ограничение в 8000 байт.Если вы передадите -1, то, похоже, обойдёт эту проблему и позволит вам создать агрегат (который я также протестировал с> 8000 байтов).

Ошибка:

Размер (100000) для "Class.Concatenate" находится вне допустимого диапазона.Размер должен быть -1 или число от 1 до 8000.

Вот определение рабочего класса VB.NET для поддержки> 8000 байтов в SQL 2008.

<Serializable(), SqlUserDefinedAggregate(Format.UserDefined, 
IsInvariantToNulls:=True, 
IsInvariantToDuplicates:=False, 
IsInvariantToOrder:=False, MaxByteSize:=-1)>
<System.Runtime.InteropServices.ComVisible(False)> _
Public Class Concatenate Implements IBinarySerialize
End Class
3 голосов
/ 24 марта 2011

Приведенный ниже код показывает, как рассчитать мультимедиа для набора десятичных чисел в SQLAggregate. Это решает проблему ограничения параметров размера, реализуя словарь данных. Идея взята из Expert SQL Express 2005.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using SafeDictionary;


[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Format.UserDefined, MaxByteSize=16)]

public struct CMedian2 : IBinarySerialize
{
    readonly static SafeDictionary<Guid , List<String>> theLists = new SafeDictionary<Guid , List<String>>();

    private List<String> theStrings;
    //Make sure to use SqlChars if you use
    //VS deployment!
    public SqlString Terminate()
    {

        List<Decimal> ld = new List<Decimal>();
        foreach(String s in theStrings){
           ld.Add(Convert.ToDecimal(s));
        }

        Decimal median;
        Decimal tmp;
        int halfIndex;
        int numberCount;


        ld.Sort();
        Decimal[] allvalues = ld.ToArray();

        numberCount = allvalues.Count();

        if ((numberCount % 2) == 0)
            {
                halfIndex = (numberCount) / 2;
                tmp = Decimal.Add(allvalues[halfIndex-1], allvalues[halfIndex]);
                median = Decimal.Divide(tmp,2);
            }
        else
            {
                halfIndex = (numberCount + 1) / 2;
                median =  allvalues[halfIndex - 1];
                tmp = 1;
            }

        return new SqlString(Convert.ToString(median));
    }

    public void Init()
        {
        theStrings = new List<String>();
        }

    public void Accumulate(SqlString Value)
        {
        if (!(Value.IsNull))
            theStrings.Add(Value.Value);
        }

    public void Merge(CMedian2 Group)
        {
        foreach (String theString in Group.theStrings)
            this.theStrings.Add(theString);
        }

    public void Write(System.IO.BinaryWriter w)
    {
    Guid g = Guid.NewGuid();
        try
        {
            //Add the local collection to the static dictionary
            theLists.Add(g, this.theStrings);
            //Persist the GUID
            w.Write(g.ToByteArray());
        }
        catch
        {
            //Try to clean up in case of exception
            if (theLists.ContainsKey(g))
            theLists.Remove(g);
        }
    }
    public void Read(System.IO.BinaryReader r)
    {
        //Get the GUID from the stream
        Guid g = new Guid(r.ReadBytes(16));
        try
        {
            //Grab the collection of strings
            this.theStrings = theLists[g];
        }
        finally
        {
            //Clean up
            theLists.Remove(g);
        }
    }
}

вам также нужно реализовать словарь, как это делает Expert 2005:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SafeDictionary 
{
public class SafeDictionary<K, V>
{
    private readonly Dictionary<K, V> dict = new Dictionary<K,V>();
    private readonly ReaderWriterLock theLock = new ReaderWriterLock();

    public void Add(K key, V value)
    {
        theLock.AcquireWriterLock(2000);
        try
            {
                dict.Add(key, value);
            }
        finally
            {
                theLock.ReleaseLock();
            }
   }

    public V this[K key]
    {
        get
            {
                theLock.AcquireReaderLock(2000);
                try
                    {
                        return (this.dict[key]);
                    }
                finally
                    {
                        theLock.ReleaseLock();
                    }
            }
        set
            {
                theLock.AcquireWriterLock(2000);
                try
                    {
                        dict[key] = value;
                    }
                finally
                    {
                        theLock.ReleaseLock();
                    }
           }
    }

    public bool Remove(K key)
    {
        theLock.AcquireWriterLock(2000);
        try
            {
                return (dict.Remove(key));
            }
        finally
            {
                theLock.ReleaseLock();
            }
    }

    public bool ContainsKey(K key)
    {
        theLock.AcquireReaderLock(2000);
        try
            {
                return (dict.ContainsKey(key));
            }
        finally
            {
                theLock.ReleaseLock();
            }
    }
}
}

Словарь должен быть развернут в отдельной сборке с небезопасными кодами. Идея состоит в том, чтобы избежать сериализации всех чисел, сохраняя в памяти словарь структуры данных. Я рекомендую главу Expert SQL 2005:

ГЛАВА 6 ■ SQLCLR: АРХИТЕКТУРА И ПРОЕКТНЫЕ СООБРАЖЕНИЯ.

Кстати, это решение не сработало для меня. Слишком большое количество преобразований из десятичного в строковое и наоборот замедляет работу при работе с миллионами строк, в любом случае, мне понравилось пробовать это. Для других случаев это хороший шаблон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...