ODBC 驱动程序 API 支持¶
Snowflake ODBC 驱动程序支持 3.52 版本的 ODBC API。本主题列出了与 Snowflake 相关的 ODBC 例程,并指出是否支持这些例程。例程根据执行的函数进行分类。
本主题内容:
连接到数据源¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
获取有关驱动程序和数据源的信息¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
设置和检索驱动程序属性¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
设置 SQL_ATTR_METADATA_ID 仅影响 SQLTables 和 SQLColumns 函数(而不影响其他 支持的目录函数)。 |
|
✔ |
不支持只读模式。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。 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
|
|
✔ |
SQL_ATTR_CONNECTION_POOLING 属性是在 ODBC API 版本 3.52 之后的版本中引入的,不受支持。 |
|
✔ |
SQL_ATTR_CURSOR_SCROLLABLE 仅支持 SQL_NONSCROLLABLE 值。. SQL_ATTR_USE_BOOKMARKS 仅支持 SQL_UB_OFF 值。. . 为了与第三方工具兼容,SQL_ATTR_ENABLE_AUTO_IPD 默认为 True,即使 ODBC 标准规定它应该默认为 False,也是如此。若要将默认值更改为 False,请将 EnableAutoIpdByDefault 参数设置为 |
|
✔ |
除了标准属性之外,Snowflake 实现还支持属性 SQL_SF_STMT_ATTR_LAST_QUERY_ID,该属性允许用户检索与指定语句句柄关联的最新查询 ID。部分示例位于以下的 示例 部分。 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 |
上述每个函数都有一个接受宽字符 (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 建议使用此属性来设置私钥。
设置和检索描述符字段¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
准备 SQL 请求¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
受 Snowflake 驱动程序支持,但已弃用 ODBC API。 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 2.x 中已弃用。已替换为 |
备注
可以绑定的数据大小有上限。有关详细信息,请参阅 查询文本大小的限制。
支持预编译的 SQL 语句 列出支持准备的 SQL 语句类型。
提交请求¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
无论绑定到参数的数据类型如何,Snowflake 都会执行服务器端转换并返回最大长度为 16777216 的 VARCHAR。 |
|
✔ |
|
|
✔ |
在 ODBC 驱动程序版本 2.23.3 中添加了对此函数的支持。 |
|
✔ |
在 ODBC 驱动程序版本 2.23.3 中添加了对此函数的支持。 |
检索结果和结果相关信息¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
ODBC 驱动程序当前不支持半结构化数据,包括 |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
对于 GEOGRAPHY 列, |
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 2.x 中已弃用。已替换为 |
|
✔ |
|
|
✔ |
|
|
已在 API 版本 3.x 驱动程序中替换为 |
|
|
Snowflake 不支持该功能。 |
|
|
Snowflake 不支持该功能。 |
获取有关数据源系统表的信息(目录函数)¶
函数名称 |
支持 |
备注 |
---|---|---|
|
返回一个空结果集。 |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
在结果集中, |
|
返回一个空结果集。 |
|
|
返回一个空结果集。 |
|
|
返回一个空结果集。 |
|
|
✔ |
如果传递给函数的参数为“TABLE”,则该函数返回所有类型的表,包括瞬态表和临时表。. . 如果传递给函数的参数为“VIEW”,则该函数返回所有类型的视图,包括物化视图。. . 如果传递给函数的参数是“TABLE、VIEW”或“%”,则该函数将返回有关所有类型的表和所有类型的视图的信息。 |
如果传递给目录函数的名称具有无效字符,或者该名称与任何数据库对象都不匹配,则该函数将返回空结果集。
设置 SQL_ATTR_METADATA_ID
仅影响 SQLTables
、SQLColumns
和 SQLProcedures
函数。
终止语句¶
函数名称 |
支持 |
备注 |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。已替换为 |
终止连接¶
函数名称 |
支持 |
备注 |
---|---|---|
|
版本 3.52 之后引入 API。 |
|
|
✔ |
|
|
✔ |
|
|
✔ |
受 Snowflake 驱动程序支持,但在 ODBC API 版本 3.x 中已弃用。 |
|
✔ |
受 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
以下代码演示了自定义数据类型的示例用法:
// 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);
示例¶
本部分提供了使用 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);
如果在 Linux 或 macOS 中执行,则调用 SQLGetStmtAttrW
并传递相应数据类型的参数(例如,“wchar”而不是“char”)。
在检索数据时提高性能的最佳实践¶
使用 SQLFetch
检索数据时,可以使用 SQLGetData
或 SQLBindCol
函数访问单元格的内容。在大多数情况下,使用 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);
使用 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);
使用 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);