Example #1
0
    def test_request_message_use_last_session_id(self):
        connection = Connection("localhost", 30015, "Fuu", "Bar")
        connection.session_id = 3

        msg1 = RequestMessage.new(connection)
        assert msg1.session_id == connection.session_id

        connection.session_id = 5
        msg2 = RequestMessage.new(connection)
        assert msg2.session_id == connection.session_id
Example #2
0
    def test_request_message_use_last_session_id(self):
        connection = Connection("localhost", 30015, "Fuu", "Bar")
        connection.session_id = 3

        msg1 = RequestMessage.new(connection)
        assert msg1.session_id == connection.session_id

        connection.session_id = 5
        msg2 = RequestMessage.new(connection)
        assert msg2.session_id == connection.session_id
Example #3
0
    def execute_prepared(self, prepared_statement, multi_row_parameters):
        """
        :param prepared_statement: A PreparedStatement instance
        :param multi_row_parameters: A list/tuple containing list/tuples of parameters (for multiple rows)
        """
        self._check_closed()

        # Convert parameters into a generator producing lists with parameters as named tuples (incl. some meta data):
        parameters = prepared_statement.prepare_parameters(multi_row_parameters)

        while parameters:
            request = RequestMessage.new(
                self.connection,
                RequestSegment(
                    message_types.EXECUTE,
                    (StatementId(prepared_statement.statement_id),
                     Parameters(parameters))
                )
            )
            reply = self.connection.send_request(request)

            parts = reply.segments[0].parts
            function_code = reply.segments[0].function_code
            if function_code == function_codes.SELECT:
                self._handle_select(parts, prepared_statement.result_metadata_part)
            elif function_code in function_codes.DML:
                self._handle_upsert(parts, request.segments[0].parts[1].unwritten_lobs)
            elif function_code == function_codes.DDL:
                # No additional handling is required
                pass
            elif function_code in (function_codes.DBPROCEDURECALL, function_codes.DBPROCEDURECALLWITHRESULT):
                self._handle_dbproc_call(parts, prepared_statement._params_metadata) # resultset metadata set in prepare
            else:
                raise InterfaceError("Invalid or unsupported function code received: %d" % function_code)
Example #4
0
    def _execute_direct(self, operation):
        """Execute statements which are not going through 'prepare_statement' (aka 'direct execution').
        Either their have no parameters, or Python's string expansion has been applied to the SQL statement.
        :param operation:
        """
        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.EXECUTEDIRECT,
                Command(operation)
            )
        )
        reply = self.connection.send_request(request)

        parts = reply.segments[0].parts
        function_code = reply.segments[0].function_code
        if function_code == function_codes.SELECT:
            self._handle_select(parts)
        elif function_code in function_codes.DML:
            self._handle_upsert(parts)
        elif function_code == function_codes.DDL:
            # No additional handling is required
            pass
        elif function_code in (function_codes.DBPROCEDURECALL, function_codes.DBPROCEDURECALLWITHRESULT):
            self._handle_dbproc_call(parts, None)
        else:
            raise InterfaceError("Invalid or unsupported function code received: %d" % function_code)
Example #5
0
    def connect(self):
        with self._socket_lock:
            if self._socket is not None:
                # Socket already established
                return

            self._open_socket_and_init_protocoll()

            # Perform the authenication handshake and get the part
            # with the agreed authentication data
            agreed_auth_part = self._auth_manager.perform_handshake()

            request = RequestMessage.new(
                self,
                RequestSegment(
                    message_types.CONNECT,
                    (
                        agreed_auth_part,
                        ClientId(
                            "pyhdb-%s@%s" % (os.getpid(), socket.getfqdn())
                        ),
                        ConnectOptions(DEFAULT_CONNECTION_OPTIONS)
                    )
                )
            )
            reply = self.send_request(request, no_reconnect=True)

            for segment in reply.segments:
                for part in segment.parts:
                    if part.kind == part_kinds.CONNECTOPTIONS:
                        self.connect_options = part.options
Example #6
0
    def prepare(self, statement):
        """Prepare SQL statement in HANA and cache it
        :param statement; a valid SQL statement
        :returns: statement_id (of prepared and cached statement)
        """
        self._check_closed()
        self._column_types = None
        statement_id = params_metadata = result_metadata_part = None

        request = RequestMessage.new(
            self.connection,
            RequestSegment(message_types.PREPARE, Command(statement)))
        response = self.connection.send_request(request)

        for part in response.segments[0].parts:
            if part.kind == part_kinds.STATEMENTID:
                statement_id = part.statement_id
            elif part.kind == part_kinds.PARAMETERMETADATA:
                params_metadata = part.values
            elif part.kind == part_kinds.RESULTSETMETADATA:
                result_metadata_part = part

        # Check that both variables have been set in previous loop, we need them:
        assert statement_id is not None
        assert params_metadata is not None
        # cache statement:
        self._prepared_statements[statement_id] = PreparedStatement(
            self.connection, statement_id, params_metadata,
            result_metadata_part)
        return statement_id
Example #7
0
    def _execute_direct(self, operation):
        """Execute statements which are not going through 'prepare_statement' (aka 'direct execution').
        Either their have no parameters, or Python's string expansion has been applied to the SQL statement.
        :param operation:
        """
        request = RequestMessage.new(
            self.connection,
            RequestSegment(message_types.EXECUTEDIRECT, Command(operation)))
        reply = self.connection.send_request(request)

        parts = reply.segments[0].parts
        function_code = reply.segments[0].function_code
        if function_code == function_codes.SELECT:
            self._handle_select(parts)
        elif function_code in function_codes.DML:
            self._handle_upsert(parts)
        elif function_code == function_codes.DDL:
            # No additional handling is required
            pass
        elif function_code in (function_codes.DBPROCEDURECALL,
                               function_codes.DBPROCEDURECALLWITHRESULT):
            self._handle_dbproc_call(parts, None)
        else:
            raise InterfaceError(
                "Invalid or unsupported function code received: %d" %
                function_code)
Example #8
0
    def test_request_message_init_with_multiple_segments_as_tuple(self):
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        request_seg_1 = RequestSegment(0)
        request_seg_2 = RequestSegment(1)
        msg = RequestMessage.new(connection, (request_seg_1, request_seg_2))
        assert msg.segments == (request_seg_1, request_seg_2)
Example #9
0
    def prepare(self, statement):
        """Prepare SQL statement in HANA and cache it
        :param statement; a valid SQL statement
        :returns: statement_id (of prepared and cached statement)
        """
        self._check_closed()
        self._column_types = None
        statement_id = params_metadata = result_metadata_part = None

        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.PREPARE,
                Command(statement)
            )
        )
        response = self.connection.send_request(request)

        for part in response.segments[0].parts:
            if part.kind == part_kinds.STATEMENTID:
                statement_id = part.statement_id
            elif part.kind == part_kinds.PARAMETERMETADATA:
                params_metadata = part.values
            elif part.kind == part_kinds.RESULTSETMETADATA:
                result_metadata_part = part

        # Check that both variables have been set in previous loop, we need them:
        assert statement_id is not None
        assert params_metadata is not None
        # cache statement:
        self._prepared_statements[statement_id] = PreparedStatement(self.connection, statement_id,
                                                                    params_metadata, result_metadata_part)
        return statement_id
Example #10
0
    def test_pack():
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        msg = RequestMessage.new(connection, [DummySegment(None)])
        payload = msg.pack()
        packed = payload.getvalue()
        assert isinstance(packed, bytes)

        # Session id
        assert packed[0:8] == b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"

        # Packet count
        assert packed[8:12] == b"\x00\x00\x00\x00"

        # var part length
        assert packed[12:16] == b"\x0A\x00\x00\x00"

        # var part size
        assert packed[16:20] == b"\xE0\xFF\x01\x00"

        # no of segments
        assert packed[20:22] == b"\x01\x00"

        # reserved
        assert packed[22:32] == b"\x00" * 10

        # payload
        assert packed[32:42] == b"\x00" * 10
Example #11
0
    def fetchmany(self, size=None):
        """Fetch many rows from select result set.
        :param size: Number of rows to return.
        :returns: list of row records (tuples)
        """
        self._check_closed()
        if not self._executed:
            raise ProgrammingError("Require execute() first")
        if size is None:
            size = self.arraysize

        result = []
        cnt = 0
        while cnt != size:
            try:
                result.append(next(self._buffer))
                cnt += 1
            except StopIteration:
                break

        if cnt == size or self._received_last_resultset_part:
            # No rows are missing or there are no additional rows
            return result

        request = RequestMessage.new(
            self.connection,
            RequestSegment(message_types.FETCHNEXT, (ResultSetId(self._resultset_id), FetchSize(size - cnt))),
        )
        response = self.connection.send_request(request)

        resultset_part = response.segments[0].parts[1]
        if resultset_part.attribute & 1:
            self._received_last_resultset_part = True
        result.extend(resultset_part.unpack_rows(self._column_types, self.connection))
        return result
Example #12
0
    def test_request_message_init_with_multiple_segments_as_tuple():
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        request_seg_1 = RequestSegment(0)
        request_seg_2 = RequestSegment(1)
        msg = RequestMessage.new(connection, (request_seg_1, request_seg_2))
        assert msg.segments == (request_seg_1, request_seg_2)
Example #13
0
    def connect(self):
        with self._socket_lock:
            if self._socket is not None:
                # Socket already established
                return

            self._open_socket_and_init_protocoll()

            # Perform the authenication handshake and get the part
            # with the agreed authentication data
            agreed_auth_part = self._auth_manager.perform_handshake()

            request = RequestMessage.new(
                self,
                RequestSegment(
                    message_types.CONNECT,
                    (
                        agreed_auth_part,
                        ClientId(
                            "pyhdb-%s@%s" % (os.getpid(), socket.getfqdn())
                        ),
                        ConnectOptions(DEFAULT_CONNECTION_OPTIONS)
                    )
                )
            )
            self.send_request(request)
Example #14
0
    def test_pack(self):
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        msg = RequestMessage.new(connection, [DummySegment(None)])
        payload = msg.pack()
        packed = payload.getvalue()
        assert isinstance(packed, bytes)

        # Session id
        assert packed[0:8] == b"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"

        # Packet count
        assert packed[8:12] == b"\x00\x00\x00\x00"

        # var part length
        assert packed[12:16] == b"\x0A\x00\x00\x00"

        # var part size
        assert packed[16:20] == b"\xE0\xFF\x01\x00"

        # no of segments
        assert packed[20:22] == b"\x01\x00"

        # reserved
        assert packed[22:32] == b"\x00" * 10

        # payload
        assert packed[32:42] == b"\x00" * 10
Example #15
0
    def fetchmany(self, size=None):
        self._check_closed()
        if not self._executed:
            raise ProgrammingError("Require execute() first")
        if size is None:
            size = self.arraysize

        _result = []
        _missing = size

        while bool(self._buffer) and _missing > 0:
            _result.append(self._buffer.popleft())
            _missing -= 1

        if _missing == 0 or self._received_last_resultset_part:
            # No rows are missing or there are no additional rows
            return _result

        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.FETCHNEXT,
                (ResultSetId(self._resultset_id), FetchSize(_missing))
            )
        )
        response = self.connection.send_request(request)

        if response.segments[0].parts[1].attribute & 1:
            self._received_last_resultset_part = True

        resultset_part = response.segments[0].parts[1]
        for row in self._unpack_rows(resultset_part.payload, resultset_part.rows):
            _result.append(row)
        return _result
Example #16
0
    def test_payload_pack(self, autocommit):
        connection = Connection("localhost", 30015, "Fuu", "Bar", autocommit=autocommit)

        msg = RequestMessage.new(connection, [DummySegment(None)])
        payload = BytesIO()
        msg.build_payload(payload)

        assert payload.getvalue() == b"\x00" * 10
Example #17
0
def test_invalid_request(connection):
    request = RequestMessage.new(
        connection,
        RequestSegment(2)
    )

    with pytest.raises(DatabaseError):
        connection.send_request(request)
Example #18
0
    def commit(self):
        self._check_closed()

        request = RequestMessage.new(
            self,
            RequestSegment(message_types.COMMIT)
        )
        self.send_request(request)
Example #19
0
    def commit(self):
        self._check_closed()

        request = RequestMessage.new(
            self,
            RequestSegment(message_types.COMMIT)
        )
        self.send_request(request)
Example #20
0
    def rollback(self):
        self._check_closed()

        request = RequestMessage.new(
            self,
            RequestSegment(message_types.ROLLBACK)
        )
        self.send_request(request)
Example #21
0
    def rollback(self):
        self._check_closed()

        request = RequestMessage.new(
            self,
            RequestSegment(message_types.ROLLBACK)
        )
        self.send_request(request)
Example #22
0
    def test_request_message_use_last_session_id():
        connection = Connection("localhost", 30015, "Fuu", "Bar")
        connection.session_id = 1

        msg = RequestMessage.new(connection)
        assert msg.session_id == connection.session_id

        connection.session_id = 5
        assert msg.session_id == connection.session_id
Example #23
0
    def test_request_message_keep_packet_count(self, get_next_packet_count):
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        msg = RequestMessage.new(connection)
        assert msg.packet_count == 0

        # Check two time packet count of the message
        # but the get_next_packet_count method of connection
        # should only called once.
        assert msg.packet_count == 0
        get_next_packet_count.assert_called_once_with()
Example #24
0
    def test_request_message_keep_packet_count(self, get_next_packet_count):
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        msg = RequestMessage.new(connection)
        assert msg.packet_count == 0

        # Check two time packet count of the message
        # but the get_next_packet_count method of connection
        # should only called once.
        assert msg.packet_count == 0
        get_next_packet_count.assert_called_once_with()
Example #25
0
 def _perform_lob_write_requests(self, unwritten_lobs):
     """After sending incomplete LOB data during an INSERT or UPDATE this method will be called.
     It sends missing LOB data possibly in multiple LOBWRITE requests for all LOBs.
     :param unwritten_lobs: A deque list of LobBuffer instances containing LOB data.
            Those buffers have been assembled in the parts.Parameter.pack_lob_data() method.
     """
     while unwritten_lobs:
         request = RequestMessage.new(
             self.connection, RequestSegment(message_types.WRITELOB, WriteLobRequest(unwritten_lobs))
         )
         self.connection.send_request(request)
Example #26
0
    def test_payload_pack(self, autocommit):
        connection = Connection("localhost",
                                30015,
                                "Fuu",
                                "Bar",
                                autocommit=autocommit)

        msg = RequestMessage.new(connection, [DummySegment(None)])
        payload = BytesIO()
        msg.build_payload(payload)

        assert payload.getvalue() == b"\x00" * 10
Example #27
0
 def _perform_lob_write_requests(self, unwritten_lobs):
     """After sending incomplete LOB data during an INSERT or UPDATE this method will be called.
     It sends missing LOB data possibly in multiple LOBWRITE requests for all LOBs.
     :param unwritten_lobs: A deque list of LobBuffer instances containing LOB data.
            Those buffers have been assembled in the parts.Parameter.pack_lob_data() method.
     """
     while unwritten_lobs:
         request = RequestMessage.new(
             self.connection,
             RequestSegment(message_types.WRITELOB,
                            WriteLobRequest(unwritten_lobs)))
         self.connection.send_request(request)
Example #28
0
def close_result(connection, _resultset_id):

    request = RequestMessage.new(
        connection,
        RequestSegment(message_types.CLOSERESULTSET,
                       (ResultSetId(_resultset_id))))

    response = connection.send_request(request)

    # no exception...
    # no result check...
    # never failed... (what if connection issue...)
    return
Example #29
0
    def close(self):
        with self._socket_lock:
            if self._socket is None:
                raise Error("Connection already closed")

            try:
                request = RequestMessage.new(self, RequestSegment(message_types.DISCONNECT))
                reply = self.send_request(request)
                if reply.segments[0].function_code != function_codes.DISCONNECT:
                    raise Error("Connection wasn't closed correctly")
            finally:
                self._socket.close()
                self._socket = None
Example #30
0
    def close(self):
        with self._socket_lock:
            if self._socket is None:
                raise Error("Connection already closed")

            try:
                request = RequestMessage.new(
                    self, RequestSegment(message_types.DISCONNECT))
                reply = self.send_request(request)
                if reply.segments[0].function_code != \
                   function_codes.DISCONNECT:
                    raise Error("Connection wasn't closed correctly")
            finally:
                self._socket.close()
                self._socket = None
Example #31
0
    def _make_read_lob_request(self, readoffset, readlength):
        """Make low level request to HANA database (READLOBREQUEST).
        Compose request message with proper parameters and read lob data from second part object of reply.
        """
        self._connection._check_closed()

        request = RequestMessage.new(
            self._connection,
            RequestSegment(message_types.READLOB, (ReadLobRequest(
                self._lob_header.locator_id, readoffset, readlength), )))
        response = self._connection.send_request(request)

        # The segment of the message contains two parts.
        # 1) StatementContext -> ignored for now
        # 2) ReadLobReply -> contains some header information and actual LOB data
        data_part = response.segments[0].parts[1]
        # return actual lob container (BytesIO/TextIO):
        return data_part.data
Example #32
0
def drop_statement(connection, statement_id):

    log('psid to drop --> %s' % (hextostr(statement_id)), 4)

    if statement_id is None or connection is None:
        return

    t0 = time.time()

    request = RequestMessage.new(
        connection,
        RequestSegment(message_types.DROPSTATEMENTID,
                       StatementId(statement_id)))

    response = connection.send_request(request)

    t1 = time.time()

    log('psid drop took %s' % (str(round(t1 - t0, 3))), 4)
Example #33
0
    def perform_handshake(self):
        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.AUTHENTICATE,
                Authentication(self.user, {self.method: self.client_key})))
        response = self.connection.send_request(request, no_reconnect=True)

        auth_part = response.segments[0].parts[0]
        if self.method not in auth_part.methods:
            raise Exception(
                "Only unknown authentication methods available: %s" %
                b",".join(auth_part.methods.keys()))

        salt, server_key = Fields.unpack_data(
            BytesIO(auth_part.methods[self.method]))

        self.client_proof = self.calculate_client_proof([salt], server_key)
        return Authentication(self.user, {'SCRAMSHA256': self.client_proof})
Example #34
0
    def fetchmany(self, size=None):
        """Fetch many rows from select result set.
        :param size: Number of rows to return.
        :returns: list of row records (tuples)
        """
        self._check_closed()
        if not self._executed:
            raise ProgrammingError("Require execute() first")
        if size is None:
            size = self.arraysize

        column_names = [column[0] for column in self.description
                        ] if self.description else []

        result = []
        cnt = 0
        while cnt != size:
            try:
                result.append(ResultRow(column_names, next(self._buffer)))
                cnt += 1
            except StopIteration:
                break

        if cnt == size or self._received_last_resultset_part:
            # No rows are missing or there are no additional rows
            return result

        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.FETCHNEXT,
                (ResultSetId(self._resultset_id), FetchSize(size - cnt))))
        response = self.connection.send_request(request)

        resultset_part = response.segments[0].parts[1]
        if resultset_part.attribute & 1:
            self._received_last_resultset_part = True
        result_parts = resultset_part.unpack_rows(self._column_types,
                                                  self.connection)
        for result_part in result_parts:
            result.append(ResultRow(column_names, result_part))
        return result
Example #35
0
    def _make_read_lob_request(self, readoffset, readlength):
        """Make low level request to HANA database (READLOBREQUEST).
        Compose request message with proper parameters and read lob data from second part object of reply.
        """
        self._connection._check_closed()

        request = RequestMessage.new(
            self._connection,
            RequestSegment(
                message_types.READLOB, (ReadLobRequest(self._lob_header.locator_id, readoffset, readlength),)
            ),
        )
        response = self._connection.send_request(request)

        # The segment of the message contains two parts.
        # 1) StatementContext -> ignored for now
        # 2) ReadLobReply -> contains some header information and actual LOB data
        data_part = response.segments[0].parts[1]
        # return actual lob container (BytesIO/TextIO):
        return data_part.data
Example #36
0
def test_tracing_output():
    msg_header = MessageHeader(session_id=5,
                               packet_count=3,
                               payload_length=500,
                               varpartsize=500,
                               num_segments=1,
                               packet_options=0)
    request = RequestMessage(session_id=msg_header.session_id,
                             packet_count=msg_header.packet_count,
                             segments=RequestSegment(
                                 message_types.EXECUTE,
                                 Command('select * from dummy')),
                             header=msg_header)

    pyhdb.tracing = True
    try:
        trace_msg = trace(request)
    finally:
        pyhdb.tracing = False

    assert trace_msg == TRACE_MSG
Example #37
0
    def execute_prepared(self, prepared_statement, multi_row_parameters):
        """
        :param prepared_statement: A PreparedStatement instance
        :param multi_row_parameters: A list/tuple containing list/tuples of parameters (for multiple rows)
        """
        self._check_closed()

        # Convert parameters into a generator producing lists with parameters as named tuples (incl. some meta data):
        parameters = prepared_statement.prepare_parameters(
            multi_row_parameters)

        while parameters:
            request = RequestMessage.new(
                self.connection,
                RequestSegment(message_types.EXECUTE, (StatementId(
                    prepared_statement.statement_id), Parameters(parameters))))
            reply = self.connection.send_request(request)

            parts = reply.segments[0].parts
            function_code = reply.segments[0].function_code
            if function_code == function_codes.SELECT:
                self._handle_select(parts,
                                    prepared_statement.result_metadata_part)
            elif function_code in function_codes.DML:
                self._handle_upsert(
                    parts, request.segments[0].parts[1].unwritten_lobs)
            elif function_code == function_codes.DDL:
                # No additional handling is required
                pass
            elif function_code in (function_codes.DBPROCEDURECALL,
                                   function_codes.DBPROCEDURECALLWITHRESULT):
                self._handle_dbproc_call(parts,
                                         prepared_statement._params_metadata
                                         )  # resultset metadata set in prepare
            else:
                raise InterfaceError(
                    "Invalid or unsupported function code received: %d" %
                    function_code)
Example #38
0
    def perform_handshake(self):
        request = RequestMessage.new(
            self.connection,
            RequestSegment(
                message_types.AUTHENTICATE,
                Authentication(self.user, {self.method: self.client_key})
            )
        )
        response = self.connection.send_request(request, no_reconnect=True)

        auth_part = response.segments[0].parts[0]
        if self.method not in auth_part.methods:
            raise Exception(
                "Only unknown authentication methods available: %s" %
                b",".join(auth_part.methods.keys())
            )

        salt, server_key = Fields.unpack_data(
            BytesIO(auth_part.methods[self.method])
        )

        self.client_proof = self.calculate_client_proof([salt], server_key)
        return Authentication(self.user, {'SCRAMSHA256': self.client_proof})
Example #39
0
def test_invalid_request(connection):
    request = RequestMessage.new(connection, RequestSegment(2))

    with pytest.raises(DatabaseError):
        connection.send_request(request)
Example #40
0
 def test_request_message_init_without_segment(self):
     connection = Connection("localhost", 30015, "Fuu", "Bar")
     msg = RequestMessage.new(connection)
     assert msg.segments == ()
Example #41
0
    def test_request_message_init_with_single_segment(self):
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        request_seg = RequestSegment(0)
        msg = RequestMessage.new(connection, request_seg)
        assert msg.segments == (request_seg, )
Example #42
0
 def test_request_message_init_without_segment():
     connection = Connection("localhost", 30015, "Fuu", "Bar")
     msg = RequestMessage.new(connection)
     assert msg.segments == []
Example #43
0
    def test_request_message_init_with_single_segment():
        connection = Connection("localhost", 30015, "Fuu", "Bar")

        request_seg = RequestSegment(0)
        msg = RequestMessage.new(connection, request_seg)
        assert msg.segments == [request_seg]