65.9K
CodeProject 正在变化。 阅读更多。
Home

如何在 SQL 脚本中在线将代码页转换为 Unicode。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (5投票s)

2001 年 9 月 1 日

5分钟阅读

viewsIcon

79968

downloadIcon

1790

本文展示了如何在 Microsoft SQL Server 中直接使用一个扩展存储过程,该过程可以实现 Unicode 和代码页数据之间的转换。

它还提供了一个 C++ 客户端示例,用于测试 U2CP 和 CP2U 转换函数。

Sample Image - Usage.gif

Sample Image - Dialog.gif

概述

很久以前,我遇到了一种非常新颖且奇怪的情况。我的公司基于一个旧的骨架站点构建了一个新的金融站点。需要将大量数据从旧数据库(Access 97)迁移到新数据库(Microsoft SQL 7)。

问题是什么? - 旧数据库中的所有数据都使用希腊代码页编写,而新数据库则计划使用 Unicode。客户的另一个要求是两个站点的数据都能在线访问。这意味着当用户在一个表中输入代码页数据时,这些信息必须自动转换为 Unicode 数据(在另一个表中),反之亦然。

我花了 4 天时间研究 Microsoft SQL 事务语言,希望能找到一些非常简单的函数来在代码页和 Unicode 字符之间进行转换。不幸的是,我没有找到……Microsoft SQL Server 支持 Unicode 和代码页格式,但不支持它们之间的转换函数。

我确信会在互联网上找到一些非常简单的转换函数或程序。又过了 2 天,我放弃了。我只找到了 Microsoft API 函数 - WideCharToMultiByteMultiByteToWideChar - 以及一个使用它们来转换文件的庞大程序。

这就是为什么我决定自己编写函数。

详细说明

WideCharToMultiByteMultiByteToWideChar 在 MSDN 上有详细的文档。我为这些函数创建了两个简单的包装器,并设置了一些默认参数。

bool CDialogDlg::U2CP(
LPCWSTR    pUSourceData,
char        pOutData[],
UINT        giUDestinationCodePage,
char        pErrorData[] 
)

// pUSourceData = This is Unicode multibyte string
//        that has to be translated 

// pOutData = In this variable will be put the code page translated string

// giUDestinationCodePage= Integer that must
//        contain the code page number (1253 for Greek)

// pErrorData = A string that eventually contains an error.


bool CDialogDlg::CP2U(
LPCSTR    pSourceData,
WCHAR    pOutData[],
UINT        giSourceCodePage,
char        pErrorData[]
        )

// pUSourceData = This is code page input
//                string that has to be translated

// pOutData = In this multibyte variable
//                will be put the unicode translated string

// giSourceCodePage = Integer that must contain
//                the code page number (1253 for Greek)

// pErrorData        = A string that eventually contains an error.

我从 Microsoft 示例中保留了一个用于分配内存的实用函数。

LPVOID ManageMemory (UINT message, 
  UINT sourcedestination, DWORD nBytes, LPVOID p)

现在,如果您想测试这些函数,请尝试使用 *C++ 对话框客户端*。

将键盘设置更改为所需的语言(例如希腊语),然后在第一个编辑框中输入一些单词/字符。可以调整编辑框的设置以正确显示所需的代码页字符(默认情况下您会看到一些 ASCII 字符,但这没关系 - 只需复制并粘贴到 Word 中查看即可)。

在右侧的编辑框中,您需要输入代码页(希腊语为 1253)。按 *CP2U 按钮*。由于 C++ 编辑框不支持 Unicode,您将在 Unicode 编辑框中看到一些奇怪的字符(“± » Ζ ± ”)。

要再次在第三个按钮中查看代码页数据,请按 *U2CP 按钮*。

当然,这些函数可以在许多情况下使用。

  • 直接从 C++ 调用,以处理来自文件或数据库的字符串。
  • 将函数封装到 COM 组件中,并从其他程序或语言平台使用它。
  • 更多...

要直接在 Microsoft SQL 事务语言中使用它们,您需要将函数封装到两个 C 扩展存储过程中。出于部署原因,我创建了两个函数:xp_u2cpxp_cp2u_web

Microsoft SQL Server 允许用户创建自己的函数。要构建一个:

  • 创建一个 *扩展存储过程* Microsoft Visual C++ 项目。
  • 在向导中,为函数指定与项目名称相同的名称。
  • 完成向导后,将 XP_U2CP.dll 复制到您的 SQL Server 的 \Binn 目录下。
  • 通过执行以下 SQL 命令,从查询分析器添加您的新扩展存储过程。
    sp_addextendedproc 'xp_u2cp', 'XP_U2CP.DLL'
  • 您会在 master 数据库的 *扩展存储过程* 组中找到该函数。如有必要,请授予适当的权限!
  • 您可以使用以下 SQL 命令删除扩展存储过程:
    sp_dropextendedproc 'xp_u2cp'
  • 您可以使用以下 SQL 命令将 DLL 从服务器释放(以删除或替换文件):
    DBCC xp_u2cp(FREE)
  • 从查询分析器或存储过程访问函数。
    Master.dbo.xp_u2cp

A. Unicode 到代码页的转换。

图片中是一个证明该函数的通用脚本。

为了使用它,您需要使用 SQL 存储过程。

Exec spDu2cp N'ατηενσ ι νιψοσια', 1253

spDu2cp 存储过程是 xp_u2cp 扩展过程的包装器。

第一个参数是 nvarchar(Unicode 字符串),第二个参数是代码页。该存储过程将打印 varchar 结果。在 spDu2cp 存储过程中,使用了一些设置的 xp_u2cp 扩展过程。

关于 Unicode 到代码页扩展存储过程的参数。

扩展过程必须这样使用:

exec master.dbo.xp_u2cp @param1, @param2 OUTPUT, @cp

@param1= must be varbinary(8000). 

This will contain the Unicode characters in hexadecimals format. 
The CAST translation is needed because the extended 
procedure parameters don’t know multibyte characters.

set @param1 = CAST(@u_value AS varbinary(8000))
@param2     = must be  varchar(4000). 
This output variable will contain the code page translated string.
@cp    = must be a int. 
This parameter contains the needed code page 
(1253 – Greek, for example).

B. 代码页到 Unicode 的转换。

图片中是一个证明该函数的通用脚本。

为了使用它,您需要使用 SQL 存储过程。

Exec spDcp2u 'gica in code page', 1253

spDcp2u 存储过程是 xp_cp2u_web 扩展过程的包装器。

第一个参数是 varchar 字符串,第二个参数是代码页。该存储过程将打印 nvarchar 结果。在 spDcp2u 存储过程中,使用了一些设置的 xp_cp2u_web 扩展过程。

关于代码页到 Unicode 扩展存储过程的参数。

扩展过程必须这样使用:

exec master.dbo.xp_cp2u_web @param1, @param2 OUTPUT, @cp

@param1= must be varchar (2000). 
This will contain the code page characters

@param2 = must be  varbinary(4000). 
This output variable will contain the code page 
translated string in hexadecimal format. 

In order to use it, this must be translated in nvarchar Unicode format. 
The CAST translation is needed because the 
extended procedure parameters don’t know multibyte characters.

set @param1 = CAST(@u_value AS varbinary(8000))

@cp    = must be a int. 
This parameter contains the needed code page 
(1253 – Greek, for example).

这些函数必须直接从 Unicode(nvarchar)/代码页(varchar)数据表中获取数据并放入数据表。示例中的字符串变量仅用于测试。Microsoft 查询分析器 SQL 编辑器只知道 Unicode,因此您无法将真正的代码页字符串参数传递给这些函数(编辑器会将输入字符串转换为 Unicode 格式)。

C 扩展过程中执行的步骤:

  • 我检查了接收到的每个参数,并对其类型和大小进行了一些测试。
    //Returns the data type of a remote stored procedure call parameter
    srv_paramtype (srvproc, 1 );
    
    // Returns the maximum data length of
    // a remote stored procedure call parameter.
    srv_parammaxlen (srvproc, 1 ); 
    //Returns the data length of a remote stored procedure call parameter.
    srv_paramlen (srvproc, 1 ); 
  • 之后,我检索了输入参数。
    // Returns the value of a remote stored procedure call parameter.
    srv_paramdata (srvproc, 1 );
  • 我进行了 Unicode 转换。
    U2CP( pUSourceData, pOutData,  iCodePage, pErrorData )
  • 我设置了输出参数。
    // Sets the value of a remote stored procedure call return parameter.
    
    srv_paramset(srvproc, 2, (void*)pOutData, strlen(pOutData)

    在扩展过程的 C 代码内部,我保留了一些 Microsoft 示例中的实用函数。

    // send XP usage info to client
    
    void printUsage (SRV_PROC *srvproc)
    
    // send szErrorMsg to client
    void printError (SRV_PROC *srvproc, CHAR* szErrorMsg)
    
    //send a simple message to the client sql console
    void printMessage (SRV_PROC *srvproc, DBCHAR* szMsg)

安装

  • 直接使用 *Dialog.exe* 示例 C++ 程序。
  • XP_U2CP.dllXP_CP2U_web.dll 复制到您的 SQL Server \Binn 目录下。
  • 通过执行以下 SQL 命令,从查询分析器添加您的新扩展存储过程:
    sp_addextendedproc 'xp_u2cp', 'XP_U2CP.DLL'
    sp_addextendedproc 'xp_cp2u_web', 'XP_CP2U.DLL'
  • 从查询分析器或存储过程访问函数。
    Master.dbo. xp_u2cp
    Master.dbo. xp_cp2u_web
  • 使用 spDcp2u.sqlspDu2cp.sql SQL 事务脚本在查询分析器中为这些扩展过程创建包装器存储过程。
© . All rights reserved.