Oracle OCI 64-bit integer on 32-bit box

Michael Popov
Уже с Приветом
Posts: 991
Joined: 09 Sep 2001 09:01
Location: The Earth

Oracle OCI 64-bit integer on 32-bit box

Post by Michael Popov »

Нужно запихнуть в базу длинный integer (long long on Solaris, __int64 on Win) через binding. Пляски с бубном вокруг OCI пока положительных результатов не дали. Кто-то сталкивался с этой проблемой ? Советы ? Пожелания ? Соболезнования ? :)
Best regards,

Michael Popov
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Re: Oracle OCI 64-bit integer on 32-bit box

Post by roadman »

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
vc
Уже с Приветом
Posts: 664
Joined: 05 Jun 2002 01:11

Re: Oracle OCI 64-bit integer on 32-bit box

Post by vc »

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
Michael Popov
Уже с Приветом
Posts: 991
Joined: 09 Sep 2001 09:01
Location: The Earth

Post by Michael Popov »

Преобразовывать в строчку не желательно (performance issues).

Если можно преобразовать в SQLT_NUM, то наверное пойдет. В приведенном примере вся суть спрятана в методах класса numeric. Если это open source или public domain, можно ли ссылку на сорсы ? Или ссылку на формат этого самого SQLT_NUM ? Пошел гонять google ... :)
Best regards,

Michael Popov
User avatar
roadman
Уже с Приветом
Posts: 707
Joined: 12 Mar 2003 22:29
Location: Moscow->Bay Area, CA

Post by roadman »

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
Michael Popov
Уже с Приветом
Posts: 991
Joined: 09 Sep 2001 09:01
Location: The Earth

Post by Michael Popov »

Спасибо, roadman.
Best regards,

Michael Popov

Return to “Вопросы и новости IT”