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

SQLAllocHandle

SQLConnect

SQLDriverConnect

SQLAllocEnv

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLAllocConnect

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLBrowseConnect

Abrufen von Informationen zu einem Treiber und einer Datenquelle

Funktionsname

Unterstützt

Anmerkungen

SQLDataSources

SQLDrivers

SQLGetInfo

SQLGetFunctions

SQLGetTypeInfo

Einstellen und Abrufen von Treiberattributen

Funktionsname

Unterstützt

Anmerkungen

SQLSetConnectAttr

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).

SQLGetConnectAttr

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.

SQLSetConnectOption

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLGetConnectOption

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLSetEnvAttr

SQLGetEnvAttr

Das SQL_ATTR_CONNECTION_POOLING-Attribut wurde nach ODBC-API in Version 3.52 eingeführt und wird nicht unterstützt.

SQLSetStmtAttr

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 false. . . Die Einstellung SQL_ATTR_METADATA_ID betrifft nur die Funktionen SQLTables und SQLColumns (und nicht die anderen von unterstützten Katalogfunktionen). . . Nicht unterstützte Attribute: SQL_ATTR_SIMULATE_CURSOR, SQL_ATTR_FETCH_BOOKMARK_PTR, SQL_ATTR_KEYSET_SIZE.

SQLGetStmtAttr

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.

SQLSetStmtOption

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch SQLSetStmtAttr.

SQLGetStmtOption

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch SQLGetStmtAttr.

SQLParamOptions

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch SQLSetStmtAttr.

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

SQLGetDescField

SQLGetDescRec

SQLSetDescField

SQLSetDescRec

Vorbereitung von SQL-Anforderungen

Funktionsname

Unterstützt

Anmerkungen

SQLAllocStmt

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLBindParameter

SQLPrepare

SQLGetCursorName

SQLSetCursorName

SQLSetScrollOptions

Wird vom Snowflake-Treiber unterstützt, aber veraltete ODBC-API.

SQLSetParam

Wird vom Snowflake-Treiber unterstützt, ist aber ab ODBC-API-Version 2.x veraltet. Ersetzt durch SQLBindParameter.

Bemerkung

Übermitteln von Anforderungen

Funktionsname

Unterstützt

Anmerkungen

SQLExecute

SQLExecDirect

SQLNativeSql

SQLDescribeParam

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.

SQLNumParams

SQLParamData

Die Unterstützung für diese Funktion wurde in Version 2.23.3 des ODBC-Treibers hinzugefügt.

SQLPutData

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

SQLBindCol

Der ODBC-Treiber unterstützt derzeit keine semistrukturierten Daten. Dies betrifft auch die Datentypen VARIANT, OBJECT und ARRAY.

SQLError

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch SQLGetDiagRec.

SQLGetData

SQLGetDiagField

SQLGetDiagRec

SQLRowCount

SQLNumResultCols

SQLDescribeCol

SQLColAttribute

Bei GEOGRAPHY-Spalten gibt SQL_DESC_TYPE_NAME einen GEOGRAPHY-Wert zurück. Beachten Sie, dass andere Deskriptoren (z. B. SQL_DESC_CONCISE_TYPE) nicht angeben, dass der Spaltentyp GEOGRAPHY ist.

SQLColAttributes

Wird vom Snowflake-Treiber unterstützt, ist aber ab ODBC-API-Version 2.x veraltet. Ersetzt durch SQLColAttribute.

SQLFetch

SQLFetchScroll

Das FetchOrientation-Argument unterstützt nur den SQL_FETCH_NEXT-Wert. Alle anderen Typen von Abrufen scheitern.

SQLExtendedFetch

Ersetzt durch SQLFetchScroll in Treiber mit API-Version 3.x.

SQLSetPos

Snowflake unterstützt die Funktionalität nicht.

SQLBulkOperations

Snowflake unterstützt die Funktionalität nicht.

Abrufen von Informationen zu den Systemtabellen der Datenquelle (Katalogfunktionen)

Funktionsname

Unterstützt

Anmerkungen

SQLColumnPrivileges

Gibt ein leeres Resultset zurück.

SQLColumns

SQLForeignKeys

SQLPrimaryKeys

SQLProcedureColumns

SQLProcedures

Im Resultset enthält die Spalte NUM_INPUT_PARAMS die Anzahl der Argumente der Prozedur (der Wert der Spalte „max_num_arguments“ in der Ausgabe des Befehls SHOW PROCEDURES). . . Die Spalte NUM_OUTPUT_PARAMS enthält NULL-Werte, da gespeicherte Prozeduren in Snowflake keine Ausgabeparameter unterstützen. . . Die Spalte NUM_RESULT_SETS enthält ebenfalls NULL-Werte, da gespeicherte Prozeduren in Snowflake keine Resultsets zurückgeben. . . Die Spalte PROCEDURE_TYPE enthält immer SQL_PT_FUNCTION, da gespeicherte Prozeduren in Snowflake immer einen Wert zurückgeben.

SQLSpecialColumns

Gibt ein leeres Resultset zurück.

SQLStatistics

Gibt ein leeres Resultset zurück.

SQLTablePrivileges

Gibt ein leeres Resultset zurück.

SQLTables

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

SQLFreeStmt

SQLCloseCursor

SQLCancel

SQLEndTran

SQLTransact

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet. Ersetzt durch SQLEndTran.

Beenden einer Verbindung

Funktionsname

Unterstützt

Anmerkungen

SQLCancelHandle

Eingeführt in die API nach Version 3.52.

SQLDisconnect

SQLFreeHandle

SQLFreeConnect

Wird vom Snowflake-Treiber unterstützt, ist aber in ODBC-API-Version 3.x veraltet.

SQLFreeEnv

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
Copy

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);
Copy

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);
Copy

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);
Copy

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);
Copy

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);
Copy