You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl-cvs@perl.apache.org by ri...@apache.org on 2001/02/12 10:21:26 UTC
cvs commit: modperl-site/embperl Changes.pod.46.html IntroEmbperlObject.pod.1.html IntroEmbperlObject.pod.2.html IntroEmbperlObject.pod.3.html IntroEmbperlObject.pod.4.html IntroEmbperlObject.pod.5.html IntroEmbperlObject.pod.6.html IntroEmbperlObject.pod.7.html IntroEmbperlObject.pod.8.html IntroEmbperlObject.pod.9.html IntroEmbperlObject.pod.cont.html Recordset.pod.1.html Recordset.pod.10.html Recordset.pod.11.html Recordset.pod.12.html Recordset.pod.13.html Recordset.pod.14.html Recordset.pod.15.html Recordset.pod.2.html Recordset.pod.3.html Recordset.pod.4.html Recordset.pod.5.html Recordset.pod.6.html Recordset.pod.7.html Recordset.pod.8.html Recordset.pod.9.html Recordset.pod.cont.html TipsAndTricks.pod.1.html TipsAndTricks.pod.2.html TipsAndTricks.pod.3.html TipsAndTricks.pod.4.html TipsAndTricks.pod.5.html TipsAndTricks.pod.6.html TipsAndTricks.pod.7.html TipsAndTricks.pod.8.html TipsAndTricks.pod.cont.html
richter 01/02/12 01:21:26
Added: embperl Changes.pod.46.html IntroEmbperlObject.pod.1.html
IntroEmbperlObject.pod.2.html
IntroEmbperlObject.pod.3.html
IntroEmbperlObject.pod.4.html
IntroEmbperlObject.pod.5.html
IntroEmbperlObject.pod.6.html
IntroEmbperlObject.pod.7.html
IntroEmbperlObject.pod.8.html
IntroEmbperlObject.pod.9.html
IntroEmbperlObject.pod.cont.html
Recordset.pod.1.html Recordset.pod.10.html
Recordset.pod.11.html Recordset.pod.12.html
Recordset.pod.13.html Recordset.pod.14.html
Recordset.pod.15.html Recordset.pod.2.html
Recordset.pod.3.html Recordset.pod.4.html
Recordset.pod.5.html Recordset.pod.6.html
Recordset.pod.7.html Recordset.pod.8.html
Recordset.pod.9.html Recordset.pod.cont.html
TipsAndTricks.pod.1.html TipsAndTricks.pod.2.html
TipsAndTricks.pod.3.html TipsAndTricks.pod.4.html
TipsAndTricks.pod.5.html TipsAndTricks.pod.6.html
TipsAndTricks.pod.7.html TipsAndTricks.pod.8.html
TipsAndTricks.pod.cont.html
Log:
- New documenation
Revision Changes Path
1.1 modperl-site/embperl/Changes.pod.46.html
Index: Changes.pod.46.html
===================================================================
<HTML>
<HEAD>
<TITLE>0.10beta Jan 18 1997</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="0_10beta_Jan_18_1997">0.10beta Jan 18 1997</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Changes.pod.cont.html">CONTENT</a>] [<a href="Changes.pod.45.html">PREV (0.10b-beta Jan 23 1997)</a>] <br><hr>
<P>
<PRE> - first public beta release
</PRE>
<p>[<a href="" >HOME</a>] [<a href="Changes.pod.cont.html">CONTENT</a>] [<a href="Changes.pod.45.html">PREV (0.10b-beta Jan 23 1997)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.1.html
Index: IntroEmbperlObject.pod.1.html
===================================================================
<HTML>
<HEAD>
<TITLE>Introduction</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Introduction">Introduction</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.cont.html">PREV (Introduction to EmbperlObject - Content)</a>] [<a href="IntroEmbperlObject.pod.2.html">NEXT (Getting Started)</a>] <br> <UL>
<LI><A href="IntroEmbperlObject.pod.1.html#Motivation_Constructing_Modular">Motivation: Constructing Modular Websites</A>
</UL>
<hr>
<P>
This tutorial is intended as a complement to the Embperl documentation, not
a replacement. We assume a basic familiarity with Apache, mod_perl, and
Perl, and the Embperl documentation. No prior experience with EmbperlObject
is assumed. The real purpose here is to give a clearer idea of how
EmbperlObject can help you to build large websites. We give example code
which could serve as a starting template for your own projects, and hints
about best practices which have come out of real experience using the
toolkit. As always, there is more than one way to do it!
<P>
Since EmbperlObject is an evolving tool, it is likely that these design
patterns will evolve over time, and it is recommended that the reader check
back on the Embperl website for new versions from time to time.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Motivation_Constructing_Modular">Motivation: Constructing Modular Websites</A></H2>
<P>
Embperl is a tool which allows you to embed Perl code in your HTML
documents. As such, it could by itself handle just about everything you
need to do with your website. So what is the point of EmbperlObject? What
does it give us that we don't already get with basic Embperl?
<P>
As often seems to be the case with Perl, the answer has to do with
laziness. We would all like the task of building websites to be as simple
as possible. Anyone who has had to build a non-trivial site using pure HTML
will have quickly experienced the irritation of having to copy-and-paste
common code between documents - stuff like navigation bars and table
formats. We have probably all wished for an ``include'' HTML tag.
EmbperlObject goes a long way toward solving this problem, without
requiring the developer to resort to a lot of customized Perl code.
<P>
In a nutshell, EmbperlObject extends Embperl by enabling the construction
of websites in a modular, or object-oriented, fashion. I am using the term
``object-oriented'' (OO) loosely here in the context of inheritance and
overloading, but you don't really need to know anything about the OO
paradigm to benefit from EmbperlObject. As you will see from this short
tutorial, it is possible to benefit from using EmbperlObject with even a
minimal knowledge of Perl. With just a little instruction, in fact, pure
HTML coders could use it to improve their website architecture. Having said
that, however, EmbperlObject also provides for more advanced OO
functionality, as we'll see later.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.cont.html">PREV (Introduction to EmbperlObject - Content)</a>] [<a href="IntroEmbperlObject.pod.2.html">NEXT (Getting Started)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.2.html
Index: IntroEmbperlObject.pod.2.html
===================================================================
<HTML>
<HEAD>
<TITLE>Getting Started</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Getting_Started">Getting Started</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.1.html">PREV (Introduction)</a>] [<a href="IntroEmbperlObject.pod.3.html">NEXT (Hello World)</a>] <br> <UL>
<LI><A href="IntroEmbperlObject.pod.2.html#Configuring_F_httpd_conf_">Configuring <EM>httpd.conf</EM></A>
</UL>
<hr>
<P>
We'll assume here that you've successfully installed the latest Apache,
mod_perl and Embperl on your system. That should all be relatively painless
- problems normally occur when mixing older versions of one tool with later
versions of another. If you can, try to download the latest versions of
everything.
<P>
Having done all that, you might want to get going with configuring a
website. The first thing you need to do is set up the Apache config file,
usually called <EM>httpd.conf</EM>.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Configuring_F_httpd_conf_">Configuring <EM>httpd.conf</EM></A></H2>
<P>
The following is an example configuration for a single virtual host to use
EmbperlObject. There are, as usual, different ways to do this; but if you
are starting from scratch then it may be useful as a template. It works
with the later versions of Apache (1.3.6 and up). Obviously, substitute
your own IP address and domain name.
<P>
<PRE> NameVirtualHost 10.1.1.3:80
</PRE>
<P>
<PRE> <VirtualHost 10.1.1.3:80>
ServerName www.mydomain.com
ServerAdmin webmaster@mydomain.com
DocumentRoot /www/mydomain/com/htdocs
DirectoryIndex index.html
ErrorLog /www/mydomain/com/logs/error_log
TransferLog /www/mydomain/com/logs/access_log
PerlSetEnv EMBPERL_ESCMODE 0
PerlSetEnv EMBPERL_OPTIONS 16
PerlSetEnv EMBPERL_MAILHOST mail.mydomain.com
PerlSetEnv EMBPERL_OBJECT_BASE base.html
PerlSetEnv EMBPERL_OBJECT_FALLBACK notfound.html
PerlSetEnv EMBPERL_DEBUG 0
</VirtualHost>
</PRE>
<P>
<PRE> # Set EmbPerl handler for main directory
<Directory "/www/mydomain/com/htdocs/">
<FilesMatch ".*\.(html)$">
SetHandler perl-script
PerlHandler HTML::EmbperlObject
Options ExecCGI
</FilesMatch>
</Directory>
</PRE>
<P>
Note that you can change the file extension in the FilesMatch directive,
for example if you like .epl as a file extension. Personally, I use .html
simply because I can edit files using my favorite editor (emacs) and it
will automatically load html mode. Plus, this may be a minor thing - but
using .html rather than a special extension such as .epl adds a small
amount of security to your site since it provides no clue that the website
is using Embperl. If you're careful about the handling of error messages,
then there never be any indication of this. These days, the less the script
kiddies can deduce about you, the better...
<P>
So how does all this translate into a real website?
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.1.html">PREV (Introduction)</a>] [<a href="IntroEmbperlObject.pod.3.html">NEXT (Hello World)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.3.html
Index: IntroEmbperlObject.pod.3.html
===================================================================
<HTML>
<HEAD>
<TITLE>Hello World</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Hello_World">Hello World</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.2.html">PREV (Getting Started)</a>] [<a href="IntroEmbperlObject.pod.4.html">NEXT (Website-Global Variables)</a>] <br><hr>
<P>
The file specified by the EMBPERL_OBJECT_BASE apache directive (usually
called <EM>base.html</EM>) is the lynchpin of how EmbperlObject operates. Whenever a request comes
in for any page on this website, Emperl will look for <EM>base.html</EM> - first in the same directory as the request, and if not found there then
working up the directory tree to the root dir of the website. For example,
if a request comes in for <A
HREF="http://www.yoursite.com/foo/bar/file.html,">http://www.yoursite.com/foo/bar/file.html,</A>
then Embperl first looks for <EM>/foo/bar/base.html</EM>. If it doesn't find <EM>base.html</EM> there, then it looks in <EM>/foo/base.html</EM>. If no luck, then finally
<EM>/base.html</EM>. (These paths are all relative to the document root for the website). What
is the point of all this?
<P>
In a nutshell, <EM>base.html</EM> is a template for giving a common look-and-feel to your web pages. This
file is what is actually used to build the response to any request,
regardless of the actual filename which was asked for. So even if <EM>file.html</EM> was requested,
<EM>base.html</EM> is what is actually executed. <EM>base.html</EM> is a normal file containing valid HTML mixed with Perl code, but with a
couple of small differences. Here's a simple 'Hello World' example of this
approach:
<P>
<EM>/base.html</EM>
<P>
<PRE> <HTML>
<HEAD>
<TITLE>Some title</TITLE>
</HEAD>
<BODY>
Joe's Website
<P>
[- Execute ('*') -]
</BODY>
</HTML>
</PRE>
<P>
<EM>/hello.html</EM>
<P>
<PRE> Hello world!
</PRE>
<P>
Now, if the file <A
HREF="http://www.yoursite.com/hello.html">http://www.yoursite.com/hello.html</A>
is requested, then
<EM>base.html</EM> is what will actually get executed initially. So where does the file <EM>hello.html</EM> get into the picture? Well, the key is the '*' parameter in the call to
<CODE>Execute().</CODE> '*' is a special filename, only used in <EM>base.html</EM>. It means, literally, ``the filename which was actually requested''.
<P>
What you will see if you try this example is something like this:
<P>
<PRE> Joe's Website
</PRE>
<P>
<PRE> Hello world!
</PRE>
<P>
As you can see here, the text ``Joe's Website'' is from <EM>base.html</EM> and the ``Hello world!'' is from <EM>hello.html</EM>.
<P>
This architecture also means that only <EM>base.html</EM> has to have the boilerplate code which every HTML file normally needs to
contain - namely the <HTML> <BODY>, </HTML> and so on. Since the '*' file is simply inserted into the code,
all it needs to contain is the actual content which is specific to that
file. Nothing else is necessary, because <EM>base.html</EM> has all the standard HTML trappings. Of course, you'll probably have more
interesting content, but you get the point.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.2.html">PREV (Getting Started)</a>] [<a href="IntroEmbperlObject.pod.4.html">NEXT (Website-Global Variables)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.4.html
Index: IntroEmbperlObject.pod.4.html
===================================================================
<HTML>
<HEAD>
<TITLE>Website-Global Variables</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Website_Global_Variables">Website-Global Variables</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.3.html">PREV (Hello World)</a>] [<a href="IntroEmbperlObject.pod.5.html">NEXT (Modular Files)</a>] <br><hr>
<P>
Now let's look at a slightly more interesting example. When you create Perl
variables in Embperl usually, their scope is the current file; so, they are
effectively ``local'' to that file. When you come to split your website up
into modules, however, it quickly becomes apparent that it is very useful
to have variables which are global to the website, i.e. shared between
multiple files.
<P>
To achieve this, EmbperlObject has special object which is automatically
passed to every page as it is executed. This object is usually referred to
as the ``Request'' object, because we get one of these objects created for
every document request that the web server receives. This object is passed
in on the stack, so you can retrieve it using the Perl ``shift'' statement.
This object is also automatically destroyed after the request, so the
Request object cannot be used to store data between requests. The idea is
that you can store variables which are local to the current request, and
shared between all documents on the current website; plus, as we'll see
later, we can also use it to call object methods. For example, Let's say
you set up some variables in <EM>base.html</EM>, and then use them in <EM>file.html</EM>:
<P>
<EM>/base.html</EM>
<P>
<PRE> <HTML>
<HEAD>
<TITLE>Some title</TITLE>
</HEAD>
[-
$req = shift;
$req->{webmaster} = 'John Smith'
-]
<BODY>
[- Execute ('*') -]
</BODY>
</HTML>
</PRE>
<P>
<EM>/file.html</EM>
<P>
<PRE> [- $req = shift -]
Please send all suggestions to [+ $req->{webmaster} +].
</PRE>
<P>
You can see that EmbperlObject is allowing us to set up global variables in
one place, and share them throughout the website. If you place <EM>base.html</EM> in the root document directory, you can have any number of other files in
this and subdirectories, and they will all get these variables whenever
they are executed. No matter which file is requested, <EM>/base.html</EM> is executed first, and then the requested file.
<P>
You don't even need to include the requested '*' file, but the usual case
would be to do so - it would be a little odd to completely ignore the
requested file!
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.3.html">PREV (Hello World)</a>] [<a href="IntroEmbperlObject.pod.5.html">NEXT (Modular Files)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.5.html
Index: IntroEmbperlObject.pod.5.html
===================================================================
<HTML>
<HEAD>
<TITLE>Modular Files</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Modular_Files">Modular Files</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.4.html">PREV (Website-Global Variables)</a>] [<a href="IntroEmbperlObject.pod.6.html">NEXT (Modular File Inheritance)</a>] <br><hr>
<P>
The previous example is nice, it demonstrates the basic ability to have
website-wide variables set up in <EM>base.html</EM> and then automatically shared by all other files. Leading on from this, we
probably want to split up our files, for both maintainability and
readability. For example, a non-trivial website will probably define some
website-wide constants, perhaps some global variables, and maybe also have
some kind of initialization code which has to be executed for every page
(e.g. setting up a database connection). We could put all of this in <EM>base.html</EM>, but this file would quickly begin to look really messy. It would be nice
to split this stuff out into other files. For example:
<P>
<EM>/base.html</EM>
<P>
<PRE> <HTML>
[- Execute ('constants.html')-]
[- Execute ('init.html')-]
<HEAD>
<TITLE>Some title</TITLE>
</HEAD>
<BODY>
[- Execute ('*') -]
</BODY>
[- Execute ('cleanup.html') -]
</HTML>
</PRE>
<P>
<EM>/constants.html</EM>
<P>
<PRE> [-
$req = shift;
$req->{bgcolor} = "white";
$req->{webmaster} = "John Smith";
$req->{website_database} = "mydatabase";
-]
</PRE>
<P>
<EM>/init.html</EM>
<P>
<PRE> [-
$req = shift;
# Set up database connection
use DBI;
use CGI qw(:standard);
$dsn = "DBI:mysql:$req->{website_database}";
$req->{dbh} = DBI->connect ($dsn);
-]
</PRE>
<P>
<EM>/cleanup.html</EM>
<P>
<PRE> [-
$req = shift;
# Close down database connection
$req->{dbh}->disconnect();
-]
</PRE>
<P>
You can see how this would be useful, since every page on your site now has
available a database connection, in $req->{dbh}. Also notice that we
have a <EM>cleanup.html</EM> file which is always executed at the end - this is very useful for cleaning
up, shutting down connections and so on.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.4.html">PREV (Website-Global Variables)</a>] [<a href="IntroEmbperlObject.pod.6.html">NEXT (Modular File Inheritance)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.6.html
Index: IntroEmbperlObject.pod.6.html
===================================================================
<HTML>
<HEAD>
<TITLE>Modular File Inheritance</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Modular_File_Inheritance">Modular File Inheritance</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.5.html">PREV (Modular Files)</a>] [<a href="IntroEmbperlObject.pod.7.html">NEXT (Subroutines in EmbperlObject)</a>] <br><hr>
<P>
To recap, we have seen how we can break our site into modules which are
common across multiple files, because they are automatically included by <EM>base.html</EM>. Inheritance is a way in which we can make our websites even more modular.
<P>
Although the concept of inheritance is one that stems from the
object-oriented paradigm, you really don't need to be an OO guru to
understand it. We will demonstrate the concept through a simple example,
leading on from the previous one.
<P>
Say you wanted different parts of your website to have different <TITLE> tags. You could set the title in each page manually, but if you
had a number of different pages in each section, then this would quickly
get tiresome. Now we could split off the <HEAD> section into its own file, just like <EM>constants.html</EM> and <EM>init.html</EM>, right? But so far, it looks like we are stuck with a single <EM>head.html</EM> file for the entire website, which doesn't really help much.
<P>
The answer lies in subdirectories. This is the key to unlocking
inheritance, and one of the most powerful features of EmbperlObject. You
may use subdirectories currently in your website design, maybe for purposes
of organization and maintenance. But here, subdirectories actually enable
you to override files from upper directories. This is best demonstrated by
example (simplified to make this specific point clearer - assume <EM>constants.html</EM>, <EM>init.html</EM>
and <EM>cleanup.html</EM> are the same as in the previous example):
<P>
<EM>/base.html</EM>
<P>
<PRE> <HTML>
[- Execute ('constants.html')-]
[- Execute ('init.html')-]
<HEAD>
[- Execute ('head.html')-]
</HEAD>
<BODY>
[- Execute ('*') -]
</BODY>
[- Execute ('cleanup.html') -]
</HTML>
</PRE>
<P>
<EM>/head.html</EM>
<P>
<PRE> <TITLE>Joe's Website</TITLE>
</PRE>
<P>
<EM>/contact/head.html</EM>
<P>
<PRE> <TITLE>Contacting Joe</TITLE>
</PRE>
<P>
Assume here that we have an <EM>index.html</EM> file in each directory that does something useful. The main thing to focus
on here is
<EM>head.html</EM>. You can see that we have one instance of this file in the root directory,
and one in a subdirectory, namely
<EM>/contact/head.html</EM>. Here's the neat part: When a page is requested from your website,
EmbperlObject will search automatically for
<EM>base.html</EM> first in the same directory as the requested page. If it doesn't find it
there, then it tracks back up the directory tree until it does find the
file. But then, when executing <EM>base.html</EM>, any files which are Executed (such as <EM>head.html</EM>) are first looked for in the <STRONG>original directory</STRONG> of the requested file. Again, if the file is not found there, then
EmbperlObject tracks back up the directory tree.
<P>
So what does this mean exactly? Well, if we have a subdirectory, then we
can if we want just have the usual <EM>index.html</EM> file and nothing else. In that case, all the files included by <EM>base.html</EM> will be found in the root document directory. But if we redefine <EM>head.html</EM>, as in our example, then EmbperlObject will pick up that version of the
file whenever we are in the /contact/ subdirectory.
<P>
That is inheritance in action. In a nutshell, subdirectories inherit files
such as <EM>head.html</EM>, <EM>constants.html</EM> and so on from upper, ``parent'' directories. But if we want, we can
redefine any of these files in our subdirectories, thus specializing that
functionality for that part of our website. If we had 20 .html files in
/contact/, then loading any one of them would automatically get
<EM>/contact/head.html</EM>.
<P>
This is all very cool, but there is one more wrinkle. Let's say we want to
redefine <EM>init.html</EM>, because there is some initialization which is specific to the /contact/
subdirectory. That's fine, we could create <EM>/contact/init.html</EM> and that file would be loaded instead of
<EM>/init.html</EM> whenever a file is requested from the /contact/ subdir. But this also means
that the initialization code which is in
<EM>/init.html</EM> would never get executed, right? That's bad, because the base version of
the file does a lot of useful set up. The answer is simple: For cases like
this, we just make sure and call the parent version of the file at the
start. For example:
<P>
<EM>/contact/init.html</EM>
<P>
<PRE> [- Execute ('../init.html') -]
</PRE>
<P>
<PRE> [-
# Do some setup specific to this subdirectory
-]
</PRE>
<P>
You can see that the very first thing we do here is to Execute the parent
version of the file (i.e. the one in the immediate parent directory). Thus
we can ensure the integrity of the basic initialization which every page
should receive.
<P>
EmbperlObject is very smart about this process. Say, for example, we have a
situation where we have several levels of subdirectory; then, say we only
redefine <EM>init.html</EM> in one of the deeper levels, say
<EM>/sub/sub/sub/init.html</EM>. Now, if this file tries to Execute
<EM>../init.html</EM>, there may not be any such file in the immediate parent directory - so
EmbperlObject automatically tracks back up the directories until it finds
the base version, <EM>/init.html</EM>. So, for any subdirectory level in your website, you only have to redefine
those files which are specific to this particular area. This results in a
much cleaner website.
<P>
You may break your files up into whatever level of granularity you want,
depending on your needs. For instance, instead of just
<EM>head.html</EM> you might break it down into <EM>title.html</EM>,
<EM>metatags.html</EM> and so on. It's up to you. The more you split it up, the more you can
specialize in each of the subdirectories. There is a balance however,
because splitting things up too much results in an overly fragmented site
that can be harder to maintain. Moderation is the key - only split out
files if they contain a substantial chunk of code, or if you know that you
need to redefine them in subdirectories, generally speaking.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.5.html">PREV (Modular Files)</a>] [<a href="IntroEmbperlObject.pod.7.html">NEXT (Subroutines in EmbperlObject)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.7.html
Index: IntroEmbperlObject.pod.7.html
===================================================================
<HTML>
<HEAD>
<TITLE>Subroutines in EmbperlObject</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Subroutines_in_EmbperlObject">Subroutines in EmbperlObject</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.6.html">PREV (Modular File Inheritance)</a>] [<a href="IntroEmbperlObject.pod.8.html">NEXT (Conclusions)</a>] <br><hr>
<P>
There are two kinds of inheritance in EmbperlObject. The first is the one
which we described in the previous section, i.e. inheritance of modular
files via the directory hierarchy. The other kind, closely related, is the
inheritance of subroutines (both pure Perl and Embperl). In this context,
subroutines are really object methods, as we'll see below. As you are
probably already aware, there are two kinds of subroutine in Embperl, for
example:
<P>
<PRE> [!
sub perl_sub
{
# Some perl code
}
!]
</PRE>
<P>
<PRE> [$ sub embperl_sub $]
Some HTML
[$ endsub $]
</PRE>
<P>
In EmbperlObject, subroutines become object methods; the difference is that
you always call an object method through an object reference. For example,
instead of a straight subroutine call like this:
<P>
<PRE> foo();
</PRE>
<P>
We have instead a call through some object:
<P>
<PRE> $obj->foo();
</PRE>
<P>
EmbperlObject allows you to inherit object methods in much the same way as
files. Because of the way that Perl implements objects and methods, there
is just a little extra consideration needed. (Note: This is not really a
good place to introduce Perl's object functionality. If you're not
comfortable with inheritance, <CODE>@ISA</CODE> and object methods, then I
suggest you take a look at the book ``Programming Perl'' (O'Reilly) or
``Object Oriented Perl'' by Damien Conway (Manning).)
<P>
A simple use of methods can be demonstrated using the following example:
<P>
<EM>/base.html</EM>
<P>
<PRE> [! sub title {'Joe's Website'} !]
[- $req = shift -]
<HTML>
<HEAD>
<TITLE>[+ $req->title() +]</TITLE>
</HEAD>
</HTML>
</PRE>
<P>
<EM>/contact/index.html</EM>
<P>
<PRE> [! sub title {'Contacting Joe'} !]
[- $req = shift -]
<HTML>
A contact form goes here
</HTML>
</PRE>
<P>
This is an alternative way of implementing the previous ``contact''
example, which still uses inheritance - but instead of placing the <TITLE> tag in a separate file (<EM>head.html</EM>), we use a method (title()). You can see that we define this method in
<EM>/base.html</EM>, so any page which is requested from the root directory will get the title
``Joe's Website''. This is a pretty good default title. Then, in <EM>/foo/index.html</EM> we redefine the <CODE>title()</CODE> method to return ``Contacting Joe''.
Inheritance insures that when the call to <CODE>title()</CODE> occurs in <EM>/base.html</EM>, the correct version of the method will be executed. Since <EM>/foo/index.html</EM> has its own version of that method, it will automatically be called instead
of the base version. This allows every file to potentially redefine methods
which were defined in <EM>/base.html</EM>, and it works well. But, as your websites get bigger, you will probably
want to split off some routines into their own files.
<P>
EmbperlObject also allows us to create special files which just contain
inheritable object methods. EmbperlObject can set up <CODE>@ISA</CODE> for
us, so that the Perl object methods will work as expected. To do this, we
need to access our methods through a specially created object rather than
directly through the Request object (usually called <CODE>$r</CODE> or
$req). This is best illustrated by the following example, which
demonstrates the code that needs to be added to <EM>base.html</EM> and also shows how we implement inheritance via a subdirectory. Once again,
assume that missing files such as <EM>constants.html</EM> are the same as previously.
<P>
<EM>/base.html</EM>
<P>
<PRE> <HTML>
[- $subs = Execute ({object => 'subs.html'}); -]
[- Execute ('constants.html') -]
[- Execute ('init.html') -]
<HEAD>
[- Execute ('head.html') -]
</HEAD>
<BODY>
[- Execute ('*', $subs) -]
</BODY>
[- Execute ('cleanup.html') -]
</HTML>
</PRE>
<P>
<EM>/subs.html</EM>
<P>
<PRE> [!
sub hello
{
my ($self, $name) = @_;
print OUT "Hello, $name";
}
!]
</PRE>
<P>
<EM>/insult/index.html</EM>
<P>
<PRE> [-
$subs = param[0];
$subs->hello ("Joe");
-]
</PRE>
<P>
<EM>/insult/subs.html</EM>
<P>
<PRE> [! Execute ({isa => '../subs.html'}) !]
</PRE>
<P>
<PRE> [!
sub hello
{
my ($self, $name) = @_;
$self->SUPER::hello ($name);
print OUT ", you schmuck";
}
!]
</PRE>
<P>
If we requested the file <EM>/insult/index.html</EM> then we would see something like
<P>
<PRE> Hello, Joe, you schmuck
</PRE>
<P>
So what is happening here? First of all, note that we create a
<CODE>$subs</CODE> object in <EM>base.html</EM>, using a special call to <CODE>Execute().</CODE> We then pass this object
to files which will need it, via an <CODE>Execute()</CODE> parameter. This
can be seen with the '*' file.
<P>
Next, we have two versions of <EM>subs.html</EM>. The first, <EM>/subs.html</EM>, is pretty straightforward. All we need to do is remember that all of
these subroutines are now object methods, and so take the extra parameter
($self). The basic <CODE>hello()</CODE> method simply says Hello to the
name of the person passed in.
<P>
Then we have a subdirectory, called /insult/. Here we have another instance
of <EM>subs.html</EM>, and we redefine <CODE>hello().</CODE> We call the parent version of the
function, and then add the insult (``you schmuck''). You don't have to call
the parent version of methods you define, of course, but it's a useful
demonstration of the possibilities.
<P>
The file <EM>/insult/subs.html</EM> has to have a call to <CODE>Execute()</CODE> which sets up @ISA. This is
the first line. You might ask why EmbperlObject doesn't do this
automatically; it is mainly for reasons of efficiency. Not every file is
going to contain methods which need to inherit from the parent file, and so
simply requiring this one line seemed to be a good compromise. It also
allows for a bit more flexibility, as you can if you want include other
arbitrary files into the <CODE>@ISA</CODE> tree.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.6.html">PREV (Modular File Inheritance)</a>] [<a href="IntroEmbperlObject.pod.8.html">NEXT (Conclusions)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.8.html
Index: IntroEmbperlObject.pod.8.html
===================================================================
<HTML>
<HEAD>
<TITLE>Conclusions</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Conclusions">Conclusions</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.7.html">PREV (Subroutines in EmbperlObject)</a>] [<a href="IntroEmbperlObject.pod.9.html">NEXT (Author)</a>] <br><hr>
<P>
So there you have it - an introduction to the use of EmbperlObject for
constructing large, modular websites. You will probably use it to enable
such things as website-wide navigation bars, table layouts and whatever
else needs to be modularized.
<P>
This document is just an introduction, to give a broad flavor of the tool.
You should refer to the actual documentation for details.
<P>
EmbperlObject will inevitably evolve as developers find out what is useful
and what isn't. We will try to keep this document up-to-date with these
changes, but also make sure to check the Embperl website regularly for the
latest changes.
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.7.html">PREV (Subroutines in EmbperlObject)</a>] [<a href="IntroEmbperlObject.pod.9.html">NEXT (Author)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.9.html
Index: IntroEmbperlObject.pod.9.html
===================================================================
<HTML>
<HEAD>
<TITLE>Author</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Author">Author</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.8.html">PREV (Conclusions)</a>] <br><hr>
<P>
Neil Gunton <A HREF="mailto:neil@nilspace.com">neil@nilspace.com</A>
<p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.8.html">PREV (Conclusions)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/IntroEmbperlObject.pod.cont.html
Index: IntroEmbperlObject.pod.cont.html
===================================================================
<HTML>
<HEAD>
<TITLE>Introduction to EmbperlObject - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Content-IntroEmbperlObject.pod.cont">Introduction to EmbperlObject - Content</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.1.html">NEXT (Introduction)</a>] <br><HTML>
<HEAD>
<TITLE>Introduction to EmbperlObject - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY>
<!-- INDEX BEGIN -->
<UL>
<LI><A href="IntroEmbperlObject.pod.1.html#Introduction">Introduction</A>
<UL>
<LI><A href="IntroEmbperlObject.pod.1.html#Motivation_Constructing_Modular">Motivation: Constructing Modular Websites</A>
</UL>
<LI><A href="IntroEmbperlObject.pod.2.html#Getting_Started">Getting Started</A>
<UL>
<LI><A href="IntroEmbperlObject.pod.2.html#Configuring_F_httpd_conf_">Configuring <EM>httpd.conf</EM></A>
</UL>
<LI><A href="IntroEmbperlObject.pod.3.html#Hello_World">Hello World</A>
<LI><A href="IntroEmbperlObject.pod.4.html#Website_Global_Variables">Website-Global Variables</A>
<LI><A href="IntroEmbperlObject.pod.5.html#Modular_Files">Modular Files</A>
<LI><A href="IntroEmbperlObject.pod.6.html#Modular_File_Inheritance">Modular File Inheritance</A>
<LI><A href="IntroEmbperlObject.pod.7.html#Subroutines_in_EmbperlObject">Subroutines in EmbperlObject</A>
<LI><A href="IntroEmbperlObject.pod.8.html#Conclusions">Conclusions</A>
<LI><A href="IntroEmbperlObject.pod.9.html#Author">Author</A>
</UL>
<!-- INDEX END -->
<hr><p>[<a href="" >HOME</a>] [<a href="IntroEmbperlObject.pod.cont.html">CONTENT</a>] [<a href="IntroEmbperlObject.pod.1.html">NEXT (Introduction)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</body></html>
1.1 modperl-site/embperl/Recordset.pod.1.html
Index: Recordset.pod.1.html
===================================================================
<HTML>
<HEAD>
<TITLE>DESCRIPTION</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="DESCRIPTION">DESCRIPTION</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.cont.html">PREV (DBIx::Recordset - Content)</a>] [<a href="Recordset.pod.2.html">NEXT (ARGUMENTS)</a>] <br><hr>
<P>
DBIx::Recordset is a perl module for abstraction and simplification of
database access.
<P>
The goal is to make standard database access (select/insert/update/delete)
easier to handle and independend of the underlying DBMS. Special attention
is made on web applications to make it possible to handle the state-less
access and to process the posted data of formfields, but DBIx::Recordset is
not limited to web applications.
<P>
<STRONG>DBIx::Recordset</STRONG> uses the DBI API to access the database, so it should work with every
database for which a DBD driver is available (see also DBIx::Compat).
<P>
Most public functions take a hash reference as parameter, which makes it
simple to supply various different arguments to the same function. The
parameter hash can also be taken from a hash containing posted formfields
like those available with CGI.pm, mod_perl, HTML::Embperl and others.
<P>
Before using a recordset it is necessary to setup an object. Of course the
setup step can be made with the same function call as the first database
access, but it can also be handled separately.
<P>
Most functions which set up an object return a <STRONG>typglob</STRONG>. A typglob in Perl is an object which holds pointers to all datatypes with
the same name. Therefore a typglob must always have a name and <STRONG>can't</STRONG> be declared with <STRONG>my</STRONG>. You can only use it as <STRONG>global</STRONG> variable or declare it with <STRONG>local</STRONG>. The trick for using a typglob is that setup functions can return a <STRONG>reference to an object</STRONG>, an
<STRONG>array</STRONG> and a <STRONG>hash</STRONG> at the same time.
<P>
The object is used to access the object's methods, the array is used to
access the records currently selected in the recordset and the hash is used
to access the current record.
<P>
If you don't like the idea of using typglobs you can also set up the
object, array and hash separately, or just set the ones you need.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.cont.html">PREV (DBIx::Recordset - Content)</a>] [<a href="Recordset.pod.2.html">NEXT (ARGUMENTS)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.10.html
Index: Recordset.pod.10.html
===================================================================
<HTML>
<HEAD>
<TITLE>DEBUGGING</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="DEBUGGING">DEBUGGING</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.9.html">PREV (FETCHSIZE / $FetchsizeWarn)</a>] [<a href="Recordset.pod.11.html">NEXT (SECURITY)</a>] <br><hr>
<P>
DBIx::Recordset is able to write a logfile so you can see what's happening
inside. There are two public variables and the <CODE>!Debug</CODE> parameter used for this purpose:
<DL>
<DT><STRONG><A NAME="_DBIx_Recordset_Debug">$DBIx::Recordset::Debug or !Debug</A></STRONG><DD>
Debuglevel 0 = off 1 = log only errors 2 = show connect, disconnect and SQL
Statements 3 = some more infos 4 = much infos
<P>
<CODE>$DBIx::Recordset::Debug</CODE> sets the default debug level for new objects,
<CODE>!Debug</CODE> can be used to set the debuglevel on a per object basis.
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::LOG</A></STRONG><DD>
The filehandle used for logging. The default is STDOUT, unless you are
running under HTML::Embperl, in which case the default is the Embperl
logfile.
</DL>
<P>
<PRE> Example:
</PRE>
<P>
<PRE> # open the log file
open LOG, ">test.log" or die "Cannot open test.log" ;
</PRE>
<P>
<PRE> # assign filehandle
*DBIx::Recordset::LOG = \*LOG ;
# set debugging level
$DBIx::Recordset::Debug = 2 ;
</PRE>
<P>
<PRE> # now you can create a new DBIx::Recordset object
</PRE>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.9.html">PREV (FETCHSIZE / $FetchsizeWarn)</a>] [<a href="Recordset.pod.11.html">NEXT (SECURITY)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.11.html
Index: Recordset.pod.11.html
===================================================================
<HTML>
<HEAD>
<TITLE>SECURITY</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="SECURITY">SECURITY</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.10.html">PREV (DEBUGGING)</a>] [<a href="Recordset.pod.12.html">NEXT (Compatibility with different DBD drivers)</a>] <br><hr>
<P>
Since one possible application of DBIx::Recordset is its use in a
web-server environment, some attention should paid to security issues.
<P>
The current version of DBIx::Recordset does not include extended security
management, but some features can be used to make your database access
safer. (More security features will come in future releases.)
<P>
First of all, use the security feature of your database. Assign the web
server process as few rights as possible.
<P>
The greatest security risk is when you feed DBIx::Recordset a hash which
contains the formfield data posted to the web server. Somebody who knows
DBIx::Recordset can post other parameters than those you would expect a
normal user to post. For this reason, a primary issue is to override all
parameters which should <STRONG>never</STRONG> be posted by your script.
<P>
Example: <CODE>*set</CODE> = DBIx::Recordset -> Search ({%fdat,
('!DataSource' => ``dbi:$Driver:$DB'', '!Table' => ``$Table'')}) ;
<P>
(assuming your posted form data is in %fdat). The above call will make sure
that nobody from outside can override the values supplied by $Driver,
<CODE>$DB</CODE> and $Table.
<P>
It is also wise to initialize your objects by supplying parameters which
can not be changed.
<P>
Somewhere in your script startup (or at server startup time) add a setup
call:
<P>
<PRE> *set = DBIx::Recordset-> Setup ({'!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table",
'!Fields' => "a, b, c"}) ;
</PRE>
<P>
Later, when you process a request you can write:
<P>
<PRE> $set -> Search (\%fdat) ;
</PRE>
<P>
This will make sure that only the database specified by $Driver, $DB, the
table specified by <A href="Recordset.pod.7.html#item__Table">$Table</A> and the Fields a, b,
and c can be accessed.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.10.html">PREV (DEBUGGING)</a>] [<a href="Recordset.pod.12.html">NEXT (Compatibility with different DBD drivers)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.12.html
Index: Recordset.pod.12.html
===================================================================
<HTML>
<HEAD>
<TITLE>Compatibility with different DBD drivers</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Compatibility_with_different_DBD">Compatibility with different DBD drivers</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.11.html">PREV (SECURITY)</a>] [<a href="Recordset.pod.13.html">NEXT (EXAMPLES)</a>] <br><hr>
<P>
I have put a great deal of effort into making DBIx::Recordset run with
various DBD drivers. The problem is that not all necessary information is
specified via the DBI interface (yet). So I have made the module <STRONG>DBIx::Compat</STRONG> which gives information about the difference between various DBD drivers
and their underlying database systems. Currently, there are definitions
for:
<DL>
<DT><STRONG><A NAME="DBD">DBD::mSQL</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::mysql</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::Pg</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::Solid</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::ODBC</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::CSV</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::Oracle (requires DBD::Oracle 0.60 or higher)</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::Sysbase</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::Informix</A></STRONG><DD>
<DT><STRONG><A NAME="DBD">DBD::InterBase</A></STRONG><DD>
DBIx::Recordset has been tested with all those DBD drivers (on Linux
2.0.32, except DBD::ODBC, which has been tested on Windows '95 using Access
7 and with MS SQL Server).
<P>
If you want to use another DBD driver with DBIx::Recordset, it may be
necessary to create an entry for that driver. See <STRONG>perldoc DBIx::Compat</STRONG> for more information.
</DL>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.11.html">PREV (SECURITY)</a>] [<a href="Recordset.pod.13.html">NEXT (EXAMPLES)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.13.html
Index: Recordset.pod.13.html
===================================================================
<HTML>
<HEAD>
<TITLE>EXAMPLES</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="EXAMPLES">EXAMPLES</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.12.html">PREV (Compatibility with different DBD drivers)</a>] [<a href="Recordset.pod.14.html">NEXT (SUPPORT)</a>] <br><hr>
<P>
The following are some examples of how to use DBIx::Recordset. The Examples
are from the test.pl. The examples show the DBIx::Recordset call first,
followed by the generated SQL command.
<P>
<PRE> *set = DBIx::Recordset-> Setup ({'!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table"}) ;
</PRE>
<P>
Setup a DBIx::Recordset for driver $Driver, database <CODE>$DB</CODE> to
access table $Table.
<P>
<PRE> $set -> Select () ;
</PRE>
<P>
<PRE> SELECT * from <table> ;
</PRE>
<P>
<PRE> $set -> Select ({'id'=>2}) ;
is the same as
$set1 -> Select ('id=2') ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE id = 2 ;
</PRE>
<P>
<PRE> $set -> Search({ '$fields' => 'id, balance AS paid - total ' }) ;
</PRE>
<P>
<PRE> SELECT id, balance AS paid - total FROM <table>
</PRE>
<P>
<PRE> $set -> Select ({name => "Second Name\tFirst Name"}) ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE name = 'Second Name' or name = 'First Name' ;
</PRE>
<P>
<PRE> $set1 -> Select ({value => "9991 9992\t9993",
'$valuesplit' => ' |\t'}) ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE value = 9991 or value = 9992 or value = 9993 ;
</PRE>
<P>
<PRE> $set -> Select ({'+name&value' => "9992"}) ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE name = '9992' or value = 9992 ;
</PRE>
<P>
<PRE> $set -> Select ({'+name&value' => "Second Name\t9991"}) ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE (name = 'Second Name' or name = '9991) or
(value = 0 or value = 9991) ;
</PRE>
<P>
<PRE> $set -> Search ({id => 1,name => 'First Name',addon => 'Is'}) ;
</PRE>
<P>
<PRE> SELECT * from <table> WHERE id = 1 and name = 'First Name' and addon = 'Is' ;
</PRE>
<P>
<PRE> $set1 -> Search ({'$start'=>0,'$max'=>2, '$order'=>'id'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * from <table> ORDER BY id ;
B<Note:> Because of the B<start> and B<max> only records 0,1 will be returned
</PRE>
<P>
<PRE> $set1 -> Search ({'$start'=>0,'$max'=>2, '$next'=>1, '$order'=>'id'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * from <table> ORDER BY id ;
B<Note:> Because of the B<start>, B<max> and B<next> only records 2,3 will be
returned
</PRE>
<P>
<PRE> $set1 -> Search ({'$start'=>2,'$max'=>1, '$prev'=>1, '$order'=>'id'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * from <table> ORDER BY id ;
B<Note:> Because of the B<start>, B<max> and B<prev> only records 0,1,2 will be
returned
</PRE>
<P>
<PRE> $set1 -> Search ({'$start'=>5,'$max'=>5, '$next'=>1, '$order'=>'id'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * from <table> ORDER BY id ;
B<Note:> Because of the B<start>, B<max> and B<next> only records 5-9 will be
returned
</PRE>
<P>
<PRE> *set6 = DBIx::Recordset -> Search ({ '!DataSource' => "dbi:$Driver:$DB",
'!Table' => "t1, t2",
'!TabRelation' =>
"t1.value=t2.value",
'!Fields' => 'id, name, text',
'id' => "2\t4" }) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (id=2 or id=4) and t1.value=t2.value ;
</PRE>
<P>
<PRE> $set6 -> Search ({'name' => "Fourth Name" }) or die "not ok
($DBI::errstr)" ;
SELECT id, name, text FROM t1, t2 WHERE (name = 'Fourth Name') and
t1.value=t2.value
;
</PRE>
<P>
<PRE> $set6 -> Search ({'id' => 3,
'$operator' => '<' }) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (id < 3) and t1.value=t2.value ;
</PRE>
<P>
<PRE> $set6 -> Search ({'id' => 4,
'name' => 'Second Name',
'*id' => '<',
'*name' => '<>' }) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (id<4 and name <> 'Second Name') and
t1.value=t2.value ;
</PRE>
<P>
<PRE> $set6 -> Search ({'id' => 2,
'name' => 'Fourth Name',
'*id' => '<',
'*name' => '=',
'$conj' => 'or' }) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (id<2 or name='Fourth Name') and
t1.value=t2.value ;
</PRE>
<P>
<PRE> $set6 -> Search ({'+id|addon' => "7\tit",
'name' => 'Fourth Name',
'*id' => '<',
'*addon' => '=',
'*name' => '<>',
'$conj' => 'and' }) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (t1.value=t2.value) and ( ((name <>
Fourth
Name)) and ( ( id < 7 or addon = 7) or ( id < 0 or addon = 0)))
</PRE>
<P>
<PRE> $set6 -> Search ({'+id|addon' => "6\tit",
'name' => 'Fourth Name',
'*id' => '>',
'*addon' => '<>',
'*name' => '=',
'$compconj' => 'and',
'$conj' => 'or' }) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT id, name, text FROM t1, t2 WHERE (t1.value=t2.value) and ( ((name =
Fourth
Name)) or ( ( id > 6 and addon <> 6) or ( id > 0 and addon <> 0))) ;
</PRE>
<P>
<PRE> *set7 = DBIx::Recordset -> Search ({ '!DataSource' => "dbi:$Driver:$DB",
'!Table' => "t1, t2",
'!TabRelation' => "t1.id=t2.id",
'!Fields' => 'name, typ'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT name, typ FROM t1, t2 WHERE t1.id=t2.id ;
</PRE>
<P>
<PRE> %h = ('id' => 22,
'name2' => 'sqlinsert id 22',
'value2'=> 1022) ;
</PRE>
<P>
<PRE> *set9 = DBIx::Recordset -> Insert ({%h,
('!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table[1]")}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> INSERT INTO <table> (id, name2, value2) VALUES (22, 'sqlinsert id 22', 1022) ;
</PRE>
<P>
<PRE> %h = ('id' => 22,
'name2' => 'sqlinsert id 22u',
'value2'=> 2022) ;
</PRE>
<P>
<PRE> $set9 -> Update (\%h, 'id=22') or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> UPDATE <table> WHERE id=22 SET id=22, name2='sqlinsert id 22u', value2=2022 ;
</PRE>
<P>
<PRE> %h = ('id' => 21,
'name2' => 'sqlinsert id 21u',
'value2'=> 2021) ;
</PRE>
<P>
<PRE> *set10 = DBIx::Recordset -> Update ({%h,
('!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table[1]",
'!PrimKey' => 'id')}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> UPDATE <table> WHERE id=21 SET name2='sqlinsert id 21u', value2=2021 ;
</PRE>
<P>
<PRE> %h = ('id' => 21,
'name2' => 'Ready for delete 21u',
'value2'=> 202331) ;
</PRE>
<P>
<PRE> *set11 = DBIx::Recordset -> Delete ({%h,
('!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table[1]",
'!PrimKey' => 'id')}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> DELETE FROM <table> WHERE id = 21 ;
</PRE>
<P>
<PRE> *set12 = DBIx::Recordset -> Execute ({'id' => 20,
'*id' => '<',
'!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table[1]",
'!PrimKey' => 'id'}) or die "not ok
($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * FROM <table> WHERE id<20 ;
</PRE>
<P>
<PRE> *set13 = DBIx::Recordset -> Execute ({'=search' => 'ok',
'name' => 'Fourth Name',
'!DataSource' => "dbi:$Driver:$DB",
'!Table' => "$Table[0]",
'!PrimKey' => 'id'}) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * FROM <table> WHERE ((name = Fourth Name))
</PRE>
<P>
<PRE> $set12 -> Execute ({'=insert' => 'ok',
'id' => 31,
'name2' => 'insert by exec',
'value2' => 3031,
# Execute should ignore the following params, since it is already setup
'!DataSource' => "dbi:$Driver:$DB",
'!Table' => "quztr",
'!PrimKey' => 'id99'}) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> SELECT * FROM <table> ;
</PRE>
<P>
<PRE> $set12 -> Execute ({'=update' => 'ok',
'id' => 31,
'name2' => 'update by exec'}) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> UPDATE <table> SET name2=update by exec,id=31 WHERE id=31 ;
</PRE>
<P>
<PRE> $set12 -> Execute ({'=insert' => 'ok',
'id' => 32,
'name2' => 'insert/upd by exec',
'value2' => 3032}) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> INSERT INTO <table> (name2,id,value2) VALUES (insert/upd by exec,32,3032) ;
</PRE>
<P>
<PRE> $set12 -> Execute ({'=delete' => 'ok',
'id' => 32,
'name2' => 'ins/update by exec',
'value2' => 3032}) or die "not ok ($DBI::errstr)" ;
</PRE>
<P>
<PRE> DELETE FROM <table> WHERE id=32 ;
</PRE>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.12.html">PREV (Compatibility with different DBD drivers)</a>] [<a href="Recordset.pod.14.html">NEXT (SUPPORT)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.14.html
Index: Recordset.pod.14.html
===================================================================
<HTML>
<HEAD>
<TITLE>SUPPORT</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="SUPPORT">SUPPORT</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.13.html">PREV (EXAMPLES)</a>] [<a href="Recordset.pod.15.html">NEXT (AUTHOR)</a>] <br><hr>
<P>
As far as possible for me, support will be available via the DBI Users'
mailing list. (<A HREF="mailto:dbi-user@fugue.com">dbi-user@fugue.com</A>)
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.13.html">PREV (EXAMPLES)</a>] [<a href="Recordset.pod.15.html">NEXT (AUTHOR)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.15.html
Index: Recordset.pod.15.html
===================================================================
<HTML>
<HEAD>
<TITLE>AUTHOR</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="AUTHOR">AUTHOR</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.14.html">PREV (SUPPORT)</a>] <br><hr>
<P>
G.Richter (<A HREF="mailto:richter@dev.ecos.de">richter@dev.ecos.de</A>)
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.14.html">PREV (SUPPORT)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.2.html
Index: Recordset.pod.2.html
===================================================================
<HTML>
<HEAD>
<TITLE>ARGUMENTS</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="ARGUMENTS">ARGUMENTS</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.1.html">PREV (DESCRIPTION)</a>] [<a href="Recordset.pod.3.html">NEXT (METHODS)</a>] <br> <UL>
<LI><A href="Recordset.pod.2.html#Setup_Parameters">Setup Parameters</A>
<LI><A href="Recordset.pod.2.html#Link_Parameters">Link Parameters</A>
<LI><A href="Recordset.pod.2.html#Where_Parameters">Where Parameters</A>
<LI><A href="Recordset.pod.2.html#Search_parameters">Search parameters</A>
<LI><A href="Recordset.pod.2.html#Execute_parameters">Execute parameters</A>
</UL>
<hr>
<P>
Since most methods take a hash reference as argument, here is a description
of the valid arguments first.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Setup_Parameters">Setup Parameters</A></H2>
<P>
All parameters starting with an '!' are only recognized at setup time. If
you specify them in later function calls they will be ignored. You can also
preset these parameters with the TableAttr method of DBIx::Database. This
allows you to presetup most parameters for the whole database and they will
be use every time you create a new DBIx::Recordset object, without
specifing it every time.
<DL>
<DT><STRONG><A NAME="_DataSource">!DataSource</A></STRONG><DD>
Specifies the database to which to connect. This information can be given
in the following ways:
<DL>
<DT><STRONG><A NAME="Driver">Driver/DB/Host.</A></STRONG><DD>
Same as the first parameter to the DBI connect function.
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset object</A></STRONG><DD>
Takes the same database handle as the given DBIx::Recordset object.
<br> <DT><STRONG><A NAME="DBIx">DBIx::Database object</A></STRONG><DD>
Takes Driver/DB/Host from the given database object.
<br> <DT><STRONG><A NAME="DBIx">DBIx::Datasbase object name</A></STRONG><DD>
Takes Driver/DB/Host from the database object which is saved under the
given name ($saveas parameter to DBIx::Database -> new)
<br> <DT><STRONG><A NAME="an">an DBI database handle</A></STRONG><DD>
Uses given database handle.
</DL>
<br> <DT><STRONG><A NAME="_Table">!Table</A></STRONG><DD>
Tablename. Multiple tables are comma-separated.
<br> <DT><STRONG><A NAME="_Username">!Username</A></STRONG><DD>
Username. Same as the second parameter to the DBI connect function.
<br> <DT><STRONG><A NAME="_Password">!Password</A></STRONG><DD>
Password. Same as the third parameter to the DBI connect function.
<br> <DT><STRONG><A NAME="_DBIAttr">!DBIAttr</A></STRONG><DD>
Reference to a hash which holds the attributes for the DBI connect
function. See perldoc DBI for a detailed description.
<br> <DT><STRONG><A NAME="_Fields">!Fields</A></STRONG><DD>
Fields which should be returned by a query. If you have specified multiple
tables the fieldnames should be unique. If the names are not unique you
must specify them along with the tablename (e.g. tab1.field).
<P>
NOTE 1: Fieldnames specified with !Fields can't be overridden. If you plan
to use other fields with this object later, use <CODE>$Fields</CODE>
instead.
<P>
NOTE 2: The keys for the returned hash normally don't have a table part.
Only the fieldname part forms the key. (See !LongNames for an exception.)
<P>
NOTE 3: Because the query result is returned in a hash, there can only be
one out of multiple fields with the same name fetched at once. If you
specify multiple fields with the same name, only one is returned from a
query. Which one this actually is depends on the DBD driver. (See
!LongNames for an exception.)
<P>
NOTE 4: Some databases (e.g. mSQL) require you to always qualify a
fieldname with a tablename if more than one table is accessed in one query.
<br> <DT><STRONG><A NAME="_TableFilter">!TableFilter</A></STRONG><DD>
The TableFilter parameter specifies which tables should be honoured when
DBIx::Recordset searches for links between tables (see below). When given
as parameter to DBIx::Database it filters for which tables DBIx::Database
retrieves metadata. Only thoses tables are used which starts with prefix
given by <CODE>!TableFilter</CODE>. Also the DBIx::Recordset link detection tries to use this value as a
prefix of table names, so you can leave out this prefix when you write a
fieldname that should be detected as a link to another table.
<br> <DT><STRONG><A NAME="_LongNames">!LongNames</A></STRONG><DD>
When set to 1, the keys of the hash returned for each record not only
consist of the fieldnames, but are built in the form table.field.
<br> <DT><STRONG><A NAME="_Order">!Order</A></STRONG><DD>
Fields which should be used for ordering any query. If you have specified
multiple tables the fieldnames should be unique. If the names are not
unique you must specify them among with the tablename (e.g. tab1.field).
<P>
NOTE 1: Fieldnames specified with !Order can't be overridden. If you plan
to use other fields with this object later, use <CODE>$order</CODE>
instead.
<br> <DT><STRONG><A NAME="_TabRelation">!TabRelation</A></STRONG><DD>
Condition which describes the relation between the given tables (e.g.
tab1.id = tab2.id) (See also <EM>!TabJoin</EM>.)
<P>
<PRE> Example
</PRE>
<P>
<PRE> '!Table' => 'tab1, tab2',
'!TabRelation' => 'tab1.id=tab2.id',
'name' => 'foo'
</PRE>
<P>
<PRE> This will generate the following SQL statement:
</PRE>
<P>
<PRE> SELECT * FROM tab1, tab2 WHERE name = 'foo' and tab1.id=tab2.id ;
</PRE>
<br> <DT><STRONG><A NAME="_TabJoin">!TabJoin</A></STRONG><DD>
!TabJoin allows you to specify an <STRONG>INNER/RIGHT/LEFT JOIN</STRONG> which is used in a <STRONG>SELECT</STRONG> statement. (See also <EM>!TabRelation</EM>.)
<P>
<PRE> Example
</PRE>
<P>
<PRE> '!Table' => 'tab1, tab2',
'!TabJoin' => 'tab1 LEFT JOIN tab2 ON (tab1.id=tab2.id)',
'name' => 'foo'
</PRE>
<P>
<PRE> This will generate the following SQL statement:
</PRE>
<P>
<PRE> SELECT * FROM tab1 LEFT JOIN tab2 ON (tab1.id=tab2.id) WHERE name =
'foo' ;
</PRE>
<br> <DT><STRONG><A NAME="_PrimKey">!PrimKey</A></STRONG><DD>
Name of the primary key. When this key appears in a WHERE parameter list
(see below), DBIx::Recordset will ignore all other keys in the list,
speeding up WHERE expression preparation and execution. Note that this key
does NOT have to correspond to a field tagged as PRIMARY KEY in a CREATE
TABLE statement.
<br> <DT><STRONG><A NAME="_Serial">!Serial</A></STRONG><DD>
Name of the primary key. In contrast to <CODE>!PrimKey</CODE> this field is treated as an autoincrement field. If the database does not
support autoincrement fields, but sequences the field is set to the next
value of a sequence (see <CODE>!Sequence</CODE> and <CODE>!SeqClass</CODE>) upon each insert. If a <CODE>!SeqClass</CODE> is given the values are always retrived from the sequence class regardless
if the DBMS supports autoincrement or not. The value from this field from
the last insert could be retrieved by the function <CODE>LastSerial</CODE>.
<br> <DT><STRONG><A NAME="_Sequence">!Sequence</A></STRONG><DD>
Name of the sequence to use for this table when inserting a new record and
<CODE>!Serial</CODE> is defind. Defaults to <tablename>_seq.
<br> <DT><STRONG><A NAME="_SeqClass">!SeqClass</A></STRONG><DD>
Name and Parameter for a class that can generate unique sequence values.
This is a string that holds comma separated values. The first value is the
class name and the following parameters are given to the new constructor.
See also <EM>DBIx::Recordset::FileSeq</EM>
and <EM>DBIx::Recordset::DBSeq</EM>.
<P>
Example: '!SeqClass' => 'DBIx::Recordset::FileSeq, /tmp/seq'
<br> <DT><STRONG><A NAME="_WriteMode">!WriteMode</A></STRONG><DD>
!WriteMode specifies which write operations to the database are allowed and
which are disabled. You may want to set !WriteMode to zero if you only need
to query data, to avoid accidentally changing the content of the database.
<P>
<STRONG>NOTE:</STRONG> The !WriteMode only works for the DBIx::Recordset methods. If you disable
!WriteMode, it is still possible to use <STRONG>do</STRONG> to send normal SQL statements to the database engine to write/delete any
data.
<P>
!WriteMode consists of some flags, which may be added together:
<DL>
<DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmNONE (0)</A></STRONG><DD>
Allow <STRONG>no</STRONG> write access to the <CODE>table(s)</CODE>
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmINSERT (1)</A></STRONG><DD>
Allow INSERT
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmUPDATE (2)</A></STRONG><DD>
Allow UPDATE
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmDELETE (4)</A></STRONG><DD>
Allow DELETE
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmCLEAR (8)</A></STRONG><DD>
To allow DELETE for the whole table, wmDELETE must be also specified. This
is necessary for assigning a hash to a hash which is tied to a table. (Perl
will first erase the whole table, then insert the new data.)
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::wmALL (15)</A></STRONG><DD>
Allow every access to the <CODE>table(s)</CODE>
</DL>
<P>
Default is wmINSERT + wmUPDATE + wmDELETE
<br> <DT><STRONG><A NAME="_StoreAll">!StoreAll</A></STRONG><DD>
If present, this will cause DBIx::Recordset to store all rows which will be
fetched between consecutive accesses, so it's possible to access data in a
random order. (e.g. row 5, 2, 7, 1 etc.) If not specified, rows will only
be fetched into memory if requested, which means that you will have to
access rows in ascending order. (e.g. 1,2,3 if you try 3,2,4 you will get
an undef for row 2 while 3 and 4 is ok) see also <STRONG>DATA ACCESS</STRONG> below.
<br> <DT><STRONG><A NAME="_HashAsRowKey">!HashAsRowKey</A></STRONG><DD>
By default, the hash returned by the setup function is tied to the current
record. You can use it to access the fields of the current record. If you
set this parameter to true, the hash will by tied to the whole database.
This means that the key of the hash will be used as the primary key in the
table to select one row. (This parameter only has an effect on functions
which return a typglob.)
<br> <DT><STRONG><A NAME="_IgnoreEmpty">!IgnoreEmpty</A></STRONG><DD>
This parameter defines how <STRONG>empty</STRONG> and <STRONG>undefined</STRONG> values are handled. The values 1 and 2 may be helpful when using
DBIx::Recordset inside a CGI script, because browsers send empty formfields
as empty strings.
<OL>
<LI><STRONG><A NAME="_default_">(default)</A></STRONG><br>
An undefined value is treated as SQL <STRONG>NULL</STRONG>: an empty string remains an empty string.
<br> <LI>
All fields with an undefined value are ignored when building the WHERE
expression.
<br> <LI>
All fields with an undefined value or an empty string are ignored when
building the WHERE expression.
</OL>
<P>
<STRONG>NOTE:</STRONG> The default for versions before 0.18 was 2.
<br> <DT><STRONG><A NAME="_Filter">!Filter</A></STRONG><DD>
Filters can be used to pre/post-process the data which is read from/written
to the database. The !Filter parameter takes a hash reference which
contains the filter functions. If the key is numeric, it is treated as a
type value and the filter is applied to all fields of that type. If the key
if alphanumeric, the filter is applied to the named field. Every filter
description consists of an array with at least two elements. The first
element must contain the input function, and the second element must
contain the output function. Either may be undef, if only one of them are
necessary. The data is passed to the input function before it is written to
the database. The input function must return the value in the correct
format for the database. The output function is applied to data read from
the database before it is returned to the user. Example:
<P>
<PRE> '!Filter' =>
{
DBI::SQL_DATE =>
[
sub { shift =~ /(\d\d)\.(\d\d)\.(\d\d)/ ; "19$3$2$1"},
sub { shift =~ /\d\d(\d\d)(\d\d)(\d\d)/ ; "$3.$2.$1"}
],
</PRE>
<P>
<PRE> 'datefield' =>
[
sub { shift =~ /(\d\d)\.(\d\d)\.(\d\d)/ ; "19$3$2$1"},
sub { shift =~ /\d\d(\d\d)(\d\d)(\d\d)/ ; "$3.$2.$1"}
],
</PRE>
<P>
<PRE> }
</PRE>
<P>
Both filters convert a date in the format dd.mm.yy to the database format
19yymmdd and vice versa. The first one does this for all fields of the type
SQL_DATE, the second one does this for the fields with the name datefield.
<P>
The <STRONG>!Filter</STRONG> parameter can also be passed to the function <STRONG>TableAttr</STRONG> of the <STRONG>DBIx::Database</STRONG>
object. In this case it applies to all DBIx::Recordset objects which use
these tables.
<P>
A third parameter can be optionally specified. It could be set to <CODE>DBIx::Recordset::rqINSERT</CODE>,
<CODE>DBIx::Recordset::rqUPDATE</CODE>, or the sum of both. If set, the InputFunction (which is called during
UPDATE or INSERT) is always called for this field in updates and/or inserts
depending on the value. If there is no data specified for this field as an
argument to a function which causes an UPDATE/INSERT, the InputFunction is
called with an argument of <STRONG>undef</STRONG>.
<P>
During UPDATE and INSERT the input function gets either the string 'insert'
or 'update' passed as second parameter.
<br> <DT><STRONG><A NAME="_LinkName">!LinkName</A></STRONG><DD>
This allows you to get a clear text description of a linked table, instead
of (or in addition to) the !LinkField. For example, if you have a record
with all your bills, and each record contains a customer number, setting
!LinkName DBIx::Recordset can automatically retrieve the name of the
customer instead of (or in addition to) the bill record itself.
<OL>
<LI><STRONG><A NAME="select_additional_fields">select additional fields</A></STRONG><br>
This will additionally select all fields given in <STRONG>!NameField</STRONG> of the Link or the table attributes (see TableAttr).
<br> <LI><STRONG><A NAME="build_name_in_uppercase_of_Main">build name in uppercase of !MainField</A></STRONG><br>
This takes the values of <STRONG>!NameField</STRONG> of the Link or the table attributes (see TableAttr) and joins the content
of these fields together into a new field, which has the same name as the
!MainField, but in uppercase.
<br> <LI><STRONG><A NAME="replace_MainField_with_the_cont">replace !MainField with the contents of !NameField</A></STRONG><br>
Same as 2, but the !MainField is replaced with ``name'' of the linked
record.
</OL>
<P>
See also <STRONG>!Links</STRONG> and <STRONG>WORKING WITH MULTIPLE TABLES</STRONG> below
<br> <DT><STRONG><A NAME="_Links">!Links</A></STRONG><DD>
This parameter can be used to link multiple tables together. It takes a
reference to a hash, which has - as keys, names for a special <STRONG>"linkfield"</STRONG>
and - as value, a parameter hash. The parameter hash can contain all the
<STRONG>Setup parameters</STRONG>. The setup parameters are taken to construct a new recordset object to
access the linked table. If !DataSource is omitted (as it normally should
be), the same DataSource (and database handle), as the main object is
taken. There are special parameters which can only occur in a link
definition (see next paragraph). For a detailed description of how links
are handled, see <STRONG>WORKING WITH MULTIPLE TABLES</STRONG> below.
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Link_Parameters">Link Parameters</A></H2>
<br> <DT><STRONG><A NAME="_MainField">!MainField</A></STRONG><DD>
The <STRONG>!MailField</STRONG> parameter holds a fieldname which is used to retrieve a key value for the
search in the linked table from the main table. If omitted, it is set to
the same value as <STRONG>!LinkedField</STRONG>.
<br> <DT><STRONG><A NAME="_LinkedField">!LinkedField</A></STRONG><DD>
The fieldname which holds the key value in the linked table. If omitted, it
is set to the same value as <STRONG>!MainField</STRONG>.
<br> <DT><STRONG><A NAME="_NameField">!NameField</A></STRONG><DD>
This specifies the field or fields which will be used as a ``name'' for the
destination table. It may be a string or a reference to an array of
strings. For example, if you link to an address table, you may specify the
field ``nickname'' as the name field for that table, or you may use
['name', 'street', 'city'].
<P>
Look at <STRONG>!LinkName</STRONG> for more information.
<br> <DT><STRONG><A NAME="_DoOnConnect">!DoOnConnect</A></STRONG><DD>
You can give an SQL Statement (or an array reference of SQL statements),
that will be executed every time, just after an connect to the db. As third
possibilty you can give an hash reference. After every successful connect,
DBIx::Recordset excutes the statements, in the element which corresponds to
the name of the driver. '*' is executed for all drivers.
<br> <DT><STRONG><A NAME="_Default">!Default</A></STRONG><DD>
Specifies default values for new rows that are inserted via hash or array
access. The Insert method ignores this parameter.
<br> <DT><STRONG><A NAME="_TieRow">!TieRow</A></STRONG><DD>
Setting this parameter to zero will cause DBIx::Recordset to <STRONG>not</STRONG> tie the returned rows to an DBIx::Recordset::Row object and instead returns
an simple hash. The benefit of this is that it will speed up things, but
you aren't able to write to such an row, nor can you use the link feature
with such a row.
<br> <DT><STRONG><A NAME="_Debug">!Debug</A></STRONG><DD>
Set the debug level. See DEBUGGING.
<br> <DT><STRONG><A NAME="_PreFetch">!PreFetch</A></STRONG><DD>
Only for tieing a hash! Gives an where expression (either as string or as
hashref) that is used to prefetch records from that database. All following
accesses to the tied hash only access this prefetched data and don't
execute any database queries. See <CODE>!Expires</CODE> how to force a refetch. Giving a '*' as value to <CODE>!PreFetch</CODE> fetches the whole table into memory.
<P>
<PRE> The following example prefetches all record with id < 7:
</PRE>
<P>
<PRE> tie %dbhash, 'DBIx::Recordset::Hash', {'!DataSource' => $DSN,
'!Username' => $User,
'!Password' => $Password,
'!Table' => 'foo',
'!PreFetch' => {
'*id' => '<',
'id' => 7
},
'!PrimKey' => 'id'} ;
</PRE>
<P>
<PRE> The following example prefetches all records:
</PRE>
<P>
<PRE> tie %dbhash, 'DBIx::Recordset::Hash', {'!DataSource' => $DSN,
'!Username' => $User,
'!Password' => $Password,
'!Table' => 'bar',
'!PreFetch' => '*',
'!PrimKey' => 'id'} ;
</PRE>
<br> <DT><STRONG><A NAME="_Expires">!Expires</A></STRONG><DD>
Only for tieing a hash! If the values is numeric, the prefetched data will
be refetched is it is older then the given number of seconds. If the values
is a CODEREF the function is called and the data is refetched is the
function returns true.
<br> <DT><STRONG><A NAME="_MergeFunc">!MergeFunc</A></STRONG><DD>
Only for tieing a hash! Gives an reference to an function that is called
when more then one record for a given hash key is found to merge the
records into one. The function receives a refence to both records a
arguments. If more the two records are found, the function is called again
for each following record, which is already merged data as first parameter.
<P>
<PRE> The following example sets up a hash, that, when more then one record with the same id is
found, the field C<sum> is added and the first record is returned, where the C<sum> field
contains the sum of B<all> found records:
</PRE>
<P>
<PRE> tie %dbhash, 'DBIx::Recordset::Hash', {'!DataSource' => $DSN,
'!Username' => $User,
'!Password' => $Password,
'!Table' => 'bar',
'!MergeFunc' => sub { my ($a, $b) = @_ ; $a->{sum} += $b->{sum} ; },
'!PrimKey' => 'id'} ;
</PRE>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Where_Parameters">Where Parameters</A></H2>
<P>
The following parameters are used to build an SQL WHERE expression
<br> <DT><STRONG><A NAME="_where">$where</A></STRONG><DD>
Give an SQL WHERE expression literaly. If <CODE>$where</CODE> is specified, all other where parameters described below are ignored. The
only expection is <CODE>$values</CODE> which can be used to give the values to bind to the placeholders in <CODE>$where</CODE>
<br> <DT><STRONG><A NAME="_values">$values</A></STRONG><DD>
Values which should be bound to the placeholders given in <CODE>$where</CODE>.
<P>
<PRE> Example:
</PRE>
<P>
<PRE> *set = DBIx::Recordset -> Search ({'!DataSource' => 'dbi:Oracle:....',
'!Table' => 'users',
'$where' => 'name = ? and age > ?',
'$values' => ['richter', 25] }) ;
</PRE>
<P>
<STRONG>NOTE:</STRONG> Filters defined with <CODE>!Filter</CODE> are <STRONG>not</STRONG> applied to these values, because DBIx::Recordset has no chance to know with
values belongs to which field.
<br> <DT><STRONG><A NAME="_fieldname_">{fieldname}</A></STRONG><DD>
Value for field. The value will be quoted automatically, if necessary. The
value can also be an array ref in which case the values are put together
with the operator passed via <STRONG>$valueconj</STRONG> (default: or)
<P>
<PRE> Example:
</PRE>
<P>
<PRE> 'name' => [ 'mouse', 'cat'] will expand to name='mouse' or name='cat'
</PRE>
<br> <DT><STRONG><A NAME="_fieldname_">'{fieldname}</A></STRONG><DD>
Value for field. The value will always be quoted. This is only necessary if
DBIx::Recordset cannot determine the correct type for a field.
<br> <LI>
Value for field. The value will never be quoted, but will converted a to
number. This is only necessary if DBIx::Recordset cannot determine the
correct type for a field.
<br> <DT><STRONG><A NAME="_fieldname_">\{fieldname}</A></STRONG><DD>
Value for field. The value will not be converted in any way, i.e. you have
to quote it before supplying it to DBIx::Recordset if necessary.
<br> <DT><STRONG><A NAME="_fieldname_fieldname_">+{fieldname}|{fieldname}..</A></STRONG><DD>
Values for multiple fields. The value must be in one/all fields depending
on <CODE>$compconj</CODE> Example: '+name|text' => 'abc' will expand to
name='abc' or text='abc'
<br> <DT><STRONG><A NAME="_compconj">$compconj</A></STRONG><DD>
'or' or 'and' (default is 'or'). Specifies the conjunction between multiple
fields. (see above)
<br> <DT><STRONG><A NAME="_valuesplit">$valuesplit</A></STRONG><DD>
Regular expression for splitting a field value in multiple values (default
is '\t') The conjunction for multiple values could be specified with <STRONG>$valueconj</STRONG>. By default, only one of the values must match the field.
<P>
<PRE> Example:
'name' => "mouse\tcat" will expand to name='mouse' or name='cat'
</PRE>
<P>
<PRE> NOTE: The above example can also be written as 'name' => [ 'mouse', 'cat']
</PRE>
<br> <DT><STRONG><A NAME="_valueconj">$valueconj</A></STRONG><DD>
'or' or 'and' (default is 'or'). Specifies the conjunction for multiple
values.
<br> <DT><STRONG><A NAME="_conj">$conj</A></STRONG><DD>
'or' or 'and' (default is 'and') conjunction between fields
<br> <DT><STRONG><A NAME="_operator">$operator</A></STRONG><DD>
Default operator if not otherwise specified for a field. (default is '=')
<br> <LI><STRONG>{fieldname}</STRONG><br>
Operator for the named field
<P>
<PRE> Example:
'value' => 9, '*value' => '>' expand to value > 9
</PRE>
<P>
Could also be an array ref, so you can pass different operators for the
values. This is mainly handy when you need to select a range
<P>
<PRE> Example:
</PRE>
<P>
<PRE> $set -> Search ({id => [5, 7 ],
'*id' => ['>=', '<='],
'$valueconj' => 'and'}) ;
</PRE>
<P>
<PRE> This will expanded to "id >= 5 and id <= 7"
</PRE>
<P>
NOTE: To get a range you need to specify the <CODE>$valueconj</CODE> parameter as <CODE>and</CODE> because it defaults to <CODE>or</CODE>.
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Search_parameters">Search parameters</A></H2>
<br> <DT><STRONG><A NAME="_start">$start</A></STRONG><DD>
First row to fetch. The row specified here will appear as index 0 in the
data array.
<br> <DT><STRONG><A NAME="_max">$max</A></STRONG><DD>
Maximum number of rows to fetch. Every attempt to fetch more rows than
specified here will return undef, even if the select returns more rows.
<br> <DT><STRONG><A NAME="_next">$next</A></STRONG><DD>
Add the number supplied with <STRONG>$max</STRONG> to <STRONG>$start</STRONG>. This is intended to implement a next button.
<br> <DT><STRONG><A NAME="_prev">$prev</A></STRONG><DD>
Subtract the number supplied with <STRONG>$max</STRONG> from <STRONG>$start</STRONG>. This is intended to implement a previous button.
<br> <DT><STRONG><A NAME="_order">$order</A></STRONG><DD>
<CODE>Fieldname(s)</CODE> for ordering (ORDER BY) (must be comma-separated,
could also contain USING)
<br> <DT><STRONG><A NAME="_group">$group</A></STRONG><DD>
<CODE>Fieldname(s)</CODE> for grouping (GROUP BY) (must be comma-separated,
could also contain HAVING).
<br> <DT><STRONG><A NAME="_append">$append</A></STRONG><DD>
String which is appended to the end of a SELECT statement, can contain any
data.
<br> <DT><STRONG><A NAME="_fields">$fields</A></STRONG><DD>
Fields which should be returned by a query. If you have specified multiple
tables the fieldnames should be unique. If the names are not unique you
must specify them along with the tablename (e.g. tab1.field).
<P>
NOTE 1: If <STRONG>!fields</STRONG> is supplied at setup time, this can not be overridden by $fields.
<P>
NOTE 2: The keys for the returned hash normally don't have a table part.
Only the fieldname part forms the key. (See !LongNames for an exception.)
<P>
NOTE 3: Because the query result is returned in a hash, there can only be
one out of multiple fields with the same name fetched at once. If you
specify multiple fields with same name, only one is returned from a query.
Which one this actually is, depends on the DBD driver. (See !LongNames for
an exception.)
<br> <DT><STRONG><A NAME="_primkey">$primkey</A></STRONG><DD>
Name of primary key. DBIx::Recordset assumes that if specified, this is a
unique key to the given <CODE>table(s).</CODE> DBIx::Recordset can not
verify this. You are responsible for specifying the right key. If such a
primary exists in your table, you should specify it here, because it helps
DBIx::Recordset optimize the building of WHERE expressions.
<P>
See also <STRONG>!primkey</STRONG>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Execute_parameters">Execute parameters</A></H2>
<P>
The following parameters specify which action is to be executed:
<br> <DT><STRONG><A NAME="_search">=search</A></STRONG><DD>
search data
<br> <DT><STRONG><A NAME="_update">=update</A></STRONG><DD>
update <CODE>record(s)</CODE>
<br> <DT><STRONG><A NAME="_insert">=insert</A></STRONG><DD>
insert record
<br> <DT><STRONG><A NAME="_delete">=delete</A></STRONG><DD>
delete <CODE>record(s)</CODE>
<br> <DT><STRONG><A NAME="_empty">=empty</A></STRONG><DD>
setup empty object
</DL>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.1.html">PREV (DESCRIPTION)</a>] [<a href="Recordset.pod.3.html">NEXT (METHODS)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.3.html
Index: Recordset.pod.3.html
===================================================================
<HTML>
<HEAD>
<TITLE>METHODS</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="METHODS">METHODS</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.2.html">PREV (ARGUMENTS)</a>] [<a href="Recordset.pod.4.html">NEXT (DATA ACCESS)</a>] <br><hr>
<UL>
<LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Setup (\%params)</A></STRONG><br>
Setup a new object and connect it to a database and <CODE>table(s).</CODE>
Collects information about the tables which are needed later. Returns a
typglob which can be used to access the object ($set), an array (@set) and
a hash (%set).
<P>
<STRONG>params:</STRONG> setup
<br> <DT><STRONG><A NAME="_set">$set = DBIx::Recordset -gt SetupObject (\%params)</A></STRONG><DD>
Same as above, but setup only the object, do not tie anything (no array, no
hash)
<P>
<STRONG>params:</STRONG> setup
<br> <DT><STRONG>$set = tie @set, 'DBIx::Recordset', $set</STRONG><DD>
<DT><STRONG>$set = tie @set, 'DBIx::Recordset', \%params</STRONG><DD>
Ties an array to a recordset object. The result of a query which is
executed by the returned object can be accessed via the tied array. If the
array contents are modified, the database is updated accordingly (see Data
access below for more details). The first form ties the array to an already
existing object, the second one setup a new object.
<P>
<STRONG>params:</STRONG> setup
<br> <DT><STRONG>$set = tie %set, 'DBIx::Recordset::Hash', $set</STRONG><DD>
<DT><STRONG>$set = tie %set, 'DBIx::Recordset::Hash', \%params</STRONG><DD>
Ties a hash to a recordset object. The hash can be used to
access/update/insert single rows of a table: the hash key is identical to
the primary key value of the table. (see Data access below for more
details)
<P>
The first form ties the hash to an already existing object, the second one
sets up a new object.
<P>
<STRONG>params:</STRONG> setup
<br> <DT><STRONG>$set = tie %set, 'DBIx::Recordset::CurrRow', $set</STRONG><DD>
<DT><STRONG>$set = tie %set, 'DBIx::Recordset::CurrRow', \%params</STRONG><DD>
Ties a hash to a recordset object. The hash can be used to access the
fields of the current record of the recordset object. (See Data access
below for more details.)
<P>
The first form ties the hash to an already existing object, the second one
sets up a new object.
<P>
<STRONG>params:</STRONG> setup
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Select (\%params, $fields, $order)</A></STRONG><br>
<DT><STRONG>$set -gt Select (\%params, $fields, $order)</STRONG><DD>
<DT><STRONG>$set -gt Select ($where, $fields, $order)</STRONG><DD>
Selects records from the recordsets <CODE>table(s).</CODE>
<P>
The first syntax setups a new DBIx::Recordset object and does the select.
<P>
The second and third syntax selects from an existing DBIx::Recordset
object.
<P>
<STRONG>params:</STRONG> setup (only syntax 1), where (without <CODE>$order</CODE> and $fields)
<P>
<STRONG>where:</STRONG> (only syntax 3) string for SQL WHERE expression
<P>
<STRONG>fields:</STRONG> comma separated list of fieldnames to select
<P>
<STRONG>order:</STRONG> comma separated list of fieldnames to sort on
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Search (\%params)</A></STRONG><br>
<DT><STRONG><A NAME="set">set -gt Search (\%params)</A></STRONG><DD>
Does a search on the given tables and prepares data to access them via
<CODE>@set</CODE> or %set. The first syntax also sets up a new object.
<P>
<STRONG>params:</STRONG> setup (only syntax 1), where, search
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Insert (\%params)</A></STRONG><br>
<DT><STRONG>$set -gt Insert (\%params)</STRONG><DD>
Inserts a new record in the recordset <CODE>table(s).</CODE> Params should
contain one entry for every field for which you want to insert a value.
<P>
Fieldnames may be prefixed with a '\' in which case they are not processed
(quoted) in any way.
<P>
<STRONG>params:</STRONG> setup (only syntax 1), fields
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Update (\%params, $where)</A></STRONG><br>
<LI><STRONG>set = DBIx::Recordset -gt Update (\%params, $where)</STRONG><br>
<DT><STRONG>set -gt Update (\%params, $where)</STRONG><DD>
<DT><STRONG>set -gt Update (\%params, $where)</STRONG><DD>
Updates one or more records in the recordset <CODE>table(s).</CODE>
Parameters should contain one entry for every field you want to update. The
<CODE>$where</CODE> contains the SQL WHERE condition as a string or as a
reference to a hash. If <CODE>$where</CODE> is omitted, the where
conditions are buily from the parameters. If !PrimKey is given for the
table, only that !PrimKey is used for the WHERE clause.
<P>
Fieldnames may be prefixed with a '\', in which case they are not processed
(quoted) in any way.
<P>
<STRONG>params:</STRONG> setup (only syntax 1+2), where (only if <CODE>$where</CODE> is omitted),
fields
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Delete (\%params)</A></STRONG><br>
<DT><STRONG>$set -gt Delete (\%params)</STRONG><DD>
Deletes one or more records from the recordsets <CODE>table(s).</CODE>
<P>
<STRONG>params:</STRONG> setup (only syntax 1), where
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt DeleteWithLinks (\%params)</A></STRONG><br>
<DT><STRONG>$set -gt DeleteWithLinks (\%params)</STRONG><DD>
Deletes one or more records from the recordsets <CODE>table(s).</CODE>
Additonal all record of links with have the <CODE>!OnDelete</CODE> set, are either deleted or the correspending field is set to undef. What to
do is determinated by the constants <CODE>odDELETE</CODE> and <CODE>odCLEAR</CODE>. This is very helpfull to guaratee the inetgrity of the database.
<P>
<STRONG>params:</STRONG> setup (only syntax 1), where
<br> <LI><STRONG><A NAME="set">set = DBIx::Recordset -gt Execute (\%params)</A></STRONG><br>
<DT><STRONG>$set -gt Execute (\%params)</STRONG><DD>
Executes one of the above methods, depending on the given arguments. If
multiple execute parameters are specified, the priority is =search =update
=insert =delete =empty
<P>
If none of the above parameters are specified, a search is performed. A
search is always performed. On an <CODE>=update</CODE>, the <CODE>!PrimKey</CODE>, if given, is looked upon and used for the where part of the SQL
statement, while all other parameters are updated.
<P>
<STRONG>params:</STRONG> setup (only syntax 1), execute, where, search, fields
<br> <DT><STRONG>$set -gt do ($statement, $attribs, \%params)</STRONG><DD>
Same as DBI. Executes a single SQL statement on the open database.
<br> <DT><STRONG>$set -gt Reset ()</STRONG><DD>
Set the record pointer to the initial state, so the next call to
<P>
<CODE>Next</CODE> returns the first row.
<br> <DT><STRONG>$set -gt First ()</STRONG><DD>
Position the record pointer to the first row and returns it.
<br> <DT><STRONG>$set -gt Next ()</STRONG><DD>
Position the record pointer to the next row and returns it.
<br> <DT><STRONG>$set -gt Prev ()</STRONG><DD>
Position the record pointer to the previous row and returns it.
<br> <DT><STRONG>$set -gt Curr ()</STRONG><DD>
Returns the current row.
<br> <DT><STRONG>$set -gt AllNames ()</STRONG><DD>
Returns a reference to an array of all fieldnames of all tables used by the
object.
<br> <DT><STRONG>$set -gt Names ()</STRONG><DD>
Returns a reference to an array of the fieldnames from the last query.
<br> <DT><STRONG>$set -gt AllTypes ()</STRONG><DD>
Returns a reference to an array of all fieldtypes of all tables used by the
object.
<br> <DT><STRONG>$set -gt Types ()</STRONG><DD>
Returns a reference to an array of the fieldtypes from the last query.
<br> <DT><STRONG>$set -gt Add ()</STRONG><DD>
<DT><STRONG>$set -gt Add (\%data)</STRONG><DD>
Adds a new row to a recordset. The first one adds an empty row, the second
one will assign initial data to it. The Add method returns an index into
the array where the new record is located.
<P>
<PRE> Example:
</PRE>
<P>
<PRE> # Add an empty record
$i = $set -> Add () ;
# Now assign some data
$set[$i]{id} = 5 ;
$set[$i]{name} = 'test' ;
# and here it is written to the database
# (without Flush it is written, when the record goes out of scope)
$set -> Flush () ;
</PRE>
<P>
Add will also set the current record to the newly created empty record. So,
you can assign the data by simply using the current record.
<P>
<PRE> # Add an empty record
$set -> Add () ;
# Now assign some data to the new record
$set{id} = 5 ;
$set{name} = 'test' ;
</PRE>
<br> <DT><STRONG>$set -gt MoreRecords ([$ignoremax])</STRONG><DD>
Returns true if there are more records to fetch from the current recordset.
If the <CODE>$ignoremax</CODE> parameter is specified and is true,
MoreRecords ignores the <CODE>$max</CODE> parameter of the last Search.
<P>
To tell you if there are more records, More actually fetches the next
record from the database and stores it in memory. It does not, however,
change the current record.
<br> <DT><STRONG>$set -gt PrevNextForm ($prevtext, $nexttext, \%fdat)</STRONG><DD>
<DT><STRONG>$set -gt PrevNextForm (\%param, \%fdat)</STRONG><DD>
Returns a HTML form which contains a previous and a next button and all
data from %fdat, as hidden fields. When calling the Search method, You must
set the <CODE>$max</CODE> parameter to the number of rows you want to see
at once. After the search and the retrieval of the rows, you can call
PrevNextForm to generate the needed buttons for scrolling through the
recordset.
<P>
The second for allows you the specifies addtional parameter, which creates
first, previous, next, last and goto buttons. Example:
<P>
<PRE> $set -> PrevNextForm ({-first => 'First', -prev => '<<Back',
-next => 'Next>>', -last => 'Last',
-goto => 'Goto #'}, \%fdat)
</PRE>
<P>
The goto button lets you jump to an random record number. If you obmit any
of the parameters, the corresponding button will not be shown.
<br> <DT><STRONG>$set -gt Flush</STRONG><DD>
The Flush method flushes all data to the database and therefore makes sure
that the db is up-to-date. Normally, DBIx::Recordset holds the update in
memory until the row is destroyed, by either a new Select/Search or by the
Recordsetobject itself is destroyed. With this method you can make sure
that every update is really written to the db.
<br> <DT><STRONG>$set -> Dirty ()</STRONG><DD>
Returns true if there is at least one dirty row containing unflushed data.
<br> <DT><STRONG><A NAME="DBIx">DBIx::Recordset::Undef ($name)</A></STRONG><DD>
Undef takes the name of a typglob and will destroy the array, the hash, and
the object. All unwritten data is written to the db. All db connections are
closed and all memory is freed.
<P>
<PRE> Example:
# this destroys $set, @set and %set
DBIx::Recordset::Undef ('set') ;
</PRE>
<br> <DT><STRONG>$set -gt Begin</STRONG><DD>
Starts a transaction. Calls the DBI method begin.
<br> <DT><STRONG>$set -gt Rollback</STRONG><DD>
Rolls back a transaction. Calls the DBI method rollback and makes sure that
all internal buffers of DBIx::Recordset are flushed.
<br> <DT><STRONG>$set -gt Commit</STRONG><DD>
Commits a transaction. Calls the DBI method commit and makes sure that all
internal buffers of DBIx::Recordset are flushed.
<br> <DT><STRONG>$set -gt DBHdl ()</STRONG><DD>
Returns the DBI database handle.
<br> <DT><STRONG>$set -gt StHdl ()</STRONG><DD>
Returns the DBI statement handle of the last select.
<br> <DT><STRONG>$set -> TableName ()</STRONG><DD>
Returns the name of the table of the recordset object.
<br> <DT><STRONG>$set -> TableNameWithOutFilter ()</STRONG><DD>
Returns the name of the table of the recordset object, but removes the
string given with !TableFilter, if it is the prefix of the table name.
<br> <DT><STRONG>$set -> PrimKey ()</STRONG><DD>
Returns the primary key given in the !PrimKey parameter.
<br> <DT><STRONG>$set -> TableFilter ()</STRONG><DD>
Returns the table filter given in the !TableFilter parameter.
<br> <DT><STRONG>$set -gt StartRecordNo ()</STRONG><DD>
Returns the record number of the record which will be returned for index 0.
<br> <DT><STRONG>$set -gt LastSQLStatement ()</STRONG><DD>
Returns the last executed SQL Statement.
<br> <DT><STRONG>$set -gt LastSerial ()</STRONG><DD>
Return the last value of the field defined with !Serial
<br> <DT><STRONG>$set -gt Disconnect ()</STRONG><DD>
Closes the connection to the database.
<br> <DT><STRONG>$set -gt Link($linkname)</STRONG><DD>
If <CODE>$linkname</CODE> is undef, returns reference to a hash of all
links of the object. Otherwise, it returns a reference to the link with the
given name.
<br> <DT><STRONG>$set -gt Links()</STRONG><DD>
Returns reference to a hash of all links of the object.
<br> <DT><STRONG>$set -gt Link4Field($fieldname)</STRONG><DD>
Returns the name of the link for that field, or <undef> if there is
no link for that field.
<br> <DT><STRONG>$set -> TableAttr ($key, $value, $table)</STRONG><DD>
get and/or set an attribute of the table
<DL>
<DT><STRONG><A NAME="_key">$key</A></STRONG><DD>
key to set/get
<br> <DT><STRONG><A NAME="_value">$value</A></STRONG><DD>
if present, set key to this value
<br> <DT><STRONG><A NAME="_table">$table</A></STRONG><DD>
Optional, let you specify another table, then the one use by the recordset
object.
</DL>
<br> <DT><STRONG>$set -> Stats ()</STRONG><DD>
Returns an hash ref with some statistical values.
<br> <DT><STRONG>$set -> LastError ()</STRONG><DD>
<DT><STRONG><A NAME="DBIx">DBIx::Recordset -> LastError ()</A></STRONG><DD>
Returns the last error message, if any. If called in an array context the
first element receives the last error message and the second the last error
code.
</UL>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.2.html">PREV (ARGUMENTS)</a>] [<a href="Recordset.pod.4.html">NEXT (DATA ACCESS)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.4.html
Index: Recordset.pod.4.html
===================================================================
<HTML>
<HEAD>
<TITLE>DATA ACCESS</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="DATA_ACCESS">DATA ACCESS</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.3.html">PREV (METHODS)</a>] [<a href="Recordset.pod.5.html">NEXT (MODIFYING DATA DIRECTLY)</a>] <br><hr>
<P>
The data which is returned by a <STRONG>Select</STRONG> or a <STRONG>Search</STRONG> can be accessed in two ways:
<P>
1.) Through an array. Each item of the array corresponds to one of the
selected records. Each array-item is a reference to a hash containing an
entry for every field.
<P>
Example: $set[1]{id} access the field 'id' of the second record found
$set[3]{name} access the field 'name' of the fourth record found
<P>
The record is fetched from the DBD driver when you access it the first time
and is stored by DBIx::Recordset for later access. If you don't access the
records one after each other, the skipped records are not stored and
therefore can't be accessed anymore, unless you specify the <STRONG>!StoreAll</STRONG> parameter.
<P>
2.) DBIx::Recordset holds a <STRONG>current record</STRONG> which can be accessed directly via a hash. The current record is the one
you last accessed via the array. After a Select or Search, it is reset to
the first record. You can change the current record via the methods <STRONG>Next</STRONG>, <STRONG>Prev</STRONG>, <STRONG>First</STRONG>, <STRONG>Add</STRONG>.
<P>
Example: $set{id} access the field 'id' of the current record $set{name}
access the field 'name' of the current record
<P>
Instead of doing a <STRONG>Select</STRONG> or <STRONG>Search</STRONG> you can directly access one row of a table when you have tied a hash to
DBIx::Recordset::Hash or have specified the <STRONG>!HashAsRowKey</STRONG> Parameter. The hashkey will work as primary key to the table. You must
specify the
<STRONG>!PrimKey</STRONG> as setup parameter.
<P>
Example: $set{4}{name} access the field 'name' of the row with primary key
= 4
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.3.html">PREV (METHODS)</a>] [<a href="Recordset.pod.5.html">NEXT (MODIFYING DATA DIRECTLY)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.5.html
Index: Recordset.pod.5.html
===================================================================
<HTML>
<HEAD>
<TITLE>MODIFYING DATA DIRECTLY</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="MODIFYING_DATA_DIRECTLY">MODIFYING DATA DIRECTLY</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.4.html">PREV (DATA ACCESS)</a>] [<a href="Recordset.pod.6.html">NEXT (WORKING WITH MULTIPLE TABLES)</a>] <br><hr>
<P>
One way to update/insert data into the database is by using the Update,
Insert or Execute method of the DBIx::Recordset object. A second way is to
directly assign new values to the result of a previous Select/Search.
<P>
Example: # setup a new object and search all records with name xyz
<CODE>*set</CODE> = DBIx::Recordset -> Search ({'!DataSource' =>
'dbi:db:tab', '!PrimKey => 'id', '!Table' => 'tabname', 'name' =>
'xyz'}) ;
<P>
<PRE> #now you can update an existing record by assigning new values
#Note: if possible, specify a PrimKey for update to work faster
$set[0]{'name'} = 'zyx' ;
</PRE>
<P>
<PRE> # or insert a new record by setting up an new array row
$set[9]{'name'} = 'foo' ;
$set[9]{'id'} = 10 ;
</PRE>
<P>
<PRE> # if you don't know the index of a new row you can obtain
# one by using Add
my $i = $set -> Add () ;
$set[$i]{'name'} = 'more foo' ;
$set[$i]{'id'} = 11 ;
</PRE>
<P>
<PRE> # or add an empty record via Add and assign the values to the current
# record
$set -> Add () ;
$set{'name'} = 'more foo' ;
$set{'id'} = 11 ;
</PRE>
<P>
<PRE> # or insert the data directly via Add
$set -> Add ({'name' => 'even more foo',
'id' => 12}) ;
</PRE>
<P>
<PRE> # NOTE: up to this point, NO data is actually written to the db!
</PRE>
<P>
<PRE> # we are done with that object, Undef will flush all data to the db
DBIx::Recordset::Undef ('set') ;
</PRE>
<P>
IMPORTANT: The data is not written to the database until you explicitly
call <STRONG>flush</STRONG>, or a new query is started, or the object is destroyed. This is to keep
the actual writes to the database to a minimum.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.4.html">PREV (DATA ACCESS)</a>] [<a href="Recordset.pod.6.html">NEXT (WORKING WITH MULTIPLE TABLES)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.6.html
Index: Recordset.pod.6.html
===================================================================
<HTML>
<HEAD>
<TITLE>WORKING WITH MULTIPLE TABLES</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="WORKING_WITH_MULTIPLE_TABLES">WORKING WITH MULTIPLE TABLES</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.5.html">PREV (MODIFYING DATA DIRECTLY)</a>] [<a href="Recordset.pod.7.html">NEXT (DBIx::Database)</a>] <br> <UL>
<LI><A href="Recordset.pod.6.html#Joins">Joins</A>
<LI><A href="Recordset.pod.6.html#Join_Example_">Join Example:</A>
<LI><A href="Recordset.pod.6.html#Links">Links</A>
<LI><A href="Recordset.pod.6.html#LinkName">LinkName</A>
<LI><A href="Recordset.pod.6.html#Automatic_detection_of_links">Automatic detection of links</A>
</UL>
<hr>
<P>
DBIx::Recordset has some nice features to make working with multiple tables
and their relations easier.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Joins">Joins</A></H2>
<P>
First, you can specify more than one table to the <STRONG>!Table</STRONG> parameter. If you do so, you need to specify how both tables are related.
You do this with <STRONG>!TabRelation</STRONG> parameter. This method will access all the specified tables simultanously.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Join_Example_">Join Example:</A></H2>
<P>
If you have the following two tables, where the field street_id is a
pointer to the table street:
<P>
<PRE> table name
name char (30),
street_id integer
</PRE>
<P>
<PRE> table street
id integer,
street char (30),
city char (30)
</PRE>
<P>
You can perform the following search:
<P>
<PRE> *set = DBIx::Recordset -> Search ({'!DataSource' => 'dbi:drv:db',
'!Table' => 'name, street',
'!TabRelation'=> 'name.street_id = street.id'}) ;
</PRE>
<P>
The result is that you get a set which contains the fields <STRONG>name</STRONG>, <STRONG>street_id</STRONG>,
<STRONG>street</STRONG>, <STRONG>city</STRONG> and <STRONG>id</STRONG>, where id is always equal to street_id. If there are multiple streets for
one name, you will get as many records for that name as there are streets
present for it. For this reason, this approach works best when you have a
1:1 relation.
<P>
It is also possible to specify <STRONG>JOINs</STRONG>. Here's how:
<P>
<PRE> *set = DBIx::Recordset -> Search ({
'!DataSource' => 'dbi:drv:db',
'!Table' => 'name, street',
'!TabJoin' => 'name LEFT JOIN street ON (name.street_id=street.id)'}) ;
</PRE>
<P>
The difference between this and the first example is that this version also
returns a record even if neither table contains a record for the given id.
The way it's done depends on the JOIN you are given (LEFT/RIGHT/INNER) (see
your SQL documentation for details about JOINs).
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Links">Links</A></H2>
<P>
If you have 1:n relations between two tables, the following may be a better
way to handle it:
<P>
<PRE> *set = DBIx::Recordset -> Search ({'!DataSource' => 'dbi:drv:db',
'!Table' => 'name',
'!Links' => {
'-street' => {
'!Table' => 'street',
'!LinkedField' => 'id',
'!MainField' => 'street_id'
}
}
}) ;
</PRE>
<P>
After that query, every record will contain the fields <STRONG>name</STRONG> and <STRONG>street_id</STRONG>. Additionally, there is a pseudofield named <STRONG>-street</STRONG>, which could be used to access another recordset object, which is the
result of a query where <STRONG>street_id = id</STRONG>. Use
<P>
<PRE> $set{name} to access the name field
$set{-street}{street} to access the first street (as long as the
current record of the subobject isn't
modified)
</PRE>
<P>
<PRE> $set{-street}[0]{street} first street
$set{-street}[1]{street} second street
$set{-street}[2]{street} third street
</PRE>
<P>
<PRE> $set[2]{-street}[1]{street} to access the second street of the
third name
</PRE>
<P>
You can have multiple linked tables in one recordset; you can also nest
linked tables or link a table to itself.
<P>
<STRONG>NOTE:</STRONG> If you select only some fields and not all, the field which is specified by
'!MainField' must be also given in the '!Fields' or '$fields' parameter.
<P>
<STRONG>NOTE:</STRONG> See also <STRONG>Automatic detection of links</STRONG> below
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="LinkName">LinkName</A></H2>
<P>
In the LinkName feature you may specify a ``name'' for every table. A name
is one or more fields which gives a human readable ``key'' of that record.
For example in the above example
<STRONG>id</STRONG> is the key of the record, but the human readable form is <STRONG>street</STRONG>.
<P>
<PRE> *set = DBIx::Recordset -> Search ({'!DataSource' => 'dbi:drv:db',
'!Table' => 'name',
'!LinkName' => 1,
'!Links' => {
'-street' => {
'!Table' => 'street',
'!LinkedField' => 'id',
'!MainField' => 'street_id',
'!NameField' => 'street'
}
}
}) ;
</PRE>
<P>
For every record in the table, this example will return the fields:
<P>
<PRE> name street_id street
</PRE>
<P>
If you have more complex records, you may also specify more than one field
in !NameField and pass it as an reference to an array e.g. ['street',
'city']. In this case, the result will contain
<P>
<PRE> name street_id street city
</PRE>
<P>
If you set !LinkName to 2, the result will contain the fields
<P>
<PRE> name street_id STREET_ID
</PRE>
<P>
where STREET_ID contains the values of the street and city fields joined
together. If you set !LinkName to 3, you will get only
<P>
<PRE> name street_id
</PRE>
<P>
where street_id contains the values of the street and city fields joined
together.
<P>
NOTE: The !NameField can also be specified as a table attribute with the
function TableAttr. In this case you don't need to specify it in every
link. When a !NameField is given in a link description, it overrides the
table attribute.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="Automatic_detection_of_links">Automatic detection of links</A></H2>
<P>
DBIx::Recordset and DBIx::Database will try to automatically detect links
between tables based on the field and table names. For this feature to
work, the field which points to another table must consist of the table
name and the field name of the destination joined together with an
underscore (as in the above example name.street_id). Then it will
automatically recognized as a pointer to street.id.
<P>
<PRE> *set = DBIx::Recordset -> Search ({'!DataSource' => 'dbi:drv:db',
'!Table' => 'name') ;
</PRE>
<P>
is enough. DBIx::Recordset will automatically add the !Links attribute.
Additionally, DBIx::Recordset adds a backlink (which starts with a star
('*')), so for the table street, in our above example, there will be a
link, named *name, which is a pointer from table street to all records in
the table name where street.id is equal to name.street_id.
<P>
You may use the !Links attribute to specify links which can not be
automatically detected.
<P>
NOTE: To specify more then one link from one table to another table, you
may prefix the field name with an specifier followed by two underscores.
Example: first__street_id, second__street_id. The link (and backlink) names
are named with the prefix, e.g. -first__street and the backlink
*first__name.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.5.html">PREV (MODIFYING DATA DIRECTLY)</a>] [<a href="Recordset.pod.7.html">NEXT (DBIx::Database)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.7.html
Index: Recordset.pod.7.html
===================================================================
<HTML>
<HEAD>
<TITLE>DBIx::Database</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="DBIx_Database">DBIx::Database</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.6.html">PREV (WORKING WITH MULTIPLE TABLES)</a>] [<a href="Recordset.pod.8.html">NEXT (Casesensitive/insensitiv)</a>] <br> <UL>
<LI><A href="Recordset.pod.7.html#new_data_source_username_p">new ($data_source, $username, $password, \%attr, $saveas, $keepopen)</A>
<LI><A href="Recordset.pod.7.html#_db_DBIx_Database_DBHdl">$db = DBIx::Database -> DBHdl </A>
<LI><A href="Recordset.pod.7.html#_db_DBIx_Database_Get_na">$db = DBIx::Database -> Get ($name)</A>
<LI><A href="Recordset.pod.7.html#_db_TableAttr_table_key_">$db -> TableAttr ($table, $key, $value)</A>
<LI><A href="Recordset.pod.7.html#_db_TableLink_table_linkn">$db -> TableLink ($table, $linkname, $value)</A>
<LI><A href="Recordset.pod.7.html#_db_MetaData_table_metada">$db -> MetaData ($table, $metadata, $clear)</A>
<LI><A href="Recordset.pod.7.html#_db_AllTables">$db -> AllTables</A>
<LI><A href="Recordset.pod.7.html#_db_AllNames_table_">$db -> AllNames ($table)</A>
<LI><A href="Recordset.pod.7.html#_db_AllTypes_table_">$db -> AllTypes ($table)</A>
</UL>
<hr>
<P>
The DBIx::Database object gathers information about a datasource. Its main
purpose is to create, at startup, an object which retrieves all necessary
information from the database. This object detects links between tables and
stores this information for use by the DBIx::Recordset objects. There are
additional methods which allow you to add kinds of information which cannot
be retreived automatically.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="new_data_source_username_p">new ($data_source, $username, $password, \%attr, $saveas, $keepopen)</A></H2>
<DL>
<DT><STRONG><A NAME="_data_source">$data_source</A></STRONG><DD>
Specifies the database to which to connect. Driver/DB/Host. Same as the
first parameter to the DBI connect function.
<br> <DT><STRONG><A NAME="_username">$username</A></STRONG><DD>
Username (optional)
<br> <DT><STRONG><A NAME="_password">$password</A></STRONG><DD>
Password (optional)
<br> <DT><STRONG><A NAME="_attr">\%attr</A></STRONG><DD>
Attributes (optional) Same as the attribute parameter to the DBI connect
function.
<br> <DT><STRONG><A NAME="_saveas">$saveas</A></STRONG><DD>
Name for this DBIx::Database object to save as. The name can be used in
DBIx::Database::Get, or as !DataSource parameter in call to the
DBIx::Recordset object.
<P>
This is intended as mechanism to retrieve the necessary metadata; for
example, when your web server starts (e.g. in the startup.pl file of
mod_perl). Here you can give the database object a name. Later in your
mod_perl or Embperl scripts, you can use this metadata by specifying this
name. This will speed up the setup of DBIx::Recordset object without the
need to pass a reference to the DBIx::Database object.
<br> <DT><STRONG><A NAME="_keepopen">$keepopen</A></STRONG><DD>
Normaly the database connection will be closed after the metadata has been
retrieved from the database. This makes sure you don't get trouble when
using the new method in a mod_perl startup file. You can keep the
connection open to use them in further setup call to DBIx::Recordset
objects.
<br> <DT><STRONG><A NAME="_tabfilter">$tabfilter</A></STRONG><DD>
same as setup parameter !TableFilter
<br> <DT><STRONG><A NAME="_doonconnect">$doonconnect</A></STRONG><DD>
same as setup parameter !DoOnConnect
<br> <DT><STRONG><A NAME="_reconnect">$reconnect</A></STRONG><DD>
If set, forces <EM>DBIx::Database</EM> to <CODE>undef</CODE> any preexisting database handle and call connect in any case. This is
usefull in together with <EM>Apache::DBI</EM>. While the database connection are still kept open by <EM>Apache::DBI</EM>, <EM>Apache::DBI</EM> preforms a test if the handle is still vaild (which DBIx::Database itself
wouldn't).
</DL>
<P>
You also can specify a hashref which can contain the following parameters:
<P>
!DataSource, !Username, !Password, !DBIAttr, !SaveAs, !KeepOpen,
!TableFilter, !DoOnConnect, !Reconnect
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_DBIx_Database_DBHdl">$db = DBIx::Database -> DBHdl</A></H2>
<P>
returns the database handle (only if you specify !KeepOpen when calling <CODE>new</CODE>).
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_DBIx_Database_Get_na">$db = DBIx::Database -> Get ($name)</A></H2>
<P>
<CODE>$name</CODE> = The name of the DBIx::Database object you wish to
retrieve
<P>
Get a DBIx::Database object which has already been set up based on the
name.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_TableAttr_table_key_">$db -> TableAttr ($table, $key, $value)</A></H2>
<P>
get and/or set an attribute for an specfic table.
<DL>
<DT><STRONG><A NAME="_table">$table</A></STRONG><DD>
Name of <CODE>table(s).</CODE> You may use '*' instead of the table name to
specify a default value which applies to all tables for which no other
value is specified.
<br> <DT><STRONG><A NAME="_key">$key</A></STRONG><DD>
key to set/get
<br> <DT><STRONG><A NAME="_value">$value</A></STRONG><DD>
if present, set key to this value
</DL>
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_TableLink_table_linkn">$db -> TableLink ($table, $linkname, $value)</A></H2>
<P>
Get and/or set a link description for an table. If no
<CODE>$linkname</CODE> is given, returns all links for that table.
<DL>
<DT><STRONG>$table</STRONG><DD>
Name of <CODE>table(s)</CODE>
<br> <DT><STRONG><A NAME="_linkname">$linkname</A></STRONG><DD>
Name of link to set/get
<br> <DT><STRONG>$value</STRONG><DD>
if present, this must be a reference to a hash with the link decription.
See !Links for more information.
</DL>
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_MetaData_table_metada">$db -> MetaData ($table, $metadata, $clear)</A></H2>
<P>
Get and/or set the meta data for the given table.
<DL>
<DT><STRONG>$table</STRONG><DD>
Name of <CODE>table(s)</CODE>
<br> <DT><STRONG><A NAME="_metadata">$metadata</A></STRONG><DD>
If present, this must be a reference to a hash with the new metadata. You
should only use this if you really know what you are doing.
<br> <DT><STRONG><A NAME="_clear">$clear</A></STRONG><DD>
Clears the metadata for the given table, The next call to DBIx::Database
-> new will recreate the metadata. Useful if your table has changed
(e.g. by ALTER TABLE).
</DL>
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_AllTables">$db -> AllTables</A></H2>
<P>
This returns a reference to a hash of the keys to all the tables of the
datasource.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_AllNames_table_">$db -> AllNames ($table)</A></H2>
<P>
Returns a reference to an array of all fieldnames for the given table.
<P>
<HR>
<H2><img src="sq.gif" width="16" height="16" alt="-"> <A NAME="_db_AllTypes_table_">$db -> AllTypes ($table)</A></H2>
<P>
Returns a reference to an array of all fieldtypes for the given table.
<DL>
<DT><STRONG><A NAME="_db">$db -> do ($statement, $attribs, \%params)</A></STRONG><DD>
Same as DBI. Executes a single SQL statement on the open database.
</DL>
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.6.html">PREV (WORKING WITH MULTIPLE TABLES)</a>] [<a href="Recordset.pod.8.html">NEXT (Casesensitive/insensitiv)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.8.html
Index: Recordset.pod.8.html
===================================================================
<HTML>
<HEAD>
<TITLE>Casesensitive/insensitiv</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Casesensitive_insensitiv">Casesensitive/insensitiv</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.7.html">PREV (DBIx::Database)</a>] [<a href="Recordset.pod.9.html">NEXT (FETCHSIZE / $FetchsizeWarn)</a>] <br><hr>
<P>
In SQL all names (field/tablenames etc.) should be case insensitive.
Various DBMS handle the case of names differently. For that reason <EM>DBIx::Recordset</EM>
translates all names to lower case, ensuring your application will run with
any DBMS, regardless of whether names are returned in lower/uppercase by
the DBMS. Some DBMS are case-sensitive (I know at least Sybase, depending
on your collate settings). To use such a case-sensitive DBMS, it is best to
create your database with all names written in lowercase. In a situation
where this isn't possible, you can set <CODE>$PreserveCase</CODE> to 1. In this case DBIx::Recordset will not perform any case translation. <STRONG>NOTE:</STRONG> <CODE>$PreserveCase</CODE> is still experimental and may change in future releases.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.7.html">PREV (DBIx::Database)</a>] [<a href="Recordset.pod.9.html">NEXT (FETCHSIZE / $FetchsizeWarn)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.9.html
Index: Recordset.pod.9.html
===================================================================
<HTML>
<HEAD>
<TITLE>FETCHSIZE / $FetchsizeWarn</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="FETCHSIZE_FetchsizeWarn">FETCHSIZE / $FetchsizeWarn</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.8.html">PREV (Casesensitive/insensitiv)</a>] [<a href="Recordset.pod.10.html">NEXT (DEBUGGING)</a>] <br><hr>
<P>
Some operations in Perl (i.e. foreach</A>, assigning arrays) need to know the size of the whole array. When Perl
needs to know the size of an array it call the method
<CODE>FETCHSIZE</CODE>. Since not all DBD drivers/DBMS returns the number of selected rows after
an SQL <CODE>SELECT</CODE>, the only way to really determine the number of selected rows would be to
fetch them all from the DBMS. Since this could cause a lot of work, it may
be very inefficent. Therefore <EM>DBIx::Recordset</EM> by default calls <CODE>die()</CODE> when Perl calls FETCHSIZE. If you know
your DBD drivers returns the correct value in <CODE>$sth</CODE> -> <CODE>rows</CODE>
after the execution of an <CODE>SELECT</CODE>, you can set <CODE>$FetchsizeWarn</CODE> to zero to let
<CODE>FETCHSIZE</CODE> return the value from <CODE>$sth</CODE> -> <CODE>rows</CODE>. Setting it to 1 will cause
<EM>DBIx::Recordset</EM> to only issue a warning, but perform the operation.
<P>
<STRONG>NOTE:</STRONG> Since I don't have enough experience with the behaviour of this feature
with different DBMS, this is considered experimental.
<p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.8.html">PREV (Casesensitive/insensitiv)</a>] [<a href="Recordset.pod.10.html">NEXT (DEBUGGING)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/Recordset.pod.cont.html
Index: Recordset.pod.cont.html
===================================================================
<HTML>
<HEAD>
<TITLE>DBIx::Recordset - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Content-Recordset.pod.cont">DBIx::Recordset - Content</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.1.html">NEXT (DESCRIPTION)</a>] <br><HTML>
<HEAD>
<TITLE>DBIx::Recordset - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY>
<!-- INDEX BEGIN -->
<UL>
<LI><A href="Recordset.pod.1.html#DESCRIPTION">DESCRIPTION</A>
<LI><A href="Recordset.pod.2.html#ARGUMENTS">ARGUMENTS</A>
<UL>
<LI><A href="Recordset.pod.2.html#Setup_Parameters">Setup Parameters</A>
<LI><A href="Recordset.pod.2.html#Link_Parameters">Link Parameters</A>
<LI><A href="Recordset.pod.2.html#Where_Parameters">Where Parameters</A>
<LI><A href="Recordset.pod.2.html#Search_parameters">Search parameters</A>
<LI><A href="Recordset.pod.2.html#Execute_parameters">Execute parameters</A>
</UL>
<LI><A href="Recordset.pod.3.html#METHODS">METHODS</A>
<LI><A href="Recordset.pod.4.html#DATA_ACCESS">DATA ACCESS</A>
<LI><A href="Recordset.pod.5.html#MODIFYING_DATA_DIRECTLY">MODIFYING DATA DIRECTLY</A>
<LI><A href="Recordset.pod.6.html#WORKING_WITH_MULTIPLE_TABLES">WORKING WITH MULTIPLE TABLES</A>
<UL>
<LI><A href="Recordset.pod.6.html#Joins">Joins</A>
<LI><A href="Recordset.pod.6.html#Join_Example_">Join Example:</A>
<LI><A href="Recordset.pod.6.html#Links">Links</A>
<LI><A href="Recordset.pod.6.html#LinkName">LinkName</A>
<LI><A href="Recordset.pod.6.html#Automatic_detection_of_links">Automatic detection of links</A>
</UL>
<LI><A href="Recordset.pod.7.html#DBIx_Database">DBIx::Database</A>
<UL>
<LI><A href="Recordset.pod.7.html#new_data_source_username_p">new ($data_source, $username, $password, \%attr, $saveas, $keepopen)</A>
<LI><A href="Recordset.pod.7.html#_db_DBIx_Database_DBHdl">$db = DBIx::Database -> DBHdl </A>
<LI><A href="Recordset.pod.7.html#_db_DBIx_Database_Get_na">$db = DBIx::Database -> Get ($name)</A>
<LI><A href="Recordset.pod.7.html#_db_TableAttr_table_key_">$db -> TableAttr ($table, $key, $value)</A>
<LI><A href="Recordset.pod.7.html#_db_TableLink_table_linkn">$db -> TableLink ($table, $linkname, $value)</A>
<LI><A href="Recordset.pod.7.html#_db_MetaData_table_metada">$db -> MetaData ($table, $metadata, $clear)</A>
<LI><A href="Recordset.pod.7.html#_db_AllTables">$db -> AllTables</A>
<LI><A href="Recordset.pod.7.html#_db_AllNames_table_">$db -> AllNames ($table)</A>
<LI><A href="Recordset.pod.7.html#_db_AllTypes_table_">$db -> AllTypes ($table)</A>
</UL>
<LI><A href="Recordset.pod.8.html#Casesensitive_insensitiv">Casesensitive/insensitiv</A>
<LI><A href="Recordset.pod.9.html#FETCHSIZE_FetchsizeWarn">FETCHSIZE / $FetchsizeWarn</A>
<LI><A href="Recordset.pod.10.html#DEBUGGING">DEBUGGING</A>
<LI><A href="Recordset.pod.11.html#SECURITY">SECURITY</A>
<LI><A href="Recordset.pod.12.html#Compatibility_with_different_DBD">Compatibility with different DBD drivers</A>
<LI><A href="Recordset.pod.13.html#EXAMPLES">EXAMPLES</A>
<LI><A href="Recordset.pod.14.html#SUPPORT">SUPPORT</A>
<LI><A href="Recordset.pod.15.html#AUTHOR">AUTHOR</A>
</UL>
<!-- INDEX END -->
<hr><p>[<a href="" >HOME</a>] [<a href="Recordset.pod.cont.html">CONTENT</a>] [<a href="Recordset.pod.1.html">NEXT (DESCRIPTION)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</body></html>
1.1 modperl-site/embperl/TipsAndTricks.pod.1.html
Index: TipsAndTricks.pod.1.html
===================================================================
<HTML>
<HEAD>
<TITLE>Tips and Tricks</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Tips_and_Tricks">Tips and Tricks</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.cont.html">PREV (Tips & Tricks - Content)</a>] [<a href="TipsAndTricks.pod.2.html">NEXT (Alternative Way To Do Global Variables, using __PACKAGE__)</a>] <br><hr>
<P>
This document follows on from the Embperl/EmbperlObject introductory
tutorial. As you can see from that, Embperl/EmbperlObject enables extremely
powerful websites to be built using a very intuitive object-oriented
structure. Now, we'll look at some additional, ``unofficial'' techniques
which may also be useful in certain circumstances.
<P>
This is a small collection of personal tricks which I have developed over
the course of months using EmbperlObject in my own websites. I hope they
are useful, or at least spur you on to develop your own frameworks and
share these with others.
<P>
If you have any Tips & Tricks you want to share with the public please
send them to <A HREF="mailto:richter@dev.ecos.de">richter@dev.ecos.de</A> .
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.cont.html">PREV (Tips & Tricks - Content)</a>] [<a href="TipsAndTricks.pod.2.html">NEXT (Alternative Way To Do Global Variables, using __PACKAGE__)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.2.html
Index: TipsAndTricks.pod.2.html
===================================================================
<HTML>
<HEAD>
<TITLE>Alternative Way To Do Global Variables, using __PACKAGE__</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Alternative_Way_To_Do_Global_Var">Alternative Way To Do Global Variables, using __PACKAGE__</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.1.html">PREV (Tips and Tricks)</a>] [<a href="TipsAndTricks.pod.3.html">NEXT (Global Variables Via Namespaces)</a>] <br><hr>
<P>
In the process of developing a large website I have found it can be a
little onerous at times to use the Request object to pass around global
data. I would like to just create variables like <CODE>$xxx</CODE> rather
than typing $req->{xxx} all the time. It may not seem like much, but
after a while your code can start looking a lot more complex because of all
the extra brackets and suchlike. As a typical lazy programmer, I looked for
a way to simplify this.
<P>
The method I am going to describe should be used with caution, because it
can increase memory useage rather dramatically if you're not careful. The
way I use it, no extra memory is used, but you do need to be aware of the
issues.
<P>
Basically, you change the way you include files from <EM>/base.html</EM>, so that they are included into the same package as <EM>/base.html</EM>:
<P>
<PRE> [- Execute ({inputfile => '*', package => __PACKAGE__}) -]
</PRE>
<P>
You should only do this with HTML files which are included from
<EM>/base.html</EM>, not with the files such as <EM>subs.html</EM> - those files have to be in their own packages in order for Perl
inheritance to work. You can't use this technique with any files which are
accessed via method calls.
<P>
So how does this make things better? Well, since all these files now share
the same package, any variables which are created in one of the files is
accessible to any of the other files. This means that if you create
<CODE>$xxx</CODE> in <EM>/init.html</EM>, then you can access <CODE>$xxx</CODE> in
<EM>/head.html</EM> or any other file. This effectively gives you global variables across all
the files which are included from <EM>/base.html</EM>
into the same package as <EM>/base.html</EM>.
<P>
The thing you need to be careful of here is that if one of these files is
included more than once elsewhere on the website, then it will be
seperately compiled for that instance - thus taking up more memory. This is
the big caveat. As a rule, if your files are all just included once by <EM>/base.html</EM>, then you should be fine. Note that you'll also need to change any calls
to parent files, for example:
<P>
<EM>/contact/init.html</EM>
<P>
<PRE> [- Execute ({inputfile => '../init.html', package => __PACKAGE__}) -]
</PRE>
<P>
<PRE> [-
# Do some setup specific to this subdirectory
-]
</PRE>
<P>
This is ok, since <EM>../init.html</EM> will still be compiled into the same package as the rest of the files
included from <EM>/base.html</EM>, and so only one version of it will exist in the Embperl cache. Thus
memory usage is not increased.
<P>
I like this technique because it simplifies the look of my code, which is
important for projects containing complex algorithms. It is not the
``official'' way to implement globals though, and should be used with care.
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.1.html">PREV (Tips and Tricks)</a>] [<a href="TipsAndTricks.pod.3.html">NEXT (Global Variables Via Namespaces)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.3.html
Index: TipsAndTricks.pod.3.html
===================================================================
<HTML>
<HEAD>
<TITLE>Global Variables Via Namespaces</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Global_Variables_Via_Namespaces">Global Variables Via Namespaces</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.2.html">PREV (Alternative Way To Do Global Variables, using __PACKAGE__)</a>] [<a href="TipsAndTricks.pod.4.html">NEXT (Handling Queries in DBI)</a>] <br><hr>
<P>
The previous section described a way to share variables between different
files which are included from <EM>/base.html</EM>, by using the same package across all the files. However this doesn't help
us much when dealing with the method files such as <EM>subs.html</EM>, because these files have to have their own packages - so we are back to
square one.
<P>
There is another way to share variables across even different packages, and
that is by using namespaces. For variables that need to be accessible even
from <EM>subs.html</EM>, you could use a namespace which is specific to your website. For example,
if your website domain is mydomain.com, then you could create variables
using the form
<P>
<PRE> $mydomain::xxx = "hello";
</PRE>
<P>
As long as you then make sure that you only use this namespace on this
website (and other websites on the same Apache web server use their own
namespaces), then you shouldn't get any conflicts. Once again, use this
with caution, since you introduce the possibility of inadvertently sharing
variables between completely different websites. For example, if you cut
and paste some useful code from one website to another, you will need to
make sure you change the namespace of any globals. Otherwise, you could get
some very obscure bugs, since different requests to the various websites
could conflict.
<P>
You also need to be careful about variable initialization, since these
globals will now exist between different requests. So, it's possible that
if you don't re-initialize a global variable, then it may contain some
random value from a previous request. This can result in obscure bugs. Just
be careful to initialize all variables properly and you'll be fine.
<P>
Finally, note that Embperl will only clean up variables which don't have an
explicit package (i.e. are in one of the packages automatically set up by
Embperl). Variables in other namespaces are not automatically cleaned up.
As a result, you need to pay closer attention to cleaning up if you use
your own namespaces. The safe way to clean up a variable is simply to
'undef' it.
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.2.html">PREV (Alternative Way To Do Global Variables, using __PACKAGE__)</a>] [<a href="TipsAndTricks.pod.4.html">NEXT (Handling Queries in DBI)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.4.html
Index: TipsAndTricks.pod.4.html
===================================================================
<HTML>
<HEAD>
<TITLE>Handling Queries in DBI</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Handling_Queries_in_DBI">Handling Queries in DBI</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.3.html">PREV (Global Variables Via Namespaces)</a>] [<a href="TipsAndTricks.pod.5.html">NEXT (Handling Exits)</a>] <br><hr>
<P>
If you are like me, you probably use DBI extensively to enable your dynamic
websites. I have found the cleanup of queries to be onerous - e.g. calling
<CODE>finish()</CODE> on queries. If you don't do that, then you tend to
get warnings in your error log about unfinished queries.
<P>
What I do these days is use a global hash, called e.g. %domain::query (see
the previous section for using namespaces to safely implement global
variables). Then, whenever I create a query, I use this variable. For
example:
<P>
<PRE> $domain::query{first_page} = $domain::dbh->prepare (qq{
SELECT *
FROM pages
WHERE page = 1
});
$domain::query{first_page}->execute();
my $first_page = $domain::query{first_page}->fetchrow_hashref();
</PRE>
<P>
This little pattern, I find, makes all my queries easier to read and keep
track of. You give each one a name in the %domain::query hash that makes
sense. Then, at the end of each request, in the
<EM>/cleanup.html</EM> file, you can do something like this:
<P>
<PRE> while (($name, $query) = each (%domain::query))
{
$query->finish();
}
$domain::dbh->disconnect();
</PRE>
<P>
Once again, this method is not really the ``official'' way of doing things
in Embperl. You should use the Request object to pass around global
variables if you're not comfortable with the risks involved with namespaces
(e.g. conflicting websites on the same web server).
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.3.html">PREV (Global Variables Via Namespaces)</a>] [<a href="TipsAndTricks.pod.5.html">NEXT (Handling Exits)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.5.html
Index: TipsAndTricks.pod.5.html
===================================================================
<HTML>
<HEAD>
<TITLE>Handling Exits</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Handling_Exits">Handling Exits</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.4.html">PREV (Handling Queries in DBI)</a>] [<a href="TipsAndTricks.pod.6.html">NEXT (Handling Errors)</a>] <br><hr>
<P>
You will often find that you want to terminate a page before the end. This
doesn't necessarily indicate an error condition; it can be just that you've
done all you want to do. When you do this, it is good to first clean up,
otherwise you can get annoying warnings showing up in your error logs.
<P>
I use the following framework. <EM>/cleanup.html</EM> is Executed from
<EM>/base.html</EM>, and it is the last thing that is done. It calls the
<CODE>cleanup()</CODE> function in the <EM>/subs.html</EM> file:
<P>
<EM>/cleanup.html</EM>
<P>
<PRE> [-
$subs->cleanup ();
-]
</PRE>
<P>
<EM>/subs.html</EM>
<P>
<PRE> [!
sub cleanup
{
while (($name, $query) = each (%domain::query))
{
$query->finish();
}
$domain::dbh->disconnect();
}
</PRE>
<P>
<PRE> sub clean_exit
{
cleanup();
exit();
}
!]
</PRE>
<P>
Now, whenever I want to exit prematurely, I use a call to
$subs->clean_exit() rather than just <CODE>exit().</CODE> This makes
sure that the queries and database connections are shut down nicely.
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.4.html">PREV (Handling Queries in DBI)</a>] [<a href="TipsAndTricks.pod.6.html">NEXT (Handling Errors)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.6.html
Index: TipsAndTricks.pod.6.html
===================================================================
<HTML>
<HEAD>
<TITLE>Handling Errors</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Handling_Errors">Handling Errors</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.5.html">PREV (Handling Exits)</a>] [<a href="TipsAndTricks.pod.7.html">NEXT (Development and Production Websites)</a>] <br><hr>
<P>
The EMBPERL_OBJECT_FALLBACK directive in <EM>httpd.conf</EM> allows you to set a file which will be loaded in the event that the
requested file is not found. This file should be relative to the same
directory as
<EM>base.html</EM>.
<P>
I have found that making a special /errors/ directory is useful, because it
enables that special subdirectory to define its own
<EM>head.html</EM> file, <EM>init.html</EM> and so on. So, I then just put this in <EM>/notfound.html</EM>:
<P>
<PRE> [-
$http_headers_out{'Location'} = "/errors/";
clean_exit();
-]
</PRE>
<P>
See the previous section, ``Handling Exits'' for more on
<CODE>clean_exit().</CODE>
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.5.html">PREV (Handling Exits)</a>] [<a href="TipsAndTricks.pod.7.html">NEXT (Development and Production Websites)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.7.html
Index: TipsAndTricks.pod.7.html
===================================================================
<HTML>
<HEAD>
<TITLE>Development and Production Websites</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Development_and_Production_Websi">Development and Production Websites</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.6.html">PREV (Handling Errors)</a>] [<a href="TipsAndTricks.pod.8.html">NEXT (Author)</a>] <br><hr>
<P>
When I am developing a website, I usually use at least two machines. I have
a workstation where I do developing and testing, and a separate production
server, which is accessed by the public. When I am finished making changes
to the development version of the website, I move it over to the production
server for testing there. However when I do this, I usually don't copy it
immediately over the existing production version, because there are
sometimes issues with Perl modules which haven't been installed on the
server, or other issues which break the code on a different machine. So I
use a separate virtual server and subdomain (which is easy if you run your
own DNS) to test the new version. For example if the production version of
the server is at www.mydomain.com, then I might do testing on the
production server under test.mydomain.com, or beta. or whatever subdomain
you like. This means you have to create a new virtual server in the
httpd.conf file. You also obviously create a new directory for the test
server (see below for an example).
<P>
When you do all this, you end up with a very nice, isolated testing
environment on the same server as production. Obviously you hopefully did
all your major testing on your workstation, where you can crash the machine
and it doesn't matter too much. The production server testbed is a last
staging area before production, to get rid of any lingering glitches or
omissions. When you're sure it's all working correctly you just copy the
files from one directory tree (test) to another (production) on the same
machine. This test server can also be used as a beta of the new production
version. Friendly users can be given access to the new version, while the
old version is still running.
<P>
One issue that comes up when you do this is that of databases. It is very
likely that you will be using a special test database rather than the live
one to test your new version. It would be very unwise to use a production
database for testing. So your production database might be called
``mydatabase'', and the test one called ``mydatabase_test''. This is fine,
but it means that you have to remember to change the database name in your
code when you copy the files over to production. This is very error prone.
The solution is to set variables like the database name in httpd.conf, by
setting an environment variable. You just add it to the virtual server
section.
<P>
Here is a real example of two virtual servers on the same production
machine, which use two different directories, separate log files and
different databases. The website is crazyguyonabike.com, which is a journal
of a bicycle ride I did across America in 1998. I decided to expand the
site to allow other cyclists to upload their own journals, which resulted
in substantial changes to the code. I wanted to keep the original site up
while testing the new version, which I put under new.crazyguyonabike.com.
Here are the relevant apache settings:
<P>
<EM>/etc/apache/httpd.conf</EM>
<P>
<PRE> # The production server
<VirtualHost 10.1.1.2:80>
ServerName www.crazyguyonabike.com
SSLDisable
ServerAdmin neil@nilspace.com
DocumentRoot /www/crazyguyonabike/com/htdocs
DirectoryIndex index.html
ErrorLog /www/crazyguyonabike/com/logs/error_log
TransferLog /www/crazyguyonabike/com/logs/access_log
ErrorDocument 403 /
ErrorDocument 404 /
PerlSetEnv WEBSITE_DATABASE crazyguyonabike
PerlSetEnv WEBSITE_ROOT /www/crazyguyonabike/com/htdocs
PerlSetEnv EMBPERL_DEBUG 0
PerlSetEnv EMBPERL_ESCMODE 0
PerlSetEnv EMBPERL_OPTIONS 16
PerlSetEnv EMBPERL_MAILHOST mail.nilspace.com
PerlSetEnv EMBPERL_OBJECT_BASE base.html
PerlSetEnv EMBPERL_OBJECT_FALLBACK notfound.html
</VirtualHost>
</PRE>
<P>
<PRE> <VirtualHost 10.1.1.2:80>
ServerName crazyguyonabike.com
Redirect / <A HREF="http://www.crazyguyonabike.com">http://www.crazyguyonabike.com</A>
</VirtualHost>
</PRE>
<P>
<PRE> # Set EmbPerl handler for main directory
<Directory "/www/crazyguyonabike/com/htdocs/">
<FilesMatch ".*\.html$">
SetHandler perl-script
PerlHandler HTML::EmbperlObject
Options ExecCGI
</FilesMatch>
</Directory>
</PRE>
<P>
<PRE> # The test server
<VirtualHost 10.1.1.2:80>
ServerName new.crazyguyonabike.com
SSLDisable
ServerAdmin neil@nilspace.com
DocumentRoot /www/crazyguyonabike/com/new
Alias /pics /www/crazyguyonabike/com/pics
DirectoryIndex index.html
ErrorLog /www/crazyguyonabike/com/logs/new_error_log
TransferLog /www/crazyguyonabike/com/logs/new_access_log
ErrorDocument 401 /user/register/
ErrorDocument 403 /
ErrorDocument 404 /
PerlSetEnv WEBSITE_DATABASE crazyguyonabike_new
PerlSetEnv WEBSITE_ROOT /www/crazyguyonabike/com/new
PerlSetEnv EMBPERL_DEBUG 0
PerlSetEnv EMBPERL_ESCMODE 0
PerlSetEnv EMBPERL_OPTIONS 16
PerlSetEnv EMBPERL_MAILHOST mail.nilspace.com
PerlSetEnv EMBPERL_OBJECT_BASE base.html
PerlSetEnv EMBPERL_OBJECT_FALLBACK notfound.html
</VirtualHost>
</PRE>
<P>
<PRE> # Set EmbPerl handler for new directory
<Directory "/www/crazyguyonabike/com/new/">
<FilesMatch ".*\.html$">
SetHandler perl-script
PerlHandler HTML::EmbperlObject
Options ExecCGI
</FilesMatch>
</Directory>
</PRE>
<P>
<PRE> # Restrict access to test server
<Directory /www/crazyguyonabike/com/new>
AuthType Basic
AuthName CrazyTest
Auth_MySQL_DB http_auth
Auth_MySQL_Encryption_Types Plaintext
require valid-user
PerlSetEnv EMBPERL_OPTIONS 16
PerlSetEnv EMBPERL_MAILHOST mail.nilspace.com
</Directory>
</PRE>
<P>
Note that the test and production servers each get their own databases,
directories and log files.
<P>
You can also see that I restrict access to the test server (which is
generally wise, unless you actually like hackers potentially screwing with
your head while testing). For basic authentication I use mod_auth_mysql,
which is available from the MySQL website. It is nice because it allows you
to authenticate based on a MySQL database.
<P>
When you use PerlSetEnv to pass in variables, you access these variables in
your code as follows:
<P>
<PRE> $db_name = $ENV{WEBSITE_DATABASE};
</PRE>
<P>
If you move those constants which differ between the test and production
versions of the same code into the httpd.conf file, then you can just copy
the files over from the test directories to the production directory
without any alterations. This cuts down on editing errors and also
documents specific constants in one place.
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.6.html">PREV (Handling Errors)</a>] [<a href="TipsAndTricks.pod.8.html">NEXT (Author)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.8.html
Index: TipsAndTricks.pod.8.html
===================================================================
<HTML>
<HEAD>
<TITLE>Author</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Author">Author</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.7.html">PREV (Development and Production Websites)</a>] <br><hr>
<P>
Neil Gunton <A HREF="mailto:neil@nilspace.com">neil@nilspace.com</A>
<p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.7.html">PREV (Development and Production Websites)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</BODY>
</HTML>
1.1 modperl-site/embperl/TipsAndTricks.pod.cont.html
Index: TipsAndTricks.pod.cont.html
===================================================================
<HTML>
<HEAD>
<TITLE>Tips & Tricks - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY bgcolor="#FFFFFF">
<blockquote>
<blockquote>
<table>
<tr>
<td valign=bottom align=center>
<font size=6><strong>
<A NAME="Content-TipsAndTricks.pod.cont">Tips & Tricks - Content</a></strong></font>
</td><td rowspan=2 align=right></td>
</tr><tr><td valign=top align=center>
<img src="line.jpg" alt="________" WIDTH="732" HEIGHT="35" >
</td></tr></table>
[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.1.html">NEXT (Tips and Tricks)</a>] <br><HTML>
<HEAD>
<TITLE>Tips & Tricks - Content</TITLE>
<LINK REV="made" HREF="mailto:root@venus.gr.ecos.de">
</HEAD>
<BODY>
<!-- INDEX BEGIN -->
<UL>
<LI><A href="TipsAndTricks.pod.1.html#Tips_and_Tricks">Tips and Tricks</A>
<LI><A href="TipsAndTricks.pod.2.html#Alternative_Way_To_Do_Global_Var">Alternative Way To Do Global Variables, using __PACKAGE__</A>
<LI><A href="TipsAndTricks.pod.3.html#Global_Variables_Via_Namespaces">Global Variables Via Namespaces</A>
<LI><A href="TipsAndTricks.pod.4.html#Handling_Queries_in_DBI">Handling Queries in DBI</A>
<LI><A href="TipsAndTricks.pod.5.html#Handling_Exits">Handling Exits</A>
<LI><A href="TipsAndTricks.pod.6.html#Handling_Errors">Handling Errors</A>
<LI><A href="TipsAndTricks.pod.7.html#Development_and_Production_Websi">Development and Production Websites</A>
<LI><A href="TipsAndTricks.pod.8.html#Author">Author</A>
</UL>
<!-- INDEX END -->
<hr><p>[<a href="" >HOME</a>] [<a href="TipsAndTricks.pod.cont.html">CONTENT</a>] [<a href="TipsAndTricks.pod.1.html">NEXT (Tips and Tricks)</a>] <br>
<font color="#808080">___________________________________________________________________________________<br>
HTML::Embperl - Copyright (c) 1997-2001 Gerald Richter / <a href="http://www.ecos.de/">ecos gmbh</a>
</font></p>
</blockquote>
</blockquote>
</td></tr></table></body>
</html>
</body></html>