Just a short example C implementation of Oracle VARNUM/NUMBER type encoding, in case you could not use library functions. I didn’t found it anywhere when needed (and afterwards I found it doesn’t helps me at all due to little ‘problem’ in ora :() and Oracle documentation is pretty unclear about how-to do it.
typedef struct
{
uint8_t len;
uint8_t exp;
uint8_t man[20];
} VARNUM_t;
static void setVARNUM(VARNUM_t *varnum, int64_t value)
{
int8_t digits = 0;
uint64_t u_value = 0;
/* init */
memset(varnum, 0, sizeof(*varnum));
varnum->len = 1; //start len
/* check sign */
if(value >= 0)
{
u_value = value;
varnum->exp = trunc(log(u_value) / log(100)) + 128 + 65;
}
else
{
u_value = value * - 1;
varnum->exp = trunc(log(u_value) / log(100)) + 128 + 65;
varnum->exp = ~varnum->exp;
}
/* count value digits */
digits = trunc(log(u_value) / log(10));
digits = ((digits / 2) + 1);
/* mantisa */
for(; digits >= 0 && varnum->len <= 20; digits--)
{
uint64_t v_tmp = 0;
/* prevent INT overflow for too much digits */
if(digits > 0)
{
uint64_t v_pow = powl(100, digits - 1);
v_tmp = ((u_value / v_pow) / 100) % 100;
}
else
v_tmp = u_value % 100;
if(!v_tmp)
continue;
/* +1 for positive, subtract 101 for negative */
v_tmp = (value < 0 ? (101 - v_tmp) : (v_tmp + 1));
varnum->man[varnum->len - 1] = v_tmp;
varnum->len++;
}
/* terminator byte for negative value */
if(value < 0 && varnum->len <= 20) {
varnum->man[varnum->len - 1] = 102;
varnum->len++;
}
return;
}
NUMBER is just the same as VARNUM but without len member, thus is one byte shorter.
Note: this is just a quick implementation that works, there are some easy optimizations possible…