I'm not sure I'd call 30% a modest improvement. :-) That's a huge
difference when you're talking lots of transactions.
Regarding the API, I just want to point out that 'id = :id' is not my
syntax - it's pervasive in DB adapters and ORM's alike. Hence the
reason I naively tried it in Sequel and stumbled on it raising an OCI
error ("not all variables bound").
I think there are a couple things that are getting intertwined:
1) My proposal to extend the Sequel syntax - bind vars or not - to
support :named placeholders like other DB toolsets
2) Your concern that bind variables can be enabled/disabled per-query
since some adapters (or queries) may not want to use them
3) Backwards compatibility/spec/adapter concerns (I'm a huge proponent
of backwards compat, so let's assume that one will be solved)
Regarding #1, let me try to show why this is really powerful. Here's
a real snippet from our codebase:
curs = conn.parse("SELECT lb.* FROM
(SELECT rownum as rn, a.* FROM
(SELECT * FROM #{table_name}
WHERE game_type_id = :game_type_id
AND platform_id = :platform_id
AND rank >= :rank-:num_above_below
AND rank <= :rank+:num_above_below
ORDER BY rank) a) lb,
(SELECT rn from
(SELECT rownum as rn, b.player_id FROM
(SELECT player_id FROM #{table_name}
WHERE game_type_id = :game_type_id
AND platform_id = :platform_id
AND rank >= :rank-:num_above_below
AND rank <= :rank+:num_above_below
ORDER BY rank) b)
WHERE player_id = :player_id) p_rownum
WHERE lb.rn >=
p_rownum.rn-:num_above_below AND lb.rn <= p_rownum.rn+:num_above_below
ORDER BY lb.rank", sql_args])
sql_args = {:game_type_id => game_type_id,
:platform_id => platform_id,
:player_id => player_id,
:rank => player.rank,
:num_above_below => num_above_below}
You'll notice that the bind params are reused multiple times in the
statement - :player_id, :num_above_below, etc. (That query is highly-
tuned c/o my team's DBA)
When that query was first written, the programmer used ?'s and
positional binding, and it was a mess. You couldn't tell which ? went
with which parameter, and it actually had a bug since the wrong one
was bound to the wrong position, and it took a good long while to
figure out.
So in this case, your suggestion of wrapping the existing API:
dataset.bindfilt('id = :id', :id=>1) == dataset.filter('id = ?', :
$id).bind(:id=>1)
Doesn't work, since it's the *:named placeholder itself* that's so
important. Replacing it with ?'s results in the problems I mentioned
above.
2) Regarding enabling/disabling bind vars, as a variant of your idea,
how about this:
# No bind variables (default behavior remains unchanged)
User.filter('id = ?', 14).all
User.filter('id = :id', :id => 14).all
User.filter('lower(city) like lower(:search) or lower(state) like
lower(:search)', :search => string).all
# Enable bind variables by calling bind()
User.filter('id = ?', 14).bind.all
User.filter('id = :id', :id => 14).bind.all
# bind() accepts delayed bind args too
User.filter('lower(city) like lower(:search) or lower(state) like
lower(:search)').bind(:search => string).all
Additionally, how about an adapter setting (off by default) to
globally always use bind()?
DB = Sequel.connect(..., :logger => ..., :always_bind_variables =>
true) # or whatever
Then a person could still disable it per-query with bind(false):
User.filter('id = ?', 14).bind(false).all
This way we get the "best of all worlds."
Finally, there's no reason why the existing API couldn't remain around
for compat, and this stuff could all be shortcuts to it. But
the :named placeholders would have to go in core since they're in the
sql string like ? is.
Thoughts?
-Nate
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sequel-talk" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/sequel-talk?hl=en
-~----------~----~----~----~------~----~------~--~---