设置 ODBC 会话的区域设置和编码
Vertica 提供以下方法来设置 ODBC 会话的区域设置和编码:
-
使用 DSN 指定所有已建立的连接的区域设置:
-
在 Linux 和其他类 UNIX 平台上: 为 Linux 创建 ODBC DSN
-
在 Windows 平台上,在 ODBC DSN 配置编辑器的“服务器设置 (Server Settings)”选项卡上的“区域设置 (Locale)”字段中设置区域设置。有关详细信息,请参阅为 Windows 客户端创建 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);
}