C++ e ODBC

A interface ODBC é primordial aos sistemas Windows, apesar de, nos sistemas UNIX/LINUX, já existirem gerenciadores livres de drivers ODBC. Vou aqui delinear os aspectos gerais relacionados com a utilização da interface em plataformas Windows.
O melhor IDE para desenvolver em Windows é o Visual Studio. Existe uma distribuição gratuita do VS, nomeadamente o Visual Studio Express Edition. No entanto, alguns cuidados devem ser tomados quando se pretende reutilizar o código em outras plataformas, uma vez que o compilador não segue o ISO C99 na íntegra.
Os passos a seguir numa ligação à base de dados ODBC são:

  • Conexão: para isso, é necessário inciar o administrador e criar um identificador com as informações associadas ao respectivo ambiente e outro associado ao próprio administrador. Assim se prepara o sistema para efectuar a ligação.
  • Inicialização: este passo varia com a aplicação mas consiste em determinar as capacidades do driver ao qual se conectou e criar um manipulador de comandos SQL, onde se podem iniciar alguns atributos relacionados com o comando tais como o tipo de cursor utilizado ou a existências de marcadores.
  • Construir e executar o comando: este passo varia de forma abrupta entre aplicações. No entanto, é nesta fase que são definidos os parâmetros a comunicar à base de dados.
  • Tratar os resultados: também varia de aplicação para aplicação a forma como os resultados retornados da base de dados são tratados.
  • Efectuar transacções: este passo só é necessário no caso de se pretender segurança integral dos dados.
  • Desconectar: desligar da base de dados e libertar os recursos requeridos pelos manipuladores.

As funções relativas ao ODBC recebem como argumento cadeias de caracteres (strings) da forma SQLWCHAR*, o qual correponde a um typedef de WCHAR*. A promoção estática ou dinâmica entre os dois tipos parece não funcionar convenientemente. Existem, contudo funções que permitem converter entre CHAR (que pode ser inicializado da forma vulgar) e WCHAR. No entanto, um pequeno ciclo pode resolver o problema.
O código que se segue ilustra basicamente os passos a tomar.

#include "stdafx.h"
#include <stdio.h>
// SQLConnect_ref.cpp
// compile with: odbc32.lib
#include <windows.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
#include <mbstring.h>
using namespace System;

int main() {
   SQLHENV henv;
   SQLHDBC hdbc;
   SQLHSTMT hstmt;
   SQLRETURN retcode;
   SQLPOINTER rgbValue;
   int i = 5;
   rgbValue = &i;

   SQLWCHAR sql_conn[SQL_MAX_DSN_LENGTH];
   unsigned char tmp[24] = "DSN_designation";
   //Probably it would be better to use mbstowcs_s
   for(int count = 0; count <24; count++){
       sql_conn[count] = tmp[count];
   }//Easy way to convert char to WCHAR that works

   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
      retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
         retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
            SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)(rgbValue), 0);

            retcode = SQLConnect(hdbc, sql_conn, SQL_NTS, NULL, 0, NULL, 0);

            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
               retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
                    unsigned char query[255] = "select * from company";
                    SQLWCHAR sql_query[255];
                    for(int count = 0; count <255; count++){
                        sql_query[count] = query[count];
                    }  //Easy way to convert
char to WCHAR and works
                    retcode = SQLExecDirect(hstmt,sql_query,SQL_NTS);
                    if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
                        SQLWCHAR sql_result[255];
                        SQLINTEGER sql_info;

//Process the information…
                        while((retcode = SQLFetch(hstmt)) == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
                            retcode = SQLGetData(hstmt,2,SQL_C_WCHAR,sql_result,255,&sql_info);
                            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
                                for(int count=0;count<sql_info && sql_result[count]!=0;count++){
                                    Console::Write(sql_result[count]);
                                }
                                Console::WriteLine();
                            }
                            else{
                                Console::WriteLine("Failed to read field");
                            }

                        }
                    }
                    else{
                        Console::WriteLine("Failed SQLExecDirect");
                    }
                    SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
               }
               else{
                   Console::WriteLine("Error");
               }

               SQLDisconnect(hdbc);
            }
            else{
                Console::WriteLine("Connection failed.");
            }

            SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
         }
         else{
             Console::WriteLine("Error, allocating connection handler.");
         }
      }
      else{
          Console::WriteLine("Error, setting environment attribute.");
      }
      SQLFreeHandle(SQL_HANDLE_ENV, henv);
   }
   else{
       Console::WriteLine("Error in handle allocation.");
   }
   Console::ReadLine();
}

As funções associadas a cada um dos passos estão decalcadas a azul. Este código permite listar o segundo campo da tabela company na consola. Utilizei um pequeno programa para consola para tirar partido da simplicidade relativa ao restante desenvolvimento, foncando apenas os aspectos essenciais à utilização do ODBC. Este código só foi testado com o Visual Studio 2008 Express Edition e não há qualquer garantias que funcione com outros compiladores.

Para mais detalhes ver a respectiva referência.

Sobre Sérgio O. Marques

Licenciado em Física/Matemática Aplicada (Astronomia) pela Faculdade de Ciências da Universidade do Porto e Mestre em Matemática Aplicada pela mesma instituição, desenvolvo trabalho no PTC (Porto Technical Centre) - Yazaki como Administrador de bases-de-dados. Dentro o meu leque de interesses encontram-se todos os temas afins às disciplinas de Matemática, Física e Astronomia. Porém, como entusiasta, interesso-me por temas relacionados com electrónica, poesia, música e fotografia.
Esta entrada foi publicada em Computadores e Internet. ligação permanente.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s