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

Posted

技术标签:

【中文标题】Oracle ODBC 插入失败,没有任何错误诊断【英文标题】:Oracle ODBC insert fails without any error diagnostic 【发布时间】:2016-12-02 15:47:35 【问题描述】:

我正在执行一个简单的 INSERT 语句,其中一个参数 (SQL_BIGINT) 使用 SQLBindParameter 函数绑定。执行失败,但没有错误诊断。该命令如下所示:

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

但是在这里,什么都没有返回。

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

我在 Xubuntu 16.04 64 位上使用“Oracle 12c ODBC 驱动程序”(Instant Client 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)。

【问题讨论】:

您是否提交了 INSERT?其他自动提交设置? 默认情况下,ODBC 设置为自动提交。如果你设置自动提交关闭,结果是一样的。 请编辑您的问题以包含失败的 INSERT 语句、尝试处理它的 C++ 代码(包括 SQLBindParameter 调用等)。谢谢。 鲍勃·贾维斯,它就在那里。 在 *** 上发布问题时,您应该将代码直接放入问题中,而不是作为链接。谢谢。 【参考方案1】:

我终于找到了this other question 发生这种情况的原因。显然是 Oracle ODBC 驱动程序doesn't support binding of BIGINT parameters。不好的是,它只是没有给你任何关于失败原因的错误信息。

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

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);

【讨论】:

以上是关于Oracle ODBC 插入失败,没有任何错误诊断的主要内容,如果未能解决你的问题,请参考以下文章

使用 Oracle SQL Developer 测试 UCanAccess -> ODBC 错误

odbc 连接oracle数据库失败!

求救:jdbc_odbc链接oracle数据库失败,代码如下,运行后,显示:常连接到数据库。 但没有抓到资料。

如何在没有任何错误或警告的情况下找到构建失败的原因

为啥我的 ODBC 在添加新记录后立即失败?

ODBC数据库连接SQL Server失败?啥原因啊!~~