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 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 OCIAttrGet(param, oci_function, oci_type, oci_subfunction, environment, context): c_result = oci_type() arg3 = oci.POINTER( oci.ub4)() # TODO: move somewhere where it is evaluated only once status = oci.OCIAttrGet(param, oci_function, byref(c_result), arg3, oci_subfunction, environment.error_handle) environment.check_for_error(status, context) return c_result.value
def new_from_scratch(threaded, events, encoding, nencoding): mode = oci.OCI_OBJECT if threaded: mode |= oci.OCI_THREADED #TODO: if EVENTS_SUPPORTED: # if events: # mode |= ociap.OCI_EVENTS argtypes = oci.OCIEnvNlsCreate.argtypes handle = oci.POINTER(oci.OCIEnv)() status = oci.OCIEnvNlsCreate(byref(handle), mode, argtypes[2](), argtypes[3](), argtypes[4](), argtypes[5](), 0, None, 0, 0) if not handle or (status != oci.OCI_SUCCESS and status != oci.OCI_SUCCESS_WITH_INFO): raise InterfaceError("Unable to acquire Oracle environment handle") env = Environment(handle) c_maxBytesPerCharacter = oci.sb4() status = oci.OCINlsNumericInfoGet(handle, env.error_handle, byref(c_maxBytesPerCharacter), oci.OCI_NLS_CHARSET_MAXBYTESZ) env.check_for_error(status, "Environment_New(): get max bytes per character") env.maxBytesPerCharacter = c_maxBytesPerCharacter.value env.maxStringBytes = MAX_STRING_CHARS * env.maxBytesPerCharacter # acquire whether character set is fixed width c_fixedWidth = oci.sb4() status = oci.OCINlsNumericInfoGet(handle, env.error_handle, byref(c_fixedWidth), oci.OCI_NLS_CHARSET_FIXEDWIDTH) env.check_for_error( status, "Environment_New(): determine if charset fixed width") env.fixedWidth = c_fixedWidth.value # determine encodings to use for Unicode values env.encoding = env.get_characterset_name(oci.OCI_ATTR_ENV_CHARSET_ID, encoding) env.nencoding = env.get_characterset_name(oci.OCI_ATTR_ENV_NCHARSET_ID, nencoding) # fill buffers for number formats env.numberToStringFormatBuffer = Environment.set_buffer( "TM9", env.encoding) env.numberFromStringFormatBuffer = Environment.set_buffer( "999999999999999999999999999999999999999999999999999999999999999", env.encoding) env.nlsNumericCharactersBuffer = Environment.set_buffer( "NLS_NUMERIC_CHARACTERS='.,'", env.encoding) return env
def OCIParamGet(handle, htype, environment, pos, context): # cant pass cast_param to OCI and return non-cast param. ctypes doesn't know the cast param and the non-cast param are the same. param_type = oci.POINTER(oci.OCIParam) param = ctypes.c_void_p() # acquire parameter descriptor status = oci.OCIParamGet(handle, htype, environment.error_handle, byref(param), pos) environment.check_for_error(status, context) result = ctypes.cast(param, param_type) return result
def close(self): """Close the connection, disconnecting from the database.""" self.rollback() # will check if we are actually connected # logoff of the server if self.session_handle: status = oci.OCISessionEnd(self.handle, self.environment.error_handle, self.session_handle, oci.OCI_DEFAULT) self.environment.check_for_error( status, "Connection_Close(): end session") oci.OCIHandleFree(self.handle, oci.OCI_HTYPE_SVCCTX) self.handle = oci.POINTER(oci.OCISvcCtx)()
def __init__(self, handle): self.handle = handle self.fixedWidth = self.maxBytesPerCharacter = 1 self.maxStringBytes = MAX_STRING_CHARS self.cloneEnv = None # used for connection pooling, but that is still TODO self.numberToStringFormatBuffer = cxBuffer.new_null() self.numberFromStringFormatBuffer = cxBuffer.new_null() self.nlsNumericCharactersBuffer = cxBuffer.new_null() # create the error handle error_handle_as_void_p = ctypes.c_void_p() argtypes = oci.OCIHandleAlloc.argtypes status = oci.OCIHandleAlloc(handle, byref(error_handle_as_void_p), oci.OCI_HTYPE_ERROR, 0, argtypes[4]()) self.check_for_error(status, "Environment_New(): create error handle") self.error_handle = ctypes.cast(error_handle_as_void_p, oci.POINTER(oci.OCIError))
def __init__(self): VariableType.__init__(self) self.oci_type = oci.POINTER(oci.OCIStmt) #self.initialize_proc = None #self.finalize_proc = None self.pre_define_proc = None self.post_define_proc = None self.pre_fetch_proc = None self.is_null_proc = None #self.set_value_proc = None #self.get_value_proc = None self.get_buffer_size_proc = None self.python_type = CURSOR self.oracle_type = oci.SQLT_RSET self.charset_form = oci.SQLCS_IMPLICIT self.size = ctypes.sizeof(self.oci_type) self.is_character_data = False self.is_variable_length = False self.can_be_copied = False self.can_be_in_array = False
def __init__(self, environment, context, retrieve_error): self.context = context if retrieve_error: if environment.error_handle: handle = environment.error_handle handle_type = oci.OCI_HTYPE_ERROR else: handle = environment.handle handle_type = oci.OCI_HTYPE_ENV error_text = ctypes.create_string_buffer(4096) error_text_as_ub1_pointer = ctypes.cast(error_text, oci.POINTER(oci.ub1)) c_code = oci.sb4() argtypes = oci.OCIErrorGet.argtypes status = oci.OCIErrorGet(handle, 1, argtypes[2](), byref(c_code), error_text_as_ub1_pointer, len(error_text), handle_type) self.code = c_code.value if status != oci.OCI_SUCCESS: raise InternalError("No Oracle error?") if not python3_or_better(): self.message = error_text.value else: self.message = error_text.decode(environment.encoding)
def __init__(self): VariableType.__init__(self) self.oci_type = oci.POINTER(oci.OCIInterval) #self.initialize_proc = None #self.finalize_proc = None self.pre_define_proc = None self.post_define_proc = None self.pre_fetch_proc = None self.is_null_proc = None #self.set_value_proc = None #self.get_value_proc = None self.get_buffer_size_proc = None self.python_type = INTERVAL self.oracle_type = oci.SQLT_INTERVAL_DS self.charset_form = oci.SQLCS_IMPLICIT self.size = ctypes.sizeof(self.oci_type) self.is_character_data = False self.is_variable_length = False self.can_be_copied = True self.can_be_in_array = True self.descriptor_manager = DescriptorManager()
def __init__(self): VariableType.__init__(self) self.oci_type = oci.POINTER(oci.OCILobLocator) self.initialize_proc = self.initialize self.finalize_proc = self.finalize self.pre_define_proc = None self.post_define_proc = None self.pre_fetch_proc = self.pre_fetch self.is_null_proc = None self.set_value_proc = self.set_value self.get_value_proc = self.get_value self.get_buffer_size_proc = None #self.python_type = None #self.oracle_type = None #self.charset_form = None self.size = ctypes.sizeof(self.oci_type) #self.is_character_data = None self.is_variable_length = False self.can_be_copied = False self.can_be_in_array = False self.descriptor_manager = DescriptorManager()
def connect(self, mode, twophase, newpassword): """Create a new connection object by connecting to the database.""" credential_type = oci.OCI_CRED_EXT # allocate the server handle self.server_handle = oci.POINTER(oci.OCIServer)() OCIHandleAlloc(self.environment, self.server_handle, oci.OCI_HTYPE_SERVER, "Connection_Connect(): allocate server handle") buffer = cxBuffer.new_from_object(self.dsn, self.environment.encoding) # attach to the server status = oci.OCIServerAttach(self.server_handle, self.environment.error_handle, buffer.cast_ptr, buffer.size, oci.OCI_DEFAULT) self.environment.check_for_error( status, "Connection_Connect(): server attach") # allocate the service context handle self.handle = oci.POINTER(oci.OCISvcCtx)() OCIHandleAlloc( self.environment, self.handle, oci.OCI_HTYPE_SVCCTX, "Connection_Connect(): allocate service context handle") # set attribute for server handle status = oci.OCIAttrSet(self.handle, oci.OCI_HTYPE_SVCCTX, self.server_handle, 0, oci.OCI_ATTR_SERVER, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set server handle") # set the internal and external names; these are needed for global # transactions but are limited in terms of the lengths of the strings if twophase: status = oci.OCIAttrSet(self.server_handle, oci.OCI_HTYPE_SERVER, "cx_Oracle", 0, oci.OCI_ATTR_INTERNAL_NAME, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set internal name") status = oci.OCIAttrSet(self.server_handle, oci.OCI_HTYPE_SERVER, "cx_Oracle", 0, oci.OCI_ATTR_EXTERNAL_NAME, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set external name") # allocate session handle self.session_handle = oci.POINTER(oci.OCISession)() OCIHandleAlloc(self.environment, self.session_handle, oci.OCI_HTYPE_SESSION, "Connection_Connect(): allocate session handle") # set user name in session handle buffer = cxBuffer.new_from_object(self.username, self.environment.encoding) if buffer.size > 0: credential_type = oci.OCI_CRED_RDBMS status = oci.OCIAttrSet(self.session_handle, oci.OCI_HTYPE_SESSION, buffer.ptr, buffer.size, oci.OCI_ATTR_USERNAME, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set user name") # set password in session handle buffer = cxBuffer.new_from_object(self.password, self.environment.encoding) if buffer.size > 0: credential_type = oci.OCI_CRED_RDBMS status = oci.OCIAttrSet(self.session_handle, oci.OCI_HTYPE_SESSION, buffer.ptr, buffer.size, oci.OCI_ATTR_PASSWORD, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set password") if hasattr(oci, 'OCI_ATTR_DRIVER_NAME'): buffer = cxBuffer.new_from_object(DRIVER_NAME, self.environment.encoding) status = oci.OCIAttrSet(self.session_handle, oci.OCI_HTYPE_SESSION, buffer.ptr, buffer.size, oci.OCI_ATTR_DRIVER_NAME, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set driver name") # set the session handle on the service context handle status = oci.OCIAttrSet(self.handle, oci.OCI_HTYPE_SVCCTX, self.session_handle, 0, oci.OCI_ATTR_SESSION, self.environment.error_handle) self.environment.check_for_error( status, "Connection_Connect(): set session handle") # if a new password has been specified, change it which will also # establish the session #TODO: implement change_password if newpassword: return self.change_password( self.password ) # TODO: removed one arg, what about the new password?!?! # begin the session status = oci.OCISessionBegin(self.handle, self.environment.error_handle, self.session_handle, credential_type, mode) try: self.environment.check_for_error( status, "Connection_Connect(): begin session") except Error: self.session_handle = oci.POINTER(oci.OCISession)( ) # who frees the session handle? the failed session begin call? raise
def get_typed_data(self, var): return ctypes.cast(var.data, oci.POINTER(self.oci_type))