aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/varbit.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-09-18 21:35:25 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-09-18 21:35:25 +0000
commitb26dfb95222fddd25322bdddf3a5a58d3392d8b1 (patch)
tree757cf0bafab985d38a5c84d3afebe5edd34c4f27 /src/backend/utils/adt/varbit.c
parentcc70ba2e4daa78ba99619770e19beb06de3dfd1c (diff)
downloadpostgresql-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.c121
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)