본문 바로가기

연구개발/CLR

CLR Utf8String - UDT

728x90
반응형

김종열

MS SQL Server MVP

엔트리브 소프트


안녕하세요. CLR에 오랜만에 하나를 올리는 듯하네요.
강좌를 목표로 하지 않고 실무에 필요한 것을 하나 하나 만들고 적용하다 보니 그렇습니다.
그리고 Database & C#의 수준이 한층 높아졌을 꺼라는 아니면 관심도라도 높아졌으리라는 희망을 가져봅니다.

이번 강좌는 sql2005에서 제공하는 User Defined Type(사용자정의데이터형)을 만들어볼까 합니다.

User Defined Type을 C#에서 만드시려면 C#에서 Datatype에 대한 옵션을 줄 때 
Optimiser에 대한 간략한 이해가 선행이 되면 훨씬 좋구요.
또한 DataType이기에 Transaction Isolation에 대한 이해도 선행되면 훨씬 좋을 듯합니다.

그럼 C#코드와 SQL 코드의 샘플들입니다.

using System;

using System.Xml;

using System.Data.Sql;

using System.Data.SqlTypes;

using System.Globalization;

using Microsoft.SqlServer.Server;

 

[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Samples.SqlServer")]

 

namespace Microsoft.Samples.SqlServer

{

    [Serializable]

    [Microsoft.SqlServer.Server.SqlUserDefinedType(Microsoft.SqlServer.Server.Format.UserDefined, IsByteOrdered = true, MaxByteSize = 8000)]

    [CLSCompliant(false)]

    public class Utf8String : INullable, IComparable, Microsoft.SqlServer.Server.IBinarySerialize

    {

 

        public static Utf8String Parse(SqlString sqlString)

        {

            if (sqlString.IsNull)

                return Utf8String.Null;

 

            return new Utf8String(sqlString.Value);

        }

 

        public SqlBinary Utf8Bytes

        {

            get

            {

                if (this.IsNull)

                    return SqlBinary.Null;

 

                if (this.m_Bytes != null)

                    return this.m_Bytes;

 

                if (this.m_String != null)

                {

                    this.m_Bytes = System.Text.Encoding.UTF8.GetBytes(this.m_String);

                    return new SqlBinary(this.m_Bytes);

                }

 

                throw new NotSupportedException("cannot return bytes for empty instance");

            }

            set

            {

                if (value.IsNull)

                {

                    this.m_Bytes = null;

                    this.m_String = null;

                }

                else

                {

                    this.m_Bytes = value.Value;

                    this.m_String = null;

                }

            }

        }

 

        [Microsoft.SqlServer.Server.SqlMethod(IsDeterministic = true, IsPrecise = true, DataAccess = Microsoft.SqlServer.Server.DataAccessKind.None, SystemDataAccess = Microsoft.SqlServer.Server.SystemDataAccessKind.None)]

        public override string ToString()

        {

            if (this.IsNull)

                return null;

 

            if (this.m_String != null)

                return this.m_String;

 

            if (this.m_Bytes != null)

            {

                this.m_String = System.Text.Encoding.UTF8.GetString(this.m_Bytes);

                return this.m_String;

            }

 

            throw new NotSupportedException("dont know how to return string from empty instance");

        }

 

 

        public SqlString ToSqlString()

        {

            if (this.IsNull)

                return SqlString.Null;

 

            return new SqlString(this.ToString());

        }

 

 

        private SqlString GetSortKeyUsingCultureInternal(CultureInfo culture, bool ignoreCase,

            bool ignoreNonSpace, bool ignoreWidth)

        {

            if (this.IsNull)

                return SqlString.Null;

 

            SqlCompareOptions compareOptions = SqlCompareOptions.None;

            if (ignoreCase)

                compareOptions = compareOptions | SqlCompareOptions.IgnoreCase;

 

            if (ignoreNonSpace)

                compareOptions = compareOptions | SqlCompareOptions.IgnoreNonSpace;

 

            if (ignoreWidth)

                compareOptions = compareOptions | SqlCompareOptions.IgnoreWidth;

 

            return new SqlString(this.ToString(), culture.LCID, compareOptions);

        }

 

        [Microsoft.SqlServer.Server.SqlMethod(IsDeterministic = true, IsPrecise = true)]

        public SqlString GetSortKeyUsingCulture(string cultureName, bool ignoreCase,

            bool ignoreNonSpace, bool ignoreWidth)

        {

            CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);

            if (culture == null)

                throw new ArgumentException(string.Format(

                    CultureInfo.InvariantCulture,

                    "Culture {0} not recognized.", cultureName));

 

            return this.GetSortKeyUsingCultureInternal(culture, ignoreCase,

                ignoreNonSpace, ignoreWidth);

        }

 

        [Microsoft.SqlServer.Server.SqlMethod(IsDeterministic = false)]

        public SqlString GetSortKey(bool ignoreCase, bool ignoreNonSpace, bool ignoreWidth)

        {

            return this.GetSortKeyUsingCultureInternal(CultureInfo.CurrentCulture,

                ignoreCase, ignoreNonSpace, ignoreWidth);

        }

 

 

        #region comparison operators

        public override bool Equals(object obj)

        {

            return this.CompareTo(obj) == 0;

        }

 

        public static bool operator ==(Utf8String utf8String, Utf8String other)

        {

            return utf8String.Equals(other);

        }

 

        public static bool operator !=(Utf8String utf8String, Utf8String other)

        {

            return !(utf8String == other);

        }

 

        public static bool operator <(Utf8String utf8String, Utf8String other)

        {

            return (utf8String.CompareTo(other) < 0);

        }

 

        public static bool operator >(Utf8String utf8String, Utf8String other)

        {

            return (utf8String.CompareTo(other) > 0);

        }

 

        private int CompareUsingCultureInternal(Utf8String other, CultureInfo culture, bool ignoreCase,

            bool ignoreNonSpace, bool ignoreWidth)

        {

            if (other == null)

                return 1;

 

            if (this.IsNull)

                if (other.IsNull)

                    return 0;

                else

                    return -1;

 

            if (other.IsNull)

                return 1;

 

            return this.GetSortKeyUsingCultureInternal(culture, ignoreCase, ignoreNonSpace,

                ignoreWidth).CompareTo(other.GetSortKeyUsingCultureInternal(culture, ignoreCase,

                ignoreNonSpace, ignoreWidth));

        }

 

        public int CompareUsingCulture(Utf8String other, string cultureName, bool ignoreCase,

            bool ignoreNonSpace, bool ignoreWidth)

        {

            CultureInfo culture = CultureInfo.CreateSpecificCulture(cultureName);

            if (culture == null)

                throw new ArgumentException(string.Format(

                    CultureInfo.InvariantCulture,

                    "Culture {0} not recognized.", cultureName));

 

            return this.CompareUsingCultureInternal(other, culture, ignoreCase,

                ignoreNonSpace, ignoreWidth);

        }

 

        public int Compare(Utf8String other, bool ignoreCase,

            bool ignoreNonSpace, bool ignoreWidth)

        {

            return this.CompareUsingCultureInternal(other, CultureInfo.CurrentCulture, ignoreCase,

                ignoreNonSpace, ignoreWidth);

        }

 

        public override int GetHashCode()

        {

            if (this.IsNull)

                return 0;

 

            return this.ToString().GetHashCode();

        }

 

        public int CompareTo(object obj)

        {

            if (obj == null)

                return 1;

 

            Utf8String s = obj as Utf8String;

 

            if (s == null)

                throw new ArgumentException("the argument to compare is not a Utf8String");

 

            if (this.IsNull)

            {

                if (s.IsNull)

                    return 0;

 

                return -1;

            }

 

            if (s.IsNull)

                return 1;

 

            return this.ToString().CompareTo(s.ToString());

        }

 

        #endregion

 

        #region private state and constructors

        private string m_String;

 

        private byte[] m_Bytes;

 

        public Utf8String(string value)

        {

            this.m_String = value;

        }

 

        public Utf8String(byte[] bytes)

        {

            this.m_Bytes = bytes;

        }

        #endregion

 

        #region UserDefinedType boilerplate code

 

        public bool IsNull

        {

            get

            {

                return this.m_String == null && this.m_Bytes == null;

            }

        }

 

        public static Utf8String Null

        {

            get

            {

                Utf8String str = new Utf8String((string)null);

 

                return str;

            }

        }

 

        public Utf8String()

        {

        }

        #endregion

 

        #region IBinarySerialize Members

        public void Write(System.IO.BinaryWriter w)

        {

            byte header = (byte)(this.IsNull ? 1 : 0);

 

            w.Write(header);

            if (header == 1)

                return;

 

            byte[] bytes = this.Utf8Bytes.Value;

 

            w.Write(bytes.Length);

            w.Write(bytes);

        }

 

        public void Read(System.IO.BinaryReader r)

        {

            byte header = r.ReadByte();

 

            if ((header & 1) > 0)

            {

                this.m_Bytes = null;

                return;

            }

 

            int length = r.ReadInt32();

 

            this.m_Bytes = r.ReadBytes(length);

        }

        #endregion

    }

}


조금 어렵죠? 저는 이런 복잡한 것은 ㅋ , SQL2005에서 이미 제공하는 UDT입니다.

use youlyDB

 

DECLARE @u1 Utf8String

       , @u2  Utf8String

      

select @u1 = CONVERT(Utf8String, ',“')

       , @u2 = CONVERT(Utf8String, ', “')

 

select PATINDEX('%,%', @u1.ToString())

       , PATINDEX('%,%', @u2.ToString())

 

go

 

 

Create Table utfTest(u Utf8String)

go

 

insert into utfTest values (cast('SQLLeader.Com' as Utf8String))

go

 

select

       u

       , u.ToString()

       , u.Utf8Bytes

from utfTest



참고 파일 : Utf8String.cs
              Utf8Test.sql

728x90
반응형

'연구개발 > CLR' 카테고리의 다른 글

CLR-User Definded Aggregatiion  (0) 2009.06.22
CLR- 음력을 양력으로 변환하는 함수  (0) 2009.06.22
CLR - Mail 보내기  (0) 2009.06.22
CLR - FTP download(FTP 2탄)  (0) 2009.06.22
CLR - FTP upload 구현(FTP 1탄)  (0) 2009.06.22