diff --git a/lib/modules/Sql.pmod/pgsql.h b/lib/modules/Sql.pmod/pgsql.h index e65ff70fde91de5fe3bab75906bfb6f6f49cd628..77d3759febf5bc1748edca22af53aaeda4bdd8b9 100644 --- a/lib/modules/Sql.pmod/pgsql.h +++ b/lib/modules/Sql.pmod/pgsql.h @@ -59,10 +59,12 @@ #define BPCHAROID 1042 #define VARCHAROID 1043 #define CTIDOID 1247 +#define NUMERICOID 1700 #define UUIDOID 2950 #define UTF8CHARSET "UTF8" #define CLIENT_ENCODING "client_encoding" +#define NUMERIC_MAGSTEP 10000 #define DERROR(msg ...) ({sprintf(msg),backtrace()}) #define SERROR(msg ...) (sprintf(msg)) diff --git a/lib/modules/Sql.pmod/pgsql_util.pmod b/lib/modules/Sql.pmod/pgsql_util.pmod index 28538b0ba29d8e6ced747dc9c68e7959b7bf9dfb..e2f1d82a88fd71b1258faeee80219db04bd7bddc 100644 --- a/lib/modules/Sql.pmod/pgsql_util.pmod +++ b/lib/modules/Sql.pmod/pgsql_util.pmod @@ -180,6 +180,7 @@ private int readoidformat(int oid) { #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__) case FLOAT8OID: #endif + case NUMERICOID: case TEXTOID: case OIDOID: case XMLOID: @@ -212,6 +213,7 @@ private int writeoidformat(int oid, array(string|int) paramValues, case CTIDOID: case UUIDOID: return 1; //binary + case NUMERICOID: case FLOAT4OID: #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__) case FLOAT8OID: @@ -902,6 +904,59 @@ class sql_result { serror = SERROR("%O contains non-%s characters\n", value, UTF8CHARSET); break; + case NUMERICOID: + if (_forcetext) { + value = cr->read(collen); + if (!alltext) { + value = value/"."; + if (sizeof(value) == 1) + value = (int)value[0]; + else { + int i = sizeof(value[1]); + int denom = 1; + do + denom *= 10; + while (--i >= 0); + value = Gmp.mpq((int)value[0] * denom + (int)value[1], + denom); + } + } + } else { + int nwords = cr->read_int16(); + int magnitude = cr->read_sint(2); + int sign = cr->read_int16(); + cr->consume(2); + switch (nwords) { + default: + for (value = cr->read_int16(); + --nwords; + magnitude--) + value = value * NUMERIC_MAGSTEP + cr->read_int16(); + if (sign) + value = -value; + if (magnitude > 0) + do + value *= NUMERIC_MAGSTEP; + while (--magnitude); + else if (magnitude < 0) { + for (sign = NUMERIC_MAGSTEP; + ++magnitude; + sign *= NUMERIC_MAGSTEP); + value = Gmp.mpq(value, sign); + } + break; + case 1: + for (value = cr->read_int16(); + magnitude--; + value *= NUMERIC_MAGSTEP); + if (sign) + value = -value; + break; + case 0:; + value = 0; + } + } + break; case INT8OID:case INT2OID: case OIDOID:case INT4OID: if (_forcetext) { @@ -1081,6 +1136,42 @@ class sql_result { } } break; + case NUMERICOID: + if (stringp(value)) + plugbuffer->add_hstring(value, 4); + else { + int num, den, sign, magnitude = 0; + value = Gmp.mpq(value); + num = value->num(); + den = value->den(); + for (value = den; + value > NUMERIC_MAGSTEP; + value /= NUMERIC_MAGSTEP); + if (value > 1) { + value = NUMERIC_MAGSTEP / value; + num *= value; + den *= value; + } + if (num < 0) + sign = 0x4000, num = -num; + else + sign = 0; + array stor = ({}); + if (num) { + while (!(num % NUMERIC_MAGSTEP)) + num /= NUMERIC_MAGSTEP, magnitude++; + do + stor = ({num % NUMERIC_MAGSTEP}) + stor, magnitude++; + while (num /= NUMERIC_MAGSTEP); + num = --magnitude << 2; + while (den > 1) + magnitude--, den /= NUMERIC_MAGSTEP; + } + plugbuffer->add_int32(4 * 2 + (sizeof(stor) << 1)) + ->add_int16(sizeof(stor))->add_int16(magnitude) + ->add_int16(sign)->add_int16(num)->add_ints(stor, 2); + } + break; case FLOAT4OID: #if !constant(__builtin.__SINGLE_PRECISION_FLOAT__) case FLOAT8OID: