]> granicus.if.org Git - postgresql/commitdiff
PL/Python regression tests for data type handling
authorPeter Eisentraut <peter_e@gmx.net>
Fri, 14 Aug 2009 13:42:16 +0000 (13:42 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Fri, 14 Aug 2009 13:42:16 +0000 (13:42 +0000)
Add some checks on various data types are converted into and out of Python.
This is extracted from Caleb Welton's patch for improved bytea support,
but much expanded.

src/pl/plpython/Makefile
src/pl/plpython/expected/plpython_types.out [new file with mode: 0644]
src/pl/plpython/sql/plpython_types.sql [new file with mode: 0644]

index 77d66657e1d08d0589b4b33cee66f258e37e327a..11cd5a8811ef83a9880819beb1b92ee68273e730 100644 (file)
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.33 2009/08/12 16:37:25 petere Exp $
+# $PostgreSQL: pgsql/src/pl/plpython/Makefile,v 1.34 2009/08/14 13:42:16 petere Exp $
 
 subdir = src/pl/plpython
 top_builddir = ../../..
@@ -70,6 +70,7 @@ REGRESS = \
        plpython_setof \
        plpython_record \
        plpython_trigger \
+       plpython_types \
        plpython_error \
        plpython_unicode \
        plpython_drop
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
new file mode 100644 (file)
index 0000000..fd4efe9
--- /dev/null
@@ -0,0 +1,378 @@
+--
+-- Test data type behavior
+--
+--
+-- Base/common types
+--
+CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_bool(true);
+INFO:  (True, <type 'bool'>)
+CONTEXT:  PL/Python function "test_type_conversion_bool"
+ test_type_conversion_bool 
+---------------------------
+ t
+(1 row)
+
+SELECT * FROM test_type_conversion_bool(false);
+INFO:  (False, <type 'bool'>)
+CONTEXT:  PL/Python function "test_type_conversion_bool"
+ test_type_conversion_bool 
+---------------------------
+ f
+(1 row)
+
+SELECT * FROM test_type_conversion_bool(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_bool"
+ test_type_conversion_bool 
+---------------------------
+(1 row)
+
+CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_char('a');
+INFO:  ('a', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_char"
+ test_type_conversion_char 
+---------------------------
+ a
+(1 row)
+
+SELECT * FROM test_type_conversion_char(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_char"
+ test_type_conversion_char 
+---------------------------
+(1 row)
+
+CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_int2(100::int2);
+INFO:  (100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_int2"
+ test_type_conversion_int2 
+---------------------------
+                       100
+(1 row)
+
+SELECT * FROM test_type_conversion_int2(-100::int2);
+INFO:  (-100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_int2"
+ test_type_conversion_int2 
+---------------------------
+                      -100
+(1 row)
+
+SELECT * FROM test_type_conversion_int2(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_int2"
+ test_type_conversion_int2 
+---------------------------
+                          
+(1 row)
+
+CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_int4(100);
+INFO:  (100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_int4"
+ test_type_conversion_int4 
+---------------------------
+                       100
+(1 row)
+
+SELECT * FROM test_type_conversion_int4(-100);
+INFO:  (-100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_int4"
+ test_type_conversion_int4 
+---------------------------
+                      -100
+(1 row)
+
+SELECT * FROM test_type_conversion_int4(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_int4"
+ test_type_conversion_int4 
+---------------------------
+                          
+(1 row)
+
+CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_int8(100);
+INFO:  (100L, <type 'long'>)
+CONTEXT:  PL/Python function "test_type_conversion_int8"
+ test_type_conversion_int8 
+---------------------------
+                       100
+(1 row)
+
+SELECT * FROM test_type_conversion_int8(-100);
+INFO:  (-100L, <type 'long'>)
+CONTEXT:  PL/Python function "test_type_conversion_int8"
+ test_type_conversion_int8 
+---------------------------
+                      -100
+(1 row)
+
+SELECT * FROM test_type_conversion_int8(5000000000);
+INFO:  (5000000000L, <type 'long'>)
+CONTEXT:  PL/Python function "test_type_conversion_int8"
+ test_type_conversion_int8 
+---------------------------
+                5000000000
+(1 row)
+
+SELECT * FROM test_type_conversion_int8(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_int8"
+ test_type_conversion_int8 
+---------------------------
+                          
+(1 row)
+
+CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+/* The current implementation converts numeric to float. */
+SELECT * FROM test_type_conversion_numeric(100);
+INFO:  (100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_numeric"
+ test_type_conversion_numeric 
+------------------------------
+                        100.0
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric(-100);
+INFO:  (-100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_numeric"
+ test_type_conversion_numeric 
+------------------------------
+                       -100.0
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric(5000000000.5);
+INFO:  (5000000000.5, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_numeric"
+ test_type_conversion_numeric 
+------------------------------
+                 5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric(79228162514264337593543950336);
+INFO:  (7.9228162514264338e+28, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_numeric"
+ test_type_conversion_numeric  
+-------------------------------
+ 79228162514300000000000000000
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_numeric"
+ test_type_conversion_numeric 
+------------------------------
+                             
+(1 row)
+
+CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_float4(100);
+INFO:  (100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float4"
+ test_type_conversion_float4 
+-----------------------------
+                         100
+(1 row)
+
+SELECT * FROM test_type_conversion_float4(-100);
+INFO:  (-100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float4"
+ test_type_conversion_float4 
+-----------------------------
+                        -100
+(1 row)
+
+SELECT * FROM test_type_conversion_float4(5000.5);
+INFO:  (5000.5, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float4"
+ test_type_conversion_float4 
+-----------------------------
+                      5000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_float4(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_float4"
+ test_type_conversion_float4 
+-----------------------------
+                            
+(1 row)
+
+CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_float8(100);
+INFO:  (100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float8"
+ test_type_conversion_float8 
+-----------------------------
+                         100
+(1 row)
+
+SELECT * FROM test_type_conversion_float8(-100);
+INFO:  (-100.0, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float8"
+ test_type_conversion_float8 
+-----------------------------
+                        -100
+(1 row)
+
+SELECT * FROM test_type_conversion_float8(5000000000.5);
+INFO:  (5000000000.5, <type 'float'>)
+CONTEXT:  PL/Python function "test_type_conversion_float8"
+ test_type_conversion_float8 
+-----------------------------
+                5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_float8(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_float8"
+ test_type_conversion_float8 
+-----------------------------
+                            
+(1 row)
+
+CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_text('hello world');
+INFO:  ('hello world', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_text"
+ test_type_conversion_text 
+---------------------------
+ hello world
+(1 row)
+
+SELECT * FROM test_type_conversion_text(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_text"
+ test_type_conversion_text 
+---------------------------
+(1 row)
+
+CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_bytea('hello world');
+INFO:  ('\\x68656c6c6f20776f726c64', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_bytea"
+ test_type_conversion_bytea 
+----------------------------
+ \x68656c6c6f20776f726c64
+(1 row)
+
+SELECT * FROM test_type_conversion_bytea(null);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_bytea"
+ test_type_conversion_bytea 
+----------------------------
+(1 row)
+
+CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$
+import marshal
+return marshal.dumps('hello world')
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$
+import marshal
+try:
+    return marshal.loads(x)
+except ValueError, e:
+    return 'FAILED: ' + str(e)
+$$ LANGUAGE plpythonu;
+/* This will currently fail because the bytea datum is presented to
+   Python as a string in bytea-encoding, which Python doesn't understand. */
+SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
+   test_type_unmarshal    
+--------------------------
+ FAILED: bad marshal data
+(1 row)
+
+--
+-- Domains
+--
+CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0);
+CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$
+plpy.info(x, type(x))
+return y
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
+INFO:  (100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_uint2"
+ test_type_conversion_uint2 
+----------------------------
+                         50
+(1 row)
+
+SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
+INFO:  (100, <type 'int'>)
+CONTEXT:  PL/Python function "test_type_conversion_uint2"
+ERROR:  value for domain uint2 violates check constraint "uint2_check"
+CONTEXT:  PL/Python function "test_type_conversion_uint2"
+SELECT * FROM test_type_conversion_uint2(null, 1);
+INFO:  (None, <type 'NoneType'>)
+CONTEXT:  PL/Python function "test_type_conversion_uint2"
+ test_type_conversion_uint2 
+----------------------------
+                          1
+(1 row)
+
+CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 AND VALUE IS NOT NULL);
+CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) RETURNS bytea10 AS $$
+plpy.info(x, type(x))
+return y
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
+INFO:  ('\\x68656c6c6f20776f6c64', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_bytea10"
+ test_type_conversion_bytea10 
+------------------------------
+ \x68656c6c6f20776f6c64
+(1 row)
+
+SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold');
+ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
+SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
+INFO:  ('\\x68656c6c6f20776f7264', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_bytea10"
+ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
+CONTEXT:  PL/Python function "test_type_conversion_bytea10"
+SELECT * FROM test_type_conversion_bytea10(null, 'hello word');
+ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
+SELECT * FROM test_type_conversion_bytea10('hello word', null);
+INFO:  ('\\x68656c6c6f20776f7264', <type 'str'>)
+CONTEXT:  PL/Python function "test_type_conversion_bytea10"
+ERROR:  value for domain bytea10 violates check constraint "bytea10_check"
+CONTEXT:  PL/Python function "test_type_conversion_bytea10"
diff --git a/src/pl/plpython/sql/plpython_types.sql b/src/pl/plpython/sql/plpython_types.sql
new file mode 100644 (file)
index 0000000..d057996
--- /dev/null
@@ -0,0 +1,157 @@
+--
+-- Test data type behavior
+--
+
+--
+-- Base/common types
+--
+
+CREATE FUNCTION test_type_conversion_bool(x bool) RETURNS bool AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_bool(true);
+SELECT * FROM test_type_conversion_bool(false);
+SELECT * FROM test_type_conversion_bool(null);
+
+
+CREATE FUNCTION test_type_conversion_char(x char) RETURNS char AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_char('a');
+SELECT * FROM test_type_conversion_char(null);
+
+
+CREATE FUNCTION test_type_conversion_int2(x int2) RETURNS int2 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_int2(100::int2);
+SELECT * FROM test_type_conversion_int2(-100::int2);
+SELECT * FROM test_type_conversion_int2(null);
+
+
+CREATE FUNCTION test_type_conversion_int4(x int4) RETURNS int4 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_int4(100);
+SELECT * FROM test_type_conversion_int4(-100);
+SELECT * FROM test_type_conversion_int4(null);
+
+
+CREATE FUNCTION test_type_conversion_int8(x int8) RETURNS int8 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_int8(100);
+SELECT * FROM test_type_conversion_int8(-100);
+SELECT * FROM test_type_conversion_int8(5000000000);
+SELECT * FROM test_type_conversion_int8(null);
+
+
+CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+/* The current implementation converts numeric to float. */
+SELECT * FROM test_type_conversion_numeric(100);
+SELECT * FROM test_type_conversion_numeric(-100);
+SELECT * FROM test_type_conversion_numeric(5000000000.5);
+SELECT * FROM test_type_conversion_numeric(79228162514264337593543950336);
+SELECT * FROM test_type_conversion_numeric(null);
+
+
+CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_float4(100);
+SELECT * FROM test_type_conversion_float4(-100);
+SELECT * FROM test_type_conversion_float4(5000.5);
+SELECT * FROM test_type_conversion_float4(null);
+
+
+CREATE FUNCTION test_type_conversion_float8(x float8) RETURNS float8 AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_float8(100);
+SELECT * FROM test_type_conversion_float8(-100);
+SELECT * FROM test_type_conversion_float8(5000000000.5);
+SELECT * FROM test_type_conversion_float8(null);
+
+
+CREATE FUNCTION test_type_conversion_text(x text) RETURNS text AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_text('hello world');
+SELECT * FROM test_type_conversion_text(null);
+
+
+CREATE FUNCTION test_type_conversion_bytea(x bytea) RETURNS bytea AS $$
+plpy.info(x, type(x))
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_bytea('hello world');
+SELECT * FROM test_type_conversion_bytea(null);
+
+
+CREATE FUNCTION test_type_marshal() RETURNS bytea AS $$
+import marshal
+return marshal.dumps('hello world')
+$$ LANGUAGE plpythonu;
+
+CREATE FUNCTION test_type_unmarshal(x bytea) RETURNS text AS $$
+import marshal
+try:
+    return marshal.loads(x)
+except ValueError, e:
+    return 'FAILED: ' + str(e)
+$$ LANGUAGE plpythonu;
+
+/* This will currently fail because the bytea datum is presented to
+   Python as a string in bytea-encoding, which Python doesn't understand. */
+SELECT test_type_unmarshal(x) FROM test_type_marshal() x;
+
+
+--
+-- Domains
+--
+
+CREATE DOMAIN uint2 AS int2 CHECK (VALUE >= 0);
+
+CREATE FUNCTION test_type_conversion_uint2(x uint2, y int) RETURNS uint2 AS $$
+plpy.info(x, type(x))
+return y
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_uint2(100::uint2, 50);
+SELECT * FROM test_type_conversion_uint2(100::uint2, -50);
+SELECT * FROM test_type_conversion_uint2(null, 1);
+
+
+CREATE DOMAIN bytea10 AS bytea CHECK (octet_length(VALUE) = 10 AND VALUE IS NOT NULL);
+
+CREATE FUNCTION test_type_conversion_bytea10(x bytea10, y bytea) RETURNS bytea10 AS $$
+plpy.info(x, type(x))
+return y
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_bytea10('hello wold', 'hello wold');
+SELECT * FROM test_type_conversion_bytea10('hello world', 'hello wold');
+SELECT * FROM test_type_conversion_bytea10('hello word', 'hello world');
+SELECT * FROM test_type_conversion_bytea10(null, 'hello word');
+SELECT * FROM test_type_conversion_bytea10('hello word', null);