[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