At 6:14 PM +1200 7/5/05, Sam Vilain wrote:
I think I'm beginning to like it.
Allow me to suggest one or two further refinements...

  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

FYI, I'm not stuck on the name 'compile'; the method could be called something else. In fact, I still think 'prepare' is more broadly descriptive considering the wide range of things that could be happening inside that method; I see it as ultimately getting ready for the execute() anyway. The problem is that the word 'prepare' is commonly associated with something different, so we're stuck having to find a different word.

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.

Yes, that is true. However, I like for all application calls to go through the Interface module (DBI) since that is what the Interface is for. It is also more practical to go by way of the DBI module because it can do things for you like certain kinds of validation on application input and driver output, so the application or driver respectively doesn't have to do those tests for robustness. Each DBI driver can worry less about that its input is correct and focus more on its actual work. (FYI, a common input/output validation is one of the main things that the 'Rosetta' module does for its own drivers and users. More so in next release v0.46.)

Because you constructed it like this, without reference to a
(possibly unconnected) connection object, then $sth1.prepare is not
available.

I wouldn't worry about that; the proposed DBI would elegantly handle (throw an exception) attempts to invoke methods that depend on an open connection when there is none. People who like to check first will also have a $dbh.is_open() method available to them. I also see the situation as no worse than the current DBI v1 where you can invoke such things as fetchrow_arrayref() on a $sth that hasn't been executed yet.

Oh, and I have another DBI v2 suggestion to add, also following Rosetta design:

1. A $sth should not contain any methods for fetching the result of an executed statement; rather, execute() should return an object when successful that represents its result; you invoke fetching methods on that object. For example:

  my $rlh = $sth->execute();
  my $rowset = $rlh->fetchrow_arrayref();

This approach is a lot more flexible.

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.

You still can. The point of an "abstract syntax tree" is that the original SQL dialect isn't very important to what it contains (and this is how SQL::Routine is); by contrast, a "concrete syntax tree" cares very much about the original syntax and preserves it to the last detail. I don't see a problem here.
...
Except that those AST-like-modules which embed raw SQL fragments (like where-clauses) as a matter of course aren't actually that abstract and could pose a problem; lots of DBI wrappers are this way, unfortunately (but not mine).

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.

Er, I hope you didn't interpret this as the application source code. My point was that the database connection details can be part of the general application configuration file, which is still data and not code. This way, each application can have distinct database settings if it wants to.

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.

Well, I have also decided that I can accept one specific type of flexability on the 'whole module name' thing. That is, if we assume that DBI drivers will commonly have 'DBD::' at the start of their names, users can optionally leave that prefix off, but they still have to spell the rest of the name out in full and with the correct letter case. In this case, when trying to load a driver, DBI would first try the pristine module name it was given, and if a module fails to load by that name, then it will try adding 'DBD::' to the front as an alternative; failing those two, it will croak. But the point is, aside from the text 'DBD::', which is reasonable as it is a general case, there are no hard coded driver names in DBI.

Another suggestion:

2. Unless there is a strong impetus for there being a separate root namespace for DBI drivers, I suggest a better naming scheme would be to put everything under DBI:: instead. For example, DBI::Driver::SQLite or DBI::D::SQLite, or DBI::DBD::SQLite. If this idea is adopted, then that auto-prefix thing I previously mentioned would be changed accordingly. I think that having the standard driver namespace being outside DBI::* is an antiquated notion that bears little resemblence to what is standard in most frameworks. All this said, I'm not stuck on a change here, so do as you will.

-- Darren Duncan

Reply via email to