mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-03 02:27:19 +02:00
Fix integer-overflow corner cases in substring() functions.
If the substring start index and length overflow when added together,
substring() misbehaved, either throwing a bogus "negative substring
length" error on a case that should succeed, or failing to complain that
a negative length is negative (and instead returning the whole string,
in most cases). Unsurprisingly, the text, bytea, and bit variants of
the function all had this issue. Rearrange the logic to ensure that
negative lengths are always rejected, and add an overflow check to
handle the other case.
Also install similar guards into detoast_attr_slice() (nee
heap_tuple_untoast_attr_slice()), since it's far from clear that
no other code paths leading to that function could pass it values
that would overflow.
Patch by myself and Pavel Stehule, per bug #16804 from Rafi Shamim.
Back-patch to v11. While these bugs are old, the common/int.h
infrastructure for overflow-detecting arithmetic didn't exist before
commit 4d6ad3125
, and it doesn't seem like these misbehaviors are bad
enough to justify developing a standalone fix for the older branches.
Discussion: https://postgr.es/m/16804-f4eeeb6c11ba71d4@postgresql.org
This commit is contained in:
parent
f6704ac83e
commit
50a420bee0
@ -35,6 +35,7 @@
|
|||||||
#include "access/tuptoaster.h"
|
#include "access/tuptoaster.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/catalog.h"
|
#include "catalog/catalog.h"
|
||||||
|
#include "common/int.h"
|
||||||
#include "common/pg_lzcompress.h"
|
#include "common/pg_lzcompress.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "utils/expandeddatum.h"
|
#include "utils/expandeddatum.h"
|
||||||
@ -252,6 +253,9 @@ heap_tuple_untoast_attr(struct varlena *attr)
|
|||||||
*
|
*
|
||||||
* Public entry point to get back part of a toasted value
|
* Public entry point to get back part of a toasted value
|
||||||
* from compression or external storage.
|
* from compression or external storage.
|
||||||
|
*
|
||||||
|
* sliceoffset is where to start (zero or more)
|
||||||
|
* If slicelength < 0, return everything beyond sliceoffset
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
struct varlena *
|
struct varlena *
|
||||||
@ -261,8 +265,21 @@ heap_tuple_untoast_attr_slice(struct varlena *attr,
|
|||||||
struct varlena *preslice;
|
struct varlena *preslice;
|
||||||
struct varlena *result;
|
struct varlena *result;
|
||||||
char *attrdata;
|
char *attrdata;
|
||||||
|
int32 slicelimit;
|
||||||
int32 attrsize;
|
int32 attrsize;
|
||||||
|
|
||||||
|
if (sliceoffset < 0)
|
||||||
|
elog(ERROR, "invalid sliceoffset: %d", sliceoffset);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute slicelimit = offset + length, or -1 if we must fetch all of the
|
||||||
|
* value. In case of integer overflow, we must fetch all.
|
||||||
|
*/
|
||||||
|
if (slicelength < 0)
|
||||||
|
slicelimit = -1;
|
||||||
|
else if (pg_add_s32_overflow(sliceoffset, slicelength, &slicelimit))
|
||||||
|
slicelength = slicelimit = -1;
|
||||||
|
|
||||||
if (VARATT_IS_EXTERNAL_ONDISK(attr))
|
if (VARATT_IS_EXTERNAL_ONDISK(attr))
|
||||||
{
|
{
|
||||||
struct varatt_external toast_pointer;
|
struct varatt_external toast_pointer;
|
||||||
@ -326,8 +343,7 @@ heap_tuple_untoast_attr_slice(struct varlena *attr,
|
|||||||
sliceoffset = 0;
|
sliceoffset = 0;
|
||||||
slicelength = 0;
|
slicelength = 0;
|
||||||
}
|
}
|
||||||
|
else if (slicelength < 0 || slicelimit > attrsize)
|
||||||
if (((sliceoffset + slicelength) > attrsize) || slicelength < 0)
|
|
||||||
slicelength = attrsize - sliceoffset;
|
slicelength = attrsize - sliceoffset;
|
||||||
|
|
||||||
result = (struct varlena *) palloc(slicelength + VARHDRSZ);
|
result = (struct varlena *) palloc(slicelength + VARHDRSZ);
|
||||||
@ -2093,7 +2109,12 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length)
|
|||||||
length = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((sliceoffset + length) > attrsize) || length < 0)
|
/*
|
||||||
|
* Adjust length request if needed. (Note: our sole caller,
|
||||||
|
* heap_tuple_untoast_attr_slice, protects us against sliceoffset + length
|
||||||
|
* overflowing.)
|
||||||
|
*/
|
||||||
|
else if (((sliceoffset + length) > attrsize) || length < 0)
|
||||||
length = attrsize - sliceoffset;
|
length = attrsize - sliceoffset;
|
||||||
|
|
||||||
result = (struct varlena *) palloc(length + VARHDRSZ);
|
result = (struct varlena *) palloc(length + VARHDRSZ);
|
||||||
|
@ -1049,7 +1049,7 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
|
|||||||
len,
|
len,
|
||||||
ishift,
|
ishift,
|
||||||
i;
|
i;
|
||||||
int e,
|
int32 e,
|
||||||
s1,
|
s1,
|
||||||
e1;
|
e1;
|
||||||
bits8 *r,
|
bits8 *r,
|
||||||
@ -1062,18 +1062,24 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
|
|||||||
{
|
{
|
||||||
e1 = bitlen + 1;
|
e1 = bitlen + 1;
|
||||||
}
|
}
|
||||||
|
else if (l < 0)
|
||||||
|
{
|
||||||
|
/* SQL99 says to throw an error for E < S, i.e., negative length */
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
||||||
|
errmsg("negative substring length not allowed")));
|
||||||
|
e1 = -1; /* silence stupider compilers */
|
||||||
|
}
|
||||||
|
else if (pg_add_s32_overflow(s, l, &e))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* L could be large enough for S + L to overflow, in which case the
|
||||||
|
* substring must run to end of string.
|
||||||
|
*/
|
||||||
|
e1 = bitlen + 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
e = s + l;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A negative value for L is the only way for the end position to be
|
|
||||||
* before the start. SQL99 says to throw an error.
|
|
||||||
*/
|
|
||||||
if (e < s)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
||||||
errmsg("negative substring length not allowed")));
|
|
||||||
e1 = Min(e, bitlen + 1);
|
e1 = Min(e, bitlen + 1);
|
||||||
}
|
}
|
||||||
if (s1 > bitlen || e1 <= s1)
|
if (s1 > bitlen || e1 <= s1)
|
||||||
|
@ -817,29 +817,38 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
|||||||
int32 S = start; /* start position */
|
int32 S = start; /* start position */
|
||||||
int32 S1; /* adjusted start position */
|
int32 S1; /* adjusted start position */
|
||||||
int32 L1; /* adjusted substring length */
|
int32 L1; /* adjusted substring length */
|
||||||
|
int32 E; /* end position */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SQL99 says S can be zero or negative, but we still must fetch from the
|
||||||
|
* start of the string.
|
||||||
|
*/
|
||||||
|
S1 = Max(S, 1);
|
||||||
|
|
||||||
/* life is easy if the encoding max length is 1 */
|
/* life is easy if the encoding max length is 1 */
|
||||||
if (eml == 1)
|
if (eml == 1)
|
||||||
{
|
{
|
||||||
S1 = Max(S, 1);
|
|
||||||
|
|
||||||
if (length_not_specified) /* special case - get length to end of
|
if (length_not_specified) /* special case - get length to end of
|
||||||
* string */
|
* string */
|
||||||
L1 = -1;
|
L1 = -1;
|
||||||
|
else if (length < 0)
|
||||||
|
{
|
||||||
|
/* SQL99 says to throw an error for E < S, i.e., negative length */
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
||||||
|
errmsg("negative substring length not allowed")));
|
||||||
|
L1 = -1; /* silence stupider compilers */
|
||||||
|
}
|
||||||
|
else if (pg_add_s32_overflow(S, length, &E))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* L could be large enough for S + L to overflow, in which case
|
||||||
|
* the substring must run to end of string.
|
||||||
|
*/
|
||||||
|
L1 = -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* end position */
|
|
||||||
int E = S + length;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A negative value for L is the only way for the end position to
|
|
||||||
* be before the start. SQL99 says to throw an error.
|
|
||||||
*/
|
|
||||||
if (E < S)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
||||||
errmsg("negative substring length not allowed")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A zero or negative value for the end position can happen if the
|
* A zero or negative value for the end position can happen if the
|
||||||
* start was negative or one. SQL99 says to return a zero-length
|
* start was negative or one. SQL99 says to return a zero-length
|
||||||
@ -853,8 +862,8 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* return a zero-length string -- DatumGetTextPSlice() will do that
|
||||||
* that for us. Convert to zero-based starting position
|
* for us. We need only convert S1 to zero-based starting position.
|
||||||
*/
|
*/
|
||||||
return DatumGetTextPSlice(str, S1 - 1, L1);
|
return DatumGetTextPSlice(str, S1 - 1, L1);
|
||||||
}
|
}
|
||||||
@ -875,12 +884,6 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
|||||||
char *s;
|
char *s;
|
||||||
text *ret;
|
text *ret;
|
||||||
|
|
||||||
/*
|
|
||||||
* if S is past the end of the string, the tuple toaster will return a
|
|
||||||
* zero-length string to us
|
|
||||||
*/
|
|
||||||
S1 = Max(S, 1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to start at position zero because there is no way to know
|
* We need to start at position zero because there is no way to know
|
||||||
* in advance which byte offset corresponds to the supplied start
|
* in advance which byte offset corresponds to the supplied start
|
||||||
@ -891,19 +894,24 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
|||||||
if (length_not_specified) /* special case - get length to end of
|
if (length_not_specified) /* special case - get length to end of
|
||||||
* string */
|
* string */
|
||||||
slice_size = L1 = -1;
|
slice_size = L1 = -1;
|
||||||
|
else if (length < 0)
|
||||||
|
{
|
||||||
|
/* SQL99 says to throw an error for E < S, i.e., negative length */
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
||||||
|
errmsg("negative substring length not allowed")));
|
||||||
|
slice_size = L1 = -1; /* silence stupider compilers */
|
||||||
|
}
|
||||||
|
else if (pg_add_s32_overflow(S, length, &E))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* L could be large enough for S + L to overflow, in which case
|
||||||
|
* the substring must run to end of string.
|
||||||
|
*/
|
||||||
|
slice_size = L1 = -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int E = S + length;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A negative value for L is the only way for the end position to
|
|
||||||
* be before the start. SQL99 says to throw an error.
|
|
||||||
*/
|
|
||||||
if (E < S)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
||||||
errmsg("negative substring length not allowed")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A zero or negative value for the end position can happen if the
|
* A zero or negative value for the end position can happen if the
|
||||||
* start was negative or one. SQL99 says to return a zero-length
|
* start was negative or one. SQL99 says to return a zero-length
|
||||||
@ -921,8 +929,10 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
|
|||||||
/*
|
/*
|
||||||
* Total slice size in bytes can't be any longer than the start
|
* Total slice size in bytes can't be any longer than the start
|
||||||
* position plus substring length times the encoding max length.
|
* position plus substring length times the encoding max length.
|
||||||
|
* If that overflows, we can just use -1.
|
||||||
*/
|
*/
|
||||||
slice_size = (S1 + L1) * eml;
|
if (pg_mul_s32_overflow(E, eml, &slice_size))
|
||||||
|
slice_size = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2884,9 +2894,13 @@ bytea_substring(Datum str,
|
|||||||
int L,
|
int L,
|
||||||
bool length_not_specified)
|
bool length_not_specified)
|
||||||
{
|
{
|
||||||
int S1; /* adjusted start position */
|
int32 S1; /* adjusted start position */
|
||||||
int L1; /* adjusted substring length */
|
int32 L1; /* adjusted substring length */
|
||||||
|
int32 E; /* end position */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The logic here should generally match text_substring().
|
||||||
|
*/
|
||||||
S1 = Max(S, 1);
|
S1 = Max(S, 1);
|
||||||
|
|
||||||
if (length_not_specified)
|
if (length_not_specified)
|
||||||
@ -2897,20 +2911,24 @@ bytea_substring(Datum str,
|
|||||||
*/
|
*/
|
||||||
L1 = -1;
|
L1 = -1;
|
||||||
}
|
}
|
||||||
|
else if (L < 0)
|
||||||
|
{
|
||||||
|
/* SQL99 says to throw an error for E < S, i.e., negative length */
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_SUBSTRING_ERROR),
|
||||||
|
errmsg("negative substring length not allowed")));
|
||||||
|
L1 = -1; /* silence stupider compilers */
|
||||||
|
}
|
||||||
|
else if (pg_add_s32_overflow(S, L, &E))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* L could be large enough for S + L to overflow, in which case the
|
||||||
|
* substring must run to end of string.
|
||||||
|
*/
|
||||||
|
L1 = -1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* end position */
|
|
||||||
int E = S + L;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A negative value for L is the only way for the end position to be
|
|
||||||
* before the start. SQL99 says to throw an error.
|
|
||||||
*/
|
|
||||||
if (E < S)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_SUBSTRING_ERROR),
|
|
||||||
errmsg("negative substring length not allowed")));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A zero or negative value for the end position can happen if the
|
* A zero or negative value for the end position can happen if the
|
||||||
* start was negative or one. SQL99 says to return a zero-length
|
* start was negative or one. SQL99 says to return a zero-length
|
||||||
@ -2925,7 +2943,7 @@ bytea_substring(Datum str,
|
|||||||
/*
|
/*
|
||||||
* 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 -- DatumGetByteaPSlice() will do that for
|
* return a zero-length string -- DatumGetByteaPSlice() will do that for
|
||||||
* us. Convert to zero-based starting position
|
* us. We need only convert S1 to zero-based starting position.
|
||||||
*/
|
*/
|
||||||
return DatumGetByteaPSlice(str, S1 - 1, L1);
|
return DatumGetByteaPSlice(str, S1 - 1, L1);
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,35 @@ SELECT v,
|
|||||||
01010101010 | 1010 | 01010 | 101010
|
01010101010 | 1010 | 01010 | 101010
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
|
||||||
|
-- test overflow cases
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM 2 FOR 2147483646) AS "1010101";
|
||||||
|
1010101
|
||||||
|
---------
|
||||||
|
1010101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR 2147483646) AS "01010101";
|
||||||
|
01010101
|
||||||
|
----------
|
||||||
|
01010101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR -2147483646) AS "error";
|
||||||
|
ERROR: negative substring length not allowed
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM 2 FOR 2147483646) AS "1010101";
|
||||||
|
1010101
|
||||||
|
---------
|
||||||
|
1010101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM -10 FOR 2147483646) AS "01010101";
|
||||||
|
01010101
|
||||||
|
----------
|
||||||
|
01010101
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM -10 FOR -2147483646) AS "error";
|
||||||
|
ERROR: negative substring length not allowed
|
||||||
--- Bit operations
|
--- Bit operations
|
||||||
DROP TABLE varbit_table;
|
DROP TABLE varbit_table;
|
||||||
CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16));
|
CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16));
|
||||||
|
@ -313,7 +313,22 @@ SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456";
|
|||||||
t
|
t
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- T581 regular expression substring (with SQL99's bizarre regexp syntax)
|
-- test overflow cases
|
||||||
|
SELECT SUBSTRING('string' FROM 2 FOR 2147483646) AS "tring";
|
||||||
|
tring
|
||||||
|
-------
|
||||||
|
tring
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('string' FROM -10 FOR 2147483646) AS "string";
|
||||||
|
string
|
||||||
|
--------
|
||||||
|
string
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('string' FROM -10 FOR -2147483646) AS "error";
|
||||||
|
ERROR: negative substring length not allowed
|
||||||
|
-- T581 regular expression substring (with SQL's bizarre regexp syntax)
|
||||||
SELECT SUBSTRING('abcdefg' FROM 'a#"(b_d)#"%' FOR '#') AS "bcd";
|
SELECT SUBSTRING('abcdefg' FROM 'a#"(b_d)#"%' FOR '#') AS "bcd";
|
||||||
bcd
|
bcd
|
||||||
-----
|
-----
|
||||||
@ -1788,6 +1803,32 @@ SELECT repeat('Pg', -4);
|
|||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('1234567890'::bytea FROM 3) "34567890";
|
||||||
|
34567890
|
||||||
|
----------
|
||||||
|
34567890
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('1234567890'::bytea FROM 4 FOR 3) AS "456";
|
||||||
|
456
|
||||||
|
-----
|
||||||
|
456
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM 2 FOR 2147483646) AS "tring";
|
||||||
|
tring
|
||||||
|
-------
|
||||||
|
tring
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM -10 FOR 2147483646) AS "string";
|
||||||
|
string
|
||||||
|
--------
|
||||||
|
string
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM -10 FOR -2147483646) AS "error";
|
||||||
|
ERROR: negative substring length not allowed
|
||||||
SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea);
|
SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea);
|
||||||
btrim
|
btrim
|
||||||
-------
|
-------
|
||||||
|
@ -53,6 +53,14 @@ SELECT v,
|
|||||||
SUBSTRING(v FROM 6) AS sub_6
|
SUBSTRING(v FROM 6) AS sub_6
|
||||||
FROM VARBIT_TABLE;
|
FROM VARBIT_TABLE;
|
||||||
|
|
||||||
|
-- test overflow cases
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM 2 FOR 2147483646) AS "1010101";
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR 2147483646) AS "01010101";
|
||||||
|
SELECT SUBSTRING('01010101'::bit(8) FROM -10 FOR -2147483646) AS "error";
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM 2 FOR 2147483646) AS "1010101";
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM -10 FOR 2147483646) AS "01010101";
|
||||||
|
SELECT SUBSTRING('01010101'::varbit FROM -10 FOR -2147483646) AS "error";
|
||||||
|
|
||||||
--- Bit operations
|
--- Bit operations
|
||||||
DROP TABLE varbit_table;
|
DROP TABLE varbit_table;
|
||||||
CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16));
|
CREATE TABLE varbit_table (a BIT VARYING(16), b BIT VARYING(16));
|
||||||
|
@ -110,7 +110,12 @@ SELECT SUBSTRING('1234567890' FROM 3) = '34567890' AS "34567890";
|
|||||||
|
|
||||||
SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456";
|
SELECT SUBSTRING('1234567890' FROM 4 FOR 3) = '456' AS "456";
|
||||||
|
|
||||||
-- T581 regular expression substring (with SQL99's bizarre regexp syntax)
|
-- test overflow cases
|
||||||
|
SELECT SUBSTRING('string' FROM 2 FOR 2147483646) AS "tring";
|
||||||
|
SELECT SUBSTRING('string' FROM -10 FOR 2147483646) AS "string";
|
||||||
|
SELECT SUBSTRING('string' FROM -10 FOR -2147483646) AS "error";
|
||||||
|
|
||||||
|
-- T581 regular expression substring (with SQL's bizarre regexp syntax)
|
||||||
SELECT SUBSTRING('abcdefg' FROM 'a#"(b_d)#"%' FOR '#') AS "bcd";
|
SELECT SUBSTRING('abcdefg' FROM 'a#"(b_d)#"%' FOR '#') AS "bcd";
|
||||||
|
|
||||||
-- No match should return NULL
|
-- No match should return NULL
|
||||||
@ -613,6 +618,12 @@ SELECT chr(0);
|
|||||||
SELECT repeat('Pg', 4);
|
SELECT repeat('Pg', 4);
|
||||||
SELECT repeat('Pg', -4);
|
SELECT repeat('Pg', -4);
|
||||||
|
|
||||||
|
SELECT SUBSTRING('1234567890'::bytea FROM 3) "34567890";
|
||||||
|
SELECT SUBSTRING('1234567890'::bytea FROM 4 FOR 3) AS "456";
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM 2 FOR 2147483646) AS "tring";
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM -10 FOR 2147483646) AS "string";
|
||||||
|
SELECT SUBSTRING('string'::bytea FROM -10 FOR -2147483646) AS "error";
|
||||||
|
|
||||||
SELECT trim(E'\\000'::bytea from E'\\000Tom\\000'::bytea);
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user