Pular para o conteúdo

Recuperando dados deletados do SQL Server sem Backup Full – Parte 5

Este post é parte 5 de 6 na série Recuperando dados deletados sem Backup Full

Recuperando dados deletados sem Backup Full

Recuperando dados deletados do SQL Server sem Backup Full – Parte 1

Recuperando dados deletados do SQL Server sem Backup Full – Parte 2

Recuperando dados deletados do SQL Server sem Backup Full – Parte 2

Recuperando dados deletados do SQL Server sem Backup Full – Parte 3

Recuperando dados deletados do SQL Server sem Backup Full – Parte 4

Recuperando dados deletados do SQL Server sem Backup Full – Parte 5

Recuperando dados deletados do SQL Server sem Backup Full – Parte 6

Tempo de Leitura: 4 minutos

Olá! Hoje, dando continuidade a nossa série, vou responder a pergunta do último post: E se nos dados que estou recuperando tinham valores NULL?

E a resposta é muito simples: Isso está junto no meio desse binário todo! Como você estudou sobre a anatomia de um registro , com os vários links que eu coloquei nos posts anteriores (né?), então aprendeu que existe um negócio chamado NULL bitmap. Basicamente é uma sequencia de bytes que indicam quais colunas tem o valor nulo ou não. Recorra aos links que coloquei anteriormente para entender com mais detalhes sobre ele.

Sabendo isso, tudo que precisamos é identificar o NULL bitmap no meio desse binário todo, de cada registro, e checar se a coluna está nula ou não. Identificar o NULL bitmap envolve, além de conhecer a anatomia do registro, um pouco de mágica matemática:

Este trecho envolve basicamente achar alguns metadados que existem no registro (Veja o Post do Paul Randal) para encontrar o resto das informações. Primeiro, eu preciso encontrar os bytes que indicam a quantidade de colunas, por dois motivos:

  1. Achando a posição deles eu sei onde começa o NULL bitmap
  2. O tamanho do NULL bitmap, isto é, quantidade de bytes que formam ele, depende da quantidade de colunas
    A cada 8 colunas, ele precisa de um byte adicional. Por exemplo, uma tabela com 8 colunas, precisa de um NULL bitmap com 1 byte (8 bits, 1 pra cada coluna). Já com 10 colunas, ele vai gastar 2 bytes (16 bits, sendo apenas 10 usados). Com 16 colunas, continuamos com os 2 bytes (agora usando todos os 16 bits) e por aí vai…
[stextbox id=’info’ caption=’Mas pera aí Rodrigo ✋’]Se toda linha sempre tem a mesma quantidade de colunas, porque o SQL Server armazena esse dado para cada linha?

Pois é… corre elá nas fontes sobre a anatomia do registro e você entender os porquês disso…[/stextbox]

Por essas razões, eu precisei gerar a coluna chamada ColCount, que me indica a quantidade de colunas. Ela começa no byte 27 porque a última coluna de tipo fixo é a DataCadastro, que começa no byte 19 e usa 8 bytes… Os bytes dela são do 19 ao 26… A quantidade de colunas sempre gasta 2 bytes (Neste caso, bytes 27 e 28).

Na subquery acima, a coluna NullBmp contém todo o NULL bitmap! Novamente, estou usando a função SUBSTRING com a coluna Registro ([RowLog Contents 0] de fn_dump_dblog) para extrair os bytes que compõe o NULL bitmap. Neste caso, o NULL bitmap começa no byte 29. E Pronto (como tenho 7 colunas, preciso de apenas 1 byte)! Agora que tenho o NULL bitmap completo, é so checar cada bit dele para saber se a respectiva coluna é nulo ou não:

  • O primeiro bit (o bit 0), indica se a primeira coluna é ou não nula (neste caso sempre vai ser zero, pois é a coluna Id, que é chave primária)
  • O bit 1 controla a da segunda
  • O bit 2 da coluna 3 e por aí vai.
Demonstração do NULL bitmap
No exemplo, o null bitmap possui o valor hexadecimal 48, e convertendo pra binário é 0100 1000. Começando do bit mais a direita, conseguimos mapear o NULL de cada coluna!

 

De posse do NULL bitmap, testar o valor de um binário no SQL Server, em uma posição específica, requer apenas um pouquinho de matemática (e talvez uma pesquisa no stack overflow):

Utilizando mais um pouco de matemática eu consigo testar cada bit do NULL bitmap e montar uma lista de colunas indicando qual se a respectiva coluna era NULL ou não

A lógica é: eu crio uma coluna para cada uma das colunas das tabelas. Basicamente o valor dessa coluna é o valor do bit respectivo no NULL bitmap: 1 indica que é NULL, 0 é o contrário. Eu resolvi colocar numa lista separada para que a expressão no SELECT principal não ficasse monstruosa. Então, lá no SELECT final, eu apenas faço uma condição mais simples: Se o valor da respectiva coluna for 1, então significa que ela é NULL, então retorno o valor NULL. Caso contrário, retorna o valor resultante daquela expressão que extrai o valor original:

Para as colunas que são NOT NULL, eu nem me dou o trabalho de fazer essa verificação, pois o bit sempre será 0, como, por exemplo, é o caso da coluna Id.

Com o NULL bitmap, além de determinar quais colunas tem o valor NULL, você consegue identificar onde iniciam as colunas de tipos variáveis. E no próximo, e último post, vamos entender como lidamos com essas colunas, que, na minha opinião, são as mais chatas de recuperar!

Até lá!

Recuperando dados deletados sem Backup Full

Recuperando dados deletados do SQL Server sem Backup Full – Parte 4 Recuperando dados deletados do SQL Server sem Backup Full – Parte 6
Compartilhe este post!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *