diff options
Diffstat (limited to 'src/backend/utils/adt/varbit.c')
-rw-r--r-- | src/backend/utils/adt/varbit.c | 174 |
1 files changed, 172 insertions, 2 deletions
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 7f39866f005..4a550cdae29 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 - * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.63 2010/01/07 20:17:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.64 2010/01/25 20:55:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,8 +23,10 @@ #define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A')) +static VarBit *bit_catenate(VarBit *arg1, VarBit *arg2); static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified); +static VarBit *bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl); /* common code for bittypmodin and varbittypmodin */ @@ -877,6 +879,13 @@ bitcat(PG_FUNCTION_ARGS) { VarBit *arg1 = PG_GETARG_VARBIT_P(0); VarBit *arg2 = PG_GETARG_VARBIT_P(1); + + PG_RETURN_VARBIT_P(bit_catenate(arg1, arg2)); +} + +static VarBit * +bit_catenate(VarBit *arg1, VarBit *arg2) +{ VarBit *result; int bitlen1, bitlen2, @@ -919,7 +928,7 @@ bitcat(PG_FUNCTION_ARGS) } } - PG_RETURN_VARBIT_P(result); + return result; } /* bitsubstr @@ -1034,6 +1043,67 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified) return result; } +/* + * bitoverlay + * Replace specified substring of first string with second + * + * The SQL standard defines OVERLAY() in terms of substring and concatenation. + * This code is a direct implementation of what the standard says. + */ +Datum +bitoverlay(PG_FUNCTION_ARGS) +{ + VarBit *t1 = PG_GETARG_VARBIT_P(0); + VarBit *t2 = PG_GETARG_VARBIT_P(1); + int sp = PG_GETARG_INT32(2); /* substring start position */ + int sl = PG_GETARG_INT32(3); /* substring length */ + + PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl)); +} + +Datum +bitoverlay_no_len(PG_FUNCTION_ARGS) +{ + VarBit *t1 = PG_GETARG_VARBIT_P(0); + VarBit *t2 = PG_GETARG_VARBIT_P(1); + int sp = PG_GETARG_INT32(2); /* substring start position */ + int sl; + + sl = VARBITLEN(t2); /* defaults to length(t2) */ + PG_RETURN_VARBIT_P(bit_overlay(t1, t2, sp, sl)); +} + +static VarBit * +bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl) +{ + VarBit *result; + VarBit *s1; + VarBit *s2; + int sp_pl_sl; + + /* + * Check for possible integer-overflow cases. For negative sp, + * throw a "substring length" error because that's what should be + * expected according to the spec's definition of OVERLAY(). + */ + if (sp <= 0) + ereport(ERROR, + (errcode(ERRCODE_SUBSTRING_ERROR), + errmsg("negative substring length not allowed"))); + sp_pl_sl = sp + sl; + if (sp_pl_sl <= sl) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("integer out of range"))); + + s1 = bitsubstring(t1, 1, sp-1, false); + s2 = bitsubstring(t1, sp_pl_sl, -1, true); + result = bit_catenate(s1, t2); + result = bit_catenate(result, s2); + + return result; +} + /* bitlength, bitoctetlength * Return the length of a bit string */ @@ -1606,3 +1676,103 @@ bitposition(PG_FUNCTION_ARGS) } PG_RETURN_INT32(0); } + + +/* + * bitsetbit + * + * Given an instance of type 'bit' creates a new one with + * the Nth bit set to the given value. + * + * The bit location is specified left-to-right in a zero-based fashion + * consistent with the other get_bit and set_bit functions, but + * inconsistent with the standard substring, position, overlay functions + */ +Datum +bitsetbit(PG_FUNCTION_ARGS) +{ + VarBit *arg1 = PG_GETARG_VARBIT_P(0); + int32 n = PG_GETARG_INT32(1); + int32 newBit = PG_GETARG_INT32(2); + VarBit *result; + int len, + bitlen; + bits8 *r, + *p; + int byteNo, + bitNo; + + bitlen = VARBITLEN(arg1); + if (n < 0 || n >= bitlen) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("bit index %d out of valid range (0..%d)", + n, bitlen - 1))); + /* + * sanity check! + */ + if (newBit != 0 && newBit != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("new bit must be 0 or 1"))); + + len = VARSIZE(arg1); + result = (VarBit *) palloc(len); + SET_VARSIZE(result, len); + VARBITLEN(result) = bitlen; + + p = VARBITS(arg1); + r = VARBITS(result); + + memcpy(r, p, VARBITBYTES(arg1)); + + byteNo = n / BITS_PER_BYTE; + bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE); + + /* + * Update the byte. + */ + if (newBit == 0) + r[byteNo] &= (~(1 << bitNo)); + else + r[byteNo] |= (1 << bitNo); + + PG_RETURN_VARBIT_P(result); +} + +/* + * bitgetbit + * + * returns the value of the Nth bit of a bit array (0 or 1). + * + * The bit location is specified left-to-right in a zero-based fashion + * consistent with the other get_bit and set_bit functions, but + * inconsistent with the standard substring, position, overlay functions + */ +Datum +bitgetbit(PG_FUNCTION_ARGS) +{ + VarBit *arg1 = PG_GETARG_VARBIT_P(0); + int32 n = PG_GETARG_INT32(1); + int bitlen; + bits8 *p; + int byteNo, + bitNo; + + bitlen = VARBITLEN(arg1); + if (n < 0 || n >= bitlen) + ereport(ERROR, + (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("bit index %d out of valid range (0..%d)", + n, bitlen - 1))); + + p = VARBITS(arg1); + + byteNo = n / BITS_PER_BYTE; + bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE); + + if (p[byteNo] & (1 << bitNo)) + PG_RETURN_INT32(1); + else + PG_RETURN_INT32(0); +} |