pgsql: PL/Python: Convert numeric to Decimal

Started by Peter Eisentrautover 12 years ago10 messages
#1Peter Eisentraut
peter_e@gmx.net

PL/Python: Convert numeric to Decimal

The old implementation converted PostgreSQL numeric to Python float,
which was always considered a shortcoming. Now numeric is converted to
the Python Decimal object. Either the external cdecimal module or the
standard library decimal module are supported.

From: Szymon Guz <mabewlun@gmail.com>
From: Ronan Dunklau <rdunklau@gmail.com>
Reviewed-by: Steve Singer <steve@ssinger.info>

Branch
------
master

Details
-------
http://git.postgresql.org/pg/commitdiff/7919398bac8bacd75ec5d763ce8b15ffaaa3e071

Modified Files
--------------
doc/src/sgml/plpython.sgml | 23 +++++++++---
src/pl/plpython/expected/plpython_types.out | 49 +++++++++++++++++++++----
src/pl/plpython/expected/plpython_types_3.out | 49 +++++++++++++++++++++----
src/pl/plpython/plpy_typeio.c | 42 ++++++++++++++++-----
src/pl/plpython/sql/plpython_types.sql | 9 ++++-
5 files changed, 138 insertions(+), 34 deletions(-)

--
Sent via pgsql-committers mailing list (pgsql-committers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-committers

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Peter Eisentraut (#1)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

Peter Eisentraut <peter_e@gmx.net> writes:

PL/Python: Convert numeric to Decimal

Assorted buildfarm members don't like this patch.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Claudio Freire
klaussfreire@gmail.com
In reply to: Tom Lane (#2)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On Sat, Jul 6, 2013 at 2:39 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter_e@gmx.net> writes:

PL/Python: Convert numeric to Decimal

Assorted buildfarm members don't like this patch.

Do you have failure details?

This is probably an attempt to operate decimals vs floats.

Ie: Decimal('3.0') > 0 works, but Decimal('3.0') > 1.3 doesn't
(decimal is explicitly forbidden from operating on floats, some design
decision that can only be disabled in 3.3).

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Andrew Dunstan
andrew@dunslane.net
In reply to: Claudio Freire (#3)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On 07/06/2013 01:52 AM, Claudio Freire wrote:

On Sat, Jul 6, 2013 at 2:39 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter_e@gmx.net> writes:

PL/Python: Convert numeric to Decimal

Assorted buildfarm members don't like this patch.

Do you have failure details?

This is probably an attempt to operate decimals vs floats.

Ie: Decimal('3.0') > 0 works, but Decimal('3.0') > 1.3 doesn't
(decimal is explicitly forbidden from operating on floats, some design
decision that can only be disabled in 3.3).

Instead of speculating, you can actually see for yourself. The dashboard
is at <http://www.pgbuildfarm.org/cgi-bin/show_status.pl&gt; Pick one of
the machines failing at PLCheck-C and click its 'Details' link. Then
scroll down a bit and you'll see what is failing.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Claudio Freire
klaussfreire@gmail.com
In reply to: Andrew Dunstan (#4)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

Look at that:

  return x
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_numeric(100);
! INFO:  (Decimal('100'), 'Decimal')
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric
  ------------------------------
--- 219,225 ----
  return x
  $$ LANGUAGE plpythonu;
  SELECT * FROM test_type_conversion_numeric(100);
! INFO:  (Decimal("100"), 'Decimal')
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric
  ------------------------------

" instead of '

All the more reason to use as_tuple

On Sat, Jul 6, 2013 at 9:16 AM, Andrew Dunstan <andrew@dunslane.net> wrote:

On 07/06/2013 01:52 AM, Claudio Freire wrote:

On Sat, Jul 6, 2013 at 2:39 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter_e@gmx.net> writes:

PL/Python: Convert numeric to Decimal

Assorted buildfarm members don't like this patch.

Do you have failure details?

This is probably an attempt to operate decimals vs floats.

Ie: Decimal('3.0') > 0 works, but Decimal('3.0') > 1.3 doesn't
(decimal is explicitly forbidden from operating on floats, some design
decision that can only be disabled in 3.3).

Instead of speculating, you can actually see for yourself. The dashboard is
at <http://www.pgbuildfarm.org/cgi-bin/show_status.pl&gt; Pick one of the
machines failing at PLCheck-C and click its 'Details' link. Then scroll down
a bit and you'll see what is failing.

cheers

andrew

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Szymon Guz
mabewlun@gmail.com
In reply to: Claudio Freire (#5)
1 attachment(s)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On 6 July 2013 17:58, Claudio Freire <klaussfreire@gmail.com> wrote:

Look at that:

return x
$$ LANGUAGE plpythonu;
SELECT * FROM test_type_conversion_numeric(100);
! INFO:  (Decimal('100'), 'Decimal')
CONTEXT:  PL/Python function "test_type_conversion_numeric"
test_type_conversion_numeric
------------------------------
--- 219,225 ----
return x
$$ LANGUAGE plpythonu;
SELECT * FROM test_type_conversion_numeric(100);
! INFO:  (Decimal("100"), 'Decimal')
CONTEXT:  PL/Python function "test_type_conversion_numeric"
test_type_conversion_numeric
------------------------------

" instead of '

All the more reason to use as_tuple

On Sat, Jul 6, 2013 at 9:16 AM, Andrew Dunstan <andrew@dunslane.net>
wrote:

On 07/06/2013 01:52 AM, Claudio Freire wrote:

On Sat, Jul 6, 2013 at 2:39 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Peter Eisentraut <peter_e@gmx.net> writes:

PL/Python: Convert numeric to Decimal

Assorted buildfarm members don't like this patch.

Do you have failure details?

This is probably an attempt to operate decimals vs floats.

Ie: Decimal('3.0') > 0 works, but Decimal('3.0') > 1.3 doesn't
(decimal is explicitly forbidden from operating on floats, some design
decision that can only be disabled in 3.3).

Instead of speculating, you can actually see for yourself. The dashboard

is

at <http://www.pgbuildfarm.org/cgi-bin/show_status.pl&gt; Pick one of the
machines failing at PLCheck-C and click its 'Details' link. Then scroll

down

a bit and you'll see what is failing.

cheers

andrew

Hi,
I've modifled the tests to check the numeric->decimal conversion some other
way. They check now conversion to float/int and to string, and also tuple
values.

I've checked that on decimal and cdecimal on python 2.7 and 3.3. The
outputs are the same regardles the Python and decimal versions.

thanks,
Szymon

Attachments:

fix_plpython_decimal_tests.patchapplication/octet-stream; name=fix_plpython_decimal_tests.patchDownload
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
index edc5142..e83ee32 100644
--- a/src/pl/plpython/expected/plpython_types.out
+++ b/src/pl/plpython/expected/plpython_types.out
@@ -212,74 +212,190 @@ CONTEXT:  PL/Python function "test_type_conversion_int8"
                           
 (1 row)
 
-CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
-# print just the class name, not the type, to avoid differences
-# between decimal and cdecimal
-plpy.info(x, x.__class__.__name__)
-return x
-$$ LANGUAGE plpythonu;
-SELECT * FROM test_type_conversion_numeric(100);
-INFO:  (Decimal('100'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                          100
-(1 row)
+CREATE FUNCTION test_type_conversion_numeric_tuple(
+  x numeric,
+  expected_sign int,
+  expected_digits int[],
+  expected_exponent int
+) RETURNS numeric AS $$
 
-SELECT * FROM test_type_conversion_numeric(-100);
-INFO:  (Decimal('-100'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                         -100
-(1 row)
+t = x.as_tuple()
 
-SELECT * FROM test_type_conversion_numeric(100.0);
-INFO:  (Decimal('100.0'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                        100.0
+plpy.info(t.sign == expected_sign)
+plpy.info(t.digits == tuple(expected_digits))
+plpy.info(t.exponent == expected_exponent)
+
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_numeric_tuple(100, 0, ARRAY[1, 0, 0], 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                                100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(-100, 1, ARRAY[1, 0, 0], 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                               -100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(5000000000.5, 0, ARRAY[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], -1 );
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                       5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(1234567890.0987654321, 0, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+              1234567890.0987654321
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(-1234567890.0987654321, 1, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+             -1234567890.0987654321
+(1 row)
+
+CREATE FUNCTION test_type_conversion_numeric_string(
+  x numeric,
+  expected_string text
+) RETURNS numeric AS $$
+plpy.info(str(x) == expected_string)
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_numeric_string(100, '100');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                                 100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(-100, '-100');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                                -100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(5000000000.5, '5000000000.5');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                        5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(1234567890.0987654321, '1234567890.0987654321');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+               1234567890.0987654321
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(-1234567890.0987654321, '-1234567890.0987654321');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+              -1234567890.0987654321
+(1 row)
+
+CREATE FUNCTION test_type_conversion_numeric_int(
+  x numeric,
+  expected_value int
+) RETURNS numeric AS $$
+plpy.info(int(x) == expected_value)
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_numeric_int(100, 100);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_int"
+ test_type_conversion_numeric_int 
+----------------------------------
+                              100
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(100.00);
-INFO:  (Decimal('100.00'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                       100.00
+SELECT * FROM test_type_conversion_numeric_int(-100, -100);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_int"
+ test_type_conversion_numeric_int 
+----------------------------------
+                             -100
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(5000000000.5);
-INFO:  (Decimal('5000000000.5'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                 5000000000.5
+CREATE FUNCTION test_type_conversion_numeric_float(
+  x numeric,
+  expected_float float,
+  epsilon float
+) RETURNS numeric AS $$
+plpy.info( abs(float(x) - expected_float) <= epsilon )
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_numeric_float(5000000000.5, 5000000000.5, 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+                       5000000000.5
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
-INFO:  (Decimal('1234567890.0987654321'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-        1234567890.0987654321
+SELECT * FROM test_type_conversion_numeric_float(1234567890.0987654321, 1234567890.0987654321, 0.00001);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+              1234567890.0987654321
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
-INFO:  (Decimal('-1234567890.0987654321'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-       -1234567890.0987654321
+SELECT * FROM test_type_conversion_numeric_float(-1234567890.0987654321, -1234567890.0987654321, 0.00001);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+             -1234567890.0987654321
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(null);
-INFO:  (None, 'NoneType')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                             
+CREATE FUNCTION test_type_conversion_numeric_null(x numeric) RETURNS numeric AS $$
+return x
+$$ LANGUAGE plpythonu;
+SELECT * FROM test_type_conversion_numeric_null(null);
+ test_type_conversion_numeric_null 
+-----------------------------------
+                                  
 (1 row)
 
 CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
diff --git a/src/pl/plpython/expected/plpython_types_3.out b/src/pl/plpython/expected/plpython_types_3.out
index 11c4c47..dbb566c 100644
--- a/src/pl/plpython/expected/plpython_types_3.out
+++ b/src/pl/plpython/expected/plpython_types_3.out
@@ -212,74 +212,190 @@ CONTEXT:  PL/Python function "test_type_conversion_int8"
                           
 (1 row)
 
-CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
-# print just the class name, not the type, to avoid differences
-# between decimal and cdecimal
-plpy.info(x, x.__class__.__name__)
-return x
-$$ LANGUAGE plpython3u;
-SELECT * FROM test_type_conversion_numeric(100);
-INFO:  (Decimal('100'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                          100
-(1 row)
+CREATE FUNCTION test_type_conversion_numeric_tuple(
+  x numeric,
+  expected_sign int,
+  expected_digits int[],
+  expected_exponent int
+) RETURNS numeric AS $$
 
-SELECT * FROM test_type_conversion_numeric(-100);
-INFO:  (Decimal('-100'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                         -100
-(1 row)
+t = x.as_tuple()
 
-SELECT * FROM test_type_conversion_numeric(100.0);
-INFO:  (Decimal('100.0'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                        100.0
+plpy.info(t.sign == expected_sign)
+plpy.info(t.digits == tuple(expected_digits))
+plpy.info(t.exponent == expected_exponent)
+
+return x
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_numeric_tuple(100, 0, ARRAY[1, 0, 0], 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                                100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(-100, 1, ARRAY[1, 0, 0], 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                               -100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(5000000000.5, 0, ARRAY[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], -1 );
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+                       5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(1234567890.0987654321, 0, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+              1234567890.0987654321
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_tuple(-1234567890.0987654321, 1, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_tuple"
+ test_type_conversion_numeric_tuple 
+------------------------------------
+             -1234567890.0987654321
+(1 row)
+
+CREATE FUNCTION test_type_conversion_numeric_string(
+  x numeric,
+  expected_string text
+) RETURNS numeric AS $$
+plpy.info(str(x) == expected_string)
+return x
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_numeric_string(100, '100');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                                 100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(-100, '-100');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                                -100
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(5000000000.5, '5000000000.5');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+                        5000000000.5
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(1234567890.0987654321, '1234567890.0987654321');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+               1234567890.0987654321
+(1 row)
+
+SELECT * FROM test_type_conversion_numeric_string(-1234567890.0987654321, '-1234567890.0987654321');
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_string"
+ test_type_conversion_numeric_string 
+-------------------------------------
+              -1234567890.0987654321
+(1 row)
+
+CREATE FUNCTION test_type_conversion_numeric_int(
+  x numeric,
+  expected_value int
+) RETURNS numeric AS $$
+plpy.info(int(x) == expected_value)
+return x
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_numeric_int(100, 100);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_int"
+ test_type_conversion_numeric_int 
+----------------------------------
+                              100
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(100.00);
-INFO:  (Decimal('100.00'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                       100.00
+SELECT * FROM test_type_conversion_numeric_int(-100, -100);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_int"
+ test_type_conversion_numeric_int 
+----------------------------------
+                             -100
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(5000000000.5);
-INFO:  (Decimal('5000000000.5'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                 5000000000.5
+CREATE FUNCTION test_type_conversion_numeric_float(
+  x numeric,
+  expected_float float,
+  epsilon float
+) RETURNS numeric AS $$
+plpy.info( abs(float(x) - expected_float) <= epsilon )
+return x
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_numeric_float(5000000000.5, 5000000000.5, 0);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+                       5000000000.5
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
-INFO:  (Decimal('1234567890.0987654321'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-        1234567890.0987654321
+SELECT * FROM test_type_conversion_numeric_float(1234567890.0987654321, 1234567890.0987654321, 0.00001);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+              1234567890.0987654321
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
-INFO:  (Decimal('-1234567890.0987654321'), 'Decimal')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-       -1234567890.0987654321
+SELECT * FROM test_type_conversion_numeric_float(-1234567890.0987654321, -1234567890.0987654321, 0.00001);
+INFO:  True
+CONTEXT:  PL/Python function "test_type_conversion_numeric_float"
+ test_type_conversion_numeric_float 
+------------------------------------
+             -1234567890.0987654321
 (1 row)
 
-SELECT * FROM test_type_conversion_numeric(null);
-INFO:  (None, 'NoneType')
-CONTEXT:  PL/Python function "test_type_conversion_numeric"
- test_type_conversion_numeric 
-------------------------------
-                             
+CREATE FUNCTION test_type_conversion_numeric_null(x numeric) RETURNS numeric AS $$
+return x
+$$ LANGUAGE plpython3u;
+SELECT * FROM test_type_conversion_numeric_null(null);
+ test_type_conversion_numeric_null 
+-----------------------------------
+                                  
 (1 row)
 
 CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
diff --git a/src/pl/plpython/sql/plpython_types.sql b/src/pl/plpython/sql/plpython_types.sql
index 6881880..5761b22 100644
--- a/src/pl/plpython/sql/plpython_types.sql
+++ b/src/pl/plpython/sql/plpython_types.sql
@@ -85,21 +85,78 @@ 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 $$
-# print just the class name, not the type, to avoid differences
-# between decimal and cdecimal
-plpy.info(x, x.__class__.__name__)
+CREATE FUNCTION test_type_conversion_numeric_tuple(
+  x numeric,
+  expected_sign int,
+  expected_digits int[],
+  expected_exponent int
+) RETURNS numeric AS $$
+
+t = x.as_tuple()
+
+plpy.info(t.sign == expected_sign)
+plpy.info(t.digits == tuple(expected_digits))
+plpy.info(t.exponent == expected_exponent)
+
+return x
+$$ LANGUAGE plpythonu;
+
+
+SELECT * FROM test_type_conversion_numeric_tuple(100, 0, ARRAY[1, 0, 0], 0);
+SELECT * FROM test_type_conversion_numeric_tuple(-100, 1, ARRAY[1, 0, 0], 0);
+SELECT * FROM test_type_conversion_numeric_tuple(5000000000.5, 0, ARRAY[5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], -1 );
+SELECT * FROM test_type_conversion_numeric_tuple(1234567890.0987654321, 0, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+SELECT * FROM test_type_conversion_numeric_tuple(-1234567890.0987654321, 1, ARRAY[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1], -10);
+
+
+CREATE FUNCTION test_type_conversion_numeric_string(
+  x numeric,
+  expected_string text
+) RETURNS numeric AS $$
+plpy.info(str(x) == expected_string)
+return x
+$$ LANGUAGE plpythonu;
+
+SELECT * FROM test_type_conversion_numeric_string(100, '100');
+SELECT * FROM test_type_conversion_numeric_string(-100, '-100');
+SELECT * FROM test_type_conversion_numeric_string(5000000000.5, '5000000000.5');
+SELECT * FROM test_type_conversion_numeric_string(1234567890.0987654321, '1234567890.0987654321');
+SELECT * FROM test_type_conversion_numeric_string(-1234567890.0987654321, '-1234567890.0987654321');
+
+
+CREATE FUNCTION test_type_conversion_numeric_int(
+  x numeric,
+  expected_value int
+) RETURNS numeric AS $$
+plpy.info(int(x) == expected_value)
+return x
+$$ LANGUAGE plpythonu;
+
+
+SELECT * FROM test_type_conversion_numeric_int(100, 100);
+SELECT * FROM test_type_conversion_numeric_int(-100, -100);
+
+
+CREATE FUNCTION test_type_conversion_numeric_float(
+  x numeric,
+  expected_float float,
+  epsilon float
+) RETURNS numeric AS $$
+plpy.info( abs(float(x) - expected_float) <= epsilon )
+return x
+$$ LANGUAGE plpythonu;
+
+
+SELECT * FROM test_type_conversion_numeric_float(5000000000.5, 5000000000.5, 0);
+SELECT * FROM test_type_conversion_numeric_float(1234567890.0987654321, 1234567890.0987654321, 0.00001);
+SELECT * FROM test_type_conversion_numeric_float(-1234567890.0987654321, -1234567890.0987654321, 0.00001);
+
+
+CREATE FUNCTION test_type_conversion_numeric_null(x numeric) RETURNS numeric AS $$
 return x
 $$ LANGUAGE plpythonu;
 
-SELECT * FROM test_type_conversion_numeric(100);
-SELECT * FROM test_type_conversion_numeric(-100);
-SELECT * FROM test_type_conversion_numeric(100.0);
-SELECT * FROM test_type_conversion_numeric(100.00);
-SELECT * FROM test_type_conversion_numeric(5000000000.5);
-SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
-SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
-SELECT * FROM test_type_conversion_numeric(null);
+SELECT * FROM test_type_conversion_numeric_null(null);
 
 
 CREATE FUNCTION test_type_conversion_float4(x float4) RETURNS float4 AS $$
#7Peter Eisentraut
peter_e@gmx.net
In reply to: Peter Eisentraut (#1)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On Sun, 2013-07-07 at 02:01 -0300, Claudio Freire wrote:

You really want to test more than just the str. The patch contains
casts to int and float, which is something existing PLPython code will
be doing, so it's good to test it still can be done with decimal.

Let's remember that we are regression testing PL/Python here, not
Python. The functionality of PL/Python is to convert a numeric to
Decimal, and that's what we are testing. What Python can or cannot do
with that is not our job to test.

Existing python code will also expect the number to be a float, and
will try to operate against other floats. That's not going to work
anymore, that has to go into release notes.

Right, this will be listed in the release notes under upgrade caveats.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Peter Eisentraut
peter_e@gmx.net
In reply to: Peter Eisentraut (#1)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On Sun, 2013-07-07 at 17:21 +0200, Szymon Guz wrote:

I think that these tests are much better, so they should go into
trunk.
As for Python 2.5 I think we could modify the code and makefile (with
additional documentation info) so the decimal code wouldn't be
compiled
with python 2.5.

I'd welcome updated tests, if you want to work on that. But they would
need to work uniformly for Python 2.4 through 3.3.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Szymon Guz
mabewlun@gmail.com
In reply to: Peter Eisentraut (#8)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On 7 July 2013 21:35, Peter Eisentraut <peter_e@gmx.net> wrote:

On Sun, 2013-07-07 at 17:21 +0200, Szymon Guz wrote:

I think that these tests are much better, so they should go into
trunk.
As for Python 2.5 I think we could modify the code and makefile (with
additional documentation info) so the decimal code wouldn't be
compiled
with python 2.5.

I'd welcome updated tests, if you want to work on that. But they would
need to work uniformly for Python 2.4 through 3.3.

Well... I don't know what to do and which solution is better.

This patch works, but the tests are not working on some old machines.

This patch works, but changes the plpython functions, so I assume that it
will provide errors to some existing functions. I've noticed yesterday that
you cannot run code like `Decimal(10) - float(10)`. So if a function
accepts a numeric parameter 'x', which currently is converted to float,
then the code like `x - float(10)` currently works, and will not work after
this change.

Introducing decimal.Decimal also breaks python earlier than 2.4, as the
decimal module has been introduced in 2.4. We could use the old conversion
for versions before 2.4, and the new for 2.4 and newer. Do we want it to
work like this? Do we want to have different behaviour for different python
versions? I'm not sure if anyone still uses Python 2.3, but I've already
realised that the patch breaks all the functions for 2.3 which use numeric
argument.

I assume that the patch will be rolled back, if it the tests don't work on
some machines, right?

szymon

#10Claudio Freire
klaussfreire@gmail.com
In reply to: Peter Eisentraut (#7)
Re: [COMMITTERS] pgsql: PL/Python: Convert numeric to Decimal

On Sun, Jul 7, 2013 at 4:28 PM, Peter Eisentraut <peter_e@gmx.net> wrote:

On Sun, 2013-07-07 at 02:01 -0300, Claudio Freire wrote:

You really want to test more than just the str. The patch contains
casts to int and float, which is something existing PLPython code will
be doing, so it's good to test it still can be done with decimal.

Let's remember that we are regression testing PL/Python here, not
Python. The functionality of PL/Python is to convert a numeric to
Decimal, and that's what we are testing. What Python can or cannot do
with that is not our job to test.

I was just proposing to test behavior likely to be expected by
PL/Python functions, but you probably know better than I.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers