ODBC - 用C ++编写准备语句

时间:2017-12-08 22:57:36

标签: c++ sql c odbc

大家好,

学习如何开发ODBC SQL驱动程序和数据源的东西,但我似乎遇到了一些障碍。我目前正在使用以下语句处理数据库上的预准备语句:

select * from TEST1 where NAME = ? and LOCATION__LATITUDE__S = ?

在英语中,查找TEST1中具有待指定名称和纬度坐标的所有记录。我能够使用ODBCTest应用程序执行上述操作,因此我知道我可以连接到数据源并使用参数化查询进行查询。这就是我为有问题的功能编写的代码:

void ExecPreparedStatement(const char* stmt) {
    HSTMT hstmt;
    SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

    RETCODE rc = SQLPrepare(hstmt, (WCHAR*)stmt, SQL_NTS);

    SQLSMALLINT numParams;
    rc = SQLNumParams(hstmt, &numParams);

    WCHAR* param1 = (WCHAR*)L"Jacob";
    SQLFLOAT param2 = 40.0;

    rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 80, 0, (SQLPOINTER)param1, 300, NULL);
    rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, 0, 0, &param2, 300, NULL);

    rc = SQLExecute(hstmt); /* <fails here> */

    SQLSMALLINT numCols;
    SQLNumResultCols(hstmt, &numCols);

    DisplayRecords(hstmt, numCols);

    SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}

这个 应该从测试应用程序给出相同的结果:13个属性的3条记录(3行,13列)。相反,它在执行时失败了。为了便于阅读,我已经从代码中删除了所有RetCode处理,但我确实已经在那里检查语句是否已完成并在它们失败时正常处理它。这里肯定有一些我误解的东西 - 它还告诉我语句中的参数数量是0(使用numParams变量);我认为这是因为它应该放在执行调用之后,但我现在无法测试,因为我从未在执行中达到这一点。

有什么想法吗?我在这里的砖墙上敲我的头; MSDN和其他在线资源证明不足以提供相关信息。

对主要问题的澄清:有人知道为什么执行功能失败了吗?

找到答案

问题是错误的投射导致SQL格式错误。我没有将const char *字符串传递给函数,而是传入一个WCHAR *字符串,而在函数内部我使用了WCHAR *。功能代码现在看起来像这样:

HSTMT hstmt;

SQLAllocStmt(hdbc, &hstmt);

TryODBC(hstmt, SQL_HANDLE_STMT, SQLPrepare(hstmt, stmt, SQL_NTS));
// Prepare passes test - we return 0.

WCHAR* param1 = (WCHAR*)L"Jacob";

TryODBC(hstmt, SQL_HANDLE_STMT, 
    SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_WCHAR, 
        SQL_WVARCHAR, 80, 0, (SQLPOINTER)param1, 300, NULL)
);

TryODBC(hstmt, SQL_HANDLE_STMT, SQLExecute(hstmt));

SQLSMALLINT numCols;
TryODBC(hstmt, SQL_HANDLE_STMT, SQLNumResultCols(hstmt, &numCols));
DisplayRecords(hstmt, numCols);

SQLFreeStmt(hstmt, SQL_CLOSE);

TryODBC()的功能如下:

bool disconnectOnError = false;
if (rc == SQL_SUCCESS_WITH_INFO || rc == SQL_ERROR) {
    if (!Success(rc)) {
        disconnectOnError = true;
    }
    SQLWCHAR       state[6], errorMsg[SQL_MAX_MESSAGE_LENGTH];
    SQLINTEGER    nativeError;
    SQLSMALLINT   i = 1, msgLen;

    while ((rc = SQLGetDiagRec(handleType, handle, i, state, 
        &nativeError, errorMsg, sizeof(errorMsg), &msgLen)) != SQL_NO_DATA)
    {
        ShowMessage(nativeError, errorMsg);
        i++;
    }
}
if (disconnectOnError) {
    Disconnect(-1);
}

非常感谢@erg指导我使用SQLGetDiagRec()函数。

2 个答案:

答案 0 :(得分:1)

您正在传递一个宽字符串,但指定SQL_C_CHAR作为参数类型,这应该是SQL_C_WCHAR。

300,因为您的BufferLength参数没有意义,因为字符串参数传递正确的字节数,因为param2只传递0(对于非字符或二进制字符串数据,忽略BufferLength)。

并且您确实需要在每次ODBC调用之后检查错误代码,如果它是错误转储诊断程序。要么是这样,要么打开跟踪连接属性并查看结果。

答案 1 :(得分:0)

原始问题中提到的答案。