SQL Server始终加密操作数类型冲突:varchar与运行EXEC sproc时的varchar(60)不兼容

时间:2017-11-21 14:46:07

标签: sql-server stored-procedures operand always-encrypted

我无法使用Always Encrypted来执行存储过程,该存储过程使用加密列来复制表。但是,我能够从sproc复制SQL并将其作为常规SQL运行并设置参数,通过SSMS中的EXEC函数执行sproc时无法触发sproc,这也导致了问题。应用

该表上有一个触发器,它插入到另一个类似结构的审计表中,该表也使用相同的加密进行加密。我做了通常的事情:

  • 检查“查询选项中始终加密的启用参数化”
  • 在“连接设置”中设置列加密设置=启用。
  • 刷新sproc的encyrption元数据:

        EXEC sp_refresh_parameter_encryption 'organization.uspOrganizationAddressUpsert'
    

    表:

        CREATE TABLE [organization].[OrganizationAddress](
    [OrganizationAddressId] [int] IDENTITY(1,1) NOT NULL,
    [CreatedUser] [int] NOT NULL,
    [CreatedDate] [datetime2](7) NOT NULL,
    [LastUpdateUser] [int] NOT NULL,
    [LastUpdateDate] [datetime2](7) NOT NULL,
    [RemovedDate] [datetime2](7) NULL,
    [Address1] [varchar](60) NOT NULL,
    [Address2] [varchar](60) NULL,
    [City] [varchar](60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
    [State] [varchar](60) NOT NULL,
    [ZipCode] [varchar](60) NOT NULL,
    [ClientNumberId] [int] NOT NULL
    
        CREATE TABLE [audit].[OrganizationAddressAudit](
    [OrganizationAddressId] [int] NOT NULL,
    [CreatedUser] [int] NOT NULL,
    [CreatedDate] [datetime2](7) NOT NULL,
    [LastUpdateUser] [int] NOT NULL,
    [LastUpdateDate] [datetime2](7) NOT NULL,
    [RemovedDate] [datetime2](7) NULL,
    [Address1] [varchar](60) NOT NULL,
    [Address2] [varchar](60) NULL,
    [City] [varchar](60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
    [State] [varchar](60) NOT NULL,
    [ZipCode] [varchar](60) NOT NULL,
    [ClientNumberId] [int] NOT NULL,
    [OperationDate] [datetime] NOT NULL,
    [Operation] [varchar](50) NOT NULL,
    [OperationBy] [varchar](100) NOT NULL
    

    存储过程:

        ALTER PROCEDURE [organization].[uspOrganizationAddressUpsert]
        @OrganizationId INT,
        @ExecutingUserId INT,
        @Address1 VARCHAR(60),
        @Address2 VARCHAR(60),
        @City VARCHAR(60),
        @State VARCHAR(60),
        @ZipCode VARCHAR(60),
        @ClientNumberId INT
    AS
    BEGIN
    SET NOCOUNT ON
        DECLARE @RightNow AS DATETIME2 = SYSDATETIME()
        If EXISTS (Select 1 From [organization].[OrganizationAddress] Where ClientNumberId = @ClientNumberId)
            BEGIN
                UPDATE [organization].[OrganizationAddress] SET
                LastUpdateUser = @ExecutingUserId,
                LastUpdateDate = @RightNow,
                Address1 = @Address1,
                Address2 = @Address2,
                City = @City,
                [State] = @State,
                ZipCode = @ZipCode,
                RemovedDate = Null
                Where ClientNumberId = @ClientNumberId
                END
        ELSE
            BEGIN -- INSERT part of the UPSERT
                INSERT INTO [organization].[OrganizationAddress]
                (CreatedUser
                ,CreatedDate
                ,LastUpdateUser
                ,LastUpdateDate
                ,Address1
                ,Address2
                ,City
                ,[State]
                ,ZipCode
                ,ClientNumberId)
                VALUES
                (@ExecutingUserId
                ,@RightNow
                ,@ExecutingUserId
                ,@RightNow
                ,@Address1
                ,@Address2
                ,@City
                ,@State
                ,@ZipCode
                ,@ClientNumberId)   
            END
    END
    

    使用参数设置运行存储过程代码很好,但我无法执行sproc:

            declare @orgId INT = 1;
    declare @client int = 888;
    declare @user int = 1;
    declare @Add1 varchar(60)= 'Test Address1';
    declare @Add2 varchar(60)= 'Test Address2';
    declare @city varchar(60) = 'City';
    declare @state varchar(60) = 'St';
    declare @zip varchar(60) = '12345';
    
    EXEC organization.uspOrganizationAddressUpsert 
        @OrganizationID=@orgID,
        @ExecutingUserId = @user, -- int
        @Address1 = @Add1, -- varchar(60)
        @Address2 = @Add2, -- varchar(60)
        @City = @city, -- varchar(60)
        @State = @state, -- varchar(60)
        @ZipCode = @zip, -- varchar(60)
        @ClientNumberId = @client; -- int
    
    Msg 206, Level 16, State 2, Procedure uspOrganizationAddressUpsert, Line 0 [Batch Start Line 1]
    Operand type clash: varchar is incompatible with varchar(60) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK_Auto1', column_encryption_key_database_name = 'BankruptcyApp') collation_name = 'SQL_Latin1_General_CP1_CI_AS'
    

    我在带有VARCHAR(60)的测试数据库中为加密列,触发器和审计表创建了一个类似的表,并且它在那里工作正常,我无法找到允许的表/ sproc / trigger中的任何差异它在那里工作,而不是在这里。我可以找到其他帖子和博客,我已经筋疲力尽了。

  • 1 个答案:

    答案 0 :(得分:0)

    固定!需要更新应用程序代码以指定数据类型和长度:

    parameters.Add("@City", organizationAddress.City, System.Data.DbType.AnsiString, System.Data.ParameterDirection.Input, 60);
    

    之前只是:

    parameters.Add("@City", organizationAddress.City)
    

    这至少让应用程序运行sproc但仍然无法通过EXEC从SSMS运行它