ODBC 驱动程序 API 支持

Snowflake ODBC 驱动程序支持 3.52 版本的 ODBC API。本主题列出了与 Snowflake 相关的 ODBC 例程,并指出是否支持这些例程。例程根据执行的函数进行分类。

本主题内容:

连接到数据源

函数名称

支持

备注

SQLAllocHandle

SQLConnect

SQLDriverConnect

SQLAllocEnv

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLAllocConnect

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLBrowseConnect

获取有关驱动程序和数据源的信息

函数名称

支持

备注

SQLDataSources

SQLDrivers

SQLGetInfo

SQLGetFunctions

SQLGetTypeInfo

设置和检索驱动程序属性

函数名称

支持

备注

SQLSetConnectAttr

设置 SQL_ATTR_METADATA_ID 仅影响 SQLTables 和 SQLColumns 函数(而不影响其他 支持的目录函数)。

SQLGetConnectAttr

不支持只读模式。SQL_MODE_READ_ONLY 传递给驱动程序,但 Snowflake 仍写入数据库。. . 此外,在 API 版本 3.52 之后的版本中引入了一些属性: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

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLGetConnectOption

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLSetEnvAttr

SQLGetEnvAttr

SQL_ATTR_CONNECTION_POOLING 属性是在 ODBC API 版本 3.52 之后的版本中引入的,不受支持。

SQLSetStmtAttr

SQL_ATTR_CURSOR_SCROLLABLE 仅支持 SQL_NONSCROLLABLE 值。. SQL_ATTR_USE_BOOKMARKS 仅支持 SQL_UB_OFF 值。. . 为了与第三方工具兼容,SQL_ATTR_ENABLE_AUTO_IPD 默认为 True,即使 ODBC 标准规定它应该默认为 False,也是如此。若要将默认值更改为 False,请将 EnableAutoIpdByDefault 参数设置为 false. . 设置 SQL_ATTR_METADATA_ID 仅影响 SQLTables 和 SQLColumns 函数(而不影响其他 支持的目录函数)。. . 不支持的属性:SQL_ATTR_SIMULATE_CURSOR、SQL_ATTR_FETCH_BOOKMARK_PTR、SQL_ATTR_KEYSET_SIZE。

SQLGetStmtAttr

除了标准属性之外,Snowflake 实现还支持属性 SQL_SF_STMT_ATTR_LAST_QUERY_ID,该属性允许用户检索与指定语句句柄关联的最新查询 ID。部分示例位于以下的 示例 部分。

SQLSetStmtOption

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 SQLSetStmtAttr

SQLGetStmtOption

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 SQLGetStmtAttr

SQLParamOptions

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 SQLSetStmtAttr

上述每个函数都有一个接受宽字符 (unicode) 的相应函数。每个此类 unicode 函数的名称如上所示,后跟“W”。例如,接受 char 数组作为第三个参数的函数 SQLGetStmtAttr 具有一个名为 SQLGetStmtAttrW 的相应函数,该函数接受 wchar 数组作为第三个参数。

Snowflake 特定行为

  • SQLSetConnectAttr

    此方法支持两个特定于 Snowflake 的属性:

    属性名称

    描述

    SQL_SF_CONN_ATTR_APPLICATION

    这将替换注册表或 .ini 文件中的 APPLICATION 设置指定的值。

    SQL_SF_CONN_ATTR_PRIV_KEY

    这是一个 EVP_PKEY* 指针,指向私钥的内存副本。这将替换注册表或 .ini 文件中的 PRIV_KEY_FILE 和 PRIV_KEY_PWD 设置。Snowflake 建议使用此属性来设置私钥。

设置和检索描述符字段

函数名称

支持

备注

SQLGetDescField

SQLGetDescRec

SQLSetDescField

SQLSetDescRec

准备 SQL 请求

函数名称

支持

备注

SQLAllocStmt

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLBindParameter

SQLPrepare

SQLGetCursorName

SQLSetCursorName

SQLSetScrollOptions

受 Snowflake 驱动程序支持,但已弃用 ODBC API。

SQLSetParam

受 Snowflake 驱动程序支持,但在 ODBC API 版本 2.x 中已弃用。已替换为 SQLBindParameter

备注

提交请求

函数名称

支持

备注

SQLExecute

SQLExecDirect

SQLNativeSql

SQLDescribeParam

无论绑定到参数的数据类型如何,Snowflake 都会执行服务器端转换并返回最大长度为 16777216 的 VARCHAR。

SQLNumParams

SQLParamData

在 ODBC 驱动程序版本 2.23.3 中添加了对此函数的支持。

SQLPutData

在 ODBC 驱动程序版本 2.23.3 中添加了对此函数的支持。

检索结果和结果相关信息

函数名称

支持

备注

SQLBindCol

ODBC 驱动程序当前不支持半结构化数据,包括 VARIANTOBJECTARRAY 数据类型。

SQLError

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 SQLGetDiagRec

SQLGetData

SQLGetDiagField

SQLGetDiagRec

SQLRowCount

SQLNumResultCols

SQLDescribeCol

SQLColAttribute

对于 GEOGRAPHY 列,SQL_DESC_TYPE_NAME 返回 GEOGRAPHY。请注意,其他描述符(例如 SQL_DESC_CONCISE_TYPE)不指示列类型为 GEOGRAPHY

SQLColAttributes

受 Snowflake 驱动程序支持,但在 ODBC API 版本 2.x 中已弃用。已替换为 SQLColAttribute

SQLFetch

SQLFetchScroll

FetchOrientation 实参仅支持 SQL_FETCH_NEXT 值。所有其他类型的提取都失败。

SQLExtendedFetch

已在 API 版本 3.x 驱动程序中替换为 SQLFetchScroll

SQLSetPos

Snowflake 不支持该功能。

SQLBulkOperations

Snowflake 不支持该功能。

获取有关数据源系统表的信息(目录函数)

函数名称

支持

备注

SQLColumnPrivileges

返回一个空结果集。

SQLColumns

SQLForeignKeys

SQLPrimaryKeys

SQLProcedureColumns

SQLProcedures

在结果集中,NUM_INPUT_PARAMS 列包含过程的实参数(SHOW PROCEDURES 命令输出中 max_num_arguments 列的值)。. . NUM_OUTPUT_PARAMS 列包含 NULL 值,因为 Snowflake 中的存储过程不支持输出参数。. . NUM_RESULT_SETS 列还包含 NULL 值,因为 Snowflake 中的存储过程不返回结果集。. . PROCEDURE_TYPE 列始终包含 SQL_PT_FUNCTION,因为 Snowflake 中的存储过程始终返回一个值。

SQLSpecialColumns

返回一个空结果集。

SQLStatistics

返回一个空结果集。

SQLTablePrivileges

返回一个空结果集。

SQLTables

如果传递给函数的参数为“TABLE”,则该函数返回所有类型的表,包括瞬态表和临时表。. . 如果传递给函数的参数为“VIEW”,则该函数返回所有类型的视图,包括物化视图。. . 如果传递给函数的参数是“TABLE、VIEW”或“%”,则该函数将返回有关所有类型的表和所有类型的视图的信息。

如果传递给目录函数的名称具有无效字符,或者该名称与任何数据库对象都不匹配,则该函数将返回空结果集。

设置 SQL_ATTR_METADATA_ID 仅影响 SQLTablesSQLColumnsSQLProcedures 函数。

终止语句

函数名称

支持

备注

SQLFreeStmt

SQLCloseCursor

SQLCancel

SQLEndTran

SQLTransact

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 SQLEndTran

终止连接

函数名称

支持

备注

SQLCancelHandle

版本 3.52 之后引入 API。

SQLDisconnect

SQLFreeHandle

SQLFreeConnect

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

SQLFreeEnv

受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。

自定义 SQL 数据类型

Snowflake 支持的某些 SQL 数据类型在 ODBC 中没有直接映射(例如 TIMESTAMP_*tz、VARIANT)。若要使 ODBC 驱动程序能够使用不受支持的数据类型,驱动程序附带的头文件包括以下自定义数据类型的定义:

////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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

以下代码演示了自定义数据类型的示例用法:

// 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

示例

本部分提供了使用 API 的示例。

检索上次的查询 ID

检索上次的查询 ID 是 Snowflake 对 ODBC 标准的一种扩展。

要检索上次的查询 ID,请调用函数 SQLGetStmtAttr (或 SQLGetStmtAttrW),传递属性 SQL_SF_STMT_ATTR_LAST_QUERY_ID 和足够大的字符数组来保存查询 ID。

以下示例演示如何检索查询的查询 ID:

// 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

如果在 Linux 或 macOS 中执行,则调用 SQLGetStmtAttrW 并传递相应数据类型的参数(例如,“wchar”而不是“char”)。

在检索数据时提高性能的最佳实践

使用 SQLFetch 检索数据时,可以使用 SQLGetDataSQLBindCol 函数访问单元格的内容。在大多数情况下,使用 SQLBindCol 可提供更好的性能,因为它减少了检索数据所需的 ODBC 调用次数,并且因为它允许您利用在内存中复制数据的优势。

使用 SQLGetData 检索单元格数据

以下示例使用 SQLGetData 函数从 SQLFetch 返回的数据缓冲区中检索单元格值。请注意,您需要为行中的每个单元格调用一次 SQLGetData

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

使用 SQLBindCol 绑定一行数据的列

以下示例使用 SQLBindCol 函数从 SQLFetch 返回的数据缓冲区中检索单元格值。它为一行中的列数创建一个内存中缓冲区,然后进行单个 SQLBindCol 调用以将应用程序缓冲区绑定到结果集。最后,它每行调用一次 SQLFetch,并将单元格值加载到缓冲区中。这种方法可以显著提高检索数据的速度和效率。

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

使用 SQLBindCol 绑定多行数据的列

通过在单个 SQLFetch 调用中提取多行,可以进一步提高性能,从而减少处理查询表的所有行所需的 ODBC SQLFetch 调用的数量。

以下示例:

  • 确定结果集中的列数。

  • 创建一个内存数组来存储多列的数据。

  • 为每列调用 SQLBindCol 以将应用程序缓冲区绑定到结果集。

  • 调用 SQLFetch 以获取指定的行数 (100),并处理内存缓冲区中的数据,而不进行 ODBC 调用,直到到达查询表的末尾。

这种方法可以显著提高检索数据的速度和效率。对于具有 20 列和 1000 行的查询表,此示例将仅进行 20 次 SQLBindCol 和 10 次 SQLFetch 调用,而不是 20000 次 SQLGetData 调用来加载所有表数据。

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
语言: 中文