Compartilhar via


Obter dados Long

Os DBMSs definem dados longos como qualquer caractere ou dados binários em um determinado tamanho, como 255 caracteres. Esses dados podem ser pequenos o suficiente para serem armazenados em um único buffer, como uma descrição de parte de vários milhares de caracteres. No entanto, pode ser muito longo para armazenar na memória, como documentos de texto longos ou bitmaps. Como esses dados não podem ser armazenados em um único buffer, eles são recuperados do driver em partes com SQLGetData depois que os outros dados na linha são buscados.

Observação

Um aplicativo pode realmente recuperar qualquer tipo de dados com SQLGetData, não apenas dados longos, embora apenas dados binários e caracteres possam ser recuperados em partes. No entanto, se os dados forem pequenos o suficiente para caber em um único buffer, geralmente não há motivo para usar SQLGetData. É muito mais fácil associar um buffer à coluna e permitir que o driver retorne os dados no buffer.

Para recuperar dados longos de uma coluna, um aplicativo primeiro chama SQLFetchScroll ou SQLFetch para mover para uma linha e buscar os dados para colunas associadas. Em seguida, o aplicativo chama SQLGetData. SQLGetData tem os mesmos argumentos que SQLBindCol: um identificador de instrução; um número de coluna; o tipo de dados C, o endereço e o comprimento de bytes de uma variável de aplicativo; e o endereço de um buffer de comprimento/indicador. Ambas as funções têm os mesmos argumentos porque executam essencialmente a mesma tarefa: ambas descrevem uma variável de aplicativo para o driver e especificam que os dados de uma determinada coluna devem ser retornados nessa variável. As principais diferenças são que SQLGetData é chamado depois que uma linha é buscada (e às vezes é conhecida como associação tardia por esse motivo) e que a associação especificada por SQLGetData dura apenas durante a chamada.

Em relação a uma única coluna, SQLGetData se comporta como SQLFetch: recupera os dados da coluna, converte-os no tipo da variável de aplicativo e retorna-os nessa variável. Ele também retorna o tamanho em bytes dos dados no buffer de comprimento/indicador. Para obter mais informações sobre como o SQLFetch retorna dados, consulte Fetching a Row of Data.

SQLGetData difere do SQLFetch em um aspecto importante. Se for chamado mais de uma vez consecutiva para a mesma coluna, cada chamada retornará uma parte sucessiva dos dados. Cada chamada, exceto a última, retorna SQL_SUCCESS_WITH_INFO e SQLSTATE 01004 (dados de string, truncados à direita); a última chamada retorna SQL_SUCCESS. É assim que o SQLGetData é usado para recuperar dados longos em partes. Quando não há mais dados a serem retornados, o SQLGetData retorna SQL_NO_DATA. O aplicativo é responsável por juntar os dados longos, o que pode significar concatenar as partes dos dados. Cada parte é terminada em nulo; o aplicativo deve remover o caractere de terminação nula se concatenar as partes. A recuperação de dados em partes pode ser feita para marcadores de comprimento variável, assim como para outros dados extensos. O valor retornado no buffer de comprimento/indicador diminui em cada chamada pelo número de bytes retornados na chamada anterior, embora seja comum que o driver não consiga descobrir a quantidade de dados disponíveis e retornar um comprimento de byte de SQL_NO_TOTAL. Por exemplo:

// Declare a binary buffer to retrieve 5000 bytes of data at a time.  
SQLCHAR       BinaryPtr[5000];  
SQLUINTEGER   PartID;  
SQLINTEGER    PartIDInd, BinaryLenOrInd, NumBytes;  
SQLRETURN     rc;   
SQLHSTMT      hstmt;  
  
// Create a result set containing the ID and picture of each part.  
SQLExecDirect(hstmt, "SELECT PartID, Picture FROM Pictures", SQL_NTS);  
  
// Bind PartID to the PartID column.  
SQLBindCol(hstmt, 1, SQL_C_ULONG, &PartID, 0, &PartIDInd);  
  
// Retrieve and display each row of data.  
while ((rc = SQLFetch(hstmt)) != SQL_NO_DATA) {  
   // Display the part ID and initialize the picture.  
   DisplayID(PartID, PartIDInd);  
   InitPicture();  
  
   // Retrieve the picture data in parts. Send each part and the number   
   // of bytes in each part to a function that displays it. The number   
   // of bytes is always 5000 if there were more than 5000 bytes   
   // available to return (cbBinaryBuffer > 5000). Code to check if   
   // rc equals SQL_ERROR or SQL_SUCCESS_WITH_INFO not shown.  
   while ((rc = SQLGetData(hstmt, 2, SQL_C_BINARY, BinaryPtr, sizeof(BinaryPtr),  
                           &BinaryLenOrInd)) != SQL_NO_DATA) {  
      NumBytes = (BinaryLenOrInd > 5000) || (BinaryLenOrInd == SQL_NO_TOTAL) ?  
                  5000 : BinaryLenOrInd;  
      DisplayNextPictPart(BinaryPtr, NumBytes);  
   }  
}  
  
// Close the cursor.  
SQLCloseCursor(hstmt);  

Há várias restrições ao uso do SQLGetData. Em geral, as colunas acessadas com SQLGetData:

  • Deve ser acessado em ordem crescente do número das colunas (devido à maneira como as colunas de um conjunto de resultados são lidas a partir da fonte de dados). Por exemplo, é um erro chamar SQLGetData para a coluna 5 e depois chamá-lo para a coluna 4.

  • Não pode ser vinculado.

  • Deve ter um número de coluna maior do que a última coluna vinculada. Por exemplo, se a última coluna vinculada for a coluna 3, é um erro chamar SQLGetData para a coluna 2. Por esse motivo, os aplicativos devem fazer com que as colunas de dados longas sejam colocadas no final da lista de seleção.

  • Não será possível usar se SQLFetch ou SQLFetchScroll tiverem sido chamados para recuperar mais de uma linha. Para obter mais informações, consulte Como usar cursores de bloco.

Alguns drivers não impõem essas restrições. Aplicativos interoperáveis devem assumir que existem ou determinar quais restrições não são impostas chamando SQLGetInfo com a opção SQL_GETDATA_EXTENSIONS.

Se o aplicativo não precisar de todos os dados em um caractere ou coluna de dados binários, ele poderá reduzir o tráfego de rede em drivers baseados em DBMS definindo o atributo de instrução SQL_ATTR_MAX_LENGTH antes de executar a instrução. Isso restringe o número de bytes de dados que serão retornados para qualquer caractere ou coluna binária. Por exemplo, suponha que uma coluna contenha documentos de texto longo. Um aplicativo que navega pela tabela que contém essa coluna pode ter que exibir apenas a primeira página de cada documento. Embora esse atributo de instrução possa ser simulado no driver, não há razão para fazer isso. Em particular, se um aplicativo quiser truncar dados binários ou caracteres, ele deverá associar um pequeno buffer à coluna com SQLBindCol e permitir que o driver trunque os dados.