"bigint", s)));
}
+/*
+ * Convert input string to an unsigned 32 bit integer.
+ *
+ * Allows any number of leading or trailing whitespace characters.
+ *
+ * If endloc isn't NULL, store a pointer to the rest of the string there,
+ * so that caller can parse the rest. Otherwise, it's an error if anything
+ * but whitespace follows.
+ *
+ * typname is what is reported in error messges.
+ *
+ * If escontext points to an ErrorSaveContext node, that is filled instead
+ * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
+ * to detect errors.
+ */
+uint32
+uint32in_subr(const char *s, char **endloc,
+ const char *typname, Node *escontext)
+{
+ uint32 result;
+ unsigned long cvt;
+ char *endptr;
+
+ errno = 0;
+ cvt = strtoul(s, &endptr, 0);
+
+ /*
+ * strtoul() normally only sets ERANGE. On some systems it may also set
+ * EINVAL, which simply means it couldn't parse the input string. Be sure
+ * to report that the same way as the standard error indication (that
+ * endptr == s).
+ */
+ if ((errno && errno != ERANGE) || endptr == s)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ typname, s)));
+
+ if (errno == ERANGE)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ s, typname)));
+
+ 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)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ typname, s)));
+ }
+
+ result = (uint32) cvt;
+
+ /*
+ * Cope with possibility that unsigned long is wider than uint32, in which
+ * case strtoul will not raise an error for some values that are out of
+ * the range of uint32.
+ *
+ * For backwards compatibility, we want to accept inputs that are given
+ * with a minus sign, so allow the input value if it matches after either
+ * signed or unsigned extension to long.
+ *
+ * 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 PG_UINT32_MAX != ULONG_MAX
+ if (cvt != (unsigned long) result &&
+ cvt != (unsigned long) ((int) result))
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ s, typname)));
+#endif
+
+ return result;
+}
+
+/*
+ * Convert input string to an unsigned 64 bit integer.
+ *
+ * Allows any number of leading or trailing whitespace characters.
+ *
+ * If endloc isn't NULL, store a pointer to the rest of the string there,
+ * so that caller can parse the rest. Otherwise, it's an error if anything
+ * but whitespace follows.
+ *
+ * typname is what is reported in error messges.
+ *
+ * If escontext points to an ErrorSaveContext node, that is filled instead
+ * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
+ * to detect errors.
+ */
+uint64
+uint64in_subr(const char *s, char **endloc,
+ const char *typname, Node *escontext)
+{
+ uint64 result;
+ char *endptr;
+
+ errno = 0;
+ result = strtou64(s, &endptr, 0);
+
+ /*
+ * strtoul[l] normally only sets ERANGE. On some systems it may also set
+ * EINVAL, which simply means it couldn't parse the input string. Be sure
+ * to report that the same way as the standard error indication (that
+ * endptr == s).
+ */
+ if ((errno && errno != ERANGE) || endptr == s)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ typname, s)));
+
+ if (errno == ERANGE)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value \"%s\" is out of range for type %s",
+ s, typname)));
+
+ 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)
+ ereturn(escontext, 0,
+ (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+ errmsg("invalid input syntax for type %s: \"%s\"",
+ typname, s)));
+ }
+
+ return result;
+}
+
/*
* pg_itoa: converts a signed 16-bit integer to its string representation
* and returns strlen(a).
* USER I/O ROUTINES *
*****************************************************************************/
-/*
- * Parse a single OID and return its value.
- *
- * If endloc isn't NULL, store a pointer to the rest of the string there,
- * so that caller can parse the rest. Otherwise, it's an error if anything
- * but whitespace follows.
- *
- * If escontext points to an ErrorSaveContext node, that is filled instead
- * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
- * to detect errors.
- */
-static Oid
-oidin_subr(const char *s, char **endloc, Node *escontext)
-{
- unsigned long cvt;
- char *endptr;
- Oid result;
-
- if (*s == '\0')
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s: \"%s\"",
- "oid", s)));
-
- 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.
- */
- if (errno && errno != ERANGE && errno != EINVAL)
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s: \"%s\"",
- "oid", s)));
-
- if (endptr == s && *s != '\0')
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s: \"%s\"",
- "oid", s)));
-
- if (errno == ERANGE)
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value \"%s\" is out of range for type %s",
- s, "oid")));
-
- 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)
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
- errmsg("invalid input syntax for type %s: \"%s\"",
- "oid", s)));
- }
-
- result = (Oid) cvt;
-
- /*
- * Cope with possibility that unsigned long is wider than Oid, in which
- * case strtoul will not raise an error for some values that are out of
- * the range of Oid.
- *
- * For backwards compatibility, we want to accept inputs that are given
- * with a minus sign, so allow the input value if it matches after either
- * signed or unsigned extension to long.
- *
- * 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) result &&
- cvt != (unsigned long) ((int) result))
- ereturn(escontext, InvalidOid,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value \"%s\" is out of range for type %s",
- s, "oid")));
-#endif
-
- return result;
-}
-
Datum
oidin(PG_FUNCTION_ARGS)
{
char *s = PG_GETARG_CSTRING(0);
Oid result;
- result = oidin_subr(s, NULL, fcinfo->context);
+ result = uint32in_subr(s, NULL, "oid", fcinfo->context);
PG_RETURN_OID(result);
}
oidString++;
if (*oidString == '\0')
break;
- result->values[n] = oidin_subr(oidString, &oidString, escontext);
+ result->values[n] = uint32in_subr(oidString, &oidString,
+ "oid", escontext);
if (SOFT_ERROR_OCCURRED(escontext))
PG_RETURN_NULL();
}
* constants by the lexer. Accept these if they are valid OID
* strings.
*/
- return oidin_subr(castNode(Float, node)->fval, NULL, NULL);
+ return uint32in_subr(castNode(Float, node)->fval, NULL,
+ "oid", NULL);
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
}
xidin(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
+ TransactionId result;
- PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0));
+ result = uint32in_subr(str, NULL, "xid", fcinfo->context);
+ PG_RETURN_TRANSACTIONID(result);
}
Datum
xid8in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
+ uint64 result;
- PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(strtou64(str, NULL, 0)));
+ result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
+ PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
}
Datum
cidin(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
+ CommandId result;
- PG_RETURN_COMMANDID((CommandId) strtoul(str, NULL, 0));
+ result = uint32in_subr(str, NULL, "cid", fcinfo->context);
+ PG_RETURN_COMMANDID(result);
}
/*
extern int32 pg_strtoint32_safe(const char *s, Node *escontext);
extern int64 pg_strtoint64(const char *s);
extern int64 pg_strtoint64_safe(const char *s, Node *escontext);
+extern uint32 uint32in_subr(const char *s, char **endloc,
+ const char *typname, Node *escontext);
+extern uint64 uint64in_subr(const char *s, char **endloc,
+ const char *typname, Node *escontext);
extern int pg_itoa(int16 i, char *a);
extern int pg_ultoa_n(uint32 value, char *a);
extern int pg_ulltoa_n(uint64 value, char *a);
8 | 42 | 4294967295 | 4294967295 | 8 | 42 | 18446744073709551615 | 18446744073709551615
(1 row)
--- garbage values are not yet rejected (perhaps they should be)
+-- garbage values
select ''::xid;
- xid
------
- 0
+ERROR: invalid input syntax for type xid: ""
+LINE 1: select ''::xid;
+ ^
+select 'asdf'::xid;
+ERROR: invalid input syntax for type xid: "asdf"
+LINE 1: select 'asdf'::xid;
+ ^
+select ''::xid8;
+ERROR: invalid input syntax for type xid8: ""
+LINE 1: select ''::xid8;
+ ^
+select 'asdf'::xid8;
+ERROR: invalid input syntax for type xid8: "asdf"
+LINE 1: select 'asdf'::xid8;
+ ^
+-- Also try it with non-error-throwing API
+SELECT pg_input_is_valid('42', 'xid');
+ pg_input_is_valid
+-------------------
+ t
(1 row)
-select 'asdf'::xid;
- xid
------
- 0
+SELECT pg_input_is_valid('asdf', 'xid');
+ pg_input_is_valid
+-------------------
+ f
(1 row)
-select ''::xid8;
- xid8
-------
- 0
+SELECT pg_input_error_message('0xffffffffff', 'xid');
+ pg_input_error_message
+---------------------------------------------------
+ value "0xffffffffff" is out of range for type xid
(1 row)
-select 'asdf'::xid8;
- xid8
-------
- 0
+SELECT pg_input_is_valid('42', 'xid8');
+ pg_input_is_valid
+-------------------
+ t
+(1 row)
+
+SELECT pg_input_is_valid('asdf', 'xid8');
+ pg_input_is_valid
+-------------------
+ f
+(1 row)
+
+SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
+ pg_input_error_message
+--------------------------------------------------------------
+ value "0xffffffffffffffffffff" is out of range for type xid8
(1 row)
-- equality
'0xffffffffffffffff'::xid8,
'-1'::xid8;
--- garbage values are not yet rejected (perhaps they should be)
+-- garbage values
select ''::xid;
select 'asdf'::xid;
select ''::xid8;
select 'asdf'::xid8;
+-- Also try it with non-error-throwing API
+SELECT pg_input_is_valid('42', 'xid');
+SELECT pg_input_is_valid('asdf', 'xid');
+SELECT pg_input_error_message('0xffffffffff', 'xid');
+SELECT pg_input_is_valid('42', 'xid8');
+SELECT pg_input_is_valid('asdf', 'xid8');
+SELECT pg_input_error_message('0xffffffffffffffffffff', 'xid8');
+
-- equality
select '1'::xid = '1'::xid;
select '1'::xid != '1'::xid;