Hi Jon,
Instead of asking "where should I put the SQL?", you might ask "should I
write the raw final SQL?"?
If you have 50 queries, and 10 platforms, you probably don't want to to
maintain 500 text strings in your program. Ideally you want to write 50
queries in some generic format, and get the benefits of your
solution #1, and then have 10 pieces of logic to translate a general
query into a platform's specific SQL, to get the benefits of solution #2.
What we use internally here represents each query (basically) as a table
and a series of key-value pairs. One layer expands the key-value pairs
to do things like add required joins, and a second takes that and writes
an actual SQL string.
Writing a good layer like that can be complicated, depending on how
hairy your SQL gets. There are a ton of modules on CPAN which let you
work with a database w/o writing the raw SQL, like Class::DBI. There
are a few which try to re-write SQL from one platform to another, which
might give you what you need with minimal code changes.
If you do write your own, the DBI module has a lot of catalog methods to
let you examine your database. You could have your core subroutine
check the data type of fields passed-in and handle boolean values
specially, for instance, in a generic way. We use these and actual
queries to the data dictionary of the given database to make the SQL
writer "smart".
Scott Smith
Informatics
Genome Sequencing Center
Washington University School of Medicine
David Dooling wrote:
Care to respond?
----- Forwarded message from Jon Lapham <[EMAIL PROTECTED]> -----
Date: Fri, 18 Feb 2005 16:37:16 -0200
From: Jon Lapham <[EMAIL PROTECTED]>
Subject: elegent way to handle "pluggable" backend servers?
To: dbi-users@perl.org
Reply-To: [EMAIL PROTECTED]
My DBI perl application needs to support many database servers and
versions, but will only use one database server per installation. IE:
one customer may be using MySQL v3.xx, while another has PgSQL v7.4,
while another has Oracle... etc. My application needs to work for them
all, with minimal fuss.
As an example of why this is necessary, MySQL v<4 does not support
boolean variables, and date handling between databases (and different
versions of the same database) are often different.
I would like to ask your opinion(s) on which approach to take for coding
this backend server "plugablility". It seems to me that there are a
number of approaches.
1) The first idea would be to simple wrap all SQL in some conditional in
the main body of the code, [or pseudocode in this case :) ]
if ($dbserver eq 'MySQL' and $dbversion == 3.23) {
$SQL = 'SELECT * FROM blah WHERE active=1';
} elsif ($dbserver eq 'PgSQL' and $dbversion == 7.4) {
$SQL = 'SELECT * FROM blah WHERE active';
} elsif (etc...) {
...
}
$result = $conn->prepare($SQL);
$result->execute();
Okay, this has the advantage that all the SQL for all the supported
backends sits easy to see in the main code body. Disadvantage is that
it is ugly as sin making your main body code harder to follow, imagine
if you wanted to support 20 database backend-version combinations?
2) But the SQL into a subroutine, held in an external module. One
module for each database-version combo you want to support. Then, your
main body code would look like:
$SQL = &db_some_query();
$result = $conn->prepare($SQL);
$result->execute();
...where the subroutine &db_some_query() exists in a bunch of modules
(ie: SQLpgsql_7_4.pm, SQLmysql_3_23.pm, SQLoracle_x_xx, etc) with only
the appropriate on loaded earier in the app.
The advantage here is that it is extensible, more database-versions
supported simply means creating more SQL* modules. The disadvantage is
that these modules could become easily out of sync... nightmare in terms
of maintainablity. Another disadvantage is that since the main body
code contains a subroutine call rather than the actual SQL code, it is
hard to see what is happening in the main body code, you would
continually need to refer to the appropriate module.
Any opinions? Is there another approach that I should think about? Has
anyone encountered this situation before?
Thanks!!!!
-Jon