#include "libpq/pqformat.h"
 #include "utils/builtins.h"
 #include "utils/json.h"
+#include "utils/jsonapi.h"
 #include "utils/jsonb.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
    int         count = HS_COUNT(in);
    char       *base = STRPTR(in);
    HEntry     *entries = ARRPTR(in);
-   bool        is_number;
    StringInfoData tmp,
                dst;
 
            appendStringInfoString(&dst, "false");
        else
        {
-           is_number = false;
            resetStringInfo(&tmp);
            appendBinaryStringInfo(&tmp, HS_VAL(entries, base, i), HS_VALLEN(entries, i));
-
-           /*
-            * don't treat something with a leading zero followed by another
-            * digit as numeric - could be a zip code or similar
-            */
-           if (tmp.len > 0 &&
-               !(tmp.data[0] == '0' &&
-                 isdigit((unsigned char) tmp.data[1])) &&
-               strspn(tmp.data, "+-0123456789Ee.") == tmp.len)
-           {
-               /*
-                * might be a number. See if we can input it as a numeric
-                * value. Ignore any actual parsed value.
-                */
-               char       *endptr = "junk";
-               long        lval;
-
-               lval = strtol(tmp.data, &endptr, 10);
-               (void) lval;
-               if (*endptr == '\0')
-               {
-                   /*
-                    * strol man page says this means the whole string is
-                    * valid
-                    */
-                   is_number = true;
-               }
-               else
-               {
-                   /* not an int - try a double */
-                   double      dval;
-
-                   dval = strtod(tmp.data, &endptr);
-                   (void) dval;
-                   if (*endptr == '\0')
-                       is_number = true;
-               }
-           }
-           if (is_number)
+           if (IsValidJsonNumber(tmp.data, tmp.len))
                appendBinaryStringInfo(&dst, tmp.data, tmp.len);
            else
                escape_json(&dst, tmp.data);
 
     (c) == '_' || \
     IS_HIGHBIT_SET(c))
 
+/* utility function to check if a string is a valid JSON number */
+extern bool
+IsValidJsonNumber(const char * str, int len)
+{
+   bool        numeric_error;
+   JsonLexContext dummy_lex;
+
+
+   /*
+    * json_lex_number expects a leading  '-' to have been eaten already.
+    *
+    * having to cast away the constness of str is ugly, but there's not much
+    * easy alternative.
+    */
+   if (*str == '-')
+   {
+       dummy_lex.input = (char *) str + 1;
+       dummy_lex.input_length = len - 1;
+   }
+   else
+   {
+       dummy_lex.input = (char *) str;
+       dummy_lex.input_length = len;
+   }
+
+   json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error);
+
+   return ! numeric_error;
+}
+
 /*
  * Input.
  */
 {
    char       *outputstr;
    text       *jsontext;
-   bool        numeric_error;
-   JsonLexContext dummy_lex;
 
    /* callers are expected to ensure that null keys are not passed in */
    Assert( ! (key_scalar && is_null));
            break;
        case JSONTYPE_NUMERIC:
            outputstr = OidOutputFunctionCall(outfuncoid, val);
-           if (key_scalar)
-           {
-               /* always quote keys */
-               escape_json(result, outputstr);
-           }
+           /*
+            * Don't call escape_json for a non-key if it's a valid JSON
+            * number.
+            */
+           if (!key_scalar && IsValidJsonNumber(outputstr, strlen(outputstr)))
+               appendStringInfoString(result, outputstr);
            else
-           {
-               /*
-                * Don't call escape_json for a non-key if it's a valid JSON
-                * number.
-                */
-               dummy_lex.input = *outputstr == '-' ? outputstr + 1 : outputstr;
-               dummy_lex.input_length = strlen(dummy_lex.input);
-               json_lex_number(&dummy_lex, dummy_lex.input, &numeric_error);
-               if (!numeric_error)
-                   appendStringInfoString(result, outputstr);
-               else
-                   escape_json(result, outputstr);
-           }
+               escape_json(result, outputstr);
            pfree(outputstr);
            break;
        case JSONTYPE_DATE: