Search code examples
databasesqliteeiffelagents

Eiffel sqlite call with extra parameters


I have copied some code from an example for accessing an sqlite database. It uses an agent to get the returned rows:

    check_db (input_line: STRING)

    local

        df_db:       SQLITE_DATABASE
        df_db_query: SQLITE_QUERY_STATEMENT

        test_val: STRING

    do

        test_val := "whatever"

        create df_db.make_open_read_write ("Large.db")

        create df_db_query.make ("SELECT * FROM test_table WHERE test_val =%
                    % :TEST_VAL%
                    % ;", df_db)

        check df_db_query_is_compiled: df_db_query.is_compiled
            end

        df_db_query.execute_with_arguments (agent (returned_row: SQLITE_RESULT_ROW): BOOLEAN
                do
                    if returned_row.is_null (1) then
                        insert_into_db
                    end
                end,
            << create {SQLITE_STRING_ARG}.make  (":TEST_VAL", test_val) >>)

    end -- check_db

The problem I have is that I would like to pass input_line to the procedure insert_into_db. The inline procedure used by execute_with_arguments isn't able to see any variables outside its scope, but I presume there must be a way to pass an extra parameter to it? Everything I have tried simply refuses to compile with syntax errors.

In this case, I simply want to add a database entry if it doesn't already exist, but I can easily see the case where I would want to send the returned row along with some extra data to another procedure, so it must be doable.


Solution

  • As you correctly point out, at the moment, local variables in Eiffel are not automatically passed into inline agents. The solution is to add explicit formal arguments to an inline agent and to pass the corresponding actual arguments to it.

    The inline agent from the example can be adapted as follows (the outer context with the argument input_line is omitted for brevity):

    agent (returned_row: SQLITE_RESULT_ROW; s: STRING): BOOLEAN
        do
                -- `s` is attached to `input_line` here.
            if returned_row.is_null (1) then
                insert_into_db
            end
        end (?, input_line)
    

    In addition to the formal argument s that will get the value of input_line, you can see an explicit list of actual arguments (?, input_line). The question mark denotes an open argument, that will be passed to the agent by execute_with_arguments as before. input_line stands for a closed argument.

    When the list has no closed arguments, as in the original code, it can be omitted. However, one could have written (?) after the keyword end of the inline agent in the original code to be absolutely explicit.