Jasne i ciemne strony baz danych

… w szczególności MS SQL Server ;-)

Posts Tagged ‘strona kodowa’

SQL Server – Jak wylistować dostępne kodowania funkcją tabelaryczną CLR?

Posted by C3PO w dniu 16 czerwca 2010


Ostatnimi czasy przesiaduję trochę na portalu WSS.pl. Na forum tegoż portalu wywiązała się całkiem interesująca dyskusja nad konwersją pomiędzy stroną kodową Mazovia (CP620) a stroną Windows-1250. Cały wątek jest tutaj. Postanowiłem drążyć temat dalej. Na razie stanęliśmy na tym, że mamy funkcję T-SQL:

IF OBJECT_ID('dbo.ufn_MazoviaTo1250', 'FN') IS NOT NULL
  DROP FUNCTION dbo.ufn_MazoviaTo1250;
GO
CREATE FUNCTION dbo.ufn_MazoviaTo1250 (@String varchar(maX))
RETURNS varchar(max)
WITH SCHEMABINDING
AS
BEGIN
  SET @String = @String COLLATE Polish_BIN;
  RETURN
    REPLACE (
      REPLACE (
        REPLACE (
          REPLACE (
            REPLACE (
              REPLACE (
                REPLACE (
                  REPLACE (
                    REPLACE (
                      REPLACE (
                        REPLACE (
                          REPLACE (
                            REPLACE (
                              REPLACE (
                                REPLACE (
                                  REPLACE (
                                    REPLACE (
                                      REPLACE (
                                        @String, CHAR(165), CHAR(209) -- Ń
                                      ), CHAR(143), CHAR(165)         -- Ą
                                    ), CHAR(163), CHAR(211)           -- Ó
                                  ), CHAR(156), CHAR(163)             -- Ł
                                ), CHAR(149), CHAR(198)               -- Ć
                              ), CHAR(144), CHAR(202)                 -- Ę
                            ), CHAR(152), CHAR(140)                   -- Ś
                          ), CHAR(160), CHAR(143)                     -- Ź
                        ), CHAR(161), CHAR(175)                       -- Ż
                      ), CHAR(134), CHAR(185)                         -- ą
                    ), CHAR(141), CHAR(230)                           -- ć
                  ), CHAR(145), CHAR(234)                             -- ę
                ), CHAR(146), CHAR(179)                               -- ł
              ), CHAR(164), CHAR(241)                                 -- ń
            ), CHAR(162), CHAR(243)                                   -- ó
          ), CHAR(158), CHAR(156)                                     -- ś
        ), CHAR(166), CHAR(159)                                       -- ź
      ), CHAR(167), CHAR(191)                                         -- ż
    ) COLLATE database_default;
END;
GO
-- Test
SELECT dbo.ufn_MazoviaTo1250 ('Ź•śĄŁ˜ ˇ†Ť‘’¤˘ž¦§'); 

Jeden z uczestników dyskusji zasugerował, by problem rozwiązać za pomocą funkcji napisanej w .NET (CLR). Wydaje się to być rozsądnym posunięciem. W końcu CLR może się spisywać lepiej w przypadku operacji na tekście (zwłaszcza długim). Na pierwszy ogień jednak postanowiłem rzucić sobie zadanie – napisanie funkcji do listowania dostępnych kodowań z poziomu .NET. Dzięki temu dowiem się, jakie kodowania mogę wykorzystać w konwersjach z użyciem metod klas z przestrzeni System.Text (np. klasy Encoding). Czyli rozchodzi się o to, by wiedzieć, jakie strony kodowe mogę konwertować niekoniecznie znak po znaku.

Po chwili skrobania wyszło mi coś takiego:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text;
using System.Collections;
public partial class UserDefinedFunctions
{
    [Microsoft.SqlServer.Server.SqlFunction(
        FillRowMethodName="FillEncodings",
        Name="ufn_CLR_GetEncodings",
        TableDefinition="CodePage int,
          EncodingName nvarchar(255),
          DisplayName nvarchar(255)"
        )]
    public static IEnumerable ufn_CLR_GetEncodings()
    {
        EncodingInfo[] Encodings = Encoding.GetEncodings();
        return Encodings;
    }
    public static void FillEncodings(
      object Obj,
      out int CodePage,
      out string EncodingName,
      out string DisplayName)
    {
        EncodingInfo e = (EncodingInfo) Obj;
        EncodingName = e.Name;
        DisplayName = e.DisplayName;
        CodePage = e.CodePage;
    }
};

W razie wątpliwości, co należy z tym kodem zrobić, zajrzyj na przykład tutaj: http://geekswithblogs.net/frankw/archive/2008/05/03/a-quick-walk-through-of-clr-integration-with-sql-server.aspx.

Test wdrożonej funkcji wygląda tak:

SELECT * FROM dbo.ufn_CLR_GetEncodings() ORDER BY CodePage;

I okazuje się, że Mazovia oczywiście nie znalazła się na liście. No cóż, pozostaje zatem żmudna podmiana znak po znaku. Ale o tym już napiszę następnym razem, jak tylko napiszę właściwy kod i przetestuję szybkość rozwiązania CLR vs. szybkość rozwiązania T-SQL. Ciąg dalszy nastapi ;-)

 

Posted in MS SQL Server | Otagowane: , , , , | 7 komentarzy »