def get_value(self, var, pos): """Returns the value stored at the given array position.""" if not python3_or_better(): types = (vt_Boolean, vt_Integer) else: types = (vt_Boolean,) typed_data = self.get_typed_data(var) if var.type in types: c_integer_value = ctypes.c_long() status = oci.OCINumberToInt( var.environment.error_handle, byref(typed_data[pos]), ctypes.sizeof(c_integer_value), oci.OCI_NUMBER_SIGNED, byref(c_integer_value), ) integer_value = c_integer_value.value var.environment.check_for_error(status, "NumberVar_GetValue(): as integer") if not python3_or_better(): if var.type is vt_Integer: return integer_value return bool(integer_value) if var.type in (vt_NumberAsString, vt_LongInteger): c_string = ctypes.create_string_buffer(200) cast_c_string = ctypes.cast(c_string, oci.POINTER(oci.ub1)) c_string_length = oci.ub4() c_string_length.value = ctypes.sizeof(c_string) typed_data = self.get_typed_data(var) status = oci.OCINumberToText( var.environment.error_handle, byref(typed_data[pos]), var.environment.numberToStringFormatBuffer.cast_ptr, var.environment.numberToStringFormatBuffer.size, None, 0, byref(c_string_length), cast_c_string, ) var.environment.check_for_error(status, "NumberVar_GetValue(): as string") python_string = c_string.value unicode_str = cxString_from_encoded_string(python_string, var.environment.encoding) if var.type is vt_NumberAsString: return unicode_str try: return int(unicode_str) except ValueError: pass return oracle_number_to_python_float(var.environment, byref(typed_data[pos]))
def set_max_data_size(self): if (self.type == vt_String or self.type == vt_FixedChar) and self.size > self.type.size: c_size = oci.ub4() status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.type.size = c_size.value self.environment.check_for_error(status, "Variable_InternalBind(): set max data size")
def get_value(self, var, pos): """Returns the value stored at the given array position.""" if not python3_or_better(): types = (vt_Boolean, vt_Integer) else: types = (vt_Boolean, ) typed_data = self.get_typed_data(var) if var.type in types: c_integer_value = ctypes.c_long() status = oci.OCINumberToInt(var.environment.error_handle, byref(typed_data[pos]), ctypes.sizeof(c_integer_value), oci.OCI_NUMBER_SIGNED, byref(c_integer_value)) integer_value = c_integer_value.value var.environment.check_for_error( status, "NumberVar_GetValue(): as integer") if not python3_or_better(): if var.type is vt_Integer: return integer_value return bool(integer_value) if var.type in (vt_NumberAsString, vt_LongInteger): c_string = ctypes.create_string_buffer(200) cast_c_string = ctypes.cast(c_string, oci.POINTER(oci.ub1)) c_string_length = oci.ub4() c_string_length.value = ctypes.sizeof(c_string) typed_data = self.get_typed_data(var) status = oci.OCINumberToText( var.environment.error_handle, byref(typed_data[pos]), var.environment.numberToStringFormatBuffer.cast_ptr, var.environment.numberToStringFormatBuffer.size, None, 0, byref(c_string_length), cast_c_string) var.environment.check_for_error(status, "NumberVar_GetValue(): as string") python_string = c_string.value unicode_str = cxString_from_encoded_string( python_string, var.environment.encoding) if var.type is vt_NumberAsString: return unicode_str try: return int(unicode_str) except ValueError: pass return oracle_number_to_python_float(var.environment, byref(typed_data[pos]))
def internal_bind(self): """Allocate a variable and bind it to the given statement.""" if self.is_array: alloc_elems = self.allocelems actual_elements_ref = byref(self.c_actual_elements) else: alloc_elems = 0 actual_elements_ref = oci.POINTER(oci.ub4)() # perform the bind if self.bound_name: buffer = cxBuffer.new_from_object(self.bound_name, self.environment.encoding) status = oci.OCIBindByName(self.bound_cursor_handle, byref(self.bind_handle), self.environment.error_handle, buffer.cast_ptr, buffer.size, self.data, self.bufferSize, self.type.oracle_type, self.indicator, self.actual_length, self.return_code, alloc_elems, actual_elements_ref, oci.OCI_DEFAULT) else: status = oci.OCIBindByPos(self.bound_cursor_handle, byref(self.bind_handle), self.environment.error_handle, self.bound_pos, self.data, self.bufferSize, self.type.oracle_type, self.indicator, self.actual_length, self.return_code, alloc_elems, actual_elements_ref, oci.OCI_DEFAULT) self.environment.check_for_error(status, "Variable_InternalBind()") if not python3_or_better(): # set the charset form and id if applicable if self.type.charset_form != oci.SQLCS_IMPLICIT: c_charset_form = oci.ub1(self.type.charset_form) status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_charset_form), 0, oci.OCI_ATTR_CHARSET_FORM, self.environment.error_handle) self.environment.check_for_error( status, "Variable_InternalBind(): set charset form") self.type.charset_form = c_charset_form.value c_buffer_size = oci.ub4(self.bufferSize) status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_buffer_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.environment.check_for_error( status, "Variable_InternalBind(): set max data size") self.bufferSize = self.maxlength = c_buffer_size.value # set the max data size for strings self.set_max_data_size()
def set_max_data_size(self): # TODO: well, self.type here always is vt_FixedChar. But we can refactor this better, the code in the if is the same for strings if (self.type == vt_String or self.type == vt_FixedChar) and self.size > self.type.size: c_size = oci.ub4() status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.type.size = c_size.value self.environment.check_for_error(status, "Variable_InternalBind(): set max data size")
def _internal_size(self, ): c_length = oci.ub4() typed_data = self._get_lobvar_typed_data() status = oci.OCILobGetLength(self.lob_var.connection.handle, self.lob_var.environment.error_handle, typed_data[self.pos], byref(c_length)) self.lob_var.environment.check_for_error(status, "ExternalLobVar_InternalSize()") return c_length.value
def _internal_size(self, ): c_length = oci.ub4() typed_data = self._get_lobvar_typed_data() status = oci.OCILobGetLength(self.lob_var.connection.handle, self.lob_var.environment.error_handle, typed_data[self.pos], byref(c_length)) self.lob_var.environment.check_for_error( status, "ExternalLobVar_InternalSize()") return c_length.value
def set_max_data_size(self): if (self.type == vt_String or self.type == vt_FixedChar) and self.size > self.type.size: c_size = oci.ub4() status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.type.size = c_size.value self.environment.check_for_error( status, "Variable_InternalBind(): set max data size")
def set_max_data_size(self): # TODO: well, self.type here always is vt_FixedChar. But we can refactor this better, the code in the if is the same for strings if (self.type == vt_String or self.type == vt_FixedChar) and self.size > self.type.size: c_size = oci.ub4() status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.type.size = c_size.value self.environment.check_for_error( status, "Variable_InternalBind(): set max data size")
def __init__(self, cursor, num_elements, type, size): self.environment = cursor.connection.environment self.bind_handle = oci.POINTER(oci.OCIBind)() self.define_handle = oci.POINTER(oci.OCIDefine)() self.bound_cursor_handle = oci.POINTER(oci.OCIStmt)() self.bound_name = None self.inconverter = None # public self.outconverter = None # public self.bound_pos = 0 if num_elements < 1: self.numElements = self.allocelems = 1 else: self.numElements = self.allocelems = num_elements # the OCI will keep a ref to this across multiple calls, so we have to keep one too. # to avoid duplication of python-level vs c-level fields, self.actual_elements is a property self.c_actual_elements = oci.ub4(0) self.internal_fetch_num = 0 self.is_array = False self.is_allocated_internally = True self.type = type self.actual_length = oci.POINTER(oci.ub2)() self.return_code = oci.POINTER(oci.ub2)() # set the maximum length of the variable, ensure that a minimum of # 2 bytes is allocated to ensure that the array size check works self.size = type.size if type.is_variable_length: if size < ctypes.sizeof(oci.ub2): size = ctypes.sizeof(oci.ub2) self.size = size # allocate the data for the variable self.allocate_data() # allocate the indicator for the variable self.indicator = (self.numElements * oci.sb2)() # ensure that all variable values start out NULL for i in xrange(self.numElements): self.indicator[i] = oci.OCI_IND_NULL # for variable length data, also allocate the return code if type.is_variable_length: self.return_code = (self.numElements * oci.ub2)() # perform extended initialization if self.type.initialize_proc: self.type.initialize_proc(self, cursor)
def internal_bind(self): """Allocate a variable and bind it to the given statement.""" if self.is_array: alloc_elems = self.allocelems actual_elements_ref = byref(self.c_actual_elements) else: alloc_elems = 0 actual_elements_ref = oci.POINTER(oci.ub4)() # perform the bind if self.bound_name: buffer = cxBuffer.new_from_object(self.bound_name, self.environment.encoding) status = oci.OCIBindByName(self.bound_cursor_handle, byref(self.bind_handle), self.environment.error_handle, buffer.cast_ptr, buffer.size, self.data, self.bufferSize, self.type.oracle_type, self.indicator, self.actual_length, self.return_code, alloc_elems, actual_elements_ref, oci.OCI_DEFAULT) else: status = oci.OCIBindByPos(self.bound_cursor_handle, byref(self.bind_handle), self.environment.error_handle, self.bound_pos, self.data, self.bufferSize, self.type.oracle_type, self.indicator, self.actual_length, self.return_code, alloc_elems, actual_elements_ref, oci.OCI_DEFAULT) self.environment.check_for_error(status, "Variable_InternalBind()") if not python3_or_better(): # set the charset form and id if applicable if self.type.charset_form != oci.SQLCS_IMPLICIT: c_charset_form = oci.ub1(self.type.charset_form) status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_charset_form), 0, oci.OCI_ATTR_CHARSET_FORM, self.environment.error_handle) self.environment.check_for_error(status, "Variable_InternalBind(): set charset form") self.type.charset_form = c_charset_form.value c_buffer_size = oci.ub4(self.bufferSize) status = oci.OCIAttrSet(self.bind_handle, oci.OCI_HTYPE_BIND, byref(c_buffer_size), 0, oci.OCI_ATTR_MAXDATA_SIZE, self.environment.error_handle) self.environment.check_for_error(status, "Variable_InternalBind(): set max data size") self.bufferSize = self.maxlength = c_buffer_size.value # set the max data size for strings self.set_max_data_size()
def _internal_read(self, offset, amount): from lobvar import vt_CLOB, vt_NCLOB lob_type = self.lob_var.type if self.lob_var.is_file: self._internal_open(oci.OCI_FILE_READONLY, "ExternalLobVar_FileOpen()") if lob_type == vt_CLOB: buffer_size = amount * self.lob_var.environment.maxBytesPerCharacter elif lob_type == vt_NCLOB: buffer_size = amount * 2 else: buffer_size = amount buffer = ctypes.create_string_buffer(buffer_size) typed_data = self._get_lobvar_typed_data() c_length = oci.ub4(amount) arg8 = oci.OCILobRead.argtypes[8]() status = oci.OCILobRead(self.lob_var.connection.handle, self.lob_var.environment.error_handle, typed_data[self.pos], byref(c_length), offset, buffer, buffer_size, None, arg8, 0, self.lob_var.type.charset_form) length = c_length.value # unused? try: self.lob_var.environment.check_for_error( status, "ExternalLobVar_LobRead()") except DatabaseError: # don't know why cx oracle does not try to catch the error in the close. but if we do, there are 2 errors to report. try: self._internal_close("ExternalLobVar_FileClose()") except DatabaseError: pass raise if self.lob_var.is_file: self._internal_close("ExternalLobVar_FileClose()") return buffer.value
def oracle_timestamp_to_python_date(environment, value): """Return a Python date object given an Oracle timestamp.""" year = oci.sb2() month = oci.ub1() day = oci.ub1() hour = oci.ub1() minute = oci.ub1() second = oci.ub1() fsecond = oci.ub4() status = oci.OCIDateTimeGetDate(environment.handle, environment.error_handle, value, byref(year), byref(month), byref(day)) environment.check_for_error(status, "OracleTimestampToPythonDate(): date portion") status = oci.OCIDateTimeGetTime(environment.handle, environment.error_handle, value, byref(hour), byref(minute), byref(second), byref(fsecond)) environment.check_for_error(status, "OracleTimestampToPythonDate(): time portion") return datetime(year.value, month.value, day.value, hour.value, minute.value, second.value, fsecond.value / 1000)
def _write(self, var, pos, data_obj, offset): """Write data to the LOB variable.""" # verify the data type var_type = var.type if var_type == vt_BFILE: raise TypeError("BFILEs are read only") if var_type == vt_BLOB: buffer = cxBuffer.new_from_object(data_obj, var.environment.encoding) amount = buffer.size elif not python3_or_better() and var_type == vt_NCLOB: buffer = cxBuffer.new_from_object(data_obj, var.environment.nencoding) amount = buffer.size else: buffer = cxBuffer.new_from_object(data_obj, var.environment.encoding) if var.environment.fixedWidth and var.environment.maxBytesPerCharacter > 1: amount = buffer.size / var.environment.maxBytesPerCharacter else: amount = buffer.size # nothing to do if no data to write if amount == 0: return amount typed_data = self.get_typed_data(var) c_amount = oci.ub4(amount) callback_lob_write_type = oci.OCILobWrite.argtypes[9] null_oci_callback = callback_lob_write_type() status = oci.OCILobWrite(var.connection.handle, var.environment.error_handle, typed_data[pos], byref(c_amount), offset, buffer.ptr, buffer.size, oci.OCI_ONE_PIECE, None, null_oci_callback, 0, var.type.charset_form) var.environment.check_for_error(status, "LobVar_Write()") amount = c_amount.value # not sure if the write can change it, i dont think so, but just for correctness return amount
def oracle_timestamp_to_python_date(environment, value): """Return a Python date object given an Oracle timestamp.""" year = oci.sb2() month = oci.ub1() day = oci.ub1() hour = oci.ub1() minute = oci.ub1() second = oci.ub1() fsecond = oci.ub4() status = oci.OCIDateTimeGetDate( environment.handle, environment.error_handle, value, byref(year), byref(month), byref(day) ) environment.check_for_error(status, "OracleTimestampToPythonDate(): date portion") status = oci.OCIDateTimeGetTime( environment.handle, environment.error_handle, value, byref(hour), byref(minute), byref(second), byref(fsecond) ) environment.check_for_error(status, "OracleTimestampToPythonDate(): time portion") return datetime(year.value, month.value, day.value, hour.value, minute.value, second.value, fsecond.value / 1000)
def _internal_read(self, offset, amount): from lobvar import vt_CLOB, vt_NCLOB lob_type = self.lob_var.type if self.lob_var.is_file: self._internal_open(oci.OCI_FILE_READONLY, "ExternalLobVar_FileOpen()") if lob_type == vt_CLOB: buffer_size = amount * self.lob_var.environment.maxBytesPerCharacter elif lob_type == vt_NCLOB: buffer_size = amount * 2 else: buffer_size = amount buffer = ctypes.create_string_buffer(buffer_size) typed_data = self._get_lobvar_typed_data() c_length = oci.ub4(amount) arg8 = oci.OCILobRead.argtypes[8]() status = oci.OCILobRead(self.lob_var.connection.handle, self.lob_var.environment.error_handle, typed_data[self.pos], byref(c_length), offset, buffer, buffer_size, None, arg8, 0, self.lob_var.type.charset_form) length = c_length.value # unused? try: self.lob_var.environment.check_for_error(status, "ExternalLobVar_LobRead()") except DatabaseError: # don't know why cx oracle does not try to catch the error in the close. but if we do, there are 2 errors to report. try: self._internal_close("ExternalLobVar_FileClose()") except DatabaseError: pass raise if self.lob_var.is_file: self._internal_close("ExternalLobVar_FileClose()") return buffer.value