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

From Dann Corbit
Subject Numeric data type conversion form binary cursor -- Am I all wet, or is this about right?
Date
Msg-id D90A5A6C612A39408103E6ECDD77B8290FD4E1@voyager.corporate.connx.com
Whole thread Raw
List 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
thatthe 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)
thenwe 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#");   }
}


pgsql-hackers by date:

Previous
From: noy
Date:
Subject: Re: Permissions problem
Next
From: bpalmer
Date:
Subject: Re: benchmarking postgres