mirror of
https://github.com/postgres/postgres.git
synced 2025-07-14 08:21:07 +03:00
Add get_bit/set_bit functions for bit strings, paralleling those for bytea,
and implement OVERLAY() for bit strings and bytea. In passing also convert text OVERLAY() to a true built-in, instead of relying on a SQL function. Leonardo F, reviewed by Kevin Grittner
This commit is contained in:
@ -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);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.173 2010/01/02 16:57:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.174 2010/01/25 20:55:32 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -60,11 +60,19 @@ static int text_position(text *t1, text *t2);
|
||||
static void text_position_setup(text *t1, text *t2, TextPositionState *state);
|
||||
static int text_position_next(int start_pos, TextPositionState *state);
|
||||
static void text_position_cleanup(TextPositionState *state);
|
||||
static text *text_catenate(text *t1, text *t2);
|
||||
static text *text_substring(Datum str,
|
||||
int32 start,
|
||||
int32 length,
|
||||
bool length_not_specified);
|
||||
static text *text_overlay(text *t1, text *t2, int sp, int sl);
|
||||
static void appendStringInfoText(StringInfo str, const text *t);
|
||||
static bytea *bytea_catenate(bytea *t1, bytea *t2);
|
||||
static bytea *bytea_substring(Datum str,
|
||||
int S,
|
||||
int L,
|
||||
bool length_not_specified);
|
||||
static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
@ -559,17 +567,31 @@ textcat(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *t1 = PG_GETARG_TEXT_PP(0);
|
||||
text *t2 = PG_GETARG_TEXT_PP(1);
|
||||
|
||||
PG_RETURN_TEXT_P(text_catenate(t1, t2));
|
||||
}
|
||||
|
||||
/*
|
||||
* text_catenate
|
||||
* Guts of textcat(), broken out so it can be used by other functions
|
||||
*
|
||||
* Arguments can be in short-header form, but not compressed or out-of-line
|
||||
*/
|
||||
static text *
|
||||
text_catenate(text *t1, text *t2)
|
||||
{
|
||||
text *result;
|
||||
int len1,
|
||||
len2,
|
||||
len;
|
||||
text *result;
|
||||
char *ptr;
|
||||
|
||||
len1 = VARSIZE_ANY_EXHDR(t1);
|
||||
len2 = VARSIZE_ANY_EXHDR(t2);
|
||||
|
||||
/* paranoia ... probably should throw error instead? */
|
||||
if (len1 < 0)
|
||||
len1 = 0;
|
||||
|
||||
len2 = VARSIZE_ANY_EXHDR(t2);
|
||||
if (len2 < 0)
|
||||
len2 = 0;
|
||||
|
||||
@ -586,7 +608,7 @@ textcat(PG_FUNCTION_ARGS)
|
||||
if (len2 > 0)
|
||||
memcpy(ptr + len1, VARDATA_ANY(t2), len2);
|
||||
|
||||
PG_RETURN_TEXT_P(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -865,6 +887,67 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* textoverlay
|
||||
* 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
|
||||
textoverlay(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *t1 = PG_GETARG_TEXT_PP(0);
|
||||
text *t2 = PG_GETARG_TEXT_PP(1);
|
||||
int sp = PG_GETARG_INT32(2); /* substring start position */
|
||||
int sl = PG_GETARG_INT32(3); /* substring length */
|
||||
|
||||
PG_RETURN_TEXT_P(text_overlay(t1, t2, sp, sl));
|
||||
}
|
||||
|
||||
Datum
|
||||
textoverlay_no_len(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *t1 = PG_GETARG_TEXT_PP(0);
|
||||
text *t2 = PG_GETARG_TEXT_PP(1);
|
||||
int sp = PG_GETARG_INT32(2); /* substring start position */
|
||||
int sl;
|
||||
|
||||
sl = text_length(PointerGetDatum(t2)); /* defaults to length(t2) */
|
||||
PG_RETURN_TEXT_P(text_overlay(t1, t2, sp, sl));
|
||||
}
|
||||
|
||||
static text *
|
||||
text_overlay(text *t1, text *t2, int sp, int sl)
|
||||
{
|
||||
text *result;
|
||||
text *s1;
|
||||
text *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 = text_substring(PointerGetDatum(t1), 1, sp-1, false);
|
||||
s2 = text_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
|
||||
result = text_catenate(s1, t2);
|
||||
result = text_catenate(result, s2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* textpos -
|
||||
* Return the position of the specified substring.
|
||||
@ -1640,17 +1723,31 @@ byteacat(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *t1 = PG_GETARG_BYTEA_PP(0);
|
||||
bytea *t2 = PG_GETARG_BYTEA_PP(1);
|
||||
|
||||
PG_RETURN_BYTEA_P(bytea_catenate(t1, t2));
|
||||
}
|
||||
|
||||
/*
|
||||
* bytea_catenate
|
||||
* Guts of byteacat(), broken out so it can be used by other functions
|
||||
*
|
||||
* Arguments can be in short-header form, but not compressed or out-of-line
|
||||
*/
|
||||
static bytea *
|
||||
bytea_catenate(bytea *t1, bytea *t2)
|
||||
{
|
||||
bytea *result;
|
||||
int len1,
|
||||
len2,
|
||||
len;
|
||||
bytea *result;
|
||||
char *ptr;
|
||||
|
||||
len1 = VARSIZE_ANY_EXHDR(t1);
|
||||
len2 = VARSIZE_ANY_EXHDR(t2);
|
||||
|
||||
/* paranoia ... probably should throw error instead? */
|
||||
if (len1 < 0)
|
||||
len1 = 0;
|
||||
|
||||
len2 = VARSIZE_ANY_EXHDR(t2);
|
||||
if (len2 < 0)
|
||||
len2 = 0;
|
||||
|
||||
@ -1667,7 +1764,7 @@ byteacat(PG_FUNCTION_ARGS)
|
||||
if (len2 > 0)
|
||||
memcpy(ptr + len1, VARDATA_ANY(t2), len2);
|
||||
|
||||
PG_RETURN_BYTEA_P(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#define PG_STR_GET_BYTEA(str_) \
|
||||
@ -1691,16 +1788,41 @@ byteacat(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
bytea_substr(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int S = PG_GETARG_INT32(1); /* start position */
|
||||
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
|
||||
PG_GETARG_INT32(1),
|
||||
PG_GETARG_INT32(2),
|
||||
false));
|
||||
}
|
||||
|
||||
/*
|
||||
* bytea_substr_no_len -
|
||||
* Wrapper to avoid opr_sanity failure due to
|
||||
* one function accepting a different number of args.
|
||||
*/
|
||||
Datum
|
||||
bytea_substr_no_len(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_BYTEA_P(bytea_substring(PG_GETARG_DATUM(0),
|
||||
PG_GETARG_INT32(1),
|
||||
-1,
|
||||
true));
|
||||
}
|
||||
|
||||
static bytea *
|
||||
bytea_substring(Datum str,
|
||||
int S,
|
||||
int L,
|
||||
bool length_not_specified)
|
||||
{
|
||||
int S1; /* adjusted start position */
|
||||
int L1; /* adjusted substring length */
|
||||
|
||||
S1 = Max(S, 1);
|
||||
|
||||
if (fcinfo->nargs == 2)
|
||||
if (length_not_specified)
|
||||
{
|
||||
/*
|
||||
* Not passed a length - PG_GETARG_BYTEA_P_SLICE() grabs everything to
|
||||
* Not passed a length - DatumGetByteaPSlice() grabs everything to
|
||||
* the end of the string if we pass it a negative value for length.
|
||||
*/
|
||||
L1 = -1;
|
||||
@ -1708,7 +1830,7 @@ bytea_substr(PG_FUNCTION_ARGS)
|
||||
else
|
||||
{
|
||||
/* end position */
|
||||
int E = S + PG_GETARG_INT32(2);
|
||||
int E = S + L;
|
||||
|
||||
/*
|
||||
* A negative value for L is the only way for the end position to be
|
||||
@ -1725,28 +1847,78 @@ bytea_substr(PG_FUNCTION_ARGS)
|
||||
* string.
|
||||
*/
|
||||
if (E < 1)
|
||||
PG_RETURN_BYTEA_P(PG_STR_GET_BYTEA(""));
|
||||
return PG_STR_GET_BYTEA("");
|
||||
|
||||
L1 = E - S1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the start position is past the end of the string, SQL99 says to
|
||||
* return a zero-length string -- PG_GETARG_TEXT_P_SLICE() will do that
|
||||
* return a zero-length string -- DatumGetByteaPSlice() will do that
|
||||
* for us. Convert to zero-based starting position
|
||||
*/
|
||||
PG_RETURN_BYTEA_P(PG_GETARG_BYTEA_P_SLICE(0, S1 - 1, L1));
|
||||
return DatumGetByteaPSlice(str, S1 - 1, L1);
|
||||
}
|
||||
|
||||
/*
|
||||
* bytea_substr_no_len -
|
||||
* Wrapper to avoid opr_sanity failure due to
|
||||
* one function accepting a different number of args.
|
||||
* byteaoverlay
|
||||
* 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
|
||||
bytea_substr_no_len(PG_FUNCTION_ARGS)
|
||||
byteaoverlay(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return bytea_substr(fcinfo);
|
||||
bytea *t1 = PG_GETARG_BYTEA_PP(0);
|
||||
bytea *t2 = PG_GETARG_BYTEA_PP(1);
|
||||
int sp = PG_GETARG_INT32(2); /* substring start position */
|
||||
int sl = PG_GETARG_INT32(3); /* substring length */
|
||||
|
||||
PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
|
||||
}
|
||||
|
||||
Datum
|
||||
byteaoverlay_no_len(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *t1 = PG_GETARG_BYTEA_PP(0);
|
||||
bytea *t2 = PG_GETARG_BYTEA_PP(1);
|
||||
int sp = PG_GETARG_INT32(2); /* substring start position */
|
||||
int sl;
|
||||
|
||||
sl = VARSIZE_ANY_EXHDR(t2); /* defaults to length(t2) */
|
||||
PG_RETURN_BYTEA_P(bytea_overlay(t1, t2, sp, sl));
|
||||
}
|
||||
|
||||
static bytea *
|
||||
bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
|
||||
{
|
||||
bytea *result;
|
||||
bytea *s1;
|
||||
bytea *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 = bytea_substring(PointerGetDatum(t1), 1, sp-1, false);
|
||||
s2 = bytea_substring(PointerGetDatum(t1), sp_pl_sl, -1, true);
|
||||
result = bytea_catenate(s1, t2);
|
||||
result = bytea_catenate(result, s2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user