TN045: suporte a MFC/banco de dados para Long Varchar/Varbinary

Observação

A nota técnica a seguir não foi atualizada desde que foi incluída pela primeira vez na documentação online. Como resultado, alguns procedimentos e tópicos podem estar desatualizados ou incorretos. Para obter as informações mais recentes, é recomendável que você pesquise o tópico de interesse no índice de documentação online.

Esta nota descreve como recuperar e enviar os tipos de dados ODBC SQL_LONGVARCHAR e SQL_LONGVARBINARY usando as classes de banco de dados MFC.

Visão geral do Suporte Long Varchar/Varbinary

Os tipos de dados ODBC SQL_LONG_VARCHAR e SQL_LONGBINARY (conhecidos aqui por longas colunas de dados) podem conter grandes quantidades de dados. Existem três maneiras de lidar com esses dados:

  • Associe-o a um CString/CByteArray.

  • Associe-o a um CLongBinary.

  • Não associe e recupere e envie o valor de dados longos manualmente, independentemente das classes de banco de dados.

Cada um dos três métodos tem vantagens e desvantagens.

Não há suporte para colunas de dados longas para parâmetros para uma consulta. Eles só têm suporte para outputColumns.

Associar uma coluna de dados longos a um CString/CByteArray

Vantagens:

Essa abordagem é simples de entender e você trabalha com classes familiares. A estrutura fornece suporte CFormView para CString com DDX_Text. Você tem muitas funcionalidades gerais de cadeia de caracteres ou coleção com as classes CString e CByteArray e pode controlar a quantidade de memória alocada localmente para manter o valor dos dados. A estrutura mantém uma cópia antiga de dados de campo durante chamadas de função Edit ou AddNew. Ela pode detectar automaticamente as alterações nos dados para você.

Observação

Como CString foi projetado para trabalhar em dados de caractere e CByteArray para trabalhar em dados binários, é recomendável colocar os dados de caractere (SQL_LONGVARCHAR) em CString, e os dados binários (SQL_LONGVARBINARY) em CByteArray.

As funções RFX para CStringe CByteArray têm um argumento adicional que permite substituir o tamanho padrão da memória alocada para manter o valor recuperado para a coluna de dados. Observe o argumento nMaxLength nas seguintes declarações de função:

void AFXAPI RFX_Text(CFieldExchange* pFX,
    const char *szName,
    CString& value,
    int nMaxLength = 255,
    int nColumnType =
    SQL_VARCHAR);

void AFXAPI RFX_Binary(CFieldExchange* pFX,
    const char *szName,
    CByteArray& value,
    int nMaxLength = 255);

Se você recuperar uma coluna de dados longa em um CString ou CByteArray, a quantidade máxima retornada de dados será, por padrão, 255 bytes. Qualquer coisa além disso é ignorada. Nesse caso, a estrutura lançará o AFX_SQL_ERROR_DATA_TRUNCATED de exceção. Felizmente, você pode aumentar explicitamente o nMaxLength para valores maiores, até MAXINT.

Observação

O valor de nMaxLength é usado pelo MFC para definir o buffer local da função SQLBindColumn. Esse é o buffer local para armazenamento dos dados e não afeta realmente a quantidade de dados retornados pelo driver ODBC. RFX_Text e RFX_Binary fazem apenas uma chamada usando SQLFetch para recuperar os dados do banco de dados de back-end. Cada driver ODBC tem uma limitação diferente na quantidade de dados que pode retornar em uma única busca. Esse limite pode ser muito menor do que o valor definido em nMaxLength, nesse caso, a exceção AFX_SQL_ERROR_DATA_TRUNCATED será gerada. Nessas circunstâncias, alterne para usar RFX_LongBinary em vez de RFX_Text ou RFX_Binary para que todos os dados possam ser recuperados.

O ClassWizard associará um SQL_LONGVARCHAR a um CStringou um SQL_LONGVARBINARY a um CByteArray para você. Se você quiser alocar mais de 255 bytes nos quais recupera sua coluna de dados longa, poderá fornecer um valor explícito para nMaxLength.

Quando uma coluna de dados longa está associada a um CString ou CByteArray, a atualização do campo funciona da mesma forma que quando está associada a um SQL_VARCHAR ou SQL_VARBINARY. Durante Edit, o valor dos dados é armazenado em cache e posteriormente comparado quando Update é chamado para detectar alterações no valor de dados e definir os valores Dirty e Null para a coluna adequadamente.

Associar uma coluna de dados longos a um CLongBinary

Se sua coluna de dados longa pode conter mais bytes MAXINT de dados, você provavelmente deve considerar recuperá-los em um CLongBinary.

Vantagens:

Isso recupera uma coluna de dados longa inteira, até a memória disponível.

As desvantagens:

Os dados são mantidos na memória. Essa abordagem também é proibitivamente cara para grandes quantidades de dados. Você deve chamar SetFieldDirty para o membro de dados associado para garantir que o campo esteja incluído em uma operação Update.

Se você recuperar colunas de dados longas em uma CLongBinary, as classes de banco de dados verificarão o tamanho total da coluna de dados longa e alocarão um segmento de memória HGLOBAL grande o suficiente para mantê-lo no valor de dados inteiro. Em seguida, as classes de banco de dados recuperam todo o valor de dados no alocado HGLOBAL.

Se a fonte de dados não puder retornar o tamanho esperado da coluna de dados longa, a estrutura gerará a exceção AFX_SQL_ERROR_SQL_NO_TOTAL. Se a tentativa de alocar a falha HGLOBAL, uma exceção de memória padrão será gerada.

O ClassWizard associará um SQL_LONGVARCHAR ou SQL_LONGVARBINARY a um CLongBinary para você. Selecione CLongBinary como o Tipo de Variável na caixa de diálogo Adicionar Variável de Membro. O ClassWizard adicionará uma chamada RFX_LongBinary à sua chamada DoFieldExchange e incrementará o número total de campos associados.

Para atualizar valores de coluna de dados longos, primeiro verifique se o alocado HGLOBAL é grande o suficiente para manter seus novos dados chamando ::GlobalSize no membro m_hData do CLongBinary. Se for muito pequeno, solte o HGLOBAL e aloque um do tamanho apropriado. Em seguida, defina m_dwDataLength para refletir o novo tamanho.

Caso contrário, se m_dwDataLength for maior que o tamanho dos dados que você está substituindo, você poderá liberar e realocar os HGLOBAL ou deixá-los alocados. Certifique-se de indicar o número de bytes realmente usados em m_dwDataLength.

Como a atualização de um CLongBinary funciona

Não é necessário entender como a atualização de um CLongBinary funciona, mas pode ser útil como exemplo sobre como enviar valores de dados longos para uma fonte de dados, se você escolher este terceiro método, descrito abaixo.

Observação

Para que um campo CLongBinary seja incluído em uma atualização, você deve chamar explicitamente SetFieldDirty para o campo. Se você fizer qualquer alteração em um campo, incluindo defini-lo nulo, você deverá chamar SetFieldDirty. Você também deve chamar SetFieldNull, com o segundo parâmetro sendo FALSE, para marcar o campo como tendo um valor.

Ao atualizar um campo CLongBinary, as classes de banco de dados usam o mecanismo DATA_AT_EXEC do ODBC (consulte a documentação do ODBC sobre o argumento rgbValue do SQLSetPos). Quando a estrutura prepara a instrução de inserção ou atualização, em vez de apontar para os dados HGLOBAL que contêm, o endereço do CLongBinary é definido como o valor da coluna e o indicador de comprimento definido como SQL_DATA_AT_EXEC. Posteriormente, quando a instrução de atualização for enviada à fonte de dados, SQLExecDirect retornará SQL_NEED_DATA. Isso alerta a estrutura de que o valor do param para esta coluna é, na verdade, o endereço de um CLongBinary. A estrutura chama SQLGetData uma vez com um buffer pequeno, esperando que o driver retorne o comprimento real dos dados. Se o driver retornar o comprimento real do objeto binário grande (o BLOB), o MFC realoca o espaço necessário para buscar o BLOB. Se a fonte de dados retornar SQL_NO_TOTAL, indicando que não pode determinar o tamanho do BLOB, o MFC criará blocos menores. O tamanho inicial padrão é 64k e os blocos subsequentes serão o dobro do tamanho; por exemplo, o segundo será 128k, o terceiro é 256k e assim por diante. O tamanho inicial é configurável.

Não associação: recuperando/enviando dados diretamente do ODBC com SQLGetData

Com esse método, você ignora completamente as classes de banco de dados e lida com a coluna de dados longa por conta própria.

Vantagens:

Você pode armazenar dados em cache no disco, se necessário, ou decidir dinamicamente quantos dados recuperar.

As desvantagens:

Você não obtém o suporte ou Edit a AddNew da estrutura e deve escrever o código por conta própria para executar a funcionalidade básica (Delete funciona, porém, já que não é uma operação de nível de coluna).

Nesse caso, a coluna de dados longa deve estar na lista de seleção do conjunto de registros, mas não deve ser associada pela estrutura. Uma maneira de fazer isso é fornecer sua própria instrução SQL por meio GetDefaultSQL ou como o argumento lpszSQL à CRecordsetfunção 's Open e não associar a coluna extra a uma chamada de função RFX_. O ODBC exige que campos não associados apareçam à direita dos campos associados, portanto, adicione sua coluna ou colunas não associadas ao final da lista de seleção.

Observação

Como sua coluna de dados longa não está associada à estrutura, as alterações nela não serão tratadas com chamadas CRecordset::Update. Você deve criar e enviar as instruções SQL INSERT e UPDATE necessárias por conta própria.

Confira também

Observações técnicas por número
Observações técnicas por categoria