gpt4 book ai didi

c++ - Oracle ODBC 插入失败,没有任何错误诊断

转载 作者:行者123 更新时间:2023-11-30 05:19:54 26 4
gpt4 key购买 nike

我正在执行一个简单的 INSERT 语句,其中一个参数 ( SQL_BIGINT ) 使用 SQLBindParameter 绑定(bind)功能。执行失败,但没有错误诊断。命令看起来像这样:

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 绑定(bind))执行时没有任何问题。并且错误诊断检索在其他方面完全正常。例如,当试图删除一个不存在的表时,它会正确返回:

[42S02] (native 942): [Oracle][ODBC][Ora]ORA-00942: table or view does not exist

但是在这里,没有任何返回。

你们有没有遇到过执行命令失败但没有可用的错误诊断的问题?

我在 Xubuntu 16.04 64 位上使用“Oracle 12c ODBC 驱动程序”(即时客户端 12.1.0.2.0)。使用 ODBC 版本 3。该数据库是在 CentOS 7 上运行的“Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 64bit”。

相同的代码在 PostgreSQL 9.2.15(驱动程序“PostgreSQL Unicode”9.3.300)上运行良好,

和 MySQL 5.5.50(驱动程序“MySQL ODBC 5.3 Unicode 驱动程序”5.3.6)。

最佳答案

我终于在 this other question 中找到了发生这种情况的原因。显然是 Oracle ODBC 驱动程序 doesn't support binding of BIGINT parameters 。糟糕的是,它不会为您提供有关失败原因的任何错误信息。

因此,如果您想使用 64 位整数参数(SQL_C_UBIGINTSQL_C_SBIGINT),您必须将它们绑定(bind)为字符串,如本例所示:

int64_t val = 123456789;
char* cstr = convert_to_string(val);
size_t len = strlen(cstr);
SQLLEN ind = len;
SQLRETURN ret = SQLBindParameter(hstmt, column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, len, 0, cstr, len, &ind);

关于c++ - Oracle ODBC 插入失败,没有任何错误诊断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40936038/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com