diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2002-09-18 21:35:25 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2002-09-18 21:35:25 +0000 |
commit | b26dfb95222fddd25322bdddf3a5a58d3392d8b1 (patch) | |
tree | 757cf0bafab985d38a5c84d3afebe5edd34c4f27 /src/backend/utils/adt/varbit.c | |
parent | cc70ba2e4daa78ba99619770e19beb06de3dfd1c (diff) | |
download | postgresql-b26dfb95222fddd25322bdddf3a5a58d3392d8b1.tar.gz postgresql-b26dfb95222fddd25322bdddf3a5a58d3392d8b1.zip |
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/varbit.c')
-rw-r--r-- | src/backend/utils/adt/varbit.c | 121 |
1 files changed, 56 insertions, 65 deletions
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index f0c31a3961b..715a99863fd 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.25 2002/09/04 20:31:29 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.26 2002/09/18 21:35:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,6 +35,11 @@ * data section -- private data section for the bits data structures * bitlength -- length of the bit string in bits * bitdata -- bit string, most significant byte first + * + * The length of the bitdata vector should always be exactly as many + * bytes as are needed for the given bitlength. If the bitlength is + * not a multiple of 8, the extra low-order padding bits of the last + * byte must be zeroes. *---------- */ @@ -104,7 +109,7 @@ bit_in(PG_FUNCTION_ARGS) len = VARBITTOTALLEN(atttypmod); result = (VarBit *) palloc(len); /* set to 0 so that *r is always initialised and string is zero-padded */ - memset(result, 0, len); + MemSet(result, 0, len); VARATT_SIZEP(result) = len; VARBITLEN(result) = atttypmod; @@ -203,50 +208,52 @@ bit_out(PG_FUNCTION_ARGS) /* bit() * Converts a bit() type to a specific internal length. * len is the bitlength specified in the column definition. + * + * If doing implicit cast, raise error when source data is wrong length. + * If doing explicit cast, silently truncate or zero-pad to specified length. */ Datum bit(PG_FUNCTION_ARGS) { VarBit *arg = PG_GETARG_VARBIT_P(0); int32 len = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); + VarBit *result; + int rlen; + int ipad; + bits8 mask; /* No work if typmod is invalid or supplied data matches it already */ if (len <= 0 || len == VARBITLEN(arg)) PG_RETURN_VARBIT_P(arg); - else + + if (!isExplicit) elog(ERROR, "Bit string length %d does not match type BIT(%d)", VARBITLEN(arg), len); - return 0; /* quiet compiler */ -} -/* _bit() - * Converts an array of bit() elements to a specific internal length. - * len is the bitlength specified in the column definition. - */ -Datum -_bit(PG_FUNCTION_ARGS) -{ - ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); - int32 len = PG_GETARG_INT32(1); - FunctionCallInfoData locfcinfo; + rlen = VARBITTOTALLEN(len); + result = (VarBit *) palloc(rlen); + /* set to 0 so that string is zero-padded */ + MemSet(result, 0, rlen); + VARATT_SIZEP(result) = rlen; + VARBITLEN(result) = len; + + memcpy(VARBITS(result), VARBITS(arg), + Min(VARBITBYTES(result), VARBITBYTES(arg))); /* - * Since bit() is a built-in function, we should only need to look it - * up once per run. + * Make sure last byte is zero-padded if needed. This is useless but + * safe if source data was shorter than target length (we assume the + * last byte of the source data was itself correctly zero-padded). */ - static FmgrInfo bit_finfo; - - if (bit_finfo.fn_oid == InvalidOid) - fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext); - - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &bit_finfo; - locfcinfo.nargs = 2; - /* We assume we are "strict" and need not worry about null inputs */ - locfcinfo.arg[0] = PointerGetDatum(v); - locfcinfo.arg[1] = Int32GetDatum(len); + ipad = VARBITPAD(result); + if (ipad > 0) + { + mask = BITMASK << ipad; + *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask; + } - return array_map(&locfcinfo, BITOID, BITOID); + PG_RETURN_VARBIT_P(result); } /* @@ -311,7 +318,7 @@ varbit_in(PG_FUNCTION_ARGS) len = VARBITTOTALLEN(bitlen); result = (VarBit *) palloc(len); /* set to 0 so that *r is always initialised and string is zero-padded */ - memset(result, 0, len); + MemSet(result, 0, len); VARATT_SIZEP(result) = len; VARBITLEN(result) = Min(bitlen, atttypmod); @@ -406,20 +413,26 @@ varbit_out(PG_FUNCTION_ARGS) /* varbit() * Converts a varbit() type to a specific internal length. * len is the maximum bitlength specified in the column definition. + * + * If doing implicit cast, raise error when source data is too long. + * If doing explicit cast, silently truncate to max length. */ Datum varbit(PG_FUNCTION_ARGS) { VarBit *arg = PG_GETARG_VARBIT_P(0); int32 len = PG_GETARG_INT32(1); + bool isExplicit = PG_GETARG_BOOL(2); VarBit *result; int rlen; + int ipad; + bits8 mask; /* No work if typmod is invalid or supplied data matches it already */ if (len <= 0 || len >= VARBITLEN(arg)) PG_RETURN_VARBIT_P(arg); - if (len < VARBITLEN(arg)) + if (!isExplicit) elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len); rlen = VARBITTOTALLEN(len); @@ -429,37 +442,15 @@ varbit(PG_FUNCTION_ARGS) memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result)); - PG_RETURN_VARBIT_P(result); -} - -/* _varbit() - * Converts an array of bit() elements to a specific internal length. - * len is the maximum bitlength specified in the column definition. - */ -Datum -_varbit(PG_FUNCTION_ARGS) -{ - ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); - int32 len = PG_GETARG_INT32(1); - FunctionCallInfoData locfcinfo; - - /* - * Since varbit() is a built-in function, we should only need to look - * it up once per run. - */ - static FmgrInfo varbit_finfo; - - if (varbit_finfo.fn_oid == InvalidOid) - fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext); - - MemSet(&locfcinfo, 0, sizeof(locfcinfo)); - locfcinfo.flinfo = &varbit_finfo; - locfcinfo.nargs = 2; - /* We assume we are "strict" and need not worry about null inputs */ - locfcinfo.arg[0] = PointerGetDatum(v); - locfcinfo.arg[1] = Int32GetDatum(len); + /* Make sure last byte is zero-padded if needed */ + ipad = VARBITPAD(result); + if (ipad > 0) + { + mask = BITMASK << ipad; + *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask; + } - return array_map(&locfcinfo, VARBITOID, VARBITOID); + PG_RETURN_VARBIT_P(result); } @@ -978,7 +969,7 @@ bitshiftleft(PG_FUNCTION_ARGS) /* If we shifted all the bits out, return an all-zero string */ if (shft >= VARBITLEN(arg)) { - memset(r, 0, VARBITBYTES(arg)); + MemSet(r, 0, VARBITBYTES(arg)); PG_RETURN_VARBIT_P(result); } @@ -991,7 +982,7 @@ bitshiftleft(PG_FUNCTION_ARGS) /* Special case: we can do a memcpy */ len = VARBITBYTES(arg) - byte_shift; memcpy(r, p, len); - memset(r + len, 0, byte_shift); + MemSet(r + len, 0, byte_shift); } else { @@ -1037,7 +1028,7 @@ bitshiftright(PG_FUNCTION_ARGS) /* If we shifted all the bits out, return an all-zero string */ if (shft >= VARBITLEN(arg)) { - memset(r, 0, VARBITBYTES(arg)); + MemSet(r, 0, VARBITBYTES(arg)); PG_RETURN_VARBIT_P(result); } @@ -1046,7 +1037,7 @@ bitshiftright(PG_FUNCTION_ARGS) p = VARBITS(arg); /* Set the first part of the result to 0 */ - memset(r, 0, byte_shift); + MemSet(r, 0, byte_shift); r += byte_shift; if (ishift == 0) |