[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