<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>UseStrict Consulting &#187; subroutine</title>
	<atom:link href="http://usestrict.net/tag/subroutine/feed/" rel="self" type="application/rss+xml" />
	<link>http://usestrict.net</link>
	<description>Professional IT Solutions &#38; Training</description>
	<lastBuildDate>Sat, 12 May 2012 14:25:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Recursion with Perl and CDS</title>
		<link>http://usestrict.net/2009/06/recursion-with-perl-and-cds/</link>
		<comments>http://usestrict.net/2009/06/recursion-with-perl-and-cds/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 22:16:10 +0000</pubDate>
		<dc:creator>vinny</dc:creator>
				<category><![CDATA[Perl]]></category>
		<category><![CDATA[CDS]]></category>
		<category><![CDATA[complex data structures]]></category>
		<category><![CDATA[recursion]]></category>
		<category><![CDATA[subroutine]]></category>
		<category><![CDATA[trim]]></category>
		<category><![CDATA[trimming]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=720</guid>
		<description><![CDATA[Recursion on Perl Complex Data Structures made easy.]]></description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: Changed subroutine to comply with <a href="http://www.amazon.com/gp/product/0596001738?ie=UTF8&#038;tag=usst-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0596001738" target="_blank">Perl Best Practices</a><img src="http://www.assoc-amazon.com/e/ir?t=usst-20&#038;l=as2&#038;o=1&#038;a=0596001738" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p><strong>Update2</strong>: Removed the prototype from the subroutine.</p>
<p>I&#8217;ve always had a problem with recursion. Not with the general theory that a function will call itself, etc &#8211; no, that&#8217;s easy. The hard part was when I had to deal with complex data structures in Perl (an array- or hashref containing a hash of arrays of hashes, a gazillion levels deep). Well, I guess anyone would have a hard time with that kind of data.</p>
<p>Anyway, in this post I don&#8217;t intend to get all complicated explaining all the kinds of recursions out there. If you want that, check <a href="http://en.wikipedia.org/wiki/Recursion_(computer_science)" target="_blank">this article at wikipedia</a>. What I do want to do is help all of those who are in the situation I was in, by explaining in the simplest way possible how to deal with this scenario.<span id="more-720"></span></p>
<p>Let&#8217;s start with a need. I have a complex data structure that needs its spaces trimmed on both sides. But since I&#8217;m lazy, I&#8217;d like my subroutine to modify the data directly, and not return the modified value (pass by reference, not pass by value). </p>
<p>Here&#8217;s our data structure:</p>
<p>&nbsp;</p>
<pre class="brush:perl">
    my $data = [
                       {
                          key1 => '   trim me!   ',
                          key2 => '   trim me too!    ',
                       },
                       [
                          'some element to trim   ',
                          '    another one    ',
                       ],
                       '    a simple string needing trimming    ',
                  ];
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>$data explained</code>:  an array containing 3 elements: element 0 is a hashref of keys <code>"key1"</code> and <code>"key2"</code>, element 1 is an arrayref of 2 elements. Element 3 is a simple string. All values have some extra spaces that need trimming (or so they say). We could use whatever number of levels and data types we want (except for anonymous subroutines, I guess &#8211; let&#8217;s not get too complicated).</p>
<p>Now, to trim all that, I want to be able to simply call <code>trim()</code> à la PHP. </p>
<p>&nbsp;</p>
<pre class="brush:perl">
     trim($data); # note the lack of the lvalue (lvalue = rvalue)
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>I also want it to accept simple arrays and hashes, and the references thereof: <code>trim(@array); trim(@array); trim(%hash); trim(%hash); trim($string)</code>. After all, I never know what kind of data my colleagues will be working with. Better have it deal with everything.</p>
<p>The logic to do that is this:  our subroutine will have to do the trimming (s///g) on scalars only. For that, it has to check if the data it received is a hash, array, etc, and if it is, iterate through each element and trim the value&#8230; but only if the element is not itself a hash, array, etc. Found it confusing? No problem, it really is.</p>
<p>In Perl, if I tried to remove the white space from element 0 of my <code>$data</code>  variable, it wouldn&#8217;t work. The reason being is that if I printed <code>$data->[0]</code> onto the screen, I&#8217;d get a funny looking output, something like <code>HASH(0x1004f5f0)</code>. That&#8217;s Perl&#8217;s way of saying that you have a HASH structure stored in memory position 0x1004f5f0. You can try to trim the spaces off of that string, but it won&#8217;t do you any good. The elements of your hash will still be untouched. That&#8217;s why you need to <em>de-reference</em> your data structures and dive into them.</p>
<p>To de-reference a structure is simple, just add a % in front of the variable if it&#8217;s a hashref, or an @ if it&#8217;s an array. But how do you know which is which? Use <code>ref()</code>.</p>
<p>&nbsp;</p>
<pre class="brush:perl">
       print ref($data->[0]) . "n"; # HASH
       print ref($data->[1]) . "n"; # ARRAY
       print ref($data->[3]) . "n"; # empty string, which is false
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>ref()</code> tells you what kind of data you are dealing with. It returns <code>CODE</code> if you have a closure or anonymous subroutine, but we&#8217;re not going there today.</p>
<p>So, now that we know how to identify the type of element we&#8217;re going to be working with, we can build our subroutine&#8230;</p>
<p>&nbsp;</p>
<pre class="brush:perl">
sub trim() {
	for my $param (@_) {
		if (ref($param) eq 'ARRAY') {
			for my $element (@{$param}) {
				trim($element);
			}
		}
		elsif (ref($param) eq 'HASH') {
			for my $val (values %{$param}) {
				trim($val);
			}
		}
		elsif (ref($param) eq 'CODE') {
			return;
		}
		else {
			$param =~ s/(^s+|s+$)//g;
		}
	}
}
</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><code>trim()</code> explained:</p>
<p>We&#8217;re working with passing elements by reference instead of by value. This means that the elements themselves will be modified &#8211; no need to return any data. The first thing we do is to iterate through all parameters passed to <code>trim()</code>. In a subroutine, parameters (in our case, variables) are populated into the special <code>@_</code> array, allowing us to call <code>trim($var1, $var2, $var3)</code>  if we want.</p>
<p>We iterate through all elements of <code>@_</code> and verify if they are an Array. If they are, we iterate through each of their elements once, and call <code>trim()</code> again against them. That will handle as many nested arrays we want (or that your computer can handle). Now we have to make it deal with hashes. Same technique &#8211; use <code>ref()</code>  to see if it&#8217;s a hash. If it is, then iterate through each of its key/pair elements. There are several ways to do that. I personally prefer calling <code>keys</code>  to get the keys and use them to fetch the values of the hash. The value of the hash is passed to <code>trim()</code> for more validation. We also check to see if we received a <code>sub { }</code> (anonymous subroutine). In that case, we do nothing, just return.</p>
<p>Finally, after handling Arrays, Hashes and Anonymous subroutines, we can set up the actual trimming of the strings. We take the <code>$_[$i]</code> which is the parameter passed and remove the leading and trailing spaces with one neat substitution: <code>^s+</code> stands for leading spaces, <code>s+$</code> stands for trailing spaces, and it&#8217;s all joined by the <code>(  |  )</code> (this or that). We only call it once because we&#8217;re using the global (g) modifier of the substitution <code>s///g</code>.</p>
<p>And that&#8217;s all there is to it!</p>
<p><em>A note on prototypes:</em> This post generated a healthy discussion on prototypes. I had originally added the dollar prototype to the <code>trim()</code> subroutine, but that was forcing it to accept only scalars (strings and references), and not working with normal hashes and arrays. Thanks to everyone who participated in the discussion.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/06/recursion-with-perl-and-cds/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Perl: Connecting to an Oracle database WITHOUT having an installed client</title>
		<link>http://usestrict.net/2009/01/perl-connecting-to-an-oracle-database-without-having-an-installed-client/</link>
		<comments>http://usestrict.net/2009/01/perl-connecting-to-an-oracle-database-without-having-an-installed-client/#comments</comments>
		<pubDate>Sun, 11 Jan 2009 03:41:28 +0000</pubDate>
		<dc:creator>vinny</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[alternative]]></category>
		<category><![CDATA[archive tool]]></category>
		<category><![CDATA[array reference]]></category>
		<category><![CDATA[bastard]]></category>
		<category><![CDATA[BEGIN]]></category>
		<category><![CDATA[client]]></category>
		<category><![CDATA[CPAN]]></category>
		<category><![CDATA[day]]></category>
		<category><![CDATA[dbd::oracle]]></category>
		<category><![CDATA[dbi]]></category>
		<category><![CDATA[dbs]]></category>
		<category><![CDATA[ENV]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[fileName]]></category>
		<category><![CDATA[filenames]]></category>
		<category><![CDATA[hash]]></category>
		<category><![CDATA[hostname]]></category>
		<category><![CDATA[intention]]></category>
		<category><![CDATA[ip port]]></category>
		<category><![CDATA[lazy bastard]]></category>
		<category><![CDATA[libs]]></category>
		<category><![CDATA[oracle 10g client]]></category>
		<category><![CDATA[oracle client]]></category>
		<category><![CDATA[oracle database]]></category>
		<category><![CDATA[PAR]]></category>
		<category><![CDATA[password]]></category>
		<category><![CDATA[perl archive]]></category>
		<category><![CDATA[perl module]]></category>
		<category><![CDATA[Pretty]]></category>
		<category><![CDATA[quickie]]></category>
		<category><![CDATA[Solaris]]></category>
		<category><![CDATA[subroutine]]></category>
		<category><![CDATA[SUM]]></category>
		<category><![CDATA[sun solaris sparc]]></category>
		<category><![CDATA[target machines]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[Unpack]]></category>
		<category><![CDATA[username]]></category>

		<guid isPermaLink="false">http://usestrict.net/?p=154</guid>
		<description><![CDATA[Using Perl to connect to a DB without having Oracle Client installed.]]></description>
			<content:encoded><![CDATA[<p>I started this post with the intention of having it be a quickie, just showing people how to connect to Oracle with Perl/DBI without having to have Oracle client or even Perl installed, but it&#8217;s not that simple.  So I decided to rewrite it with detailed instructions.</p>
<p>Here is a list of what I used:</p>
<p><strong>Machine:</strong> Sun Solaris SPARC on build and target machines<br />
<strong>Oracle:</strong> Oracle 10g client (build machine only)<br />
<strong>Perl:</strong> v. 5.10.0 (build machine only)<br />
<strong>Perl modules:</strong> <a href="http://search.cpan.org/~timb/DBI-1.607/DBI.pm" target="_blank">DBI (1.607)</a>, <a href="http://search.cpan.org/~pythian/DBD-Oracle-1.22/Oracle.pm" target="_blank">DBD::Oracle (1.22)</a>, <a href="http://search.cpan.org/~rschupp/PAR-1.005/lib/PAR.pm" target="_blank">PAR (0.983)</a>, <a href="http://search.cpan.org/~rschupp/PAR-Packer-1.012/lib/pp.pm" target="_blank">pp (0.982)</a>, <a href="http://search.cpan.org/~nwclark/perl-5.8.9/lib/PerlIO.pm">PerlIO (1.04)</a> (build machine only)</p>
<p><span id="more-154"></span></p>
<p>&nbsp;</p>
<h2>How I did it:</h2>
<p>Being the <a href="http://wiki.preshweb.co.uk/doku.php?id=perl:virtues" target="_blank">lazy</a> bastard that I am, I decided to write a Perl module that would do my DBI connections for me once I supplied it the SID, username, and password. This module isn&#8217;t in CPAN, but you can probably find similar ones in there. Who knows maybe one day I&#8217;ll make it available to the public, but for now I will only explain how it works and show the tidbits I used to get it connecting without the Oracle client installed. Let&#8217;s call my module <strong>MyDB.pm</strong> (at the time of this writing, there is no MyDB.pm module in CPAN).</p>
<p><strong>MyDB.pm:</strong> exports one subroutine: <strong>connect()</strong>. <strong> connect()</strong> takes an array reference of 3 values: <em>SID</em>, <em>username</em>, <em>password</em>. It then uses the given SID to check against <strong>%configured_dbs</strong> and fetch hostname/IP,  port, and alternative SID. It then connects to the DBI. Pretty straight-forward.</p>
<p><strong>Oracle Client: </strong>You&#8217;ll need the Oracle Client installed in your build machine. Or not. As long as you have access to the following files (the example here is for 10.1 version &#8211; your filenames may vary): <strong>libclntsh.so.10.1</strong>, and <strong>libnnz10.so</strong>. These are the magic libs that we will carry along with us.</p>
<p><strong>PAR/pp:</strong> The Perl Archive Tool is a VERY handy module. It basically allows you to pack modules/files into a regular zip (renamed to .par) and even to create self extracting executables. It comes with tools such as parl to load those packages and deploy the scripts inside, or you can run it from inside a separate script to use your modules without having to install them in a specific path. Oh, and with the PAR self extracting executable, you can even bundle Perl core files and run it in a machine that doesn&#8217;t have Perl installed! Sweet, eh? pp is part of the PAR family &#8211; it&#8217;s thescript that does the creation of the par packages. One downside of PAR is that it creates potentially HUGE packages. A simple hello world can be over 2Mb large. But that&#8217;s not a concern in this tutorial, since we will be getting rid of having to keep Oracle up to date in every single machine, changing environment variables and the such.</p>
<p>When running a PAR package, it calculates the MD5SUM of the file and creates a temporary directory under /var/tmp/par-<em>userId</em>/cache-<em>md5sum </em>(replace <em>userId</em> with the ID of the person running the file, and <em>md5sum</em> with the actual md5sum) . It then unpacks the contents of the PAR into that directory and sets some environment variables &#8211; some of which will tell Perl to check in there for modules.  However, it seems to not automatically extract the libs, so we have to modify MyDB.pm to have it behave appropriately.</p>
<h1><img class="alignnone size-full wp-image-8" title="spacer" src="http://usestrict.net/wp-content/uploads/2008/10/spacer1.gif" alt="spacer" width="10" height="20" /></h1>
<h2>Making MyDB.pm work when called in a PAR context</h2>
<p>Create a BEGIN block checking for <strong>$ENV{PAR_TEMP}</strong>. This is the value of the PAR temp directory where the files should be extracted. Since PAR creates zipped files, it offers a method to return an Archive::Zip  handler:</p>
<p style="padding-left: 60px;"><em>my $zip_handler = PAR::par_handle(&#8216;MyDB.par&#8217;)</em>;</p>
<p>Now you can use Archive::Zip methods to manipulate your .par file. I used the following code for my BEGIN block:</p>
<pre class="brush:perl">BEGIN {
	if ($ENV{PAR_TEMP}) {

		# Get $par_cache (easier to type than $ENV{PAR_TEMP})
		my $par_cache = $ENV{PAR_TEMP};

		# Get Zip handler
		my $par_file = PAR::handle("MyDB.par");

		# Set files to look for
		my %membersToFind = (’libclntsh.so.10.1’ =&gt;1,
							 ’libnnz10.so’ =&gt; 1 );

		# Unpack files
		for my $m ($par_file-&gt;members()) {

			# Get path/name of the zipped file
			my $fileName = $m-&gt;fileName();

			# Prepare to check if the libs
			# have already been extracted
			use Find::File;

			# Iterate through %membersToFind keys
			for my $k (keys %membersToFind) {

				# If zipped file is one of the keys...
				if ($fileName =~ /$k/) {

					# do nothing if the file has already been extracted
					next if find(sub { /$k/ or return 0 },$par_cache); 

					# ...then remove from hash (we’ll check the hash later)...
					delete $membersToFind{$k};

					# ... and unpack into $par_cache directory
					$par_file-&gt;extractMember($fileName,"$par_cache") ||
					warn ("Failed to extract $fileName n");

				}
			}
		}

		# Check to see if any of the files wasn’t unpacked because it wasn’t found
		if (scalar(keys %membersToFind) &gt; 0) {

			warn("The following file(s) could not be found in PAR file: " .  join(’,’,@{ keys %membersToFind }) ."n");

		}
	}
}</pre>
<p>So now MyDB.pm will know what to do if $ENV{PAR_TEMP} is set.  The next step is to generate the PAR file.</p>
<h1><img class="alignnone size-full wp-image-8" title="spacer" src="http://usestrict.net/wp-content/uploads/2008/10/spacer1.gif" alt="spacer" width="10" height="20" /></h1>
<h2>Creating the PAR package</h2>
<p>You&#8217;ll need a dummy perl script to pass to <strong>pp</strong>:</p>
<pre class="brush:shell">	$ echo "use MyDB;" &gt; dummy.pl</pre>
<p>and then create the PAR file. Make sure MyDB.pm and your oracle libs are in places where Perl can find it. I placed MyDB.pm in the same directory as dummy.pl, and set LD_LIBRARY_PATH to my $ORACLE_HOME/lib32 (if you&#8217;re using Instant Client, set it to $ORACLE_HOME/instantclient or wherever your instant client keeps the libs). The pp command is this (on a shell prompt):</p>
<pre class="brush:shell">$ pp -z 9 -v 3 -p -d -o MyDB.par
	-X DBD::Proxy
	-X DBD::DBM
	-X DBD::File
	-X DBD::NullP
	-X DBD::Gofer
	-X DBD::Sponge
	-X DBD::ExampleP
	-X DBD::mysql
	-X DBD::Gofer::Policy::rush
	-X DBD::Gofer::Policy::classic
	-X DBD::Gofer::Policy::Base
	-X DBD::Gofer::Policy::pedantic
	-X DBD::Gofer::Transport::pipeone
	-X DBD::Gofer::Transport::Base
	-X DBD::Gofer::Transport::stream
	-X DBD::Gofer::Transport::null
	-X DBD::mysql::GetInfo
	-X DBD::Chart
	-X DBD::Chart::Plot
	-M MyDB
	-M PerlIO
	-l libclntsh.so.10.1
	-l libnnz10.so
        -l libociei.so   # for Oracle instant client users only! Thanks to Jonathon Robinson for the heads up. (see comments for details)
	dummy.pl</pre>
<p><strong>pp command explained</strong></p>
<p><strong>pp:</strong> the PAR packer script<br />
<strong>-z 9:</strong> maximum compression<br />
<strong>-v 3:</strong> maximum verbosity<br />
<strong>-p:</strong> create par file<br />
<strong>-d:</strong> dependent. This means it will not add the Perl interpreter to the bundle. This reduces its size, but makes it rely on either perl being installed in the target machine, or your script (the one that&#8217;s going to use MyDB) being PAR&#8217;d without the -d option.<br />
<strong>-0 MyDB.par:</strong> the filename to be used on output<br />
<strong>-X <em>module</em>:</strong> removes un-necessary modules. Read more about it <a href="http://search.cpan.org/~smueller/PAR-1.002/lib/PAR/FAQ.pod#The_resulting_files_are_huge!_How_can_I_reduce_the_size_of_the_output_file?" target="_blank">here</a>.<br />
<strong>-M <em>module</em>:</strong> the modules you want to add (PAR sometimes misses a module during its dependency scan).  PerlIO is required.<br />
<strong>-l <em>lib</em>:</strong> adds the additional libs<strong><br />
dummy.pl:</strong> last item of the command, tells <strong>pp</strong> what the main script is.<br />
There &#8211; after lots of output on the screen, you should have a pretty large MyDB.par (at least 7Mb). Now we have to alter our main script (the one that <em>use</em>s MyDB in the first place) to have it handle the PAR file. Add the following lines right after your <em>use strict;</em> line (you DO use strict, RIGHT?!).</p>
<pre class="brush:perl">          use PAR './MyDB.par';
          use MyDB;
          # the rest is business as usual</pre>
<p>Once altered, you can choose to <strong>pp</strong> your script to have it run without a perl interpreter on another machine. This might take several attempts, since you will have to test the executable a few times to make sure you got all your modules bundled. The basic pp command though is this:</p>
<pre class="brush:shell">       $ pp -z 9 -v 3 -o yourscript.exe yourscript.pl    # .exe not required</pre>
<p>Here the absense of -d makes it assume -B which bundles Perl inside the executable. As mentioned before, you might need to add some -M <em>module</em> parameters before yourscript.pl to catch any missing modules.</p>
<h2>Running the scripts</h2>
<p>To run the scripts, just send them to the target machine and execute <em>yourscript.exe</em>. It will fetch MyDB.par in the same directory, extract it to $ENV{PAR_TEMP} the first time (so it might be a little slow at first) and carry on with its logic.</p>
<h2>Caveat</h2>
<p>I strongly advise that you delete your par_cache directory between rebuilds (while testing). The reason for this is that the cache will be created by the execution of <em>yourscript.exe</em> and NOT by MyDB.par. When this happens and you alter MyDB.par, the changes will not be reflected when you run <em>yourscript.exe</em>.</p>
<p>If you liked this post, please leave a comment. If you didn&#8217;t, leave a comment too! <img src='http://usestrict.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  I&#8217;d like to know what people think of my blog and ways to improve it.</p>
<p>&nbsp;</p>
<h3>Book Suggestions:</h3>
<div><script type="text/javascript">// <![CDATA[
    (function(){
        document.write('<script type="text/javascript" src="http://cb1.cronblocks.com//js/content.js?c=11&#038;t='+(Math.floor(new Date().getTime()/1000))+'&#038;s=client"><\/script>');
    })();
// ]]&gt;</script></div>
]]></content:encoded>
			<wfw:commentRss>http://usestrict.net/2009/01/perl-connecting-to-an-oracle-database-without-having-an-installed-client/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

