|
37 | 37 | RequestUpdate,
|
38 | 38 | RequestUpsert,
|
39 | 39 | RequestAuthenticate,
|
40 |
| - RequestExecute |
| 40 | + RequestExecute, |
| 41 | + RequestProtocolVersion, |
41 | 42 | )
|
42 | 43 | from tarantool.space import Space
|
43 | 44 | from tarantool.const import (
|
|
55 | 56 | REQUEST_TYPE_ERROR,
|
56 | 57 | IPROTO_GREETING_SIZE,
|
57 | 58 | ITERATOR_EQ,
|
58 |
| - ITERATOR_ALL |
| 59 | + ITERATOR_ALL, |
| 60 | + CONNECTOR_IPROTO_VERSION, |
| 61 | + CONNECTOR_FEATURES, |
| 62 | + IPROTO_FEATURE_STREAMS, |
| 63 | + IPROTO_FEATURE_TRANSACTIONS, |
| 64 | + IPROTO_FEATURE_ERROR_EXTENSION, |
| 65 | + IPROTO_FEATURE_WATCHERS, |
| 66 | + IPROTO_FEATURE_GRACEFUL_SHUTDOWN, |
59 | 67 | )
|
60 | 68 | from tarantool.error import (
|
61 | 69 | Error,
|
@@ -498,6 +506,15 @@ def __init__(self, host, port,
|
498 | 506 | self.ssl_cert_file = ssl_cert_file
|
499 | 507 | self.ssl_ca_file = ssl_ca_file
|
500 | 508 | self.ssl_ciphers = ssl_ciphers
|
| 509 | + self._protocol_version = None |
| 510 | + self._features = { |
| 511 | + IPROTO_FEATURE_STREAMS: False, |
| 512 | + IPROTO_FEATURE_TRANSACTIONS: False, |
| 513 | + IPROTO_FEATURE_ERROR_EXTENSION: False, |
| 514 | + IPROTO_FEATURE_WATCHERS: False, |
| 515 | + IPROTO_FEATURE_GRACEFUL_SHUTDOWN: False, |
| 516 | + } |
| 517 | + |
501 | 518 | if connect_now:
|
502 | 519 | self.connect()
|
503 | 520 |
|
@@ -686,6 +703,7 @@ def connect(self):
|
686 | 703 | self.wrap_socket_ssl()
|
687 | 704 | self.handshake()
|
688 | 705 | self.load_schema()
|
| 706 | + self._check_features() |
689 | 707 | except SslError as e:
|
690 | 708 | raise e
|
691 | 709 | except Exception as e:
|
@@ -1602,3 +1620,44 @@ def execute(self, query, params=None):
|
1602 | 1620 | request = RequestExecute(self, query, params)
|
1603 | 1621 | response = self._send_request(request)
|
1604 | 1622 | return response
|
| 1623 | + |
| 1624 | + def _check_features(self): |
| 1625 | + """ |
| 1626 | + Execute an ID request: inform the server about the protocol |
| 1627 | + version and features connector support and get server-side |
| 1628 | + information about it. |
| 1629 | +
|
| 1630 | + After executing this request, the connector will choose a |
| 1631 | + protocol version and features supported both by connector and |
| 1632 | + server. |
| 1633 | +
|
| 1634 | + :raise: :exc:`~AssertionError`, |
| 1635 | + :exc:`~tarantool.error.DatabaseError`, |
| 1636 | + :exc:`~tarantool.error.SchemaError`, |
| 1637 | + :exc:`~tarantool.error.NetworkError`, |
| 1638 | + :exc:`~tarantool.error.SslError` |
| 1639 | + """ |
| 1640 | + |
| 1641 | + try: |
| 1642 | + request = RequestProtocolVersion(self, |
| 1643 | + CONNECTOR_IPROTO_VERSION, |
| 1644 | + CONNECTOR_FEATURES) |
| 1645 | + response = self._send_request(request) |
| 1646 | + server_protocol_version = response.protocol_version |
| 1647 | + server_features = response.features |
| 1648 | + except DatabaseError as exc: |
| 1649 | + ER_UNKNOWN_REQUEST_TYPE = 48 |
| 1650 | + if exc.code == ER_UNKNOWN_REQUEST_TYPE: |
| 1651 | + server_protocol_version = None |
| 1652 | + server_features = [] |
| 1653 | + else: |
| 1654 | + raise exc |
| 1655 | + |
| 1656 | + if server_protocol_version is not None: |
| 1657 | + self._protocol_version = min(server_protocol_version, |
| 1658 | + CONNECTOR_IPROTO_VERSION) |
| 1659 | + |
| 1660 | + # Intercept lists of features |
| 1661 | + features_list = [val for val in CONNECTOR_FEATURES if val in server_features] |
| 1662 | + for val in features_list: |
| 1663 | + self._features[val] = True |
0 commit comments