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: