elixir-ecto/myxql

Using loops in MySQL stored procedures

ibooking-rolf opened this issue · 2 comments

I am having issues using stored-procedures containing loops in MySQL.

When trying to call the following procedure:

DROP PROCEDURE IF EXISTS test_proc;

DELIMITER $$

CREATE PROCEDURE test_proc()
BEGIN
    DECLARE loop_var_exit BOOLEAN DEFAULT FALSE;

    DECLARE temp_test INT;

    DECLARE test_cursor CURSOR FOR SELECT 1;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET loop_var_exit = TRUE;

    OPEN test_cursor;

    read_loop: LOOP
        FETCH test_cursor INTO temp_test;

        IF loop_var_exit THEN
            LEAVE read_loop;
        END IF;
    END LOOP;

    CLOSE test_cursor;

    SELECT 1 AS result;
END$$

DELIMITER ;

using:

Ecto.Adapters.SQL.query!(MyRepo.Repo,  "CALL test_proc()", [])

I get the following error:

iex(1)> Ecto.Adapters.SQL.query!(MyRepo.Repo, "CALL test_proc()", [])

18:45:09.326 [info]  QUERY ERROR db=24.3ms queue=1.0ms idle=802.3ms
CALL test_proc() []
** (MatchError) no match of right hand side value: <<10, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 254, 0, 0, 202, 0>>
    (myxql 0.4.5) lib/myxql/protocol.ex:506: MyXQL.Protocol.decode_resultset/4
    (myxql 0.4.5) lib/myxql/client.ex:204: MyXQL.Client.recv_packets/6
    (myxql 0.4.5) lib/myxql/connection.ex:103: MyXQL.Connection.handle_execute/4
    (db_connection 2.4.1) lib/db_connection/holder.ex:354: DBConnection.Holder.holder_apply/4
    (db_connection 2.4.1) lib/db_connection.ex:1333: DBConnection.run_execute/5
    (db_connection 2.4.1) lib/db_connection.ex:1428: DBConnection.run/6
    (db_connection 2.4.1) lib/db_connection.ex:593: DBConnection.parsed_prepare_execute/5
    (db_connection 2.4.1) lib/db_connection.ex:585: DBConnection.prepare_execute/4

18:45:09.321 [error] GenServer #PID<0.357.0> terminating
** (DBConnection.ConnectionError) client #PID<0.392.0> stopped: ** (MatchError) no match of right hand side value: <<10, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 254, 0, 0, 202, 0>>
    (myxql 0.4.5) lib/myxql/protocol.ex:506: MyXQL.Protocol.decode_resultset/4
    (myxql 0.4.5) lib/myxql/client.ex:204: MyXQL.Client.recv_packets/6
    (myxql 0.4.5) lib/myxql/connection.ex:103: MyXQL.Connection.handle_execute/4
    (db_connection 2.4.1) lib/db_connection/holder.ex:354: DBConnection.Holder.holder_apply/4
    (db_connection 2.4.1) lib/db_connection.ex:1333: DBConnection.run_execute/5
    (db_connection 2.4.1) lib/db_connection.ex:1428: DBConnection.run/6
    (db_connection 2.4.1) lib/db_connection.ex:593: DBConnection.parsed_prepare_execute/5
    (db_connection 2.4.1) lib/db_connection.ex:585: DBConnection.prepare_execute/4

    (db_connection 2.4.1) lib/db_connection/connection.ex:198: DBConnection.Connection.handle_cast/2
    (connection 1.1.0) lib/connection.ex:810: Connection.handle_async/3
    (stdlib 3.13.2) gen_server.erl:680: :gen_server.try_dispatch/4
    (stdlib 3.13.2) gen_server.erl:756: :gen_server.handle_msg/6
    (stdlib 3.13.2) proc_lib.erl:236: :proc_lib.wake_up/3
Last message: {:"$gen_cast", {:stop, #Reference<0.3573120068.4004904964.201146>, %DBConnection.ConnectionError{message: "client #PID<0.392.0> stopped: ** (MatchError) no match of right hand side value: <<10, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 254, 0, 0, 202, 0>>\n    (myxql 0.4.5) lib/myxql/protocol.ex:506: MyXQL.Protocol.decode_resultset/4\n    (myxql 0.4.5) lib/myxql/client.ex:204: MyXQL.Client.recv_packets/6\n    (myxql 0.4.5) lib/myxql/connection.ex:103: MyXQL.Connection.handle_execute/4\n    (db_connection 2.4.1) lib/db_connection/holder.ex:354: DBConnection.Holder.holder_apply/4\n    (db_connection 2.4.1) lib/db_connection.ex:1333: DBConnection.run_execute/5\n    (db_connection 2.4.1) lib/db_connection.ex:1428: DBConnection.run/6\n    (db_connection 2.4.1) lib/db_connection.ex:593: DBConnection.parsed_prepare_execute/5\n    (db_connection 2.4.1) lib/db_connection.ex:585: DBConnection.prepare_execute/4\n", reason: :error, severity: :error}, %MyXQL.Connection{client: %MyXQL.Client{connection_id: 892, sock: {:gen_tcp, #Port<0.23>}}, cursors: %{}, disconnect_on_error_codes: [:ER_MAX_PREPARED_STMT_COUNT_REACHED], last_ref: #Reference<0.3573120068.4004773890.202638>, ping_timeout: 15000, prepare: :unnamed, queries: #Reference<0.3573120068.4004904964.201132>, transaction_status: :idle}}}
State: {MyXQL.Connection, %MyXQL.Connection{client: %MyXQL.Client{connection_id: 892, sock: {:gen_tcp, #Port<0.23>}}, cursors: %{}, disconnect_on_error_codes: [:ER_MAX_PREPARED_STMT_COUNT_REACHED], last_ref: #Reference<0.3573120068.4004773890.202638>, ping_timeout: 15000, prepare: :unnamed, queries: #Reference<0.3573120068.4004904964.201132>, transaction_status: :idle}}

If I remove the loop from the procedure, everything works as expected.

Info:
MySQL server: Community Server 5.7.31
myxql: v0.4.5
ecto: v3.7.1
elixir: v1.11.2-otp-23
erlang: v23.1.5

The Repo is also configured with prepare: :unnamed.

I have tried updating myxql to version 0.5.1 and downgrading to version 0.4.0 but to no avail. Is this a known error, or am I doing something wrong? Thank you!

I believe it is returning a multiple results set and we don’t parse those. We would generate to implement it according to the binary protocol. A PR is welcome!

Closing in favour of PR.