diff options
author | Tom Lane | 2002-09-18 21:35:25 +0000 |
---|---|---|
committer | Tom Lane | 2002-09-18 21:35:25 +0000 |
commit | b26dfb95222fddd25322bdddf3a5a58d3392d8b1 (patch) | |
tree | 757cf0bafab985d38a5c84d3afebe5edd34c4f27 /src/backend/utils/adt/int8.c | |
parent | cc70ba2e4daa78ba99619770e19beb06de3dfd1c (diff) |
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
Diffstat (limited to 'src/backend/utils/adt/int8.c')
-rw-r--r-- | src/backend/utils/adt/int8.c | 137 |
1 files changed, 115 insertions, 22 deletions
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 267ad821037..8a346cd8b83 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.41 2002/09/04 20:31:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.42 2002/09/18 21:35:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -48,14 +48,16 @@ * Formatting and conversion routines. *---------------------------------------------------------*/ -/* int8in() +/* + * scanint8 --- try to parse a string into an int8. + * + * If errorOK is false, elog a useful error message if the string is bad. + * If errorOK is true, just return "false" for bad input. */ -Datum -int8in(PG_FUNCTION_ARGS) +bool +scanint8(const char *str, bool errorOK, int64 *result) { - char *str = PG_GETARG_CSTRING(0); - int64 result; - char *ptr = str; + const char *ptr = str; int64 tmp = 0; int sign = 1; @@ -63,8 +65,11 @@ int8in(PG_FUNCTION_ARGS) * Do our own scan, rather than relying on sscanf which might be * broken for long long. */ - while (*ptr && isspace((unsigned char) *ptr)) /* skip leading spaces */ + + /* skip leading spaces */ + while (*ptr && isspace((unsigned char) *ptr)) ptr++; + /* handle sign */ if (*ptr == '-') { @@ -79,28 +84,61 @@ int8in(PG_FUNCTION_ARGS) #ifndef INT64_IS_BUSTED if (strcmp(ptr, "9223372036854775808") == 0) { - result = -INT64CONST(0x7fffffffffffffff) - 1; - PG_RETURN_INT64(result); + *result = -INT64CONST(0x7fffffffffffffff) - 1; + return true; } #endif } else if (*ptr == '+') ptr++; - if (!isdigit((unsigned char) *ptr)) /* require at least one digit */ - elog(ERROR, "Bad int8 external representation \"%s\"", str); - while (*ptr && isdigit((unsigned char) *ptr)) /* process digits */ + + /* require at least one digit */ + if (!isdigit((unsigned char) *ptr)) + { + if (errorOK) + return false; + else + elog(ERROR, "Bad int8 external representation \"%s\"", str); + } + + /* process digits */ + while (*ptr && isdigit((unsigned char) *ptr)) { int64 newtmp = tmp * 10 + (*ptr++ - '0'); if ((newtmp / 10) != tmp) /* overflow? */ - elog(ERROR, "int8 value out of range: \"%s\"", str); + { + if (errorOK) + return false; + else + elog(ERROR, "int8 value out of range: \"%s\"", str); + } tmp = newtmp; } - if (*ptr) /* trailing junk? */ - elog(ERROR, "Bad int8 external representation \"%s\"", str); - result = (sign < 0) ? -tmp : tmp; + /* trailing junk? */ + if (*ptr) + { + if (errorOK) + return false; + else + elog(ERROR, "Bad int8 external representation \"%s\"", str); + } + *result = (sign < 0) ? -tmp : tmp; + + return true; +} + +/* int8in() + */ +Datum +int8in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int64 result; + + (void) scanint8(str, false, &result); PG_RETURN_INT64(result); } @@ -747,7 +785,7 @@ i8tod(PG_FUNCTION_ARGS) } /* dtoi8() - * Convert double float to 8-byte integer. + * Convert float8 to 8-byte integer. */ Datum dtoi8(PG_FUNCTION_ARGS) @@ -771,9 +809,67 @@ dtoi8(PG_FUNCTION_ARGS) PG_RETURN_INT64(result); } -/* text_int8() +Datum +i8tof(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + float4 result; + + result = val; + + PG_RETURN_FLOAT4(result); +} + +/* ftoi8() + * Convert float4 to 8-byte integer. */ Datum +ftoi8(PG_FUNCTION_ARGS) +{ + float4 val = PG_GETARG_FLOAT4(0); + int64 result; + float8 dval; + + /* Round val to nearest integer (but it's still in float form) */ + dval = rint(val); + + /* + * Does it fit in an int64? Avoid assuming that we have handy + * constants defined for the range boundaries, instead test for + * overflow by reverse-conversion. + */ + result = (int64) dval; + + if ((float8) result != dval) + elog(ERROR, "Floating point conversion to int8 is out of range"); + + PG_RETURN_INT64(result); +} + +Datum +i8tooid(PG_FUNCTION_ARGS) +{ + int64 val = PG_GETARG_INT64(0); + Oid result; + + result = (Oid) val; + + /* Test for overflow by reverse-conversion. */ + if ((int64) result != val) + elog(ERROR, "int8 conversion to OID is out of range"); + + PG_RETURN_OID(result); +} + +Datum +oidtoi8(PG_FUNCTION_ARGS) +{ + Oid val = PG_GETARG_OID(0); + + PG_RETURN_INT64((int64) val); +} + +Datum text_int8(PG_FUNCTION_ARGS) { text *str = PG_GETARG_TEXT_P(0); @@ -793,9 +889,6 @@ text_int8(PG_FUNCTION_ARGS) return result; } - -/* int8_text() - */ Datum int8_text(PG_FUNCTION_ARGS) { |