+static Oid
+oidin_subr(const char *funcname, const char *s, char **endloc)
+{
+ unsigned long cvt;
+ char *endptr;
+ Oid result;
+
+ errno = 0;
+
+ cvt = strtoul(s, &endptr, 10);
+
+ /*
+ * strtoul() normally only sets ERANGE. On some systems it also
+ * may set EINVAL, which simply means it couldn't parse the
+ * input string. This is handled by the second "if" consistent
+ * across platforms. Note that for historical reasons we accept
+ * an empty string as meaning 0.
+ */
+ if (errno && errno != EINVAL)
+ elog(ERROR, "%s: error reading \"%s\": %m",
+ funcname, s);
+ if (endptr == s && *endptr)
+ elog(ERROR, "%s: error in \"%s\": can't parse \"%s\"",
+ funcname, s, endptr);
+
+ if (endloc)
+ {
+ /* caller wants to deal with rest of string */
+ *endloc = endptr;
+ }
+ else
+ {
+ /* allow only whitespace after number */
+ while (*endptr && isspace((unsigned char) *endptr))
+ endptr++;
+ if (*endptr)
+ elog(ERROR, "%s: error in \"%s\": can't parse \"%s\"",
+ funcname, s, endptr);
+ }
+
+ result = (Oid) cvt;
+
+ /*
+ * Cope with possibility that unsigned long is wider than Oid.
+ *
+ * To ensure consistent results on 32-bit and 64-bit platforms,
+ * make sure the error message is the same as if strtoul() had
+ * returned ERANGE.
+ */
+#if OID_MAX < ULONG_MAX
+ if (cvt > (unsigned long) OID_MAX)
+ elog(ERROR, "%s: error reading \"%s\": %s",
+ funcname, s, strerror(ERANGE));
+#endif
+
+ return result;
+}
+
+Datum
+oidin(PG_FUNCTION_ARGS)
+{
+ char *s = PG_GETARG_CSTRING(0);
+ Oid result;
+
+ result = oidin_subr("oidin", s, NULL);
+ PG_RETURN_OID(result);
+}
+
+Datum
+oidout(PG_FUNCTION_ARGS)
+{
+ Oid o = PG_GETARG_OID(0);
+ char *result = (char *) palloc(12);
+
+ snprintf(result, 12, "%u", o);
+ PG_RETURN_CSTRING(result);
+}
+
+