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

afa at codespeak.net afa at codespeak.net
Wed Nov 25 12:08:05 CET 2009


Author: afa
Date: Wed Nov 25 12:08:04 2009
New Revision: 69630

Added:
   pypy/trunk/pypy/module/oracle/interp_lob.py
   pypy/trunk/pypy/module/oracle/test/test_lobvar.py
Modified:
   pypy/trunk/pypy/module/oracle/__init__.py
   pypy/trunk/pypy/module/oracle/interp_variable.py
   pypy/trunk/pypy/module/oracle/roci.py
Log:
Start to implement BLOB variables


Modified: pypy/trunk/pypy/module/oracle/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/oracle/__init__.py	(original)
+++ pypy/trunk/pypy/module/oracle/__init__.py	Wed Nov 25 12:08:04 2009
@@ -17,6 +17,7 @@
         'LONG_BINARY': 'interp_variable.VT_LongBinary',
         'FIXED_CHAR': 'interp_variable.VT_FixedChar',
         'CURSOR': 'interp_variable.VT_Cursor',
+        'BLOB': 'interp_variable.VT_BLOB',
         'Variable': 'interp_variable.W_Variable',
         'Timestamp': 'interp_error.get(space).w_DateTimeType',
         'Date': 'interp_error.get(space).w_DateType',

Added: pypy/trunk/pypy/module/oracle/interp_lob.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/oracle/interp_lob.py	Wed Nov 25 12:08:04 2009
@@ -0,0 +1,34 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.gateway import ObjSpace
+from pypy.interpreter.gateway import interp2app
+
+class W_ExternalLob(Wrappable):
+    def __init__(self, var, pos):
+        self.lobVar = var
+        self.pos = pos
+        self.internalFetchNum = var.internalFetchNum
+
+    def _verify(self, space):
+        if self.internalFetchNum != self.lobVar.internalFetchNum:
+            raise OperationError(
+                get(space).w_ProgrammingError,
+                space.wrap(
+                    "LOB variable no longer valid after subsequent fetch"))
+
+    def read(self, space, offset=-1, amount=-1):
+        self._verify(space)
+        return self.lobVar.read(space, self.pos, offset, amount)
+    read.unwrap_spec=['self', ObjSpace, int, int]
+
+    def desc_str(self, space):
+        return self.read(space, offset=1, amount=-1)
+    desc_str.unwrap_spec=['self', ObjSpace]
+
+W_ExternalLob.typedef = TypeDef(
+    'ExternalLob',
+    read = interp2app(W_ExternalLob.read,
+                      unwrap_spec=W_ExternalLob.read.unwrap_spec),
+    __str__ = interp2app(W_ExternalLob.desc_str,
+                         unwrap_spec=W_ExternalLob.desc_str.unwrap_spec),
+    )

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 12:08:04 2009
@@ -8,7 +8,7 @@
 from pypy.rlib.rarithmetic import ovfcheck
 
 import sys
-from pypy.module.oracle import roci, config, transform
+from pypy.module.oracle import roci, config, transform, interp_lob
 from pypy.module.oracle.interp_error import W_Error, get
 from pypy.module.oracle.config import string_w, StringBuffer
 
@@ -914,18 +914,165 @@
         self.environment.checkForError(
             status, "IntervalVar_SetValue()")
 
+class W_LobVariable(W_VariableWithDescriptor):
+    descriptorType = roci.OCI_DTYPE_LOB
+    descriptionText = "LobVar"
+    temporaryLobType = roci.OCI_TEMP_CLOB
 
-class VT_CLOB(W_Variable):
-    pass
+    def initialize(self, space, cursor):
+        super(W_LobVariable, self).initialize(space, cursor)
+        self.connection = cursor.connection
 
-class VT_NCLOB(W_Variable):
-    pass
+    def ensureTemporary(self, space, pos):
+        # make sure we have a temporary LOB set up
+        temporaryptr = lltype.malloc(rffi.CArrayPtr(roci.boolean).TO, 1, flavor='raw')
+        try:
+            status = roci.OCILobIsTemporary(
+                self.environment.handle,
+                self.environment.errorHandle,
+                self.getDataptr(pos)[0],
+                temporaryptr);
+            self.environment.checkForError(
+                status,
+                "LobVar_SetValue(): check temporary")
+            temporary = temporaryptr[0]
+        finally:
+            lltype.free(temporaryptr, flavor='raw')
 
-class VT_BLOB(W_Variable):
-    pass
+        if temporary:
+            return
 
-class VT_BFILE(W_Variable):
-    pass
+        status = roci.OCILobCreateTemporary(
+            self.connection.handle,
+            self.environment.errorHandle,
+            self.getDataptr(pos)[0],
+            roci.OCI_DEFAULT,
+            roci.OCI_DEFAULT,
+            self.temporaryLobType,
+            False,
+            roci.OCI_DURATION_SESSION)
+        self.environment.checkForError(
+            status,
+            "LobVar_SetValue(): create temporary")
+
+
+    def setValueProc(self, space, pos, w_value):
+        self.ensureTemporary(space, pos)
+
+        # trim the current value
+        status = roci.OCILobTrim(
+            self.connection.handle,
+            self.environment.errorHandle,
+            self.getDataptr(pos)[0],
+            0)
+        self.environment.checkForError(
+            status,
+            "LobVar_SetValue(): trim")
+
+        # set the value
+        self.write(space, pos, w_value, 1)
+
+    def getLength(self, space, pos):
+        "Return the size of the LOB variable for internal comsumption."
+        lengthptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
+        try:
+            status = roci.OCILobGetLength(
+                self.connection.handle,
+                self.environment.errorHandle,
+                self.getDataptr(pos)[0],
+                lengthptr)
+            self.environment.checkForError(
+                status,
+                "LobVar_GetLength()")
+            return int(lengthptr[0]) # XXX test overflow
+        finally:
+            lltype.free(lengthptr, flavor='raw')
+
+    def read(self, space, pos, offset, amount):
+        # modify the arguments
+        if offset <= 0:
+            offset = 1
+        if amount < 0:
+            amount = self.getLength(space, pos) - offset + 1
+            if amount <= 0:
+                amount = 1
+
+        bufferSize = amount
+        raw_buffer, gc_buffer = rffi.alloc_buffer(bufferSize)
+        amountptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
+        amountptr[0] = rffi.cast(roci.ub4, amount)
+        try:
+            status = roci.OCILobRead(
+                self.connection.handle,
+                self.environment.errorHandle,
+                self.getDataptr(pos)[0],
+                amountptr, offset,
+                raw_buffer, bufferSize,
+                None, None,
+                config.CHARSETID, self.charsetForm)
+            self.environment.checkForError(
+                status,
+                "LobVar_Read()")
+            amount = int(amountptr[0]) # XXX test overflow
+            value = rffi.str_from_buffer(raw_buffer, gc_buffer, bufferSize, amount)
+            return space.wrap(value)
+        finally:
+            lltype.free(amountptr, flavor='raw')
+            rffi.keep_buffer_alive_until_here(raw_buffer, gc_buffer)
+
+    def write(self, space, pos, w_value, offset):
+        databuf = config.StringBuffer()
+        databuf.fill(space, w_value)
+        amountptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
+        amountptr[0] = rffi.cast(roci.ub4, databuf.size)
+
+        try:
+            status = roci.OCILobWrite(
+                self.connection.handle,
+                self.environment.errorHandle,
+                self.getDataptr(pos)[0],
+                amountptr, offset,
+                databuf.ptr, databuf.size,
+                roci.OCI_ONE_PIECE,
+                None, None,
+                config.CHARSETID, self.charsetForm)
+            self.environment.checkForError(
+                status,
+                "LobVar_Write()")
+            amount = amountptr[0]
+        finally:
+            lltype.free(amountptr, flavor='raw')
+            databuf.clear()
+
+        return amount
+
+    def getValueProc(self, space, pos):
+        return space.wrap(interp_lob.W_ExternalLob(self, pos))
+
+class VT_CLOB(W_LobVariable):
+    oracleType = roci.SQLT_CLOB
+
+class VT_NCLOB(W_LobVariable):
+    oracleType = roci.SQLT_CLOB
+
+class VT_BLOB(W_LobVariable):
+    oracleType = roci.SQLT_BLOB
+    temporaryLobType = roci.OCI_TEMP_BLOB
+
+class VT_BFILE(W_LobVariable):
+    oracleType = roci.SQLT_BFILE
+
+    def write(self, space, pos, w_value, offset):
+        raise OperationError(
+            space.w_TypeError,
+            space.wrap("BFILEs are read only"))
+
+    def read(self, space, pos, offset, amount):
+        self.fileOpen()
+        try:
+            return W_LobVariable.read(self, space, pos, offset, amount)
+        finally:
+            self.fileClose()
 
 class VT_Cursor(W_Variable):
     oracleType = roci.SQLT_RSET

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 12:08:04 2009
@@ -31,6 +31,8 @@
     sb4 = platform.SimpleType('sb4', rffi.INT)
     sword = platform.SimpleType('sword', rffi.INT)
     uword = platform.SimpleType('uword', rffi.UINT)
+    boolean = platform.SimpleType('boolean', rffi.UINT)
+    OCIDuration = platform.SimpleType('OCIDuration', rffi.UINT)
 
     OCINumber = platform.Struct('OCINumber', [])
     OCITime   = platform.Struct('OCITime',
@@ -50,7 +52,7 @@
     OCI_SUCCESS OCI_SUCCESS_WITH_INFO OCI_INVALID_HANDLE OCI_NO_DATA
     OCI_HTYPE_ERROR OCI_HTYPE_SVCCTX OCI_HTYPE_SERVER OCI_HTYPE_SESSION
     OCI_HTYPE_STMT OCI_HTYPE_DESCRIBE OCI_HTYPE_ENV
-    OCI_DTYPE_PARAM OCI_DTYPE_TIMESTAMP OCI_DTYPE_INTERVAL_DS
+    OCI_DTYPE_PARAM OCI_DTYPE_TIMESTAMP OCI_DTYPE_INTERVAL_DS OCI_DTYPE_LOB
     OCI_CRED_RDBMS OCI_CRED_EXT OCI_SPOOL_ATTRVAL_NOWAIT
     OCI_ATTR_SERVER OCI_ATTR_SESSION OCI_ATTR_USERNAME OCI_ATTR_PASSWORD
     OCI_ATTR_STMT_TYPE OCI_ATTR_PARAM_COUNT OCI_ATTR_ROW_COUNT
@@ -69,6 +71,7 @@
     SQLT_TIMESTAMP_TZ SQLT_TIMESTAMP_LTZ SQLT_INTERVAL_DS
     SQLT_CLOB SQLT_CLOB SQLT_BLOB SQLT_BFILE SQLT_RSET SQLT_NTY
     SQLCS_IMPLICIT SQLCS_NCHAR
+    OCI_TEMP_CLOB OCI_TEMP_BLOB OCI_DURATION_SESSION OCI_ONE_PIECE
     OCI_NUMBER_SIGNED
     OCI_NLS_MAXBUFSZ OCI_NLS_CS_ORA_TO_IANA
     '''.split()
@@ -93,13 +96,14 @@
 OCISnapshot = rffi.VOIDP
 OCIDateTime = rffi.VOIDP
 OCIInterval = rffi.VOIDP
+OCILobLocator = rffi.VOIDP
 
+Ptr = rffi.CArrayPtr
 void = lltype.Void
 dvoidp = rffi.VOIDP
 dvoidpp = rffi.VOIDPP
 size_t = rffi.SIZE_T
 oratext = rffi.CCHARP
-Ptr = rffi.CArrayPtr
 
 def external(name, args, result):
     return rffi.llexternal(name, args, result, compilation_info=eci)
@@ -318,6 +322,77 @@
      ub4],         # mode
     sword)
 
+# LOB Functions
+
+OCILobCreateTemporary = external(
+    'OCILobCreateTemporary',
+    [OCISvcCtx,     # svchp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     ub2,           # csid
+     ub1,           # csfrm
+     ub1,           # lobtype
+     boolean,       # cache
+     OCIDuration],  # duration
+    sword)
+
+OCILobGetLength = external(
+    'OCILobGetLength',
+    [OCIEnv,        # envhp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     Ptr(ub4)],     # lenp
+    sword)
+
+OCILobIsTemporary = external(
+    'OCILobIsTemporary',
+    [OCIEnv,        # envhp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     Ptr(boolean)], # is_temporary
+    sword)
+
+OCICallbackLobRead = dvoidp
+OCILobRead = external(
+    'OCILobRead',
+    [OCISvcCtx,     # svchp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     Ptr(ub4),      # amtp
+     ub4,           # offset
+     dvoidp,        # bufp
+     ub4,           # buflen
+     dvoidp,        # ctxp
+     OCICallbackLobRead, # cbfp
+     ub2,           # csid
+     ub1],          # csfrm
+    sword)
+
+OCILobTrim = external(
+    'OCILobTrim',
+    [OCISvcCtx,     # svchp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     ub4],          # newlen
+    sword)
+
+OCICallbackLobWrite = dvoidp
+OCILobWrite = external(
+    'OCILobWrite',
+    [OCISvcCtx,     # svchp
+     OCIError,      # errhp
+     OCILobLocator, # locp
+     Ptr(ub4),      # amtp
+     ub4,           # offset
+     dvoidp,        # bufp
+     ub4,           # buflen
+     ub1,           # piece
+     dvoidp,        # ctxp
+     OCICallbackLobWrite, # cbfp
+     ub2,           # csid
+     ub1],          # csfrm
+    sword)
+
 # Transaction Functions
 
 OCITransCommit = external(

Added: pypy/trunk/pypy/module/oracle/test/test_lobvar.py
==============================================================================
--- (empty file)
+++ pypy/trunk/pypy/module/oracle/test/test_lobvar.py	Wed Nov 25 12:08:04 2009
@@ -0,0 +1,33 @@
+from pypy.module.oracle.test.test_connect import OracleTestBase
+
+class LobTests(object):
+    @classmethod
+    def setup_class(cls):
+        super(LobTests, cls).setup_class()
+        cls.w_lobType = cls.space.wrap(cls.lobType)
+
+    def test_bind(self):
+        inputType = getattr(oracle, self.lobType)
+
+        cur = self.cnx.cursor()
+        try:
+            cur.execute("drop table pypy_temp_lobtable")
+        except oracle.DatabaseError:
+            pass
+        cur.execute("create table pypy_temp_lobtable "
+                    "(lobcol %s)" % self.lobType)
+
+        longString = ""
+        for i in range(2):
+            if i > 0:
+                longString += chr(65+i) * 25000
+
+        cur.setinputsizes(lob=inputType)
+        cur.execute("insert into pypy_temp_lobtable values (:lob)",
+                    lob=longString)
+        cur.execute("select lobcol from pypy_temp_lobtable")
+        lob, = cur.fetchone()
+        assert lob.read() == longString
+
+class AppTestLob(LobTests, OracleTestBase):
+    lobType = "BLOB"



More information about the Pypy-commit mailing list