mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 22:57:18 +02:00
As gist__int_ops stands in intarray, it is possible to store GiST entries for leaf pages that can cause corruptions when decompressed. Leaf nodes are stored as decompressed all the time by the compression method, and the decompression method should map with that, retrieving the contents of the page without doing any decompression. However, the code authorized the insertion of leaf page data with a higher number of array items than what can be supported, generating a NOTICE message to inform about this matter (199 for a 8k page, for reference). When calling the decompression method, a decompression would be attempted on this leaf node item but the contents should be retrieved as they are. The NOTICE message generated when dealing with the compression of a leaf page and too many elements in the input array for gist__int_ops has been introduced by08ee64e
, removing the marker stored in the array to track if this is actually a leaf node. However, it also missed the fact that the decompression path should do nothing for a leaf page. Hence, as the code stand, a too-large array would be stored as uncompressed but the decompression path would attempt a decompression rather that retrieving the contents as they are. This leads to various problems. First, even if08ee64e
tried to address that, it is possible to do out-of-bound chunk writes with a large input array, with the backend informing about that with WARNINGs. On decompression, retrieving the stored leaf data would lead to incorrect memory reads, leading to crashes or even worse. Perhaps somebody would be interested in expanding the number of array items that can be handled in a leaf page for this operator in the future, which would require revisiting the choice done in08ee64e
, but based on the lack of reports about this problem since 2005 it does not look so. For now, this commit prevents the insertion of data for leaf pages when using more array items that the code can handle on decompression, switching the NOTICE message to an ERROR. If one wishes to use more array items, gist__intbig_ops is an optional choice. While on it, use ERRCODE_PROGRAM_LIMIT_EXCEEDED as error code when a limit is reached, because that's what the module is facing in such cases. Author: Ankit Kumar Pandey, Alexander Lakhin Reviewed-by: Richard Guo, Michael Paquier Discussion: https://postgr.es/m/796b65c3-57b7-bddf-b0d5-a8afafb8b627@gmail.com Discussion: https://postgr.es/m/17888-f72930e6b5ce8c14@postgresql.org Backpatch-through: 11
701 lines
11 KiB
Plaintext
701 lines
11 KiB
Plaintext
CREATE EXTENSION intarray;
|
|
-- Check whether any of our opclasses fail amvalidate
|
|
SELECT amname, opcname
|
|
FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod
|
|
WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
|
|
amname | opcname
|
|
--------+---------
|
|
(0 rows)
|
|
|
|
SELECT intset(1234);
|
|
intset
|
|
--------
|
|
{1234}
|
|
(1 row)
|
|
|
|
SELECT icount('{1234234,234234}');
|
|
icount
|
|
--------
|
|
2
|
|
(1 row)
|
|
|
|
SELECT sort('{1234234,-30,234234}');
|
|
sort
|
|
----------------------
|
|
{-30,234234,1234234}
|
|
(1 row)
|
|
|
|
SELECT sort('{1234234,-30,234234}','asc');
|
|
sort
|
|
----------------------
|
|
{-30,234234,1234234}
|
|
(1 row)
|
|
|
|
SELECT sort('{1234234,-30,234234}','desc');
|
|
sort
|
|
----------------------
|
|
{1234234,234234,-30}
|
|
(1 row)
|
|
|
|
SELECT sort_asc('{1234234,-30,234234}');
|
|
sort_asc
|
|
----------------------
|
|
{-30,234234,1234234}
|
|
(1 row)
|
|
|
|
SELECT sort_desc('{1234234,-30,234234}');
|
|
sort_desc
|
|
----------------------
|
|
{1234234,234234,-30}
|
|
(1 row)
|
|
|
|
SELECT uniq('{1234234,-30,-30,234234,-30}');
|
|
uniq
|
|
--------------------------
|
|
{1234234,-30,234234,-30}
|
|
(1 row)
|
|
|
|
SELECT uniq(sort_asc('{1234234,-30,-30,234234,-30}'));
|
|
uniq
|
|
----------------------
|
|
{-30,234234,1234234}
|
|
(1 row)
|
|
|
|
SELECT idx('{1234234,-30,-30,234234,-30}',-30);
|
|
idx
|
|
-----
|
|
2
|
|
(1 row)
|
|
|
|
SELECT subarray('{1234234,-30,-30,234234,-30}',2,3);
|
|
subarray
|
|
------------------
|
|
{-30,-30,234234}
|
|
(1 row)
|
|
|
|
SELECT subarray('{1234234,-30,-30,234234,-30}',-1,1);
|
|
subarray
|
|
----------
|
|
{-30}
|
|
(1 row)
|
|
|
|
SELECT subarray('{1234234,-30,-30,234234,-30}',0,-1);
|
|
subarray
|
|
--------------------------
|
|
{1234234,-30,-30,234234}
|
|
(1 row)
|
|
|
|
SELECT #'{1234234,234234}'::int[];
|
|
?column?
|
|
----------
|
|
2
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] + 1245;
|
|
?column?
|
|
--------------------
|
|
{123,623,445,1245}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] + 445;
|
|
?column?
|
|
-------------------
|
|
{123,623,445,445}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] + '{1245,87,445}';
|
|
?column?
|
|
---------------------------
|
|
{123,623,445,1245,87,445}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] - 623;
|
|
?column?
|
|
-----------
|
|
{123,445}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] - '{1623,623}';
|
|
?column?
|
|
-----------
|
|
{123,445}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] | 623;
|
|
?column?
|
|
---------------
|
|
{123,445,623}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] | 1623;
|
|
?column?
|
|
--------------------
|
|
{123,445,623,1623}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] | '{1623,623}';
|
|
?column?
|
|
--------------------
|
|
{123,445,623,1623}
|
|
(1 row)
|
|
|
|
SELECT '{123,623,445}'::int[] & '{1623,623}';
|
|
?column?
|
|
----------
|
|
{623}
|
|
(1 row)
|
|
|
|
SELECT '{-1,3,1}'::int[] & '{1,2}';
|
|
?column?
|
|
----------
|
|
{1}
|
|
(1 row)
|
|
|
|
SELECT '{1}'::int[] & '{2}'::int[];
|
|
?column?
|
|
----------
|
|
{}
|
|
(1 row)
|
|
|
|
SELECT array_dims('{1}'::int[] & '{2}'::int[]);
|
|
array_dims
|
|
------------
|
|
|
|
(1 row)
|
|
|
|
SELECT ('{1}'::int[] & '{2}'::int[]) = '{}'::int[];
|
|
?column?
|
|
----------
|
|
t
|
|
(1 row)
|
|
|
|
SELECT ('{}'::int[] & '{}'::int[]) = '{}'::int[];
|
|
?column?
|
|
----------
|
|
t
|
|
(1 row)
|
|
|
|
--test query_int
|
|
SELECT '1'::query_int;
|
|
query_int
|
|
-----------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT ' 1'::query_int;
|
|
query_int
|
|
-----------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT '1 '::query_int;
|
|
query_int
|
|
-----------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT ' 1 '::query_int;
|
|
query_int
|
|
-----------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT ' ! 1 '::query_int;
|
|
query_int
|
|
-----------
|
|
!1
|
|
(1 row)
|
|
|
|
SELECT '!1'::query_int;
|
|
query_int
|
|
-----------
|
|
!1
|
|
(1 row)
|
|
|
|
SELECT '1|2'::query_int;
|
|
query_int
|
|
-----------
|
|
1 | 2
|
|
(1 row)
|
|
|
|
SELECT '1|!2'::query_int;
|
|
query_int
|
|
-----------
|
|
1 | !2
|
|
(1 row)
|
|
|
|
SELECT '!1|2'::query_int;
|
|
query_int
|
|
-----------
|
|
!1 | 2
|
|
(1 row)
|
|
|
|
SELECT '!1|!2'::query_int;
|
|
query_int
|
|
-----------
|
|
!1 | !2
|
|
(1 row)
|
|
|
|
SELECT '!(!1|!2)'::query_int;
|
|
query_int
|
|
--------------
|
|
!( !1 | !2 )
|
|
(1 row)
|
|
|
|
SELECT '!(!1|2)'::query_int;
|
|
query_int
|
|
-------------
|
|
!( !1 | 2 )
|
|
(1 row)
|
|
|
|
SELECT '!(1|!2)'::query_int;
|
|
query_int
|
|
-------------
|
|
!( 1 | !2 )
|
|
(1 row)
|
|
|
|
SELECT '!(1|2)'::query_int;
|
|
query_int
|
|
------------
|
|
!( 1 | 2 )
|
|
(1 row)
|
|
|
|
SELECT '1&2'::query_int;
|
|
query_int
|
|
-----------
|
|
1 & 2
|
|
(1 row)
|
|
|
|
SELECT '!1&2'::query_int;
|
|
query_int
|
|
-----------
|
|
!1 & 2
|
|
(1 row)
|
|
|
|
SELECT '1&!2'::query_int;
|
|
query_int
|
|
-----------
|
|
1 & !2
|
|
(1 row)
|
|
|
|
SELECT '!1&!2'::query_int;
|
|
query_int
|
|
-----------
|
|
!1 & !2
|
|
(1 row)
|
|
|
|
SELECT '(1&2)'::query_int;
|
|
query_int
|
|
-----------
|
|
1 & 2
|
|
(1 row)
|
|
|
|
SELECT '1&(2)'::query_int;
|
|
query_int
|
|
-----------
|
|
1 & 2
|
|
(1 row)
|
|
|
|
SELECT '!(1)&2'::query_int;
|
|
query_int
|
|
-----------
|
|
!1 & 2
|
|
(1 row)
|
|
|
|
SELECT '!(1&2)'::query_int;
|
|
query_int
|
|
------------
|
|
!( 1 & 2 )
|
|
(1 row)
|
|
|
|
SELECT '1|2&3'::query_int;
|
|
query_int
|
|
-----------
|
|
1 | 2 & 3
|
|
(1 row)
|
|
|
|
SELECT '1|(2&3)'::query_int;
|
|
query_int
|
|
-----------
|
|
1 | 2 & 3
|
|
(1 row)
|
|
|
|
SELECT '(1|2)&3'::query_int;
|
|
query_int
|
|
---------------
|
|
( 1 | 2 ) & 3
|
|
(1 row)
|
|
|
|
SELECT '1|2&!3'::query_int;
|
|
query_int
|
|
------------
|
|
1 | 2 & !3
|
|
(1 row)
|
|
|
|
SELECT '1|!2&3'::query_int;
|
|
query_int
|
|
------------
|
|
1 | !2 & 3
|
|
(1 row)
|
|
|
|
SELECT '!1|2&3'::query_int;
|
|
query_int
|
|
------------
|
|
!1 | 2 & 3
|
|
(1 row)
|
|
|
|
SELECT '!1|(2&3)'::query_int;
|
|
query_int
|
|
------------
|
|
!1 | 2 & 3
|
|
(1 row)
|
|
|
|
SELECT '!(1|2)&3'::query_int;
|
|
query_int
|
|
----------------
|
|
!( 1 | 2 ) & 3
|
|
(1 row)
|
|
|
|
SELECT '(!1|2)&3'::query_int;
|
|
query_int
|
|
----------------
|
|
( !1 | 2 ) & 3
|
|
(1 row)
|
|
|
|
SELECT '1|(2|(4|(5|6)))'::query_int;
|
|
query_int
|
|
-------------------------------
|
|
1 | ( 2 | ( 4 | ( 5 | 6 ) ) )
|
|
(1 row)
|
|
|
|
SELECT '1|2|4|5|6'::query_int;
|
|
query_int
|
|
-------------------------------
|
|
( ( ( 1 | 2 ) | 4 ) | 5 ) | 6
|
|
(1 row)
|
|
|
|
SELECT '1&(2&(4&(5&6)))'::query_int;
|
|
query_int
|
|
-------------------
|
|
1 & 2 & 4 & 5 & 6
|
|
(1 row)
|
|
|
|
SELECT '1&2&4&5&6'::query_int;
|
|
query_int
|
|
-------------------
|
|
1 & 2 & 4 & 5 & 6
|
|
(1 row)
|
|
|
|
SELECT '1&(2&(4&(5|6)))'::query_int;
|
|
query_int
|
|
-----------------------
|
|
1 & 2 & 4 & ( 5 | 6 )
|
|
(1 row)
|
|
|
|
SELECT '1&(2&(4&(5|!6)))'::query_int;
|
|
query_int
|
|
------------------------
|
|
1 & 2 & 4 & ( 5 | !6 )
|
|
(1 row)
|
|
|
|
CREATE TABLE test__int( a int[] );
|
|
\copy test__int from 'data/test__int.data'
|
|
ANALYZE test__int;
|
|
SELECT count(*) from test__int WHERE a && '{23,50}';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23|50';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{23,50}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23&50';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a <@ '{73,23,20}';
|
|
count
|
|
-------
|
|
10
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a = '{73,23,20}';
|
|
count
|
|
-------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '50&68';
|
|
count
|
|
-------
|
|
9
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '20 | !21';
|
|
count
|
|
-------
|
|
6566
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
|
|
count
|
|
-------
|
|
6343
|
|
(1 row)
|
|
|
|
SET enable_seqscan = off; -- not all of these would use index by default
|
|
CREATE INDEX text_idx on test__int using gist ( a gist__int_ops );
|
|
SELECT count(*) from test__int WHERE a && '{23,50}';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23|50';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{23,50}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23&50';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a <@ '{73,23,20}';
|
|
count
|
|
-------
|
|
10
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a = '{73,23,20}';
|
|
count
|
|
-------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '50&68';
|
|
count
|
|
-------
|
|
9
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '20 | !21';
|
|
count
|
|
-------
|
|
6566
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
|
|
count
|
|
-------
|
|
6343
|
|
(1 row)
|
|
|
|
INSERT INTO test__int SELECT array(SELECT x FROM generate_series(1, 1001) x); -- should fail
|
|
ERROR: input array is too big (199 maximum allowed, 1001 current), use gist__intbig_ops opclass instead
|
|
DROP INDEX text_idx;
|
|
CREATE INDEX text_idx on test__int using gist ( a gist__intbig_ops );
|
|
SELECT count(*) from test__int WHERE a && '{23,50}';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23|50';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{23,50}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23&50';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a <@ '{73,23,20}';
|
|
count
|
|
-------
|
|
10
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a = '{73,23,20}';
|
|
count
|
|
-------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '50&68';
|
|
count
|
|
-------
|
|
9
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '20 | !21';
|
|
count
|
|
-------
|
|
6566
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
|
|
count
|
|
-------
|
|
6343
|
|
(1 row)
|
|
|
|
DROP INDEX text_idx;
|
|
CREATE INDEX text_idx on test__int using gin ( a gin__int_ops );
|
|
SELECT count(*) from test__int WHERE a && '{23,50}';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23|50';
|
|
count
|
|
-------
|
|
403
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{23,50}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '23&50';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}';
|
|
count
|
|
-------
|
|
12
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a <@ '{73,23,20}';
|
|
count
|
|
-------
|
|
10
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a = '{73,23,20}';
|
|
count
|
|
-------
|
|
1
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '50&68';
|
|
count
|
|
-------
|
|
9
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @> '{20,23}' or a @> '{50,68}';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '(20&23)|(50&68)';
|
|
count
|
|
-------
|
|
21
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '20 | !21';
|
|
count
|
|
-------
|
|
6566
|
|
(1 row)
|
|
|
|
SELECT count(*) from test__int WHERE a @@ '!20 & !21';
|
|
count
|
|
-------
|
|
6343
|
|
(1 row)
|
|
|
|
RESET enable_seqscan;
|