Buscando dados de resultados
Um aplicativo ODBC tem três opções para buscar dados de resultados.
A primeira opção se baseia em SQLBindCol. Antes de buscar o conjunto de resultados, o aplicativo usa SQLBindCol para associar cada coluna no conjunto de resultados a uma variável de programa. Após a associação das colunas, o driver transfere os dados da linha atual para as variáveis associadas às colunas do conjunto de resultados sempre que o aplicativo chama SQLFetch ou SQLFetchScroll. O driver manipulará as conversões de dados se a coluna do conjunto de resultados e a variável de programa tiverem tipos de dados diferentes. Se o aplicativo tiver SQL_ATTR_ROW_ARRAY_SIZE definido como um valor maior do que 1, ele poderá associar as colunas de resultados a matrizes de variáveis, que serão todas preenchidas em cada chamada a SQLFetchScroll.
A segunda opção se baseia em SQLGetData. O aplicativo não usa SQLBindCol para associar as colunas do conjunto de resultados a variáveis de programa. Depois de cada chamada para SQLFetch, o aplicativo chama SQLGetData uma vez para cada coluna no conjunto de resultados. SQLGetData instrui o driver a transferir os dados de uma coluna de conjunto de resultados específica para uma variável de programa específica e determina os tipos de dados da coluna e da variável. Isso permitirá que o driver converta os dados se a coluna de resultados e a variável de programa tiverem tipos de dados diferentes. As colunas Text, ntext e image normalmente são grandes demais para se ajustar em uma variável de programa, mas ainda podem ser recuperadas usando SQLGetData. Se os dados de text, ntext ou image da coluna de resultados forem maiores do que a variável de programa, SQLGetData retornará SQL_SUCCESS_WITH_INFO e SQLSTATE 01004 (Dados de seqüência de caracteres truncados à direita). Chamadas sucessivas para SQLGetData retornarão partes sucessivas dos dados de text ou image. Quando o término dos dados for atingido, SQLGetData retornará SQL_SUCCESS. Cada busca retornará um conjunto de linhas se SQL_ATTR_ROW_ARRAY_SIZE for maior do que 1. Antes de SQLGetData, você precisa usar SQLSetPos para determinar uma linha específica do conjunto de linhas como a atual.
A terceira opção é usar uma combinação entre SQLBindCol e SQLGetData. Por exemplo, um aplicativo poderia associar as primeiras dez colunas de um conjunto de resultados e, em cada busca, chamar SQLGetData três vezes para recuperar os dados das três colunas não associadas. Isso normalmente é usado quando um conjunto de resultados contém uma ou mais colunas de text ou image.
Dependendo das opções de cursor definidas para o conjunto de resultados, um aplicativo também pode usar as opções de rolagem de SQLFetchScroll para rolar pelo conjunto de resultados.
O uso excessivo de SQLBindCol para associar uma coluna de conjunto de resultados a uma variável de programa custa caro porque SQLBindCol faz com que um driver ODBC aloque memória. Quando você associa uma coluna de resultados a uma variável, essa associação permanece ativa até você chamar SQLFreeHandle para liberar o identificador da instrução ou chamar SQLFreeStmt com fOption definido como SQL_UNBIND. As associações não são desfeitas automaticamente quando a instrução é concluída.
Essa lógica permite lidar efetivamente com a execução da mesma instrução SELECT várias vezes com parâmetros diferentes. Como o conjunto de resultados mantém a mesma estrutura, você pode associar uma vez o conjunto, processar todas as instruções SELECT e chamar SQLFreeStmt com fOption definido como SQL_UNBIND após a última execução. Você não deve chamar SQLBindCol para associar as colunas de um conjunto de resultados sem antes chamar SQLFreeStmt com fOption definido como SQL_UNBIND para liberar quaisquer associações anteriores.
Ao usar SQLBindCol, você pode fazer uma associação por linha ou por coluna. A associação por linha é um pouco mais rápida do que a associação por coluna.
Você pode usar SQLGetData para recuperar dados de cada coluna, em vez de associar colunas de conjunto de resultados que usam SQLBindCol. Se um conjunto de resultados contiver só algumas linhas, o uso de SQLGetData, em vez de SQLBindCol será mais rápido; caso contrário, SQLBindCol oferecerá o melhor desempenho. Se você nem sempre coloca os dados no mesmo conjunto de variáveis, deve usar SQLGetData, em vez de reassociar constantemente. Você só pode usar SQLGetData em colunas que estão na lista de seleção depois que todas as colunas estão associadas a SQLBindCol. A coluna também precisa aparecer depois de quaisquer colunas nas quais você já usou SQLGetData.
As funções ODBC que lidam com a transferência de dados com destino ou origem nas variáveis de programa, como SQLGetData, SQLBindCol e SQLBindParameter, suportam a conversão implícita de tipo de dados. Por exemplo, se um aplicativo associar uma coluna inteira a uma variável de programa de cadeia de caracteres, o driver converterá automaticamente os dados de inteiro em caractere antes de colocá-lo na variável de programa.
A conversão de dados em aplicativos deve ser minimizada. A menos que a conversão de dados seja necessária ao processamento executado pelo aplicativo, os aplicativos devem associar colunas e parâmetros a variáveis de programa do mesmo tipo de dados. Se for necessário converter os dados entre um tipo e outro, entretanto, será mais eficiente fazer com que o driver execute a conversão do que fazê-lo no aplicativo. O driver ODBC do SQL Server Native Client normalmente só transfere dados diretamente dos buffers de rede para as variáveis do aplicativo. A solicitação do driver para fazer a conversão dos dados obriga o driver a armazenar em buffer os dados e os ciclos de CPU de uso para convertê-los.
As variáveis de programa devem ser grandes o suficiente para reter os dados transferidos de uma coluna, com exceção dos dados de text, ntext e image. Se um aplicativo tentar recuperar os dados do conjunto de resultados e colocá-los em uma variável pequena demais para retê-los, o driver gerará um aviso. Isso obriga o driver a alocar memória para a mensagem, e o driver e o aplicativo têm de gastar ciclos de CPU processando a mensagem e manipulando o erro. O aplicativo deve alocar uma variável grande o suficiente para reter os dados que estão sendo recuperados ou usar a função SUBSTRING na lista de seleção para reduzir o tamanho da coluna no conjunto de resultados.
É necessário ter cuidado ao usar SQL_C_DEFAULT para especificar o tipo da variável C. SQL_C_DEFAULT especifica que o tipo da variável C corresponde ao tipo de dados SQL da coluna ou parâmetro. Se SQL_C_DEFAULT for especificado para um ntext, nchar ou coluna nvarchar, dados Unicode serão retornados para o aplicativo. Isso poderá causar vários problemas se o aplicativo não foi codificado para manipular dados Unicode. Os mesmos tipos de problemas podem ocorrer com o tipo de dados uniqueidentifier (SQL_GUID).
Os dados de text, ntext e image normalmente são grandes demais para se ajustar a uma única variável de programa e normalmente são processados com SQLGetData, em vez de SQLBindCol. Ao usar cursores de servidor, o driver ODBC do SQL Server Native Client é otimizado para não transmitir os dados para as colunas não associadas de text, ntext ou image no momento da busca da linha. Os dados de text, ntext ou image não são recuperados de verdade do servidor enquanto o aplicativo não emite SQLGetData para a coluna.
Essa otimização pode ser empregada em aplicativos para que nenhum dado de text, ntext ou image seja exibido enquanto um usuário está rolando um cursor para cima e para baixo. Depois que o usuário selecionar uma linha, o aplicativo poderá chamar SQLGetData para recuperar os dados de text, ntext ou image. Esse procedimento salva a transmissão de dados de text, ntext ou image para qualquer uma das linhas que o usuário não seleciona e pode salvar a transmissão de quantidades muito grandes de dados.