ODBC error 'String data, right truncation' when updating uniqueidentifier column with null value

Viewed 393

I'm trying to update column of type uniqueidentifier with null. My query looks like:

UPDATE table_name SET column_name = ?

The column is bound with:

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

Executing the query results in a ODBC error 'String data, right truncation'. Using the exact same SQLBindParameter I'm able to successfuly insert a new row with null data. Why does this not work for updating the row?

2 Answers

Please read
https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqlbindparameter-function?view=sql-server-ver15 thoroughly.

According to it, the 6th parameter to SQLBindParameter is ColumnSize, which you set to 37. Why this value?

The 8th parameter is ParameterValuePtr, but you set it to NULL. Is NULL the value you are trying to set?

The 10th parameter is StrLen_or_IndPtr which you set to &_nullLen where SQLLEN _nullLen(SQL_NULL_DATA), but that's not the kind of thing it should point to.

Please make sure you understand each parameter passed to SQLBindParameter().

I suspect you update more than one column and that the truncation is not on the UNIQUEIDENTIFIER column but rather on something else. I fired up my old VS and coded following sample program, and it updated to NULL just fine. You might wanna put a trace to see what was actually executed.


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


Related