Numeric data type conversion form binary cursor -- Am I all wet, or is this about right?
От | Dann Corbit |
---|---|
Тема | Numeric data type conversion form binary cursor -- Am I all wet, or is this about right? |
Дата | |
Msg-id | D90A5A6C612A39408103E6ECDD77B8290FD4E1@voyager.corporate.connx.com обсуждение исходный текст |
Список | 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 по дате отправления: