Suporte de API do driver ODBC

O driver ODBC do Snowflake oferece suporte à versão 3.52 da API ODBC. Este tópico lista as rotinas ODBC relevantes para o Snowflake e indica se elas são compatíveis. As rotinas são organizadas em categorias com base na função que desempenham.

Para obter a referência completa da API, consulte a Referência do programador ODBC da Microsoft.

Neste tópico:

Conexão a uma fonte de dados

Nome da função

Com suporte

Notas

SQLAllocHandle

SQLConnect

SQLDriverConnect

SQLAllocEnv

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLAllocConnect

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLBrowseConnect

Como obter informações de drivers e fontes de dados

Nome da função

Com suporte

Notas

SQLDataSources

SQLDrivers

SQLGetInfo

SQLGetFunctions

SQLGetTypeInfo

Configuração e recuperação de atributos de drivers

Nome da função

Com suporte

Notas

SQLSetConnectAttr

A configuração SQL_ATTR_METADATA_ID afeta apenas as funções SQLTables e SQLColumns (e não as outras funções de catálogo suportadas).

SQLGetConnectAttr

Não há suporte para o modo somente leitura. SQL_MODE_READ_ONLY é passado para o driver, mas o Snowflake ainda grava no banco de dados. . . Além disso, alguns atributos foram introduzidos após a versão 3.52 da API: SQL_ATTR_ASYNC_DBC_EVENT, SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, SQL_ATTR_ASYNC_DBC_PCALLBACK, SQL_ATTR_ASYNC_DBC_PCONTEXT, SQL_ATTR_DBC_INFO_TOKEN.

SQLSetConnectOption

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLGetConnectOption

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLSetEnvAttr

SQLGetEnvAttr

O atributo SQL_ATTR_CONNECTION_POOLING foi introduzido após a versão 3.52 da API ODBC e não é suportado.

SQLSetStmtAttr

SQL_ATTR_CURSOR_SCROLLABLE aceita apenas um valor SQL_NONSCROLLABLE. . SQL_ATTR_USE_BOOKMARKS aceita apenas um valor SQL_UB_OFF. . . Para compatibilidade com ferramentas de terceiros, SQL_ATTR_ENABLE_AUTO_IPD é definido como verdadeiro por padrão, mesmo que o padrão ODBC diga que ele deve ser falso. Para alterar o valor padrão para falso, defina o parâmetro EnableAutoIpdByDefault como false. . . A configuração de SQL_ATTR_METADATA_ID afeta apenas as funções SQLTables e SQLColumns (e não as outras funções de catálogo suportadas). . . Atributos sem suporte: SQL_ATTR_SIMULATE_CURSOR, SQL_ATTR_FETCH_BOOKMARK_PTR, SQL_ATTR_KEYSET_SIZE.

SQLGetStmtAttr

Além dos atributos padrão, a implementação do Snowflake oferece suporte ao atributo SQL_SF_STMT_ATTR_LAST_QUERY_ID, que permite ao usuário recuperar a ID da consulta mais recente associada ao identificador da instrução especificada. Veja um exemplo parcial na seção Exemplos abaixo.

SQLSetStmtOption

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x. Substituída por SQLSetStmtAttr.

SQLGetStmtOption

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x. Substituída por SQLGetStmtAttr.

SQLParamOptions

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x. Substituída por SQLSetStmtAttr.

Cada uma das funções anteriores tem uma função correspondente que aceita caracteres amplos (unicode). Cada uma dessas funções unicode tem o nome mostrado acima, seguido por «W». Por exemplo, a função SQLGetStmtAttr, que aceita uma matriz de caracteres como terceiro parâmetro, tem uma função correspondente chamada SQLGetStmtAttrW, que aceita uma matriz de caracteres amplos como terceiro parâmetro.

Comportamento específico do Snowflake

  • SQLSetConnectAttr

    Esse método é compatível com dois atributos específicos do Snowflake:

    Nome do atributo

    Descrição

    SQL_SF_CONN_ATTR_APPLICATION

    Substitui o valor especificado pela configuração APPLICATION no registro ou no arquivo .ini.

    SQL_SF_CONN_ATTR_PRIV_KEY

    Ponteiro EVP_PKEY* que aponta para uma cópia da chave privada na memória. Substitui as configurações PRIV_KEY_FILE e PRIV_KEY_PWD no registro ou no arquivo .ini. O Snowflake recomenda o uso desse atributo para definir a chave privada.

Configuração e recuperação dos campos descritores

Nome da função

Com suporte

Notas

SQLGetDescField

SQLGetDescRec

SQLSetDescField

SQLSetDescRec

Preparação de solicitações SQL

Nome da função

Com suporte

Notas

SQLAllocStmt

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLBindParameter

SQLPrepare

SQLGetCursorName

SQLSetCursorName

SQLSetScrollOptions

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC.

SQLSetParam

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 2.x. Substituída por SQLBindParameter.

Nota

Envio de solicitações

Nome da função

Com suporte

Notas

SQLExecute

SQLExecDirect

SQLNativeSql

SQLDescribeParam

Independentemente do tipo de dados vinculado ao parâmetro, o Snowflake realiza uma conversão no lado do servidor e retorna um VARCHAR com um comprimento máximo de 16777216.

SQLNumParams

SQLParamData

O suporte para essa função foi adicionado na versão 2.23.3 do driver ODBC.

SQLPutData

O suporte para essa função foi adicionado na versão 2.23.3 do driver ODBC.

Obtenção de resultados e informações sobre os resultados

Nome da função

Com suporte

Notas

SQLBindCol

No momento, o driver ODBC não oferece suporte a dados semiestruturados, incluindo os tipos de dados VARIANT, OBJECT e ARRAY.

SQLError

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x. Substituída por SQLGetDiagRec.

SQLGetData

SQLGetDiagField

SQLGetDiagRec

SQLRowCount

SQLNumResultCols

SQLDescribeCol

SQLColAttribute

Nas colunas GEOGRAPHY, SQL_DESC_TYPE_NAME retorna GEOGRAPHY. Observe que outros descritores (por exemplo, SQL_DESC_CONCISE_TYPE) não indicam que o tipo de coluna é GEOGRAPHY.

SQLColAttributes

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 2.x. Substituída por SQLColAttribute.

SQLFetch

SQLFetchScroll

O argumento FetchOrientation é compatível apenas com o valor SQL_FETCH_NEXT. Todos os outros tipos de busca falham.

SQLExtendedFetch

Substituída por SQLFetchScroll na versão 3.x da API do driver.

SQLSetPos

O Snowflake não oferece suporte à funcionalidade.

SQLBulkOperations

O Snowflake não oferece suporte à funcionalidade.

Obtenção de informações sobre as tabelas de sistema da fonte de dados (funções de catálogo)

Nome da função

Com suporte

Notas

SQLColumnPrivileges

Retorna um conjunto de resultados vazio.

SQLColumns

SQLForeignKeys

SQLPrimaryKeys

SQLProcedureColumns

SQLProcedures

No conjunto de resultados, a coluna NUM_INPUT_PARAMS contém o número de argumentos do procedimento (o valor da coluna num_max_argumentos na saída do comando SHOW PROCEDURES). . . A coluna NUM_OUTPUT_PARAMS contém valores NULL porque os procedimentos armazenados no Snowflake não oferecem suporte aos parâmetros de saída. . . A coluna NUM_RESULT_SETS também contém valores NULL porque os procedimentos armazenados no Snowflake não retornam conjuntos de resultados. . . A coluna PROCEDURE_TYPE sempre contém SQL_PT_FUNCTION porque os procedimentos armazenados no Snowflake sempre retornam um valor.

SQLSpecialColumns

Retorna um conjunto de resultados vazio.

SQLStatistics

Retorna um conjunto de resultados vazio.

SQLTablePrivileges

Retorna um conjunto de resultados vazio.

SQLTables

Se o parâmetro passado para a função for “TABLE”, a função retorna todos os tipos de tabelas, incluindo tabelas transitórias e tabelas temporárias. . . Se o parâmetro passado para a função for “VIEW”, a função retorna todos os tipos de exibições, inclusive as exibições materializadas. . . Se o parâmetro passado para a função for “TABLE, VIEW” ou “%”, a função retorna informações sobre todos os tipos de tabelas e todos os tipos de exibições.

Se o nome passado para a função de catálogo tiver um caractere inválido, ou se o nome não corresponder a nenhum objeto do banco de dados, a função retorna um conjunto de resultados vazio.

A configuração SQL_ATTR_METADATA_ID afeta apenas as funções SQLTables, SQLColumns e SQLProcedures.

Encerramento de uma instrução

Nome da função

Com suporte

Notas

SQLFreeStmt

SQLCloseCursor

SQLCancel

SQLEndTran

SQLTransact

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x. Substituída por SQLEndTran.

Encerramento de uma conexão

Nome da função

Com suporte

Notas

SQLCancelHandle

Introduzida na versão da API posterior à versão 3.52.

SQLDisconnect

SQLFreeHandle

SQLFreeConnect

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

SQLFreeEnv

O driver do Snowflake oferece suporte, mas foi depreciada na API ODBC versão 3.x.

Tipos de dados SQL personalizados

Alguns tipos de dados SQL aceitos pelo Snowflake não têm mapeamento direto no ODBC (por exemplo, TIMESTAMP_*tz, VARIANT). Para permitir que o driver ODBC trabalhe com os tipos de dados sem suporte, o arquivo de cabeçalho enviado com o driver inclui definições para os seguintes tipos de dados personalizados:

////////////////////////////////////////////////////////////////////////////////////////////////////
/// Custom SQL Data Type Definition
///
///
////////////////////////////////////////////////////////////////////////////////////////////////////

#define SQL_SF_TIMESTAMP_LTZ 2000
#define SQL_SF_TIMESTAMP_TZ  2001
#define SQL_SF_TIMESTAMP_NTZ 2002
#define SQL_SF_ARRAY         2003
#define SQL_SF_OBJECT        2004
#define SQL_SF_VARIANT       2005
Copy

O código a seguir mostra um exemplo de uso dos tipos de dados personalizados:

// bind insert as timestamp_ntz
SQLRETURN rc;
rc = SQLPrepare(odbc.StmtHandle,
               (SQLCHAR *) "insert into testtimestampntz values (?)",
               SQL_NTS);

 SQL_TIMESTAMP_STRUCT bindData;
 SQLLEN datalen = sizeof(SQL_TIMESTAMP_STRUCT);
 bindData.year = 2017;
 bindData.month = 11;
 bindData.day = 30;
 bindData.hour = 18;
 bindData.minute = 17;
 bindData.second = 5;
 bindData.fraction = 123456789;

 rc = SQLBindParameter(
   odbc.StmtHandle, 1, SQL_PARAM_INPUT,
   SQL_C_TIMESTAMP, SQL_SF_TIMESTAMP_NTZ,
   100, 0, &bindData, sizeof(bindData), &datalen);

 rc = SQLExecute(odbc.StmtHandle);

 // query table
 rc = SQLExecDirect(odbc.StmtHandle, (SQLCHAR *)"select * from testtimestampntz", SQL_NTS);

 rc = SQLFetch(odbc.StmtHandle);

 // fetch data as timestamp
 SQL_TIMESTAMP_STRUCT ret;
 SQLLEN retLen = (SQLLEN) 0;
 rc = SQLGetData(odbc.StmtHandle, 1, SQL_C_TIMESTAMP, &ret, (SQLLEN)sizeof(ret), &retLen);
Copy

Exemplos

Esta seção oferece exemplos de utilização da API.

Recuperação da ID da última consulta

Recuperar a ID da última consulta é uma extensão do Snowflake para o padrão ODBC.

Para recuperar a ID da última consulta, chame a função SQLGetStmtAttr (ou SQLGetStmtAttrW), e passe o atributo SQL_SF_STMT_ATTR_LAST_QUERY_ID e uma matriz de caracteres grande o suficiente para armazenar a ID da consulta.

O exemplo abaixo mostra como recuperar a ID da consulta de uma consulta:

// Space to store the query ID.
// The SQLGetStmtAttr() function fills this in with the actual ID.
char queryId[37];   // Maximum 36 chars plus string terminator.

// The length (in characters) of the query ID. The SQLGetStmtAttr() function fills this in
// with the actual length of the query ID (usually 36).
SQLINTEGER idLen;

// Execute a query.
rc = SQLExecDirect(odbc.StmtHandle, (SQLCHAR *) "select 1", SQL_NTS);

// Retrieve the query ID (queryId) and the length of that query ID (idLen).
SQLGetStmtAttr(odbc.StmtHandle, SQL_SF_STMT_ATTR_LAST_QUERY_ID, queryId, sizeof(queryId), &idLen);
Copy

Se você estiver usando Linux ou macOS, chame SQLGetStmtAttrW e passe parâmetros do tipo de dados apropriado (por exemplo, «wchar» em vez de «char»).

Práticas recomendadas para melhorar o desempenho na recuperação de dados

Ao recuperar dados com SQLFetch, você pode usar as funções SQLGetData ou SQLBindCol para acessar o conteúdo das células. Na maioria dos casos, o uso de SQLBindCol proporciona melhor desempenho porque reduz o número de chamadas ODBC que você precisa fazer para recuperar os dados, e porque permite que você tire proveito da cópia de dados na memória.

Como usar SQLGetData para recuperar dados da célula

O exemplo a seguir usa a função SQLGetData para recuperar valores de células do buffer de dados retornados por SQLFetch. Observe que você precisa chamar SQLGetData uma vez para cada célula da linha.

SQLRETURN rc;
SQLSMALLINT numCols;
const size_t s_MaxDataLen = 300;

// fetch with SQLGetData()
// query table
rc = SQLExecDirect(stmt, (SQLCHAR *)"select * from table", SQL_NTS);

// Find out the number of result set columns.
rc = SQLNumResultCols(stmt, &numCols);

// buffer for one cell
vector<char> dataBuffer(s_MaxDataLen);
SQLLEN dataLen = (SQLLEN)0;

// call SQLFetch() per row and SQLGetData() per column per row
while (true)
{
    rc = SQLFetch(stmt);
    if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
    {
        break;
    }
    for (SQLUSMALLINT i = 0; i < numCols; i++)
    {
        rc = SQLGetData(stmt, i + 1, SQL_C_CHAR, dataBuffer.data(), (SQLLEN)s_MaxDataLen, &dataLen);
        std::string data;
        if (SQL_NULL_DATA == dataLen)
            continue;
        if (SQL_NO_TOTAL == dataLen)
            dataLen = s_MaxDataLen;
        data = std::string(dataBuffer.data(), dataLen);
    }
}
rc = SQLCloseCursor(stmt);
Copy

Como usar SQLBindCol para vincular as colunas de uma linha de dados

O exemplo a seguir usa a função SQLBindCol para recuperar valores de células do buffer de dados retornados por SQLFetch. Ela cria um buffer na memória para o número de colunas em uma linha e depois faz uma única chamada SQLBindCol para vincular os buffers do aplicativo ao conjunto de resultados. Finalmente, ela chama SQLFetch uma vez por linha e carrega os valores das células no buffer. Essa abordagem pode aumentar significativamente a velocidade e a eficiência da recuperação de dados.

SQLRETURN rc;
SQLSMALLINT numCols;
const size_t s_MaxDataLen = 300;

// fetch with SQLBindCol()
// query table
rc = SQLExecDirect(stmt, (SQLCHAR *)"select * from table", SQL_NTS);

// Find out the number of result set columns.
rc = SQLNumResultCols(stmt, &numCols);

// buffer for one row
vector<char> rowBuffer(s_MaxDataLen * numCols);
vector<SQLLEN> columnLenBuffer(numCols);

// call SQLBindCol() per column
for (SQLSMALLINT i = 0; i < numCols; ++i)
{
    SQLBindCol(stmt, i + 1, SQL_C_CHAR, &rowBuffer[s_MaxDataLen * i],
               s_MaxDataLen, &columnLenBuffer[i]);
}

// call SQLFetch() per row
while (true)
{
    rc = SQLFetch(stmt);
    if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
    {
         break;
    }
    // go through data for each cell in buffer without ODBC calls
    for (SQLUSMALLINT i = 0; i < numCols; i++)
    {
        std::string data;
        SQLLEN len = columnLenBuffer[i];
        if (SQL_NULL_DATA == len)
            continue;
        if (SQL_NO_TOTAL == len)
            len = s_MaxDataLen;
        data = std::string(&rowBuffer[s_MaxDataLen * i], len);
    }
}
rc = SQLCloseCursor(stmt);
Copy

Como usar SQLBindCol para vincular colunas de várias linhas de dados

Você pode melhorar ainda mais o desempenho ao buscar várias linhas em uma única chamada SQLFetch, o que reduz o número de chamadas ODBC SQLFetch necessárias para processar todas as linhas de uma tabela de consulta.

O exemplo a seguir:

  • Determina o número de colunas no conjunto de resultados.

  • Cria uma matriz na memória para armazenar os dados de várias colunas.

  • Chama SQLBindCol para cada coluna para vincular os buffers do aplicativo ao conjunto de resultados.

  • Chama SQLFetch para obter o número especificado de linhas (100) e processa os dados no buffer de memória sem fazer chamadas ODBC, até que o final da tabela de consulta seja alcançado.

Essa abordagem pode aumentar significativamente a velocidade e a eficiência da recuperação de dados. Para uma tabela de consulta com 20 colunas e 1.000 linhas, esse exemplo faria apenas 20 chamadas SQLBindCol e 10 SQLFetch em vez de 20.000 chamadas SQLGetData para carregar todos os dados da tabela.

SQLRETURN rc;
SQLSMALLINT numCols;
const size_t s_MaxDataLen = 300;

// fetch with SQLBindCol() and SQL_ATTR_ROW_ARRAY_SIZE > 1
const size_t s_numRowsPerSQLFetch = 100;
SQLULEN numRowsFetched = 0;
rc = SQLSetStmtAttr(stmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)s_numRowsPerSQLFetch, 0);
rc = SQLSetStmtAttr(stmt, SQL_ATTR_ROWS_FETCHED_PTR, (SQLPOINTER)&numRowsFetched, sizeof(SQLULEN));

// query table
rc = SQLExecDirect(stmt, (SQLCHAR *)"select * from table", SQL_NTS);

// Find out the number of result set columns.
rc = SQLNumResultCols(stmt, &numCols);

// buffer for all columns; each column has buffer size of s_numRowsPerSQLFetch
// To retrieve multiple rows per SQLFetch() call, use the default behavior of SQL_BIND_BY_COLUMN
vector<vector<char> > colArray(numCols);
vector<vector<SQLLEN> > colLenArray(numCols);

// call SQLBindCol() per column
for (SQLSMALLINT i = 0; i < numCols; ++i)
{
    // initialize buffer for each column
    colArray[i].resize(s_MaxDataLen * s_numRowsPerSQLFetch);
    colLenArray[i].resize(s_numRowsPerSQLFetch);

    SQLBindCol(stmt, i + 1, SQL_C_CHAR, colArray[i].data(),
                s_MaxDataLen, colLenArray[i].data());
}

// call SQLFetch() per s_numRowsPerSQLFetch rows
while (true)
{
    rc = SQLFetch(stmt);
    if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
    {
        break;
    }
    // go through data for each cell in buffer without ODBC calls
    for (SQLULEN rowIndex = 0; rowIndex < numRowsFetched; rowIndex++)
    {
        for (SQLUSMALLINT colIndex = 0; colIndex < colIndex; colIndex++)
        {
            std::string data;
            SQLLEN len = colLenArray[colIndex][rowIndex];
            if (SQL_NULL_DATA == len)
                continue;
            if (SQL_NO_TOTAL == len)
                len = s_MaxDataLen;
            data = std::string(&(colArray[colIndex][s_MaxDataLen * rowIndex]), len);
        }
    }
}
rc = SQLCloseCursor(stmt);
Copy