On 06/27/2013 05:04 AM, Szymon Guz wrote:
On 27 June 2013 05:21, Steve Singer <st...@ssinger.info <mailto:st...@ssinger.info>> wrote:

    On 06/26/2013 04:47 PM, Szymon Guz wrote:






Hi Steve,
thanks for the changes.

You're idea about common code for decimal and cdecimal is good, however not good enough. I like the idea of common code for decimal and cdecimal. But we need class name, not the value.

I've changed the code from str(x) to x.__class__.__name__ so the function prints class name (which is Decimal for both packages), not the value. We need to have the class name check. The value is returned by the function and is a couple of lines lower in the file.

patch is attached.


I think the value is more important than the name, I want to the tests to make sure that the conversion is actually converting properly. With your method of getting the class name without the module we can have both.

The attached patch should print the value and the class name but not the module name.

Steve


thanks,
Szymon







diff --git a/doc/src/sgml/plpython.sgml b/doc/src/sgml/plpython.sgml
new file mode 100644
index aaf758d..da27874
*** a/doc/src/sgml/plpython.sgml
--- b/doc/src/sgml/plpython.sgml
*************** $$ LANGUAGE plpythonu;
*** 308,321 ****
        </para>
       </listitem>
  
       <listitem>
        <para>
!        PostgreSQL <type>real</type>, <type>double</type>,
!        and <type>numeric</type> are converted to
!        Python <type>float</type>.  Note that for
!        the <type>numeric</type> this loses information and can lead to
!        incorrect results.  This might be fixed in a future
!        release.
        </para>
       </listitem>
  
--- 308,326 ----
        </para>
       </listitem>
  
+ 	 <listitem>
+       <para>
+        PostgreSQL <type>real</type> and <type>double</type> are converted to
+        Python <type>float</type>.
+       </para>
+      </listitem>
+ 
       <listitem>
        <para>
!        PostgreSQL <type>numeric</type> is converted to
!        Python <type>Decimal</type>. This type is imported from 
! 	   <literal>cdecimal</literal> package if it is available. If cdecimal
! 	   cannot be used, then <literal>decimal.Decimal</literal> will be used.
        </para>
       </listitem>
  
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
new file mode 100644
index 4641345..e602336
*** a/src/pl/plpython/expected/plpython_types.out
--- b/src/pl/plpython/expected/plpython_types.out
*************** CONTEXT:  PL/Python function "test_type_
*** 213,248 ****
  (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(null);
! INFO:  (None, <type 'NoneType'>)
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
--- 213,264 ----
  (1 row)
  
  CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
! plpy.info(x,x.__class__.__name__)
  return x
  $$ LANGUAGE plpythonu;
! /* The current implementation converts numeric to Decimal. */
  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)
  
  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)
  
  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
  (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
+ (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
+ (1 row)
+ 
  SELECT * FROM test_type_conversion_numeric(null);
! INFO:  (None, 'NoneType')
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
diff --git a/src/pl/plpython/expected/plpython_types_3.out b/src/pl/plpython/expected/plpython_types_3.out
new file mode 100644
index 511ef5a..57538b3
*** a/src/pl/plpython/expected/plpython_types_3.out
--- b/src/pl/plpython/expected/plpython_types_3.out
*************** CONTEXT:  PL/Python function "test_type_
*** 213,248 ****
  (1 row)
  
  CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
! plpy.info(x, type(x))
  return x
  $$ LANGUAGE plpython3u;
! /* The current implementation converts numeric to float. */
  SELECT * FROM test_type_conversion_numeric(100);
! INFO:  (100.0, <class '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, <class '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, <class 'float'>)
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                   5000000000.5
  (1 row)
  
  SELECT * FROM test_type_conversion_numeric(null);
! INFO:  (None, <class 'NoneType'>)
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
--- 213,264 ----
  (1 row)
  
  CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
! plpy.info(str(x))
  return x
  $$ LANGUAGE plpython3u;
! /* The current implementation converts numeric to Decimal. */
  SELECT * FROM test_type_conversion_numeric(100);
! INFO:  Decimal
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
!                           100
  (1 row)
  
  SELECT * FROM test_type_conversion_numeric(-100);
! INFO:  Decimal
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
!                          -100
  (1 row)
  
  SELECT * FROM test_type_conversion_numeric(5000000000.5);
! INFO:  Decimal
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
                   5000000000.5
  (1 row)
  
+ SELECT * FROM test_type_conversion_numeric(1234567890.0987654321);
+ INFO:  Decimal
+ CONTEXT:  PL/Python function "test_type_conversion_numeric"
+  test_type_conversion_numeric 
+ ------------------------------
+         1234567890.0987654321
+ (1 row)
+ 
+ SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
+ INFO:  Decimal
+ CONTEXT:  PL/Python function "test_type_conversion_numeric"
+  test_type_conversion_numeric 
+ ------------------------------
+        -1234567890.0987654321
+ (1 row)
+ 
  SELECT * FROM test_type_conversion_numeric(null);
! INFO:  NoneType
  CONTEXT:  PL/Python function "test_type_conversion_numeric"
   test_type_conversion_numeric 
  ------------------------------
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
new file mode 100644
index 6a9a2cb..e04c2f9
*** a/src/pl/plpython/plpy_typeio.c
--- b/src/pl/plpython/plpy_typeio.c
***************
*** 18,23 ****
--- 18,24 ----
  #include "utils/memutils.h"
  #include "utils/syscache.h"
  #include "utils/typcache.h"
+ #include "utils/numeric.h"
  
  #include "plpython.h"
  
*************** static void PLy_output_datum_func2(PLyOb
*** 35,41 ****
  static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
! static PyObject *PLyFloat_FromNumeric(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
--- 36,42 ----
  static PyObject *PLyBool_FromBool(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyFloat_FromFloat4(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyFloat_FromFloat8(PLyDatumToOb *arg, Datum d);
! static PyObject *PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyInt_FromInt16(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyInt_FromInt32(PLyDatumToOb *arg, Datum d);
  static PyObject *PLyLong_FromInt64(PLyDatumToOb *arg, Datum d);
*************** PLy_input_datum_func2(PLyDatumToOb *arg,
*** 450,456 ****
  			arg->func = PLyFloat_FromFloat8;
  			break;
  		case NUMERICOID:
! 			arg->func = PLyFloat_FromNumeric;
  			break;
  		case INT2OID:
  			arg->func = PLyInt_FromInt16;
--- 451,457 ----
  			arg->func = PLyFloat_FromFloat8;
  			break;
  		case NUMERICOID:
! 			arg->func = PLyDecimal_FromNumeric;
  			break;
  		case INT2OID:
  			arg->func = PLyInt_FromInt16;
*************** PLyFloat_FromFloat8(PLyDatumToOb *arg, D
*** 516,531 ****
  }
  
  static PyObject *
! PLyFloat_FromNumeric(PLyDatumToOb *arg, Datum d)
  {
! 	/*
! 	 * Numeric is cast to a PyFloat: This results in a loss of precision Would
! 	 * it be better to cast to PyString?
! 	 */
! 	Datum		f = DirectFunctionCall1(numeric_float8, d);
! 	double		x = DatumGetFloat8(f);
  
! 	return PyFloat_FromDouble(x);
  }
  
  static PyObject *
--- 517,549 ----
  }
  
  static PyObject *
! PLyDecimal_FromNumeric(PLyDatumToOb *arg, Datum d)
  {
! 	char *x;
! 	PyObject *pvalue, *value, *decimal, *decimal_dict;
! 	static PyObject *decimal_ctor;
  
! 	/* Try to import cdecimal, if it doesnt exist, fallback to decimal */
! 	if (decimal_ctor == NULL)
! 	{
! 		decimal = PyImport_ImportModule("cdecimal");
! 		if (decimal == NULL)
! 		{
! 			PyErr_Clear();
! 			decimal = PyImport_ImportModule("decimal");
! 		}
! 		if (decimal == NULL)
! 			PLy_elog(ERROR, "could not import module 'decimal'");
! 
! 		decimal_dict = PyModule_GetDict(decimal);
! 		decimal_ctor = PyDict_GetItemString(decimal_dict, "Decimal");
! 		Py_DECREF(decimal_dict);
! 	}
! 
! 	x = DatumGetCString(DirectFunctionCall1(numeric_out, d));
! 	pvalue = PyString_FromString(x);
! 	value = PyObject_CallFunctionObjArgs(decimal_ctor, pvalue, NULL);
! 	return value;
  }
  
  static PyObject *
diff --git a/src/pl/plpython/sql/plpython_types.sql b/src/pl/plpython/sql/plpython_types.sql
new file mode 100644
index 6a50b42..0f707cf
*** a/src/pl/plpython/sql/plpython_types.sql
--- b/src/pl/plpython/sql/plpython_types.sql
*************** SELECT * FROM test_type_conversion_int8(
*** 86,99 ****
  
  
  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(null);
  
  
--- 86,101 ----
  
  
  CREATE FUNCTION test_type_conversion_numeric(x numeric) RETURNS numeric AS $$
! plpy.info(x,x.__class__.__name__)
  return x
  $$ LANGUAGE plpythonu;
  
! /* The current implementation converts numeric to Decimal. */
  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(1234567890.0987654321);
+ SELECT * FROM test_type_conversion_numeric(-1234567890.0987654321);
  SELECT * FROM test_type_conversion_numeric(null);
  
  
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to