From: Peter Eisentraut Date: Fri, 14 Aug 2009 13:42:16 +0000 (+0000) Subject: PL/Python regression tests for data type handling X-Git-Tag: REL8_5_ALPHA1~25 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0c738084fbb2ef55dfe27702b9486bf44c911a0c;p=postgresql PL/Python regression tests for data type handling 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. --- diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile index 77d66657e1..11cd5a8811 100644 --- a/src/pl/plpython/Makefile +++ b/src/pl/plpython/Makefile @@ -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 index 0000000000..fd4efe9596 --- /dev/null +++ b/src/pl/plpython/expected/plpython_types.out @@ -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, ) +CONTEXT: PL/Python function "test_type_conversion_bool" + test_type_conversion_bool +--------------------------- + t +(1 row) + +SELECT * FROM test_type_conversion_bool(false); +INFO: (False, ) +CONTEXT: PL/Python function "test_type_conversion_bool" + test_type_conversion_bool +--------------------------- + f +(1 row) + +SELECT * FROM test_type_conversion_bool(null); +INFO: (None, ) +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', ) +CONTEXT: PL/Python function "test_type_conversion_char" + test_type_conversion_char +--------------------------- + a +(1 row) + +SELECT * FROM test_type_conversion_char(null); +INFO: (None, ) +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, ) +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, ) +CONTEXT: PL/Python function "test_type_conversion_int2" + test_type_conversion_int2 +--------------------------- + -100 +(1 row) + +SELECT * FROM test_type_conversion_int2(null); +INFO: (None, ) +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, ) +CONTEXT: PL/Python function "test_type_conversion_int4" + test_type_conversion_int4 +--------------------------- + 100 +(1 row) + +SELECT * FROM test_type_conversion_int4(-100); +INFO: (-100, ) +CONTEXT: PL/Python function "test_type_conversion_int4" + test_type_conversion_int4 +--------------------------- + -100 +(1 row) + +SELECT * FROM test_type_conversion_int4(null); +INFO: (None, ) +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, ) +CONTEXT: PL/Python function "test_type_conversion_int8" + test_type_conversion_int8 +--------------------------- + 100 +(1 row) + +SELECT * FROM test_type_conversion_int8(-100); +INFO: (-100L, ) +CONTEXT: PL/Python function "test_type_conversion_int8" + test_type_conversion_int8 +--------------------------- + -100 +(1 row) + +SELECT * FROM test_type_conversion_int8(5000000000); +INFO: (5000000000L, ) +CONTEXT: PL/Python function "test_type_conversion_int8" + test_type_conversion_int8 +--------------------------- + 5000000000 +(1 row) + +SELECT * FROM test_type_conversion_int8(null); +INFO: (None, ) +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, ) +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, ) +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, ) +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, ) +CONTEXT: PL/Python function "test_type_conversion_numeric" + test_type_conversion_numeric +------------------------------- + 79228162514300000000000000000 +(1 row) + +SELECT * FROM test_type_conversion_numeric(null); +INFO: (None, ) +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, ) +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, ) +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, ) +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, ) +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, ) +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, ) +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, ) +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, ) +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', ) +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, ) +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', ) +CONTEXT: PL/Python function "test_type_conversion_bytea" + test_type_conversion_bytea +---------------------------- + \x68656c6c6f20776f726c64 +(1 row) + +SELECT * FROM test_type_conversion_bytea(null); +INFO: (None, ) +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, ) +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, ) +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, ) +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', ) +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', ) +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', ) +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 index 0000000000..d0579962a9 --- /dev/null +++ b/src/pl/plpython/sql/plpython_types.sql @@ -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);