Skip to content

Commit

Permalink
numeric patch from Jakob Egger
Browse files Browse the repository at this point in the history
  • Loading branch information
brianb committed Mar 20, 2011
1 parent ff251e7 commit 1f3c049
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 42 deletions.
26 changes: 4 additions & 22 deletions src/libmdb/data.c
Expand Up @@ -28,9 +28,10 @@
#define OFFSET_MASK 0x1fff

char *mdb_money_to_string(MdbHandle *mdb, int start);
char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale);

static int _mdb_attempt_bind(MdbHandle *mdb,
MdbColumn *col, unsigned char isnull, int offset, int len);
static char *mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale);
static char *mdb_date_to_string(MdbHandle *mdb, int start);
#ifdef MDB_COPY_OLE
static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size);
Expand Down Expand Up @@ -223,12 +224,9 @@ int ret;
//fprintf(stdout,"len %d size %d\n",len, col->col_size);
char *str;
if (col->col_type == MDB_NUMERIC) {
str = mdb_num_to_string(mdb, start,
col->col_type, col->col_prec,
col->col_scale);
str = mdb_numeric_to_string(mdb, start, col->col_prec, col->col_scale);
} else {
str = mdb_col_to_string(mdb, mdb->pg_buf, start,
col->col_type, len);
str = mdb_col_to_string(mdb, mdb->pg_buf, start, col->col_type, len);
}
strcpy(col->bind_ptr, str);
g_free(str);
Expand Down Expand Up @@ -754,22 +752,6 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size)
return text;
}
}
static char *
mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale)
{
char *text;
gint32 l;

memcpy(&l, mdb->pg_buf+start+13, 4);

text = (char *) g_malloc(prec+2);
sprintf(text, "%0*" G_GINT32_FORMAT, prec, GINT32_FROM_LE(l));
if (scale) {
memmove(text+prec-scale+1, text+prec-scale, scale+1);
text[prec-scale] = '.';
}
return text;
}

#if 0
static int trim_trailing_zeros(char * buff)
Expand Down
70 changes: 50 additions & 20 deletions src/libmdb/money.c
Expand Up @@ -24,7 +24,7 @@
#include "dmalloc.h"
#endif

#define MAXPRECISION 19
#define MAX_NUMERIC_PRECISION 28
/*
** these routines are copied from the freetds project which does something
** very similiar
Expand All @@ -43,41 +43,70 @@ static char *array_to_string(unsigned char *array, int unsigned scale, int neg);
*/
char *mdb_money_to_string(MdbHandle *mdb, int start)
{
const int num_bytes = 8;
int num_bytes=8, prec=19, scale=4;
int i;
int neg=0;
unsigned char multiplier[MAXPRECISION], temp[MAXPRECISION];
unsigned char product[MAXPRECISION];
unsigned char money[num_bytes];
unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION];
unsigned char product[MAX_NUMERIC_PRECISION];
unsigned char bytes[num_bytes];

memset(multiplier,0,MAXPRECISION);
memset(product,0,MAXPRECISION);
memset(multiplier,0,MAX_NUMERIC_PRECISION);
memset(product,0,MAX_NUMERIC_PRECISION);
multiplier[0]=1;
memcpy(money, mdb->pg_buf + start, num_bytes);
memcpy(bytes, mdb->pg_buf + start, num_bytes);

/* Perform two's complement for negative numbers */
if (money[7] & 0x80) {
if (bytes[num_bytes-1] & 0x80) {
neg = 1;
for (i=0;i<num_bytes;i++) {
money[i] = ~money[i];
bytes[i] = ~bytes[i];
}
for (i=0; i<num_bytes; i++) {
money[i] ++;
if (money[i]!=0) break;
bytes[i] ++;
if (bytes[i]!=0) break;
}
}

for (i=0;i<num_bytes;i++) {
/* product += multiplier * current byte */
multiply_byte(product, money[i], multiplier);
multiply_byte(product, bytes[i], multiplier);

/* multiplier = multiplier * 256 */
memcpy(temp, multiplier, MAXPRECISION);
memset(multiplier,0,MAXPRECISION);
memcpy(temp, multiplier, MAX_NUMERIC_PRECISION);
memset(multiplier, 0, MAX_NUMERIC_PRECISION);
multiply_byte(multiplier, 256, temp);
}
return array_to_string(product, 4, neg);
return array_to_string(product, scale, neg);

}

char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale) {
int num_bytes = 16;
int i;
int neg=0;
unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION];
unsigned char product[MAX_NUMERIC_PRECISION];
unsigned char bytes[num_bytes];

memset(multiplier,0,MAX_NUMERIC_PRECISION);
memset(product,0,MAX_NUMERIC_PRECISION);
multiplier[0]=1;
memcpy(bytes, mdb->pg_buf + start + 1, num_bytes);

/* Perform two's complement for negative numbers */
if (mdb->pg_buf[start] & 0x80) neg = 1;
for (i=0;i<num_bytes;i++) {
/* product += multiplier * current byte */
multiply_byte(product, bytes[12-4*(i/4)+i%4], multiplier);

/* multiplier = multiplier * 256 */
memcpy(temp, multiplier, MAX_NUMERIC_PRECISION);
memset(multiplier, 0, MAX_NUMERIC_PRECISION);
multiply_byte(multiplier, 256, temp);
}
return array_to_string(product, scale, neg);
}

static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier)
{
unsigned char number[3];
Expand All @@ -87,7 +116,7 @@ static int multiply_byte(unsigned char *product, int num, unsigned char *multipl
number[1]=(num/10)%10;
number[2]=(num/100)%10;

for (i=0;i<MAXPRECISION;i++) {
for (i=0;i<MAX_NUMERIC_PRECISION;i++) {
if (multiplier[i] == 0) continue;
for (j=0;j<3;j++) {
if (number[j] == 0) continue;
Expand All @@ -101,7 +130,7 @@ static int do_carry(unsigned char *product)
{
unsigned int j;

for (j=0;j<MAXPRECISION-1;j++) {
for (j=0;j<MAX_NUMERIC_PRECISION-1;j++) {
if (product[j]>9) {
product[j+1]+=product[j]/10;
product[j]=product[j]%10;
Expand All @@ -117,9 +146,10 @@ static char *array_to_string(unsigned char *array, unsigned int scale, int neg)
char *s;
unsigned int top, i, j=0;

for (top=MAXPRECISION;(top>0) && (top-1>scale) && !array[top-1];top--);
for (top=MAX_NUMERIC_PRECISION;(top>0) && (top-1>scale) && !array[top-1];top--);

s = (char *) g_malloc(22);
/* allocate enough space for all digits + minus sign + decimal point + trailing NULL byte */
s = (char *) g_malloc(MAX_NUMERIC_PRECISION+3);

if (neg)
s[j++] = '-';
Expand Down

0 comments on commit 1f3c049

Please sign in to comment.