コード例 #1
0
    def _performDefine(self):
        # determine number of items in select-list
        attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO,
                                1, flavor='raw')
        try:
            status = roci.OCIAttrGet(
                self.handle, roci.OCI_HTYPE_STMT,
                rffi.cast(roci.dvoidp, attrptr),
                lltype.nullptr(roci.Ptr(roci.ub4).TO),
                roci.OCI_ATTR_PARAM_COUNT,
                self.environment.errorHandle)

            self.environment.checkForError(
                status, "Cursor_PerformDefine()")
            numParams = attrptr[0]
        finally:
            lltype.free(attrptr, flavor='raw')

        self.fetchVariables = []

        # define a variable for each select-item
        self.fetchArraySize = self.arraySize
        for i in range(numParams):
            var = interp_variable.define(self, i+1, self.fetchArraySize)
            assert isinstance(var, interp_variable.W_Variable)
            self.fetchVariables.append(var)
コード例 #2
0
ファイル: interp_cursor.py プロジェクト: njues/Sypy
    def _internalFetch(self, space, numRows):
        if not self.fetchVariables:
            raise OperationError(
                get(space).w_InterfaceError, space.wrap("query not executed"))

        status = roci.OCIStmtFetch(self.handle, self.environment.errorHandle,
                                   numRows, roci.OCI_FETCH_NEXT,
                                   roci.OCI_DEFAULT)

        if status != roci.OCI_NO_DATA:
            self.environment.checkForError(status,
                                           "Cursor_InternalFetch(): fetch")

        for var in self.fetchVariables:
            assert isinstance(var, interp_variable.W_Variable)
            var.internalFetchNum += 1

        attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
        try:
            status = roci.OCIAttrGet(self.handle, roci.OCI_HTYPE_STMT,
                                     rffi.cast(roci.dvoidp, attrptr),
                                     lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                     roci.OCI_ATTR_ROW_COUNT,
                                     self.environment.errorHandle)

            self.environment.checkForError(
                status, "Cursor_InternalFetch(): row count")

            self.actualRows = (rffi.cast(lltype.Signed, attrptr[0]) -
                               self.rowCount)
            self.rowNum = 0
        finally:
            lltype.free(attrptr, flavor='raw')
コード例 #3
0
ファイル: interp_cursor.py プロジェクト: njues/Sypy
    def getDescription(self, space):
        "Return a list of 7-tuples consisting of the description of "
        "the define variables"

        # make sure the cursor is open
        self._checkOpen(space)

        # fixup bound cursor, if necessary
        self._fixupBoundCursor()

        # if not a query, return None
        if self.statementType != roci.OCI_STMT_SELECT:
            return

        # determine number of items in select-list
        attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub1).TO, 1, flavor='raw')
        try:
            status = roci.OCIAttrGet(self.handle, roci.OCI_HTYPE_STMT,
                                     rffi.cast(roci.dvoidp, attrptr),
                                     lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                     roci.OCI_ATTR_PARAM_COUNT,
                                     self.environment.errorHandle)
            self.environment.checkForError(status, "Cursor_GetDescription()")
            numItems = attrptr[0]
        finally:
            lltype.free(attrptr, flavor='raw')

        return space.newlist([
            space.newtuple(self._itemDescription(space, i + 1))
            for i in range(numItems)
        ])
コード例 #4
0
    def _setRowCount(self):
        if self.statementType == roci.OCI_STMT_SELECT:
            self.rowCount = 0
            self.actualRows = -1
            self.rowNum = 0
        elif self.statementType in (roci.OCI_STMT_INSERT,
                                    roci.OCI_STMT_UPDATE,
                                    roci.OCI_STMT_DELETE):
            attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO,
                                    1, flavor='raw')
            try:
                status = roci.OCIAttrGet(
                    self.handle, roci.OCI_HTYPE_STMT,
                    rffi.cast(roci.dvoidp, attrptr),
                    lltype.nullptr(roci.Ptr(roci.ub4).TO),
                    roci.OCI_ATTR_ROW_COUNT,
                    self.environment.errorHandle)

                self.environment.checkForError(
                    status, "Cursor_SetRowCount()")
                self.rowCount = rffi.cast(lltype.Signed, attrptr[0])
            finally:
                lltype.free(attrptr, flavor='raw')
        else:
            self.rowCount = -1
コード例 #5
0
    def initialize(self, connection, param):
        # determine the name of the attribute
        nameptr = lltype.malloc(rffi.CArrayPtr(roci.oratext).TO, 1,
                                flavor='raw')
        lenptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1,
                               flavor='raw')
        try:
            status = roci.OCIAttrGet(
                param, roci.OCI_DTYPE_PARAM,
                rffi.cast(roci.dvoidp, nameptr),
                lenptr,
                roci.OCI_ATTR_NAME,
                connection.environment.errorHandle)
            connection.environment.checkForError(
                status,
                "ObjectAttribute_Initialize(): get name")
            self.name = rffi.charpsize2str(nameptr[0], lenptr[0])
        finally:
            lltype.free(nameptr, flavor='raw')
            lltype.free(lenptr, flavor='raw')

        # determine the type of the attribute
        typecodeptr = lltype.malloc(roci.Ptr(roci.OCITypeCode).TO,
                                    1, flavor='raw')
        try:
            status = roci.OCIAttrGet(
                param, roci.OCI_DTYPE_PARAM,
                rffi.cast(roci.dvoidp, typecodeptr),
                lltype.nullptr(roci.Ptr(roci.ub4).TO),
                roci.OCI_ATTR_TYPECODE,
                connection.environment.errorHandle)
            connection.environment.checkForError(
                status, "ObjectType_Describe(): get type code")
            self.typeCode = rffi.cast(lltype.Signed, typecodeptr[0])
        finally:
            lltype.free(typecodeptr, flavor='raw')

        # if the type of the attribute is object, recurse
        if self.typeCode in (roci.OCI_TYPECODE_NAMEDCOLLECTION,
                             roci.OCI_TYPECODE_OBJECT):
            self.subType = W_ObjectType(connection, param)
        else:
            self.subType = None
コード例 #6
0
 def _setErrorOffset(self, space, e):
     if e.match(space, get(space).w_DatabaseError):
         attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
         try:
             status = roci.OCIAttrGet(
                 self.handle, roci.OCI_HTYPE_STMT,
                 rffi.cast(roci.dvoidp, attrptr),
                 lltype.nullptr(roci.Ptr(roci.ub4).TO),
                 roci.OCI_ATTR_PARSE_ERROR_OFFSET,
                 self.environment.errorHandle)
             e.offset = attrptr[0]
         finally:
             lltype.free(attrptr, flavor='raw')
コード例 #7
0
ファイル: interp_cursor.py プロジェクト: njues/Sypy
    def _getStatementType(self):
        attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO, 1, flavor='raw')
        try:
            status = roci.OCIAttrGet(self.handle, roci.OCI_HTYPE_STMT,
                                     rffi.cast(roci.dvoidp, attrptr),
                                     lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                     roci.OCI_ATTR_STMT_TYPE,
                                     self.environment.errorHandle)

            self.environment.checkForError(status, "Cursor_GetStatementType()")
            self.statementType = rffi.cast(lltype.Signed, attrptr[0])
        finally:
            lltype.free(attrptr, flavor='raw')

        self.fetchVariables = None
コード例 #8
0
    def fget(self, space):
        self.checkConnected(space)

        valueptr = lltype.malloc(rffi.CArrayPtr(oci_value_type).TO,
                                 1,
                                 flavor='raw')
        try:
            status = roci.OCIAttrGet(self.handle, roci.OCI_HTYPE_SPOOL,
                                     rffi.cast(roci.dvoidp, valueptr),
                                     lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                     oci_attr_code,
                                     self.environment.errorHandle)
            return space.wrap(valueptr[0])
        finally:
            lltype.free(valueptr, flavor='raw')
コード例 #9
0
    def _getCharacterSetName(self, space, attribute):
        # get character set id
        charsetIdPtr = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO,
                                     1,
                                     flavor='raw')
        try:
            status = roci.OCIAttrGet(self.environment.handle,
                                     roci.OCI_HTYPE_ENV,
                                     rffi.cast(roci.dvoidp, charsetIdPtr),
                                     lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                     attribute, self.environment.errorHandle)
            self.environment.checkForError(
                status, "Connection_GetCharacterSetName(): get charset id")
            charsetId = charsetIdPtr[0]
        finally:
            lltype.free(charsetIdPtr, flavor='raw')

        # get character set name
        charsetname_buf, charsetname = rffi.alloc_buffer(roci.OCI_NLS_MAXBUFSZ)
        try:
            status = roci.OCINlsCharSetIdToName(self.environment.handle,
                                                charsetname_buf,
                                                roci.OCI_NLS_MAXBUFSZ,
                                                charsetId)
            self.environment.checkForError(
                status,
                "Connection_GetCharacterSetName(): get Oracle charset name")

            ianacharset_buf, ianacharset = rffi.alloc_buffer(
                roci.OCI_NLS_MAXBUFSZ)

            try:
                # get IANA character set name
                status = roci.OCINlsNameMap(self.environment.handle,
                                            ianacharset_buf,
                                            roci.OCI_NLS_MAXBUFSZ,
                                            charsetname_buf,
                                            roci.OCI_NLS_CS_ORA_TO_IANA)
                self.environment.checkForError(
                    status,
                    "Connection_GetCharacterSetName(): translate NLS charset")
                charset = rffi.charp2str(ianacharset_buf)
            finally:
                rffi.keep_buffer_alive_until_here(ianacharset_buf, ianacharset)
        finally:
            rffi.keep_buffer_alive_until_here(charsetname_buf, charsetname)
        return space.wrap(charset)
コード例 #10
0
ファイル: interp_cursor.py プロジェクト: njues/Sypy
    def _itemDescription(self, space, pos):
        "Return a tuple describing the item at the given position"

        # acquire parameter descriptor
        paramptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO, 1, flavor='raw')
        try:
            status = roci.OCIParamGet(self.handle, roci.OCI_HTYPE_STMT,
                                      self.environment.errorHandle,
                                      rffi.cast(roci.dvoidpp, paramptr), pos)
            self.environment.checkForError(
                status, "Cursor_GetDescription(): parameter")
            param = paramptr[0]
        finally:
            lltype.free(paramptr, flavor='raw')

        try:
            # acquire usable type of item
            varType = interp_variable.typeByOracleDescriptor(
                param, self.environment)

            # acquire internal size of item
            attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO,
                                    1,
                                    flavor='raw')
            try:
                status = roci.OCIAttrGet(param, roci.OCI_HTYPE_DESCRIBE,
                                         rffi.cast(roci.dvoidp, attrptr),
                                         lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                         roci.OCI_ATTR_DATA_SIZE,
                                         self.environment.errorHandle)
                self.environment.checkForError(
                    status, "Cursor_ItemDescription(): internal size")
                internalSize = rffi.cast(lltype.Signed, attrptr[0])
            finally:
                lltype.free(attrptr, flavor='raw')

            # acquire name of item
            nameptr = lltype.malloc(rffi.CArrayPtr(roci.oratext).TO,
                                    1,
                                    flavor='raw')
            lenptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO,
                                   1,
                                   flavor='raw')
            try:
                status = roci.OCIAttrGet(param, roci.OCI_HTYPE_DESCRIBE,
                                         rffi.cast(roci.dvoidp, nameptr),
                                         lenptr, roci.OCI_ATTR_NAME,
                                         self.environment.errorHandle)
                self.environment.checkForError(
                    status, "Cursor_ItemDescription(): name")
                name = rffi.charpsize2str(nameptr[0],
                                          rffi.cast(lltype.Signed, lenptr[0]))
            finally:
                lltype.free(nameptr, flavor='raw')
                lltype.free(lenptr, flavor='raw')

            # lookup precision and scale
            if varType is interp_variable.VT_Float:
                attrptr = lltype.malloc(rffi.CArrayPtr(roci.sb1).TO,
                                        1,
                                        flavor='raw')
                try:
                    status = roci.OCIAttrGet(
                        param, roci.OCI_HTYPE_DESCRIBE,
                        rffi.cast(roci.dvoidp, attrptr),
                        lltype.nullptr(roci.Ptr(roci.ub4).TO),
                        roci.OCI_ATTR_SCALE, self.environment.errorHandle)
                    self.environment.checkForError(
                        status, "Cursor_ItemDescription(): scale")
                    scale = rffi.cast(lltype.Signed, attrptr[0])
                finally:
                    lltype.free(attrptr, flavor='raw')

                attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO,
                                        1,
                                        flavor='raw')
                try:
                    status = roci.OCIAttrGet(
                        param, roci.OCI_HTYPE_DESCRIBE,
                        rffi.cast(roci.dvoidp, attrptr),
                        lltype.nullptr(roci.Ptr(roci.ub4).TO),
                        roci.OCI_ATTR_PRECISION, self.environment.errorHandle)
                    self.environment.checkForError(
                        status, "Cursor_ItemDescription(): precision")
                    precision = rffi.cast(lltype.Signed, attrptr[0])
                finally:
                    lltype.free(attrptr, flavor='raw')
            else:
                scale = 0
                precision = 0

            # lookup whether null is permitted for the attribute
            attrptr = lltype.malloc(rffi.CArrayPtr(roci.ub1).TO,
                                    1,
                                    flavor='raw')
            try:
                status = roci.OCIAttrGet(param, roci.OCI_HTYPE_DESCRIBE,
                                         rffi.cast(roci.dvoidp, attrptr),
                                         lltype.nullptr(roci.Ptr(roci.ub4).TO),
                                         roci.OCI_ATTR_IS_NULL,
                                         self.environment.errorHandle)
                self.environment.checkForError(
                    status, "Cursor_ItemDescription(): nullable")
                nullable = rffi.cast(lltype.Signed, attrptr[0]) != 0
            finally:
                lltype.free(attrptr, flavor='raw')

            # set display size based on data type
            if varType is interp_variable.VT_String:
                displaySize = internalSize
            elif varType is interp_variable.VT_NationalCharString:
                displaySize = internalSize / 2
            elif varType is interp_variable.VT_Binary:
                displaySize = internalSize
            elif varType is interp_variable.VT_FixedChar:
                displaySize = internalSize
            elif varType is interp_variable.VT_FixedNationalChar:
                displaySize = internalSize / 2
            elif varType is interp_variable.VT_Float:
                if precision:
                    displaySize = precision + 1
                    if scale > 0:
                        displaySize += scale + 1
                else:
                    displaySize = 127
            elif varType is interp_variable.VT_DateTime:
                displaySize = 23
            else:
                displaySize = -1

            # return the tuple
            return [
                space.wrap(name),
                space.gettypeobject(varType.typedef),
                space.wrap(displaySize),
                space.wrap(internalSize),
                space.wrap(precision),
                space.wrap(scale),
                space.wrap(nullable)
            ]

        finally:
            roci.OCIDescriptorFree(param, roci.OCI_DTYPE_PARAM)
コード例 #11
0
    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:
            self.describe(connection, describeHandle)
        finally:
            roci.OCIHandleFree(describeHandle, roci.OCI_HTYPE_DESCRIBE)
コード例 #12
0
    def describe(self, connection, describeHandle):
        "Describe the type and store information about it as needed"

        # describe the type
        status = roci.OCIDescribeAny(
            connection.handle,
            self.environment.errorHandle,
            self.tdo, 0,
            roci.OCI_OTYPE_PTR,
            roci.OCI_DEFAULT,
            roci.OCI_PTYPE_TYPE,
            describeHandle)
        self.environment.checkForError(
            status, "ObjectType_Describe(): describe type")

        # get top level parameter descriptor
        paramptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO,
                                 1, flavor='raw')
        try:
            status = roci.OCIAttrGet(
                describeHandle, roci.OCI_HTYPE_DESCRIBE,
                rffi.cast(roci.dvoidp, paramptr),
                lltype.nullptr(roci.Ptr(roci.ub4).TO),
                roci.OCI_ATTR_PARAM,
                self.environment.errorHandle)
            self.environment.checkForError(
                status,
                "ObjectType_Describe(): get top level parameter descriptor")
            toplevelParam = paramptr[0]
        finally:
            lltype.free(paramptr, flavor='raw')

        # determine type of type
        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 type code")
            typeCode = rffi.cast(lltype.Signed, typecodeptr[0])
        finally:
            lltype.free(typecodeptr, flavor='raw')

        # if a collection, need to determine the sub type
        if typeCode == roci.OCI_TYPECODE_NAMEDCOLLECTION:
            self.isCollection = 1

            # determine type of collection
            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
            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
            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 = rffi.cast(lltype.Signed, typecodeptr[0])
            finally:
                lltype.free(typecodeptr, flavor='raw')

            # if element type is an object type get its type
            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,
                               1, flavor='raw')
        try:
            status = roci.OCIAttrGet(
                toplevelParam, roci.OCI_DTYPE_PARAM,
                rffi.cast(roci.dvoidp, numptr),
                lltype.nullptr(roci.Ptr(roci.ub4).TO),
                roci.OCI_ATTR_NUM_TYPE_ATTRS,
                self.environment.errorHandle)
            self.environment.checkForError(
                status, "ObjectType_Describe(): get number of attributes")
            numAttributes = numptr[0]
        finally:
            lltype.free(numptr, flavor='raw')

        # allocate the attribute list and dictionary
        self.attributes = []
        self.attributesByName = {}

        # acquire the list parameter descriptor
        listptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO,
                               1, flavor='raw')
        try:
            status = roci.OCIAttrGet(
                toplevelParam, roci.OCI_DTYPE_PARAM,
                rffi.cast(roci.dvoidp, listptr),
                lltype.nullptr(roci.Ptr(roci.ub4).TO),
                roci.OCI_ATTR_LIST_TYPE_ATTRS,
                self.environment.errorHandle)
            self.environment.checkForError(
                status, "ObjectType_Describe(): get list parameter descriptor")
            attributeListParam = listptr[0]
        finally:
            lltype.free(listptr, flavor='raw')

        # create attribute information for each attribute
        for i in range(numAttributes):
            paramptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO,
                                    1, flavor='raw')
            try:
                status = roci.OCIParamGet(
                    attributeListParam, roci.OCI_DTYPE_PARAM,
                    self.environment.errorHandle,
                    paramptr, i + 1)
                self.environment.checkForError(
                    status,
                    "ObjectType_Describe(): get attribute param descriptor")
                attribute = W_ObjectAttribute(connection, paramptr[0])
            finally:
                lltype.free(paramptr, flavor='raw')

            self.attributes.append(attribute)
            self.attributesByName[attribute.name] = attribute