ODBC ドライバー API サポート

Snowflake ODBC ドライバーは、 ODBC API のバージョン3.52をサポートしています。このトピックでは、Snowflakeに関連する ODBC ルーチンをリストし、それらがサポートされているかどうかを示します。ルーチンは、実行する機能に基づいてカテゴリに分類されます。

完全な API リファレンスについては、 Microsoft 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 属性は、 ODBCAPI バージョン3.52の後に導入されており、サポートされていません。

SQLSetStmtAttr

SQL_ATTR_CURSOR_SCROLLABLE は、SQL_NONSCROLLABLE 値のみをサポートします。 . SQL_ATTR_USE_BOOKMARKS は、SQL_UB_OFF 値のみをサポートします。 . . サードパーティツールとの互換性のために、ODBC 標準ではデフォルトはfalseであると規定されていますが、SQL_ATTR_ENABLE_AUTO_IPD はデフォルトでtrueに設定されています。デフォルト値を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」が付いています。例えば、3番目のパラメーターとしてchar配列を受け入れる関数 SQLGetStmtAttr には、3番目のパラメーターとしてwchar配列を受け入れる SQLGetStmtAttrW という名前の対応する関数があります。

Snowflake固有の動作

  • SQLSetConnectAttr

    このメソッドは、次の2つの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

SQLError

Snowflakeドライバーによりサポートされていますが、 ODBC API バージョン3.xでは非推奨です。 SQLGetDiagRec に置き換えられました。

SQLGetData

SQLGetDiagField

SQLGetDiagRec

SQLRowCount

SQLNumResultCols

SQLDescribeCol

SQLColAttribute

GEOGRAPHY 列に対して、 SQL_DESC_TYPE_NAMEGEOGRAPHY を返します。他の記述子(例: 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の列の値)が含まれています。 . . Snowflakeのストアドプロシージャは出力パラメータをサポートしていないため、 NUM_OUTPUT_PARAMS 列には NULL 値が含まれています。 . . Snowflakeのストアドプロシージャは結果セットを返さないため、 NUM_RESULT_SETS 列には NULL 値も含まれます。 . . Snowflakeのストアドプロシージャは常に値を返すため、 PROCEDURE_TYPE 列には常に SQL_PT_FUNCTION が含まれます。

SQLSpecialColumns

空の結果セットを返します。

SQLStatistics

空の結果セットを返します。

SQLTablePrivileges

空の結果セットを返します。

SQLTables

関数に渡されるパラメーターが「TABLE」の場合、関数は一時テーブルや仮テーブルを含むすべてのタイプのテーブルを返します。 . . 関数に渡されるパラメーターが「VIEW」の場合、関数はマテリアライズドビューを含むすべてのタイプのビューを返します。 . . 関数に渡されるパラメーターが「TABLE、VIEW」または「%」の場合、関数はすべてのタイプのテーブルとすべてのタイプのビューに関する情報を返します。

カタログ関数に渡された名前に無効な文字がある場合、または名前がどのデータベースオブジェクトとも一致しない場合、関数は空の結果セットを返します。

SQL_ATTR_METADATA_ID の設定は、 SQLTables 関数、 SQLColumns 関数、および SQLProcedures 関数のみに影響します。

ステートメントの終了

関数名

サポート対象

メモ

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

次のコードは、カスタムデータ型の使用例を示しています。

// 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 の取得は、 ODBC 標準のSnowflake拡張機能です。

最後のクエリ 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 を呼び出して、適切なデータ型のパラメーター(たとえば、「char」ではなく「wchar」)を渡します。

データを取得する際のパフォーマンスを向上させるためのベストプラクティス

SQLFetch でデータを取得する場合は、 SQLGetData または SQLBindCol 関数を使用してセルの内容にアクセスできます。ほとんどの場合、 SQLBindCol を使用すると、データを取得するために必要な ODBC 呼び出しの数が減り、メモリ内のデータのコピーを利用できるため、パフォーマンスが向上します。

SQLGetData の使用によるセルデータの取得

次の例では、 SQLGetData 関数を使用して、 SQLFetch によって返されたデータバッファーからセル値を取得します。行のセルごとに SQLGetData を1回呼び出す必要があることに注意してください。

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 の使用による1行のデータ列のバインド

次の例では、 SQLBindCol 関数を使用して、 SQLFetch によって返されたデータバッファーからセル値を取得します。行にある列数のメモリ内バッファーを作成して、 SQLBindCol を1回呼び出し、アプリケーションバッファーを結果セットにバインドします。最後に、行ごとに SQLFetch を1回呼び出し、セルの値をバッファーにロードします。このアプローチにより、データの取得速度と効率を大幅に向上させることができます。

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 を1回呼び出して複数の行をフェッチすると、パフォーマンスをさらに向上させることができます。これにより、クエリテーブルのすべての行を処理するために必要な ODBC SQLFetch 呼び出しの数が減ります。

次の例では、

  • 結果セットの列数を決定します。

  • 複数列からのデータを保存するためのメモリ内配列を作成します。

  • 各列に対して SQLBindCol を呼び出し、アプリケーションバッファーを結果セットにバインドします。

  • SQLFetch を呼び出して、指定された行数(100)を取得し、クエリテーブルの最後に到達するまで ODBC を呼び出さずに、メモリ内バッファーにあるデータを処理します。

このアプローチにより、データの取得速度と効率を大幅に向上させることができます。20列と1000行のクエリテーブルの場合、この例では、すべてのテーブルデータを読み込むために SQLGetData を20000回呼び出すのではなく、 SQLBindCol を20回、 SQLFetch を10回のみ呼び出します。

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