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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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 [EMAIL PROTECTED] 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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]">[EMAIL PROTECTED]</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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]">[EMAIL PROTECTED]</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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]">[EMAIL PROTECTED]</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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]">[EMAIL PROTECTED]</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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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 [EMAIL PROTECTED] 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 [EMAIL PROTECTED] 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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]">[EMAIL PROTECTED]</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:[EMAIL PROTECTED]"> </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:[EMAIL PROTECTED]"> </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>