Commit 9507c8a1 authored by Tom Lane's avatar Tom Lane

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
parent 1d1f425f
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.497 2010/01/19 05:50:18 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.498 2010/01/25 20:55:32 tgl Exp $ -->
<chapter id="functions"> <chapter id="functions">
<title>Functions and Operators</title> <title>Functions and Operators</title>
...@@ -2620,7 +2620,7 @@ ...@@ -2620,7 +2620,7 @@
<entry>Return Type</entry> <entry>Return Type</entry>
<entry>Description</entry> <entry>Description</entry>
<entry>Example</entry> <entry>Example</entry>
<entry>Result</entry> <entry>Result</entry>
</row> </row>
</thead> </thead>
...@@ -2640,32 +2640,6 @@ ...@@ -2640,32 +2640,6 @@
<entry><literal>\\Post'gres\000</literal></entry> <entry><literal>\\Post'gres\000</literal></entry>
</row> </row>
<row>
<entry><function>get_bit</function>(<parameter>string</parameter>, <parameter>offset</parameter>)</entry>
<entry><type>int</type></entry>
<entry>
Extract bit from string
<indexterm>
<primary>get_bit</primary>
</indexterm>
</entry>
<entry><literal>get_bit(E'Th\\000omas'::bytea, 45)</literal></entry>
<entry><literal>1</literal></entry>
</row>
<row>
<entry><function>get_byte</function>(<parameter>string</parameter>, <parameter>offset</parameter>)</entry>
<entry><type>int</type></entry>
<entry>
Extract byte from string
<indexterm>
<primary>get_byte</primary>
</indexterm>
</entry>
<entry><literal>get_byte(E'Th\\000omas'::bytea, 4)</literal></entry>
<entry><literal>109</literal></entry>
</row>
<row> <row>
<entry><literal><function>octet_length</function>(<parameter>string</parameter>)</literal></entry> <entry><literal><function>octet_length</function>(<parameter>string</parameter>)</literal></entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
...@@ -2675,39 +2649,21 @@ ...@@ -2675,39 +2649,21 @@
</row> </row>
<row> <row>
<entry><literal><function>position</function>(<parameter>substring</parameter> in <parameter>string</parameter>)</literal></entry> <entry><literal><function>overlay</function>(<parameter>string</parameter> placing <parameter>string</parameter> from <type>int</type> <optional>for <type>int</type></optional>)</literal></entry>
<entry><type>int</type></entry>
<entry>Location of specified substring</entry>
<entry><literal>position(E'\\000om'::bytea in E'Th\\000omas'::bytea)</literal></entry>
<entry><literal>3</literal></entry>
</row>
<row>
<entry><function>set_bit</function>(<parameter>string</parameter>,
<parameter>offset</parameter>, <parameter>newvalue</>)</entry>
<entry><type>bytea</type></entry> <entry><type>bytea</type></entry>
<entry> <entry>
Set bit in string Replace substring
<indexterm>
<primary>set_bit</primary>
</indexterm>
</entry> </entry>
<entry><literal>set_bit(E'Th\\000omas'::bytea, 45, 0)</literal></entry> <entry><literal>overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 2 for 3)</literal></entry>
<entry><literal>Th\000omAs</literal></entry> <entry><literal>T\\002\\003mas</literal></entry>
</row> </row>
<row> <row>
<entry><function>set_byte</function>(<parameter>string</parameter>, <entry><literal><function>position</function>(<parameter>substring</parameter> in <parameter>string</parameter>)</literal></entry>
<parameter>offset</parameter>, <parameter>newvalue</>)</entry> <entry><type>int</type></entry>
<entry><type>bytea</type></entry> <entry>Location of specified substring</entry>
<entry> <entry><literal>position(E'\\000om'::bytea in E'Th\\000omas'::bytea)</literal></entry>
Set byte in string <entry><literal>3</literal></entry>
<indexterm>
<primary>set_byte</primary>
</indexterm>
</entry>
<entry><literal>set_byte(E'Th\\000omas'::bytea, 4, 64)</literal></entry>
<entry><literal>Th\000o@as</literal></entry>
</row> </row>
<row> <row>
...@@ -2784,7 +2740,7 @@ ...@@ -2784,7 +2740,7 @@
</entry> </entry>
<entry><type>bytea</type></entry> <entry><type>bytea</type></entry>
<entry> <entry>
Decode binary string from <parameter>string</parameter> previously Decode binary string from <parameter>string</parameter> previously
encoded with <function>encode</>. Parameter type is same as in <function>encode</>. encoded with <function>encode</>. Parameter type is same as in <function>encode</>.
</entry> </entry>
<entry><literal>decode(E'123\\000456', 'escape')</literal></entry> <entry><literal>decode(E'123\\000456', 'escape')</literal></entry>
...@@ -2805,6 +2761,36 @@ ...@@ -2805,6 +2761,36 @@
<entry><literal>123\000456</literal></entry> <entry><literal>123\000456</literal></entry>
</row> </row>
<row>
<entry>
<literal><function>get_bit</function>(<parameter>string</parameter>, <parameter>offset</parameter>)</literal>
</entry>
<entry><type>int</type></entry>
<entry>
Extract bit from string
<indexterm>
<primary>get_bit</primary>
</indexterm>
</entry>
<entry><literal>get_bit(E'Th\\000omas'::bytea, 45)</literal></entry>
<entry><literal>1</literal></entry>
</row>
<row>
<entry>
<literal><function>get_byte</function>(<parameter>string</parameter>, <parameter>offset</parameter>)</literal>
</entry>
<entry><type>int</type></entry>
<entry>
Extract byte from string
<indexterm>
<primary>get_byte</primary>
</indexterm>
</entry>
<entry><literal>get_byte(E'Th\\000omas'::bytea, 4)</literal></entry>
<entry><literal>109</literal></entry>
</row>
<row> <row>
<entry><literal><function>length</function>(<parameter>string</parameter>)</literal></entry> <entry><literal><function>length</function>(<parameter>string</parameter>)</literal></entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
...@@ -2834,6 +2820,38 @@ ...@@ -2834,6 +2820,38 @@
<entry><literal>md5(E'Th\\000omas'::bytea)</literal></entry> <entry><literal>md5(E'Th\\000omas'::bytea)</literal></entry>
<entry><literal>8ab2d3c9689aaf18 b4958c334c82d8b1</literal></entry> <entry><literal>8ab2d3c9689aaf18 b4958c334c82d8b1</literal></entry>
</row> </row>
<row>
<entry>
<literal><function>set_bit</function>(<parameter>string</parameter>,
<parameter>offset</parameter>, <parameter>newvalue</>)</literal>
</entry>
<entry><type>bytea</type></entry>
<entry>
Set bit in string
<indexterm>
<primary>set_bit</primary>
</indexterm>
</entry>
<entry><literal>set_bit(E'Th\\000omas'::bytea, 45, 0)</literal></entry>
<entry><literal>Th\000omAs</literal></entry>
</row>
<row>
<entry>
<literal><function>set_byte</function>(<parameter>string</parameter>,
<parameter>offset</parameter>, <parameter>newvalue</>)</literal>
</entry>
<entry><type>bytea</type></entry>
<entry>
Set byte in string
<indexterm>
<primary>set_byte</primary>
</indexterm>
</entry>
<entry><literal>set_byte(E'Th\\000omas'::bytea, 4, 64)</literal></entry>
<entry><literal>Th\000o@as</literal></entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
...@@ -2934,7 +2952,15 @@ ...@@ -2934,7 +2952,15 @@
<literal><function>bit_length</function></literal>, <literal><function>bit_length</function></literal>,
<literal><function>octet_length</function></literal>, <literal><function>octet_length</function></literal>,
<literal><function>position</function></literal>, <literal><function>position</function></literal>,
<literal><function>substring</function></literal>. <literal><function>substring</function></literal>,
<literal><function>overlay</function></literal>.
</para>
<para>
The following functions work on bit strings as well as binary
strings:
<literal><function>get_bit</function></literal>,
<literal><function>set_bit</function></literal>.
</para> </para>
<para> <para>
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.704 2010/01/22 16:40:18 rhaas Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.705 2010/01/25 20:55:32 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -9586,9 +9586,9 @@ func_expr: func_name '(' ')' over_clause ...@@ -9586,9 +9586,9 @@ func_expr: func_name '(' ')' over_clause
| OVERLAY '(' overlay_list ')' | OVERLAY '(' overlay_list ')'
{ {
/* overlay(A PLACING B FROM C FOR D) is converted to /* overlay(A PLACING B FROM C FOR D) is converted to
* substring(A, 1, C-1) || B || substring(A, C+1, C+D) * overlay(A, B, C, D)
* overlay(A PLACING B FROM C) is converted to * overlay(A PLACING B FROM C) is converted to
* substring(A, 1, C-1) || B || substring(A, C+1, C+char_length(B)) * overlay(A, B, C)
*/ */
FuncCall *n = makeNode(FuncCall); FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("overlay"); n->funcname = SystemFuncName("overlay");
...@@ -10150,6 +10150,7 @@ extract_arg: ...@@ -10150,6 +10150,7 @@ extract_arg:
* SQL99 defines the OVERLAY() function: * SQL99 defines the OVERLAY() function:
* o overlay(text placing text from int for int) * o overlay(text placing text from int for int)
* o overlay(text placing text from int) * o overlay(text placing text from int)
* and similarly for binary strings
*/ */
overlay_list: overlay_list:
a_expr overlay_placing substr_from substr_for a_expr overlay_placing substr_from substr_for
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -23,8 +23,10 @@
#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A')) #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, static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l,
bool length_not_specified); bool length_not_specified);
static VarBit *bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl);
/* common code for bittypmodin and varbittypmodin */ /* common code for bittypmodin and varbittypmodin */
...@@ -877,6 +879,13 @@ bitcat(PG_FUNCTION_ARGS) ...@@ -877,6 +879,13 @@ bitcat(PG_FUNCTION_ARGS)
{ {
VarBit *arg1 = PG_GETARG_VARBIT_P(0); VarBit *arg1 = PG_GETARG_VARBIT_P(0);
VarBit *arg2 = PG_GETARG_VARBIT_P(1); 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; VarBit *result;
int bitlen1, int bitlen1,
bitlen2, bitlen2,
...@@ -919,7 +928,7 @@ bitcat(PG_FUNCTION_ARGS) ...@@ -919,7 +928,7 @@ bitcat(PG_FUNCTION_ARGS)
} }
} }
PG_RETURN_VARBIT_P(result); return result;
} }
/* bitsubstr /* bitsubstr
...@@ -1034,6 +1043,67 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified) ...@@ -1034,6 +1043,67 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
return result; 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 /* bitlength, bitoctetlength
* Return the length of a bit string * Return the length of a bit string
*/ */
...@@ -1606,3 +1676,103 @@ bitposition(PG_FUNCTION_ARGS) ...@@ -1606,3 +1676,103 @@ bitposition(PG_FUNCTION_ARGS)
} }
PG_RETURN_INT32(0); 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 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -60,11 +60,19 @@ static int text_position(text *t1, text *t2);
static void text_position_setup(text *t1, text *t2, TextPositionState *state); static void text_position_setup(text *t1, text *t2, TextPositionState *state);
static int text_position_next(int start_pos, TextPositionState *state); static int text_position_next(int start_pos, TextPositionState *state);
static void text_position_cleanup(TextPositionState *state); static void text_position_cleanup(TextPositionState *state);
static text *text_catenate(text *t1, text *t2);
static text *text_substring(Datum str, static text *text_substring(Datum str,
int32 start, int32 start,
int32 length, int32 length,
bool length_not_specified); 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 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) ...@@ -559,17 +567,31 @@ textcat(PG_FUNCTION_ARGS)
{ {
text *t1 = PG_GETARG_TEXT_PP(0); text *t1 = PG_GETARG_TEXT_PP(0);
text *t2 = PG_GETARG_TEXT_PP(1); 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, int len1,
len2, len2,
len; len;
text *result;
char *ptr; char *ptr;
len1 = VARSIZE_ANY_EXHDR(t1); len1 = VARSIZE_ANY_EXHDR(t1);
len2 = VARSIZE_ANY_EXHDR(t2);
/* paranoia ... probably should throw error instead? */
if (len1 < 0) if (len1 < 0)
len1 = 0; len1 = 0;
len2 = VARSIZE_ANY_EXHDR(t2);
if (len2 < 0) if (len2 < 0)
len2 = 0; len2 = 0;
...@@ -586,7 +608,7 @@ textcat(PG_FUNCTION_ARGS) ...@@ -586,7 +608,7 @@ textcat(PG_FUNCTION_ARGS)
if (len2 > 0) if (len2 > 0)
memcpy(ptr + len1, VARDATA_ANY(t2), len2); 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) ...@@ -865,6 +887,67 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
return NULL; 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 - * textpos -
* Return the position of the specified substring. * Return the position of the specified substring.
...@@ -1640,17 +1723,31 @@ byteacat(PG_FUNCTION_ARGS) ...@@ -1640,17 +1723,31 @@ byteacat(PG_FUNCTION_ARGS)
{ {
bytea *t1 = PG_GETARG_BYTEA_PP(0); bytea *t1 = PG_GETARG_BYTEA_PP(0);
bytea *t2 = PG_GETARG_BYTEA_PP(1); 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, int len1,
len2, len2,
len; len;
bytea *result;
char *ptr; char *ptr;
len1 = VARSIZE_ANY_EXHDR(t1); len1 = VARSIZE_ANY_EXHDR(t1);
len2 = VARSIZE_ANY_EXHDR(t2);
/* paranoia ... probably should throw error instead? */
if (len1 < 0) if (len1 < 0)
len1 = 0; len1 = 0;
len2 = VARSIZE_ANY_EXHDR(t2);
if (len2 < 0) if (len2 < 0)
len2 = 0; len2 = 0;
...@@ -1667,7 +1764,7 @@ byteacat(PG_FUNCTION_ARGS) ...@@ -1667,7 +1764,7 @@ byteacat(PG_FUNCTION_ARGS)
if (len2 > 0) if (len2 > 0)
memcpy(ptr + len1, VARDATA_ANY(t2), len2); memcpy(ptr + len1, VARDATA_ANY(t2), len2);
PG_RETURN_BYTEA_P(result); return result;
} }
#define PG_STR_GET_BYTEA(str_) \ #define PG_STR_GET_BYTEA(str_) \
...@@ -1691,16 +1788,41 @@ byteacat(PG_FUNCTION_ARGS) ...@@ -1691,16 +1788,41 @@ byteacat(PG_FUNCTION_ARGS)
Datum Datum
bytea_substr(PG_FUNCTION_ARGS) 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 S1; /* adjusted start position */
int L1; /* adjusted substring length */ int L1; /* adjusted substring length */
S1 = Max(S, 1); 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. * the end of the string if we pass it a negative value for length.
*/ */
L1 = -1; L1 = -1;
...@@ -1708,7 +1830,7 @@ bytea_substr(PG_FUNCTION_ARGS) ...@@ -1708,7 +1830,7 @@ bytea_substr(PG_FUNCTION_ARGS)
else else
{ {
/* end position */ /* 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 * A negative value for L is the only way for the end position to be
...@@ -1725,28 +1847,78 @@ bytea_substr(PG_FUNCTION_ARGS) ...@@ -1725,28 +1847,78 @@ bytea_substr(PG_FUNCTION_ARGS)
* string. * string.
*/ */
if (E < 1) if (E < 1)
PG_RETURN_BYTEA_P(PG_STR_GET_BYTEA("")); return PG_STR_GET_BYTEA("");
L1 = E - S1; L1 = E - S1;
} }
/* /*
* If the start position is past the end of the string, SQL99 says to * 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 * 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 - * byteaoverlay
* Wrapper to avoid opr_sanity failure due to * Replace specified substring of first string with second
* one function accepting a different number of args. *
* The SQL standard defines OVERLAY() in terms of substring and concatenation.
* This code is a direct implementation of what the standard says.
*/ */
Datum 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;
} }
/* /*
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.578 2010/01/22 16:42:31 rhaas Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.579 2010/01/25 20:55:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201001222 #define CATALOG_VERSION_NO 201001251
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.564 2010/01/19 14:11:32 mha Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.565 2010/01/25 20:55:32 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.pl reads this file and generates .bki * The script catalog/genbki.pl reads this file and generates .bki
...@@ -957,6 +957,10 @@ DATA(insert OID = 723 ( get_bit PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "17 ...@@ -957,6 +957,10 @@ DATA(insert OID = 723 ( get_bit PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "17
DESCR("get bit"); DESCR("get bit");
DATA(insert OID = 724 ( set_bit PGNSP PGUID 12 1 0 0 f f f t f i 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ byteaSetBit _null_ _null_ _null_ )); DATA(insert OID = 724 ( set_bit PGNSP PGUID 12 1 0 0 f f f t f i 3 0 17 "17 23 23" _null_ _null_ _null_ _null_ byteaSetBit _null_ _null_ _null_ ));
DESCR("set bit"); DESCR("set bit");
DATA(insert OID = 749 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 4 0 17 "17 17 23 23" _null_ _null_ _null_ _null_ byteaoverlay _null_ _null_ _null_ ));
DESCR("substitute portion of string");
DATA(insert OID = 752 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 3 0 17 "17 17 23" _null_ _null_ _null_ _null_ byteaoverlay_no_len _null_ _null_ _null_ ));
DESCR("substitute portion of string");
DATA(insert OID = 725 ( dist_pl PGNSP PGUID 12 1 0 0 f f f t f i 2 0 701 "600 628" _null_ _null_ _null_ _null_ dist_pl _null_ _null_ _null_ )); DATA(insert OID = 725 ( dist_pl PGNSP PGUID 12 1 0 0 f f f t f i 2 0 701 "600 628" _null_ _null_ _null_ _null_ dist_pl _null_ _null_ _null_ ));
DESCR("distance between point and line"); DESCR("distance between point and line");
...@@ -1832,9 +1836,9 @@ DESCR("current schema name"); ...@@ -1832,9 +1836,9 @@ DESCR("current schema name");
DATA(insert OID = 1403 ( current_schemas PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1003 "16" _null_ _null_ _null_ _null_ current_schemas _null_ _null_ _null_ )); DATA(insert OID = 1403 ( current_schemas PGNSP PGUID 12 1 0 0 f f f t f s 1 0 1003 "16" _null_ _null_ _null_ _null_ current_schemas _null_ _null_ _null_ ));
DESCR("current schema search list"); DESCR("current schema search list");
DATA(insert OID = 1404 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 4 0 25 "25 25 23 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + $4))" _null_ _null_ _null_ )); DATA(insert OID = 1404 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 4 0 25 "25 25 23 23" _null_ _null_ _null_ _null_ textoverlay _null_ _null_ _null_ ));
DESCR("substitute portion of string"); DESCR("substitute portion of string");
DATA(insert OID = 1405 ( overlay PGNSP PGUID 14 1 0 0 f f f t f i 3 0 25 "25 25 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, 1, ($3 - 1)) || $2 || pg_catalog.substring($1, ($3 + pg_catalog.char_length($2)))" _null_ _null_ _null_ )); DATA(insert OID = 1405 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 3 0 25 "25 25 23" _null_ _null_ _null_ _null_ textoverlay_no_len _null_ _null_ _null_ ));
DESCR("substitute portion of string"); DESCR("substitute portion of string");
DATA(insert OID = 1406 ( isvertical PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "600 600" _null_ _null_ _null_ _null_ point_vert _null_ _null_ _null_ )); DATA(insert OID = 1406 ( isvertical PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "600 600" _null_ _null_ _null_ _null_ point_vert _null_ _null_ _null_ ));
...@@ -2402,9 +2406,17 @@ DESCR("adjust varbit() to typmod length"); ...@@ -2402,9 +2406,17 @@ DESCR("adjust varbit() to typmod length");
DATA(insert OID = 1698 ( position PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ )); DATA(insert OID = 1698 ( position PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ ));
DESCR("return position of sub-bitstring"); DESCR("return position of sub-bitstring");
DATA(insert OID = 1699 ( substring PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ bitsubstr_no_len _null_ _null_ _null_ )); DATA(insert OID = 1699 ( substring PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ bitsubstr_no_len _null_ _null_ _null_ ));
DESCR("return portion of bitstring"); DESCR("return portion of bitstring");
DATA(insert OID = 3030 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 4 0 1560 "1560 1560 23 23" _null_ _null_ _null_ _null_ bitoverlay _null_ _null_ _null_ ));
DESCR("substitute portion of bitstring");
DATA(insert OID = 3031 ( overlay PGNSP PGUID 12 1 0 0 f f f t f i 3 0 1560 "1560 1560 23" _null_ _null_ _null_ _null_ bitoverlay_no_len _null_ _null_ _null_ ));
DESCR("substitute portion of bitstring");
DATA(insert OID = 3032 ( get_bit PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "1560 23" _null_ _null_ _null_ _null_ bitgetbit _null_ _null_ _null_ ));
DESCR("get bit");
DATA(insert OID = 3033 ( set_bit PGNSP PGUID 12 1 0 0 f f f t f i 3 0 1560 "1560 23 23" _null_ _null_ _null_ _null_ bitsetbit _null_ _null_ _null_ ));
DESCR("set bit");
/* for mac type support */ /* for mac type support */
DATA(insert OID = 436 ( macaddr_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 829 "2275" _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ )); DATA(insert OID = 436 ( macaddr_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 829 "2275" _null_ _null_ _null_ _null_ macaddr_in _null_ _null_ _null_ ));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.344 2010/01/19 05:50:18 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.345 2010/01/25 20:55:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -698,6 +698,8 @@ extern Datum textoctetlen(PG_FUNCTION_ARGS); ...@@ -698,6 +698,8 @@ extern Datum textoctetlen(PG_FUNCTION_ARGS);
extern Datum textpos(PG_FUNCTION_ARGS); extern Datum textpos(PG_FUNCTION_ARGS);
extern Datum text_substr(PG_FUNCTION_ARGS); extern Datum text_substr(PG_FUNCTION_ARGS);
extern Datum text_substr_no_len(PG_FUNCTION_ARGS); extern Datum text_substr_no_len(PG_FUNCTION_ARGS);
extern Datum textoverlay(PG_FUNCTION_ARGS);
extern Datum textoverlay_no_len(PG_FUNCTION_ARGS);
extern Datum name_text(PG_FUNCTION_ARGS); extern Datum name_text(PG_FUNCTION_ARGS);
extern Datum text_name(PG_FUNCTION_ARGS); extern Datum text_name(PG_FUNCTION_ARGS);
extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2); extern int varstr_cmp(char *arg1, int len1, char *arg2, int len2);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/bytea.h,v 1.2 2010/01/02 16:58:10 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/bytea.h,v 1.3 2010/01/25 20:55:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,5 +46,7 @@ extern Datum byteacat(PG_FUNCTION_ARGS); ...@@ -46,5 +46,7 @@ extern Datum byteacat(PG_FUNCTION_ARGS);
extern Datum byteapos(PG_FUNCTION_ARGS); extern Datum byteapos(PG_FUNCTION_ARGS);
extern Datum bytea_substr(PG_FUNCTION_ARGS); extern Datum bytea_substr(PG_FUNCTION_ARGS);
extern Datum bytea_substr_no_len(PG_FUNCTION_ARGS); extern Datum bytea_substr_no_len(PG_FUNCTION_ARGS);
extern Datum byteaoverlay(PG_FUNCTION_ARGS);
extern Datum byteaoverlay_no_len(PG_FUNCTION_ARGS);
#endif /* BYTEA_H */ #endif /* BYTEA_H */
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.30 2010/01/07 20:17:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.31 2010/01/25 20:55:32 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -89,6 +89,8 @@ extern Datum bitshiftright(PG_FUNCTION_ARGS); ...@@ -89,6 +89,8 @@ extern Datum bitshiftright(PG_FUNCTION_ARGS);
extern Datum bitcat(PG_FUNCTION_ARGS); extern Datum bitcat(PG_FUNCTION_ARGS);
extern Datum bitsubstr(PG_FUNCTION_ARGS); extern Datum bitsubstr(PG_FUNCTION_ARGS);
extern Datum bitsubstr_no_len(PG_FUNCTION_ARGS); extern Datum bitsubstr_no_len(PG_FUNCTION_ARGS);
extern Datum bitoverlay(PG_FUNCTION_ARGS);
extern Datum bitoverlay_no_len(PG_FUNCTION_ARGS);
extern Datum bitlength(PG_FUNCTION_ARGS); extern Datum bitlength(PG_FUNCTION_ARGS);
extern Datum bitoctetlength(PG_FUNCTION_ARGS); extern Datum bitoctetlength(PG_FUNCTION_ARGS);
extern Datum bitfromint4(PG_FUNCTION_ARGS); extern Datum bitfromint4(PG_FUNCTION_ARGS);
...@@ -96,5 +98,7 @@ extern Datum bittoint4(PG_FUNCTION_ARGS); ...@@ -96,5 +98,7 @@ extern Datum bittoint4(PG_FUNCTION_ARGS);
extern Datum bitfromint8(PG_FUNCTION_ARGS); extern Datum bitfromint8(PG_FUNCTION_ARGS);
extern Datum bittoint8(PG_FUNCTION_ARGS); extern Datum bittoint8(PG_FUNCTION_ARGS);
extern Datum bitposition(PG_FUNCTION_ARGS); extern Datum bitposition(PG_FUNCTION_ARGS);
extern Datum bitsetbit(PG_FUNCTION_ARGS);
extern Datum bitgetbit(PG_FUNCTION_ARGS);
#endif #endif
...@@ -509,3 +509,43 @@ SELECT POSITION(B'1101' IN v), ...@@ -509,3 +509,43 @@ SELECT POSITION(B'1101' IN v),
DROP TABLE BIT_SHIFT_TABLE; DROP TABLE BIT_SHIFT_TABLE;
DROP TABLE VARBIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE;
-- Get/Set bit
SELECT get_bit(B'0101011000100', 10);
get_bit
---------
1
(1 row)
SELECT set_bit(B'0101011000100100', 15, 1);
set_bit
------------------
0101011000100101
(1 row)
SELECT set_bit(B'0101011000100100', 16, 1); -- fail
ERROR: bit index 16 out of valid range (0..15)
-- Overlay
SELECT overlay(B'0101011100' placing '001' from 2 for 3);
overlay
------------
0001011100
(1 row)
SELECT overlay(B'0101011100' placing '101' from 6);
overlay
------------
0101010100
(1 row)
SELECT overlay(B'0101011100' placing '001' from 11);
overlay
---------------
0101011100001
(1 row)
SELECT overlay(B'0101011100' placing '001' from 20);
overlay
---------------
0101011100001
(1 row)
...@@ -1579,3 +1579,21 @@ SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); ...@@ -1579,3 +1579,21 @@ SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea);
\000trim\000 \000trim\000
(1 row) (1 row)
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape');
encode
-------------
TTh\x01omas
(1 row)
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape');
encode
--------------------
Th\000omas\x02\x03
(1 row)
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape');
encode
-----------------
Th\000o\x02\x03
(1 row)
...@@ -184,3 +184,14 @@ SELECT POSITION(B'1101' IN v), ...@@ -184,3 +184,14 @@ SELECT POSITION(B'1101' IN v),
DROP TABLE BIT_SHIFT_TABLE; DROP TABLE BIT_SHIFT_TABLE;
DROP TABLE VARBIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE;
-- Get/Set bit
SELECT get_bit(B'0101011000100', 10);
SELECT set_bit(B'0101011000100100', 15, 1);
SELECT set_bit(B'0101011000100100', 16, 1); -- fail
-- Overlay
SELECT overlay(B'0101011100' placing '001' from 2 for 3);
SELECT overlay(B'0101011100' placing '101' from 6);
SELECT overlay(B'0101011100' placing '001' from 11);
SELECT overlay(B'0101011100' placing '001' from 20);
...@@ -547,3 +547,6 @@ SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea); ...@@ -547,3 +547,6 @@ SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea);
SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea); SELECT btrim(E'\\000trim\\000'::bytea, E'\\000'::bytea);
SELECT btrim(''::bytea, E'\\000'::bytea); SELECT btrim(''::bytea, E'\\000'::bytea);
SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea);
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape');
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape');
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment