更新唯一标识列为 null 值时出现 ODBC 错误 'String data, right truncation'。

5

我试图将类型为 uniqueidentifier 的列更新为 null。我的 query 如下:

UPDATE table_name SET column_name = ?

该列绑定了:

SQLLEN _nullLen(SQL_NULL_DATA);

_rc = SQLBindParameter(_hstmt,          
    static_cast<SQLUSMALLINT>(1),   
    SQL_PARAM_INPUT,                    
    SQL_C_CHAR,                         
    SQL_VARCHAR,                        
    37,                         
    NULL,                               
    NULL,                               
    0,                                  
    &_nullLen);                         

执行query时出现ODBC错误“String data, right truncation”。使用完全相同的SQLBindParameter,我可以成功插入一个带有null数据的新行。为什么这不能用于更新行?


使用这段代码,我预计您会遇到无效的参数索引错误,因为索引从1开始。 - buszkiraly
很遗憾,这并不是解决方案。我使用一个计数器来作为索引,实际上第一个参数的索引从1开始。我会更新原始帖子。 - Sander Delfos
生成的SQL是什么样子?应该使用DBNULL.value而不是sql_null_data吗? - Eli
2个回答

2
请仔细阅读以下内容:
https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver15
根据该文档,SQLBindParameter的第6个参数是ColumnSize,您将其设置为37。为什么是这个值呢?
第8个参数是ParameterValuePtr,但您将其设置为NULL。 NULL是您要设置的值吗?
第10个参数是StrLen_or_IndPtr,您将其设置为&_nullLen,其中SQLLEN _nullLen(SQL_NULL_DATA),但它不应指向这种类型的内容。
请确保您理解每个传递给 SQLBindParameter() 的参数。

1
我怀疑您更新了多个列,而且截断不是在UNIQUEIDENTIFIER列上,而是在其他地方。我启动了我的旧版VS并编写了以下示例程序,它可以很好地更新为NULL。您可能需要添加跟踪以查看实际执行的内容。

#include "stdafx.h"
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <stdlib.h>
#include <sal.h>

#define TRYODBC(h, ht, x)   {   RETCODE rc = x;\
if (rc != SQL_SUCCESS) \
                                { \
                                HandleDiagnosticRecord(h, ht, rc); \
                                } \
if (rc == SQL_ERROR) \
                                { \
                                fwprintf(stderr, L"Error in " L#x L"\n"); \
                                goto Exit;  \
                                }  \
}

void HandleDiagnosticRecord(SQLHANDLE      hHandle,
    SQLSMALLINT    hType,
    RETCODE        RetCode);

int __cdecl wmain(int argc, _In_reads_(argc) WCHAR **argv)
{
    SQLHENV     hEnv = NULL;
    SQLHDBC     hDbc = NULL;
    SQLHSTMT    hStmt = NULL;
    WCHAR*      pwszConnStr;

    // Allocate an environment

    if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) == SQL_ERROR)
    {
        fwprintf(stderr, L"Unable to allocate an environment handle\n");
        exit(-1);
    }

    TRYODBC(hEnv,
        SQL_HANDLE_ENV,
        SQLSetEnvAttr(hEnv,
        SQL_ATTR_ODBC_VERSION,
        (SQLPOINTER)SQL_OV_ODBC3,
        0));

    // Allocate a connection
    TRYODBC(hEnv,
        SQL_HANDLE_ENV,
        SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc));

    pwszConnStr = L"";
    
    TRYODBC(hDbc,
        SQL_HANDLE_DBC,
        SQLDriverConnect(hDbc,
        GetDesktopWindow(),
        pwszConnStr,
        SQL_NTS,
        NULL,
        0,
        NULL,
        SQL_DRIVER_COMPLETE));

    fwprintf(stderr, L"Connected!\n");

    TRYODBC(hDbc,
        SQL_HANDLE_DBC,
        SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt));
        RETCODE     RetCode = NULL;
        SQLSMALLINT sNumResults;

        //Here be dragons
        SQLLEN _nullLen(SQL_NULL_DATA);
        SQLRETURN  _retcode = SQLBindParameter(hStmt, 1,
            SQL_PARAM_INPUT,
            SQL_C_CHAR,
            SQL_VARCHAR,
            37,
            NULL,
            NULL,
            0,
            &_nullLen);
        if (_retcode == -1)
        {
            HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, _retcode);
            return 1;
        }
        _retcode = SQLPrepare(hStmt, L"UPDATE zz SET v = ? ", SQL_NTS);
        if (_retcode == -1)
        {
            HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, _retcode);
            return 1;
        }
        RetCode= SQLExecute(hStmt);

        switch (RetCode)
        {
        case SQL_SUCCESS_WITH_INFO:
        {
            HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
            // fall through
                                      
        }
        case SQL_SUCCESS:
        {
            // If this is a row-returning query, display
            // results
            TRYODBC(hStmt,
                SQL_HANDLE_STMT,
                SQLNumResultCols(hStmt, &sNumResults));

            {
                SQLLEN cRowCount;

                TRYODBC(hStmt,
                    SQL_HANDLE_STMT,
                    SQLRowCount(hStmt, &cRowCount));

                if (cRowCount >= 0)
                {
                    wprintf(L"%Id %s affected\n",
                        cRowCount,
                        cRowCount == 1 ? L"row" : L"rows");
                }
            }
            break;
        }

        case SQL_ERROR:
        {
            HandleDiagnosticRecord(hStmt, SQL_HANDLE_STMT, RetCode);
            break;
        }

        default:
            fwprintf(stderr, L"Unexpected return code %hd!\n", RetCode);

        }
        TRYODBC(hStmt,
            SQL_HANDLE_STMT,
            SQLFreeStmt(hStmt, SQL_CLOSE));
        wprintf(L"Thanks for playing, type Enter to exit");
        getchar();

Exit:

    // Free ODBC handles and exit

    if (hStmt)
    {
        SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
    }

    if (hDbc)
    {
        SQLDisconnect(hDbc);
        SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
    }

    if (hEnv)
    {
        SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
    }

    wprintf(L"\nDisconnected.");

    return 0;

}

void HandleDiagnosticRecord(SQLHANDLE      hHandle,
    SQLSMALLINT    hType,
    RETCODE        RetCode)
{
    SQLSMALLINT iRec = 0;
    SQLINTEGER  iError;
    WCHAR       wszMessage[1000];
    WCHAR       wszState[SQL_SQLSTATE_SIZE + 1];


    if (RetCode == SQL_INVALID_HANDLE)
    {
        fwprintf(stderr, L"Invalid handle!\n");
        return;
    }

    while (SQLGetDiagRec(hType,
        hHandle,
        ++iRec,
        wszState,
        &iError,
        wszMessage,
        (SQLSMALLINT)(sizeof(wszMessage) / sizeof(WCHAR)),
        (SQLSMALLINT *)NULL) == SQL_SUCCESS)
    {
        // Hide data truncated..
        if (wcsncmp(wszState, L"01004", 5))
        {
            fwprintf(stderr, L"[%5.5s] %s (%d)\n", wszState, wszMessage, iError);
        }
    }
}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接