Maybe it is just me, but I look at perl code with SQL queries in it and cringe. I don't know what it is about them, maybe just the raw "not perl" look they have.
In some recent projects, I've attemped to modulize all my mySQL calls. I would avoid direct queries at all costs. I'd make up weird subs and stuck them in a "SQL" package so they would not muck up my real perl code.
So sitting back, looking at all of this from the distance, I've come to the conclusion that there are two possible conclusions:
DBI is tremendously powerful and cannot be leashed.or
DBI could be effectively "leashed", or at least the more simplistic usage.
Now maybe I'm crazy (and if so, please tell me and I'll just keep telling myself that SQL queries in perl code is not a bad thing.) I am no DBI Power User, as you can probably tell, so this is a shot in the dark for me: I really do not know what kind of response to expect.
It call comes down the question of Is it feasable to write a reusable module that controls DBI? Is there something similar that has been already written that I have missed?
Just off the top of my head, an example interface (quasi-code):
$db = connect(HOST => $host, PASSWORD => $pass, ..); $result = $db->select(TABLE => $table_name, FIELDS => ["one","two","th +ree"],ORDERBY => "two",DESCENDING => 1); print $result->[0]->{"one"};
Again, thats quasi-code, just an example of what I'm thinking of for an "interface." Personally, I would love that sort interface, and I would assume others would too .. ? Would a module like this be worth throwing together for personal use, or am I moron for not already knowing about something similar to this? Or should I suck it up and leave my raw queries in my code? :-D
I'd appreciate any feedback. Thanks.
-billyak
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Leashing DBI
by Masem (Monsignor) on Jun 27, 2001 at 02:08 UTC | |
Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain | [reply] [d/l] |
by jeroenes (Priest) on Jun 27, 2001 at 16:57 UTC | |
I would like to mention the possibility to use functions instead of constants, and move all these functions to a separate module. This all in the spirit of McConnell's Code Complete. Paraphrased: If you don't like/ grog/ find strange/ consider to be difficult a certain library or structure or whatever, interface it in a separate module. That way, you don't clutter up your main code with things that are unclear and hard to maintain. As a spin-off, you can reuse that module. In this case, you could write functions with very descriptive names just as wrappers for the SQL:
Hope this helps, Jeroen | [reply] [d/l] |
by Masem (Monsignor) on Jun 27, 2001 at 17:53 UTC | |
Now, let me offer to take this one step further, and cleaner: stick all SQL statements into values of a hash in a separate module: I would even go a step farther, possibly being able to class-ify this so that one can make methods that are created at runtime that correspond to the various SQL statements: As well as incorporating prepare_cached details into this class such that things can be speeded up in the SQL side. Notice that there are no dies in the main block of code, and to me this is even more readable that typical cases. Now, these ideas seem rather simple that I would figure there's already a CPAN module for this, but I thought the same of both my Game::Life and Tie::Hash::Stack too...Maybe I'll take a look into developing such a class if nothing currently exists. The only major problem with this is that sometimes the SQL statement and the code that calls it are closely nit. For example, one might try to do a SELECT listing all specific fields (more than 5, say), and using fetchrow_array with a long my() statement to collect them. If one then wanted to add another field, both the SQL statement and the perl code that called it would have to be changed at the same time; too much of a separation between the SQL statement and perl code could be confusing. But another option is to have pseudo variables in the SQL statement as well, and pass parameters by a hash; the class would be able to determine what order of parameters to pass based on placement of the placeholders in teh SQL statements. The only problem going this far is you are now losing some speed aspects for 'beauty' of code, which is always a plausable tradeoff. I might simply try this to see how bad the time difference is, though I suspect most of it is buried in the SQL server details.
Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain | [reply] [d/l] [select] |
by pope (Friar) on Jun 28, 2001 at 03:52 UTC | |
by Masem (Monsignor) on Jun 28, 2001 at 04:00 UTC | |
Re: Leashing DBI
by Abigail (Deacon) on Jun 27, 2001 at 03:56 UTC | |
I wonder whether that's really going to look better using some kind of interface to an SQL query builder. I'm afraid it would get worse. You know, when I started working with SQL, I made myself such a function, I'd pass it a table name, fields, possible other information, and it build an SQL query for me. But soon I found that for anything that isn't a trivial select, writing the SQL yourself was far easier and gave cleaner code. -- Abigail | [reply] [d/l] |
Re: Leashing DBI
by spudzeppelin (Pilgrim) on Jun 27, 2001 at 00:20 UTC | |
Check out some of the new DBIx:: modules (SearchBuilder, Easy, Abstract, CGITables, etc.) on CPAN. I was going through them a couple months ago, many of them appeared to be headed in exactly the same direction you're describing. Spud Zeppelin * spud@spudzeppelin.com | [reply] |
Re: Leashing DBI
by Mungbeans (Pilgrim) on Jun 27, 2001 at 13:29 UTC | |
Problems with SQL in code: My preference is that, for a large application, there should be a single module dealing with each data entity in your database (e.g. invoice.pm for invoices) and this module should provide interfaces to SQL to access data from that table. The perl and SQL are combined in the same module. No outside module should access the data structures other than through this module. This is database centric however and can be tricky to map onto OO. "The future will be better tomorrow." | [reply] [d/l] |
Re: Leashing DBI
by thpfft (Chaplain) on Jun 27, 2001 at 03:52 UTC | |
i think what you describe is exactly the motive behind the DBIx:: set of modules: more perl, less sql, thank you very much. It has adherents and detractors, as will already be apparent. Sometimes they meet peacefully. Sometimes it gets a little more heated. that crunchy texture you may have noticed underfoot and the napalm-in-the-morning smell are residues of last time this topic was aired. | [reply] |
Re: Leashing DBI
by jorg (Friar) on Jun 27, 2001 at 02:33 UTC | |
My preferred way of doing things is to stick the SQL in the database as stored procedures (if the database supports it) or in .sql files which we can invoke through a commandline system call.
| [reply] |
Re: Leashing DBI
by entropy (Sexton) on Jun 27, 2001 at 05:31 UTC | |
Masem hides his SQL statements by defining them elsewhere, whereas my problem is with the surrounding DBI code. Every time I want to look something up I have to do something like: DBI provides a few methods such as selectall_arrayref or whatever... but these methods are not cached, and they only return a few data types (there is no selectall_hashref). What I would like to do is this: All the statements would be compiled with prepare_cached. Does anyone know off hand if any of those DBIx modules support this sort of thing? | [reply] [d/l] [select] |
by jeffa (Bishop) on Jun 27, 2001 at 08:39 UTC | |
Correct me if i am wrong, but that statement is cached. At any rate, please read (dkubb) Re: (2) Outputing data from mySQL query into format for use with HTML::Template if you are tired of building that hash data structure. :) Jeff
| [reply] [d/l] [select] |
by buckaduck (Chaplain) on Jun 27, 2001 at 22:14 UTC | |
And the query result is stored in a Data::Table object. From there it can be extracted or manipulated at will. In a CGI program you can print it out as an HTML table easily: print $table->html; buckaduck | [reply] [d/l] [select] |
Re: Leashing DBI
by mattr (Curate) on Jun 27, 2001 at 16:48 UTC | |
So I can get a field or update arbitrary fields with this kind of thing: but it depends on what I'm trying to do. One report I generate is built around parsing a single complex query. But in a web site I tend to do lots of little things like the code above and the bulk of the code is site logic. I put the getfield and updatefields routines in my library module out of the way so I can get at all the SQL at once if I need to, and I can include that module in other programs too. If you are doing lots of little things it might pay to abstract it out of the center of things and try to see how few subs you can have that are written with SQL. But fact is, I recently sped up a script from 3 minutes to <10 seconds just by doing a complex query instead of little ones interspersed by Perl. SQL engines are fast. | [reply] [d/l] |
Re: Leashing DBI
by mugwumpjism (Hermit) on Jun 27, 2001 at 18:09 UTC | |
Let's step back a bit and look at what you're really trying to do. Databases are about storing "things" in persistent storage. Those "things" are "rows", which loosely represent something. But in OO programming, all "things" are Objects, so what we would like to do would be to store objects, not rows, in databases. There are a couple of approaches: use an OODBMS, or have some way of converting your objects into an RDBMS format. For the latter approach, I strongly recommend the Tangram library in CPAN. Here is a simple "movie database" in Tangram...
As you can see, there is no SQL here and I'm still doing some quite complex queries. A brief investigation of UML is probably worth the effort, too - so you can figure out how to think of concepts such as foreign keys in OO terms. | [reply] [d/l] |
Re: Leashing DBI
by Matt S Trout (Initiate) on Jun 27, 2001 at 20:32 UTC | |
| [reply] |