Partilhar via


Obtendo dados em formato longo

Os SGBD definem dados longos como qualquer carácter ou dado binário acima de um determinado tamanho, como 255 caracteres. Estes dados podem ser suficientemente pequenos para serem armazenados num único buffer, como uma descrição de partes com vários milhares de caracteres. No entanto, pode ser demasiado longo para armazenar na memória, como documentos de texto longos ou bitmaps. Como tais dados não podem ser armazenados num único buffer, são recuperados do driver em partes com SQLGetData depois de os outros dados da linha terem sido recuperados.

Observação

Uma aplicação pode, na verdade, recuperar qualquer tipo de dados com SQLGetData, não apenas dados longos, embora apenas dados de caracteres e binários possam ser recuperados em partes. No entanto, se os dados forem suficientemente pequenos para caber num único buffer, geralmente não há razão para usar SQLGetData. É muito mais fácil associar um buffer à coluna e deixar o driver devolver os dados no buffer.

Para recuperar dados longos de uma coluna, uma aplicação chama primeiro SQLFetchScroll ou SQLFetch para mover para uma linha e buscar os dados das colunas limitadas. A aplicação então chama SQLGetData. SQLGetData possui os mesmos parâmetros que SQLBindCol: um handle de afirmação; um número de coluna; o tipo de dados C, o endereço e o comprimento em bytes de uma variável de aplicação; e o endereço de um buffer de comprimento/indicador. Ambas as funções têm os mesmos argumentos porque desempenham essencialmente a mesma tarefa: ambas descrevem uma variável de aplicação ao driver e especificam que os dados de uma determinada coluna devem ser devolvidos nessa variável. As principais diferenças são que o SQLGetData é chamado depois de uma linha ser obtida (e por vezes é referido como late binding por esta razão) e que o binding especificado pelo SQLGetData dura apenas durante a duração da chamada.

Relativamente a uma única coluna, o SQLGetData comporta-se como o SQLFetch: recupera os dados da coluna, converte-os para o tipo da variável de aplicação e devolve-os nessa variável. Também devolve o comprimento em bytes dos dados no buffer de comprimento/indicador. Para mais informações sobre como o SQLFetch devolve dados, consulte Buscar uma Linha de Dados.

O SQLGetData difere do SQLFetch num aspeto importante. Se for chamada mais do que uma vez consecutivamente para a mesma coluna, cada chamada devolve uma parte sucessiva dos dados. Cada chamada, exceto a última, devolve SQL_SUCCESS_WITH_INFO e SQLSTATE 01004 (String data, truncado à direita); A última chamada retorna SQL_SUCCESS. É assim que o SQLGetData é usado para recuperar dados longos em partes. Quando não há mais dados para devolver, o SQLGetData devolve SQL_NO_DATA. A aplicação é responsável por juntar os dados longos, o que pode significar concatenar as partes dos dados. Cada parte tem terminação nula; a aplicação deve remover o carácter de terminação nula se concatenar as partes. A recuperação de dados em partes pode ser feita tanto para marcadores de comprimento variável como para outros dados longos. O valor devolvido no buffer de comprimento/indicador diminui em cada chamada pelo número de bytes devolvidos na chamada anterior, embora seja comum que o driver não consiga descobrir a quantidade de dados disponíveis e devolver 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);  

Existem várias restrições na utilização do SQLGetData. Geralmente, as colunas acessadas com SQLGetData:

  • Deve ser acedido por ordem crescente do número de colunas (devido à forma 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 superior ao da última coluna vinculada. Por exemplo, se a última coluna ligada for a coluna 3, é um erro chamar SQLGetData para a coluna 2. Por esta razão, as aplicações devem certificar-se de colocar colunas de dados longas no final da lista de seleção.

  • Não pode ser usado se o SQLFetch ou o SQLFetchScroll foram chamados para recuperar mais do que uma linha. Para mais informações, consulte Uso de Cursores de Bloco.

Alguns condutores não aplicam estas restrições. As aplicações interoperáveis devem assumir que existem ou determinar quais as restrições que não são aplicadas, chamando SQLGetInfo com a opção SQL_GETDATA_EXTENSIONS.

Se a aplicação não precisar de todos os dados numa coluna de dados de caracteres ou binários, pode reduzir o tráfego de rede em drivers baseados em SGBD definindo o atributo SQL_ATTR_MAX_LENGTH da instrução antes de executar a instrução. Isto restringe o número de bytes de dados que serão devolvidos para qualquer carácter ou coluna binária. Por exemplo, suponha que uma coluna contém documentos de texto longos. Uma aplicação que navegue pela tabela que contém esta coluna pode ter de mostrar apenas a primeira página de cada documento. Embora este atributo de instrução possa ser simulado no driver, não há razão para o fazer. Em particular, se uma aplicação quiser truncar dados de caracteres ou binários, deve ligar um pequeno buffer à coluna com SQLBindCol e deixar o driver truncar os dados.