class EventConduit(WireProtocol): def __init__(self, conn, names, timeout): self.sock = None self.connection = conn self.event_names = {} for name in names: self.event_names[name] = 0 self.timeout = timeout self.connection._op_connect_request() (h, oid, buf) = self.connection._op_response() family = buf[:2] port = bytes_to_bint(buf[2:4], u=True) if family == b'\x02\x00': # IPv4 ip_address = '.'.join([str(byte_to_int(c)) for c in buf[4:8]]) elif family == b'\x0a\x00': # IPv6 address = bytes_to_hex(buf[8:24]) if not isinstance(address, str): # Py3 address = address.decode('ascii') ip_address = ':'.join( [address[i: i+4] for i in range(0, len(address), 4)] ) self.sock = SocketStream(ip_address, port, timeout) self.connection.last_event_id += 1 self.event_id = self.connection.last_event_id self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() (event_id, event_names) = self._wait_for_event(timeout=timeout) assert event_id == self.event_id # treat only one event_id self.event_names.update(event_names) def wait(self, timeout=None): self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() r = self._wait_for_event(timeout=timeout) if r: (event_id, event_names) = r assert event_id == self.event_id # treat only one event_id r = {} for k in event_names: r[k] = event_names[k]-self.event_names[k] self.event_names[k] = event_names[k] else: r = {} for k in self.event_names: r[k] = 0 return r def close(self): self.connection._op_cancel_events(self.event_id) (h, oid, buf) = self.connection._op_response() self.sock.close() self.sock = None
class EventConduit(WireProtocol): def __init__(self, conn, names, timeout): self.sock = None self.connection = conn self.event_names = {} for name in names: self.event_names[name] = 0 self.timeout = timeout self.connection._op_connect_request() (h, oid, buf) = self.connection._op_response() family = bytes_to_bint(buf[:2]) port = bytes_to_bint(buf[2:4], u=True) ip_address = '.'.join([str(byte_to_int(c)) for c in buf[4:8]]) self.sock = SocketStream(ip_address, port, timeout) self.connection.last_event_id += 1 self.event_id = self.connection.last_event_id self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() (event_id, event_names) = self._wait_for_event(timeout=timeout) assert event_id == self.event_id # treat only one event_id self.event_names.update(event_names) def wait(self, timeout=None): self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() r = self._wait_for_event(timeout=timeout) if r: (event_id, event_names) = r assert event_id == self.event_id # treat only one event_id r = {} for k in event_names: r[k] = event_names[k]-self.event_names[k] self.event_names[k] = event_names[k] else: r = {} for k in self.event_names: r[k] = 0 return r def close(self): self.connection._op_cancel_events(self.event_id) (h, oid, buf) = self.connection._op_response() self.sock.close() self.sock = None
class EventConduit(WireProtocol): def __init__(self, conn, names, timeout): self.sock = None self.connection = conn self.event_names = {} for name in names: self.event_names[name] = 0 self.timeout = timeout self.connection._op_connect_request() (h, oid, buf) = self.connection._op_response() family = bytes_to_bint(buf[:2]) port = bytes_to_bint(buf[2:4], u=True) ip_address = '.'.join([str(byte_to_int(c)) for c in buf[4:8]]) self.sock = SocketStream(ip_address, port, timeout) self.connection.last_event_id += 1 self.event_id = self.connection.last_event_id self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() (event_id, event_names) = self._wait_for_event(timeout=timeout) assert event_id == self.event_id # treat only one event_id self.event_names.update(event_names) def wait(self, timeout=None): self.connection._op_que_events(self.event_names, self.event_id) (h, oid, buf) = self.connection._op_response() r = self._wait_for_event(timeout=timeout) if r: (event_id, event_names) = r assert event_id == self.event_id # treat only one event_id r = {} for k in event_names: r[k] = event_names[k] - self.event_names[k] self.event_names[k] = event_names[k] else: r = {} for k in self.event_names: r[k] = 0 return r def close(self): self.connection._op_cancel_events(self.event_id) (h, oid, buf) = self.connection._op_response() self.sock.close() self.sock = None
class EventConduit(WireProtocol): def __init__(self, conn, names, timeout): self.sock = None self.connection = conn self.event_names = {} for name in names: self.event_names[name] = 0 self.timeout = timeout (h, port, family, ip_address) = self.connection._op_connect_request() self.sock = SocketStream(ip_address, port, timeout) self.connection.last_event_id += 1 self.event_id = self.connection.last_event_id self.connection._op_que_events(self.event_names, 0, 0, self.event_id) (h, oid, buf) = self.connection._op_response() (event_id, event_names) = self._wait_for_event(timeout=timeout) assert event_id == self.event_id # treat only one event_id self.event_names.update(event_names) def wait(self, timeout=None): self.connection._op_que_events(self.event_names, 0, 0, self.event_id) (h, oid, buf) = self.connection._op_response() r = self._wait_for_event(timeout=timeout) if r: (event_id, event_names) = r assert event_id == self.event_id # treat only one event_id r = {} for k in event_names: r[k] = event_names[k]-self.event_names[k] self.event_names[k] = event_names[k] else: r = {} for k in self.event_names: r[k] = 0 return r def close(self): self.connection._op_cancel_events(self.event_id) (h, oid, buf) = self.connection._op_response() self.sock.close() self.sock = None
class Connection(WireProtocol): def cursor(self): DEBUG_OUTPUT("Connection::cursor()") if self._transaction is None: self.begin() return Cursor(self._transaction) def begin(self): DEBUG_OUTPUT("Connection::begin()") if not self.sock: raise InternalError if self._transaction is None: self._transaction = Transaction(self, self._autocommit) self._transaction.begin() def commit(self, retaining=False): DEBUG_OUTPUT("Connection::commit()") if self._transaction: self._transaction.commit(retaining=retaining) def savepoint(self, name): return self._transaction.savepoint(name) def rollback(self, retaining=False, savepoint=None): DEBUG_OUTPUT("Connection::rollback()") if self._transaction: self._transaction.rollback(retaining=retaining, savepoint=savepoint) def execute_immediate(self, query): if self._transaction is None: self._transaction = Transaction(self, self._autocommit) self._transaction.begin() self._transaction.check_trans_handle() self._op_exec_immediate( self._transaction.trans_handle, query=query) (h, oid, buf) = self._op_response() self._transaction.is_dirty = True def __init__( self, dsn=None, user=None, password=None, role=None, host=None, database=None, charset=DEFAULT_CHARSET, port=3050, page_size=4096, is_services=False, cloexec=False, timeout=None, isolation_level=None, use_unicode=None, auth_plugin_name=None, wire_crypt=True, create_new=False ): DEBUG_OUTPUT("Connection::__init__()") if auth_plugin_name is None: auth_plugin_name = 'Srp' WireProtocol.__init__(self) self.sock = None self.db_handle = None if dsn: i = dsn.find(':') if i < 0: self.hostname = host self.filename = dsn else: hostport = dsn[:i] self.filename = dsn[i+1:] i = hostport.find('/') if i < 0: self.hostname = hostport else: self.hostname = hostport[:i] port = int(hostport[i+1:]) else: self.hostname = host self.filename = database if self.hostname is None: self.hostname = 'localhost' self.port = port self.user = user self.password = password self.role = role self.charset = charset self.timeout = float(timeout) if timeout is not None else None self.auth_plugin_name = auth_plugin_name self.wire_crypt = wire_crypt self.page_size = page_size self.is_services = is_services if isolation_level is None: self.isolation_level = ISOLATION_LEVEL_READ_COMMITED else: self.isolation_level = int(isolation_level) self.use_unicode = use_unicode self.last_event_id = 0 self._autocommit = False self._transaction = None self.sock = SocketStream(self.hostname, self.port, self.timeout, cloexec) self._op_connect(auth_plugin_name, wire_crypt) try: self._op_accept() except OperationalError as e: self.sock.close() self.sock = None raise e if create_new: # create database self._op_create(self.page_size) elif self.is_services: # service api self._op_service_attach() else: # connect self._op_attach() (h, oid, buf) = self._op_response() self.db_handle = h def __enter__(self): return self def __exit__(self, exc, value, traceback): self.close() def set_isolation_level(self, isolation_level): self.isolation_level = int(isolation_level) def set_autocommit(self, is_autocommit): if self._autocommit != is_autocommit and self._transaction is not None: self.rollback() self._transaction = None self._autocommit = is_autocommit def _db_info(self, info_requests): if info_requests[-1] == isc_info_end: self._op_info_database(bs(info_requests)) else: self._op_info_database(bs(info_requests+type(info_requests)([isc_info_end]))) (h, oid, buf) = self._op_response() i = 0 i_request = 0 r = [] while i < len(buf): req = byte_to_int(buf[i]) if req == isc_info_end: break assert req == info_requests[i_request] or req == isc_info_error if req == isc_info_user_names: user_names = [] while req == isc_info_user_names: l = bytes_to_int(buf[i+1:i+3]) user_names.append(buf[i+3:i+3+l]) i = i + 3 + l req = byte_to_int(buf[i]) r.append((req, user_names)) else: l = bytes_to_int(buf[i+1:i+3]) r.append((req, buf[i+3:i+3+l])) i = i + 3 + l i_request += 1 return r def _db_info_convert_type(self, info_request, v): REQ_INT = set([ isc_info_allocation, isc_info_no_reserve, isc_info_db_sql_dialect, isc_info_ods_minor_version, isc_info_ods_version, isc_info_page_size, isc_info_current_memory, isc_info_forced_writes, isc_info_max_memory, isc_info_num_buffers, isc_info_sweep_interval, isc_info_limbo, isc_info_attachment_id, isc_info_fetches, isc_info_marks, isc_info_reads, isc_info_writes, isc_info_set_page_buffers, isc_info_db_read_only, isc_info_db_size_in_pages, isc_info_page_errors, isc_info_record_errors, isc_info_bpage_errors, isc_info_dpage_errors, isc_info_ipage_errors, isc_info_ppage_errors, isc_info_tpage_errors, # may not be available in some versions of Firebird isc_info_oldest_transaction, isc_info_oldest_active, isc_info_oldest_snapshot, isc_info_next_transaction, isc_info_active_tran_count ]) REQ_COUNT = set([ isc_info_backout_count, isc_info_delete_count, isc_info_expunge_count, isc_info_insert_count, isc_info_purge_count, isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count ]) if info_request in (isc_info_base_level, ): # IB6 API guide p52 return byte_to_int(v[1]) elif info_request in (isc_info_db_id, ): # IB6 API guide p52 conn_code = byte_to_int(v[0]) len1 = byte_to_int(v[1]) filename = self.bytes_to_str(v[2:2+len1]) len2 = byte_to_int(v[2+len1]) sitename = self.bytes_to_str(v[3+len1:3+len1+len2]) return (conn_code, filename, sitename) elif info_request in (isc_info_implementation, ): return (byte_to_int(v[1]), byte_to_int(v[2])) elif info_request in (isc_info_version, isc_info_firebird_version): # IB6 API guide p53 return self.bytes_to_str(v[2:2+byte_to_int(v[1])]) elif info_request in (isc_info_user_names, ): # IB6 API guide p54 user_names = [] for u in v: user_names.append(self.bytes_to_str(u[1:])) return user_names elif info_request in REQ_INT: return bytes_to_int(v) elif info_request in REQ_COUNT: counts = {} i = 0 while i < len(v): counts[bytes_to_int(v[i:i+2])] = bytes_to_int(v[i+2:i+6]) i += 6 return counts elif info_request in (isc_info_creation_date,): nday = bytes_to_int(v[:4]) + 2400001 - 1721119 century = (4 * nday - 1) // 146097 nday = 4 * nday - 1 - 146097 * century dd = nday // 4 nday = (4 * dd + 3) // 1461 dd = 4 * dd + 3 - 1461 * nday dd = (dd + 4) // 4 mm = (5 * dd - 3) // 153 dd = 5 * dd - 3 - 153 * mm dd = (dd + 5) // 5 yyyy = 100 * century + nday if mm < 10: mm += 3 else: mm -= 9 yyyy += 1 ntime = bytes_to_int(v[4:]) h = ntime // (3600 * ISC_TIME_SECONDS_PRECISION) ntime %= 3600 * ISC_TIME_SECONDS_PRECISION m = ntime // (60 * ISC_TIME_SECONDS_PRECISION) ntime %= 60 * ISC_TIME_SECONDS_PRECISION s = ntime // ISC_TIME_SECONDS_PRECISION ms = ntime % ISC_TIME_SECONDS_PRECISION * 100 return datetime.datetime(yyyy, mm, dd, h, m, s, ms) else: return v def db_info(self, info_requests): DEBUG_OUTPUT("Connection::db_info()") if type(info_requests) == int: # singleton r = self._db_info([info_requests]) return self._db_info_convert_type(info_requests, r[0][1]) else: results = {} rs = self._db_info(info_requests) for i in range(len(info_requests)): if rs[i][0] == isc_info_error: results[info_requests[i]] = None else: results[info_requests[i]] = self._db_info_convert_type(info_requests[i], rs[i][1]) return results def trans_info(self, info_requests): if self._transaction: return self._transaction.trans_info(info_requests) return {} def close(self): DEBUG_OUTPUT("Connection::close()") if self.sock is None: return if self.db_handle: if self.is_services: self._op_service_detach() else: self._op_detach() (h, oid, buf) = self._op_response() self.sock.close() self.sock = None self.db_handle = None def drop_database(self): DEBUG_OUTPUT("Connection::drop_database()") self._op_drop_database() (h, oid, buf) = self._op_response() self.sock.close() self.sock = None self.db_handle = None def event_conduit(self, event_names, timeout=None): return EventConduit(self, event_names, timeout) def __del__(self): if self.sock: self.close() def is_disconnect(self): return self.sock is None
class Connection(WireProtocol): def cursor(self, factory=Cursor): DEBUG_OUTPUT("Connection::cursor()") if self._transaction is None: self.begin() return factory(self._transaction) def begin(self): DEBUG_OUTPUT("Connection::begin()") if not self.sock: raise InternalError if self._transaction is None: self._transaction = Transaction(self, self._autocommit) self._transaction.begin() def commit(self, retaining=False): DEBUG_OUTPUT("Connection::commit()") if self._transaction: self._transaction.commit(retaining=retaining) def savepoint(self, name): return self._transaction.savepoint(name) def rollback(self, retaining=False, savepoint=None): DEBUG_OUTPUT("Connection::rollback()") if self._transaction: self._transaction.rollback(retaining=retaining, savepoint=savepoint) def execute_immediate(self, query): if self._transaction is None: self._transaction = Transaction(self, self._autocommit) self._transaction.begin() self._transaction.check_trans_handle() self._op_exec_immediate(self._transaction.trans_handle, query=query) (h, oid, buf) = self._op_response() self._transaction.is_dirty = True def __init__(self, dsn=None, user=None, password=None, role=None, host=None, database=None, charset=DEFAULT_CHARSET, port=3050, page_size=4096, is_services=False, cloexec=False, timeout=None, isolation_level=None, use_unicode=None, auth_plugin_name=None, wire_crypt=True, create_new=False, timezone=None): DEBUG_OUTPUT("Connection::__init__()") if auth_plugin_name is None: auth_plugin_name = 'Srp256' WireProtocol.__init__(self) self.sock = None self.db_handle = None if dsn: i = dsn.find(':') if i < 0: self.hostname = host self.filename = dsn else: hostport = dsn[:i] self.filename = dsn[i + 1:] i = hostport.find('/') if i < 0: self.hostname = hostport else: self.hostname = hostport[:i] port = int(hostport[i + 1:]) else: self.hostname = host self.filename = database if self.hostname is None: self.hostname = 'localhost' self.port = port self.user = user self.password = password self.role = role self.charset = charset self.timeout = float(timeout) if timeout is not None else None self.auth_plugin_name = auth_plugin_name self.wire_crypt = wire_crypt self.page_size = page_size self.is_services = is_services if isolation_level is None: self.isolation_level = ISOLATION_LEVEL_READ_COMMITED else: self.isolation_level = int(isolation_level) self.use_unicode = use_unicode self.timezone = timezone self.last_event_id = 0 self._autocommit = False self._transaction = None self.sock = SocketStream(self.hostname, self.port, self.timeout, cloexec) self._op_connect(auth_plugin_name, wire_crypt) try: self._parse_connect_response() except OperationalError as e: self.sock.close() self.sock = None raise e if create_new: # create database self._op_create(self.page_size) elif self.is_services: # service api self._op_service_attach() else: # connect self._op_attach() (h, oid, buf) = self._op_response() self.db_handle = h def __enter__(self): return self def __exit__(self, exc, value, traceback): self.close() def set_isolation_level(self, isolation_level): self.isolation_level = int(isolation_level) def set_autocommit(self, is_autocommit): if self._autocommit != is_autocommit and self._transaction is not None: self.rollback() self._transaction = None self._autocommit = is_autocommit def _db_info(self, info_requests): if info_requests[-1] == isc_info_end: self._op_info_database(bs(info_requests)) else: self._op_info_database( bs(info_requests + type(info_requests)([isc_info_end]))) (h, oid, buf) = self._op_response() i = 0 i_request = 0 r = [] while i < len(buf): req = byte_to_int(buf[i]) if req == isc_info_end: break assert req == info_requests[i_request] or req == isc_info_error if req == isc_info_user_names: user_names = [] while req == isc_info_user_names: l = bytes_to_int(buf[i + 1:i + 3]) user_names.append(buf[i + 3:i + 3 + l]) i = i + 3 + l req = byte_to_int(buf[i]) r.append((req, user_names)) else: l = bytes_to_int(buf[i + 1:i + 3]) r.append((req, buf[i + 3:i + 3 + l])) i = i + 3 + l i_request += 1 return r def _db_info_convert_type(self, info_request, v): REQ_INT = set([ isc_info_allocation, isc_info_no_reserve, isc_info_db_sql_dialect, isc_info_ods_minor_version, isc_info_ods_version, isc_info_page_size, isc_info_current_memory, isc_info_forced_writes, isc_info_max_memory, isc_info_num_buffers, isc_info_sweep_interval, isc_info_limbo, isc_info_attachment_id, isc_info_fetches, isc_info_marks, isc_info_reads, isc_info_writes, isc_info_set_page_buffers, isc_info_db_read_only, isc_info_db_size_in_pages, isc_info_page_errors, isc_info_record_errors, isc_info_bpage_errors, isc_info_dpage_errors, isc_info_ipage_errors, isc_info_ppage_errors, isc_info_tpage_errors, # may not be available in some versions of Firebird isc_info_oldest_transaction, isc_info_oldest_active, isc_info_oldest_snapshot, isc_info_next_transaction, isc_info_active_tran_count ]) REQ_COUNT = set([ isc_info_backout_count, isc_info_delete_count, isc_info_expunge_count, isc_info_insert_count, isc_info_purge_count, isc_info_read_idx_count, isc_info_read_seq_count, isc_info_update_count ]) if info_request in (isc_info_base_level, ): # IB6 API guide p52 return byte_to_int(v[1]) elif info_request in (isc_info_db_id, ): # IB6 API guide p52 conn_code = byte_to_int(v[0]) len1 = byte_to_int(v[1]) filename = self.bytes_to_str(v[2:2 + len1]) len2 = byte_to_int(v[2 + len1]) sitename = self.bytes_to_str(v[3 + len1:3 + len1 + len2]) return (conn_code, filename, sitename) elif info_request in (isc_info_implementation, ): return (byte_to_int(v[1]), byte_to_int(v[2])) elif info_request in (isc_info_version, isc_info_firebird_version): # IB6 API guide p53 return self.bytes_to_str(v[2:2 + byte_to_int(v[1])]) elif info_request in (isc_info_user_names, ): # IB6 API guide p54 user_names = [] for u in v: user_names.append(self.bytes_to_str(u[1:])) return user_names elif info_request in REQ_INT: return bytes_to_int(v) elif info_request in REQ_COUNT: counts = {} i = 0 while i < len(v): counts[bytes_to_int(v[i:i + 2])] = bytes_to_int(v[i + 2:i + 6]) i += 6 return counts elif info_request in (isc_info_creation_date, ): nday = bytes_to_int(v[:4]) + 2400001 - 1721119 century = (4 * nday - 1) // 146097 nday = 4 * nday - 1 - 146097 * century dd = nday // 4 nday = (4 * dd + 3) // 1461 dd = 4 * dd + 3 - 1461 * nday dd = (dd + 4) // 4 mm = (5 * dd - 3) // 153 dd = 5 * dd - 3 - 153 * mm dd = (dd + 5) // 5 yyyy = 100 * century + nday if mm < 10: mm += 3 else: mm -= 9 yyyy += 1 ntime = bytes_to_int(v[4:]) h = ntime // (3600 * ISC_TIME_SECONDS_PRECISION) ntime %= 3600 * ISC_TIME_SECONDS_PRECISION m = ntime // (60 * ISC_TIME_SECONDS_PRECISION) ntime %= 60 * ISC_TIME_SECONDS_PRECISION s = ntime // ISC_TIME_SECONDS_PRECISION ms = ntime % ISC_TIME_SECONDS_PRECISION * 100 return datetime.datetime(yyyy, mm, dd, h, m, s, ms) else: return v def db_info(self, info_requests): DEBUG_OUTPUT("Connection::db_info()") if type(info_requests) == int: # singleton r = self._db_info([info_requests]) return self._db_info_convert_type(info_requests, r[0][1]) else: results = {} rs = self._db_info(info_requests) for i in range(len(info_requests)): if rs[i][0] == isc_info_error: results[info_requests[i]] = None else: results[info_requests[i]] = self._db_info_convert_type( info_requests[i], rs[i][1]) return results def trans_info(self, info_requests): if self._transaction: return self._transaction.trans_info(info_requests) return {} def close(self): DEBUG_OUTPUT("Connection::close()") if self.sock is None: return if self.db_handle: if self.is_services: self._op_service_detach() else: self._op_detach() (h, oid, buf) = self._op_response() self.sock.close() self.sock = None self.db_handle = None def drop_database(self): DEBUG_OUTPUT("Connection::drop_database()") self._op_drop_database() (h, oid, buf) = self._op_response() self.sock.close() self.sock = None self.db_handle = None def event_conduit(self, event_names, timeout=None): return EventConduit(self, event_names, timeout) def __del__(self): if self.sock: self.close() def is_disconnect(self): return self.sock is None