【问题标题】:What is the actual data type of the @cleartext (2nd) param of SQL Server's EncryptByKey(..) function?SQL Server EncryptByKey(..) 函数的 @cleartext (2nd) 段的实际数据类型是什么?
【发布时间】:2011-01-18 00:22:21
【问题描述】:

下面我要问的是:这个 SQL 函数的@cleartext 参数的实际数据类型是什么? >> 加密密钥 (..) - http://msdn.microsoft.com/en-us/library/ms174361.aspx

(如果您在此行下方阅读,您可以了解历史和推理。我认为它比最初看起来更棘手。)


SQL Server 文档声明EncryptByKey(..) 函数的@cleartext (2nd) 参数可以接受多种类型:

EncryptByKey (@key_GUID , @cleartext [, @add_authenticator, @authenticator] )

@cleartext
是类型变量 nvarchar、char、varchar、二进制、 包含数据的 varbinary 或 nchar 即用密钥加密。

^ ^ ^ ^ ^ ^ ^ ^ ^ ^ - - - - - 但它实际声明的数据类型是什么? ...

如果我要创建一个自定义函数(与上面给出的 EncryptByKey 示例完全分开)我应该给自定义参数提供什么实际数据类型,以便它以相同的方式接受所有这些相同的类型?

编辑 1: 我实际上将 SQL EncryptByKey 函数包装在自定义 UDF 函数,我想重新创建相同的函数 要传递的参数类型 它。这就是我想按类型创建完全相同的参数的原因。

编辑 2:如果我尝试使用 sql_variant 会导致错误

消息 8116,级别 16,状态 1,程序 EncryptWrapper,第 17 行参数数据 类型 sql_variant 对 EncryptByKey 函数的参数 2。

编辑 3:

这是我的自定义包装函数 - 以及直接的问题。 @cleartext 的数据类型应该是什么来直接传递给 EncryptByKey?

ALTER FUNCTION [dbo].[EncryptWrapper]
(
 @key_GUID uniqueidentifier,
 @cleartext -- ???????????  <<< WHAT TYPE ????????????????
 @add_authenticator int = 0,
 @authenticator sysname = NULL
)
RETURNS varbinary(8000)
AS
BEGIN

    -- //Calling a SQL Server builtin function. 
    -- //Second param @cleartext is the problem. What data type should it be?
 Return EncryptByKey(@key_GUID, @cleartext, @add_authenticator, @authenticator)

END

注意:我不应该使用 CAST 或 CONVERT - 我只需要为我的 @cleartext 参数使用正确的数据类型。

编辑 4:发现 EncryptByKey(..) @cleartext 参数不是以下类型

  • sql_variant- 通过时引发错误
  • varbinary- 过于严格- 不允许传递 EncryptByKey(..) 接受的文本类型
  • sysnamenvarcharvarchar- 奇怪的行为- 往往只采用参数文本的第一个字符或其他内容

【问题讨论】:

    标签: tsql types parameters


    【解决方案1】:

    尝试 sql_variant:

    CREATE FUNCTION [dbo].[yourFunction]
    (
         @InputStr      sql_variant   --can not be varchar(max) or nvarchar(max)
    )
    returns
    varchar(8000)
    
    BEGIN
        --can use SQL_VARIANT_PROPERTY(@InputStr,'BaseType') to determine given datatype
    
        --do whatever you want with @inputStr here
        RETURN CONVERT(varchar(8000),@InputStr)  --key is to convert the sql_varient to something you can use
    
    END
    GO
    

    关键是将 sql_varient 转换为您可以在函数中使用的东西。您可以使用 IF 语句并检查 BaseType 并将 sql_varient 转换回本机数据类型

    编辑
    以下是如何获取原始数据类型的示例:

    CREATE FUNCTION [dbo].[yourFunction]
    (
         @InputStr      sql_variant   --can not be varchar(max) or nvarchar(max)
    )
    returns
    varchar(8000)
    
    BEGIN
        DECLARE @Value varchar(50)
        --can use SQL_VARIANT_PROPERTY(@InputStr,'BaseType') to determine given datatype
    
        --do whatever you want with @inputStr here
        IF @InputStr IS NULL
        BEGIN
            SET @value= 'was null'
        END
        ELSE IF SQL_VARIANT_PROPERTY(@InputStr,'BaseType')='char'
        BEGIN
            --your special code here
            SET @value= 'char('+CONVERT(varchar(10),SQL_VARIANT_PROPERTY(@InputStr,'MaxLength '))+') - '+CONVERT(varchar(8000),@InputStr)
        END
        ELSE IF SQL_VARIANT_PROPERTY(@InputStr,'BaseType')='datetime'
        BEGIN
            --your special code here
            SET @value= 'datetime - '+CONVERT(char(23),@InputStr,121)
        END
        ELSE IF SQL_VARIANT_PROPERTY(@InputStr,'BaseType')='nvarchar'
        BEGIN
            --your special code here
            SET @value= 'nvarchar('+CONVERT(varchar(10),CONVERT(int,SQL_VARIANT_PROPERTY(@InputStr,'MaxLength '))/2)+') - '+CONVERT(varchar(8000),@InputStr)
        END
        ELSE
        BEGIN
            --your special code here
            set @value= 'unknown!'
        END
    
        RETURN  @value
    
    END
    GO
    

    测试一下:

    DECLARE @x char(5), @z int, @d datetime, @n nvarchar(27)
    SELECT @x='abc',@d=GETDATE(),@n='wow!'
    select [dbo].[yourFunction](@x)
    select [dbo].[yourFunction](@d)
    select [dbo].[yourFunction](@z)
    select [dbo].[yourFunction](@n)
    

    测试输出:

    -------------------------------------
    char(5) - abc  
    
    (1 row(s) affected)
    
    
    -------------------------------------
    datetime - 2010-02-17 15:10:44.017
    
    (1 row(s) affected)
    
    
    -------------------------------------
    was null
    
    (1 row(s) affected)
    
    
    -------------------------------------
    nvarchar(27) - wow!
    
    (1 row(s) affected)
    

    【讨论】:

    • sql_variant 导致我在问题的“编辑 2”中输入错误消息。我需要执行直接传递,所以我需要与 EncryptByKey 的第二个参数完全相同的数据类型。
    • 我也编辑了我的答案,在包装函数中,将 sql_variant 输入参数转换为文本类型,然后再将其传递给 EncryptByKey 函数。
    • 这是我的问题的解决方法,而且是合理的。然而真正的问题是我不需要修改数据类型(通过转换或强制转换),而是直接将其传递给 SQL EncryptByKey 函数的第二个参数,该函数接受多种文本数据类型 - 因此我想接受相同的类型。 ...我在显示确切问题的问题中添加了 Edit 3。
    • sql_variant 是包装数据类型。您的 char、varchar、nchar 等被传递到函数中,但在函数中,参数是 sql_variant。您的 EncryptByKey 不采用 sql_variant 数据类型,因此您需要将其转换回传递给函数的原始类型。您可以使用 SQL_VARIANT_PROPERTY() 函数来执行此操作。如果您不想这样做,那么使用 TSQL 就无法实现您的目标。您可以考虑使用 CLR。​​
    • 我明白你在说什么,但@cleartext 参数不会接受 sql_variant arg;但是它接受多种文本数据类型,因此从逻辑上讲,它必须定义为 sql_variant 以外的某些数据类型。我们知道所有参数都是用实际数据类型(隐式或显式)定义的。你知道如何找出那个参数的实际数据类型吗?
    【解决方案2】:

    ENCRYPTBYKEY() 几乎可以肯定不是用普通的 T-SQL 编写的。它不需要遵循 T-SQL 数据类型规则。

    也就是说,如果您想为其编写包装器,请使用 SQL_VARIANT 作为 @cleartext 参数,正如 KM 建议的那样。

    如果 ENCRYPTBYKEY() 对 @cleartext 的最大长度不敏感,您可以将所有 CHAR/VARCHAR 转换为 VARCHAR(8000),将所有 NCHAR/NVARCHAR 转换为 NVACHAR(4000)。

    否则您可能是 SOL:任何尊重最大长度的数据类型转换——例如,CHAR(10) 与 CHAR(20)——都需要动态 SQL,因此您必须将其编写为存储过程,而不是比一个功能。到那时,它就不再是真正的包装器了。

    【讨论】:

    • 我能够将它包装在多个函数中:EncryptNVarchar(..)、EncryptVarchar(..)、EncryptNbinary(..)。但是我相信你是对的,它不必遵循标准的 SQL 规则——微软在编写那个函数时并没有吃自己的狗粮。
    猜你喜欢
    • 1970-01-01
    • 2016-04-20
    • 2015-12-06
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 2020-05-15
    相关资源
    最近更新 更多