A solução ODBC
A questão é: como o ODBC padroniza o acesso ao banco de dados? Há dois requisitos arquitetônicos:
Os aplicativos devem ser capazes de acessar vários DBMSs usando o mesmo código-fonte sem recompilar ou vincular novamente.
Os aplicativos devem ser capazes de acessar vários DBMSs simultaneamente.
Há mais uma questão, devido à realidade do mercado:
- Que recursos do DBMS o ODBC deve expor? Apenas recursos comuns a todos os DBMSs ou algum recurso disponível em qualquer DBMS?
O ODBC resolve esses problemas da seguinte maneira:
O ODBC é uma interface de nível de chamada. Para resolver o problema de como os aplicativos acessam vários DBMSs usando o mesmo código-fonte, o ODBC define uma CLI padrão. Ela contém todas as funções nas especificações de CLI do Open Group e ISO/IEC e fornece funções adicionais comumente exigidas pelos aplicativos.
Uma biblioteca ou um driver diferente são necessários para cada DBMS que dá suporte ao ODBC. O driver implementa as funções na API ODBC. Para usar um driver diferente, o aplicativo não precisa ser recompilado ou vinculado novamente. Em vez disso, o aplicativo simplesmente carrega o novo driver e chama as funções contidas nele. Para acessar vários DBMSs simultaneamente, o aplicativo carrega vários drivers. A maneira como os drivers têm suporte depende do sistema operacional. Por exemplo, no sistema operacional Microsoft Windows, os drivers são DLLs (bibliotecas de vínculo dinâmico).
O ODBC define uma gramática SQL padrão. Além de uma interface padrão em nível de chamada, o ODBC define uma gramática SQL padrão. Essa gramática se baseia na especificação Open Group SQL CAE. As diferenças entre as duas gramáticas são pequenas e, principalmente, devido às diferenças entre a gramática SQL exigida pelo SQL incorporado (Open Group) e uma CLI (ODBC). Há também algumas extensões à gramática para expor recursos de linguagem comumente disponíveis não abrangidos pela gramática do Open Group.
Os aplicativos podem enviar instruções usando a gramática do ODBC ou a gramática específica do DBMS. Se uma instrução usar uma gramática ODBC diferente da gramática específica do DBMS, o driver a converterá antes de enviá-la à fonte de dados. No entanto, essas conversões são raras, pois a maioria dos DBMSs já usa gramática SQL padrão.
O ODBC fornece um Gerenciador de Driver para gerenciar o acesso simultâneo a vários DBMSs. Embora o uso de drivers resolva o problema de acesso simultâneo a vários DBMSs, o código para isso pode ser complexo. Os aplicativos projetados para funcionar com todos os drivers não podem ser vinculados estaticamente a nenhum driver. Em vez disso, devem carregar drivers em tempo de execução e chamar as funções contidas neles por meio de uma tabela de ponteiros de função. A situação é mais complexa se o aplicativo usa vários drivers simultaneamente.
Em vez de forçar cada aplicativo a fazer isso, o ODBC fornece um Gerenciador de Driver. O Gerenciador de Driver implementa todas as funções ODBC, principalmente como chamadas de passagem para funções ODBC em drivers, e é vinculado estaticamente ao aplicativo ou carregado pelo aplicativo em tempo de execução. Assim, o aplicativo chama funções ODBC por nome no Gerenciador de Driver e não pelo ponteiro em cada driver.
Quando um aplicativo precisa de um driver específico, primeiro solicita um identificador de conexão para identificar o driver e solicita que o Gerenciador de Driver carregue o driver. O Gerenciador de Driver carrega o driver e armazena o endereço de cada função no driver. Para chamar uma função ODBC no driver, o aplicativo chama essa função no Gerenciador de Driver e passa o identificador de conexão para o driver. O Gerenciador de Driver então chama a função usando o endereço armazenado anteriormente.
O ODBC expõe um número significativo de recursos do DBMS, mas não requer drivers para dar suporte a todos eles. Se o ODBC expusesse apenas recursos comuns a todos os DBMSs, seria de pouca utilidade; a razão pela qual há tantos DBMSs diferentes hoje é que eles têm recursos diferentes. Se o ODBC expusesse todos os recursos disponíveis em qualquer DBMS, seria impossível a implementação dos drivers.
Em vez disso, o ODBC expõe um número significativo de recursos, mais do que o número ao qual a maioria dos DBMSs dá suporte, mas exige que os drivers implementem apenas um subconjunto desses recursos. Os drivers implementarão os recursos restantes somente se tiverem suporte no DBMS subjacente ou se optarem por emulá-los. Assim, os aplicativos podem ser escritos para explorar os recursos de um único DBMS conforme exposto pelo driver desse DBMS, a fim de usar apenas os recursos usados por todos os DBMSs ou verificar o suporte de um recurso específico e reagir de acordo.
Para que um aplicativo possa determinar a quais recursos um driver e o DBMS dão suporte, o ODBC fornece duas funções (SQLGetInfo e SQLGetFunctions), que retornam informações gerais sobre os recursos do driver e do DBMS e uma lista de funções às quais o driver dá suporte. O ODBC também define níveis de conformidade de API e gramática SQL, que especificam amplas gamas de recursos com suporte pelo driver. Para obter mais informações, consulte Níveis de conformidade.
É importante lembrar que o ODBC define uma interface comum para todos os recursos que expõe. Devido a isso, os aplicativos contêm código específico do recurso, não código específico do DBMS, e podem usar qualquer driver que exponha esses recursos. Uma vantagem disso é que os aplicativos não precisam ser atualizados quando os recursos com suporte por um DBMS são aprimorados; em vez disso, quando um driver atualizado é instalado, o aplicativo usa automaticamente os recursos, pois seu código é específico do recurso e não específico do driver ou do DBMS.