Search code examples
csql-serverodbcunixodbc

How to send decimal part with SQL_NUMERIC_STRUCT?


I am working with SQL Server through ODBC.

The database has a table with money field. I want to send data to it. So I am doing:

SQL_NUMERIC_STRUCT st = {.scale=4, .precision=19, .sign=1};
memcpy(st.val, convert_to_hexdecimal((int64_t)(1.2345 * 10000)), sizeof(st.val));
SQLBindParam(stmt, 1, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 19, 0, &st, 0, NULL);

And this gives me 12345.0000 inside the database.

What am I doing wrong?

Please, do not suggest to switch to SQL_C_CHAR and sending a string with "1.2345" to database. I know that solution already. I am interested in proper use of SQL_NUMERIC_STRUCT.


Solution

  • The docs say

    The precision and scale fields of the numeric structure are never used for input from an application, only for output from the driver to the application.

    That's consistent with your observations.

    Nearby docs provide an example of almost exactly the same thing you're trying to do. They show creating and configuring a parameter descriptor of type SQLHDESC for the parameter, and setting the precision and scale there. I don't have an appropriate environment for testing this, but following the example, it looks like you want something along these lines:

    SQL_NUMERIC_STRUCT st = {.sign=1};
    memcpy(st.val, convert_to_hexdecimal(12345), sizeof(st.val));
    SQLBindParam(stmt, 1, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 19, 0, &st, 0, NULL);
    
    SQLHDESC hdesc = NULL;
    
    SQLGetStmtAttr(stmt, SQL_ATTR_APP_PARAM_DESC, &hdesc, 0, NULL);
    SQLSetDescField(hdesc, 1, SQL_DESC_TYPE, (SQLPOINTER) SQL_C_NUMERIC, 0);
    SQLSetDescField(hdesc, 1, SQL_DESC_PRECISION, (SQLPOINTER) 5, 0);
    SQLSetDescField(hdesc, 1, SQL_DESC_SCALE, (SQLPOINTER) 4, 0);
    SQLSetDescField(hdesc, 1, SQL_DESC_DATA_PTR, (SQLPOINTER) &st, 0);