mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	seg stores the number of significant digits in an input number in a "char" field. If char is signed, and the input is more than 127 digits long, the count can read out as negative causing seg_out() to print garbage (or, if you're really unlucky, even crash). To fix, clamp the digit count to be not more than FLT_DIG. (In theory this loses some information about what the original input was, but it doesn't seem like useful information; it would not survive dump/restore in any case.) Also, in case there are stored values of the seg type containing bad data, add a clamp in seg_out's restore() subroutine. Per bug #17725 from Robins Tharakan. It's been like this forever, so back-patch to all supported branches. Discussion: https://postgr.es/m/17725-0a09313b67fbe86e@postgresql.org
		
			
				
	
	
		
			241 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			SQL
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			SQL
		
	
	
	
	
	
| --
 | |
| --  Test seg datatype
 | |
| --
 | |
| 
 | |
| CREATE EXTENSION seg;
 | |
| 
 | |
| -- 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);
 | |
| 
 | |
| --
 | |
| -- testing the input and output functions
 | |
| --
 | |
| 
 | |
| -- Any number
 | |
| SELECT '1'::seg AS seg;
 | |
| SELECT '-1'::seg AS seg;
 | |
| SELECT '1.0'::seg AS seg;
 | |
| SELECT '-1.0'::seg AS seg;
 | |
| SELECT '1e7'::seg AS seg;
 | |
| SELECT '-1e7'::seg AS seg;
 | |
| SELECT '1.0e7'::seg AS seg;
 | |
| SELECT '-1.0e7'::seg AS seg;
 | |
| SELECT '1e+7'::seg AS seg;
 | |
| SELECT '-1e+7'::seg AS seg;
 | |
| SELECT '1.0e+7'::seg AS seg;
 | |
| SELECT '-1.0e+7'::seg AS seg;
 | |
| SELECT '1e-7'::seg AS seg;
 | |
| SELECT '-1e-7'::seg AS seg;
 | |
| SELECT '1.0e-7'::seg AS seg;
 | |
| SELECT '-1.0e-7'::seg AS seg;
 | |
| SELECT '2e-6'::seg AS seg;
 | |
| SELECT '2e-5'::seg AS seg;
 | |
| SELECT '2e-4'::seg AS seg;
 | |
| SELECT '2e-3'::seg AS seg;
 | |
| SELECT '2e-2'::seg AS seg;
 | |
| SELECT '2e-1'::seg AS seg;
 | |
| SELECT '2e-0'::seg AS seg;
 | |
| SELECT '2e+0'::seg AS seg;
 | |
| SELECT '2e+1'::seg AS seg;
 | |
| SELECT '2e+2'::seg AS seg;
 | |
| SELECT '2e+3'::seg AS seg;
 | |
| SELECT '2e+4'::seg AS seg;
 | |
| SELECT '2e+5'::seg AS seg;
 | |
| SELECT '2e+6'::seg AS seg;
 | |
| 
 | |
| 
 | |
| -- Significant digits preserved
 | |
| SELECT '1'::seg AS seg;
 | |
| SELECT '1.0'::seg AS seg;
 | |
| SELECT '1.00'::seg AS seg;
 | |
| SELECT '1.000'::seg AS seg;
 | |
| SELECT '1.0000'::seg AS seg;
 | |
| SELECT '1.00000'::seg AS seg;
 | |
| SELECT '1.000000'::seg AS seg;
 | |
| SELECT '0.000000120'::seg AS seg;
 | |
| SELECT '3.400e5'::seg AS seg;
 | |
| 
 | |
| -- Digits truncated
 | |
| SELECT '12.34567890123456'::seg AS seg;
 | |
| 
 | |
| -- Same, with a very long input
 | |
| SELECT '12.3456789012345600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'::seg AS seg;
 | |
| 
 | |
| -- Numbers with certainty indicators
 | |
| SELECT '~6.5'::seg AS seg;
 | |
| SELECT '<6.5'::seg AS seg;
 | |
| SELECT '>6.5'::seg AS seg;
 | |
| SELECT '~ 6.5'::seg AS seg;
 | |
| SELECT '< 6.5'::seg AS seg;
 | |
| SELECT '> 6.5'::seg AS seg;
 | |
| 
 | |
| -- Open intervals
 | |
| SELECT '0..'::seg AS seg;
 | |
| SELECT '0...'::seg AS seg;
 | |
| SELECT '0 ..'::seg AS seg;
 | |
| SELECT '0 ...'::seg AS seg;
 | |
| SELECT '..0'::seg AS seg;
 | |
| SELECT '...0'::seg AS seg;
 | |
| SELECT '.. 0'::seg AS seg;
 | |
| SELECT '... 0'::seg AS seg;
 | |
| 
 | |
| -- Finite intervals
 | |
| SELECT '0 .. 1'::seg AS seg;
 | |
| SELECT '-1 .. 0'::seg AS seg;
 | |
| SELECT '-1 .. 1'::seg AS seg;
 | |
| 
 | |
| -- (+/-) intervals
 | |
| SELECT '0(+-)1'::seg AS seg;
 | |
| SELECT '0(+-)1.0'::seg AS seg;
 | |
| SELECT '1.0(+-)0.005'::seg AS seg;
 | |
| SELECT '101(+-)1'::seg AS seg;
 | |
| -- incorrect number of significant digits in 99.0:
 | |
| SELECT '100(+-)1'::seg AS seg;
 | |
| 
 | |
| -- invalid input
 | |
| SELECT ''::seg AS seg;
 | |
| SELECT 'ABC'::seg AS seg;
 | |
| SELECT '1ABC'::seg AS seg;
 | |
| SELECT '1.'::seg AS seg;
 | |
| SELECT '1.....'::seg AS seg;
 | |
| SELECT '.1'::seg AS seg;
 | |
| SELECT '1..2.'::seg AS seg;
 | |
| SELECT '1 e7'::seg AS seg;
 | |
| SELECT '1e700'::seg AS seg;
 | |
| 
 | |
| --
 | |
| -- testing the  operators
 | |
| --
 | |
| 
 | |
| -- equality/inequality:
 | |
| --
 | |
| SELECT '24 .. 33.20'::seg = '24 .. 33.20'::seg AS bool;
 | |
| SELECT '24 .. 33.20'::seg = '24 .. 33.21'::seg AS bool;
 | |
| SELECT '24 .. 33.20'::seg != '24 .. 33.20'::seg AS bool;
 | |
| SELECT '24 .. 33.20'::seg != '24 .. 33.21'::seg AS bool;
 | |
| 
 | |
| -- overlap
 | |
| --
 | |
| SELECT '1'::seg && '1'::seg AS bool;
 | |
| SELECT '1'::seg && '2'::seg AS bool;
 | |
| SELECT '0 ..'::seg && '0 ..'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '..0'::seg && '0..'::seg AS bool;
 | |
| SELECT '-1 .. 0.1'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '-1 .. 0'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '-1 .. -0.0001'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '0 ..'::seg && '1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg && '1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg && '2'::seg AS bool;
 | |
| SELECT '0 .. 2'::seg && '1'::seg AS bool;
 | |
| SELECT '1'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '2'::seg && '0 .. 1'::seg AS bool;
 | |
| SELECT '1'::seg && '0 .. 2'::seg AS bool;
 | |
| 
 | |
| -- overlap on the left
 | |
| --
 | |
| SELECT '1'::seg &< '0'::seg AS bool;
 | |
| SELECT '1'::seg &< '1'::seg AS bool;
 | |
| SELECT '1'::seg &< '2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '0'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '0 .. 2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool;
 | |
| 
 | |
| -- overlap on the right
 | |
| --
 | |
| SELECT '0'::seg &> '1'::seg AS bool;
 | |
| SELECT '1'::seg &> '1'::seg AS bool;
 | |
| SELECT '2'::seg &> '1'::seg AS bool;
 | |
| SELECT '0'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '1'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '2'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 2'::seg &> '0 .. 2'::seg AS bool;
 | |
| SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool;
 | |
| SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool;
 | |
| 
 | |
| -- left
 | |
| --
 | |
| SELECT '1'::seg << '0'::seg AS bool;
 | |
| SELECT '1'::seg << '1'::seg AS bool;
 | |
| SELECT '1'::seg << '2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '0'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '0 .. 0.5'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '0 .. 2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '1 .. 2'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg << '2 .. 3'::seg AS bool;
 | |
| 
 | |
| -- right
 | |
| --
 | |
| SELECT '0'::seg >> '1'::seg AS bool;
 | |
| SELECT '1'::seg >> '1'::seg AS bool;
 | |
| SELECT '2'::seg >> '1'::seg AS bool;
 | |
| SELECT '0'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '1'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '2'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 0.5'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 1'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '0 .. 2'::seg >> '0 .. 2'::seg AS bool;
 | |
| SELECT '1 .. 2'::seg >> '0 .. 1'::seg AS bool;
 | |
| SELECT '2 .. 3'::seg >> '0 .. 1'::seg AS bool;
 | |
| 
 | |
| 
 | |
| -- "contained in" (the left value belongs within the interval specified in the right value):
 | |
| --
 | |
| SELECT '0'::seg        <@ '0'::seg AS bool;
 | |
| SELECT '0'::seg        <@ '0 ..'::seg AS bool;
 | |
| SELECT '0'::seg        <@ '.. 0'::seg AS bool;
 | |
| SELECT '0'::seg        <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '0'::seg        <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '-1'::seg       <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '1'::seg        <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '-1 .. 1'::seg  <@ '-1 .. 1'::seg AS bool;
 | |
| 
 | |
| -- "contains" (the left value contains the interval specified in the right value):
 | |
| --
 | |
| SELECT '0'::seg @> '0'::seg AS bool;
 | |
| SELECT '0 .. '::seg <@ '0'::seg AS bool;
 | |
| SELECT '.. 0'::seg <@ '0'::seg AS bool;
 | |
| SELECT '-1 .. 1'::seg <@ '0'::seg AS bool;
 | |
| SELECT '0'::seg <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '-1'::seg <@ '-1 .. 1'::seg AS bool;
 | |
| SELECT '1'::seg <@ '-1 .. 1'::seg AS bool;
 | |
| 
 | |
| -- Load some example data and build the index
 | |
| --
 | |
| CREATE TABLE test_seg (s seg);
 | |
| 
 | |
| \copy test_seg from 'data/test_seg.data'
 | |
| 
 | |
| CREATE INDEX test_seg_ix ON test_seg USING gist (s);
 | |
| 
 | |
| SET enable_indexscan = false;
 | |
| EXPLAIN (COSTS OFF)
 | |
| SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
 | |
| SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
 | |
| RESET enable_indexscan;
 | |
| 
 | |
| SET enable_bitmapscan = false;
 | |
| EXPLAIN (COSTS OFF)
 | |
| SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
 | |
| SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
 | |
| RESET enable_bitmapscan;
 | |
| 
 | |
| -- Test sorting
 | |
| SELECT * FROM test_seg WHERE s @> '11..11.3' GROUP BY s;
 | |
| 
 | |
| -- Test functions
 | |
| SELECT seg_lower(s), seg_center(s), seg_upper(s)
 | |
| FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
 |