[pypy-svn] r69640 - in pypy/trunk/pypy/module/oracle: . test

afa at codespeak.net afa at codespeak.net
Wed Nov 25 18:21:30 CET 2009


Author: afa
Date: Wed Nov 25 18:21:29 2009
New Revision: 69640

Modified:
   pypy/trunk/pypy/module/oracle/interp_object.py
   pypy/trunk/pypy/module/oracle/interp_variable.py
   pypy/trunk/pypy/module/oracle/roci.py
   pypy/trunk/pypy/module/oracle/test/test_objectvar.py
Log:
Implement description and retrieval of collections types.


Modified: pypy/trunk/pypy/module/oracle/interp_object.py
==============================================================================
--- pypy/trunk/pypy/module/oracle/interp_object.py	(original)
+++ pypy/trunk/pypy/module/oracle/interp_object.py	Wed Nov 25 18:21:29 2009
@@ -2,7 +2,8 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.interpreter.typedef import interp_attrproperty
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.oracle import roci
+
+from pypy.module.oracle import roci, transform
 
 class W_ObjectType(Wrappable):
     def __init__(self, connection, param):
@@ -158,16 +159,59 @@
             self.isCollection = 1
 
             # determine type of collection
-            XXX
+            typecodeptr = lltype.malloc(roci.Ptr(roci.OCITypeCode).TO,
+                                        1, flavor='raw')
+            try:
+                status = roci.OCIAttrGet(
+                    toplevelParam, roci.OCI_DTYPE_PARAM,
+                    rffi.cast(roci.dvoidp, typecodeptr),
+                    lltype.nullptr(roci.Ptr(roci.ub4).TO),
+                    roci.OCI_ATTR_TYPECODE,
+                    self.environment.errorHandle)
+                self.environment.checkForError(
+                    status, "ObjectType_Describe(): get collection type code")
+                self.collectionTypeCode = typecodeptr[0]
+            finally:
+                lltype.free(typecodeptr, flavor='raw')
 
             # acquire collection parameter descriptor
-            XXX
+            paramptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO,
+                                     1, flavor='raw')
+            try:
+                status = roci.OCIAttrGet(
+                    toplevelParam, roci.OCI_DTYPE_PARAM,
+                    rffi.cast(roci.dvoidp, paramptr),
+                    lltype.nullptr(roci.Ptr(roci.ub4).TO),
+                    roci.OCI_ATTR_COLLECTION_ELEMENT,
+                    self.environment.errorHandle)
+                self.environment.checkForError(
+                    status,
+                    "ObjectType_Describe(): get collection descriptor")
+                collectionParam = paramptr[0]
+            finally:
+                lltype.free(paramptr, flavor='raw')
 
             # determine type of element
-            XXX
+            typecodeptr = lltype.malloc(roci.Ptr(roci.OCITypeCode).TO,
+                                        1, flavor='raw')
+            try:
+                status = roci.OCIAttrGet(
+                    collectionParam, roci.OCI_DTYPE_PARAM,
+                    rffi.cast(roci.dvoidp, typecodeptr),
+                    lltype.nullptr(roci.Ptr(roci.ub4).TO),
+                    roci.OCI_ATTR_TYPECODE,
+                    self.environment.errorHandle)
+                self.environment.checkForError(
+                    status, "ObjectType_Describe(): get element type code")
+                self.elementTypeCode = typecodeptr[0]
+            finally:
+                lltype.free(typecodeptr, flavor='raw')
 
             # if element type is an object type get its type
-            XXX
+            if self.elementTypeCode == roci.OCI_TYPECODE_OBJECT:
+                self.elementType = W_ObjectType(connection, collectionParam)
+            else:
+                self.elementType = None
 
         # determine the number of attributes
         numptr = lltype.malloc(roci.Ptr(roci.ub2).TO,
@@ -296,3 +340,98 @@
     'ExternalObject',
     type = interp_attrproperty('type', W_ExternalObject),
     )
+
+def convertToPython(space, environment, typeCode,
+                    value, indicator, var, subtype):
+    # null values returned as None
+    if rffi.cast(roci.Ptr(roci.OCIInd), indicator)[0] == roci.OCI_IND_NULL:
+        return space.w_None
+
+    if typeCode in (roci.OCI_TYPECODE_CHAR,
+                    roci.OCI_TYPECODE_VARCHAR,
+                    roci.OCI_TYPECODE_VARCHAR2):
+        strValue = value
+        stringValue = roci.OCIStringPtr(environment.handle, strValue)
+        stringSize = roci.OCIStringPtr(environment.handle, strValue)
+        return config.w_string(space, stringValue, stringSize)
+    elif typeCode == roci.OCI_TYPECODE_NUMBER:
+        return transform.OracleNumberToPythonFloat(
+            environment,
+            rffi.cast(roci.Ptr(roci.OCINumber), value))
+    elif typeCode == roci.OCI_TYPECODE_DATE:
+        return transform.OracleDateToPythonDate(environment, value)
+    elif typeCode == roci.OCI_TYPECODE_TIMESTAMP:
+        return transform.OracleTimestampToPythonDate(environment, value)
+    elif typeCode == roci.OCI_TYPECODE_OBJECT:
+        return space.wrap(W_ExternalObject(var, subType, value, indicator,
+                                           isIndependent=False))
+    elif typeCode == roci.OCI_TYPECODE_NAMEDCOLLECTION:
+        return convertCollection(space, environment, value, var, subType)
+
+    raise OperationError(
+        get(space).w_NotSupportedError,
+        space.wrap(
+            "ExternalObjectVar_GetAttributeValue(): unhandled data type %d" % (
+                typeCode,)))
+
+
+def convertCollection(space, environment, value, var, objectType):
+    "Convert a collection to a Python list"
+
+    result_w = []
+
+    iterptr = lltype.malloc(rffi.CArrayPtr(roci.OCIIter).TO, 1, flavor='raw')
+    try:
+        # create the iterator
+        status = roci.OCIIterCreate(
+            environment.handle,
+            environment.errorHandle,
+            value,
+            iterptr)
+        environment.checkForError(
+            status, "ExternalObjectVar_ConvertCollection(): creating iterator")
+
+        try:
+            # create the result list
+            valueptr = lltype.malloc(rffi.CArrayPtr(roci.dvoidp).TO,
+                                     1, flavor='raw')
+            indicatorptr = lltype.malloc(rffi.CArrayPtr(roci.dvoidp).TO,
+                                         1, flavor='raw')
+            eofptr = lltype.malloc(rffi.CArrayPtr(roci.boolean).TO,
+                                   1, flavor='raw')
+            try:
+                while True:
+                    status = roci.OCIIterNext(
+                        environment.handle,
+                        environment.errorHandle,
+                        iterptr[0],
+                        valueptr,
+                        indicatorptr,
+                        eofptr)
+                    environment.checkForError(
+                        status,
+                        "ExternalObjectVar_ConvertCollection(): get next")
+
+                    if eofptr[0]:
+                        break
+                    element = convertToPython(
+                        space, environment,
+                        objectType.elementTypeCode,
+                        valueptr[0], indicatorptr[0],
+                        var, objectType.elementType)
+                    result_w.append(element)
+            finally:
+                lltype.free(valueptr, flavor='raw')
+                lltype.free(indicatorptr, flavor='raw')
+                lltype.free(eofptr, flavor='raw')
+
+        finally:
+            roci.OCIIterDelete(
+                environment.handle,
+                environment.errorHandle,
+                iterptr)
+    finally:
+        lltype.free(iterptr, flavor='raw')
+
+    return space.newlist(result_w)
+

Modified: pypy/trunk/pypy/module/oracle/interp_variable.py
==============================================================================
--- pypy/trunk/pypy/module/oracle/interp_variable.py	(original)
+++ pypy/trunk/pypy/module/oracle/interp_variable.py	Wed Nov 25 18:21:29 2009
@@ -1190,7 +1190,7 @@
         # for collections, return the list rather than the object
         if self.objectType.isCollection:
             return interp_object.convertCollection(
-                self.environment, data[pos], self, self.objectType)
+                space, self.environment, data[pos], self, self.objectType)
 
         # for objects, return a representation of the object
         var = interp_object.W_ExternalObject(

Modified: pypy/trunk/pypy/module/oracle/roci.py
==============================================================================
--- pypy/trunk/pypy/module/oracle/roci.py	(original)
+++ pypy/trunk/pypy/module/oracle/roci.py	Wed Nov 25 18:21:29 2009
@@ -64,6 +64,7 @@
     OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO
     OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME OCI_ATTR_TYPECODE
     OCI_ATTR_NUM_TYPE_ATTRS OCI_ATTR_LIST_TYPE_ATTRS
+    OCI_ATTR_COLLECTION_ELEMENT
     OCI_ATTR_CHARSET_FORM OCI_ATTR_ENV_CHARSET_ID
     OCI_ATTR_PARSE_ERROR_OFFSET
     OCI_NTV_SYNTAX OCI_COMMIT_ON_SUCCESS
@@ -81,6 +82,8 @@
     SQLCS_IMPLICIT SQLCS_NCHAR
     OCI_TEMP_CLOB OCI_TEMP_BLOB OCI_DURATION_SESSION OCI_ONE_PIECE
     OCI_NUMBER_SIGNED
+    OCI_TYPECODE_CHAR OCI_TYPECODE_VARCHAR OCI_TYPECODE_VARCHAR2
+    OCI_TYPECODE_NUMBER OCI_TYPECODE_DATE OCI_TYPECODE_TIMESTAMP
     OCI_TYPECODE_NAMEDCOLLECTION OCI_TYPECODE_OBJECT
     OCI_NLS_MAXBUFSZ OCI_NLS_CS_ORA_TO_IANA
     '''.split()
@@ -111,6 +114,8 @@
 OCIRef = rffi.VOIDP
 OCIType = rffi.VOIDP
 OCIComplexObject = rffi.VOIDP
+OCIColl = rffi.VOIDP
+OCIIter = rffi.VOIDP
 
 Ptr = rffi.CArrayPtr
 void = lltype.Void
@@ -488,6 +493,32 @@
      dvoidp],          # object
     sword)
 
+# OCI Collection and Iterator Functions
+OCIIterCreate = external(
+    'OCIIterCreate',
+    [OCIEnv,           # env,
+     OCIError,         # err
+     OCIColl,          # coll
+     Ptr(OCIIter)],    # itr
+    sword)
+
+OCIIterDelete = external(
+    'OCIIterDelete',
+    [OCIEnv,           # env,
+     OCIError,         # err
+     Ptr(OCIIter)],    # itr
+    sword)
+
+OCIIterNext = external(
+    'OCIIterNext',
+    [OCIEnv,           # env,
+     OCIError,         # err
+     OCIIter,          # itr
+     dvoidpp,          # elem
+     dvoidpp,          # elemind
+     Ptr(boolean)],    # eoc
+    sword)
+
 # OCI Date, Datetime, and Interval Functions
 
 OCIDateTimeCheck = external(

Modified: pypy/trunk/pypy/module/oracle/test/test_objectvar.py
==============================================================================
--- pypy/trunk/pypy/module/oracle/test/test_objectvar.py	(original)
+++ pypy/trunk/pypy/module/oracle/test/test_objectvar.py	Wed Nov 25 18:21:29 2009
@@ -1,7 +1,7 @@
 from pypy.module.oracle.test.test_connect import OracleTestBase
 
 class AppTestObjectVar(OracleTestBase):
-    def test_fetch(self):
+    def test_fetch_object(self):
         cur = self.cnx.cursor()
         try:
             cur.execute("drop table pypy_test_objtable")
@@ -11,6 +11,10 @@
             cur.execute("drop type pypy_test_objtype")
         except oracle.DatabaseError:
             pass
+        try:
+            cur.execute("drop type pypy_test_arraytype")
+        except oracle.DatabaseError:
+            pass
         cur.execute("""\
             create type pypy_test_objtype as object (
                 numbercol number,
@@ -18,17 +22,24 @@
                 datecol   date);
             """)
         cur.execute("""\
+            create type pypy_test_arraytype as varray(10) of number;
+            """)
+        cur.execute("""\
             create table pypy_test_objtable (
-                objcol pypy_test_objtype)
+                objcol pypy_test_objtype,
+                arraycol pypy_test_arraytype)
             """)
         cur.execute("""\
             insert into pypy_test_objtable values (
             pypy_test_objtype(1, 'someText',
-                              to_date(20070306, 'YYYYMMDD')))
+                              to_date(20070306, 'YYYYMMDD')),
+            pypy_test_arraytype(5, 10, null, 20))
             """)
 
-        cur.execute("select objcol from pypy_test_objtable")
-        objValue, = cur.fetchone()
+        cur.execute("select objcol, arraycol from pypy_test_objtable")
+        objValue, arrayValue = cur.fetchone()
         assert objValue.type.schema == self.cnx.username.upper()
         assert objValue.type.name == "PYPY_TEST_OBJTYPE"
         assert objValue.type.attributes[0].name == "NUMBERCOL"
+        assert isinstance(arrayValue, list)
+        assert arrayValue == [5, 10, None, 20]



More information about the Pypy-commit mailing list