API-Unterstützung für ODBC-Treiber¶
Der Snowflake ODBC-Treiber unterstützt die Version 3.52 der ODBC-API. Unter diesem Thema werden die für Snowflake relevanten ODBC-Routinen aufgelistet und angezeigt, ob sie unterstützt werden. Die Routinen sind in Kategorien eingeteilt, die auf der Grundlage der von ihnen ausgeführten Funktion erstellt wurden.
Die vollständige API-Referenz finden Sie in der Microsoft ODBC-Programmierreferenz.
Unter diesem Thema:
Verbinden mit einer Datenquelle¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
Abrufen von Informationen zu einem Treiber und einer Datenquelle¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Einstellen und Abrufen von Treiberattributen¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
Das Festlegen von SQL_ATTR_METADATA_ID wirkt sich nur auf die Funktionen SQLTables und SQLColumns aus (und nicht auf die anderen unterstützten Katalogfunktionen). |
|
✔ |
Der Nur-Lese-Modus wird nicht unterstützt. SQL_MODE_READ_ONLY wird an den Treiber übergeben, aber Snowflake schreibt immer noch in die Datenbank. . . Außerdem wurden einige Attribute nach API-Version 3.52 eingeführt: 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. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
|
|
✔ |
Das SQL_ATTR_CONNECTION_POOLING-Attribut wurde nach ODBC-API in Version 3.52 eingeführt und wird nicht unterstützt. |
|
✔ |
SQL_ATTR_CURSOR_SCROLLABLE unterstützt nur einen SQL_NONSCROLLABLE-Wert. . SQL_ATTR_USE_BOOKMARKS unterstützt nur einen SQL_UB_OFF-Wert. . . Aus Gründen der Kompatibilität mit Tools von Drittanbietern hat SQL_ATTR_ENABLE_AUTO_IPD standardmäßig den Wert „true“, obwohl der ODBC-Standard vorschreibt, dass standardmäßig den Wert „false“ verwendet werden soll. Um den Standardwert auf „false“ zu ändern, setzen Sie den Parameter EnableAutoIpdByDefault auf |
|
✔ |
Zusätzlich zu den Standardattributen unterstützt die Snowflake-Implementierung das Attribut SQL_SF_STMT_ATTR_LAST_QUERY_ID, mit dem der Benutzer die letzte Abfrage-ID abrufen kann, die dem angegebenen Anweisungshandle zugeordnet ist. Ein unvollständiges Beispiel finden Sie unten im Abschnitt Beispiele. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch |
Jede der vorhergehenden Funktionen hat eine entsprechende Funktion, die breite Zeichen (Unicode) akzeptiert. Jede solche Unicode-Funktion hat den oben gezeigten Namen, gefolgt von „W“. Beispielsweise hat die Funktion SQLGetStmtAttr
, die ein char-Array als dritten Parameter akzeptiert, eine entsprechende Funktion mit dem Namen SQLGetStmtAttrW
, die ein wchar-Array als dritten Parameter akzeptiert.
Snowflake-spezifisches Verhalten¶
SQLSetConnectAttr
Diese Methode unterstützt zwei Snowflake-spezifische Attribute:
Attributname
Beschreibung
SQL_SF_CONN_ATTR_APPLICATION
Dies überschreibt den Wert, der durch die Einstellung APPLICATION in der Registrierungs- oder INI-Datei angegeben wird.
SQL_SF_CONN_ATTR_PRIV_KEY
Dies ist ein EVP_PKEY*-Zeiger, der auf eine speicherinterne Kopie des privaten Schlüssels verweist. Dadurch werden die Einstellungen PRIV_KEY_FILE und PRIV_KEY_PWD in der Registrierung oder der INI-Datei überschrieben. Snowflake empfiehlt, dieses Attribut zum Festlegen des privaten Schlüssels zu verwenden.
Einstellen und Abrufen von Deskriptorfeldern¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Vorbereitung von SQL-Anforderungen¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Wird vom Snowflake-Treiber unterstützt, aber veraltete ODBC-API. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber ab ODBC-API-Version 2.x veraltet. Ersetzt durch |
Bemerkung
Es gibt eine Obergrenze für die Datengröße, die Sie binden können. Weitere Details dazu finden Sie unter Begrenzung der Abfragetextgröße.
Für die Vorbereitung unterstützte SQL-Anweisungen listet die Typen von SQL-Anweisungen auf, die für die Vorbereitung unterstützt werden.
Übermitteln von Anforderungen¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Unabhängig vom Datentyp, der an dem Parameter gebunden ist, führt Snowflake eine serverseitige Konvertierung durch und gibt einen VARCHAR-Wert mit einer maximalen Länge von 16.777.216 zurück. |
|
✔ |
|
|
✔ |
Die Unterstützung für diese Funktion wurde in Version 2.23.3 des ODBC-Treibers hinzugefügt. |
|
✔ |
Die Unterstützung für diese Funktion wurde in Version 2.23.3 des ODBC-Treibers hinzugefügt. |
Abrufen von Ergebnissen und Informationen zu Ergebnissen¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
Der ODBC-Treiber unterstützt derzeit keine semistrukturierten Daten. Dies betrifft auch die Datentypen |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Bei GEOGRAPHY-Spalten gibt |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber ab ODBC-API-Version 2.x veraltet. Ersetzt durch |
|
✔ |
|
|
✔ |
Das |
|
Ersetzt durch |
|
|
Snowflake unterstützt die Funktionalität nicht. |
|
|
Snowflake unterstützt die Funktionalität nicht. |
Abrufen von Informationen zu den Systemtabellen der Datenquelle (Katalogfunktionen)¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
Gibt ein leeres Resultset zurück. |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Im Resultset enthält die Spalte |
|
Gibt ein leeres Resultset zurück. |
|
|
Gibt ein leeres Resultset zurück. |
|
|
Gibt ein leeres Resultset zurück. |
|
|
✔ |
Wenn der an die Funktion übergebene Parameter „TABLE“ ist, gibt die Funktion alle Tabellentypen zurück, einschließlich transienter Tabellen und temporärer Tabellen. . . Wenn der an die Funktion übergebene Parameter „VIEW“ ist, gibt die Funktion alle Arten von Ansichten zurück, einschließlich materialisierter Ansichten. . . Wenn der an die Funktion übergebene Parameter „TABLE, VIEW“ oder „%“ ist, gibt die Funktion Informationen zu allen Tabellentypen und Ansichtstypen zurück. |
Wenn der an die Katalogfunktion übergebene Name ein ungültiges Zeichen enthält oder wenn der Name keinem Datenbankobjekt entspricht, gibt die Funktion ein leeres Resultset zurück.
Das Einstellen von SQL_ATTR_METADATA_ID
wirkt sich nur auf die Funktionen SQLTables
, SQLColumns
und SQLProcedures
aus.
Beenden einer Anweisung¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch |
Beenden einer Verbindung¶
Funktionsname |
Unterstützt |
Anmerkungen |
---|---|---|
|
Eingeführt in die API nach Version 3.52. |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
|
✔ |
Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. |
Kundenspezifische SQL-Datentypen¶
Einige SQL-Datentypen, die von Snowflake unterstützt werden, haben keine direkte Zuordnung in ODBC (z. B. TIMESTAMP_*tz, VARIANT). Damit der ODBC-Treiber die nicht unterstützten Datentypen verarbeiten kann, enthält die mit dem Treiber gelieferte Headerdatei Definitionen für die folgenden kundenspezifische Datentypen:
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
Der folgende Code veranschaulicht die Beispielnutzung der kundenspezifischen Datentypen:
// 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);
Beispiele¶
Dieser Abschnitt enthält Beispiele für die Verwendung der API.
Abrufen der letzten Abfrage-ID¶
Das Abrufen der letzten Abfrage-ID ist eine Snowflake-Erweiterung des ODBC-Standards.
Rufen Sie zum Abrufen der letzten Abfrage-ID die Funktion SQLGetStmtAttr
(oder SQLGetStmtAttrW
) auf, und übergeben Sie das Attribut SQL_SF_STMT_ATTR_LAST_QUERY_ID und ein Zeichenarray, das groß genug ist, um die Abfrage-ID aufzunehmen.
Das folgende Beispiel zeigt, wie die Abfrage-ID für eine Abfrage abgerufen wird:
// 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);
Wenn die Ausführung unter Linux oder macOS erfolgt, rufen Sie SQLGetStmtAttrW
auf und übergeben Sie Parameter des entsprechenden Datentyps (z. B. „wchar“ anstelle von „char“).
Bewährte Methoden zur Verbesserung der Leistung beim Abrufen von Daten¶
Wenn Sie Daten mit SQLFetch
abrufen, können Sie die Funktionen SQLGetData
oder SQLBindCol
verwenden, um auf den Inhalt der Zellen zuzugreifen. In den meisten Fällen bietet die Verwendung von SQLBindCol
eine bessere Leistung, da die Anzahl der ODBC-Aufrufe zum Abrufen von Daten reduziert wird und die Vorteile des Kopierens von Daten in den Arbeitsspeicher genutzt werden können.
Verwenden von SQLGetData
zum Abrufen von Zelldaten¶
Im folgenden Beispiel wird die Funktion SQLGetData
verwendet, um Zellenwerte aus dem von SQLFetch
zurückgegebenen Datenpuffer abzurufen. Beachten Sie, dass Sie SQLGetData
für jede Zelle in der Zeile einmal aufrufen müssen.
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);
Verwenden von SQLBindCol
zum Binden der Spalten für eine einzelne Datenzeile¶
Im folgenden Beispiel wird die Funktion SQLBindCol
verwendet, um Zellenwerte aus dem von SQLFetch
zurückgegebenen Datenpuffer abzurufen. Dabei wird im Arbeitsspeicher ein Puffer für die Anzahl der Spalten einer Zeile erstellt und dann ein einziger SQLBindCol
-Aufruf ausgeführt, um die Anwendungspuffer an das Resultset zu binden. Schließlich wird SQLFetch
einmal pro Zeile aufgerufen, und die Zellwerte werden in den Puffer geladen. Mit diesem Ansatz kann die Geschwindigkeit und Effizienz des Datenabrufs erheblich gesteigert werden.
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);
Verwenden von SQLBindCol
zum Binden der Spalten für mehrere Datenzeilen¶
Sie können die Leistung noch weiter verbessern, indem Sie mehrere Zeilen mit einem einzigen SQLFetch
-Aufruf abrufen, wodurch sich die Anzahl der ODBC SQLFetch
-Aufrufe verringert, die zur Verarbeitung aller Zeilen einer Abfragetabelle erforderlich sind.
Beispiel:
Ermittelt die Anzahl der Spalten im Resultset.
Erstellt ein Array im Arbeitsspeicher zum Speichern der Daten mehrerer Spalten.
Ruft
SQLBindCol
für jede Spalte auf, um die Anwendungspuffer an das Resultset zu binden.Ruft
SQLFetch
auf, um die angegebene Anzahl von Zeilen (100) abzurufen, und verarbeitet die Daten ohne ODBC-Aufrufe über den Puffer im Arbeitsspeicher, bis das Ende der Abfragetabelle erreicht ist.
Mit diesem Ansatz kann die Geschwindigkeit und Effizienz des Datenabrufs erheblich gesteigert werden. Bei einer Abfragetabelle mit 20 Spalten und 1.000 Zeilen würde in diesem Beispiel nur 20 SQLBindCol
und 10 SQLFetch
Aufrufe anstelle von 20.000 SQLGetData
Aufrufen benötigt, um alle Daten der Tabelle zu laden.
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);