Darren Duncan wrote:
Okay, considering that using the same name prepare() like this may
confuse some people, here is a refined solution that uses 3 methods
instead; please disregard any contrary statements that I previously made:
I think I'm beginning to like it.
Allow me to suggest one or two further refinements...
# Opt 1: A user that wants the most control can do this (new feature):
my $sth1 = $dbh.compile( $sql_or_ast ); # always sans connection
$sth1.prepare(); # always with connection, even if DBD doesn't use it
$sth1.execute(); # always with connection
To me, the "compiled" form of the STH is related to the driver, but
re-usable between connections; you should be able to use something like;
my $sth1 = DBD::SQLite.compile( $sql_or_ast );
$sth1 = DBI.compile( :statement($sql_or_ast), :driver<SQLite> );
This would give you a STH which is divorced from the actual DB connection
instance. Because you constructed it like this, without reference to a
(possibly unconnected) connection object, then $sth1.prepare is not
available.
You'd then need to use something like;
$sth1.prepare($dbh);
$dbh.prepare($sth1);
Note I also think what you wrote should work, too.
The new feature is if you decide to use compile(); you then give that
method the arguments you would have given to prepare(), and you invoke
prepare() on the result with no arguments; each DBD would decide for
itself how the work is divided between compile() and prepare() with the
limitation that compile() is not allowed to access the database; ideally
the DBD would place as much work there as is possible, which would vary
between Oracle/Pg/etc.
Agreed.
In particular, I don't think that the DB driver should automatically
get a chance to interfere with SQL::Statement; if they want to do that,
then they should specialise SQL::Statement. IMHO.
I am operating under the assumption here that while the new DBI is
designed to effectively support wrapper modules, the wrapper modules
would also be altered from their current DBI-1-geared designs to
accomodate DBI-2.
But still, what do you mean by "interfere"?
Well, when you parse the statement into an AST, the flavour of SQL will
affect how it is parsed and what is allowed. Eg, Oracle has significant
features in some comments (query hints). It also has quirky and somewhat
useless keywords like CONNECT BY.
So, when you ask a DBH connected to a driver to parse something, then it
will use that driver's SQL dialect, if one exists, but I still want to be
able to deal with SQL ASTs without implying a SQL flavour.
Either way, you don't want most applications dealing with this complexity
at all, really.
I am operating under the assumption that this system should work if
there are no external config files that the DBI/DBD would read, and the
application would provide that information; if its in a file, the
application would read it in, or would explicitly tell DBI where it is.
Or at least it should be possible for this to happen, even if a DBD
defaults to look in a default location when it doesn't get the
equivalent from the application.
Absolutely, that must work. But it would still be nice to be able to
config this without digging through the application to see where the
password is written.
Unless there is a design flaw in DBI, we should not have to update that
module just because a new driver came into existence whose name has not
yet been hard-coded into DBI.
See this block for example, from DBI.pm v1.48:
my $dbd_prefix_registry = {
ad_ => { class => 'DBD::AnyData', },
[...]
yaswi_ => { class => 'DBD::Yaswi', },
};
I mean, what's up with that? I assume DBI 1 has this for legacy app
backwards compatability, but DBI version 2 should never have to
accomodate such abhorrent computer programming practices in its core.
Such a great word, abhorrent. So fitting for this case. It sure does
look like an (over&premature&misguided)-optimisation to avoid using the
full module name in an internal hash or something like that. But then
maybe (I&we&none(Gaia)) are missing some context there.
Sam.