Reading 64-bit integers from Oracle to OCCI (MSVC)
The option of converting to double and then converting to long long can suit many users, but not all, since it provides only 52-bit precision (the stored mantissa of a double type has a size of 52 bits) and, as a result, a possible loss of accuracy with large numbers. It would seem that the intermediate conversion to long double could solve the problem, but the Microsoft compiler restriction comes into play here - it does not support 80-bit floating-point numbers and perceives the long double type as an analog of the double type.
At the same time, the OCI underlying OCCI can do the conversion from Number to long long. For this, it has the following function:
sword OCINumberToInt (OCIError *err, const OCINumber *number, uword rsl_length, uword rsl_flag, void *rsl);
The function takes in the parameters a pointer to the initial number const OCINumber * number , to the resulting number void * rsl , as well as the size of the resulting number in bytes uword rsl_length . And among the supported result sizes there are 8, i.e. 64 bits. Now all that remains is to get OCINumber.
Unfortunately, here we are faced with the following problem - in OCCI from ResultSet (the class that is the result of the query), it is also not possible to get OCINumber, and the oracle :: occi :: Number class, which is a wrapper over OCINumber, also does not provide access to its viscera by declaring them private:
private:
/* Private constructor for constructing number from methods inside */
OCINumber getOCINumber() const;
OCINumber data;
And here we come to the aid of the possibility of converting completely different types to each other in C ++. Since the Number class has no virtual methods, and the OCINumber data member is the first in the class, the address of this member in memory matches the address of the class instance! Those. it is enough for us to write:
oracle::occi::Number number;
OCINumber *ociNumber = (OCINumber*)&number;
As a result, the function of converting Number to a 64-bit integer (for MSVC) is as follows:
__int64 OCCINumberToInt64 (const oracle::occi::Number &number, OCIError *hError, bool bSigned)
{
const OCINumber *ociNumber = (const OCINumber*)&number;
__int64 result;
OCINumberToInt (hError, ociNumber, 8, bSigned ? OCI_NUMBER_SIGNED : OCI_NUMBER_UNSIGNED, &result);
return result;
}
And to get the necessary OCI Error Handle function, you can use the following code:
oracle::occi::Environment env;
...
OCIEnv *hEnv = env->getOCIEnvironment ();
OCIError *hError = 0;
OCIHandleAlloc (hEnv, (void**)&hError, OCI_HTYPE_ERROR, 0, 0);
...
OCIHandleFree (hError, OCI_HTYPE_ERROR);