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

afa at codespeak.net afa at codespeak.net
Wed Nov 25 16:03:54 CET 2009


Author: afa
Date: Wed Nov 25 16:03:53 2009
New Revision: 69636

Added:
   pypy/trunk/pypy/module/oracle/interp_object.py
   pypy/trunk/pypy/module/oracle/test/test_objectvar.py
Modified:
   pypy/trunk/pypy/module/oracle/interp_variable.py
   pypy/trunk/pypy/module/oracle/roci.py
Log:
Start to implment the OBJECT datatype.
The Oracle API is really a complex beast.


Added: pypy/trunk/pypy/module/oracle/interp_object.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/oracle/interp_object.py	Wed Nov 25 16:03:53 2009
@@ -0,0 +1,115 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.oracle import roci
+
+class W_ObjectType(Wrappable):
+    def __init__(self, connection, param):
+        self.environment = connection.environment
+        self.isCollection = False
+        self.initialize(connection, param)
+
+    def initialize(self, connection, param):
+        nameptr = lltype.malloc(rffi.CArrayPtr(roci.oratext).TO, 1,
+                                flavor='raw')
+        lenptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1,
+                               flavor='raw')
+        try:
+            # determine the schema of the type
+            status = roci.OCIAttrGet(
+                param, roci.OCI_HTYPE_DESCRIBE,
+                rffi.cast(roci.dvoidp, nameptr),
+                lenptr,
+                roci.OCI_ATTR_SCHEMA_NAME,
+                self.environment.errorHandle)
+            self.environment.checkForError(
+                status,
+                "ObjectType_Initialize(): get schema name")
+            self.schema = rffi.charpsize2str(nameptr[0], lenptr[0])
+
+            # determine the name of the type
+            status = roci.OCIAttrGet(
+                param, roci.OCI_HTYPE_DESCRIBE,
+                rffi.cast(roci.dvoidp, nameptr),
+                lenptr,
+                roci.OCI_ATTR_TYPE_NAME,
+                self.environment.errorHandle)
+            self.environment.checkForError(
+                status,
+                "ObjectType_Initialize(): get schema name")
+            self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
+        finally:
+            lltype.free(nameptr, flavor='raw')
+            lltype.free(lenptr, flavor='raw')
+
+        # retrieve TDO (type descriptor object) of the parameter
+        tdorefptr = lltype.malloc(rffi.CArrayPtr(roci.OCIRef).TO, 1,
+                                  flavor='raw')
+        try:
+            status = roci.OCIAttrGet(
+                param, roci.OCI_HTYPE_DESCRIBE,
+                rffi.cast(roci.dvoidp, tdorefptr),
+                lltype.nullptr(roci.Ptr(roci.ub4).TO),
+                roci.OCI_ATTR_REF_TDO,
+                self.environment.errorHandle)
+            self.environment.checkForError(
+                status,
+                "ObjectType_Initialize(): get TDO reference")
+            tdoref = tdorefptr[0]
+        finally:
+            lltype.free(tdorefptr, flavor='raw')
+
+        tdoptr = lltype.malloc(rffi.CArrayPtr(roci.dvoidp).TO, 1,
+                               flavor='raw')
+        try:
+            status = roci.OCIObjectPin(
+                self.environment.handle,
+                self.environment.errorHandle,
+                tdoref,
+                None, roci.OCI_PIN_ANY,
+                roci.OCI_DURATION_SESSION, roci.OCI_LOCK_NONE,
+                tdoptr)
+            self.environment.checkForError(
+                status,
+                "ObjectType_Initialize(): pin TDO reference")
+            self.tdo = tdoptr[0]
+        finally:
+            lltype.free(tdoptr, flavor='raw')
+
+        # acquire a describe handle
+        handleptr = lltype.malloc(rffi.CArrayPtr(roci.OCIDescribe).TO,
+                                  1, flavor='raw')
+        try:
+            status = roci.OCIHandleAlloc(
+                self.environment.handle,
+                handleptr, roci.OCI_HTYPE_DESCRIBE, 0,
+                lltype.nullptr(rffi.CArray(roci.dvoidp)))
+            self.environment.checkForError(
+                status, "ObjectType_Initialize(): allocate describe handle")
+            describeHandle = handleptr[0]
+        finally:
+            lltype.free(handleptr, flavor='raw')
+
+        # describe the type
+        try:
+            pass
+            #self.describe(connection, describeHandle)
+        finally:
+            roci.OCIHandleFree(describeHandle, roci.OCI_HTYPE_DESCRIBE)
+W_ObjectType.typedef = TypeDef(
+    'ObjectType',
+    schema = interp_attrproperty('schema', W_ObjectType),
+    name = interp_attrproperty('name', W_ObjectType),
+    )
+
+class W_ExternalObject(Wrappable):
+    def __init__(self, ref, type, instance, indicator, isIndependent=True):
+        self.ref = ref
+        self.type = type
+        self.instance = instance
+        self.indicator = indicator
+        self.isIndependent = isIndependent
+W_ExternalObject.typedef = TypeDef(
+    'ExternalObject',
+    type = interp_attrproperty('type', W_ExternalObject),
+    )

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 16:03:53 2009
@@ -8,7 +8,8 @@
 from pypy.rlib.rarithmetic import ovfcheck
 
 import sys
-from pypy.module.oracle import roci, config, transform, interp_lob
+from pypy.module.oracle import roci, config, transform
+from pypy.module.oracle import interp_lob, interp_object
 from pypy.module.oracle.interp_error import W_Error, get
 from pypy.module.oracle.config import string_w, StringBuffer
 
@@ -111,7 +112,7 @@
         lltype.free(handleptr, flavor='raw')
 
     # call the procedure to set values after define
-    var.postDefine()
+    var.postDefine(param)
 
     return var
 
@@ -233,7 +234,7 @@
     def preDefine(cls, param, environment):
         return cls
 
-    def postDefine(self):
+    def postDefine(self, param):
         pass
 
     def bind(self, space, cursor, w_name, pos):
@@ -1126,8 +1127,79 @@
 
 
 class VT_Object(W_Variable):
+    oracleType = roci.SQLT_NTY
+    size = rffi.sizeof(roci.dvoidp)
     canBeInArray = False
 
+    objectIndicator = None
+
+    def initialize(self, space, cursor):
+        self.connection = cursor.connection
+        self.objectType = None
+        self.objectIndicator = lltype.malloc(
+            rffi.CArrayPtr(roci.dvoidp).TO,
+            self.allocatedElements,
+            flavor='raw', zero=True)
+
+    def finalize(self):
+        for i in range(self.allocatedElements):
+            data = rffi.cast(roci.Ptr(roci.dvoidp), self.data)
+            roci.OCIObjectFree(
+                self.environment.handle,
+                self.environment.errorHandle,
+                data[i],
+                roci.OCI_OBJECTFREE_FORCE)
+        if self.objectIndicator:
+            lltype.free(self.objectIndicator, flavor='raw')
+
+    def postDefine(self, param):
+        # XXX this used to be in preDefine
+        self.objectType = interp_object.W_ObjectType(self.connection, param)
+
+        data = rffi.cast(roci.Ptr(roci.dvoidp), self.data)
+
+        status = roci.OCIDefineObject(
+            self.defineHandle,
+            self.environment.errorHandle,
+            self.objectType.tdo,
+            data,
+            0,
+            self.objectIndicator,
+            0)
+        self.environment.checkForError(
+            status,
+            "ObjectVar_PostDefine(): define object")
+
+    def isNull(self, pos):
+        # look at our own indicator array
+        if not self.objectIndicator[pos]:
+            return True
+        return (rffi.cast(roci.Ptr(roci.OCIInd), self.objectIndicator[pos])[0]
+                ==
+                rffi.cast(lltype.Signed, roci.OCI_IND_NULL))
+
+    def getValueProc(self, space, pos):
+        data = rffi.cast(roci.Ptr(roci.dvoidp), self.data)
+        # only allowed to get the value once (for now)
+        if not data[pos]:
+            raise OperationError(
+                get(space).w_ProgrammingError,
+                space.wrap("variable value can only be acquired once"))
+
+
+        # for collections, return the list rather than the object
+        if self.objectType.isCollection:
+            return interp_object.convertCollection(
+                self.environment, data[pos], self, self.objectType)
+
+        # for objects, return a representation of the object
+        var = interp_object.W_ExternalObject(
+            self, self.objectType, data[pos], self.objectIndicator[pos])
+
+        data[pos] = lltype.nullptr(roci.dvoidp.TO)
+        self.objectIndicator[pos] = lltype.nullptr(roci.dvoidp.TO)
+        return space.wrap(var)
+
 all_variable_types = []
 for name, cls in globals().items():
     if not name.startswith('VT_') or not isinstance(cls, type):

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 16:03:53 2009
@@ -33,6 +33,9 @@
     uword = platform.SimpleType('uword', rffi.UINT)
     boolean = platform.SimpleType('boolean', rffi.UINT)
     OCIDuration = platform.SimpleType('OCIDuration', rffi.UINT)
+    OCIInd = platform.SimpleType('OCIInd', rffi.INT)
+    OCIPinOpt = platform.SimpleType('OCIPinOpt', rffi.INT)
+    OCILockOpt = platform.SimpleType('OCILockOpt', rffi.INT)
 
     OCINumber = platform.Struct('OCINumber', [])
     OCITime   = platform.Struct('OCITime',
@@ -57,12 +60,14 @@
     OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD
     OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT
     OCI_ATTR_NAME OCI_ATTR_SCALE OCI_ATTR_PRECISION OCI_ATTR_IS_NULL
-    OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_CHARSET_FORM
-    OCI_ATTR_ENV_CHARSET_ID
+    OCI_ATTR_DATA_SIZE OCI_ATTR_DATA_TYPE OCI_ATTR_REF_TDO
+    OCI_ATTR_SCHEMA_NAME OCI_ATTR_TYPE_NAME
+    OCI_ATTR_CHARSET_FORM OCI_ATTR_ENV_CHARSET_ID
     OCI_ATTR_PARSE_ERROR_OFFSET
     OCI_NTV_SYNTAX OCI_COMMIT_ON_SUCCESS
     OCI_FETCH_NEXT
     OCI_IND_NULL OCI_IND_NOTNULL
+    OCI_PIN_ANY OCI_LOCK_NONE
     OCI_STMT_SELECT OCI_STMT_CREATE OCI_STMT_DROP OCI_STMT_ALTER
     OCI_STMT_INSERT OCI_STMT_DELETE OCI_STMT_UPDATE
     SQLT_CHR SQLT_LNG SQLT_AFC SQLT_RDD SQLT_BIN SQLT_LBI SQLT_LVC SQLT_LVB
@@ -84,6 +89,7 @@
 OCI_IND_NOTNULL = rffi.cast(rffi.SHORT, OCI_IND_NOTNULL)
 OCI_IND_NULL = rffi.cast(rffi.SHORT, OCI_IND_NULL)
 
+# Various pointers to incomplete structures
 OCISvcCtx = rffi.VOIDP
 OCIEnv = rffi.VOIDP
 OCIError = rffi.VOIDP
@@ -93,10 +99,14 @@
 OCIParam = rffi.VOIDP
 OCIBind = rffi.VOIDP
 OCIDefine = rffi.VOIDP
+OCIDescribe = rffi.VOIDP
 OCISnapshot = rffi.VOIDP
 OCIDateTime = rffi.VOIDP
 OCIInterval = rffi.VOIDP
 OCILobLocator = rffi.VOIDP
+OCIRef = rffi.VOIDP
+OCIType = rffi.VOIDP
+OCIComplexObject = rffi.VOIDP
 
 Ptr = rffi.CArrayPtr
 void = lltype.Void
@@ -262,6 +272,17 @@
      ub4],           # mode
     sword)
 
+OCIDefineObject = external(
+    'OCIDefineObject',
+    [OCIDefine,      # defnp
+     OCIError,       # errhp
+     OCIType,        # type
+     dvoidpp,        # pgvpp
+     ub4,            # pvszsp
+     dvoidpp,        # indpp
+     ub4],           # indszp
+    sword)
+
 OCIStmtGetBindInfo = external(
     'OCIStmtGetBindInfo',
     [OCIStmt,        # stmtp
@@ -422,6 +443,20 @@
      ub4],        # type
     sword)
 
+# OCI Object Pin, Unpin, and Free Functions
+
+OCIObjectPin = external(
+    'OCIObjectPin',
+    [OCIEnv,           # env,
+     OCIError,         # err
+     OCIRef,           # object_ref
+     OCIComplexObject, # corhdl
+     OCIPinOpt,        # pin_option
+     OCIDuration,      # pin_duration
+     OCILockOpt,       # lock_option
+     dvoidpp],         # object
+    sword)
+
 # OCI Date, Datetime, and Interval Functions
 
 OCIDateTimeCheck = external(

Added: pypy/trunk/pypy/module/oracle/test/test_objectvar.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/oracle/test/test_objectvar.py	Wed Nov 25 16:03:53 2009
@@ -0,0 +1,34 @@
+from pypy.module.oracle.test.test_connect import OracleTestBase
+
+class AppTestObjectVar(OracleTestBase):
+    def test_fetch(self):
+        cur = self.cnx.cursor()
+        try:
+            cur.execute("drop table pypy_test_objtable")
+        except oracle.DatabaseError:
+            pass
+        try:
+            cur.execute("drop type pypy_test_objtype")
+        except oracle.DatabaseError:
+            pass
+        cur.execute("""\
+            create type pypy_test_objtype as object (
+                numbercol number,
+                stringcol varchar2(60),
+                datecol   date);
+            """)
+        cur.execute("""\
+            create table pypy_test_objtable (
+                objcol pypy_test_objtype)
+            """)
+        cur.execute("""\
+            insert into pypy_test_objtable values (
+            pypy_test_objtype(1, 'someText',
+                              to_date(20070306, 'YYYYMMDD')))
+            """)
+
+        cur.execute("select objcol from pypy_test_objtable")
+        objValue, = cur.fetchone()
+        assert objValue.type.schema == self.cnx.username.upper()
+        assert objValue.type.name == "PYPY_TEST_OBJTYPE"
+        #assert objValue.type.attributes[0].name == "NUMBERVALUE"



More information about the Pypy-commit mailing list