Я выполняю простой оператор INSERT с одним параметром (SQL_BIGINT
), связанным с помощью функции SQLBindParameter
. Выполнение не выполняется, но диагностика ошибок отсутствует. Команда выглядит следующим образом:Вставка Oracle ODBC не выполняется без ошибок.
INSERT INTO oracle_test_table (id) VALUES (?)
Если я использую SQLGetDiagField
получить SQL_DIAG_NUMBER
(отсчет диагностики ошибок) - это 0. И пытается получить диагностику с помощью SQLGetDiagRec
ничего не возвращает либо.
Минимальный пример:
#include <cstdint>
#include <cstdio>
#include <string>
#include <sql.h>
#include <sqlext.h>
/** Oracle ODBC insert fail without error diagnostic test.
* ======================================================
*
* compile with: g++ oracle_test.cpp -o oracle_test -lodbc -std=c++11
*/
// Extract error diagnostic.
void extractDiag(SQLSMALLINT handleType, SQLHANDLE& handle, std::string& s) {
SQLINTEGER i = 1;
SQLINTEGER native;
SQLCHAR state[7];
SQLCHAR text[512];
SQLSMALLINT len;
SQLRETURN ret;
while(true) {
ret = SQLGetDiagRecA(handleType, handle, i++, state, &native, text, sizeof(text), &len);
if (!SQL_SUCCEEDED(ret))
break;
s += "[";
s += reinterpret_cast<char*>(state);
s += "] (native ";
s += std::to_string(native);
s += "): ";
s += reinterpret_cast<char*>(text);
s += "; ";
}
}
// Allocate a statement handle.
int allocateStatement(SQLHDBC& dbConn, SQLHSTMT& stmt) {
SQLRETURN ret = SQLAllocHandle(SQL_HANDLE_STMT, dbConn, &stmt);
if (!SQL_SUCCEEDED(ret)) {
std::string s("statement allocation failed: \n");
extractDiag(SQL_HANDLE_DBC, dbConn, s);
fprintf(stderr, "%s\n", s.c_str());
return 1;
}
return 0;
}
int main() {
SQLRETURN ret;
SQLHENV env;
SQLHDBC dbConn;
SQLHSTMT stmt;
// Allocate an environment handle.
ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
// Use ODBC version 3.
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, 0);
// Allocate a connection handle.
ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbConn);
// Set connection attributes.
SQLSetConnectAttr(dbConn, SQL_ATTR_QUIET_MODE, 0, SQL_IS_POINTER);
SQLSetConnectAttr(dbConn, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)60, SQL_IS_UINTEGER);
SQLSetConnectAttr(dbConn, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER)60, SQL_IS_UINTEGER);
// Connection string.
char connStr[] = "UID=user;PWD=pass;DRIVER={Oracle 12c ODBC driver};Dbq=192.168.15.1:1521/dbora;"; // Oracle
//char connStr[] = "UID=user;PWD=pass;DRIVER={PostgreSQL Unicode};Server=192.168.15.1;Database=dbpg;"; // PostgreSQL
//char connStr[] = "UID=user;PWD=pass;DRIVER={MySQL ODBC 5.3 Unicode Driver};Server=192.168.15.1;Database=dbmy;"; // MySQL
// Connect.
ret = SQLDriverConnectA(dbConn, 0, reinterpret_cast<SQLCHAR*>(connStr), sizeof(connStr)-1, 0, 0, 0, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(ret)) {
std::string s("connection failed: \n");
extractDiag(SQL_HANDLE_DBC, dbConn, s);
fprintf(stderr, "%s\n", s.c_str());
return 1;
}
char dropTable[] = "DROP TABLE oracle_test_table";
char createTable[] = "CREATE TABLE oracle_test_table (id int)";
char insert[] = "INSERT INTO oracle_test_table (id) VALUES (?)";
// Drop table in case it exists.
if (allocateStatement(dbConn, stmt))
return 1;
ret = SQLExecDirectA(stmt, reinterpret_cast<SQLCHAR*>(dropTable), sizeof(dropTable)-1);
// could fail if there's no table... ignored
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
// Create new table.
if (allocateStatement(dbConn, stmt))
return 1;
ret = SQLExecDirectA(stmt, reinterpret_cast<SQLCHAR*>(createTable), sizeof(createTable)-1);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
// Allocate handle for the INSERT statement.
if (allocateStatement(dbConn, stmt))
return 1;
// Bind BIGINT parameter.
int64_t ival = 2;
ret = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, 19, 0, &ival, sizeof(int64_t), 0);
if (!SQL_SUCCEEDED(ret)) {
fprintf(stderr, "int binding failed\n");
return 1;
}
// Execute the INSERT statement.
ret = SQLExecDirectA(stmt, reinterpret_cast<SQLCHAR*>(insert), sizeof(insert)-1);
if (!SQL_SUCCEEDED(ret)) {
fprintf(stderr, "insert failed\n");
SQLULEN diagCount = 0;
ret = SQLGetDiagField(SQL_HANDLE_STMT, stmt, 0, SQL_DIAG_NUMBER, &diagCount, SQL_IS_UINTEGER, 0);
if (!SQL_SUCCEEDED(ret))
fprintf(stderr, "failed retrieving error diagnostic count\n");
else
fprintf(stderr, "error diagnostic count: %lu\n", diagCount);
std::string s("error diagnostics:\n");
extractDiag(SQL_HANDLE_STMT, stmt, s);
fprintf(stderr, "%s\n", s.c_str());
return 1;
}
return 0;
}
Другие команды, включая CREATE TABLE, DROP TABLE или INSERT со значениями непосредственно в команде (вместо того, чтобы связываться с помощью SQLBindParameter
) выполнить без каких-либо проблем. И обнаружение ошибок в противном случае работает совершенно нормально. Например, при попытке сбросить таблицу, которая не существует, она возвращает правильно:
[42S02] (native 942): [Oracle][ODBC][Ora]ORA-00942: table or view does not exist
Но здесь ничего не возвращается.
Неужели кто-то из вас столкнулся с этой проблемой, вызвавшей выполнение команды, но не существует диагностической диагностики?
Я использую «драйвер ODBC Oracle 12c» (Instant Client 12.1.0.2.0) на Xubuntu 16.04 64bit. ODBC версии 3. БД "Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 64bit" работает на CentOS 7.
же код работает отлично с PostgreSQL 9.2.15 (драйвер "PostgreSQL Unicode" 9.3.300),
и с MySQL 5.5.50 (драйвер "MySQL ODBC 5.3 Unicode Driver" 5.3.6).
ли вы фиксируете INSERT? Другие настройки автоматической фиксации? – jarlh
По умолчанию ODBC настроен на автоматическую фиксацию. Если вы установите auto-commit off, результат будет таким же. – omusil
Измените свой вопрос, чтобы включить инструкцию INSERT, которая не работает, код C++, который пытается обработать его, включая вызовы SQLBindParameter и т. Д. Спасибо. –