Sorry for that, but it just seemed too complicated. Perhaps there should really be a script to do this? I could imagine I'm not the only one slightly daunted by these files...
There's seems to be no reason for changing the docs since the functions are documented as existing :)
I didn't add the other functions that one might expect to exist (get-/set_byte and others), since I don't really need them.
I tested this code under 7.4 since that's what I've got here, but imagine nothing much changed in this end of the world for 7.4.1...
This is to be appended to src/backend/utils/adt/varbit.c:
/*------------------------------------------------------------- * bitSetBit * * Given an instance of type 'bit' creates a new one with * the Nth bit set to the given value. * *------------------------------------------------------------- */ PG_FUNCTION_INFO_V1(bitSetBit); 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 bitlen, bytelen, byteNo, bitNo; unsigned char oldByte, newByte;
bitlen = VARBITLEN(arg1);
/* * sanity checks! */ if (newBit != 0 && newBit != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("new bit must be 0 or 1")));
if (n < 0 || n >= bitlen) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("bit %d outside of valid range, 0..%d", n, bitlen - 1)));
/* Copy input bitstring */ bytelen = VARSIZE(arg1); result = (VarBit *) palloc(bytelen); memcpy(VARBITS(result), VARBITS(arg1), VARBITBYTES(arg1)); VARATT_SIZEP(result) = bytelen; VARBITLEN(result) = bitlen;
/* * Update the bit. */ byteNo = n / 8; bitNo = 7 - (n % 8);
oldByte = ((unsigned char *) VARBITS(result))[byteNo];
if (newBit == 0) newByte = oldByte & (~(1 << bitNo)); else newByte = oldByte | (1 << bitNo);
((unsigned char *) VARBITS(result))[byteNo] = newByte; PG_RETURN_VARBIT_P(result); }
/*------------------------------------------------------------- * bitGetBit * * Given an instance of type 'bit' returns the Nth bit. * *------------------------------------------------------------- */ PG_FUNCTION_INFO_V1(bitGetBit); Datum bitGetBit(PG_FUNCTION_ARGS) { VarBit *arg1 = PG_GETARG_VARBIT_P(0); int32 n = PG_GETARG_INT32(1); int bitlen, bytelen, byteNo, bitNo; unsigned char theByte;
bitlen = VARBITLEN(arg1);
/* * sanity check! */ if (n < 0 || n >= bitlen) ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("bit %d outside of valid range, 0..%d", n, bitlen - 1)));
/* * Find the target bit */ byteNo = n / BITS_PER_BYTE; bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);
theByte = ((unsigned char *) VARBITS(arg1))[byteNo];
/*
* Shift a set bit to target position, & with the target byte, shift back
* to get integer 0 or 1
*/
PG_RETURN_INT32((int)(theByte & (1 << bitNo)) >> bitNo);
}
---------------------------(end of broadcast)--------------------------- TIP 4: Don't 'kill -9' the postmaster