/pypy/module/oracle/interp_variable.py
Python | 1561 lines | 1439 code | 81 blank | 41 comment | 74 complexity | e82adcd54aa2416548ba131794d4ad97 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- from pypy.interpreter.baseobjspace import Wrappable
- from pypy.interpreter.typedef import TypeDef
- from pypy.interpreter.typedef import interp_attrproperty
- from pypy.interpreter.gateway import interp2app, unwrap_spec
- from pypy.interpreter.error import OperationError
- from pypy.rpython.lltypesystem import rffi, lltype
- from pypy.rlib.rarithmetic import ovfcheck
- import sys
- 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
- def define(cursor, position, numElements):
- paramptr = lltype.malloc(roci.Ptr(roci.OCIParam).TO, 1, flavor='raw')
- try:
- status = roci.OCIParamGet(
- cursor.handle, roci.OCI_HTYPE_STMT,
- cursor.environment.errorHandle,
- paramptr, position)
- cursor.environment.checkForError(
- status,
- "Variable_Define(): parameter")
- param = paramptr[0]
- finally:
- lltype.free(paramptr, flavor='raw')
- # call the helper to do the actual work
- var = _defineHelper(cursor, param, position, numElements)
- roci.OCIDescriptorFree(param, roci.OCI_DTYPE_PARAM)
- return var
- def _defineHelper(cursor, param, position, numElements):
- # determine data type
- varType = typeByOracleDescriptor(param, cursor.environment)
- if cursor.numbersAsStrings and varType is VT_Float:
- varType = VT_NumberAsString
- # retrieve size of the parameter
- size = varType.size
- if varType.isVariableLength:
- # determine the maximum length from Oracle
- 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,
- cursor.environment.errorHandle)
- cursor.environment.checkForError(
- status, "Variable_Define(): data size")
- sizeFromOracle = rffi.cast(lltype.Signed, attrptr[0])
- finally:
- lltype.free(attrptr, flavor='raw')
- # use the length from Oracle directly if available
- if sizeFromOracle:
- size = rffi.cast(lltype.Signed, sizeFromOracle)
- # otherwise, use the value set with the setoutputsize() parameter
- elif cursor.outputSize >= 0:
- if (cursor.outputSizeColumn < 0 or
- position == cursor.outputSizeColumn):
- size = cursor.outputSize
- # call the procedure to set values prior to define
- varType2 = varType.preDefine(varType, param, cursor.environment)
- # create a variable of the correct type
- if 0 and cursor.w_outputTypeHandler: # XXX
- var = newByOutputTypeHandler(
- cursor, param,
- cursor.w_outputTypeHandler,
- varType2, size, numElements)
- elif 0 and cursor.connection.w_outputTypeHandler: # XXX
- var = newByOutputTypeHandler(
- cursor, param,
- cursor.connection.w_outputTypeHandler,
- varType2, size, numElements)
- else:
- var = varType2(cursor, numElements, size)
- assert isinstance(var, W_Variable)
- # perform the define
- handleptr = lltype.malloc(roci.Ptr(roci.OCIDefine).TO, 1, flavor='raw')
- try:
- status = roci.OCIDefineByPos(
- cursor.handle,
- handleptr,
- var.environment.errorHandle,
- position,
- var.data, var.bufferSize,
- var.oracleType,
- rffi.cast(roci.dvoidp, var.indicator),
- var.actualLength,
- var.returnCode,
- roci.OCI_DEFAULT)
- var.environment.checkForError(
- status,
- "Variable_Define(): define")
- var.defineHandle = handleptr[0]
- finally:
- lltype.free(handleptr, flavor='raw')
- # call the procedure to set values after define
- var.postDefine(param)
- return var
- class W_Variable(Wrappable):
- charsetForm = roci.SQLCS_IMPLICIT
- isVariableLength = False
- canBeInArray = True
- def __init__(self, cursor, numElements, size=0):
- self.environment = cursor.environment
- self.boundCursorHandle = lltype.nullptr(roci.OCIStmt.TO)
- self.boundName = None
- self.boundPos = 0
- self.isArray = False
- self.actualElementsPtr = lltype.malloc(roci.Ptr(roci.ub4).TO, 1,
- zero=True, flavor='raw')
- if numElements < 1:
- self.allocatedElements = 1
- else:
- self.allocatedElements = numElements
- self.internalFetchNum = 0
- self.actualLength = lltype.nullptr(rffi.CArrayPtr(roci.ub2).TO)
- self.returnCode = lltype.nullptr(rffi.CArrayPtr(roci.ub2).TO)
- # set the maximum length of the variable, ensure that a minimum of
- # 2 bytes is allocated to ensure that the array size check works
- if self.isVariableLength:
- size = max(size, rffi.sizeof(roci.ub2))
- if self.size != size:
- self.size = size
- # allocate the data for the variable
- self.allocateData(self.environment.space)
- # allocate the indicator for the variable
- self.indicator = lltype.malloc(rffi.CArrayPtr(roci.sb2).TO,
- self.allocatedElements,
- flavor='raw', zero=True)
- # ensure that all variable values start out NULL
- for i in range(self.allocatedElements):
- self.indicator[i] = rffi.cast(roci.sb2, roci.OCI_IND_NULL)
- # for variable length data, also allocate the return code
- if self.isVariableLength:
- self.returnCode = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO,
- self.allocatedElements,
- flavor='raw', zero=True)
- # perform extended initialization
- self.initialize(self.environment.space, cursor)
- def __del__(self):
- self.enqueue_for_destruction(self.environment.space,
- W_Variable.destructor,
- '__del__ method of ')
- def destructor(self):
- assert isinstance(self, W_Variable)
- self.finalize()
- lltype.free(self.actualElementsPtr, flavor='raw')
- if self.actualLength:
- lltype.free(self.actualLength, flavor='raw')
- if self.data:
- lltype.free(self.data, flavor='raw')
- if self.returnCode:
- lltype.free(self.returnCode, flavor='raw')
- if self.indicator:
- lltype.free(self.indicator, flavor='raw')
- def getBufferSize(self):
- return self.size
- def allocateData(self, space):
- # set the buffer size for the variable
- self.bufferSize = self.getBufferSize()
- # allocate the data as long as it is small enough
- try:
- dataLength = ovfcheck(self.allocatedElements * self.bufferSize)
- except OverflowError:
- too_large = True
- else:
- too_large = False
- if too_large or dataLength >= roci.INT_MAX:
- raise OperationError(
- space.w_ValueError,
- space.wrap("array size too large"))
- self.data = lltype.malloc(rffi.CCHARP.TO, int(dataLength),
- flavor='raw', zero=True)
- def resize(self, space, size):
- # allocate the data for the new array
- orig_data = self.data
- orig_size = self.bufferSize
- self.size = size
- self.allocateData(space)
- # copy the data from the original array to the new array
- for i in range(self.allocatedElements):
- for j in range(orig_size):
- self.data[self.bufferSize * i + j] = \
- orig_data[orig_size * i + j]
- lltype.free(orig_data, flavor='raw')
- # force rebinding
- if self.boundName or self.boundPos:
- self._internalBind(space)
- def makeArray(self, space):
- if not self.canBeInArray:
- raise OperationError(
- get(space).w_NotSupportedError,
- space.wrap(
- "Variable_MakeArray(): type does not support arrays"))
- self.isArray = True
- def initialize(self, space, cursor):
- pass
- def finalize(self):
- pass
- @staticmethod
- def preDefine(cls, param, environment):
- return cls
- def postDefine(self, param):
- pass
- def bind(self, space, cursor, w_name, pos):
- # nothing to do if already bound
- if (cursor.handle == self.boundCursorHandle and
- w_name == self.w_boundName and pos == self.boundPos):
- return
- # set the instance variables specific for binding
- self.boundCursorHandle = cursor.handle
- self.boundPos = pos
- self.w_boundName = w_name
- # perform the bind
- self._internalBind(space)
- def _internalBind(self, space):
- bindHandlePtr = lltype.malloc(roci.Ptr(roci.OCIBind).TO, 1,
- flavor='raw')
- if self.isArray:
- allocatedElements = self.allocatedElements
- actualElementsPtr = self.actualElementsPtr
- else:
- allocatedElements = 0
- actualElementsPtr = lltype.nullptr(roci.Ptr(roci.ub4).TO)
- try:
- if self.w_boundName:
- nameBuffer = config.StringBuffer()
- nameBuffer.fill(space, self.w_boundName)
- status = roci.OCIBindByName(
- self.boundCursorHandle, bindHandlePtr,
- self.environment.errorHandle,
- nameBuffer.ptr, nameBuffer.size,
- self.data, self.bufferSize,
- self.oracleType,
- rffi.cast(roci.dvoidp, self.indicator),
- self.actualLength, self.returnCode,
- allocatedElements, actualElementsPtr,
- roci.OCI_DEFAULT)
- nameBuffer.clear()
- else:
- status = roci.OCIBindByPos(
- self.boundCursorHandle, bindHandlePtr,
- self.environment.errorHandle,
- self.boundPos,
- self.data, self.bufferSize,
- self.oracleType,
- rffi.cast(roci.dvoidp, self.indicator),
- self.actualLength, self.returnCode,
- allocatedElements, actualElementsPtr,
- roci.OCI_DEFAULT)
- self.environment.checkForError(
- status, "NumberVar_InternalBind()")
- self.bindHandle = bindHandlePtr[0]
- finally:
- lltype.free(bindHandlePtr, flavor='raw')
- # set the charset form and id if applicable
- if self.charsetForm != roci.SQLCS_IMPLICIT:
- charsetformptr = lltype.malloc(roci.Ptr(roci.ub1).TO, 1,
- zero=True, flavor='raw')
- charsetformptr[0] = rffi.cast(roci.ub1, self.charsetForm)
- try:
- status = roci.OCIAttrSet(
- self.bindHandle, roci.OCI_HTYPE_BIND,
- rffi.cast(roci.dvoidp, charsetformptr), 0,
- roci.OCI_ATTR_CHARSET_FORM,
- self.environment.errorHandle)
- self.environment.checkForError(
- status, "NumberVar_InternalBind(): set charset form")
- finally:
- lltype.free(charsetformptr, flavor='raw')
- charsetidptr = lltype.malloc(roci.Ptr(roci.ub2).TO, 1,
- zero=True, flavor='raw')
- charsetidptr[0] = rffi.cast(roci.ub2, roci.OCI_UTF16ID)
- try:
- status = roci.OCIAttrSet(
- self.bindHandle, roci.OCI_HTYPE_BIND,
- rffi.cast(roci.dvoidp, charsetidptr), 0,
- roci.OCI_ATTR_CHARSET_ID,
- self.environment.errorHandle)
- self.environment.checkForError(
- status, "NumberVar_InternalBind(): set charset Id")
- finally:
- lltype.free(charsetidptr, flavor='raw')
- # set the max data size for strings
- buffersizeptr = lltype.malloc(roci.Ptr(roci.ub4).TO, 1,
- zero=True, flavor='raw')
- buffersizeptr[0] = rffi.cast(roci.ub4, self.size)
- try:
- status = roci.OCIAttrSet(
- self.bindHandle, roci.OCI_HTYPE_BIND,
- rffi.cast(roci.dvoidp, buffersizeptr), 0,
- roci.OCI_ATTR_MAXDATA_SIZE,
- self.environment.errorHandle)
- self.environment.checkForError(
- status, "NumberVar_InternalBind(): set max data size")
- finally:
- lltype.free(buffersizeptr, flavor='raw')
- def isNull(self, pos):
- return (rffi.cast(lltype.Signed, self.indicator[pos])
- ==
- rffi.cast(lltype.Signed, roci.OCI_IND_NULL))
- def verifyFetch(self, space, pos):
- # Verifies that truncation or other problems did not take place on
- # retrieve.
- if self.isVariableLength:
- error_code = rffi.cast(lltype.Signed, self.returnCode[pos])
- if error_code != 0:
- error = W_Error(space, self.environment,
- "Variable_VerifyFetch()", 0)
- error.code = error_code
- error.message = space.wrap(
- "column at array pos %d fetched with error: %d" %
- (pos, error_code))
- w_error = get(space).w_DatabaseError
- raise OperationError(get(space).w_DatabaseError,
- space.wrap(error))
- def getSingleValue(self, space, pos):
- # ensure we do not exceed the number of allocated elements
- if pos >= self.allocatedElements:
- raise OperationError(
- space.w_IndexError,
- space.wrap("Variable_GetSingleValue: array size exceeded"))
- # check for a NULL value
- if self.isNull(pos):
- return space.wrap(None)
- # check for truncation or other problems on retrieve
- self.verifyFetch(space, pos)
- # calculate value to return
- value = self.getValueProc(space, pos)
- # XXX outConverter
- return value
- def getArrayValue(self, space, numElements):
- return space.newlist(
- [self.getSingleValue(space, i)
- for i in range(numElements)])
- @unwrap_spec(pos=int)
- def getValue(self, space, pos=0):
- if self.isArray:
- return self.getArrayValue(space, self.actualElementsPtr[0])
- return self.getSingleValue(space, pos)
- def setSingleValue(self, space, pos, w_value):
- # ensure we do not exceed the number of allocated elements
- if pos >= self.allocatedElements:
- raise OperationError(
- space.w_IndexError,
- space.wrap("Variable_SetSingleValue: array size exceeded"))
- # convert value, if necessary
- # XXX inConverter
- # check for a NULL value
- if space.is_w(w_value, space.w_None):
- self.indicator[pos] = roci.OCI_IND_NULL
- return
- self.indicator[pos] = roci.OCI_IND_NOTNULL
- if self.isVariableLength:
- self.returnCode[pos] = rffi.cast(roci.ub2, 0)
- self.setValueProc(space, pos, w_value)
- def setArrayValue(self, space, w_value):
- # ensure we have an array to set
- if not space.is_true(space.isinstance(w_value, space.w_list)):
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting array data"))
- elements_w = space.listview(w_value)
- # ensure we haven't exceeded the number of allocated elements
- if len(elements_w) > self.allocatedElements:
- raise OperationError(
- space.w_IndexError,
- space.wrap("Variable_SetArrayValue: array size exceeded"))
- # set all of the values
- self.actualElementsPtr[0] = rffi.cast(roci.ub4, len(elements_w))
- for i in range(len(elements_w)):
- self.setSingleValue(space, i, elements_w[i])
- @unwrap_spec(pos=int)
- def setValue(self, space, pos, w_value):
- if self.isArray:
- self.setArrayValue(space, w_value)
- else:
- self.setSingleValue(space, pos, w_value)
- W_Variable.typedef = TypeDef(
- 'Variable',
- getvalue = interp2app(W_Variable.getValue),
- setvalue = interp2app(W_Variable.setValue),
- maxlength = interp_attrproperty('bufferSize', W_Variable),
- bufferSize = interp_attrproperty('bufferSize', W_Variable),
- size = interp_attrproperty('size', W_Variable),
- )
- class VT_String(W_Variable):
- oracleType = roci.SQLT_CHR
- size = config.MAX_STRING_CHARS
- isVariableLength = True
- def getBufferSize(self):
- if config.WITH_UNICODE:
- return self.size * BYTES_PER_CHAR
- else:
- if self.charsetForm == roci.SQLCS_IMPLICIT:
- return self.size * self.environment.maxBytesPerCharacter
- else:
- return self.size * 2
- def initialize(self, space, cursor):
- self.actualLength = lltype.malloc(rffi.CArrayPtr(roci.ub2).TO,
- self.allocatedElements,
- zero=True, flavor='raw')
- def getValueProc(self, space, pos):
- offset = pos * self.bufferSize
- dataptr = rffi.ptradd(self.data, offset)
- length = rffi.cast(lltype.Signed, self.actualLength[pos])
- i = 0
- if config.WITH_UNICODE:
- if isinstance(self, VT_Binary):
- return space.wrap(rffi.charpsize2str(dataptr, length))
- else:
- l = []
- while i < length:
- l.append(unichr((ord(dataptr[i + 1]) << 8) +
- ord(dataptr[i])))
- i += 2
- return space.wrap(u''.join(l))
- else:
- if self.charsetForm == roci.SQLCS_IMPLICIT:
- return space.wrap(rffi.charpsize2str(dataptr, length))
- else:
- l = []
- while i < length:
- l.append(unichr((ord(dataptr[i + 1]) << 8) +
- ord(dataptr[i])))
- i += 2
- return space.wrap(u''.join(l))
- def setValueProc(self, space, pos, w_value):
- if config.WITH_UNICODE:
- wantBytes = not self.isCharacterData
- else:
- wantBytes = self.charsetForm == roci.SQLCS_IMPLICIT
- if wantBytes:
- if space.is_true(space.isinstance(w_value, space.w_str)):
- buf = config.StringBuffer()
- buf.fill(space, w_value)
- size = buf.size
- else:
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting string or buffer data"))
- else:
- if space.is_true(space.isinstance(w_value, space.w_unicode)):
- buf = config.StringBuffer()
- buf.fill_with_unicode(space, w_value)
- size = buf.size
- else:
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting unicode data"))
- try:
- if wantBytes:
- if buf.size > self.environment.maxStringBytes:
- raise OperationError(
- space.w_ValueError,
- space.wrap("string data too large"))
- else:
- if buf.size > config.MAX_STRING_CHARS * 2:
- raise OperationError(
- space.w_ValueError,
- space.wrap("unicode data too large"))
- # ensure that the buffer is large enough
- if buf.size > self.bufferSize:
- self.resize(space, size)
- # keep a copy of the string
- self.actualLength[pos] = rffi.cast(roci.ub2, buf.size)
- offset = pos * self.bufferSize
- for index in range(buf.size):
- self.data[offset + index] = buf.ptr[index]
- finally:
- buf.clear()
- class VT_FixedChar(VT_String):
- oracleType = roci.SQLT_AFC
- size = 2000
- class VT_NationalCharString(VT_String):
- charsetForm = roci.SQLCS_NCHAR
- def postDefine(self, param):
- charsetformptr = lltype.malloc(roci.Ptr(roci.ub1).TO, 1,
- zero=True, flavor='raw')
- charsetformptr[0] = rffi.cast(roci.ub1, self.charsetForm)
- try:
- status = roci.OCIAttrSet(
- self.defineHandle, roci.OCI_HTYPE_DEFINE,
- rffi.cast(roci.dvoidp, charsetformptr), 0,
- roci.OCI_ATTR_CHARSET_FORM,
- self.environment.errorHandle)
- self.environment.checkForError(
- status, "StringVar_PostDefine(): set charset form")
- finally:
- lltype.free(charsetformptr, flavor='raw')
- charsetidptr = lltype.malloc(roci.Ptr(roci.ub2).TO, 1,
- zero=True, flavor='raw')
- charsetidptr[0] = rffi.cast(roci.ub2, roci.OCI_UTF16ID)
- try:
- status = roci.OCIAttrSet(
- self.defineHandle, roci.OCI_HTYPE_DEFINE,
- rffi.cast(roci.dvoidp, charsetidptr), 0,
- roci.OCI_ATTR_CHARSET_ID,
- self.environment.errorHandle)
- self.environment.checkForError(
- status, "StringVar_PostDefine(): set charset Id")
- finally:
- lltype.free(charsetidptr, flavor='raw')
- class VT_FixedNationalChar(VT_NationalCharString):
- oracleType = roci.SQLT_AFC
- size = 2000
- class VT_LongString(W_Variable):
- oracleType = roci.SQLT_LVC
- isVariableLength = True
- size = 128 * 1024
- def getBufferSize(self):
- return self.size + rffi.sizeof(roci.ub4)
- def getValueProc(self, space, pos):
- ptr = rffi.ptradd(self.data, pos * self.bufferSize)
- length = rffi.cast(roci.Ptr(roci.ub4), ptr)[0]
- length = rffi.cast(lltype.Signed, length)
- ptr = rffi.ptradd(ptr, rffi.sizeof(roci.ub4))
- return space.wrap(rffi.charpsize2str(ptr, length))
- def setValueProc(self, space, pos, w_value):
- buf = config.StringBuffer()
- buf.fill(space, w_value)
- try:
- # ensure that the buffer is large enough
- if buf.size + rffi.sizeof(roci.ub4) > self.bufferSize:
- self.resize(space, buf.size + rffi.sizeof(roci.ub4))
- # copy the string to the Oracle buffer
- ptr = rffi.ptradd(self.data, pos * self.bufferSize)
- rffi.cast(roci.Ptr(roci.ub4), ptr)[0] = rffi.cast(roci.ub4, buf.size)
- for index in range(buf.size):
- ptr[index + rffi.sizeof(roci.ub4)] = buf.ptr[index]
- finally:
- buf.clear()
- class VT_Rowid(VT_String):
- oracleType = roci.SQLT_CHR
- size = 18
- isVariableLength = False
- class VT_Binary(VT_String):
- oracleType = roci.SQLT_BIN
- size = config.MAX_BINARY_BYTES
- class VT_LongBinary(VT_LongString):
- oracleType = roci.SQLT_LVB
- class VT_NativeFloat(W_Variable):
- pass
- class VT_Float(W_Variable):
- oracleType = roci.SQLT_VNU
- size = rffi.sizeof(roci.OCINumber)
- @staticmethod
- def preDefine(cls, param, environment):
- # if the return type has not already been specified, check to
- # see if the number can fit inside an integer by looking at
- # the precision and scale
- if cls is 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,
- environment.errorHandle)
- environment.checkForError(
- status,
- "NumberVar_PreDefine(): 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,
- environment.errorHandle)
- environment.checkForError(
- status,
- "NumberVar_PreDefine(): precision")
- precision = rffi.cast(lltype.Signed, attrptr[0])
- finally:
- lltype.free(attrptr, flavor='raw')
- if scale == 0 or (scale == -127 and precision == 0):
- if precision > 0 and precision < 10:
- return VT_Integer
- else:
- return VT_LongInteger
- return cls
- def getValueProc(self, space, pos):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCINumber), self.data),
- pos)
- if isinstance(self, VT_Integer):
- integerValuePtr = lltype.malloc(roci.Ptr(lltype.Signed).TO, 1,
- flavor='raw')
- try:
- status = roci.OCINumberToInt(
- self.environment.errorHandle,
- dataptr,
- rffi.sizeof(rffi.LONG),
- roci.OCI_NUMBER_SIGNED,
- rffi.cast(roci.dvoidp, integerValuePtr))
- self.environment.checkForError(
- status, "NumberVar_GetValue(): as integer")
- if isinstance(self, VT_Boolean):
- return space.newbool(bool(integerValuePtr[0]))
- else:
- return space.wrap(integerValuePtr[0])
- finally:
- lltype.free(integerValuePtr, flavor='raw')
- elif isinstance(self, VT_NumberAsString) or isinstance(self, VT_LongInteger):
- format_buf = config.StringBuffer()
- format_buf.fill(space, space.wrap("TM9"))
- sizeptr = lltype.malloc(rffi.CArray(roci.ub4), 1, flavor='raw')
- BUFSIZE = 200
- sizeptr[0] = rffi.cast(roci.ub4, BUFSIZE)
- textbuf, text = rffi.alloc_buffer(BUFSIZE)
- try:
- status = roci.OCINumberToText(
- self.environment.errorHandle,
- dataptr,
- format_buf.ptr, format_buf.size,
- None, 0,
- sizeptr, textbuf);
- self.environment.checkForError(
- status, "NumberVar_GetValue(): as string")
- w_strvalue = space.wrap(
- rffi.str_from_buffer(textbuf, text,
- BUFSIZE,
- rffi.cast(lltype.Signed, sizeptr[0])))
- finally:
- rffi.keep_buffer_alive_until_here(textbuf, text)
- lltype.free(sizeptr, flavor='raw')
- format_buf.clear()
- if isinstance(self, VT_NumberAsString):
- return w_strvalue
- try:
- return space.call_function(space.w_int, w_strvalue)
- except OperationError, e:
- if e.match(space, space.w_ValueError):
- return space.call_function(space.w_float, w_strvalue)
- raise
- else:
- return transform.OracleNumberToPythonFloat(
- self.environment, dataptr)
- def setValueProc(self, space, pos, w_value):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCINumber), self.data),
- pos)
- if space.is_true(space.isinstance(w_value, space.w_int)):
- integerValuePtr = lltype.malloc(roci.Ptr(lltype.Signed).TO, 1,
- flavor='raw')
- try:
- integerValuePtr[0] = space.int_w(w_value)
- status = roci.OCINumberFromInt(
- self.environment.errorHandle,
- rffi.cast(roci.dvoidp, integerValuePtr),
- rffi.sizeof(lltype.Signed),
- roci.OCI_NUMBER_SIGNED,
- dataptr)
- self.environment.checkForError(
- status, "NumberVar_SetValue(): from integer")
- finally:
- lltype.free(integerValuePtr, flavor='raw')
- return
- elif space.is_true(space.isinstance(w_value, space.w_long)):
- text_buf = config.StringBuffer()
- text_buf.fill(space, space.str(w_value))
- format_buf = config.StringBuffer()
- format_buf.fill(space, space.wrap("9" * 63))
- status = roci.OCINumberFromText(
- self.environment.errorHandle,
- text_buf.ptr, text_buf.size,
- format_buf.ptr, format_buf.size,
- None, 0,
- dataptr)
- text_buf.clear()
- format_buf.clear()
- self.environment.checkForError(
- status, "NumberVar_SetValue(): from long")
- return
- # XXX The bool case was already processed above
- elif space.is_true(space.isinstance(w_value, space.w_float)):
- doubleValuePtr = lltype.malloc(roci.Ptr(lltype.Float).TO, 1,
- flavor='raw')
- try:
- doubleValuePtr[0] = space.float_w(w_value)
- status = roci.OCINumberFromReal(
- self.environment.errorHandle,
- rffi.cast(roci.dvoidp, doubleValuePtr),
- rffi.sizeof(lltype.Float),
- dataptr)
- self.environment.checkForError(
- status, "NumberVar_SetValue(): from float")
- finally:
- lltype.free(doubleValuePtr, flavor='raw')
- return
- elif space.is_true(space.isinstance(w_value, get(space).w_DecimalType)):
- w_text, w_format = transform.DecimalToFormatAndText(self.environment, w_value)
- text_buf = config.StringBuffer()
- text_buf.fill(space, w_text)
- format_buf = config.StringBuffer()
- format_buf.fill(space, w_format)
- nls_params = "NLS_NUMERIC_CHARACTERS='.,'"
- status = roci.OCINumberFromText(
- self.environment.errorHandle,
- text_buf.ptr, text_buf.size,
- format_buf.ptr, format_buf.size,
- nls_params, len(nls_params),
- dataptr)
- text_buf.clear()
- format_buf.clear()
- self.environment.checkForError(
- status, "NumberVar_SetValue(): from decimal")
- return
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting numeric data"))
- class VT_Integer(VT_Float):
- pass
- class VT_Boolean(VT_Integer):
- pass
- class VT_NumberAsString(VT_Float):
- pass
- class VT_LongInteger(VT_Float):
- pass
- class VT_DateTime(W_Variable):
- oracleType = roci.SQLT_ODT
- size = rffi.sizeof(roci.OCIDate)
- def getValueProc(self, space, pos):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCIDate), self.data),
- pos)
- return transform.OracleDateToPythonDateTime(self.environment, dataptr)
- def setValueProc(self, space, pos, w_value):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCIDate), self.data),
- pos)
- if space.is_true(space.isinstance(w_value, get(space).w_DateTimeType)):
- year = space.int_w(space.getattr(w_value, space.wrap('year')))
- month = space.int_w(space.getattr(w_value, space.wrap('month')))
- day = space.int_w(space.getattr(w_value, space.wrap('day')))
- hour = space.int_w(space.getattr(w_value, space.wrap('hour')))
- minute = space.int_w(space.getattr(w_value, space.wrap('minute')))
- second = space.int_w(space.getattr(w_value, space.wrap('second')))
- elif space.is_true(space.isinstance(w_value, get(space).w_DateType)):
- year = space.int_w(space.getattr(w_value, space.wrap('year')))
- month = space.int_w(space.getattr(w_value, space.wrap('month')))
- day = space.int_w(space.getattr(w_value, space.wrap('day')))
- hour = minute = second = 0
- else:
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting date data"))
- # store a copy of the value
- value = dataptr[0]
- timePart = value.c_OCIDateTime
- rffi.setintfield(timePart, 'c_OCITimeHH', hour)
- rffi.setintfield(timePart, 'c_OCITimeMI', minute)
- rffi.setintfield(timePart, 'c_OCITimeSS', second)
- rffi.setintfield(dataptr[0], 'c_OCIDateYYYY', year)
- rffi.setintfield(dataptr[0], 'c_OCIDateMM', month)
- rffi.setintfield(dataptr[0], 'c_OCIDateDD', day)
- class VT_Date(VT_DateTime):
- oracleType = roci.SQLT_ODT
- size = rffi.sizeof(roci.OCIDate)
- def getValueProc(self, space, pos):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCIDate), self.data),
- pos)
- return transform.OracleDateToPythonDate(self.environment, dataptr)
- class W_VariableWithDescriptor(W_Variable):
- size = rffi.sizeof(roci.dvoidp)
- def initialize(self, space, cursor):
- # initialize the descriptors
- for i in range(self.allocatedElements):
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.dvoidp), self.data),
- i)
- status = roci.OCIDescriptorAlloc(
- self.environment.handle,
- dataptr,
- self.descriptorType,
- 0, None)
- self.environment.checkForError(
- status, self.descriptionText + "_Initialize()")
- def finalize(self):
- dataptr = rffi.cast(roci.Ptr(roci.dvoidp), self.data)
- for i in range(self.allocatedElements):
- if dataptr[i]:
- roci.OCIDescriptorFree(
- dataptr[i], self.descriptorType)
- def getDataptr(self, pos):
- return rffi.ptradd(
- rffi.cast(roci.Ptr(roci.dvoidp), self.data),
- pos)
- class VT_Timestamp(W_VariableWithDescriptor):
- oracleType = roci.SQLT_TIMESTAMP
- descriptorType = roci.OCI_DTYPE_TIMESTAMP
- descriptionText = "TimestampVar"
- def getValueProc(self, space, pos):
- return transform.OracleTimestampToPythonDate(
- self.environment, self.getDataptr(pos))
- def setValueProc(self, space, pos, w_value):
- # make sure a timestamp is being bound
- if not space.is_true(space.isinstance(w_value, get(space).w_DateTimeType)):
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting timestamp data"))
- year = space.int_w(space.getattr(w_value, space.wrap('year')))
- month = space.int_w(space.getattr(w_value, space.wrap('month')))
- day = space.int_w(space.getattr(w_value, space.wrap('day')))
- hour = space.int_w(space.getattr(w_value, space.wrap('hour')))
- minute = space.int_w(space.getattr(w_value, space.wrap('minute')))
- second = space.int_w(space.getattr(w_value, space.wrap('second')))
- microsecond = space.int_w(space.getattr(w_value, space.wrap('microsecond')))
- status = roci.OCIDateTimeConstruct(
- self.environment.handle,
- self.environment.errorHandle,
- self.getDataptr(pos)[0],
- year, month, day, hour, minute, second, microsecond * 1000,
- None, 0)
- self.environment.checkForError(
- status, "TimestampVar_SetValue(): create structure")
- validptr = lltype.malloc(rffi.CArrayPtr(roci.ub4).TO, 1, flavor='raw')
- try:
- status = roci.OCIDateTimeCheck(
- self.environment.handle,
- self.environment.errorHandle,
- self.getDataptr(pos)[0],
- validptr);
- self.environment.checkForError(
- status,
- "TimestampVar_SetValue()")
- valid = rffi.cast(lltype.Signed, validptr[0])
- finally:
- lltype.free(validptr, flavor='raw')
- if valid != 0:
- raise OperationError(
- get(space).w_DataError,
- space.wrap("invalid date"))
- class VT_Interval(W_VariableWithDescriptor):
- oracleType = roci.SQLT_INTERVAL_DS
- descriptorType = roci.OCI_DTYPE_INTERVAL_DS
- descriptionText = "TimestampVar"
- def getValueProc(self, space, pos):
- return transform.OracleIntervalToPythonDelta(
- self.environment, self.getDataptr(pos))
- def setValueProc(self, space, pos, w_value):
- if not space.is_true(space.isinstance(w_value,
- get(space).w_TimedeltaType)):
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting timedelta data"))
- days = space.int_w(space.getattr(w_value, space.wrap('days')))
- seconds = space.int_w(space.getattr(w_value, space.wrap('seconds')))
- hours = seconds / 3600
- seconds -= hours * 3600
- minutes = seconds / 60
- seconds -= minutes * 60
- microseconds = space.int_w(
- space.getattr(w_value, space.wrap('microseconds')))
- status = roci.OCIIntervalSetDaySecond(
- self.environment.handle,
- self.environment.errorHandle,
- days, hours, minutes, seconds, microseconds,
- self.getDataptr(pos)[0])
- self.environment.checkForError(
- status, "IntervalVar_SetValue()")
- class W_LobVariable(W_VariableWithDescriptor):
- descriptorType = roci.OCI_DTYPE_LOB
- descriptionText = "LobVar"
- temporaryLobType = roci.OCI_TEMP_CLOB
- def initialize(self, space, cursor):
- W_VariableWithDescriptor.initialize(self, space, cursor)
- self.connection = cursor.connection
- 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 = rffi.cast(lltype.Signed, temporaryptr[0])
- finally:
- lltype.free(temporaryptr, flavor='raw')
- if temporary:
- return
- 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)
- self.trim(space, pos, 0)
- 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 rffi.cast(lltype.Signed,
- lengthptr[0]) # XXX test overflow
- finally:
- lltype.free(lengthptr, flavor='raw')
- def trim(self, space, pos, newSize):
- status = roci.OCILobTrim(
- self.connection.handle,
- self.environment.errorHandle,
- self.getDataptr(pos)[0],
- newSize)
- self.environment.checkForError(
- status,
- "LobVar_Trim()")
- 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 = rffi.cast(lltype.Signed,
- 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:
- # nothing to do if no data to write
- if databuf.size == 0:
- return 0
- 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.openFile()
- try:
- return W_LobVariable.read(self, space, pos, offset, amount)
- finally:
- self.closeFile()
- def openFile(self):
- pass # XXX
- def closeFile(self):
- pass # XXX
- class VT_Cursor(W_Variable):
- oracleType = roci.SQLT_RSET
- size = rffi.sizeof(roci.OCIStmt)
- canBeInArray = False
- def initialize(self, space, cursor):
- from pypy.module.oracle import interp_cursor
- self.connection = cursor.connection
- self.cursors_w = [None] * self.allocatedElements
- for i in range(self.allocatedElements):
- tempCursor = interp_cursor.W_Cursor(space, self.connection)
- tempCursor.allocateHandle()
- self.cursors_w[i] = space.wrap(tempCursor)
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCIStmt), self.data),
- i)
- dataptr[0] = tempCursor.handle
- def getValueProc(self, space, pos):
- from pypy.module.oracle import interp_cursor
- w_cursor = self.cursors_w[pos]
- space.interp_w(interp_cursor.W_Cursor, w_cursor).statementType = -1
- return w_cursor
- def setValueProc(self, space, pos, w_value):
- from pypy.module.oracle import interp_cursor
- w_CursorType = space.gettypeobject(interp_cursor.W_Cursor.typedef)
- if not space.is_true(space.isinstance(w_value, w_CursorType)):
- raise OperationError(
- space.w_TypeError,
- space.wrap("expecting cursor"))
- self.cursors_w[pos] = w_value
- cursor = space.interp_w(interp_cursor.W_Cursor, w_value)
- if not cursor.isOwned:
- cursor.freeHandle(space, raiseError=True)
- cursor.isOwned = True
- cursor.allocateHandle()
- dataptr = rffi.ptradd(
- rffi.cast(roci.Ptr(roci.OCIStmt), self.data),
- pos)
- dataptr[0] = cursor.handle
- cursor.statementType = -1
- class VT_Object(W_Variable):
- oracleType = roci.SQLT_NTY
- size = rffi.sizeof(roci.dvoidp)
- canBeInArray = False
- objectIndicator = lltype.nullptr(rffi.CArrayPtr(roci.dvoidp).TO)
- 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(lltype.Signed,
- 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(
- space, 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):
- continue
- def register_variable_class(cls):
- def clone(self, cursor, numElements, size):
- return cls(cursor, numElements, size)
- cls.clone = clone
- cls.typedef = TypeDef(
- cls.__name__, W_Variable.typedef,
- )
- all_variable_types.append(cls)
- register_variable_class(cls)
- def typeByOracleDescriptor(param, environment):
- # retrieve datatype of the parameter
- 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_TYPE,
- environment.errorHandle)
- environment.checkForError(
- status,
- "Variable_TypeByOracleDescriptor(): data type")
- dataType = rffi.cast(lltype.Signed, attrptr[0])
- finally:
- lltype.free(attrptr, flavor='raw')
- # retrieve character set form of the parameter
- if dataType not in (roci.SQLT_CHR, roci.SQLT_AFC,…
Large files files are truncated, but you can click here to view the full file