diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-01-25 20:55:32 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-01-25 20:55:32 +0000 |
commit | 9507c8a1db14d022296144f391ea4741f4f848ca (patch) | |
tree | 72fe8e5370f8b8d9ef07dc460daaac5be1797430 /src/backend/utils/adt/varlena.c | |
parent | 1d1f425f8d4331ecf09512386880af0827cd6091 (diff) | |
download | postgresql-9507c8a1db14d022296144f391ea4741f4f848ca.tar.gz postgresql-9507c8a1db14d022296144f391ea4741f4f848ca.zip |
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
Diffstat (limited to 'src/backend/utils/adt/varlena.c')
-rw-r--r-- | src/backend/utils/adt/varlena.c | 214 |
1 files changed, 193 insertions, 21 deletions
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 53650c88786..7a8abf14a83 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -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; } /* @@ -866,6 +888,67 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified) } /* + * 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. * Implements the SQL92 POSITION() function. @@ -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; } /* |