Using the ODBC Driver

This topic provides information about how to use the ODBC driver.

In this Topic:

Compiling Your Code

Linux

  • If a C/C++ application is built with the Snowflake ODBC driver library and loads a non-pthread-compatible library, the application could crash due to unsafe concurrent access to shared memory. To prevent this, compile the application with the option which ensures that only pthread-compatible libraries are loaded with the application.

    For gcc/g++, the option is “-pthread”.

macOS

  • If a C/C++ application is built with the Snowflake ODBC driver library and loads a non-pthread-compatible library, the application could crash due to unsafe concurrent access to shared memory. To prevent this, compile the application with the option which ensures that only pthread-compatible libraries are loaded with the application.

    For clang/clang++, the option is “-pthread”.

Executing a Batch of SQL Statements (Multi-Statement Support)

In ODBC, you can send a batch of SQL statements (separated by semicolons) to be executed in a single request. For example:

// Sending a batch of SQL statements to be executed
rc = SQLExecDirect(hstmt,
     (SQLCHAR *) "select c1 from t1; select c2 from t2; select c3 from t3",
     SQL_NTS);

To send a batch of statements with the Snowflake ODBC Driver, you must specify the number of statements in the batch. The Snowflake database requires the exact number of statements in order to guard against SQL injection attacks.

The next section explains how to specify the number of statements in a batch.

Specifying the Number of Statements in a Batch

By default, the Snowflake database expects the driver to prepare and send a single statement for execution.

You can override this by specifying the number of statements in a batch for a given request or by enabling multiple statements for the current session or account:

  • To specify the number for a given request, call SqlSetStmtAttr to set the SQL_SF_STMT_ATTR_MULTI_STATEMENT_COUNT attribute to the number of statements in the batch.

    // Specify that you want to execute a batch of 3 SQL statements
    rc = SQLSetStmtAttr(hstmt, SQL_SF_STMT_ATTR_MULTI_STATEMENT_COUNT, (SQLPOINTER)3, 0);
    

    If you want to use the setting for the current session or account (rather than specify the number for the request), set SQL_SF_STMT_ATTR_MULTI_STATEMENT_COUNT to -1.

  • To enable multiple statements for the current session or account, alter the session or account, and set the Snowflake MULTI_STATEMENT_COUNT parameter to 0.

    -- Specify that you want to execute batches of multiple SQL statements
    -- for the current session.
    alter session set MULTI_STATEMENT_COUNT = 0;
    
     -- Specify that you want to execute batches of multiple SQL statements
     -- for the current account.
    alter account <account> set MULTI_STATEMENT_COUNT = 0;
    

    By default, MULTI_STATEMENT_COUNT is set to 1, which indicates that only one SQL statement can be executed.

    Note: Setting the MULTI_STATEMENT_COUNT parameter at the account level also affects other Snowflake connectors and drivers that use the account (e.g. the Snowflake JDBC Driver).

Preparing a Batch of SQL Statements

The ODBC Driver supports the ability to prepare a batch of SQL statements (e.g. by calling the SQLPrepare function). Note the following:

  • If the statements have parameters, calling the SQLNumParams function returns the total number of parameters in all the statements in the batch.

  • Column information about the result set (e.g. data returned by SQLNumResultCols, SQLDescribeCol, SQLColAttribute and SQLColAttributes) is not available until you call SQLExecute or SQLExecDirect. (Just calling SQLPrepare does not make this information available.)

Limitations

GET and PUT commands are not supported in batches of SQL statements. When you send a batch of SQL statements with GET and PUT comments to be executed, the GET and PUT commands are ignored, and no errors are reported.

Binding Parameters to Array Variables For Batch Inserts

In your application code, you can insert multiple rows in a single batch by binding parameters in an INSERT statement to array variables.

As an example, the following code inserts rows into a table that contains an INTEGER column and a VARCHAR column. The example binds arrays to the parameters in the INSERT statement.

SQLCHAR * Statement = "INSERT INTO t (c1, c2) VALUES (?, ?)";

SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, ARRAY_SIZE, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_STATUS_PTR, ParamStatusArray, 0);
SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMS_PROCESSED_PTR, &ParamsProcessed, 0);
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 5, 0,
                 IntValuesArray, 0, IntValuesIndArray);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, STR_VALUE_LEN - 1, 0,
                 StringValuesArray, STR_VALUE_LEN, StringValuesLenOrIndArray);
...
SQLExecDirect(hstmt, Statement, SQL_NTS);

When you use this technique to insert a large number of values, the driver can improve performance by sending the data to a temporary stage for ingestion. The driver automatically does this when the number of values exceeds a threshold.

In order for the driver to send the data to a temporary stage, the user must have the following privilege on the schema:

  • CREATE STAGE.

If the user does not have this privilege, the driver falls back to sending the data with the query to the Snowflake database.

In addition, the current database and schema for the session must be set. If these are not set, the CREATE TEMPORARY STAGE command executed by the driver can fail with the following error:

CREATE TEMPORARY STAGE SYSTEM$BIND file_format=(type=csv field_optionally_enclosed_by='"')
Cannot perform CREATE STAGE. This session does not have a current schema. Call 'USE SCHEMA', or use a qualified name.

Note

For alternative ways to load data into the Snowflake database (including bulk loading using the COPY command), see Loading Data into Snowflake.