Prise en charge de l’API de pilote ODBC¶
Le pilote Snowflake ODBC prend en charge la version 3.52 de l’ODBC API. Ce chapitre répertorie les routines ODBC pertinentes pour Snowflake, et indique si elles sont prises en charge. Les routines sont organisées en catégories en fonction de la fonction qu’elles remplissent.
Pour la référence API complète , voir Microsoft ODBC Programmer’s Reference.
Dans ce chapitre :
Connexion à une source de données¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
Obtention d’informations sur un pilote et une source de données¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Définition et récupération des attributs du pilote¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
Le paramètre SQL_ATTR_METADATA_ID affecte uniquement les fonctions SQLTables et SQLColumns (et non les autres fonctions de catalogue prises en charge). |
|
✔ |
Le mode lecture seule n’est pas pris en charge. SQL_MODE_READ_ONLY est transmis au pilote, mais Snowflake écrit toujours dans la base de données. . . De plus, certains attributs ont été introduits après la version 3.52 de l’API : 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. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
|
|
✔ |
L’attribut SQL_ATTR_CONNECTION_POOLING a été introduit après la version 3.52 de l’API ODBC et n’est pas pris en charge. |
|
✔ |
SQL_ATTR_CURSOR_SCROLLABLE prend uniquement en charge une valeur SQL_NONSCROLLABLE. . SQL_ATTR_USE_BOOKMARKS prend uniquement en charge une valeur SQL_UB_OFF. . . Pour des raisons de compatibilité avec les outils tiers, SQL_ATTR_ENABLE_AUTO_IPD est défini par défaut sur true, même si la norme ODBC indique qu’il devrait par défaut être false. Pour changer la valeur par défaut en false, réglez le paramètre EnableAutoIpdByDefault sur |
|
✔ |
Outre les attributs standard, l’implémentation Snowflake prend en charge l’attribut SQL_SF_STMT_ATTR_LAST_QUERY_ID, qui permet à l’utilisateur de récupérer l’ID de requête le plus récent associé au descripteur d’instructions spécifié. Un exemple partiel est présenté dans la section Exemples ci-dessous. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. Remplacé par |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. Remplacé par |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. Remplacé par |
Chacune des fonctions précédentes a une fonction correspondante qui accepte les caractères larges (unicode). Chacune de ces fonctions unicode porte le nom indiqué ci-dessus, suivi de « W ». Par exemple, la fonction SQLGetStmtAttr
, qui accepte un tableau de caractères en tant que troisième paramètre, a une fonction correspondante appelée SQLGetStmtAttrW
, qui accepte un tableau wchar en tant que troisième paramètre.
Comportement spécifique à Snowflake¶
SQLSetConnectAttr
Cette méthode prend en charge deux attributs spécifiques à Snowflake :
Nom d’attribut
Description
SQL_SF_CONN_ATTR_APPLICATION
Cela remplace la valeur spécifiée par le paramètre APPLICATION dans le registre ou le fichier .ini.
SQL_SF_CONN_ATTR_PRIV_KEY
Il s’agit d’un pointeur EVP_PKEY* qui pointe vers une copie en mémoire de la clé privée. Cela remplace les paramètres PRIV_KEY_FILE et PRIV_KEY_PWD du registre ou du fichier .ini. Snowflake recommande d’utiliser cet attribut pour définir la clé privée.
Définition et récupération de champs descripteurs¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Préparation de requêtes SQL¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans l’API ODBC. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 2.x de l’API ODBC. Remplacé par |
Note
Il existe une limite supérieure à la taille des données que vous pouvez lier. Pour plus de détails, voir Limites de la taille du texte de requête.
Instructions SQL prises en charge pour la préparation liste les types d’instructions SQL qui sont pris en charge pour la préparation.
Soumission de requêtes¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Quel que soit le type de données lié au paramètre, Snowflake effectue une conversion côté serveur et retourne un VARCHAR avec une longueur maximale de 16777216. |
|
✔ |
|
|
✔ |
La prise en charge de cette fonction a été ajoutée dans la version 2.23.3 du pilote ODBC. |
|
✔ |
La prise en charge de cette fonction a été ajoutée dans la version 2.23.3 du pilote ODBC. |
Récupération de résultats et d’informations sur les résultats¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
Le pilote ODBC ne prend pas actuellement en charge les données semi-structurées, notamment les types de données |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. Remplacé par |
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Pour les colonnes GEOGRAPHY , |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 2.x de l’API ODBC. Remplacé par |
|
✔ |
|
|
✔ |
L’argument |
|
Remplacé par |
|
|
Snowflake ne prend pas en charge cette fonctionnalité. |
|
|
Snowflake ne prend pas en charge cette fonctionnalité. |
Obtention d’informations sur les tables système de la source de données (fonctions du catalogue)¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
Renvoie un ensemble de résultats vide. |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Dans le jeu de résultats, la colonne |
|
Renvoie un ensemble de résultats vide. |
|
|
Renvoie un ensemble de résultats vide. |
|
|
Renvoie un ensemble de résultats vide. |
|
|
✔ |
Si le paramètre transmis à la fonction est « TABLE », la fonction renvoie tous les types de tables, y compris les tables transitoires et les tables temporaires. . . Si le paramètre transmis à la fonction est « VIEW », la fonction renvoie tous les types de vues, y compris les vues matérialisées. . . Si le paramètre transmis à la fonction est « TABLE, VIEW » ou « % », la fonction renvoie des informations sur tous les types de tables et tous les types de vues. |
Si le nom transmis à la fonction de catalogue a un caractère non valide ou si le nom ne correspond à aucun objet de base de données, la fonction renvoie un jeu de résultats vide.
Le paramètre SQL_ATTR_METADATA_ID
affecte uniquement les fonctions SQLTables
, SQLColumns
, et SQLProcedures
.
Mettre fin à une instruction¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. Remplacé par |
Mettre fin à une connexion¶
Nom de la fonction |
Pris en charge |
Remarques |
---|---|---|
|
Introduit dans l’API après la version 3.52. |
|
|
✔ |
|
|
✔ |
|
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
|
✔ |
Pris en charge par le pilote Snowflake, mais obsolète dans la version 3.x de l’API ODBC. |
Types de données SQL personnalisés¶
Certains types de données SQL pris en charge par Snowflake n’ont pas de mappage direct dans ODBC (par exemple, TIMESTAMP_*tz, VARIANT). Pour permettre au pilote ODBC de fonctionner avec les types de données non pris en charge, le fichier d’en-tête fourni avec le pilote inclut les définitions des types de données personnalisés suivants :
////////////////////////////////////////////////////////////////////////////////////////////////////
/// 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
Le code suivant illustre un exemple d’utilisation des types de données personnalisés :
// 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);
Exemples¶
Cette section fournit des exemples d’utilisation de l’API.
Récupération de l’ID de la dernière requête¶
La récupération de l’ID de la dernière requête est une extension Snowflake au standard ODBC.
Pour récupérer l’ID de la dernière requête, appelez la fonction SQLGetStmtAttr
(ou SQLGetStmtAttrW
) en transmettant l’attribut SQL_SF_STMT_ATTR_LAST_QUERY_ID et un tableau de caractères suffisamment grand pour contenir l’ID de requête.
L’exemple ci-dessous montre comment récupérer l’ID de requête pour une requête :
// 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);
Si vous travaillez sous Linux ou macOS, appelez SQLGetStmtAttrW
et transmettez les paramètres du type de données approprié (par exemple, « wchar » plutôt que « char »).
Meilleures pratiques pour améliorer les performances lors de la récupération de données¶
Lorsque vous récupérez des données avec SQLFetch
, vous pouvez utiliser les fonctions SQLGetData
ou SQLBindCol
pour accéder au contenu des cellules. Dans la plupart des cas, l’utilisation de SQLBindCol
offre de meilleures performances en raison de la réduction du nombre d’appels ODBC que vous devez effectuer pour récupérer des données et parce que cela vous permet de tirer parti de la copie des données en mémoire.
Utilisation de SQLGetData
pour récupérer des données de cellule¶
L’exemple suivant utilise la fonction SQLGetData
pour récupérer les valeurs des cellules du tampon de données renvoyé par SQLFetch
. Notez que vous devez appeler SQLGetData
une fois pour chaque cellule de la ligne.
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);
Utilisation de SQLBindCol
pour lier les colonnes d’une ligne de données¶
L’exemple suivant utilise la fonction SQLBindCol
pour récupérer les valeurs des cellules du tampon de données renvoyé par SQLFetch
. Un tampon est créé en mémoire pour le nombre de colonnes d’une ligne, puis un appel SQLBindCol
unique est effectué pour lier les tampons de l’application au jeu de résultats. Enfin, un appel SQLFetch
se produit une fois par ligne, avec le chargement des valeurs des cellules dans le tampon. Cette approche peut augmenter considérablement la vitesse et l’efficacité de la récupération des données.
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);
Utilisation de SQLBindCol
pour lier les colonnes de plusieurs lignes de données¶
Vous pouvez encore améliorer les performances en extrayant plusieurs lignes en un seul appel SQLFetch
, ce qui réduit le nombre d’appels ODBC SQLFetch
nécessaires pour traiter toutes les lignes d’une table de requête.
L’exemple suivant :
Détermine le nombre de colonnes dans le jeu de résultats.
Crée un tableau en mémoire pour stocker les données de plusieurs colonnes.
Appelle
SQLBindCol
pour chaque colonne afin de lier les tampons de l’application au jeu de résultats.Appelle
SQLFetch
pour obtenir le nombre de lignes spécifié (100) et traite les données dans le tampon en mémoire sans faire d’appels ODBC, jusqu’à ce que la fin de la table de requête soit atteinte.
Cette approche peut augmenter considérablement la vitesse et l’efficacité de la récupération des données. Pour une table de requête comportant 20 colonnes et 1 000 lignes, cet exemple n’effectuerait que 20 appels SQLBindCol
et 10 appels SQLFetch
au lieu de 20 000 appels SQLGetData
pour charger toutes les données de la table.
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);