设置 ODBC 会话的区域设置和编码

Vertica 提供以下方法来设置 ODBC 会话的区域设置和编码:

  • 使用 DSN 指定所有已建立的连接的区域设置:

  • SQLDriverConnect() 函数的连接字符串中设置 Locale 连接参数。例如:

    SQLDriverConnect(conn, NULL, (SQLCHAR*)"DSN=Vertica;Locale=en_GB@collation=binary", SQL_NTS, szConnOut, sizeof(szConnOut), &iAvailable, SQL_DRIVER_NOPROMPT)
    
  • 使用 SQLSetConnectAttr() 设置编码和区域设置。通常,您应该始终使用此函数设置编码,而不是在 DSN 中设置它。

    • 传递 SQL_ATTR_VERTICA_LOCALE 常量和 ICU 字符串作为属性值。例如:

      => SQLSetConnectAttr(hdlDbc, SQL_ATTR_VERTICA_LOCALE, (SQLCHAR*)newLocale,
              SQL_NTS);
      
    • 传递 SQL_ATTR_AP_WCHAR_TYPE 常量和编码作为属性值。例如:

      => rc = SQLSetConnectAttr (hdbc, SQL_ATTR_APP_WCHAR_TYPE, (void *)SQL_DD_CP_UTF16, SQL_IS_INTEGER);
      

注意

  • 如果让客户端系统使用非 Unicode 区域设置(例如,在 Linux 平台上设置 LANG=C)并对与 Vertica 的连接使用 Unicode 区域设置,则会生成诸如“(10170) 来自数据源的数据进行字符串数据右截断 (String data right truncation on data from data source)”等错误。如果从 Vertica 收到的数据不采用 UTF-8 格式,驱动程序将基于系统的区域设置来分配字符串内存,并且非 UTF-8 数据会触发超限。如果始终在客户端系统上使用 Unicode 区域设置,您可以避免这些错误。

    如果在连接字符串或 DSN 中指定区域设置,调用连接函数将返回有关成功连接的 SQL_SUCCESS_WITH_INFO,并显示有关区域设置状态的消息。

  • ODBC 应用程序可以处于 ANSI 模式或 Unicode 模式:

    • 如果处于 Unicode 模式,则 ODBC 使用的编码是 UCS-2。

    • 如果处于 ANSI 模式,则数据必须采用单字节 ASCII 编码,此编码与数据库服务器上的 UTF-8 兼容。

    向 Vertica 服务器传递数据时,ODBC 驱动程序会将 UCS-2 转换为 UTF-8,并会将 Vertica 服务器发来的数据从 UTF-8 转换为 UCS-2。

  • 如果最终用户应用程序尚未处于 UCS-2 编码模式,则应用程序应负责将输入数据转换为 UCS-2,否则会出现意外结果。例如:

    • 向 ODBC API 传递非 UCS-2 数据时,如果该数据解释为 UCS-2,将导致向 API 传递无效的 UCS-2 符号,从而生成错误。

    • 或者在备用编码中提供的符号可能是有效的 UCS-2 符号;在这种情况下,会将不正确的数据插入到数据库。

    ODBC 应用程序应使用 SQLSetConnectAttr 设置正确的服务器会话区域设置(如果与数据库范围设置不同),以便在服务器上设置正确的排序规则和字符串函数行为。

以下示例代码演示了同时使用连接字符串和 SQLSetConnectAttr() 函数来设置区域设置。

// Standard i/o library
#include <stdio.h>
#include <stdlib.h>
// Only needed for Windows clients
// #include <windows.h>
// SQL include files that define data types and ODBC API
// functions
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
// Vertica-specific definitions. This include file is located as
// /opt/vertica/include on database hosts.
#include <verticaodbc.h>
int main()
{
    SQLRETURN ret;   // Stores return value from ODBC API calls
    SQLHENV hdlEnv;  // Handle for the SQL environment object
    // Allocate an a SQL environment object
    ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hdlEnv);
    if(!SQL_SUCCEEDED(ret)) {
        printf("Could not allocate a handle.\n");
        exit(EXIT_FAILURE);
    } else {
        printf("Allocated an environment handle.\n");
    }
    // Set the ODBC version we are going to use to 3.
    ret = SQLSetEnvAttr(hdlEnv, SQL_ATTR_ODBC_VERSION,
        (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);
    if(!SQL_SUCCEEDED(ret)) {
        printf("Could not set application version to ODBC 3.\n");
        exit(EXIT_FAILURE);
    } else {
        printf("Set application version to ODBC 3.\n");
    }
    // Allocate a database handle.
    SQLHDBC hdlDbc;
    ret = SQLAllocHandle(SQL_HANDLE_DBC, hdlEnv, &hdlDbc);
    if(!SQL_SUCCEEDED(ret)) {
        printf("Could not allocate database handle.\n");
        exit(EXIT_FAILURE);
    } else {
        printf("Allocated Database handle.\n");
    }
    // Connect to the database using SQLDriverConnect
    printf("Connecting to database.\n");
    // Set the locale to English in Great Britain.
    const char *connStr = "DSN=ExampleDB;locale=en_GB;"
        "UID=dbadmin;PWD=password123";
    ret = SQLDriverConnect(hdlDbc, NULL, (SQLCHAR*)connStr, SQL_NTS,
               NULL, 0, NULL, SQL_DRIVER_NOPROMPT );
    if(!SQL_SUCCEEDED(ret)) {
        printf("Could not connect to database.\n");
        exit(EXIT_FAILURE);
    } else {
        printf("Connected to database.\n");
    }
    // Get the Locale
    char locale[256];
    SQLGetConnectAttr(hdlDbc, SQL_ATTR_VERTICA_LOCALE, locale, sizeof(locale),
        0);
    printf("Locale is set to: %s\n", locale);
    // Set the locale to a new value
    const char* newLocale = "en_GB";
    SQLSetConnectAttr(hdlDbc, SQL_ATTR_VERTICA_LOCALE, (SQLCHAR*)newLocale,
        SQL_NTS);

    // Get the Locale again
    SQLGetConnectAttr(hdlDbc, SQL_ATTR_VERTICA_LOCALE, locale, sizeof(locale),
        0);
    printf("Locale is now set to: %s\n", locale);

    // Set the encoding
    SQLSetConnectAttr (hdbc, SQL_ATTR_APP_WCHAR_TYPE, (void *)SQL_DD_CP_UTF16,
        SQL_IS_INTEGER);

    // When done, free all of the handles to close them
    // in an orderly fashion.
    printf("Disconnecting and freeing handles.\n");
    ret = SQLDisconnect( hdlDbc );
    if(!SQL_SUCCEEDED(ret)) {
        printf("Error disconnecting from database. Transaction still open?\n");
        exit(EXIT_FAILURE);
    }
    SQLFreeHandle(SQL_HANDLE_DBC, hdlDbc);
    SQLFreeHandle(SQL_HANDLE_ENV, hdlEnv);
    exit(EXIT_SUCCESS);
}