Oracle OCI 64-bit integer on 32-bit box
-
- Уже с Приветом
- Posts: 991
- Joined: 09 Sep 2001 09:01
- Location: The Earth
Oracle OCI 64-bit integer on 32-bit box
Нужно запихнуть в базу длинный integer (long long on Solaris, __int64 on Win) через binding. Пляски с бубном вокруг OCI пока положительных результатов не дали. Кто-то сталкивался с этой проблемой ? Советы ? Пожелания ? Соболезнования ?
Best regards,
Michael Popov
Michael Popov
-
- Уже с Приветом
- Posts: 707
- Joined: 12 Mar 2003 22:29
- Location: Moscow->Bay Area, CA
Re: Oracle OCI 64-bit integer on 32-bit box
Michael Popov wrote:Нужно запихнуть в базу длинный integer (long long on Solaris, __int64 on Win) через binding. Пляски с бубном вокруг OCI пока положительных результатов не дали. Кто-то сталкивался с этой проблемой ? Советы ? Пожелания ? Соболезнования ?
Можно преобразовать int64 в Oracle numeric и делать bind на этот тип, а в базе соответственно иметь numeric(18,0) что с запасом хватит для int64. Код прошу рассматривать только как пример:
<PRE>
case vt_ub8:
// let use numeric type
cur._max_length = 21;
{
#ifdef OS_64BIT
numeric conv(cur._value.val.intVal, _temp_allocator);
#else
numeric conv(cur._value.val.intVal ? *cur._value.val.intVal : (sb8_t)0, _temp_allocator);
#endif
if (!conv.parse_orcl(cur._value.val.bufVal))
exception::_throw("Out of range");
size_t len = conv.orcl_len();
len -= conv.sign() ? 0 : 1;
cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
memcpy(cur._bind_buffer, cur._value.val.bufVal, len);
memset((ub1_t*)cur._bind_buffer + len, 0, cur._max_length - len);
cur._real_length = cur._value.nullVal || !cur._value.val.intVal ? 0 : len;
}
cur._native_type = SQLT_NUM;
break;
</PRE>
Ну и сам binding
<PRE>
OCIBind* bindp = 0;
check_retcode(OCIBindByPos(_stmthp, &bindp, _errhp,
index + 1, cur._bind_buffer, cur._max_length,
cur._native_type, (ub2*)&cur._bind_type,
(ub2*)&cur._real_length, 0, 0, 0,
OCI_DEFAULT), _errhp, OCI_HTYPE_ERROR)
</PRE>
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
-
- Уже с Приветом
- Posts: 664
- Joined: 05 Jun 2002 01:11
Re: Oracle OCI 64-bit integer on 32-bit box
Michael Popov wrote:Нужно запихнуть в базу длинный integer (long long on Solaris, __int64 on Win) через binding. Пляски с бубном вокруг OCI пока положительных результатов не дали. Кто-то сталкивался с этой проблемой ? Советы ? Пожелания ? Соболезнования ?
There is no external OCI data type for 'long long'. You'll have to convert your 'long long' to a string and use SQLT_STR which Oracle will convert to NUMBER.
VC
-
- Уже с Приветом
- Posts: 991
- Joined: 09 Sep 2001 09:01
- Location: The Earth
Преобразовывать в строчку не желательно (performance issues).
Если можно преобразовать в SQLT_NUM, то наверное пойдет. В приведенном примере вся суть спрятана в методах класса numeric. Если это open source или public domain, можно ли ссылку на сорсы ? Или ссылку на формат этого самого SQLT_NUM ? Пошел гонять google ...
Если можно преобразовать в SQLT_NUM, то наверное пойдет. В приведенном примере вся суть спрятана в методах класса numeric. Если это open source или public domain, можно ли ссылку на сорсы ? Или ссылку на формат этого самого SQLT_NUM ? Пошел гонять google ...
Best regards,
Michael Popov
Michael Popov
-
- Уже с Приветом
- Posts: 707
- Joined: 12 Mar 2003 22:29
- Location: Moscow->Bay Area, CA
Michael Popov wrote:Преобразовывать в строчку не желательно (performance issues).
Если можно преобразовать в SQLT_NUM, то наверное пойдет. В приведенном примере вся суть спрятана в методах класса numeric. Если это open source или public domain, можно ли ссылку на сорсы ? Или ссылку на формат этого самого SQLT_NUM ? Пошел гонять google ...
К сожалению я не могу открыть numeric class код, но весь алгоритм сделан и ТЕСТИРОВАН на ORACLE 8.0 OCI, посмотрите вот это:
Oracle stores values of the NUMBER datatype in a variable-length format. The first byte is the exponent and is followed by 1 to 20 mantissa bytes. The high-order bit of the exponent byte is the sign bit; it is set for positive numbers. The lower 7 bits represent the exponent, which is a base-100 digit with an offset of 65.
Each mantissa byte is a base-100 digit, in the range 1..100. For positive numbers, the digit has 1 added to it. So, the mantissa digit for the value 5 is 6. For negative numbers, instead of adding 1, the digit is subtracted from 101. So, the mantissa digit for the number -5 is 96 (101-5). Negative numbers have a byte containing 102 appended to the data bytes. However, negative numbers that have 20 mantissa bytes do not have the trailing 102 byte. Because the mantissa digits are stored in base 100, each byte can represent 2 decimal digits. The mantissa is normalized; leading zeroes are not stored.
Up to 20 data bytes can represent the mantissa. However, only 19 are guaranteed to be accurate. The 19 data bytes, each representing a base-100 digit, yield a maximum precision of 38 digits for an Oracle NUMBER.
Ещё немного кусочка кода:
<PRE>
bool
numeric::persist_orcl(ub1_t* buf) const
{
// buf should have 22 bytes
if (_precision > 40)
return false;
if (is_zero())
{
buf[0] = 128;
buf[1] = 0;
return true;
}
else if (sign()) // negative
{
bool odd_scale = _scale % 2 != 0;
size_t scale = _scale + (odd_scale ? 1 : 0);
size_t precision = _precision + (odd_scale ? 1 : 0);
bool odd_precision = precision % 2 != 0;
size_t mantissa = precision / 2;
for (size_t index = 0; index < mantissa; ++index)
{
ub1_t result = odd_scale ?
_vec[2*index] * 10 + (index == 0 ? 0 : _vec[2*index - 1]) :
_vec[2*index] + _vec[2*index + 1] * 10;
buf[mantissa - index + (odd_precision ? 1 : 0)] = 101 - result;
}
buf[0] = ~(mantissa - (odd_precision ? 0 : 1) - (ub1_t)scale / 2) - 193;
if (odd_precision)
buf[1] = 101 - _vec[_precision - 1];
// add last 102 byte
if (mantissa < 20)
buf[mantissa + 1 + (odd_precision ? 1 : 0)] = 102;
}
else // positive
{
bool odd_scale = _scale % 2 != 0;
size_t scale = _scale + (odd_scale ? 1 : 0);
size_t precision = _precision + (odd_scale ? 1 : 0);
bool odd_precision = precision % 2 != 0;
size_t mantissa = precision / 2;
for (size_t index = 0; index < mantissa; ++index)
{
ub1_t result = odd_scale ?
_vec[2*index] * 10 + (index == 0 ? 0 : _vec[2*index - 1]) :
_vec[2*index] + _vec[2*index + 1] * 10;
buf[mantissa - index + (odd_precision ? 1 : 0)] = result + 1;
}
buf[0] = mantissa - (odd_precision ? 0 : 1) - (ub1_t)scale / 2 + 193;
if (odd_precision)
buf[1] = _vec[_precision - 1] + 1;
// add last 0 byte
if (mantissa < 20)
buf[mantissa + 1 + (odd_precision ? 1 : 0)] = 0;
}
return true;
}
</PRE>
Или подождите выхода в свет всего продукта DB access (бесплатного) на сайте компании Terimber
http://www.terimber.com
The philosophy of one century is the common sense of the next. --Henry Ward Beecher
-
- Уже с Приветом
- Posts: 991
- Joined: 09 Sep 2001 09:01
- Location: The Earth