Мы используем базу данных Oracle 12c и CentOS7 с OCCI для подключения. Мы пытаемся вставить массив символов в базу данных, но этот массив символов имеет символ NUL посередине. Когда мы используем функцию statement->setString, обновление выполняется успешно, однако, как только оно увидит символ NUL, оно помещает туда только символы NUL. См. этот пример кода и его вывод.
Пример кода с использованием setString:
static void Run(const std::string &connectionString, const std::string &user, const std::string &pwd)
{
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection(user, pwd, connectionString);
Statement *stmt = conn->createStatement("UPDATE my_customers SET first_name = :1 WHERE customer_id = :2");
stmt->setString(1, std::string("GEO\0RGE ", 20));
stmt->setInt(2, 10);
stmt->setString(1, std::string(adrs_first_name, sizeof(adrs_first_name)));
oracle::occi::Statement::Status status = stmt->execute();
conn->terminateStatement(stmt);
conn->commit();
}
Доступ к базе данных после обновления:
SELECT first_name FROM my_customers WHERE customer_id = 10;
GEO
SELECT rawtohex(first_name) FROM my_customers WHERE customer_id = 10;
47454F0000000000000000000000000000000000
Однако я ожидал, что это будет
47454F0047452032322020202020202020202020
Итак, я попытался использовать oracle::occi::Bytes - эта ошибка с
ORA – 12899: слишком большое значение для столбца "MAIN_USER"."MY_CUSTOMERS"."FIRST_NAME" (фактическое: 40, максимальное: 20)
Пример кода с использованием setBytes:
static void Run(const std::string &connectionString, const std::string &user, const std::string &pwd)
{
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection(user, pwd, connectionString);
Statement *stmt = conn->createStatement("UPDATE my_customers SET first_name = :1 WHERE customer_id = :2");
std::string s("GEO\0RGE ", 20);
oracle::occi::Bytes bytes((unsigned char *)s.c_str(), 20, 0, env);
stmt->setBytes(1, bytes);
stmt->setInt(2, 10);
try
{
oracle::occi::Statement::Status status = stmt->execute();
}
catch (oracle::occi::SQLException &e)
{
std::cout << "Error " << e.getErrorCode() << ": " << e.what() << std::endl;
}
conn->terminateStatement(stmt);
conn->commit();
}
Вывод:
Error 12899 : ORA - 12899 : value too large for column "MAIN_USER"."MY_CUSTOMERS"."FIRST_NAME" (actual : 40, maximum : 20)
Итак, я попытался отправить половину байтов, изменив второй параметр конструктора oracle::occi::Bytes на 10, и это удалось, однако после чтения значения из базы данных я понял, что это строковое представление шестнадцатеричного значения символы. Итак, мой вопрос на данный момент: почему Oracle12c помещает шестнадцатеричное значение в виде строки, когда я передаю oracle::occi:Bytes.
Пример кода с использованием половины фактической длины и setBytes:
static void Run(const std::string &connectionString, const std::string &user, const std::string &pwd)
{
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection(user, pwd, connectionString);
Statement *stmt = conn->createStatement("UPDATE my_customers SET first_name = :1 WHERE customer_id = :2");
std::string s("GEO\0RGE ", 20);
oracle::occi::Bytes bytes((unsigned char *)s.c_str(), 10, 0, env);
stmt->setBytes(1, bytes);
stmt->setInt(2, 10);
try
{
oracle::occi::Statement::Status status = stmt->execute();
}
catch (oracle::occi::SQLException &e)
{
std::cout << "Error " << e.getErrorCode() << ": " << e.what() << std::endl;
}
conn->terminateStatement(stmt);
conn->commit();
}
Доступ к базе данных после обновления: SELECT first_name FROM my_customers WHERE customer_id = 10;
47454F00524745202020
ПРИМЕЧАНИЕ. Этот запрос не был преобразован в rawtohex — это фактическое значение массива символов в базе данных.
Вот определение таблицы:
DESCRIBE MAIN_USER.MY_CUSTOMERS
Name Null Type
------------------------------ ---- --------------
CUSTOMER_ID NUMBER(10)
FIRST_NAME CHAR(20 CHAR)
Вот информация о нашем экземпляре Oracle: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 — 64-битная рабочая версия с опциями секционирования, реальных кластеров приложений, автоматического управления хранилищем, OLAP, расширенной аналитики и тестирования реальных приложений.
Мы используем клиент Oracle occi 12.1 64bit.
std::string
поддерживает символы NULL. Проблема в том, что вы делаете предположение о том, как работаетsetString
, когда дана строка с нулевым символом, а длина выходит за пределы нулевого символа. Если в документах для этой функции явно не указано, что она делает, или у вас нет исходного кода этой функции, вы не можете предположить, как она обрабатывает строку. Даже если setString действительно делает то, что вы говорите, как база данных обрабатывает управляющие символы внутри типовCHAR
? Чтобы облегчить это, вы можете сохранить строку в кодировке Base64. Вот для чего создан Base64. - person PaulMcKenzie   schedule 08.06.2016CHAR
, а не проблема occi или selectString. - person PaulMcKenzie   schedule 08.06.2016