Numeric data type conversion form binary cursor -- Am I all wet, or is this about right?

From: "Dann Corbit" <DCorbit(at)connx(dot)com>
To: <pgsql-hackers(at)postgresql(dot)org>
Subject: Numeric data type conversion form binary cursor -- Am I all wet, or is this about right?
Date: 2002-02-13 10:58:14
Message-ID: D90A5A6C612A39408103E6ECDD77B8290FD4E1@voyager.corporate.connx.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers


#include <stdlib.h>
#include <limits.h>
#include "postgres.h"
#include "fmgr.h"
#include "numeric.h"

/*
** PostgreSQL Numeric data type conversion functions
**
** Original implementation by Dann Corbit on 2-8-2002
**
** Since all of the digit groups *should* be in the range of 00 to 99,
** it may seem strange that these arrays are all dimensioned with
** UCHAR_MAX+1 (255+1=256 on most systems). But in having an enlarged
** dimension, we are safeguarded against an accidental over run
** due to bad data, etc. In any case, very little space is wasted
** (less than 1K in total).
** Instead of deciphering the digits one at a time, we just make the
** look up table with gaps instead so that we can look them up two
** digits [as encoded into one character] at a time.
*/

/*
If I collect a numeric entry like so:
void *vp = PQgetvalue(result, r, c);
int st = PQgetlength(result, r, c);
char num_data[2000] ={0};
int err;

I then call the NumericUntangle() routine as follows:
NumericUntangle(vp, st, num_data, sizeof num_data, &err);
*/

static const char *two_dig[UCHAR_MAX + 1] =
{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "", "",
"", "", "", "",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "", "",
"", "", "", "",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "", "",
"", "", "", "",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "", "",
"", "", "", "",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "", "",
"", "", "", "",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "", "",
"", "", "", "",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "", "",
"", "", "", "",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "", "",
"", "", "", "",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "", "",
"", "", "", "",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "", "",
"", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};

static const char *two_p_dig[UCHAR_MAX + 1] =
{
"0.0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8",
"0.9", "", "", "", "", "", "",
"1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8",
"1.9", "", "", "", "", "", "",
"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "2.7", "2.8",
"2.9", "", "", "", "", "", "",
"3.0", "3.1", "3.2", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8",
"3.9", "", "", "", "", "", "",
"4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6", "4.7", "4.8",
"4.9", "", "", "", "", "", "",
"5.0", "5.1", "5.2", "5.3", "5.4", "5.5", "5.6", "5.7", "5.8",
"5.9", "", "", "", "", "", "",
"6.0", "6.1", "6.2", "6.3", "6.4", "6.5", "6.6", "6.7", "6.8",
"6.9", "", "", "", "", "", "",
"7.0", "7.1", "7.2", "7.3", "7.4", "7.5", "7.6", "7.7", "7.8",
"7.9", "", "", "", "", "", "",
"8.0", "8.1", "8.2", "8.3", "8.4", "8.5", "8.6", "8.7", "8.8",
"8.9", "", "", "", "", "", "",
"9.0", "9.1", "9.2", "9.3", "9.4", "9.5", "9.6", "9.7", "9.8",
"9.9", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};

static const char *p_two_dig[UCHAR_MAX + 1] =
{
".00", ".01", ".02", ".03", ".04", ".05", ".06", ".07", ".08",
".09", "", "", "", "", "", "",
".10", ".11", ".12", ".13", ".14", ".15", ".16", ".17", ".18",
".19", "", "", "", "", "", "",
".20", ".21", ".22", ".23", ".24", ".25", ".26", ".27", ".28",
".29", "", "", "", "", "", "",
".30", ".31", ".32", ".33", ".34", ".35", ".36", ".37", ".38",
".39", "", "", "", "", "", "",
".40", ".41", ".42", ".43", ".44", ".45", ".46", ".47", ".48",
".49", "", "", "", "", "", "",
".50", ".51", ".52", ".53", ".54", ".55", ".56", ".57", ".58",
".59", "", "", "", "", "", "",
".60", ".61", ".62", ".63", ".64", ".65", ".66", ".67", ".68",
".69", "", "", "", "", "", "",
".70", ".71", ".72", ".73", ".74", ".75", ".76", ".77", ".78",
".79", "", "", "", "", "", "",
".80", ".81", ".82", ".83", ".84", ".85", ".86", ".87", ".88",
".89", "", "", "", "", "", "",
".90", ".91", ".92", ".93", ".94", ".95", ".96", ".97", ".98",
".99", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};

static const char *two_dig_p[UCHAR_MAX + 1] =
{
"00.", "01.", "02.", "03.", "04.", "05.", "06.", "07.", "08.",
"09.", "", "", "", "", "", "",
"10.", "11.", "12.", "13.", "14.", "15.", "16.", "17.", "18.",
"19.", "", "", "", "", "", "",
"20.", "21.", "22.", "23.", "24.", "25.", "26.", "27.", "28.",
"29.", "", "", "", "", "", "",
"30.", "31.", "32.", "33.", "34.", "35.", "36.", "37.", "38.",
"39.", "", "", "", "", "", "",
"40.", "41.", "42.", "43.", "44.", "45.", "46.", "47.", "48.",
"49.", "", "", "", "", "", "",
"50.", "51.", "52.", "53.", "54.", "55.", "56.", "57.", "58.",
"59.", "", "", "", "", "", "",
"60.", "61.", "62.", "63.", "64.", "65.", "66.", "67.", "68.",
"69.", "", "", "", "", "", "",
"70.", "71.", "72.", "73.", "74.", "75.", "76.", "77.", "78.",
"79.", "", "", "", "", "", "",
"80.", "81.", "82.", "83.", "84.", "85.", "86.", "87.", "88.",
"89.", "", "", "", "", "", "",
"90.", "91.", "92.", "93.", "94.", "95.", "96.", "97.", "98.",
"99.", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
};
/*
#define NUMERIC_SIGN_MASK 0xC000
#define NUMERIC_POS 0x0000
#define NUMERIC_NEG 0x4000
#define NUMERIC_NAN 0xC000
#define NUMERIC_DSCALE_MASK 0x3FFF
#define NUMERIC_SIGN(n) ((n)->n_sign_dscale & NUMERIC_SIGN_MASK)
#define NUMERIC_DSCALE(n) ((n)->n_sign_dscale &
NUMERIC_DSCALE_MASK)
#define NUMERIC_IS_NAN(n) (NUMERIC_SIGN(n) != NUMERIC_POS &&
NUMERIC_SIGN(n) != NUMERIC_NEG)
*/

void NumericUntangle(void *vp, int bytes_of_digits, char
*num_data, size_t num_data_len, int *err)
{
/* It appears that the pointer to data returned by PQgetvalue() is
* identical to a struct NumericData except that the varlen field is
* missing.
*/
typedef struct tag_numeric_overlay {
short base_ten_exponent;
short decimal_shift_right;
short n_sign_dscale;
unsigned char digits[1];
} numeric_overlay;
int i;
numeric_overlay *pno;
pno = (numeric_overlay *) vp;
char *s = num_data;
*err = 0;
if (!NUMERIC_IS_NAN(pno)) {
int sign = NUMERIC_SIGN(pno);
int dscale = NUMERIC_DSCALE(pno);
bytes_of_digits -= 3 * sizeof(short);
/* If there is too much hamburger to shove into the can (IOW, we
* have more bytes of data than we do of string) then we set the
* error flag and fill the string with pound signs. (#)
*/
if (num_data_len < (bytes_of_digits + 1) * 2) {
memset(s, '#', num_data_len - 1);
s[num_data_len - 1] = 0;
*err = 1;
return;
}
if (sign)
strcpy(s, "-");
else
s[0] = 0;
if (pno->base_ten_exponent < 0) {
strcat(s, "0.");
int slen = strlen(s);
int zcount = abs(pno->base_ten_exponent) - 1;
memset(s + slen, '0', zcount);
s[slen + zcount + 1] = 0;
for (i = 0; i < bytes_of_digits; i++)
strcat(s, two_dig[pno->digits[i]]);
} else {
int texp = pno->base_ten_exponent;
int bytes_to_go = bytes_of_digits;
for (bytes_to_go = bytes_of_digits, i = 0; texp > 1; texp -=
2, bytes_to_go--, i++) {
if (bytes_to_go)
strcat(s, two_dig[pno->digits[i]]);
else
strcat(s, two_dig[pno->digits[0]]);
}
switch (texp) {
case -1:
if (bytes_to_go) {
strcat(s, p_two_dig[pno->digits[i]]);
bytes_to_go--;
} else
strcat(s, p_two_dig[pno->digits[0]]);
break;
case 0:
if (bytes_to_go) {
strcat(s, two_p_dig[pno->digits[i]]);
bytes_to_go--;
} else
strcat(s, two_p_dig[pno->digits[0]]);
break;
case 1:
if (bytes_to_go) {
strcat(s, two_dig_p[pno->digits[i]]);
bytes_to_go--;
} else
strcat(s, two_dig_p[pno->digits[0]]);
break;
}
texp -= 2;
for (++i; texp > 1 || bytes_to_go > 0; texp -= 2,
bytes_to_go--, i++) {
if (bytes_to_go)
strcat(s, two_dig[pno->digits[i]]);
else
strcat(s, two_dig[pno->digits[0]]);
}

}
} else { /* This is a NAN */
strcpy(s, "#NAN#");
}
}

Browse pgsql-hackers by date

  From Date Subject
Next Message bpalmer 2002-02-13 11:56:14 Re: benchmarking postgres
Previous Message noy 2002-02-13 10:13:27 Re: Permissions problem