SQL to C: Numeric

The identifiers for the numeric ODBC SQL data types are the following:

  • SQL_DECIMAL
  • SQL_BIGINT
  • SQL_NUMERIC
  • SQL_REAL
  • SQL_TINYINT
  • SQL_FLOAT
  • SQL_SMALLINT
  • SQL_DOUBLE SQL_INTEGER

The following table shows the ODBC C data types to which numeric SQL data may be converted. For an explanation of the columns and terms in the table, see Converting Data from SQL to C Data Types.

C type identifier Test *TargetValuePtr *StrLen_or_IndPtr SQLSTATE
SQL_C_CHAR Character byte length < BufferLength

Number of whole (as opposed to fractional) digits < BufferLength

Number of whole (as opposed to fractional) digits >= BufferLength
Data

Truncated data

Undefined
Length of data in bytes

Length of data in bytes

Undefined
n/a

01004

22003
SQL_C_WCHAR Character length < BufferLength

Number of whole (as opposed to fractional) digits < BufferLength

Number of whole (as opposed to fractional) digits >= BufferLength
Data

Truncated data

Undefined
Length of data in characters

Length of data in characters

Undefined
n/a

01004

22003
SQL_C_STINYINT

SQL_C_UTINYINT

SQL_C_TINYINT

SQL_C_SBIGINT

SQL_C_UBIGINT

SQL_C_SSHORT

SQL_C_USHORT

SQL_C_SHORT

SQL_C_SLONG

SQL_C_ULONG

SQL_C_LONG

SQL_C_NUMERIC
Data converted without truncation[a]

Data converted with truncation of fractional digits[a]

Conversion of data would result in loss of whole (as opposed to fractional) digits[a]
Data

Truncated data

Undefined
Size of the C data type

Size of the C data type

Undefined
n/a

01S07

22003
SQL_C_FLOAT

SQL_C_DOUBLE
Data is within the range of the data type to which the number is being converted[a]

Data is outside the range of the data type to which the number is being converted[a]
Data

Undefined
Size of the C data type

Undefined
n/a

22003
SQL_C_BIT Data is 0 or 1[a]

Data is greater than 0, less than 2, and not equal to 1[a]

Data is less than 0 or greater than or equal to 2[a]
Data

Truncated data

Undefined
1[b]

1[b]

Undefined
n/a

01S07

22003
SQL_C_BINARY Byte length of data <= BufferLength

Byte length of data > BufferLength
Data

Undefined
Length of data

Undefined
n/a

22003
SQL_C_INTERVAL_MONTH[c] SQL_C_INTERVAL_YEAR[c] SQL_C_INTERVAL_DAY[c] SQL_C_INTERVAL_HOUR[c] SQL_C_INTERVAL_MINUTE[c] SQL_C_INTERVAL_SECOND[c] Data not truncated

Fractional seconds portion truncated

Whole part of number truncated
Data

Truncated data

Undefined
Length of data in bytes

Length of data in bytes

Undefined
n/a

01S07

22015
SQL_C_INTERVAL_YEAR_TO_MONTH SQL_C_INTERVAL_DAY_TO_HOUR SQL_C_INTERVAL_DAY_TO_MINUTE SQL_C_INTERVAL_DAY_TO_SECOND SQL_C_INTERVAL_HOUR_TO_MINUTE SQL_C_INTERVAL_HOUR_TO_SECOND Whole part of number truncated Undefined Undefined 22015

[a] The value of BufferLength is ignored for this conversion. The driver assumes that the size of *TargetValuePtr is the size of the C data type.

[b] This is the size of the corresponding C data type.

[c] This conversion is supported only for the exact numeric data types (SQL_DECIMAL, SQL_NUMERIC, SQL_TINYINT, SQL_SMALLINT, SQL_INTEGER, and SQL_BIGINT). It is not supported for the approximate numeric data types (SQL_REAL, SQL_FLOAT, or SQL_DOUBLE).

SQL_C_NUMERIC and SQLSetDescField

The SQLSetDescField Function is required to perform manual binding with SQL_C_NUMERIC values. (Note that SQLSetDescField was added in ODBC 3.0.) To perform manual binding, you must first get the descriptor handle.

if (fCType == SQL_C_NUMERIC) {   
   // special processing required for NUMERIC to get right scale & precision  
   // Modify the fields in the implicit application parameter descriptor  
   SQLHDESC hdesc=NULL;  
  
   // Use SQL_ATTR_APP_ROW_DESC for calls to SQLBindCol()  
   // Use SQL_ATTR_APP_PARAM_DESC for calls to SQLBindParameter()  
   //  
   // retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_ROW_DESC, &hdesc, 0, NULL);  
   retcode = SQLGetStmtAttr(hstmt, SQL_ATTR_APP_PARAM_DESC, &hdesc, 0, NULL);  
   if (!ODBC_CALL_SUCCESS(retcode)) {  
      printf ("\nSQLGetStmtAttr failed");  
      i = 1;  
      sqlstate[7] = '\0';  
      while (SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, i, sqlstate, &NativeError, wrkbuf, sizeof(wrkbuf), &len) != SQL_NO_DATA) {  
         printf("\niTestCase = %d Failed...Precision = %d, Scale = %d\nNativeError=%d, State=%s, \n  Message=%s",   
            iTestCase, Precision, Scale, NativeError, sqlstate, wrkbuf);  
         i++;  
      }  
      continue;  
   }  
   retcode = SQLSetDescField(hdesc, iCol, SQL_DESC_TYPE, (SQLPOINTER) SQL_C_NUMERIC, 0);  
   if (!ODBC_CALL_SUCCESS(retcode))  
      goto error;  
   retcode = SQLSetDescField(hdesc, iCol, SQL_DESC_PRECISION, (SQLPOINTER)num.precision, 0);  
   if (!ODBC_CALL_SUCCESS(retcode))  
      goto error;  
   retcode = SQLSetDescField(hdesc, iCol, SQL_DESC_SCALE, (SQLPOINTER)num.scale, 0);  
   if (!ODBC_CALL_SUCCESS(retcode))  
      goto error;  
   retcode = SQLSetDescField(hdesc, iCol, SQL_DESC_DATA_PTR, (SQLPOINTER) &(num), sizeof(num));