On 01/05/2013 10:49 AM, Igor Galić wrote:
> 
>> Implied semantics matter a LOT in API design.
> 
> +1
>  
>>>
>>> Check your errors :-)
>> I don't need to check errors, I just need to check whether 'rows' is
>> a
>> table or a nil value in the case of an error. I could've checked if
>> 'err' was anything, but the result is the same.
>>
>> An API which returns (foo, err) should be error checked on the error,
>> not the foo. This style of API will sometimes return a foo in a bad
>> state, and an err to let you know. In your example this is fine, I
>> am just being a pedant because if an API is designed a certain way,
>> we should use it that way :-)
>>
> 
> My take away is that we want mod_dbd bindings in mod_lua, but we
> want the API to be more carefully crafted.
> 
> i
> 
My attempt at humour seems to have failed, so I'll be more to the point.
Yes, calling it acquire rather than open makes sense, and it's a good
suggestion that I have applied to my draft.

Regarding the return values of 'acquire' (dbacquire, as it's currently
called), this, as well as the query/run (or should it be called
select/query? I'm not sure, but running db:select("SELECT...") seems a
bit redundant in my mind) will never return a 'bad state', they will
return nil if an error occurred, followed by an error message. How one
chooses to check for an error, whether it be checking the nil value or
checking for an error message, the result will be the same. However, in
my documentation addition to mod_lua, I have consistently made the
examples check for an error message, so no need to worry there - I was
only being brief in my example snippets in the previous email, apologies.

Return values are as follows:

r:dbacquire(type, connstring): DB handle on success, nil + error on
failure (error is either can't connect, can't load driver or mod_dbd not
loaded)

db:query("SELECT ...."): Result set on success, nil + error on failure
(syntax error, permission issue or db handle not connected to backend)

db:run("DELETE ...."): Number of affected rows on success, nil + error
on failure (same errors as :query)

With regards to how :query should work, this could either be done
synchronously, wherein all rows are fetched at once, or async where rows
are fetched as needed. The sync way is rather easy, but could fill up
more memory than needed, while the async has a smaller footprint but
proves rather difficult to implement, as the darn dbd driver keeps
wanting to free up the result set before it's finished being used
(apr_dbd_get_row keeps segfaulting when I request a row that is out of
bounds... :( ). Also,there is the consideration of what happens if you
query a db, get a result set, close the db handle and try to fetch more
rows - this would most likely result in a segfault, as the db handle
would have been freed when you try to use it again (how to check that?).
Also, getting the number of rows, or even doing: for k, v in pairs(rows)
... proves to be quite difficult with the async method.

What I've pieced together so far would work something like this:

local results, err = db:query("SELECT .....")
it not err then
    -- Async method here:
    local x = 1
    local row = results(x) -- fetch row 1
    while row do
        ....
        x = x + 1
        row = results(x) -- fetch row 2,3,4,5...N
    end

    -- Sync method here:
    local rows = results() -- fetch all rows at once
    for index, row in pairs(rows) do
        ....
    end
end

As usual, suggestions and comments are most welcome!
And as for the inject/prepare stuff, I'm working on a new approach to
that as well, will keep you guys posted.

With regards,
Daniel.

Reply via email to