none
Varbinary(MAX) e Hashs diferentes para o mesmo arquivo RRS feed

  • Pergunta

  • Boa tarde,

    Ao inserir um pdf em uma tabela (SQL Server 2014) via C# via aplicativo,  é convertido o pdf em bytes (readallbytes) e é feito um INSERT em um campo varbinary(MAX).

    Antes da inserção, é calculado o hash dos bytes extraídos do pdf (readallbytes), e calculando após o hash do campo varbinary(MAX), mas eles não batem! São diferentes.

    Para calcular o hash foi criado um CLR com o mesmo código do C# em ambas, no aplicativo e no banco e os hashs, não batem, nem mesmo utilizando funções nativas do SQL Server (hashbyte) com arquivos menores de 8000.

    Alguém sabe se isto é problema de compactação do campo ou se realmente o SQL Server trata diferente o Hash do C#?

    sexta-feira, 23 de setembro de 2016 17:05

Respostas

  • Ronald,

    Então, eu sei disso, foi justamente o que eu imaginei!!!

    Mas na verdade poderíamos tentar fazer da mesma forma que normalmente é inserido uma imagem no SQL Server, algo similar a este exemplo de código:

    CREATE TABLE Imagem
       (
           id INT IDENTITY PRIMARY KEY
         , nome VARCHAR(100) NOT NULL
         , tipoMIME VARCHAR(20) NOT NULL
         , imagem VARBINARY(MAX)
         )
          
    INSERT INTO Imagem VALUES ('Minha imagem','image/jpeg',
    (SELECT * FROM OPENROWSET(BULK 'E:\Imagem.jpg', SINGLE_BLOB) AS A))

    Outra coisa, você realmente precisa ter o arquivo gravado no banco?

    Já pensou em guardar o arquivo diretamente em file system e fazer uma referência neste tabela apontando para o local de armazenamento do arquivo?

    Além disso, se você estiver utilizando o SQL Server 2012 ou superior poderíamos pensar no conceito de file stream e file table.


    Pedro Antonio Galvao Junior [MVP | MCC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | Professor Universitario | SoroCodigos | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]


    quarta-feira, 28 de setembro de 2016 15:34

Todas as Respostas

  • Pode postar o código C# para testes?

    Talvez ele esteja utilizando um salt.

    sábado, 24 de setembro de 2016 04:12
  • Bom dia André, obrigado por responder. Segue.

    Na CLR está assim :

     

    public class Hash

        {

            [Microsoft.SqlServer.Server.SqlFunction

             (IsDeterministic = true,  

              DataAccess = DataAccessKind.None)]

            public static string GetHashNewPDF

            (

             [SqlFacet(MaxSize = -1)] SqlBytes ArqBin

            )

            {

                //// Return NULL if Algorithm or Plaintext is NULL

                if (ArqBin.IsNull)

                     return "";

                string sendCheckSum = string.Empty;

                var sha = new SHA1Managed();

                byte[] checksum = sha.ComputeHash(ArqBin.Value);

                //byte[] checksum = sha.ComputeHash(ArqBin.Stream);  //este fez o mesmo resultado acima.

                sendCheckSum = BitConverter.ToString(checksum).Replace("-", string.Empty);

                return sendCheckSum;

            }

        }

    No aplicativo que atualiza a tabela em C# esta assim :

                   

          var arqBin = File.ReadAllBytes(Arquivo.FullName);

          string sendCheckSum = string.Empty;

          var sha = new SHA1Managed();

          byte[] checksum = sha.ComputeHash(arqBin);

          sendCheckSum = BitConverter.ToString(checksum).Replace("-", string.Empty);

          String sSql = String.Format(

                                "UPDATE FolhasDocsContratos SET HashFolhaDocContrato = '{0}'  "

                            + "where IdFolhaDocContrato = {1} "

                        , sendCheckSum, Codigo

                    );

           //Após faço insert na tabela com as imagens     

          sSql = "INSERT INTO IMAGENCONTRATOS_03 (IdFolhaDocContrato,Imagem) VALUES(@ANEXO,@CONTEUDO)"; 

          cmdImg = new SqlCommand();

          cmdImg.CommandText = sSql;

          cmdImg.Connection = con;                   

          cmdImg.Parameters.Add("@ANEXO", SqlDbType.Int).Value = Codigo;

          cmdImg.Parameters.Add("@CONTEUDO", SqlDbType.VarBinary).Value = arqBin;

          cmdImg.ExecuteNonQuery();

          cmdImg.Dispose();                   

     

    segunda-feira, 26 de setembro de 2016 12:58
  • Ronald, fiz um teste com o teu segundo código C# e a função HASHBYTES do SQL Server para um arquivo de 1.843 bytes, eis os resultados:

    Hash C#: A153D04024DD329A89B7B4397325F3B88C4E9922

    Hash SQL Server: 0xA153D04024DD329A89B7B4397325F3B88C4E9922

    Lembrando que apenas um caractere a mais ou a menos produz um hash completamente diferente.

    Pode postar os resultados de um teste que você fez com um arquivo menor do que 8.000 caracteres?

    Verifique se a variável sendCheckSum(função C#, não CLR) condiz com o valor que é gravado no banco de dados.

    terça-feira, 27 de setembro de 2016 02:10
  • Bom dia André,

    Realmente arquivos pequenos sempre funciona, o problema é que aqui só utilizamos arquivos maiores que os 8000 bytes...Gostaria de saber como proceder nestes casos. Tem alguma ideia? 

    Obrigado!

    terça-feira, 27 de setembro de 2016 13:30
  • Ronald,

    Não seria o caso de passar diretamente este arquivo .pdf para ser inserido no SQL Server fazendo uso somente do Hash gerado pelo SQL?


    Pedro Antonio Galvao Junior [MVP | MCC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | Professor Universitario | SoroCodigos | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    quarta-feira, 28 de setembro de 2016 14:21
  • Bom dia Junior,

    Não sei se entendi. 

    É um sistema Web onde o usuário anexa o pdf via tela, ou seja, o arquivo obrigatoriamente passa pela camada de aplicação e vira um stream de bytes que inserimos na base. 

    Como faria isto diretamente pelo SQL Server? Sabe dizer?

    Abraço!


    quarta-feira, 28 de setembro de 2016 14:55
  • Ronald,

    Então, eu sei disso, foi justamente o que eu imaginei!!!

    Mas na verdade poderíamos tentar fazer da mesma forma que normalmente é inserido uma imagem no SQL Server, algo similar a este exemplo de código:

    CREATE TABLE Imagem
       (
           id INT IDENTITY PRIMARY KEY
         , nome VARCHAR(100) NOT NULL
         , tipoMIME VARCHAR(20) NOT NULL
         , imagem VARBINARY(MAX)
         )
          
    INSERT INTO Imagem VALUES ('Minha imagem','image/jpeg',
    (SELECT * FROM OPENROWSET(BULK 'E:\Imagem.jpg', SINGLE_BLOB) AS A))

    Outra coisa, você realmente precisa ter o arquivo gravado no banco?

    Já pensou em guardar o arquivo diretamente em file system e fazer uma referência neste tabela apontando para o local de armazenamento do arquivo?

    Além disso, se você estiver utilizando o SQL Server 2012 ou superior poderíamos pensar no conceito de file stream e file table.


    Pedro Antonio Galvao Junior [MVP | MCC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | Professor Universitario | SoroCodigos | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]


    quarta-feira, 28 de setembro de 2016 15:34