Um bug no SSMS ao exibir Linked Servers?

Olá, caro leitor!

Após um breve período de descanso, estou retornando ao blog e espero que esse ano possa estar mais ativo, trazendo mais conteúdo!

Resolvi começar por uma situação que ocorreu há pouco tempo e apesar de não ser algo crítico, achei bastante interessante!

Linked Server! Este é o nome de um recurso muito interessante no SQL Server que permite acessar diversas fontes de dados OLE DB a partir de uma instância SQL. Muito útil para acessar outras instâncias SQL,  arquivos excel, Active Directory, etc. Assim como a maioria das coisas no SQL Server, os Linked Servers podem ser criados de, no mínimo, duas maneiras:

  1. Via código T-SQL usando a procedure de sistema sp_addlinkedserver
  2. Via SQL Server Management Studio (interface gráfica), clicando com o botão direito em “Server Objects > Linked Servers”, e escolhendo a opção “New Linked Server”

Na maior parte do tempo eu uso a interface gráfica, por comodidade. Uso muito a interface gráfica sim (pois sou adepto da praticidade e usabilidade), e uso inclusve para checar as propriedades de algum linked server, quando preciso.  Ao clicar em propriedades é possível ver uma tela semelhante a esta:

image

 

Este linked server foi criado no SQL SERVER 2016 CTP 3.3 e aponta para a própria instância onde foi criada. Note que os campos que mostram as propriedades do Linked Server não nos revelam isto. Apenas o nome do provider OLE DB é mostrado: Microsoft OLE DB Provider for SQL Server. Bom isto é comportamento muito estranho, já que estas propriedades existem e algumas estão com valores. Isto é o que mostra a DMV “sys.servers” desta instância:

 

image

A coluna “data_source” contém o valor “localhost\sql16” e este valor não é exibido na interface. Para comprovar que a interface exibe adequadamente estes valores, eu criei um segundo Linked Server, com uma pequena diferença que irei mostrar mais adiante. Segue o script:

 

E eis a tela:

image

 

Note que desta vez, as informações são exbidas adequadamente. Óbvio que por razões de simplicidade, eu apenas estou considerando a informação “Data Source”, mas o que estou mostrando aqui é válido para todas as outras.

Bom, mas por que será que, na primeira imagem, estas informações não aparecem? A resposta está no provider. Repare que na primeira imagem, o provider é o “Microsoft OLE DB Provider for SQL Server”. Na segunda, o provider é o “SQL Server Native Client 11.0”. Providers OLE DB (e ODBC) são coisas que durante um bom tempo eram um bicho de sete cabeças sentado sob trono do rei Daburá, cantando “Tá Tranquilo, Tá favorável”. Eu tinha pavor só de ouvir falar… Mas em suma, providers são apenas DLLs chamadas pela engine do OLE DB. São essas DLLs quem, de fato, se conectam com a fonte de dados, obtém os dados, e os apresenta de um forma padronizada para o OLE DB. Isso permite que uma aplicação possa facilmente mudar a fonte de dados sem mexer no código, e isso é incrivelmente demais.

Os providers possuem uma espécie de identificação que é globalmente única! Essa identificação é nada mais do que um GUID. Há também um identificador mais amigável, chamado “ProgID”.  É esse identificador que usamos ao criar o linked server. No código acima, o ProgID que usei foi “SQLNCLI11”. Você pode ver a lista de ProgIDs usando a procedure “sp_enum_oledb_providers” ou no SSMS, caminho “Server Objects > Linked Servers > Providers”.

Tá, mas o que isso tem a ver!? Calma lá…. Te prometo que tudo irá fazer sentido já já.  A procedure “sp_addlinkedserver” aceita um “ProgID” especial. Na verdade, não é nem um “ProgID” existente (ele não é retornado pela procedure “sp_enum_oledb_providers”, e muito menos é exibido no direótrio “Providers” do SSMS). Este ProgID especial é o “SQLNCLI”. A documentação de “sp_addlinkedserver” destaca o seguinte, para o parâmetro @provider:

[ @provider = ] provider_name

Is the unique programmatic identifier (PROGID) of the OLE DB provider that corresponds to this data source. provider_name must be unique for the specified OLE DB provider installed on the current computer. provider_name is nvarchar(128), with a default of NULL; however, ifprovider_name is omitted, SQLNCLI is used. (Use SQLNCLI and SQL Server will redirect to the latest version of SQL Server Native Client OLE DB Provider.) The OLE DB provider is expected to be registered with the specified PROGID in the registry.

 

O ProgID SQLNCLI é o padrão e é usado sempre que o valor do parâmetro @provider é omitido. Porém, por debaixo dos panos, o que o SQL Server faz quando o linked server é executado, é selecionar a versão mais recente do Native Client disponível, o que é ótimo. Porém, o SSMS parece não entender muito bem esta regra.  Aqui está o “provider_name” de cada um dos linked servers criados anteriormente:

image

 

No Linked Server “THE_SQL_TIMES”, o que não exibe as informações corretamente no SSMS, o provider é justamente o SQLNCLI. No segundo, o provider é o “SQLNCLI11”. E eu ainda criei um terceiro, cujo o provider é fornecido pelo pacote Microsoft Data Access Components (ProgID = MSDASQL):

 

 

image

 

E, lá está o valor da propriedade! O que parece acontecer é que a interface se atrapalha quando vai exibir os dados e o provider é o “SQLNCLI”. Eu ativei um trace ao usar a interface e percebi que a interface faz as seguintes ações (um resumo):

  1. Obtém as informaçoes do Linked Server, lendo os dados da sys.servers
  2. Executa a procedure “sp_enum_oledb_providers”

Ao que tudo indica, ao perceber que o provider retornado no passo 1 não exite na lista retornado no passo 2, algo acontece e a interface simplesmente não exibe as informações! A solução é fácil, e conforme já mostrei anteriormente, basta criar o linked server com o ProgID SQLNCLIXX, onde XX é a versão correspondente instalada no servidor onde a instância está. Claro, isto se você deseja usar o Native Client como provider.

Extendendo a brincadeira

Bom, para deixar as coisas com mais um pouco de graça, relembre a tela em que as informações não são exibidas:

image

Eu ainda não estava convencido do porquê o texto “Microsoft OLE DB Provider for SQL Server” era exibido no campo “Provider:”. Bom, para descobrir o ProgID associado com este nome, você pode pensar: “Olhe na sys.servers”. Mas, conforme mostrei anteriorment,e a “sys.servers” nos mostra que o provider é o SQLNCLI… E sabemos que como o SQLNCLI, o nome exibido é “SQL Server Native Client ” + a versão.  A procedure “sp_enum_oledb_providers” nos revela qual é o ProgID:

image

 

Perceba que no resultado, a coluna “Provider Description” fornece o valor que visualizamos na descrição. O valor corresponde ao ProgID (que está na coluna “Provider Name”) é “SQLOLEDB”, que é uma implementação depreciada fornecida pelo pacote Microsoft Data Access Components (MDAC). Bom, a minha suspeita era de que a interface iria exibir o primeiro da lista… E a minha única forma de comprovar isto foi deletando o provider pelo registro, coisa que, eu fiz na minha máquina de trabalho e vou repetir de novo em minha máquina pessoal, e nem preciso mencionar que você não precisa fazer isso em sua honrada produção, homologação e desenvolvimento, ok? Os passos são os seguintes, e você pode fazer por sua própria conta e risco:

    1. Abra o regedit.exe
    2. Clique na seguinte chave: HKEY_CLASSES_ROOT\CLSID
      Aqui contém aqueles identificadores globais das interfaces do COM. Os providers OLE DB são interfaces do COM, e como você é uma pessoa esperta, já entendeu o que vai fazer né!?
    3. Pegue o valor da coluna “Parse Name” e use o FIND (F3 ou vá pelo menu Editar) do regedit para procurá-lo.
    4. Faça um backup, usando o comando de exportar (File -> Export)
    5. Utilize sua religião, faça suas preces, e delete a chave inteira. Você vai precisar alterar o owner da chave e reaplicar as permissões para todas sub-chaves. Aqui segue um exemplo da chave que irei deletar:

image

 

Bom, após deletar a chave, a “sp_enum_oledb_providers” passou a retornar o seguinte:

image

E voilà:

image

O Provider mudou… Mas, este infeliz autor, ainda não estava satisfeito e resolveu fazer a mesma coisa com o SQLNCLI11. E a “sp_enum_oledb_providers” retornou após eu repetir as etapas acimas para o SQLNCLI11:

image

E a tela:

image

 

Sim! As suspeitas se confirmaram! Agora eu estava convencido! O SSMS parece usar o primeiro provider da lista. E por algum motivo, o que me parece ser uma espécie de “bug” do SSMS, ele não exibe as informações do Linked Server!

Bom, isto não é um problema que vá parar seu ambiente ou impedir que você use o Linked Server e talvez, por esse motivo, nunca recebeu uma atenção, e provavelmente nunca irá receber. Mas, para aqueles que são curiosos e gostam de se aventurar nos porquês das coisas, está aí a resposta, caso um dia você tenha esta curiosidade!

 

Fontes  e Referências:

 

Ops, e antes de ir, não perca o primeiro SQL Saturday do Ano, no Brasil, em JoinVille! É o SQL Saturday #488. Você pode se inscrever e obter mais informações acessando o link: http://www.sqlsaturday.com/488/eventhome.aspx